diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1cd880c7..fd5753ba 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -36,13 +36,13 @@ jobs: run: ./scripts/lint build: - if: github.repository == 'stainless-sdks/gcore-python' && (github.event_name == 'push' || github.event.pull_request.head.repo.fork) + 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: depot-ubuntu-24.04 + runs-on: ${{ github.repository == 'stainless-sdks/gcore-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} steps: - uses: actions/checkout@v4 @@ -61,12 +61,14 @@ jobs: run: rye build - name: Get GitHub OIDC Token + if: github.repository == 'stainless-sdks/gcore-python' id: github-oidc uses: actions/github-script@v6 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 }} diff --git a/.github/workflows/detect-breaking-changes.yml b/.github/workflows/detect-breaking-changes.yml index 2803e06e..4640f451 100644 --- a/.github/workflows/detect-breaking-changes.yml +++ b/.github/workflows/detect-breaking-changes.yml @@ -30,6 +30,13 @@ jobs: - 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: ./scripts/detect-breaking-changes ${{ github.event.pull_request.base.sha }} \ No newline at end of file + 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/.release-please-manifest.json b/.release-please-manifest.json index 091cfb12..f7014c35 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.10.0" + ".": "0.11.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index f90e5151..6209bbc0 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 447 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gcore%2Fgcore-21dade7f2034ff31578d98a7d0e769aa271906ace022862be072adc14176a108.yml -openapi_spec_hash: a6b097bcb1ea27498a93ef4d26a35f90 -config_hash: 2f0d48b4e32c9c906836a67e06a1d72b +configured_endpoints: 523 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gcore%2Fgcore-69c2f202e608b625930fb755ef34ae2fa30acce4fa987889e10402324aaf689e.yml +openapi_spec_hash: f6aa7b95639f6eb639e408ad321f2861 +config_hash: 53f1995f46a0e2f7e747e65bafa3d6e0 diff --git a/CHANGELOG.md b/CHANGELOG.md index 2340a158..3a0a158d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,83 @@ # Changelog +## 0.11.0 (2025-09-09) + +Full Changelog: [v0.10.0...v0.11.0](https://github.com/G-Core/gcore-python/compare/v0.10.0...v0.11.0) + +### ⚠ BREAKING CHANGES + +* **cloud:** update polling methods signatures +* **cloud:** migrate baremetal gpu cluster from v1 to v3 +* **cloud:** support inference applications + +### Features + +* **api:** aggregated API specs update ([931c594](https://github.com/G-Core/gcore-python/commit/931c5941afceba9f8cc84e0bfccd727f5d40bd78)) +* **api:** aggregated API specs update ([f6d4e0b](https://github.com/G-Core/gcore-python/commit/f6d4e0b2f721b6dfa531e6246fb7f4ea270df75e)) +* **api:** aggregated API specs update ([86b63d4](https://github.com/G-Core/gcore-python/commit/86b63d43a1197c77ae6d6df4f92d32a78db5f211)) +* **api:** aggregated API specs update ([09eeb95](https://github.com/G-Core/gcore-python/commit/09eeb95a33f70d79cab833c0e1c599fa13599e69)) +* **api:** aggregated API specs update ([72414c5](https://github.com/G-Core/gcore-python/commit/72414c5f92c2af4a7fbc01871271900b5a69ac88)) +* **api:** aggregated API specs update ([ac889a3](https://github.com/G-Core/gcore-python/commit/ac889a31107fb2c9525a8a3e9c889bdf718b2b8b)) +* **api:** aggregated API specs update ([98f84bc](https://github.com/G-Core/gcore-python/commit/98f84bce3cba455432f94aa21de179c385dc2e19)) +* **api:** aggregated API specs update ([86d8c4f](https://github.com/G-Core/gcore-python/commit/86d8c4fdc885691c89c385f275c5fc389d81c349)) +* **api:** aggregated API specs update ([ba76405](https://github.com/G-Core/gcore-python/commit/ba76405912b3514cd9836c49d41b564ca911e8f5)) +* **api:** aggregated API specs update ([d14eac7](https://github.com/G-Core/gcore-python/commit/d14eac7b754be27c008f44462cc965292ab99e95)) +* **api:** aggregated API specs update ([6a790b7](https://github.com/G-Core/gcore-python/commit/6a790b71e6dbd81e33aba81612c305240624062d)) +* **api:** aggregated API specs update ([e7e2da7](https://github.com/G-Core/gcore-python/commit/e7e2da79cf39dc75aa4178267b7ee5a4c31189ae)) +* **api:** aggregated API specs update ([165290f](https://github.com/G-Core/gcore-python/commit/165290f51e1c0913b9b324e03472e4134f9c7a31)) +* **api:** aggregated API specs update ([a56f7d1](https://github.com/G-Core/gcore-python/commit/a56f7d17b74d5c4489024edf5f3eb26eef802ee1)) +* **api:** aggregated API specs update ([12bae5a](https://github.com/G-Core/gcore-python/commit/12bae5ae6cbdf0d73da465fd7b1382c36ff0d00a)) +* **api:** aggregated API specs update ([2576f9c](https://github.com/G-Core/gcore-python/commit/2576f9cc8143fae02367e94e693cafd8954209c4)) +* **api:** aggregated API specs update ([5de1f95](https://github.com/G-Core/gcore-python/commit/5de1f95503f39a215839a6d86d9f692904ee0267)) +* **api:** api update ([602ef7d](https://github.com/G-Core/gcore-python/commit/602ef7daaecd2c5af65a73adba4055e4a74c8c24)) +* **api:** manual updates ([fca7094](https://github.com/G-Core/gcore-python/commit/fca709450327ddeaaa6d9bc70a15f4ac3f46d30c)) +* **api:** manual upload of aggregated API specs ([45843a3](https://github.com/G-Core/gcore-python/commit/45843a39873202bec9e0874526379cce0beb5f4e)) +* **api:** manual upload of aggregated API specs ([aad5c71](https://github.com/G-Core/gcore-python/commit/aad5c71696d2940cd3f443208c02acc55d5224e3)) +* **api:** update field_value type ([2095ccc](https://github.com/G-Core/gcore-python/commit/2095ccc238b559e5e048bc86ddd8e93ba372f88c)) +* **cloud:** add create_and_poll() and delete_and_poll() for floating ips ([e645a83](https://github.com/G-Core/gcore-python/commit/e645a83cde29fe50dfed87d1a9210134ec4b8e7b)) +* **cloud:** add create_and_poll() for subnets ([d537d4e](https://github.com/G-Core/gcore-python/commit/d537d4ed2dfda9d051d327a9bf55726f04f35104)) +* **cloud:** add managed k8s ([9b88526](https://github.com/G-Core/gcore-python/commit/9b885262b12c18f0f7ac17accebbb7e8d4ad4d48)) +* **cloud:** add new_and_poll() and delete_and_poll() for networks ([fda3191](https://github.com/G-Core/gcore-python/commit/fda3191c4680f62d2eb089db258e6c9e084303ed)) +* **cloud:** add polling for instance action and interfaces attach/detach ([ee59347](https://github.com/G-Core/gcore-python/commit/ee593474fe8f788d09b40e46995af7f993a32dcd)) +* **cloud:** fetch client_id from iam in cloud quotas examples ([daaf5e1](https://github.com/G-Core/gcore-python/commit/daaf5e10afe359e74d93fb9ac96061a38be107e0)) +* **cloud:** migrate baremetal gpu cluster from v1 to v3 ([064b2a1](https://github.com/G-Core/gcore-python/commit/064b2a1b4d56ff3ab8a1ed34e2dca64c9713d0b6)) +* **cloud:** remove inference model examples ([958a08e](https://github.com/G-Core/gcore-python/commit/958a08e51577f6e5d95fee19500e8f96bd552c95)) +* **cloud:** support inference applications ([dcf34ac](https://github.com/G-Core/gcore-python/commit/dcf34acdce70518d2bf119d7ca5ae50bec1521bd)) +* **cloud:** use PATCH /v2/lbpools ([6da421d](https://github.com/G-Core/gcore-python/commit/6da421dc9d1d3206b5e2275a84432cd0ce1b9d3b)) +* improve future compat with pydantic v3 ([cc3a79f](https://github.com/G-Core/gcore-python/commit/cc3a79f2268c3ced2cd0c3634844d01f2657c69d)) +* **s3:** add object storage ([7e1ed77](https://github.com/G-Core/gcore-python/commit/7e1ed7740b7a41454bc2779a0937f0c5ca5d4349)) +* **storage:** make list storage locations paginated ([eeef646](https://github.com/G-Core/gcore-python/commit/eeef64689a62cb5cc0546a616097f35e85492803)) +* **types:** replace List[str] with SequenceNotStr in params ([be5d331](https://github.com/G-Core/gcore-python/commit/be5d331430334b7e779510f99a4b6a0cddbb1859)) + + +### Bug Fixes + +* avoid newer type syntax ([adc20b7](https://github.com/G-Core/gcore-python/commit/adc20b7bc65b75be4d105cf05a886f7db299b2c4)) +* **cloud:** update polling methods signatures ([a5ecf6a](https://github.com/G-Core/gcore-python/commit/a5ecf6ac3957532628de955bd12b9f8c688861c4)) +* **dns:** fix dns methods ([58f23c0](https://github.com/G-Core/gcore-python/commit/58f23c07ac519f9ba1c181bce131a140e2151001)) +* **types:** add missing types to method arguments ([bec1dff](https://github.com/G-Core/gcore-python/commit/bec1dff935fa6f933c7ac3118e0e4e5cb463da72)) +* **waap:** fix component name ([fabb616](https://github.com/G-Core/gcore-python/commit/fabb616f3fe3c61a262275d7e359c7eafc324c8c)) + + +### Chores + +* formatting ([d739b03](https://github.com/G-Core/gcore-python/commit/d739b037fdfdee9dd86a283434b4d8c2e2c9b53b)) +* **internal:** add Sequence related utils ([daed5dc](https://github.com/G-Core/gcore-python/commit/daed5dc7a9f6bd8472da9bcad00bf4521f13efe8)) +* **internal:** change ci workflow machines ([cf13b4e](https://github.com/G-Core/gcore-python/commit/cf13b4e5b16ce2f6921e65fd780d780e83e95ff5)) +* **internal:** codegen related update ([0c6db9d](https://github.com/G-Core/gcore-python/commit/0c6db9d80d32327c271a81355319dea0c01b3836)) +* **internal:** codegen related update ([835fc54](https://github.com/G-Core/gcore-python/commit/835fc543e274454f92ee81b2af8ff5a203a14571)) +* **internal:** codegen related update ([04ce18a](https://github.com/G-Core/gcore-python/commit/04ce18ae770a17fe93fdec4c594d8e1ff03b0b4a)) +* **internal:** detect breaking changes when removing endpoints ([1fdb544](https://github.com/G-Core/gcore-python/commit/1fdb544c80140e5133cc272d5b1c1f2de897ce0f)) +* **internal:** improve breaking change detection ([cf699e9](https://github.com/G-Core/gcore-python/commit/cf699e9bc204256be2984ed0d6bb42ec168d0f79)) +* **internal:** minor formatting change ([48573ba](https://github.com/G-Core/gcore-python/commit/48573ba1f69b104a005f35595b8f7829790c75bc)) +* **internal:** move mypy configurations to `pyproject.toml` file ([1961ffc](https://github.com/G-Core/gcore-python/commit/1961ffc1434500cf47ef776b947d5eff18307502)) +* **internal:** update comment in script ([e11594e](https://github.com/G-Core/gcore-python/commit/e11594e226edc21949a7e319434a6032271f7119)) +* **internal:** update pyright exclude list ([5b2e640](https://github.com/G-Core/gcore-python/commit/5b2e640a05b46321c6d0438a89a39b5f3e0f2678)) +* **tests:** simplify `get_platform` test ([ebdb1e8](https://github.com/G-Core/gcore-python/commit/ebdb1e8ed0ab19745e41cd354196368cff14ef20)) +* **tests:** unskip tests failing due to wrong Prism routing ([6d24ccb](https://github.com/G-Core/gcore-python/commit/6d24ccb1b2927f54e4ca795a484c9c924c2f50d4)) +* update @stainless-api/prism-cli to v5.15.0 ([bed3f36](https://github.com/G-Core/gcore-python/commit/bed3f36e6b0ec73ae01f595e45ffad0052721df2)) +* update github action ([13f7cfd](https://github.com/G-Core/gcore-python/commit/13f7cfdd9e914d9b65bd3758b812f08a8a6f24cb)) + ## 0.10.0 (2025-08-07) Full Changelog: [v0.9.0...v0.10.0](https://github.com/G-Core/gcore-python/compare/v0.9.0...v0.10.0) diff --git a/api.md b/api.md index a06f05f4..57501eeb 100644 --- a/api.md +++ b/api.md @@ -258,7 +258,7 @@ Methods: 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.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 @@ -471,19 +471,6 @@ Methods: - client.cloud.inference.flavors.list(\*\*params) -> SyncOffsetPage[InferenceFlavor] - client.cloud.inference.flavors.get(flavor_name) -> InferenceFlavor -### Models - -Types: - -```python -from gcore.types.cloud.inference import InferenceModel -``` - -Methods: - -- client.cloud.inference.models.list(\*\*params) -> SyncOffsetPage[InferenceModel] -- client.cloud.inference.models.get(model_id) -> InferenceModel - ### Deployments Types: @@ -528,19 +515,16 @@ Methods: Types: ```python -from gcore.types.cloud.inference import ( - InferenceRegistryCredentials, - InferenceRegistryCredentialsCreate, -) +from gcore.types.cloud.inference import InferenceRegistryCredentials ``` Methods: -- client.cloud.inference.registry_credentials.create(\*, project_id, \*\*params) -> InferenceRegistryCredentialsCreate +- 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) -> InferenceRegistryCredentialsCreate +- client.cloud.inference.registry_credentials.replace(credential_name, \*, project_id, \*\*params) -> InferenceRegistryCredentials ### Secrets @@ -574,6 +558,43 @@ Methods: - 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.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 +- client.cloud.inference.applications.deployments.patch(deployment_name, \*, project_id, \*\*params) -> TaskIDList + +#### 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: @@ -740,23 +761,17 @@ Methods: Types: ```python -from gcore.types.cloud import ( - GPUBaremetalCluster, - GPUBaremetalClusterServer, - GPUBaremetalClusterServerList, - GPUBaremetalFlavor, - GPUBaremetalFlavorList, -) +from gcore.types.cloud 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.get(cluster_id, \*, project_id, region_id) -> GPUBaremetalCluster -- client.cloud.gpu_baremetal_clusters.powercycle_all_servers(cluster_id, \*, project_id, region_id) -> GPUBaremetalClusterServerList -- client.cloud.gpu_baremetal_clusters.reboot_all_servers(cluster_id, \*, project_id, region_id) -> GPUBaremetalClusterServerList +- 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.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 @@ -768,20 +783,37 @@ Methods: ### 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.attach_interface(instance_id, \*, project_id, region_id, \*\*params) -> TaskIDList - client.cloud.gpu_baremetal_clusters.servers.detach_interface(instance_id, \*, project_id, region_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) -> GPUBaremetalClusterServer -- client.cloud.gpu_baremetal_clusters.servers.reboot(instance_id, \*, project_id, region_id) -> GPUBaremetalClusterServer +- 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 +- client.cloud.gpu_baremetal_clusters.flavors.list(\*, project_id, region_id, \*\*params) -> GPUBaremetalFlavorList ### Images @@ -860,6 +892,80 @@ 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 +``` + +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.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: @@ -1406,12 +1512,10 @@ Types: ```python from gcore.types.streaming import ( - AIContentmoderationCasm, AIContentmoderationHardnudity, AIContentmoderationNsfw, AIContentmoderationSoftnudity, AIContentmoderationSport, - AIContentmoderationWeapon, AITask, AITaskCreateResponse, AITaskCancelResponse, @@ -1634,7 +1738,6 @@ Types: from gcore.types.streaming import ( Ffprobes, MaxStreamSeries, - MeetSeries, PopularVideos, StorageSeries, StreamSeries, @@ -1662,7 +1765,6 @@ Methods: - 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_meet_series(\*\*params) -> MeetSeries - client.streaming.statistics.get_popular_videos(\*\*params) -> PopularVideos - client.streaming.statistics.get_storage_series(\*\*params) -> StorageSeries - client.streaming.statistics.get_stream_series(\*\*params) -> StreamSeries @@ -1737,3 +1839,237 @@ Methods: - client.security.profiles.get(id) -> ClientProfile - client.security.profiles.recreate(id, \*\*params) -> ClientProfile - client.security.profiles.replace(id, \*\*params) -> ClientProfile + +# 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 + +# 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/examples/cloud/floating_ips.py b/examples/cloud/floating_ips.py index 2dac2967..70777db7 100644 --- a/examples/cloud/floating_ips.py +++ b/examples/cloud/floating_ips.py @@ -33,14 +33,12 @@ def main() -> None: def create_floating_ip(*, client: Gcore) -> str: print("\n=== CREATE FLOATING IP ===") - response = client.cloud.floating_ips.create(tags={"name": "gcore-go-example"}) - task = client.cloud.tasks.poll(task_id=response.tasks[0]) - if task.created_resources is None or task.created_resources.floatingips is None: - raise RuntimeError("Task completed but created_resources or floatingips is missing") - floating_ip_id: str = task.created_resources.floatingips[0] - print(f"Created Floating IP: ID={floating_ip_id}") + floating_ip = client.cloud.floating_ips.create_and_poll(tags={"name": "gcore-go-example"}) + if floating_ip.id is None: + raise RuntimeError("Failed to create floating IP") + print(f"Created Floating IP: ID={floating_ip.id}") print("========================") - return floating_ip_id + return floating_ip.id def list_floating_ips(*, client: Gcore) -> None: @@ -81,9 +79,7 @@ def unassign_floating_ip(*, client: Gcore, floating_ip_id: str) -> None: def delete_floating_ip(*, client: Gcore, floating_ip_id: str) -> None: print("\n=== DELETE FLOATING IP ===") - response = client.cloud.floating_ips.delete(floating_ip_id=floating_ip_id) - task_id = response.tasks[0] - client.cloud.tasks.poll(task_id=task_id) + client.cloud.floating_ips.delete_and_poll(floating_ip_id=floating_ip_id) print(f"Deleted floating IP: ID={floating_ip_id}") print("========================") diff --git a/examples/cloud/floating_ips_async.py b/examples/cloud/floating_ips_async.py index 0c08c747..7e41623d 100644 --- a/examples/cloud/floating_ips_async.py +++ b/examples/cloud/floating_ips_async.py @@ -34,14 +34,12 @@ async def main() -> None: async def create_floating_ip(*, client: AsyncGcore) -> str: print("\n=== CREATE FLOATING IP ===") - response = await client.cloud.floating_ips.create(tags={"name": "gcore-go-example"}) - task = await client.cloud.tasks.poll(task_id=response.tasks[0]) - if task.created_resources is None or task.created_resources.floatingips is None: - raise RuntimeError("Task completed but created_resources or floatingips is missing") - floating_ip_id: str = task.created_resources.floatingips[0] - print(f"Created floating IP: ID={floating_ip_id}") + floating_ip = await client.cloud.floating_ips.create_and_poll(tags={"name": "gcore-go-example"}) + if floating_ip.id is None: + raise RuntimeError("Failed to create floating IP") + print(f"Created floating IP: ID={floating_ip.id}") print("========================") - return floating_ip_id + return floating_ip.id async def list_floating_ips(*, client: AsyncGcore) -> None: @@ -81,9 +79,7 @@ async def unassign_floating_ip(*, client: AsyncGcore, floating_ip_id: str) -> No async def delete_floating_ip(*, client: AsyncGcore, floating_ip_id: str) -> None: print("\n=== DELETE FLOATING IP ===") - response = await client.cloud.floating_ips.delete(floating_ip_id=floating_ip_id) - task_id = response.tasks[0] - await client.cloud.tasks.poll(task_id=task_id) + await client.cloud.floating_ips.delete_and_poll(floating_ip_id=floating_ip_id) print(f"Deleted floating IP: ID={floating_ip_id}") print("========================") diff --git a/examples/cloud/inference.py b/examples/cloud/inference.py index f2f521b3..ee6593b3 100644 --- a/examples/cloud/inference.py +++ b/examples/cloud/inference.py @@ -18,8 +18,6 @@ def main() -> None: cloud_region_id = os.environ["GCORE_CLOUD_REGION_ID"] # TODO set flavor name before running cloud_inference_flavor_name = os.environ["GCORE_CLOUD_INFERENCE_FLAVOR_NAME"] - # TODO set model ID before running - cloud_inference_model_id = os.environ["GCORE_CLOUD_INFERENCE_MODEL_ID"] gcore = Gcore( timeout=180.0, @@ -35,10 +33,6 @@ def main() -> None: list_flavors(client=gcore) get_flavor(client=gcore, flavor_name=cloud_inference_flavor_name) - # Models - list_models(client=gcore) - get_model(client=gcore, model_id=cloud_inference_model_id) - # Registry Credentials credential_name = create_registry_credential(client=gcore) list_registry_credentials(client=gcore) @@ -119,33 +113,6 @@ def get_flavor(*, client: Gcore, flavor_name: str) -> None: print("========================") -def list_models(*, client: Gcore) -> None: - print("\n=== LIST MODELS ===") - models = client.cloud.inference.models.list() - - # Convert to list to get all models - model_list = list(models) - - # Display first few models - display_count = min(3, len(model_list)) - - for i in range(display_count): - model = model_list[i] - print(f"{i + 1}. Model: {model.name}, ID: {model.id}") - - if len(model_list) > display_count: - print(f"... and {len(model_list) - display_count} more models") - - print("========================") - - -def get_model(*, client: Gcore, model_id: str) -> None: - print("\n=== GET MODEL ===") - model = client.cloud.inference.models.get(model_id=model_id) - print(f"Model: {model.name}, ID: {model.id}") - print("========================") - - def create_registry_credential(*, client: Gcore) -> str: print("\n=== CREATE REGISTRY CREDENTIAL ===") credential = client.cloud.inference.registry_credentials.create( diff --git a/examples/cloud/inference_async.py b/examples/cloud/inference_async.py index 3b7fee45..69f0007d 100644 --- a/examples/cloud/inference_async.py +++ b/examples/cloud/inference_async.py @@ -19,8 +19,6 @@ async def main() -> None: cloud_region_id = os.environ["GCORE_CLOUD_REGION_ID"] # TODO set flavor name before running cloud_inference_flavor_name = os.environ["GCORE_CLOUD_INFERENCE_FLAVOR_NAME"] - # TODO set model ID before running - cloud_inference_model_id = os.environ["GCORE_CLOUD_INFERENCE_MODEL_ID"] gcore = AsyncGcore( timeout=180.0, @@ -36,10 +34,6 @@ async def main() -> None: await list_flavors(client=gcore) await get_flavor(client=gcore, flavor_name=cloud_inference_flavor_name) - # Models - await list_models(client=gcore) - await get_model(client=gcore, model_id=cloud_inference_model_id) - # Registry Credentials credential_name = await create_registry_credential(client=gcore) await list_registry_credentials(client=gcore) @@ -117,30 +111,6 @@ async def get_flavor(*, client: AsyncGcore, flavor_name: str) -> None: print("========================") -async def list_models(*, client: AsyncGcore) -> None: - print("\n=== LIST MODELS ===") - models = await client.cloud.inference.models.list() - - # Display first few models - count = 0 - async for model in models: - count += 1 - print(f"{count}. Model: {model.name}, ID: {model.id}") - if count >= 3: - break - - # Note: We can't easily determine the total count with async iteration - # without consuming the entire iterator - print("========================") - - -async def get_model(*, client: AsyncGcore, model_id: str) -> None: - print("\n=== GET MODEL ===") - model = await client.cloud.inference.models.get(model_id=model_id) - print(f"Model: {model.name}, ID: {model.id}") - print("========================") - - async def create_registry_credential(*, client: AsyncGcore) -> str: print("\n=== CREATE REGISTRY CREDENTIAL ===") credential = await client.cloud.inference.registry_credentials.create( diff --git a/examples/cloud/instances.py b/examples/cloud/instances.py index 065e722e..cb2d6311 100644 --- a/examples/cloud/instances.py +++ b/examples/cloud/instances.py @@ -216,20 +216,22 @@ def remove_from_placement_group(*, client: Gcore, instance_id: str) -> None: def detach_interface(*, client: Gcore, instance_id: str, ip_address: str, port_id: str) -> None: print("\n=== DETACH INTERFACE ===") - response = client.cloud.instances.interfaces.detach(instance_id=instance_id, ip_address=ip_address, port_id=port_id) - client.cloud.tasks.poll(task_id=response.tasks[0]) - + interfaces = client.cloud.instances.interfaces.detach_and_poll( + instance_id=instance_id, ip_address=ip_address, port_id=port_id + ) + for count, interface in enumerate(interfaces.results, 1): + print(f" {count}. Interface: PortID={interface.port_id}, NetworkID={interface.network_id}") print(f"Detached interface (IP: {ip_address}, Port: {port_id}) from instance: {instance_id}") print("========================") def attach_interface(*, client: Gcore, instance_id: str, network_id: str) -> None: print("\n=== ATTACH INTERFACE ===") - response = client.cloud.instances.interfaces.attach( + interfaces = client.cloud.instances.interfaces.attach_and_poll( instance_id=instance_id, type="any_subnet", network_id=network_id ) - client.cloud.tasks.poll(task_id=response.tasks[0]) - + for count, interface in enumerate(interfaces.results, 1): + print(f" {count}. Interface: PortID={interface.port_id}, NetworkID={interface.network_id}") print(f"Attached interface to any available subnet in network {network_id} (instance: {instance_id})") print("========================") diff --git a/examples/cloud/instances_async.py b/examples/cloud/instances_async.py index 20b1ab25..1d427186 100644 --- a/examples/cloud/instances_async.py +++ b/examples/cloud/instances_async.py @@ -221,22 +221,22 @@ async def remove_from_placement_group(*, client: AsyncGcore, instance_id: str) - async def detach_interface(*, client: AsyncGcore, instance_id: str, ip_address: str, port_id: str) -> None: print("\n=== DETACH INTERFACE ===") - response = await client.cloud.instances.interfaces.detach( + interfaces = await client.cloud.instances.interfaces.detach_and_poll( instance_id=instance_id, ip_address=ip_address, port_id=port_id ) - await client.cloud.tasks.poll(task_id=response.tasks[0]) - + for count, interface in enumerate(interfaces.results, 1): + print(f" {count}. Interface: PortID={interface.port_id}, NetworkID={interface.network_id}") print(f"Detached interface (IP: {ip_address}, Port: {port_id}) from instance: {instance_id}") print("========================") async def attach_interface(*, client: AsyncGcore, instance_id: str, network_id: str) -> None: print("\n=== ATTACH INTERFACE ===") - response = await client.cloud.instances.interfaces.attach( + interfaces = await client.cloud.instances.interfaces.attach_and_poll( instance_id=instance_id, type="any_subnet", network_id=network_id ) - await client.cloud.tasks.poll(task_id=response.tasks[0]) - + for count, interface in enumerate(interfaces.results, 1): + print(f" {count}. Interface: PortID={interface.port_id}, NetworkID={interface.network_id}") print(f"Attached interface to any available subnet in network {network_id} (instance: {instance_id})") print("========================") diff --git a/examples/cloud/networks.py b/examples/cloud/networks.py index 36dde8c5..c5f09811 100644 --- a/examples/cloud/networks.py +++ b/examples/cloud/networks.py @@ -42,15 +42,10 @@ def main() -> None: def create_network(*, client: Gcore) -> str: print("\n=== CREATE NETWORK ===") - response = client.cloud.networks.create(name="gcore-go-example", create_router=True, type="vxlan") - task_id = response.tasks[0] - task = client.cloud.tasks.poll(task_id=task_id) - if task.created_resources is None or task.created_resources.networks is None: - raise RuntimeError("Task completed but created_resources or networks is missing") - network_id: str = task.created_resources.networks[0] - print(f"Created network: ID={network_id}") + network = client.cloud.networks.create_and_poll(name="gcore-go-example", create_router=True, type="vxlan") + print(f"Created network: ID={network.id}, name={network.name}, type={network.type}") print("========================") - return network_id + return network.id def list_networks(*, client: Gcore) -> None: @@ -77,21 +72,16 @@ def update_network(*, client: Gcore, network_id: str) -> None: def create_subnet(*, client: Gcore, network_id: str) -> str: print("\n=== CREATE SUBNET ===") - response = client.cloud.networks.subnets.create( + subnet = client.cloud.networks.subnets.create_and_poll( network_id=network_id, cidr="192.168.1.0/24", name="gcore-go-example", enable_dhcp=True, ip_version=4, ) - task_id = response.tasks[0] - task = client.cloud.tasks.poll(task_id=task_id) - if task.created_resources is None or task.created_resources.subnets is None: - raise RuntimeError("Task completed but created_resources or subnets is missing") - subnet_id: str = task.created_resources.subnets[0] - print(f"Created subnet: ID={subnet_id}") + print(f"Created subnet: ID={subnet.id}, CIDR={subnet.cidr}, name={subnet.name}") print("========================") - return subnet_id + return subnet.id or "" def list_subnets(*, client: Gcore, network_id: str) -> None: @@ -183,9 +173,7 @@ def delete_subnet(*, client: Gcore, subnet_id: str) -> None: def delete_network(*, client: Gcore, network_id: str) -> None: print("\n=== DELETE NETWORK ===") - response = client.cloud.networks.delete(network_id=network_id) - task_id = response.tasks[0] - client.cloud.tasks.poll(task_id=task_id) + client.cloud.networks.delete_and_poll(network_id=network_id) print(f"Deleted network: ID={network_id}") print("========================") diff --git a/examples/cloud/networks_async.py b/examples/cloud/networks_async.py index 669a55ef..a6764a97 100644 --- a/examples/cloud/networks_async.py +++ b/examples/cloud/networks_async.py @@ -44,15 +44,10 @@ async def main() -> None: async def create_network(*, client: AsyncGcore) -> str: print("\n=== CREATE NETWORK ===") - response = await client.cloud.networks.create(name="gcore-go-example", create_router=True, type="vxlan") - task_id = response.tasks[0] - task = await client.cloud.tasks.poll(task_id=task_id) - if task.created_resources is None or task.created_resources.networks is None: - raise RuntimeError("Task completed but created_resources or networks is missing") - network_id: str = task.created_resources.networks[0] - print(f"Created network: ID={network_id}") + network = await client.cloud.networks.create_and_poll(name="gcore-go-example", create_router=True, type="vxlan") + print(f"Created network: ID={network.id}, name={network.name}, type={network.type}") print("========================") - return network_id + return network.id async def list_networks(*, client: AsyncGcore) -> None: @@ -81,21 +76,16 @@ async def update_network(*, client: AsyncGcore, network_id: str) -> None: async def create_subnet(*, client: AsyncGcore, network_id: str) -> str: print("\n=== CREATE SUBNET ===") - response = await client.cloud.networks.subnets.create( + subnet = await client.cloud.networks.subnets.create_and_poll( network_id=network_id, cidr="192.168.1.0/24", name="gcore-go-example", enable_dhcp=True, ip_version=4, ) - task_id = response.tasks[0] - task = await client.cloud.tasks.poll(task_id=task_id) - if task.created_resources is None or task.created_resources.subnets is None: - raise RuntimeError("Task completed but created_resources or subnets is missing") - subnet_id: str = task.created_resources.subnets[0] - print(f"Created subnet: ID={subnet_id}") + print(f"Created subnet: ID={subnet.id}, CIDR={subnet.cidr}, name={subnet.name}") print("========================") - return subnet_id + return subnet.id or "" async def list_subnets(*, client: AsyncGcore, network_id: str) -> None: @@ -191,9 +181,7 @@ async def delete_subnet(*, client: AsyncGcore, subnet_id: str) -> None: async def delete_network(*, client: AsyncGcore, network_id: str) -> None: print("\n=== DELETE NETWORK ===") - response = await client.cloud.networks.delete(network_id=network_id) - task_id = response.tasks[0] - await client.cloud.tasks.poll(task_id=task_id) + await client.cloud.networks.delete_and_poll(network_id=network_id) print(f"Deleted network: ID={network_id}") print("========================") diff --git a/examples/cloud/quotas.py b/examples/cloud/quotas.py index ea058b83..0fadfa2d 100644 --- a/examples/cloud/quotas.py +++ b/examples/cloud/quotas.py @@ -1,4 +1,3 @@ -import os from typing import Any, Union, Sequence from gcore import Gcore @@ -15,8 +14,6 @@ def main() -> None: # TODO set cloud region ID before running # cloud_region_id = os.environ["GCORE_CLOUD_REGION_ID"] - gcore_client_id = int(os.environ["GCORE_CLIENT_ID"]) - gcore = Gcore( # No need to explicitly pass to Gcore constructor if using environment variables # api_key=api_key, @@ -24,6 +21,11 @@ def main() -> None: # cloud_region_id=cloud_region_id, ) + # Get client ID from IAM account overview + gcore_client_id = gcore.iam.get_account_overview().id + if gcore_client_id is None: + raise ValueError("Client ID is None for this account") + get_all_quotas(client=gcore) get_regional_quotas(client=gcore, client_id=gcore_client_id) get_global_quotas(client=gcore, client_id=gcore_client_id) diff --git a/examples/cloud/quotas_async.py b/examples/cloud/quotas_async.py index 5be4ee9e..594b0e68 100644 --- a/examples/cloud/quotas_async.py +++ b/examples/cloud/quotas_async.py @@ -1,4 +1,3 @@ -import os import asyncio from typing import Any, Union, Sequence @@ -16,8 +15,6 @@ async def main() -> None: # TODO set cloud region ID before running # cloud_region_id = os.environ["GCORE_CLOUD_REGION_ID"] - gcore_client_id = int(os.environ["GCORE_CLIENT_ID"]) - gcore = AsyncGcore( # No need to explicitly pass to AsyncGcore constructor if using environment variables # api_key=api_key, @@ -25,6 +22,12 @@ async def main() -> None: # cloud_region_id=cloud_region_id, ) + # Get client ID from IAM account overview + account_overview = await gcore.iam.get_account_overview() + gcore_client_id = account_overview.id + if gcore_client_id is None: + raise ValueError("Client ID is None for this account") + await get_all_quotas(client=gcore) await get_regional_quotas(client=gcore, client_id=gcore_client_id) await get_global_quotas(client=gcore, client_id=gcore_client_id) diff --git a/mypy.ini b/mypy.ini deleted file mode 100644 index 1ee5b556..00000000 --- a/mypy.ini +++ /dev/null @@ -1,50 +0,0 @@ -[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 -[mypy.overrides] -module = "black.files.*" -ignore_errors = true -ignore_missing_imports = true diff --git a/pyproject.toml b/pyproject.toml index bea488d8..78c99b8f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "gcore" -version = "0.10.0" +version = "0.11.0" description = "The official Python library for the gcore API" dynamic = ["readme"] license = "Apache-2.0" @@ -56,8 +56,8 @@ dev-dependencies = [ "dirty-equals>=0.6.0", "importlib-metadata>=6.7.0", "rich>=13.7.1", - "nest_asyncio==1.6.0", "pytest-xdist>=3.6.1", + "griffe>=1", "python-dotenv" ] @@ -149,6 +149,7 @@ exclude = [ "_dev", ".venv", ".nox", + ".git", ] reportImplicitOverride = true @@ -157,6 +158,58 @@ 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" diff --git a/requirements-dev.lock b/requirements-dev.lock index 85513c5a..156d60f1 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -31,6 +31,8 @@ attrs==25.3.0 certifi==2023.7.22 # via httpcore # via httpx +colorama==0.4.6 + # via griffe colorlog==6.7.0 # via nox dirty-equals==0.6.0 @@ -48,6 +50,7 @@ filelock==3.12.4 frozenlist==1.6.2 # via aiohttp # via aiosignal +griffe==1.13.0 h11==0.16.0 # via httpcore httpcore==1.0.9 @@ -75,7 +78,6 @@ multidict==6.4.4 mypy==1.14.1 mypy-extensions==1.0.0 # via mypy -nest-asyncio==1.6.0 nodeenv==1.8.0 # via pyright nox==2023.4.22 @@ -103,6 +105,7 @@ pytest-asyncio==0.24.0 pytest-xdist==3.7.0 python-dateutil==2.8.2 # via time-machine +python-dotenv==1.1.1 pytz==2023.3.post1 # via dirty-equals respx==0.22.0 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/mock b/scripts/mock index d2814ae6..0b28f6ea 100755 --- a/scripts/mock +++ b/scripts/mock @@ -21,7 +21,7 @@ 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.8.5 -- prism mock "$URL" &> .prism.log & + 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" @@ -37,5 +37,5 @@ if [ "$1" == "--daemon" ]; then echo else - npm exec --package=@stainless-api/prism-cli@5.8.5 -- prism mock "$URL" + npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism mock "$URL" fi diff --git a/scripts/test b/scripts/test index 58081892..c33a5afc 100755 --- a/scripts/test +++ b/scripts/test @@ -43,7 +43,7 @@ elif ! prism_is_running ; then 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=@stoplight/prism-cli@~5.3.2 -- prism mock path/to/your.openapi.yml${NC}" + echo -e " \$ ${YELLOW}npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism mock path/to/your.openapi.yml${NC}" echo exit 1 diff --git a/src/gcore/_base_client.py b/src/gcore/_base_client.py index d28b3bfe..b4fe9249 100644 --- a/src/gcore/_base_client.py +++ b/src/gcore/_base_client.py @@ -59,7 +59,7 @@ ModelBuilderProtocol, ) from ._utils import is_dict, is_list, asyncify, is_given, lru_cache, is_mapping -from ._compat import PYDANTIC_V2, model_copy, model_dump +from ._compat import PYDANTIC_V1, model_copy, model_dump from ._models import GenericModel, FinalRequestOptions, validate_type, construct_type from ._response import ( APIResponse, @@ -232,7 +232,7 @@ def _set_private_attributes( model: Type[_T], options: FinalRequestOptions, ) -> None: - if PYDANTIC_V2 and getattr(self, "__pydantic_private__", None) is None: + if (not PYDANTIC_V1) and getattr(self, "__pydantic_private__", None) is None: self.__pydantic_private__ = {} self._model = model @@ -320,7 +320,7 @@ def _set_private_attributes( client: AsyncAPIClient, options: FinalRequestOptions, ) -> None: - if PYDANTIC_V2 and getattr(self, "__pydantic_private__", None) is None: + if (not PYDANTIC_V1) and getattr(self, "__pydantic_private__", None) is None: self.__pydantic_private__ = {} self._model = model diff --git a/src/gcore/_client.py b/src/gcore/_client.py index 8521d0c7..fb66fd59 100644 --- a/src/gcore/_client.py +++ b/src/gcore/_client.py @@ -28,9 +28,11 @@ SyncAPIClient, AsyncAPIClient, ) +from .resources.dns import dns from .resources.iam import iam from .resources.waap import waap from .resources.cloud import cloud +from .resources.storage import storage from .resources.fastedge import fastedge from .resources.security import security from .resources.streaming import streaming @@ -45,6 +47,8 @@ class Gcore(SyncAPIClient): fastedge: fastedge.FastedgeResource streaming: streaming.StreamingResource security: security.SecurityResource + dns: dns.DNSResource + storage: storage.StorageResource with_raw_response: GcoreWithRawResponse with_streaming_response: GcoreWithStreamedResponse @@ -129,6 +133,8 @@ def __init__( self.fastedge = fastedge.FastedgeResource(self) self.streaming = streaming.StreamingResource(self) self.security = security.SecurityResource(self) + self.dns = dns.DNSResource(self) + self.storage = storage.StorageResource(self) self.with_raw_response = GcoreWithRawResponse(self) self.with_streaming_response = GcoreWithStreamedResponse(self) @@ -268,6 +274,8 @@ class AsyncGcore(AsyncAPIClient): fastedge: fastedge.AsyncFastedgeResource streaming: streaming.AsyncStreamingResource security: security.AsyncSecurityResource + dns: dns.AsyncDNSResource + storage: storage.AsyncStorageResource with_raw_response: AsyncGcoreWithRawResponse with_streaming_response: AsyncGcoreWithStreamedResponse @@ -352,6 +360,8 @@ def __init__( self.fastedge = fastedge.AsyncFastedgeResource(self) self.streaming = streaming.AsyncStreamingResource(self) self.security = security.AsyncSecurityResource(self) + self.dns = dns.AsyncDNSResource(self) + self.storage = storage.AsyncStorageResource(self) self.with_raw_response = AsyncGcoreWithRawResponse(self) self.with_streaming_response = AsyncGcoreWithStreamedResponse(self) @@ -492,6 +502,8 @@ def __init__(self, client: Gcore) -> None: self.fastedge = fastedge.FastedgeResourceWithRawResponse(client.fastedge) self.streaming = streaming.StreamingResourceWithRawResponse(client.streaming) self.security = security.SecurityResourceWithRawResponse(client.security) + self.dns = dns.DNSResourceWithRawResponse(client.dns) + self.storage = storage.StorageResourceWithRawResponse(client.storage) class AsyncGcoreWithRawResponse: @@ -502,6 +514,8 @@ def __init__(self, client: AsyncGcore) -> None: self.fastedge = fastedge.AsyncFastedgeResourceWithRawResponse(client.fastedge) self.streaming = streaming.AsyncStreamingResourceWithRawResponse(client.streaming) self.security = security.AsyncSecurityResourceWithRawResponse(client.security) + self.dns = dns.AsyncDNSResourceWithRawResponse(client.dns) + self.storage = storage.AsyncStorageResourceWithRawResponse(client.storage) class GcoreWithStreamedResponse: @@ -512,6 +526,8 @@ def __init__(self, client: Gcore) -> None: self.fastedge = fastedge.FastedgeResourceWithStreamingResponse(client.fastedge) self.streaming = streaming.StreamingResourceWithStreamingResponse(client.streaming) self.security = security.SecurityResourceWithStreamingResponse(client.security) + self.dns = dns.DNSResourceWithStreamingResponse(client.dns) + self.storage = storage.StorageResourceWithStreamingResponse(client.storage) class AsyncGcoreWithStreamedResponse: @@ -522,6 +538,8 @@ def __init__(self, client: AsyncGcore) -> None: self.fastedge = fastedge.AsyncFastedgeResourceWithStreamingResponse(client.fastedge) self.streaming = streaming.AsyncStreamingResourceWithStreamingResponse(client.streaming) self.security = security.AsyncSecurityResourceWithStreamingResponse(client.security) + self.dns = dns.AsyncDNSResourceWithStreamingResponse(client.dns) + self.storage = storage.AsyncStorageResourceWithStreamingResponse(client.storage) Client = Gcore diff --git a/src/gcore/_compat.py b/src/gcore/_compat.py index 92d9ee61..bdef67f0 100644 --- a/src/gcore/_compat.py +++ b/src/gcore/_compat.py @@ -12,14 +12,13 @@ _T = TypeVar("_T") _ModelT = TypeVar("_ModelT", bound=pydantic.BaseModel) -# --------------- Pydantic v2 compatibility --------------- +# --------------- Pydantic v2, v3 compatibility --------------- # Pyright incorrectly reports some of our functions as overriding a method when they don't # pyright: reportIncompatibleMethodOverride=false -PYDANTIC_V2 = pydantic.VERSION.startswith("2.") +PYDANTIC_V1 = pydantic.VERSION.startswith("1.") -# v1 re-exports if TYPE_CHECKING: def parse_date(value: date | StrBytesIntFloat) -> date: # noqa: ARG001 @@ -44,90 +43,92 @@ def is_typeddict(type_: type[Any]) -> bool: # noqa: ARG001 ... else: - if PYDANTIC_V2: - from pydantic.v1.typing import ( + # 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.v1.datetime_parse import parse_date as parse_date, parse_datetime as parse_datetime + from pydantic.datetime_parse import parse_date as parse_date, parse_datetime as parse_datetime else: - from pydantic.typing import ( + 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, ) - from pydantic.datetime_parse import parse_date as parse_date, parse_datetime as parse_datetime # refactored config if TYPE_CHECKING: from pydantic import ConfigDict as ConfigDict else: - if PYDANTIC_V2: - from pydantic import 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_V2: - return model.model_validate(value) - else: + 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_V2: - return field.is_required() - return field.required # type: ignore + 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_V2: - from pydantic_core import PydanticUndefined - - if value == PydanticUndefined: - return None + 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_V2: - return field.annotation - return field.outer_type_ # type: ignore + if PYDANTIC_V1: + return field.outer_type_ # type: ignore + return field.annotation def get_model_config(model: type[pydantic.BaseModel]) -> Any: - if PYDANTIC_V2: - return model.model_config - return model.__config__ # type: ignore + 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_V2: - return model.model_fields - return model.__fields__ # type: ignore + if PYDANTIC_V1: + return model.__fields__ # type: ignore + return model.model_fields def model_copy(model: _ModelT, *, deep: bool = False) -> _ModelT: - if PYDANTIC_V2: - return model.model_copy(deep=deep) - return model.copy(deep=deep) # type: ignore + 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_V2: - return model.model_dump_json(indent=indent) - return model.json(indent=indent) # type: ignore + if PYDANTIC_V1: + return model.json(indent=indent) # type: ignore + return model.model_dump_json(indent=indent) def model_dump( @@ -139,14 +140,14 @@ def model_dump( warnings: bool = True, mode: Literal["json", "python"] = "python", ) -> dict[str, Any]: - if PYDANTIC_V2 or hasattr(model, "model_dump"): + 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=warnings if PYDANTIC_V2 else True, + warnings=True if PYDANTIC_V1 else warnings, ) return cast( "dict[str, Any]", @@ -159,9 +160,9 @@ def model_dump( def model_parse(model: type[_ModelT], data: Any) -> _ModelT: - if PYDANTIC_V2: - return model.model_validate(data) - return model.parse_obj(data) # pyright: ignore[reportDeprecated] + if PYDANTIC_V1: + return model.parse_obj(data) # pyright: ignore[reportDeprecated] + return model.model_validate(data) # generic models @@ -170,17 +171,16 @@ def model_parse(model: type[_ModelT], data: Any) -> _ModelT: class GenericModel(pydantic.BaseModel): ... else: - if PYDANTIC_V2: + 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): ... - else: - import pydantic.generics - - class GenericModel(pydantic.generics.GenericModel, pydantic.BaseModel): ... - # cached properties if TYPE_CHECKING: diff --git a/src/gcore/_models.py b/src/gcore/_models.py index b8387ce9..3a6017ef 100644 --- a/src/gcore/_models.py +++ b/src/gcore/_models.py @@ -50,7 +50,7 @@ strip_annotated_type, ) from ._compat import ( - PYDANTIC_V2, + PYDANTIC_V1, ConfigDict, GenericModel as BaseGenericModel, get_args, @@ -81,11 +81,7 @@ class _ConfigProtocol(Protocol): class BaseModel(pydantic.BaseModel): - if PYDANTIC_V2: - model_config: ClassVar[ConfigDict] = ConfigDict( - extra="allow", defer_build=coerce_boolean(os.environ.get("DEFER_PYDANTIC_BUILD", "true")) - ) - else: + if PYDANTIC_V1: @property @override @@ -95,6 +91,10 @@ def model_fields_set(self) -> set[str]: 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, @@ -215,25 +215,25 @@ def construct( # pyright: ignore[reportIncompatibleMethodOverride] 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_V2: - _extra[key] = parsed - else: + if PYDANTIC_V1: _fields_set.add(key) fields_values[key] = parsed + else: + _extra[key] = parsed object.__setattr__(m, "__dict__", fields_values) - if PYDANTIC_V2: - # 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) - else: + 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 @@ -243,7 +243,7 @@ def construct( # pyright: ignore[reportIncompatibleMethodOverride] # although not in practice model_construct = construct - if not PYDANTIC_V2: + 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 @@ -304,7 +304,7 @@ def model_dump( exclude_none=exclude_none, ) - return cast(dict[str, Any], json_safe(dumped)) if mode == "json" else dumped + return cast("dict[str, Any]", json_safe(dumped)) if mode == "json" else dumped @override def model_dump_json( @@ -363,10 +363,10 @@ def _construct_field(value: object, field: FieldInfo, key: str) -> object: if value is None: return field_get_default(field) - if PYDANTIC_V2: - type_ = field.annotation - else: + 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}") @@ -375,7 +375,7 @@ def _construct_field(value: object, field: FieldInfo, key: str) -> object: def _get_extra_fields_type(cls: type[pydantic.BaseModel]) -> type | None: - if not PYDANTIC_V2: + if PYDANTIC_V1: # TODO return None @@ -628,30 +628,30 @@ def _build_discriminated_union_meta(*, union: type, meta_annotations: tuple[Any, for variant in get_args(union): variant = strip_annotated_type(variant) if is_basemodel_type(variant): - if PYDANTIC_V2: - field = _extract_field_schema_pv2(variant, discriminator_field_name) - if not field: + 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.get("serialization_alias") - - field_schema = field["schema"] + discriminator_alias = field_info.alias - if field_schema["type"] == "literal": - for entry in cast("LiteralSchema", field_schema)["expected"]: + 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_info = cast("dict[str, FieldInfo]", variant.__fields__).get(discriminator_field_name) # pyright: ignore[reportDeprecated, reportUnnecessaryCast] - if not field_info: + 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_info.alias + discriminator_alias = field.get("serialization_alias") - if (annotation := getattr(field_info, "annotation", None)) and is_literal_type(annotation): - for entry in get_args(annotation): + field_schema = field["schema"] + + if field_schema["type"] == "literal": + for entry in cast("LiteralSchema", field_schema)["expected"]: if isinstance(entry, str): mapping[entry] = variant @@ -714,7 +714,7 @@ class GenericModel(BaseGenericModel, BaseModel): pass -if PYDANTIC_V2: +if not PYDANTIC_V1: from pydantic import TypeAdapter as _TypeAdapter _CachedTypeAdapter = cast("TypeAdapter[object]", lru_cache(maxsize=None)(_TypeAdapter)) @@ -782,12 +782,12 @@ class FinalRequestOptions(pydantic.BaseModel): json_data: Union[Body, None] = None extra_json: Union[AnyMapping, None] = None - if PYDANTIC_V2: - model_config: ClassVar[ConfigDict] = ConfigDict(arbitrary_types_allowed=True) - else: + 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): @@ -820,9 +820,9 @@ def construct( # type: ignore key: strip_not_given(value) for key, value in values.items() } - if PYDANTIC_V2: - return super().model_construct(_fields_set, **kwargs) - return cast(FinalRequestOptions, super().construct(_fields_set, **kwargs)) # pyright: ignore[reportDeprecated] + 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 diff --git a/src/gcore/_types.py b/src/gcore/_types.py index aafdc14b..078ad89a 100644 --- a/src/gcore/_types.py +++ b/src/gcore/_types.py @@ -13,10 +13,21 @@ Mapping, TypeVar, Callable, + Iterator, Optional, Sequence, ) -from typing_extensions import Set, Literal, Protocol, TypeAlias, TypedDict, override, runtime_checkable +from typing_extensions import ( + Set, + Literal, + Protocol, + TypeAlias, + TypedDict, + SupportsIndex, + overload, + override, + runtime_checkable, +) import httpx import pydantic @@ -217,3 +228,26 @@ class _GenericAlias(Protocol): 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 + 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 index(self, value: Any, start: int = 0, stop: int = ..., /) -> int: ... + def count(self, value: Any, /) -> int: ... + 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 index d4fda26f..dc64e29a 100644 --- a/src/gcore/_utils/__init__.py +++ b/src/gcore/_utils/__init__.py @@ -10,7 +10,6 @@ lru_cache as lru_cache, is_mapping as is_mapping, is_tuple_t as is_tuple_t, - parse_date as parse_date, is_iterable as is_iterable, is_sequence as is_sequence, coerce_float as coerce_float, @@ -23,7 +22,6 @@ coerce_boolean as coerce_boolean, coerce_integer as coerce_integer, file_from_path as file_from_path, - parse_datetime as parse_datetime, strip_not_given as strip_not_given, deepcopy_minimal as deepcopy_minimal, get_async_library as get_async_library, @@ -32,12 +30,20 @@ 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, @@ -55,3 +61,4 @@ 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..dd703233 --- /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 + + +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/_transform.py b/src/gcore/_utils/_transform.py index b0cc20a7..c19124f0 100644 --- a/src/gcore/_utils/_transform.py +++ b/src/gcore/_utils/_transform.py @@ -16,18 +16,20 @@ 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, ) -from .._compat import get_origin, model_dump, is_typeddict _T = TypeVar("_T") @@ -167,6 +169,8 @@ def _transform_recursive( Defaults to the same value as the `annotation` argument. """ + from .._compat import model_dump + if inner_type is None: inner_type = annotation @@ -184,6 +188,8 @@ def _transform_recursive( (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. @@ -329,6 +335,8 @@ async def _async_transform_recursive( Defaults to the same value as the `annotation` argument. """ + from .._compat import model_dump + if inner_type is None: inner_type = annotation @@ -346,6 +354,8 @@ async def _async_transform_recursive( (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. diff --git a/src/gcore/_utils/_typing.py b/src/gcore/_utils/_typing.py index 1bac9542..193109f3 100644 --- a/src/gcore/_utils/_typing.py +++ b/src/gcore/_utils/_typing.py @@ -15,7 +15,7 @@ from ._utils import lru_cache from .._types import InheritsGeneric -from .._compat import is_union as _is_union +from ._compat import is_union as _is_union def is_annotated_type(typ: type) -> bool: @@ -26,6 +26,11 @@ 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 diff --git a/src/gcore/_utils/_utils.py b/src/gcore/_utils/_utils.py index ea3cf3f2..f0818595 100644 --- a/src/gcore/_utils/_utils.py +++ b/src/gcore/_utils/_utils.py @@ -22,7 +22,6 @@ import sniffio from .._types import NotGiven, FileTypes, NotGivenOr, HeadersLike -from .._compat import parse_date as parse_date, parse_datetime as parse_datetime _T = TypeVar("_T") _TupleT = TypeVar("_TupleT", bound=Tuple[object, ...]) diff --git a/src/gcore/_version.py b/src/gcore/_version.py index 4eb294cb..1ef4a3a8 100644 --- a/src/gcore/_version.py +++ b/src/gcore/_version.py @@ -1,4 +1,4 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. __title__ = "gcore" -__version__ = "0.10.0" # x-release-please-version +__version__ = "0.11.0" # x-release-please-version diff --git a/src/gcore/resources/__init__.py b/src/gcore/resources/__init__.py index c85f01d3..e8e92c1e 100644 --- a/src/gcore/resources/__init__.py +++ b/src/gcore/resources/__init__.py @@ -1,5 +1,13 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +from .dns import ( + DNSResource, + AsyncDNSResource, + DNSResourceWithRawResponse, + AsyncDNSResourceWithRawResponse, + DNSResourceWithStreamingResponse, + AsyncDNSResourceWithStreamingResponse, +) from .iam import ( IamResource, AsyncIamResource, @@ -24,6 +32,14 @@ CloudResourceWithStreamingResponse, AsyncCloudResourceWithStreamingResponse, ) +from .storage import ( + StorageResource, + AsyncStorageResource, + StorageResourceWithRawResponse, + AsyncStorageResourceWithRawResponse, + StorageResourceWithStreamingResponse, + AsyncStorageResourceWithStreamingResponse, +) from .fastedge import ( FastedgeResource, AsyncFastedgeResource, @@ -86,4 +102,16 @@ "AsyncSecurityResourceWithRawResponse", "SecurityResourceWithStreamingResponse", "AsyncSecurityResourceWithStreamingResponse", + "DNSResource", + "AsyncDNSResource", + "DNSResourceWithRawResponse", + "AsyncDNSResourceWithRawResponse", + "DNSResourceWithStreamingResponse", + "AsyncDNSResourceWithStreamingResponse", + "StorageResource", + "AsyncStorageResource", + "StorageResourceWithRawResponse", + "AsyncStorageResourceWithRawResponse", + "StorageResourceWithStreamingResponse", + "AsyncStorageResourceWithStreamingResponse", ] diff --git a/src/gcore/resources/cloud/__init__.py b/src/gcore/resources/cloud/__init__.py index f77715a6..c78945ec 100644 --- a/src/gcore/resources/cloud/__init__.py +++ b/src/gcore/resources/cloud/__init__.py @@ -1,5 +1,13 @@ # 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, @@ -342,6 +350,12 @@ "AsyncInstancesResourceWithRawResponse", "InstancesResourceWithStreamingResponse", "AsyncInstancesResourceWithStreamingResponse", + "K8sResource", + "AsyncK8sResource", + "K8sResourceWithRawResponse", + "AsyncK8sResourceWithRawResponse", + "K8sResourceWithStreamingResponse", + "AsyncK8sResourceWithStreamingResponse", "AuditLogsResource", "AsyncAuditLogsResource", "AuditLogsResourceWithRawResponse", diff --git a/src/gcore/resources/cloud/audit_logs.py b/src/gcore/resources/cloud/audit_logs.py index b6aa9de3..1dad329f 100644 --- a/src/gcore/resources/cloud/audit_logs.py +++ b/src/gcore/resources/cloud/audit_logs.py @@ -8,7 +8,7 @@ import httpx -from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven, SequenceNotStr from ..._utils import maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource @@ -153,7 +153,7 @@ def list( order_by: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, project_id: Iterable[int] | NotGiven = NOT_GIVEN, region_id: Iterable[int] | NotGiven = NOT_GIVEN, - resource_id: List[str] | NotGiven = NOT_GIVEN, + resource_id: SequenceNotStr[str] | NotGiven = NOT_GIVEN, search_field: str | NotGiven = NOT_GIVEN, sorting: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, to_timestamp: Union[str, datetime] | NotGiven = NOT_GIVEN, @@ -362,7 +362,7 @@ def list( order_by: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, project_id: Iterable[int] | NotGiven = NOT_GIVEN, region_id: Iterable[int] | NotGiven = NOT_GIVEN, - resource_id: List[str] | NotGiven = NOT_GIVEN, + resource_id: SequenceNotStr[str] | NotGiven = NOT_GIVEN, search_field: str | NotGiven = NOT_GIVEN, sorting: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, to_timestamp: Union[str, datetime] | NotGiven = NOT_GIVEN, diff --git a/src/gcore/resources/cloud/baremetal/images.py b/src/gcore/resources/cloud/baremetal/images.py index 147ebf85..a6a22954 100644 --- a/src/gcore/resources/cloud/baremetal/images.py +++ b/src/gcore/resources/cloud/baremetal/images.py @@ -2,12 +2,11 @@ from __future__ import annotations -from typing import List from typing_extensions import Literal import httpx -from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven, SequenceNotStr from ...._utils import maybe_transform, async_maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource @@ -51,7 +50,7 @@ def list( region_id: int | None = None, include_prices: bool | NotGiven = NOT_GIVEN, private: str | NotGiven = NOT_GIVEN, - tag_key: List[str] | NotGiven = NOT_GIVEN, + tag_key: SequenceNotStr[str] | NotGiven = NOT_GIVEN, tag_key_value: str | NotGiven = NOT_GIVEN, visibility: Literal["private", "public", "shared"] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -139,7 +138,7 @@ async def list( region_id: int | None = None, include_prices: bool | NotGiven = NOT_GIVEN, private: str | NotGiven = NOT_GIVEN, - tag_key: List[str] | NotGiven = NOT_GIVEN, + tag_key: SequenceNotStr[str] | NotGiven = NOT_GIVEN, tag_key_value: str | NotGiven = NOT_GIVEN, visibility: Literal["private", "public", "shared"] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. diff --git a/src/gcore/resources/cloud/baremetal/servers.py b/src/gcore/resources/cloud/baremetal/servers.py index 6d1588e0..d9120d43 100644 --- a/src/gcore/resources/cloud/baremetal/servers.py +++ b/src/gcore/resources/cloud/baremetal/servers.py @@ -2,13 +2,13 @@ from __future__ import annotations -from typing import Dict, List, Union, Iterable, Optional +from typing import Dict, Union, Iterable, Optional from datetime import datetime from typing_extensions import Literal import httpx -from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven, SequenceNotStr from ...._utils import maybe_transform, async_maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource @@ -206,7 +206,7 @@ def list( ] | NotGiven = NOT_GIVEN, tag_key_value: str | NotGiven = NOT_GIVEN, - tag_value: List[str] | NotGiven = NOT_GIVEN, + tag_value: SequenceNotStr[str] | NotGiven = NOT_GIVEN, type_ddos_profile: Literal["basic", "advanced"] | NotGiven = NOT_GIVEN, uuid: str | NotGiven = NOT_GIVEN, with_ddos: bool | NotGiven = NOT_GIVEN, @@ -350,6 +350,12 @@ def rebuild( 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 @@ -682,7 +688,7 @@ def list( ] | NotGiven = NOT_GIVEN, tag_key_value: str | NotGiven = NOT_GIVEN, - tag_value: List[str] | NotGiven = NOT_GIVEN, + tag_value: SequenceNotStr[str] | NotGiven = NOT_GIVEN, type_ddos_profile: Literal["basic", "advanced"] | NotGiven = NOT_GIVEN, uuid: str | NotGiven = NOT_GIVEN, with_ddos: bool | NotGiven = NOT_GIVEN, @@ -826,6 +832,12 @@ async def rebuild( 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 diff --git a/src/gcore/resources/cloud/cloud.py b/src/gcore/resources/cloud/cloud.py index 3dc3eb32..bd70d20c 100644 --- a/src/gcore/resources/cloud/cloud.py +++ b/src/gcore/resources/cloud/cloud.py @@ -10,6 +10,14 @@ TasksResourceWithStreamingResponse, AsyncTasksResourceWithStreamingResponse, ) +from .k8s.k8s import ( + K8sResource, + AsyncK8sResource, + K8sResourceWithRawResponse, + AsyncK8sResourceWithRawResponse, + K8sResourceWithStreamingResponse, + AsyncK8sResourceWithStreamingResponse, +) from .regions import ( RegionsResource, AsyncRegionsResource, @@ -297,6 +305,10 @@ def gpu_baremetal_clusters(self) -> GPUBaremetalClustersResource: 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) @@ -418,6 +430,10 @@ def gpu_baremetal_clusters(self) -> AsyncGPUBaremetalClustersResource: 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) @@ -542,6 +558,10 @@ def gpu_baremetal_clusters(self) -> GPUBaremetalClustersResourceWithRawResponse: 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) @@ -647,6 +667,10 @@ def gpu_baremetal_clusters(self) -> AsyncGPUBaremetalClustersResourceWithRawResp 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) @@ -752,6 +776,10 @@ def gpu_baremetal_clusters(self) -> GPUBaremetalClustersResourceWithStreamingRes 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) @@ -857,6 +885,10 @@ def gpu_baremetal_clusters(self) -> AsyncGPUBaremetalClustersResourceWithStreami 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) diff --git a/src/gcore/resources/cloud/cost_reports.py b/src/gcore/resources/cloud/cost_reports.py index b04695a9..36075dd6 100644 --- a/src/gcore/resources/cloud/cost_reports.py +++ b/src/gcore/resources/cloud/cost_reports.py @@ -171,13 +171,13 @@ def get_aggregated( def get_aggregated_monthly( self, *, - time_from: Union[str, datetime], - time_to: Union[str, datetime], regions: Iterable[int] | NotGiven = NOT_GIVEN, response_format: Literal["csv_totals", "json"] | NotGiven = NOT_GIVEN, rounding: bool | NotGiven = NOT_GIVEN, schema_filter: cost_report_get_aggregated_monthly_params.SchemaFilter | NotGiven = NOT_GIVEN, tags: cost_report_get_aggregated_monthly_params.Tags | NotGiven = NOT_GIVEN, + time_from: Union[str, datetime] | NotGiven = NOT_GIVEN, + time_to: Union[str, datetime] | NotGiven = NOT_GIVEN, types: List[ Literal[ "ai_cluster", @@ -208,6 +208,7 @@ def get_aggregated_monthly( ] ] | NotGiven = NOT_GIVEN, + year_month: str | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -227,10 +228,6 @@ def get_aggregated_monthly( hours until the servers are back online and the missing data is filled in. Args: - time_from: Beginning of the period: YYYY-mm - - time_to: End of the period: YYYY-mm - regions: List of region IDs. response_format: Format of the response (`csv_totals` or json). @@ -241,8 +238,14 @@ def get_aggregated_monthly( 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 @@ -255,14 +258,15 @@ def get_aggregated_monthly( "/cloud/v1/reservation_cost_report/totals", body=maybe_transform( { - "time_from": time_from, - "time_to": time_to, "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, ), @@ -543,13 +547,13 @@ async def get_aggregated( async def get_aggregated_monthly( self, *, - time_from: Union[str, datetime], - time_to: Union[str, datetime], regions: Iterable[int] | NotGiven = NOT_GIVEN, response_format: Literal["csv_totals", "json"] | NotGiven = NOT_GIVEN, rounding: bool | NotGiven = NOT_GIVEN, schema_filter: cost_report_get_aggregated_monthly_params.SchemaFilter | NotGiven = NOT_GIVEN, tags: cost_report_get_aggregated_monthly_params.Tags | NotGiven = NOT_GIVEN, + time_from: Union[str, datetime] | NotGiven = NOT_GIVEN, + time_to: Union[str, datetime] | NotGiven = NOT_GIVEN, types: List[ Literal[ "ai_cluster", @@ -580,6 +584,7 @@ async def get_aggregated_monthly( ] ] | NotGiven = NOT_GIVEN, + year_month: str | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -599,10 +604,6 @@ async def get_aggregated_monthly( hours until the servers are back online and the missing data is filled in. Args: - time_from: Beginning of the period: YYYY-mm - - time_to: End of the period: YYYY-mm - regions: List of region IDs. response_format: Format of the response (`csv_totals` or json). @@ -613,8 +614,14 @@ async def get_aggregated_monthly( 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 @@ -627,14 +634,15 @@ async def get_aggregated_monthly( "/cloud/v1/reservation_cost_report/totals", body=await async_maybe_transform( { - "time_from": time_from, - "time_to": time_to, "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, ), diff --git a/src/gcore/resources/cloud/file_shares/access_rules.py b/src/gcore/resources/cloud/file_shares/access_rules.py index 21ba3f40..34cc65ee 100644 --- a/src/gcore/resources/cloud/file_shares/access_rules.py +++ b/src/gcore/resources/cloud/file_shares/access_rules.py @@ -116,7 +116,7 @@ def list( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> AccessRuleList: """ - Get file share access rules + List file share access rules Args: project_id: Project ID @@ -291,7 +291,7 @@ async def list( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> AccessRuleList: """ - Get file share access rules + List file share access rules Args: project_id: Project ID diff --git a/src/gcore/resources/cloud/file_shares/file_shares.py b/src/gcore/resources/cloud/file_shares/file_shares.py index f04a3c4f..99a806d5 100644 --- a/src/gcore/resources/cloud/file_shares/file_shares.py +++ b/src/gcore/resources/cloud/file_shares/file_shares.py @@ -76,6 +76,7 @@ def create( size: int, access: Iterable[file_share_create_params.CreateStandardFileShareSerializerAccess] | NotGiven = NOT_GIVEN, tags: Dict[str, str] | NotGiven = NOT_GIVEN, + type_name: Literal["standard"] | NotGiven = NOT_GIVEN, volume_type: Literal["default_share_type"] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -98,7 +99,7 @@ def create( protocol: File share protocol - size: File share size + size: File share size in GiB access: Access Rules @@ -108,7 +109,9 @@ def create( 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: File share volume type + type_name: Standard file share type + + volume_type: Deprecated. Use `type_name` instead. extra_headers: Send extra headers @@ -129,9 +132,10 @@ def create( name: str, protocol: Literal["NFS"], size: int, - volume_type: Literal["vast_share_type"], share_settings: file_share_create_params.CreateVastFileShareSerializerShareSettings | NotGiven = NOT_GIVEN, tags: Dict[str, str] | NotGiven = NOT_GIVEN, + type_name: Literal["vast"] | NotGiven = NOT_GIVEN, + volume_type: Literal["vast_share_type"] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -151,9 +155,7 @@ def create( protocol: File share protocol - size: File share size - - volume_type: File share volume type + size: File share size in GiB share_settings: Configuration settings for the share @@ -163,6 +165,10 @@ def create( 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 @@ -173,7 +179,7 @@ def create( """ ... - @required_args(["name", "network", "protocol", "size"], ["name", "protocol", "size", "volume_type"]) + @required_args(["name", "network", "protocol", "size"], ["name", "protocol", "size"]) def create( self, *, @@ -185,6 +191,7 @@ def create( size: int, access: Iterable[file_share_create_params.CreateStandardFileShareSerializerAccess] | NotGiven = NOT_GIVEN, tags: Dict[str, str] | NotGiven = NOT_GIVEN, + type_name: Literal["standard"] | Literal["vast"] | NotGiven = NOT_GIVEN, volume_type: Literal["default_share_type"] | Literal["vast_share_type"] | NotGiven = NOT_GIVEN, share_settings: file_share_create_params.CreateVastFileShareSerializerShareSettings | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -208,6 +215,7 @@ def create( "size": size, "access": access, "tags": tags, + "type_name": type_name, "volume_type": volume_type, "share_settings": share_settings, }, @@ -537,6 +545,7 @@ async def create( size: int, access: Iterable[file_share_create_params.CreateStandardFileShareSerializerAccess] | NotGiven = NOT_GIVEN, tags: Dict[str, str] | NotGiven = NOT_GIVEN, + type_name: Literal["standard"] | NotGiven = NOT_GIVEN, volume_type: Literal["default_share_type"] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -559,7 +568,7 @@ async def create( protocol: File share protocol - size: File share size + size: File share size in GiB access: Access Rules @@ -569,7 +578,9 @@ async def create( 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: File share volume type + type_name: Standard file share type + + volume_type: Deprecated. Use `type_name` instead. extra_headers: Send extra headers @@ -590,9 +601,10 @@ async def create( name: str, protocol: Literal["NFS"], size: int, - volume_type: Literal["vast_share_type"], share_settings: file_share_create_params.CreateVastFileShareSerializerShareSettings | NotGiven = NOT_GIVEN, tags: Dict[str, str] | NotGiven = NOT_GIVEN, + type_name: Literal["vast"] | NotGiven = NOT_GIVEN, + volume_type: Literal["vast_share_type"] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -612,9 +624,7 @@ async def create( protocol: File share protocol - size: File share size - - volume_type: File share volume type + size: File share size in GiB share_settings: Configuration settings for the share @@ -624,6 +634,10 @@ async def create( 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 @@ -634,7 +648,7 @@ async def create( """ ... - @required_args(["name", "network", "protocol", "size"], ["name", "protocol", "size", "volume_type"]) + @required_args(["name", "network", "protocol", "size"], ["name", "protocol", "size"]) async def create( self, *, @@ -646,6 +660,7 @@ async def create( size: int, access: Iterable[file_share_create_params.CreateStandardFileShareSerializerAccess] | NotGiven = NOT_GIVEN, tags: Dict[str, str] | NotGiven = NOT_GIVEN, + type_name: Literal["standard"] | Literal["vast"] | NotGiven = NOT_GIVEN, volume_type: Literal["default_share_type"] | Literal["vast_share_type"] | NotGiven = NOT_GIVEN, share_settings: file_share_create_params.CreateVastFileShareSerializerShareSettings | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -669,6 +684,7 @@ async def create( "size": size, "access": access, "tags": tags, + "type_name": type_name, "volume_type": volume_type, "share_settings": share_settings, }, diff --git a/src/gcore/resources/cloud/floating_ips.py b/src/gcore/resources/cloud/floating_ips.py index 3bbb8930..85d1e774 100644 --- a/src/gcore/resources/cloud/floating_ips.py +++ b/src/gcore/resources/cloud/floating_ips.py @@ -2,11 +2,11 @@ from __future__ import annotations -from typing import Dict, List, Optional +from typing import Dict, Optional import httpx -from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven, SequenceNotStr from ..._utils import maybe_transform, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource @@ -116,7 +116,7 @@ def list( region_id: int | None = None, limit: int | NotGiven = NOT_GIVEN, offset: int | NotGiven = NOT_GIVEN, - tag_key: List[str] | NotGiven = NOT_GIVEN, + tag_key: SequenceNotStr[str] | NotGiven = NOT_GIVEN, tag_key_value: str | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -344,6 +344,90 @@ def unassign( cast_to=FloatingIP, ) + def create_and_poll( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + fixed_ip_address: Optional[str] | NotGiven = NOT_GIVEN, + port_id: Optional[str] | NotGiven = NOT_GIVEN, + tags: Dict[str, str] | NotGiven = NOT_GIVEN, + polling_interval_seconds: int | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + ) -> FloatingIP: + """ + Create floating IP and poll for the result. Only the first task will be polled. If you need to poll more tasks, use the `tasks.poll` method. + """ + response = self.create( + project_id=project_id, + region_id=region_id, + fixed_ip_address=fixed_ip_address, + port_id=port_id, + tags=tags, + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + ) + if not response.tasks: + raise ValueError("Expected at least one task to be created") + task = self._client.cloud.tasks.poll( + task_id=response.tasks[0], + extra_headers=extra_headers, + polling_interval_seconds=polling_interval_seconds, + ) + if task.created_resources is None or task.created_resources.floatingips is None: + raise ValueError("Task completed but created_resources or floatingips is missing") + floating_ip_id = task.created_resources.floatingips[0] + return self.get( + floating_ip_id=floating_ip_id, + project_id=project_id, + region_id=region_id, + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + ) + + def delete_and_poll( + self, + floating_ip_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + polling_interval_seconds: int | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + ) -> None: + """ + Delete floating IP and poll for the result. Only the first task will be polled. If you need to poll more tasks, use the `tasks.poll` method. + """ + response = self.delete( + floating_ip_id=floating_ip_id, + project_id=project_id, + region_id=region_id, + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + ) + if not response.tasks: + raise ValueError("Expected at least one task to be created") + self._client.cloud.tasks.poll( + task_id=response.tasks[0], + extra_headers=extra_headers, + polling_interval_seconds=polling_interval_seconds, + ) + class AsyncFloatingIPsResource(AsyncAPIResource): @cached_property @@ -435,7 +519,7 @@ def list( region_id: int | None = None, limit: int | NotGiven = NOT_GIVEN, offset: int | NotGiven = NOT_GIVEN, - tag_key: List[str] | NotGiven = NOT_GIVEN, + tag_key: SequenceNotStr[str] | NotGiven = NOT_GIVEN, tag_key_value: str | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -663,6 +747,90 @@ async def unassign( cast_to=FloatingIP, ) + async def create_and_poll( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + fixed_ip_address: Optional[str] | NotGiven = NOT_GIVEN, + port_id: Optional[str] | NotGiven = NOT_GIVEN, + tags: Dict[str, str] | NotGiven = NOT_GIVEN, + polling_interval_seconds: int | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + ) -> FloatingIP: + """ + Create floating IP and poll for the result. Only the first task will be polled. If you need to poll more tasks, use the `tasks.poll` method. + """ + response = await self.create( + project_id=project_id, + region_id=region_id, + fixed_ip_address=fixed_ip_address, + port_id=port_id, + tags=tags, + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + ) + if not response.tasks: + raise ValueError("Expected at least one task to be created") + task = await self._client.cloud.tasks.poll( + task_id=response.tasks[0], + extra_headers=extra_headers, + polling_interval_seconds=polling_interval_seconds, + ) + if task.created_resources is None or task.created_resources.floatingips is None: + raise ValueError("Task completed but created_resources or floatingips is missing") + floating_ip_id = task.created_resources.floatingips[0] + return await self.get( + floating_ip_id=floating_ip_id, + project_id=project_id, + region_id=region_id, + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + ) + + async def delete_and_poll( + self, + floating_ip_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + polling_interval_seconds: int | NotGiven = NOT_GIVEN, + timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + ) -> None: + """ + Delete floating IP and poll for the result. Only the first task will be polled. If you need to poll more tasks, use the `tasks.poll` method. + """ + response = await self.delete( + floating_ip_id=floating_ip_id, + project_id=project_id, + region_id=region_id, + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + ) + if not response.tasks: + raise ValueError("Expected at least one task to be created") + await self._client.cloud.tasks.poll( + task_id=response.tasks[0], + extra_headers=extra_headers, + polling_interval_seconds=polling_interval_seconds, + ) + class FloatingIPsResourceWithRawResponse: def __init__(self, floating_ips: FloatingIPsResource) -> None: @@ -686,6 +854,12 @@ def __init__(self, floating_ips: FloatingIPsResource) -> None: self.unassign = to_raw_response_wrapper( floating_ips.unassign, ) + self.create_and_poll = to_raw_response_wrapper( + floating_ips.create_and_poll, + ) + self.delete_and_poll = to_raw_response_wrapper( + floating_ips.delete_and_poll, + ) class AsyncFloatingIPsResourceWithRawResponse: @@ -710,6 +884,12 @@ def __init__(self, floating_ips: AsyncFloatingIPsResource) -> None: self.unassign = async_to_raw_response_wrapper( floating_ips.unassign, ) + self.create_and_poll = async_to_raw_response_wrapper( + floating_ips.create_and_poll, + ) + self.delete_and_poll = async_to_raw_response_wrapper( + floating_ips.delete_and_poll, + ) class FloatingIPsResourceWithStreamingResponse: @@ -734,6 +914,12 @@ def __init__(self, floating_ips: FloatingIPsResource) -> None: self.unassign = to_streamed_response_wrapper( floating_ips.unassign, ) + self.create_and_poll = to_streamed_response_wrapper( + floating_ips.create_and_poll, + ) + self.delete_and_poll = to_streamed_response_wrapper( + floating_ips.delete_and_poll, + ) class AsyncFloatingIPsResourceWithStreamingResponse: @@ -758,3 +944,9 @@ def __init__(self, floating_ips: AsyncFloatingIPsResource) -> None: self.unassign = async_to_streamed_response_wrapper( floating_ips.unassign, ) + self.create_and_poll = async_to_streamed_response_wrapper( + floating_ips.create_and_poll, + ) + self.delete_and_poll = async_to_streamed_response_wrapper( + floating_ips.delete_and_poll, + ) diff --git a/src/gcore/resources/cloud/gpu_baremetal_clusters/flavors.py b/src/gcore/resources/cloud/gpu_baremetal_clusters/flavors.py index abe8d9ef..2c4563b5 100644 --- a/src/gcore/resources/cloud/gpu_baremetal_clusters/flavors.py +++ b/src/gcore/resources/cloud/gpu_baremetal_clusters/flavors.py @@ -16,7 +16,7 @@ ) from ...._base_client import make_request_options from ....types.cloud.gpu_baremetal_clusters import flavor_list_params -from ....types.cloud.gpu_baremetal_flavor_list import GPUBaremetalFlavorList +from ....types.cloud.gpu_baremetal_clusters.gpu_baremetal_flavor_list import GPUBaremetalFlavorList __all__ = ["FlavorsResource", "AsyncFlavorsResource"] diff --git a/src/gcore/resources/cloud/gpu_baremetal_clusters/gpu_baremetal_clusters.py b/src/gcore/resources/cloud/gpu_baremetal_clusters/gpu_baremetal_clusters.py index 795a1a13..6a040f84 100644 --- a/src/gcore/resources/cloud/gpu_baremetal_clusters/gpu_baremetal_clusters.py +++ b/src/gcore/resources/cloud/gpu_baremetal_clusters/gpu_baremetal_clusters.py @@ -2,8 +2,8 @@ from __future__ import annotations -import typing_extensions -from typing import Dict, List, Iterable, Optional +from typing import Dict, List, Optional +from typing_extensions import Literal import httpx @@ -31,7 +31,7 @@ ServersResourceWithStreamingResponse, AsyncServersResourceWithStreamingResponse, ) -from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven, SequenceNotStr from ...._utils import maybe_transform, async_maybe_transform from ...._compat import cached_property from .interfaces import ( @@ -60,7 +60,7 @@ from ...._base_client import AsyncPaginator, make_request_options from ....types.cloud.task_id_list import TaskIDList from ....types.cloud.gpu_baremetal_cluster import GPUBaremetalCluster -from ....types.cloud.gpu_baremetal_cluster_server_list import GPUBaremetalClusterServerList +from ....types.cloud.gpu_baremetal_clusters.gpu_baremetal_cluster_server_v1_list import GPUBaremetalClusterServerV1List __all__ = ["GPUBaremetalClustersResource", "AsyncGPUBaremetalClustersResource"] @@ -108,15 +108,10 @@ def create( region_id: int | None = None, flavor: str, image_id: str, - interfaces: Iterable[gpu_baremetal_cluster_create_params.Interface], name: str, - instances_count: int | NotGiven = NOT_GIVEN, - password: str | NotGiven = NOT_GIVEN, - security_groups: Iterable[gpu_baremetal_cluster_create_params.SecurityGroup] | NotGiven = NOT_GIVEN, - ssh_key_name: str | NotGiven = NOT_GIVEN, + servers_count: int, + servers_settings: gpu_baremetal_cluster_create_params.ServersSettings, tags: Dict[str, str] | NotGiven = NOT_GIVEN, - user_data: str | NotGiven = NOT_GIVEN, - username: str | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -124,31 +119,23 @@ def create( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> TaskIDList: - """Create a new GPU cluster with specified configuration. - - The cluster can be - created with one or more nodes. + """ + Create a new bare metal GPU cluster with the specified configuration. Args: - flavor: Flavor name - - image_id: Image ID + project_id: Project ID - interfaces: A list of network interfaces for the server. You can create one or more - interfaces - private, public, or both. + region_id: Region ID - name: GPU Cluster name + flavor: Cluster flavor ID - instances_count: Number of servers to create + image_id: System image ID - password: A password for a bare metal server. This parameter is used to set a password for - the "Admin" user on a Windows instance, a default user or a new user on a Linux - instance + name: Cluster name - security_groups: Security group UUIDs + servers_count: Number of servers in the cluster - 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). + 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 @@ -156,13 +143,6 @@ def create( 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. Must not be passed together with 'username' or - 'password'. Examples of the `user_data`: - https://cloudinit.readthedocs.io/en/latest/topics/examples.html - - username: A name of a new user in the Linux instance. It may be passed with a 'password' - parameter - extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -176,20 +156,15 @@ def create( if region_id is None: region_id = self._client._get_cloud_region_id_path_param() return self._post( - f"/cloud/v1/ai/clusters/gpu/{project_id}/{region_id}", + f"/cloud/v3/gpu/baremetal/{project_id}/{region_id}/clusters", body=maybe_transform( { "flavor": flavor, "image_id": image_id, - "interfaces": interfaces, "name": name, - "instances_count": instances_count, - "password": password, - "security_groups": security_groups, - "ssh_key_name": ssh_key_name, + "servers_count": servers_count, + "servers_settings": servers_settings, "tags": tags, - "user_data": user_data, - "username": username, }, gpu_baremetal_cluster_create_params.GPUBaremetalClusterCreateParams, ), @@ -199,13 +174,13 @@ def create( cast_to=TaskIDList, ) - @typing_extensions.deprecated("deprecated") def list( self, *, project_id: int | None = None, region_id: int | None = None, limit: int | NotGiven = NOT_GIVEN, + managed_by: List[Literal["k8s", "user"]] | NotGiven = NOT_GIVEN, offset: int | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -215,13 +190,22 @@ def list( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> SyncOffsetPage[GPUBaremetalCluster]: """ - Please use the `/v3/gpu/baremetal/{`project_id`}/{`region_id`}/clusters` - instead. + List all bare metal GPU clusters in the specified project and region. Args: - limit: Limit the number of returned clusters + 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. - offset: Offset value is used to exclude the first set of records from the result + - `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 @@ -236,7 +220,7 @@ def list( if region_id is None: region_id = self._client._get_cloud_region_id_path_param() return self._get_api_list( - f"/cloud/v2/ai/clusters/{project_id}/{region_id}", + f"/cloud/v3/gpu/baremetal/{project_id}/{region_id}/clusters", page=SyncOffsetPage[GPUBaremetalCluster], options=make_request_options( extra_headers=extra_headers, @@ -246,6 +230,7 @@ def list( query=maybe_transform( { "limit": limit, + "managed_by": managed_by, "offset": offset, }, gpu_baremetal_cluster_list_params.GPUBaremetalClusterListParams, @@ -260,9 +245,10 @@ def delete( *, project_id: int | None = None, region_id: int | None = None, - delete_floatings: bool | NotGiven = NOT_GIVEN, - floatings: str | NotGiven = NOT_GIVEN, - reserved_fixed_ips: str | NotGiven = NOT_GIVEN, + all_floating_ips: bool | NotGiven = NOT_GIVEN, + all_reserved_fixed_ips: bool | NotGiven = NOT_GIVEN, + floating_ip_ids: SequenceNotStr[str] | NotGiven = NOT_GIVEN, + reserved_fixed_ip_ids: SequenceNotStr[str] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -271,16 +257,24 @@ def delete( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> TaskIDList: """ - Delete bare metal GPU cluster + Delete a bare metal GPU cluster and all its associated resources. Args: - delete_floatings: True if it is required to delete floating IPs assigned to the servers. Can't be - used with floatings. + 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 - floatings: Comma separated list of floating ids that should be deleted. Can't be used with - `delete_floatings`. + floating_ip_ids: Optional list of floating ips to be deleted - reserved_fixed_ips: Comma separated list of port IDs to be deleted with the servers + reserved_fixed_ip_ids: Optional list of reserved fixed ips to be deleted extra_headers: Send extra headers @@ -297,7 +291,7 @@ def delete( 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/v2/ai/clusters/{project_id}/{region_id}/{cluster_id}", + f"/cloud/v3/gpu/baremetal/{project_id}/{region_id}/clusters/{cluster_id}", options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -305,9 +299,10 @@ def delete( timeout=timeout, query=maybe_transform( { - "delete_floatings": delete_floatings, - "floatings": floatings, - "reserved_fixed_ips": reserved_fixed_ips, + "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, }, gpu_baremetal_cluster_delete_params.GPUBaremetalClusterDeleteParams, ), @@ -315,7 +310,6 @@ def delete( cast_to=TaskIDList, ) - @typing_extensions.deprecated("deprecated") def get( self, cluster_id: str, @@ -330,11 +324,15 @@ def get( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> GPUBaremetalCluster: """ - Please use the - `/v3/gpu/baremetal/{`project_id`}/{`region_id`}/clusters/{`cluster_id`}` - instead. + 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 @@ -350,7 +348,7 @@ def get( 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/v2/ai/clusters/{project_id}/{region_id}/{cluster_id}", + 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 ), @@ -369,7 +367,7 @@ def powercycle_all_servers( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> GPUBaremetalClusterServerList: + ) -> GPUBaremetalClusterServerV1List: """ Stops and then starts all cluster servers, effectively performing a hard reboot. @@ -393,7 +391,7 @@ def powercycle_all_servers( options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=GPUBaremetalClusterServerList, + cast_to=GPUBaremetalClusterServerV1List, ) def reboot_all_servers( @@ -408,7 +406,7 @@ def reboot_all_servers( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> GPUBaremetalClusterServerList: + ) -> GPUBaremetalClusterServerV1List: """ Reboot all bare metal GPU cluster servers @@ -432,7 +430,7 @@ def reboot_all_servers( options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=GPUBaremetalClusterServerList, + cast_to=GPUBaremetalClusterServerV1List, ) def rebuild( @@ -441,7 +439,7 @@ def rebuild( *, project_id: int | None = None, region_id: int | None = None, - nodes: List[str], + nodes: SequenceNotStr[str], image_id: Optional[str] | NotGiven = NOT_GIVEN, user_data: Optional[str] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -550,10 +548,9 @@ def create_and_poll( region_id: int | None = None, flavor: str, image_id: str, - interfaces: Iterable[gpu_baremetal_cluster_create_params.Interface], name: str, - instances_count: int | NotGiven = NOT_GIVEN, - ssh_key_name: str | NotGiven = NOT_GIVEN, + servers_count: int, + servers_settings: gpu_baremetal_cluster_create_params.ServersSettings, tags: Dict[str, str] | NotGiven = NOT_GIVEN, polling_interval_seconds: int | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -571,10 +568,9 @@ def create_and_poll( region_id=region_id, flavor=flavor, image_id=image_id, - interfaces=interfaces, name=name, - instances_count=instances_count, - ssh_key_name=ssh_key_name, + servers_count=servers_count, + servers_settings=servers_settings, tags=tags, extra_headers=extra_headers, extra_query=extra_query, @@ -593,7 +589,7 @@ def create_and_poll( if not task.created_resources or not task.created_resources.ai_clusters: raise ValueError("No cluster was created") cluster_id = task.created_resources.ai_clusters[0] - return self.get( # pyright: ignore[reportDeprecated] + return self.get( # pyright: ignore[reportDeprecated] cluster_id=cluster_id, project_id=project_id, region_id=region_id, @@ -644,7 +640,7 @@ def rebuild_and_poll( extra_body=extra_body, polling_interval_seconds=polling_interval_seconds, ) - return self.get( # pyright: ignore[reportDeprecated] + return self.get( # pyright: ignore[reportDeprecated] cluster_id=cluster_id, project_id=project_id, region_id=region_id, @@ -691,7 +687,7 @@ def resize_and_poll( extra_body=extra_body, polling_interval_seconds=polling_interval_seconds, ) - return self.get( # pyright: ignore[reportDeprecated] + return self.get( # pyright: ignore[reportDeprecated] cluster_id=cluster_id, project_id=project_id, region_id=region_id, @@ -745,15 +741,10 @@ async def create( region_id: int | None = None, flavor: str, image_id: str, - interfaces: Iterable[gpu_baremetal_cluster_create_params.Interface], name: str, - instances_count: int | NotGiven = NOT_GIVEN, - password: str | NotGiven = NOT_GIVEN, - security_groups: Iterable[gpu_baremetal_cluster_create_params.SecurityGroup] | NotGiven = NOT_GIVEN, - ssh_key_name: str | NotGiven = NOT_GIVEN, + servers_count: int, + servers_settings: gpu_baremetal_cluster_create_params.ServersSettings, tags: Dict[str, str] | NotGiven = NOT_GIVEN, - user_data: str | NotGiven = NOT_GIVEN, - username: str | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -761,31 +752,23 @@ async def create( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> TaskIDList: - """Create a new GPU cluster with specified configuration. - - The cluster can be - created with one or more nodes. + """ + Create a new bare metal GPU cluster with the specified configuration. Args: - flavor: Flavor name - - image_id: Image ID + project_id: Project ID - interfaces: A list of network interfaces for the server. You can create one or more - interfaces - private, public, or both. + region_id: Region ID - name: GPU Cluster name + flavor: Cluster flavor ID - instances_count: Number of servers to create + image_id: System image ID - password: A password for a bare metal server. This parameter is used to set a password for - the "Admin" user on a Windows instance, a default user or a new user on a Linux - instance + name: Cluster name - security_groups: Security group UUIDs + servers_count: Number of servers in the cluster - 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). + 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 @@ -793,13 +776,6 @@ async def create( 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. Must not be passed together with 'username' or - 'password'. Examples of the `user_data`: - https://cloudinit.readthedocs.io/en/latest/topics/examples.html - - username: A name of a new user in the Linux instance. It may be passed with a 'password' - parameter - extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -813,20 +789,15 @@ async def create( if region_id is None: region_id = self._client._get_cloud_region_id_path_param() return await self._post( - f"/cloud/v1/ai/clusters/gpu/{project_id}/{region_id}", + f"/cloud/v3/gpu/baremetal/{project_id}/{region_id}/clusters", body=await async_maybe_transform( { "flavor": flavor, "image_id": image_id, - "interfaces": interfaces, "name": name, - "instances_count": instances_count, - "password": password, - "security_groups": security_groups, - "ssh_key_name": ssh_key_name, + "servers_count": servers_count, + "servers_settings": servers_settings, "tags": tags, - "user_data": user_data, - "username": username, }, gpu_baremetal_cluster_create_params.GPUBaremetalClusterCreateParams, ), @@ -836,13 +807,13 @@ async def create( cast_to=TaskIDList, ) - @typing_extensions.deprecated("deprecated") def list( self, *, project_id: int | None = None, region_id: int | None = None, limit: int | NotGiven = NOT_GIVEN, + managed_by: List[Literal["k8s", "user"]] | NotGiven = NOT_GIVEN, offset: int | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -852,13 +823,22 @@ def list( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> AsyncPaginator[GPUBaremetalCluster, AsyncOffsetPage[GPUBaremetalCluster]]: """ - Please use the `/v3/gpu/baremetal/{`project_id`}/{`region_id`}/clusters` - instead. + List all bare metal GPU clusters in the specified project and region. Args: - limit: Limit the number of returned clusters + 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. - offset: Offset value is used to exclude the first set of records from the result + - `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 @@ -873,7 +853,7 @@ def list( if region_id is None: region_id = self._client._get_cloud_region_id_path_param() return self._get_api_list( - f"/cloud/v2/ai/clusters/{project_id}/{region_id}", + f"/cloud/v3/gpu/baremetal/{project_id}/{region_id}/clusters", page=AsyncOffsetPage[GPUBaremetalCluster], options=make_request_options( extra_headers=extra_headers, @@ -883,6 +863,7 @@ def list( query=maybe_transform( { "limit": limit, + "managed_by": managed_by, "offset": offset, }, gpu_baremetal_cluster_list_params.GPUBaremetalClusterListParams, @@ -897,9 +878,10 @@ async def delete( *, project_id: int | None = None, region_id: int | None = None, - delete_floatings: bool | NotGiven = NOT_GIVEN, - floatings: str | NotGiven = NOT_GIVEN, - reserved_fixed_ips: str | NotGiven = NOT_GIVEN, + all_floating_ips: bool | NotGiven = NOT_GIVEN, + all_reserved_fixed_ips: bool | NotGiven = NOT_GIVEN, + floating_ip_ids: SequenceNotStr[str] | NotGiven = NOT_GIVEN, + reserved_fixed_ip_ids: SequenceNotStr[str] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -908,16 +890,24 @@ async def delete( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> TaskIDList: """ - Delete bare metal GPU cluster + Delete a bare metal GPU cluster and all its associated resources. Args: - delete_floatings: True if it is required to delete floating IPs assigned to the servers. Can't be - used with floatings. + 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 - floatings: Comma separated list of floating ids that should be deleted. Can't be used with - `delete_floatings`. + floating_ip_ids: Optional list of floating ips to be deleted - reserved_fixed_ips: Comma separated list of port IDs to be deleted with the servers + reserved_fixed_ip_ids: Optional list of reserved fixed ips to be deleted extra_headers: Send extra headers @@ -934,7 +924,7 @@ async def delete( 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/v2/ai/clusters/{project_id}/{region_id}/{cluster_id}", + f"/cloud/v3/gpu/baremetal/{project_id}/{region_id}/clusters/{cluster_id}", options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, @@ -942,9 +932,10 @@ async def delete( timeout=timeout, query=await async_maybe_transform( { - "delete_floatings": delete_floatings, - "floatings": floatings, - "reserved_fixed_ips": reserved_fixed_ips, + "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, }, gpu_baremetal_cluster_delete_params.GPUBaremetalClusterDeleteParams, ), @@ -952,7 +943,6 @@ async def delete( cast_to=TaskIDList, ) - @typing_extensions.deprecated("deprecated") async def get( self, cluster_id: str, @@ -967,11 +957,15 @@ async def get( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> GPUBaremetalCluster: """ - Please use the - `/v3/gpu/baremetal/{`project_id`}/{`region_id`}/clusters/{`cluster_id`}` - instead. + 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 @@ -987,7 +981,7 @@ async def get( 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/v2/ai/clusters/{project_id}/{region_id}/{cluster_id}", + 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 ), @@ -1006,7 +1000,7 @@ async def powercycle_all_servers( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> GPUBaremetalClusterServerList: + ) -> GPUBaremetalClusterServerV1List: """ Stops and then starts all cluster servers, effectively performing a hard reboot. @@ -1030,7 +1024,7 @@ async def powercycle_all_servers( options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=GPUBaremetalClusterServerList, + cast_to=GPUBaremetalClusterServerV1List, ) async def reboot_all_servers( @@ -1045,7 +1039,7 @@ async def reboot_all_servers( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> GPUBaremetalClusterServerList: + ) -> GPUBaremetalClusterServerV1List: """ Reboot all bare metal GPU cluster servers @@ -1069,7 +1063,7 @@ async def reboot_all_servers( options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=GPUBaremetalClusterServerList, + cast_to=GPUBaremetalClusterServerV1List, ) async def rebuild( @@ -1078,7 +1072,7 @@ async def rebuild( *, project_id: int | None = None, region_id: int | None = None, - nodes: List[str], + nodes: SequenceNotStr[str], image_id: Optional[str] | NotGiven = NOT_GIVEN, user_data: Optional[str] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -1187,10 +1181,9 @@ async def create_and_poll( region_id: int | None = None, flavor: str, image_id: str, - interfaces: Iterable[gpu_baremetal_cluster_create_params.Interface], name: str, - instances_count: int | NotGiven = NOT_GIVEN, - ssh_key_name: str | NotGiven = NOT_GIVEN, + servers_count: int, + servers_settings: gpu_baremetal_cluster_create_params.ServersSettings, tags: Dict[str, str] | NotGiven = NOT_GIVEN, polling_interval_seconds: int | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -1208,10 +1201,9 @@ async def create_and_poll( region_id=region_id, flavor=flavor, image_id=image_id, - interfaces=interfaces, name=name, - instances_count=instances_count, - ssh_key_name=ssh_key_name, + servers_count=servers_count, + servers_settings=servers_settings, tags=tags, extra_headers=extra_headers, extra_query=extra_query, @@ -1230,7 +1222,7 @@ async def create_and_poll( if not task.created_resources or not task.created_resources.ai_clusters: raise ValueError("No cluster was created") cluster_id = task.created_resources.ai_clusters[0] - return await self.get( # pyright: ignore[reportDeprecated] + return await self.get( # pyright: ignore[reportDeprecated] cluster_id=cluster_id, project_id=project_id, region_id=region_id, @@ -1281,7 +1273,7 @@ async def rebuild_and_poll( extra_body=extra_body, polling_interval_seconds=polling_interval_seconds, ) - return await self.get( # pyright: ignore[reportDeprecated] + return await self.get( # pyright: ignore[reportDeprecated] cluster_id=cluster_id, project_id=project_id, region_id=region_id, @@ -1328,7 +1320,7 @@ async def resize_and_poll( extra_body=extra_body, polling_interval_seconds=polling_interval_seconds, ) - return await self.get( # pyright: ignore[reportDeprecated] + return await self.get( # pyright: ignore[reportDeprecated] cluster_id=cluster_id, project_id=project_id, region_id=region_id, @@ -1346,18 +1338,14 @@ def __init__(self, gpu_baremetal_clusters: GPUBaremetalClustersResource) -> None self.create = to_raw_response_wrapper( gpu_baremetal_clusters.create, ) - self.list = ( # pyright: ignore[reportDeprecated] - to_raw_response_wrapper( - gpu_baremetal_clusters.list # pyright: ignore[reportDeprecated], - ) + self.list = to_raw_response_wrapper( + gpu_baremetal_clusters.list, ) self.delete = to_raw_response_wrapper( gpu_baremetal_clusters.delete, ) - self.get = ( # pyright: ignore[reportDeprecated] - to_raw_response_wrapper( - gpu_baremetal_clusters.get # pyright: ignore[reportDeprecated], - ) + self.get = to_raw_response_wrapper( + gpu_baremetal_clusters.get, ) self.powercycle_all_servers = to_raw_response_wrapper( gpu_baremetal_clusters.powercycle_all_servers, @@ -1396,18 +1384,14 @@ def __init__(self, gpu_baremetal_clusters: AsyncGPUBaremetalClustersResource) -> self.create = async_to_raw_response_wrapper( gpu_baremetal_clusters.create, ) - self.list = ( # pyright: ignore[reportDeprecated] - async_to_raw_response_wrapper( - gpu_baremetal_clusters.list # pyright: ignore[reportDeprecated], - ) + self.list = async_to_raw_response_wrapper( + gpu_baremetal_clusters.list, ) self.delete = async_to_raw_response_wrapper( gpu_baremetal_clusters.delete, ) - self.get = ( # pyright: ignore[reportDeprecated] - async_to_raw_response_wrapper( - gpu_baremetal_clusters.get # pyright: ignore[reportDeprecated], - ) + self.get = async_to_raw_response_wrapper( + gpu_baremetal_clusters.get, ) self.powercycle_all_servers = async_to_raw_response_wrapper( gpu_baremetal_clusters.powercycle_all_servers, @@ -1446,18 +1430,14 @@ def __init__(self, gpu_baremetal_clusters: GPUBaremetalClustersResource) -> None self.create = to_streamed_response_wrapper( gpu_baremetal_clusters.create, ) - self.list = ( # pyright: ignore[reportDeprecated] - to_streamed_response_wrapper( - gpu_baremetal_clusters.list # pyright: ignore[reportDeprecated], - ) + self.list = to_streamed_response_wrapper( + gpu_baremetal_clusters.list, ) self.delete = to_streamed_response_wrapper( gpu_baremetal_clusters.delete, ) - self.get = ( # pyright: ignore[reportDeprecated] - to_streamed_response_wrapper( - gpu_baremetal_clusters.get # pyright: ignore[reportDeprecated], - ) + self.get = to_streamed_response_wrapper( + gpu_baremetal_clusters.get, ) self.powercycle_all_servers = to_streamed_response_wrapper( gpu_baremetal_clusters.powercycle_all_servers, @@ -1496,18 +1476,14 @@ def __init__(self, gpu_baremetal_clusters: AsyncGPUBaremetalClustersResource) -> self.create = async_to_streamed_response_wrapper( gpu_baremetal_clusters.create, ) - self.list = ( # pyright: ignore[reportDeprecated] - async_to_streamed_response_wrapper( - gpu_baremetal_clusters.list # pyright: ignore[reportDeprecated], - ) + self.list = async_to_streamed_response_wrapper( + gpu_baremetal_clusters.list, ) self.delete = async_to_streamed_response_wrapper( gpu_baremetal_clusters.delete, ) - self.get = ( # pyright: ignore[reportDeprecated] - async_to_streamed_response_wrapper( - gpu_baremetal_clusters.get # pyright: ignore[reportDeprecated], - ) + self.get = async_to_streamed_response_wrapper( + gpu_baremetal_clusters.get, ) self.powercycle_all_servers = async_to_streamed_response_wrapper( gpu_baremetal_clusters.powercycle_all_servers, diff --git a/src/gcore/resources/cloud/gpu_baremetal_clusters/servers.py b/src/gcore/resources/cloud/gpu_baremetal_clusters/servers.py index cf5c2ef9..5943860d 100644 --- a/src/gcore/resources/cloud/gpu_baremetal_clusters/servers.py +++ b/src/gcore/resources/cloud/gpu_baremetal_clusters/servers.py @@ -2,12 +2,13 @@ from __future__ import annotations -from typing import Iterable +from typing import Union, Iterable +from datetime import datetime from typing_extensions import Literal, overload import httpx -from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven, SequenceNotStr from ...._utils import maybe_transform, async_maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource @@ -17,15 +18,18 @@ async_to_raw_response_wrapper, async_to_streamed_response_wrapper, ) -from ...._base_client import make_request_options +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, server_attach_interface_params, server_detach_interface_params, ) -from ....types.cloud.gpu_baremetal_cluster_server import GPUBaremetalClusterServer +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"] @@ -50,6 +54,120 @@ def with_streaming_response(self) -> ServersResourceWithStreamingResponse: """ return ServersResourceWithStreamingResponse(self) + def list( + self, + cluster_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + changed_before: Union[str, datetime] | NotGiven = NOT_GIVEN, + changed_since: Union[str, datetime] | NotGiven = NOT_GIVEN, + ip_address: str | NotGiven = NOT_GIVEN, + limit: int | NotGiven = NOT_GIVEN, + name: str | NotGiven = NOT_GIVEN, + offset: int | NotGiven = NOT_GIVEN, + order_by: Literal["created_at.asc", "created_at.desc", "status.asc", "status.desc"] | NotGiven = NOT_GIVEN, + status: Literal[ + "ACTIVE", + "BUILD", + "ERROR", + "HARD_REBOOT", + "MIGRATING", + "PAUSED", + "REBOOT", + "REBUILD", + "RESIZE", + "REVERT_RESIZE", + "SHELVED", + "SHELVED_OFFLOADED", + "SHUTOFF", + "SOFT_DELETED", + "SUSPENDED", + "VERIFY_RESIZE", + ] + | NotGiven = NOT_GIVEN, + uuids: SequenceNotStr[str] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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, @@ -342,11 +460,17 @@ def attach_interface( project_id: int | None = None, region_id: int | None = None, ddos_profile: server_attach_interface_params.NewInterfaceExternalExtendSchemaWithDDOSDDOSProfile + | server_attach_interface_params.NewInterfaceSpecificSubnetSchemaDDOSProfile + | server_attach_interface_params.NewInterfaceAnySubnetSchemaDDOSProfile + | server_attach_interface_params.NewInterfaceReservedFixedIPSchemaDDOSProfile | NotGiven = NOT_GIVEN, interface_name: str | NotGiven = NOT_GIVEN, ip_family: Literal["dual", "ipv4", "ipv6"] | NotGiven = NOT_GIVEN, port_group: int | NotGiven = NOT_GIVEN, security_groups: Iterable[server_attach_interface_params.NewInterfaceExternalExtendSchemaWithDDOSSecurityGroup] + | Iterable[server_attach_interface_params.NewInterfaceSpecificSubnetSchemaSecurityGroup] + | Iterable[server_attach_interface_params.NewInterfaceAnySubnetSchemaSecurityGroup] + | Iterable[server_attach_interface_params.NewInterfaceReservedFixedIPSchemaSecurityGroup] | NotGiven = NOT_GIVEN, type: str | NotGiven = NOT_GIVEN, subnet_id: str | NotGiven = NOT_GIVEN, @@ -490,7 +614,7 @@ def powercycle( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> GPUBaremetalClusterServer: + ) -> GPUBaremetalClusterServerV1: """ Stops and then starts the server, effectively performing a hard reboot. @@ -514,7 +638,7 @@ def powercycle( options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=GPUBaremetalClusterServer, + cast_to=GPUBaremetalClusterServerV1, ) def reboot( @@ -529,7 +653,7 @@ def reboot( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> GPUBaremetalClusterServer: + ) -> GPUBaremetalClusterServerV1: """ Reboot one bare metal GPU cluster server @@ -553,7 +677,7 @@ def reboot( options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=GPUBaremetalClusterServer, + cast_to=GPUBaremetalClusterServerV1, ) @@ -577,6 +701,120 @@ def with_streaming_response(self) -> AsyncServersResourceWithStreamingResponse: """ return AsyncServersResourceWithStreamingResponse(self) + def list( + self, + cluster_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + changed_before: Union[str, datetime] | NotGiven = NOT_GIVEN, + changed_since: Union[str, datetime] | NotGiven = NOT_GIVEN, + ip_address: str | NotGiven = NOT_GIVEN, + limit: int | NotGiven = NOT_GIVEN, + name: str | NotGiven = NOT_GIVEN, + offset: int | NotGiven = NOT_GIVEN, + order_by: Literal["created_at.asc", "created_at.desc", "status.asc", "status.desc"] | NotGiven = NOT_GIVEN, + status: Literal[ + "ACTIVE", + "BUILD", + "ERROR", + "HARD_REBOOT", + "MIGRATING", + "PAUSED", + "REBOOT", + "REBUILD", + "RESIZE", + "REVERT_RESIZE", + "SHELVED", + "SHELVED_OFFLOADED", + "SHUTOFF", + "SOFT_DELETED", + "SUSPENDED", + "VERIFY_RESIZE", + ] + | NotGiven = NOT_GIVEN, + uuids: SequenceNotStr[str] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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, @@ -871,11 +1109,17 @@ async def attach_interface( project_id: int | None = None, region_id: int | None = None, ddos_profile: server_attach_interface_params.NewInterfaceExternalExtendSchemaWithDDOSDDOSProfile + | server_attach_interface_params.NewInterfaceSpecificSubnetSchemaDDOSProfile + | server_attach_interface_params.NewInterfaceAnySubnetSchemaDDOSProfile + | server_attach_interface_params.NewInterfaceReservedFixedIPSchemaDDOSProfile | NotGiven = NOT_GIVEN, interface_name: str | NotGiven = NOT_GIVEN, ip_family: Literal["dual", "ipv4", "ipv6"] | NotGiven = NOT_GIVEN, port_group: int | NotGiven = NOT_GIVEN, security_groups: Iterable[server_attach_interface_params.NewInterfaceExternalExtendSchemaWithDDOSSecurityGroup] + | Iterable[server_attach_interface_params.NewInterfaceSpecificSubnetSchemaSecurityGroup] + | Iterable[server_attach_interface_params.NewInterfaceAnySubnetSchemaSecurityGroup] + | Iterable[server_attach_interface_params.NewInterfaceReservedFixedIPSchemaSecurityGroup] | NotGiven = NOT_GIVEN, type: str | NotGiven = NOT_GIVEN, subnet_id: str | NotGiven = NOT_GIVEN, @@ -1019,7 +1263,7 @@ async def powercycle( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> GPUBaremetalClusterServer: + ) -> GPUBaremetalClusterServerV1: """ Stops and then starts the server, effectively performing a hard reboot. @@ -1043,7 +1287,7 @@ async def powercycle( options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=GPUBaremetalClusterServer, + cast_to=GPUBaremetalClusterServerV1, ) async def reboot( @@ -1058,7 +1302,7 @@ async def reboot( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> GPUBaremetalClusterServer: + ) -> GPUBaremetalClusterServerV1: """ Reboot one bare metal GPU cluster server @@ -1082,7 +1326,7 @@ async def reboot( options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=GPUBaremetalClusterServer, + cast_to=GPUBaremetalClusterServerV1, ) @@ -1090,6 +1334,9 @@ 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, ) @@ -1114,6 +1361,9 @@ 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, ) @@ -1138,6 +1388,9 @@ 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, ) @@ -1162,6 +1415,9 @@ 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/inference/__init__.py b/src/gcore/resources/cloud/inference/__init__.py index d8b0c834..a3cd64c3 100644 --- a/src/gcore/resources/cloud/inference/__init__.py +++ b/src/gcore/resources/cloud/inference/__init__.py @@ -1,13 +1,5 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from .models import ( - ModelsResource, - AsyncModelsResource, - ModelsResourceWithRawResponse, - AsyncModelsResourceWithRawResponse, - ModelsResourceWithStreamingResponse, - AsyncModelsResourceWithStreamingResponse, -) from .flavors import ( FlavorsResource, AsyncFlavorsResource, @@ -48,6 +40,14 @@ DeploymentsResourceWithStreamingResponse, AsyncDeploymentsResourceWithStreamingResponse, ) +from .applications import ( + ApplicationsResource, + AsyncApplicationsResource, + ApplicationsResourceWithRawResponse, + AsyncApplicationsResourceWithRawResponse, + ApplicationsResourceWithStreamingResponse, + AsyncApplicationsResourceWithStreamingResponse, +) from .registry_credentials import ( RegistryCredentialsResource, AsyncRegistryCredentialsResource, @@ -64,12 +64,6 @@ "AsyncFlavorsResourceWithRawResponse", "FlavorsResourceWithStreamingResponse", "AsyncFlavorsResourceWithStreamingResponse", - "ModelsResource", - "AsyncModelsResource", - "ModelsResourceWithRawResponse", - "AsyncModelsResourceWithRawResponse", - "ModelsResourceWithStreamingResponse", - "AsyncModelsResourceWithStreamingResponse", "DeploymentsResource", "AsyncDeploymentsResource", "DeploymentsResourceWithRawResponse", @@ -94,6 +88,12 @@ "AsyncAPIKeysResourceWithRawResponse", "APIKeysResourceWithStreamingResponse", "AsyncAPIKeysResourceWithStreamingResponse", + "ApplicationsResource", + "AsyncApplicationsResource", + "ApplicationsResourceWithRawResponse", + "AsyncApplicationsResourceWithRawResponse", + "ApplicationsResourceWithStreamingResponse", + "AsyncApplicationsResourceWithStreamingResponse", "InferenceResource", "AsyncInferenceResource", "InferenceResourceWithRawResponse", 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..845bffce --- /dev/null +++ b/src/gcore/resources/cloud/inference/applications/deployments.py @@ -0,0 +1,649 @@ +# 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 NOT_GIVEN, Body, Query, Headers, NotGiven, SequenceNotStr +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_patch_params, deployment_create_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] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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 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, + ) + + def patch( + self, + deployment_name: str, + *, + project_id: int | None = None, + api_keys: SequenceNotStr[str] | NotGiven = NOT_GIVEN, + components_configuration: Dict[str, Optional[deployment_patch_params.ComponentsConfiguration]] + | NotGiven = NOT_GIVEN, + regions: Iterable[int] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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_patch_params.DeploymentPatchParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + +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] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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 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, + ) + + async def patch( + self, + deployment_name: str, + *, + project_id: int | None = None, + api_keys: SequenceNotStr[str] | NotGiven = NOT_GIVEN, + components_configuration: Dict[str, Optional[deployment_patch_params.ComponentsConfiguration]] + | NotGiven = NOT_GIVEN, + regions: Iterable[int] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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_patch_params.DeploymentPatchParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TaskIDList, + ) + + +class DeploymentsResourceWithRawResponse: + def __init__(self, deployments: DeploymentsResource) -> None: + self._deployments = deployments + + self.create = to_raw_response_wrapper( + deployments.create, + ) + 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.patch = to_raw_response_wrapper( + deployments.patch, + ) + + +class AsyncDeploymentsResourceWithRawResponse: + def __init__(self, deployments: AsyncDeploymentsResource) -> None: + self._deployments = deployments + + self.create = async_to_raw_response_wrapper( + deployments.create, + ) + 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.patch = async_to_raw_response_wrapper( + deployments.patch, + ) + + +class DeploymentsResourceWithStreamingResponse: + def __init__(self, deployments: DeploymentsResource) -> None: + self._deployments = deployments + + self.create = to_streamed_response_wrapper( + deployments.create, + ) + 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.patch = to_streamed_response_wrapper( + deployments.patch, + ) + + +class AsyncDeploymentsResourceWithStreamingResponse: + def __init__(self, deployments: AsyncDeploymentsResource) -> None: + self._deployments = deployments + + self.create = async_to_streamed_response_wrapper( + deployments.create, + ) + 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.patch = async_to_streamed_response_wrapper( + deployments.patch, + ) 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..1c475cb8 --- /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 NOT_GIVEN, Body, Query, Headers, NotGiven +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/deployments.py b/src/gcore/resources/cloud/inference/deployments/deployments.py index de83208e..533883c2 100644 --- a/src/gcore/resources/cloud/inference/deployments/deployments.py +++ b/src/gcore/resources/cloud/inference/deployments/deployments.py @@ -2,7 +2,8 @@ from __future__ import annotations -from typing import Dict, List, Iterable, Optional +import typing_extensions +from typing import Dict, Iterable, Optional import httpx @@ -14,7 +15,7 @@ LogsResourceWithStreamingResponse, AsyncLogsResourceWithStreamingResponse, ) -from ....._types import NOT_GIVEN, Body, Query, Headers, NoneType, NotGiven +from ....._types import NOT_GIVEN, Body, Query, Headers, NoneType, NotGiven, SequenceNotStr from ....._utils import maybe_transform, async_maybe_transform from ....._compat import cached_property from ....._resource import SyncAPIResource, AsyncAPIResource @@ -67,9 +68,9 @@ def create( image: str, listening_port: int, name: str, - api_keys: List[str] | NotGiven = NOT_GIVEN, + api_keys: SequenceNotStr[str] | NotGiven = NOT_GIVEN, auth_enabled: bool | NotGiven = NOT_GIVEN, - command: Optional[List[str]] | NotGiven = NOT_GIVEN, + command: Optional[SequenceNotStr[str]] | NotGiven = NOT_GIVEN, credentials_name: Optional[str] | NotGiven = NOT_GIVEN, description: Optional[str] | NotGiven = NOT_GIVEN, envs: Dict[str, str] | NotGiven = NOT_GIVEN, @@ -178,9 +179,9 @@ def update( deployment_name: str, *, project_id: int | None = None, - api_keys: Optional[List[str]] | NotGiven = NOT_GIVEN, + api_keys: Optional[SequenceNotStr[str]] | NotGiven = NOT_GIVEN, auth_enabled: bool | NotGiven = NOT_GIVEN, - command: Optional[List[str]] | NotGiven = NOT_GIVEN, + command: Optional[SequenceNotStr[str]] | NotGiven = NOT_GIVEN, containers: Optional[Iterable[deployment_update_params.Container]] | NotGiven = NOT_GIVEN, credentials_name: Optional[str] | NotGiven = NOT_GIVEN, description: Optional[str] | NotGiven = NOT_GIVEN, @@ -422,6 +423,7 @@ def get( cast_to=InferenceDeployment, ) + @typing_extensions.deprecated("deprecated") def get_api_key( self, deployment_name: str, @@ -567,8 +569,9 @@ def create_and_poll( image: str, listening_port: int, name: str, + api_keys: SequenceNotStr[str] | NotGiven = NOT_GIVEN, auth_enabled: bool | NotGiven = NOT_GIVEN, - command: Optional[List[str]] | NotGiven = NOT_GIVEN, + command: Optional[SequenceNotStr[str]] | NotGiven = NOT_GIVEN, credentials_name: Optional[str] | NotGiven = NOT_GIVEN, description: Optional[str] | NotGiven = NOT_GIVEN, envs: Dict[str, str] | NotGiven = NOT_GIVEN, @@ -591,6 +594,7 @@ def create_and_poll( image=image, listening_port=listening_port, name=name, + api_keys=api_keys, auth_enabled=auth_enabled, command=command, credentials_name=credentials_name, @@ -630,8 +634,9 @@ def update_and_poll( deployment_name: str, *, project_id: int | None = None, + api_keys: Optional[SequenceNotStr[str]] | NotGiven = NOT_GIVEN, auth_enabled: bool | NotGiven = NOT_GIVEN, - command: Optional[List[str]] | NotGiven = NOT_GIVEN, + command: Optional[SequenceNotStr[str]] | NotGiven = NOT_GIVEN, containers: Optional[Iterable[deployment_update_params.Container]] | NotGiven = NOT_GIVEN, credentials_name: Optional[str] | NotGiven = NOT_GIVEN, description: Optional[str] | NotGiven = NOT_GIVEN, @@ -657,6 +662,7 @@ def update_and_poll( response = self.update( deployment_name=deployment_name, project_id=project_id, + api_keys=api_keys, auth_enabled=auth_enabled, command=command, containers=containers, @@ -755,9 +761,9 @@ async def create( image: str, listening_port: int, name: str, - api_keys: List[str] | NotGiven = NOT_GIVEN, + api_keys: SequenceNotStr[str] | NotGiven = NOT_GIVEN, auth_enabled: bool | NotGiven = NOT_GIVEN, - command: Optional[List[str]] | NotGiven = NOT_GIVEN, + command: Optional[SequenceNotStr[str]] | NotGiven = NOT_GIVEN, credentials_name: Optional[str] | NotGiven = NOT_GIVEN, description: Optional[str] | NotGiven = NOT_GIVEN, envs: Dict[str, str] | NotGiven = NOT_GIVEN, @@ -866,9 +872,9 @@ async def update( deployment_name: str, *, project_id: int | None = None, - api_keys: Optional[List[str]] | NotGiven = NOT_GIVEN, + api_keys: Optional[SequenceNotStr[str]] | NotGiven = NOT_GIVEN, auth_enabled: bool | NotGiven = NOT_GIVEN, - command: Optional[List[str]] | NotGiven = NOT_GIVEN, + command: Optional[SequenceNotStr[str]] | NotGiven = NOT_GIVEN, containers: Optional[Iterable[deployment_update_params.Container]] | NotGiven = NOT_GIVEN, credentials_name: Optional[str] | NotGiven = NOT_GIVEN, description: Optional[str] | NotGiven = NOT_GIVEN, @@ -1110,6 +1116,7 @@ async def get( cast_to=InferenceDeployment, ) + @typing_extensions.deprecated("deprecated") async def get_api_key( self, deployment_name: str, @@ -1255,8 +1262,9 @@ async def create_and_poll( image: str, listening_port: int, name: str, + api_keys: SequenceNotStr[str] | NotGiven = NOT_GIVEN, auth_enabled: bool | NotGiven = NOT_GIVEN, - command: Optional[List[str]] | NotGiven = NOT_GIVEN, + command: Optional[SequenceNotStr[str]] | NotGiven = NOT_GIVEN, credentials_name: Optional[str] | NotGiven = NOT_GIVEN, description: Optional[str] | NotGiven = NOT_GIVEN, envs: Dict[str, str] | NotGiven = NOT_GIVEN, @@ -1279,6 +1287,7 @@ async def create_and_poll( image=image, listening_port=listening_port, name=name, + api_keys=api_keys, auth_enabled=auth_enabled, command=command, credentials_name=credentials_name, @@ -1318,8 +1327,9 @@ async def update_and_poll( deployment_name: str, *, project_id: int | None = None, + api_keys: Optional[SequenceNotStr[str]] | NotGiven = NOT_GIVEN, auth_enabled: bool | NotGiven = NOT_GIVEN, - command: Optional[List[str]] | NotGiven = NOT_GIVEN, + command: Optional[SequenceNotStr[str]] | NotGiven = NOT_GIVEN, containers: Optional[Iterable[deployment_update_params.Container]] | NotGiven = NOT_GIVEN, credentials_name: Optional[str] | NotGiven = NOT_GIVEN, description: Optional[str] | NotGiven = NOT_GIVEN, @@ -1345,6 +1355,7 @@ async def update_and_poll( response = await self.update( deployment_name=deployment_name, project_id=project_id, + api_keys=api_keys, auth_enabled=auth_enabled, command=command, containers=containers, @@ -1429,8 +1440,10 @@ def __init__(self, deployments: DeploymentsResource) -> None: self.get = to_raw_response_wrapper( deployments.get, ) - self.get_api_key = to_raw_response_wrapper( - deployments.get_api_key, + 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, @@ -1463,8 +1476,10 @@ def __init__(self, deployments: AsyncDeploymentsResource) -> None: self.get = async_to_raw_response_wrapper( deployments.get, ) - self.get_api_key = async_to_raw_response_wrapper( - deployments.get_api_key, + 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, @@ -1497,8 +1512,10 @@ def __init__(self, deployments: DeploymentsResource) -> None: self.get = to_streamed_response_wrapper( deployments.get, ) - self.get_api_key = to_streamed_response_wrapper( - deployments.get_api_key, + 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, @@ -1531,8 +1548,10 @@ def __init__(self, deployments: AsyncDeploymentsResource) -> None: self.get = async_to_streamed_response_wrapper( deployments.get, ) - self.get_api_key = async_to_streamed_response_wrapper( - deployments.get_api_key, + 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, diff --git a/src/gcore/resources/cloud/inference/inference.py b/src/gcore/resources/cloud/inference/inference.py index d9a20993..103c70f1 100644 --- a/src/gcore/resources/cloud/inference/inference.py +++ b/src/gcore/resources/cloud/inference/inference.py @@ -4,14 +4,6 @@ import httpx -from .models import ( - ModelsResource, - AsyncModelsResource, - ModelsResourceWithRawResponse, - AsyncModelsResourceWithRawResponse, - ModelsResourceWithStreamingResponse, - AsyncModelsResourceWithStreamingResponse, -) from .flavors import ( FlavorsResource, AsyncFlavorsResource, @@ -62,6 +54,14 @@ DeploymentsResourceWithStreamingResponse, AsyncDeploymentsResourceWithStreamingResponse, ) +from .applications.applications import ( + ApplicationsResource, + AsyncApplicationsResource, + ApplicationsResourceWithRawResponse, + AsyncApplicationsResourceWithRawResponse, + ApplicationsResourceWithStreamingResponse, + AsyncApplicationsResourceWithStreamingResponse, +) from ....types.cloud.inference_region_capacity_list import InferenceRegionCapacityList __all__ = ["InferenceResource", "AsyncInferenceResource"] @@ -72,10 +72,6 @@ class InferenceResource(SyncAPIResource): def flavors(self) -> FlavorsResource: return FlavorsResource(self._client) - @cached_property - def models(self) -> ModelsResource: - return ModelsResource(self._client) - @cached_property def deployments(self) -> DeploymentsResource: return DeploymentsResource(self._client) @@ -92,6 +88,10 @@ def secrets(self) -> SecretsResource: 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: """ @@ -136,10 +136,6 @@ class AsyncInferenceResource(AsyncAPIResource): def flavors(self) -> AsyncFlavorsResource: return AsyncFlavorsResource(self._client) - @cached_property - def models(self) -> AsyncModelsResource: - return AsyncModelsResource(self._client) - @cached_property def deployments(self) -> AsyncDeploymentsResource: return AsyncDeploymentsResource(self._client) @@ -156,6 +152,10 @@ def secrets(self) -> AsyncSecretsResource: 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: """ @@ -207,10 +207,6 @@ def __init__(self, inference: InferenceResource) -> None: def flavors(self) -> FlavorsResourceWithRawResponse: return FlavorsResourceWithRawResponse(self._inference.flavors) - @cached_property - def models(self) -> ModelsResourceWithRawResponse: - return ModelsResourceWithRawResponse(self._inference.models) - @cached_property def deployments(self) -> DeploymentsResourceWithRawResponse: return DeploymentsResourceWithRawResponse(self._inference.deployments) @@ -227,6 +223,10 @@ def secrets(self) -> SecretsResourceWithRawResponse: 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: @@ -240,10 +240,6 @@ def __init__(self, inference: AsyncInferenceResource) -> None: def flavors(self) -> AsyncFlavorsResourceWithRawResponse: return AsyncFlavorsResourceWithRawResponse(self._inference.flavors) - @cached_property - def models(self) -> AsyncModelsResourceWithRawResponse: - return AsyncModelsResourceWithRawResponse(self._inference.models) - @cached_property def deployments(self) -> AsyncDeploymentsResourceWithRawResponse: return AsyncDeploymentsResourceWithRawResponse(self._inference.deployments) @@ -260,6 +256,10 @@ def secrets(self) -> AsyncSecretsResourceWithRawResponse: 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: @@ -273,10 +273,6 @@ def __init__(self, inference: InferenceResource) -> None: def flavors(self) -> FlavorsResourceWithStreamingResponse: return FlavorsResourceWithStreamingResponse(self._inference.flavors) - @cached_property - def models(self) -> ModelsResourceWithStreamingResponse: - return ModelsResourceWithStreamingResponse(self._inference.models) - @cached_property def deployments(self) -> DeploymentsResourceWithStreamingResponse: return DeploymentsResourceWithStreamingResponse(self._inference.deployments) @@ -293,6 +289,10 @@ def secrets(self) -> SecretsResourceWithStreamingResponse: 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: @@ -306,10 +306,6 @@ def __init__(self, inference: AsyncInferenceResource) -> None: def flavors(self) -> AsyncFlavorsResourceWithStreamingResponse: return AsyncFlavorsResourceWithStreamingResponse(self._inference.flavors) - @cached_property - def models(self) -> AsyncModelsResourceWithStreamingResponse: - return AsyncModelsResourceWithStreamingResponse(self._inference.models) - @cached_property def deployments(self) -> AsyncDeploymentsResourceWithStreamingResponse: return AsyncDeploymentsResourceWithStreamingResponse(self._inference.deployments) @@ -325,3 +321,7 @@ def secrets(self) -> AsyncSecretsResourceWithStreamingResponse: @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 index f5981625..6dd78f70 100644 --- a/src/gcore/resources/cloud/inference/registry_credentials.py +++ b/src/gcore/resources/cloud/inference/registry_credentials.py @@ -22,7 +22,6 @@ registry_credential_replace_params, ) from ....types.cloud.inference.inference_registry_credentials import InferenceRegistryCredentials -from ....types.cloud.inference.inference_registry_credentials_create import InferenceRegistryCredentialsCreate __all__ = ["RegistryCredentialsResource", "AsyncRegistryCredentialsResource"] @@ -61,7 +60,7 @@ def create( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> InferenceRegistryCredentialsCreate: + ) -> InferenceRegistryCredentials: """ Create inference registry credential @@ -100,7 +99,7 @@ def create( options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=InferenceRegistryCredentialsCreate, + cast_to=InferenceRegistryCredentials, ) def list( @@ -251,7 +250,7 @@ def replace( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> InferenceRegistryCredentialsCreate: + ) -> InferenceRegistryCredentials: """ Replace inference registry credential @@ -291,7 +290,7 @@ def replace( options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=InferenceRegistryCredentialsCreate, + cast_to=InferenceRegistryCredentials, ) @@ -329,7 +328,7 @@ async def create( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> InferenceRegistryCredentialsCreate: + ) -> InferenceRegistryCredentials: """ Create inference registry credential @@ -368,7 +367,7 @@ async def create( options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=InferenceRegistryCredentialsCreate, + cast_to=InferenceRegistryCredentials, ) def list( @@ -519,7 +518,7 @@ async def replace( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> InferenceRegistryCredentialsCreate: + ) -> InferenceRegistryCredentials: """ Replace inference registry credential @@ -559,7 +558,7 @@ async def replace( options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - cast_to=InferenceRegistryCredentialsCreate, + cast_to=InferenceRegistryCredentials, ) diff --git a/src/gcore/resources/cloud/instances/images.py b/src/gcore/resources/cloud/instances/images.py index 91f82de4..7b13a49a 100644 --- a/src/gcore/resources/cloud/instances/images.py +++ b/src/gcore/resources/cloud/instances/images.py @@ -2,12 +2,12 @@ from __future__ import annotations -from typing import Dict, List, Optional +from typing import Dict, Optional from typing_extensions import Literal import httpx -from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven, SequenceNotStr from ...._utils import maybe_transform, async_maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource @@ -136,7 +136,7 @@ def list( region_id: int | None = None, include_prices: bool | NotGiven = NOT_GIVEN, private: str | NotGiven = NOT_GIVEN, - tag_key: List[str] | NotGiven = NOT_GIVEN, + tag_key: SequenceNotStr[str] | NotGiven = NOT_GIVEN, tag_key_value: str | NotGiven = NOT_GIVEN, visibility: Literal["private", "public", "shared"] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -728,7 +728,7 @@ async def list( region_id: int | None = None, include_prices: bool | NotGiven = NOT_GIVEN, private: str | NotGiven = NOT_GIVEN, - tag_key: List[str] | NotGiven = NOT_GIVEN, + tag_key: SequenceNotStr[str] | NotGiven = NOT_GIVEN, tag_key_value: str | NotGiven = NOT_GIVEN, visibility: Literal["private", "public", "shared"] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. diff --git a/src/gcore/resources/cloud/instances/instances.py b/src/gcore/resources/cloud/instances/instances.py index 18bed9dc..6cb7f865 100644 --- a/src/gcore/resources/cloud/instances/instances.py +++ b/src/gcore/resources/cloud/instances/instances.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Dict, List, Union, Iterable, Optional +from typing import Dict, Union, Iterable, Optional from datetime import datetime from typing_extensions import Literal, overload @@ -32,7 +32,7 @@ MetricsResourceWithStreamingResponse, AsyncMetricsResourceWithStreamingResponse, ) -from ...._types import NOT_GIVEN, Body, Query, Headers, NoneType, NotGiven +from ...._types import NOT_GIVEN, Body, Query, Headers, NoneType, NotGiven, SequenceNotStr from ...._utils import required_args, maybe_transform, async_maybe_transform from ...._compat import cached_property from .interfaces import ( @@ -417,7 +417,7 @@ def list( ] | NotGiven = NOT_GIVEN, tag_key_value: str | NotGiven = NOT_GIVEN, - tag_value: List[str] | NotGiven = NOT_GIVEN, + tag_value: SequenceNotStr[str] | NotGiven = NOT_GIVEN, type_ddos_profile: Literal["basic", "advanced"] | NotGiven = NOT_GIVEN, uuid: str | NotGiven = NOT_GIVEN, with_ddos: bool | NotGiven = NOT_GIVEN, @@ -773,6 +773,125 @@ def action( cast_to=TaskIDList, ) + @overload + def action_and_poll( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + action: Literal["start"], + activate_profile: Optional[bool] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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: + """ + 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_and_poll( + 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, + ) -> Instance: + """ + 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_and_poll( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + action: Literal["start", "reboot", "reboot_hard", "resume", "stop", "suspend"], + activate_profile: Optional[bool] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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: + """ + Perform the action on the instance and poll for the result. Only the first task will be polled. If you need to poll more tasks, use the `tasks.poll` method. + """ + if project_id is None: + project_id = self._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}") + response = 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, + ) + if not response.tasks: + raise ValueError("Expected at least one task to be created") + self._client.cloud.tasks.poll( + task_id=response.tasks[0], + extra_headers=extra_headers, + ) + return self.get( + instance_id=instance_id, + project_id=project_id, + region_id=region_id, + extra_headers=extra_headers, + ) + def add_to_placement_group( self, instance_id: str, @@ -1667,7 +1786,7 @@ def list( ] | NotGiven = NOT_GIVEN, tag_key_value: str | NotGiven = NOT_GIVEN, - tag_value: List[str] | NotGiven = NOT_GIVEN, + tag_value: SequenceNotStr[str] | NotGiven = NOT_GIVEN, type_ddos_profile: Literal["basic", "advanced"] | NotGiven = NOT_GIVEN, uuid: str | NotGiven = NOT_GIVEN, with_ddos: bool | NotGiven = NOT_GIVEN, @@ -2023,6 +2142,125 @@ async def action( cast_to=TaskIDList, ) + @overload + async def action_and_poll( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + action: Literal["start"], + activate_profile: Optional[bool] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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: + """ + 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_and_poll( + 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, + ) -> Instance: + """ + 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_and_poll( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + action: Literal["start", "reboot", "reboot_hard", "resume", "stop", "suspend"], + activate_profile: Optional[bool] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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: + """ + Perform the action on the instance and poll for the result. Only the first task will be polled. If you need to poll more tasks, use the `tasks.poll` method. + """ + if project_id is None: + project_id = self._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}") + response = 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, + ) + if not response.tasks: + raise ValueError("Expected at least one task to be created") + await self._client.cloud.tasks.poll( + task_id=response.tasks[0], + extra_headers=extra_headers, + ) + return await self.get( + instance_id=instance_id, + project_id=project_id, + region_id=region_id, + extra_headers=extra_headers, + ) + async def add_to_placement_group( self, instance_id: str, @@ -2591,6 +2829,9 @@ def __init__(self, instances: InstancesResource) -> None: self.action = to_raw_response_wrapper( instances.action, ) + self.action_and_poll = to_raw_response_wrapper( + instances.action_and_poll, + ) self.add_to_placement_group = to_raw_response_wrapper( instances.add_to_placement_group, ) @@ -2655,6 +2896,9 @@ def __init__(self, instances: AsyncInstancesResource) -> None: self.action = async_to_raw_response_wrapper( instances.action, ) + self.action_and_poll = async_to_raw_response_wrapper( + instances.action_and_poll, + ) self.add_to_placement_group = async_to_raw_response_wrapper( instances.add_to_placement_group, ) @@ -2719,6 +2963,9 @@ def __init__(self, instances: InstancesResource) -> None: self.action = to_streamed_response_wrapper( instances.action, ) + self.action_and_poll = to_streamed_response_wrapper( + instances.action_and_poll, + ) self.add_to_placement_group = to_streamed_response_wrapper( instances.add_to_placement_group, ) @@ -2783,6 +3030,9 @@ def __init__(self, instances: AsyncInstancesResource) -> None: self.action = async_to_streamed_response_wrapper( instances.action, ) + self.action_and_poll = async_to_streamed_response_wrapper( + instances.action_and_poll, + ) self.add_to_placement_group = async_to_streamed_response_wrapper( instances.add_to_placement_group, ) diff --git a/src/gcore/resources/cloud/instances/interfaces.py b/src/gcore/resources/cloud/instances/interfaces.py index 9cc4b04f..5d1c5c35 100644 --- a/src/gcore/resources/cloud/instances/interfaces.py +++ b/src/gcore/resources/cloud/instances/interfaces.py @@ -283,11 +283,17 @@ def attach( 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 | NotGiven = NOT_GIVEN, interface_name: str | NotGiven = NOT_GIVEN, ip_family: Literal["dual", "ipv4", "ipv6"] | NotGiven = NOT_GIVEN, port_group: int | NotGiven = NOT_GIVEN, security_groups: Iterable[interface_attach_params.NewInterfaceExternalExtendSchemaWithDDOSSecurityGroup] + | Iterable[interface_attach_params.NewInterfaceSpecificSubnetSchemaSecurityGroup] + | Iterable[interface_attach_params.NewInterfaceAnySubnetSchemaSecurityGroup] + | Iterable[interface_attach_params.NewInterfaceReservedFixedIPSchemaSecurityGroup] | NotGiven = NOT_GIVEN, type: str | NotGiven = NOT_GIVEN, subnet_id: str | NotGiven = NOT_GIVEN, @@ -328,6 +334,299 @@ def attach( cast_to=TaskIDList, ) + @overload + def attach_and_poll( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + ddos_profile: interface_attach_params.NewInterfaceExternalExtendSchemaWithDDOSDDOSProfile + | NotGiven = NOT_GIVEN, + interface_name: str | NotGiven = NOT_GIVEN, + ip_family: Literal["dual", "ipv4", "ipv6"] | NotGiven = NOT_GIVEN, + port_group: int | NotGiven = NOT_GIVEN, + security_groups: Iterable[interface_attach_params.NewInterfaceExternalExtendSchemaWithDDOSSecurityGroup] + | NotGiven = NOT_GIVEN, + type: str | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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: + """ + 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_and_poll( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + subnet_id: str, + ddos_profile: interface_attach_params.NewInterfaceSpecificSubnetSchemaDDOSProfile | NotGiven = NOT_GIVEN, + interface_name: str | NotGiven = NOT_GIVEN, + port_group: int | NotGiven = NOT_GIVEN, + security_groups: Iterable[interface_attach_params.NewInterfaceSpecificSubnetSchemaSecurityGroup] + | NotGiven = NOT_GIVEN, + type: str | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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: + """ + 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_and_poll( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + network_id: str, + ddos_profile: interface_attach_params.NewInterfaceAnySubnetSchemaDDOSProfile | NotGiven = NOT_GIVEN, + interface_name: str | NotGiven = NOT_GIVEN, + ip_family: Literal["dual", "ipv4", "ipv6"] | NotGiven = NOT_GIVEN, + port_group: int | NotGiven = NOT_GIVEN, + security_groups: Iterable[interface_attach_params.NewInterfaceAnySubnetSchemaSecurityGroup] + | NotGiven = NOT_GIVEN, + type: str | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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: + """ + 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_and_poll( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + port_id: str, + ddos_profile: interface_attach_params.NewInterfaceReservedFixedIPSchemaDDOSProfile | NotGiven = NOT_GIVEN, + interface_name: str | NotGiven = NOT_GIVEN, + port_group: int | NotGiven = NOT_GIVEN, + security_groups: Iterable[interface_attach_params.NewInterfaceReservedFixedIPSchemaSecurityGroup] + | NotGiven = NOT_GIVEN, + type: str | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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: + """ + 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_and_poll( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + ddos_profile: interface_attach_params.NewInterfaceExternalExtendSchemaWithDDOSDDOSProfile + | NotGiven = NOT_GIVEN, + interface_name: str | NotGiven = NOT_GIVEN, + ip_family: Literal["dual", "ipv4", "ipv6"] | NotGiven = NOT_GIVEN, + port_group: int | NotGiven = NOT_GIVEN, + security_groups: Iterable[interface_attach_params.NewInterfaceExternalExtendSchemaWithDDOSSecurityGroup] + | NotGiven = NOT_GIVEN, + type: str | NotGiven = NOT_GIVEN, + subnet_id: str | NotGiven = NOT_GIVEN, + network_id: str | NotGiven = NOT_GIVEN, + port_id: str | NotGiven = NOT_GIVEN, + polling_interval_seconds: int | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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: + if project_id is None: + project_id = self._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}") + response = 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, + ) + if not response.tasks: + raise ValueError("Expected at least one task to be created") + self._client.cloud.tasks.poll( + task_id=response.tasks[0], + extra_headers=extra_headers, + polling_interval_seconds=polling_interval_seconds, + ) + return self.list(instance_id, project_id=project_id, region_id=region_id, extra_headers=extra_headers) + + def detach_and_poll( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + ip_address: str, + port_id: str, + polling_interval_seconds: int | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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: + """ + Detach interface from instance and poll for completion. Only the first task will be polled. + If you need to poll more tasks, use the `tasks.poll` method. + """ + response = self.detach( + instance_id=instance_id, + project_id=project_id, + region_id=region_id, + ip_address=ip_address, + port_id=port_id, + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + ) + if not response.tasks: + raise ValueError("Expected at least one task to be created") + self._client.cloud.tasks.poll( + task_id=response.tasks[0], + extra_headers=extra_headers, + polling_interval_seconds=polling_interval_seconds, + ) + return self.list(instance_id, project_id=project_id, region_id=region_id, extra_headers=extra_headers) + def detach( self, instance_id: str, @@ -639,11 +938,17 @@ async def attach( 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 | NotGiven = NOT_GIVEN, interface_name: str | NotGiven = NOT_GIVEN, ip_family: Literal["dual", "ipv4", "ipv6"] | NotGiven = NOT_GIVEN, port_group: int | NotGiven = NOT_GIVEN, security_groups: Iterable[interface_attach_params.NewInterfaceExternalExtendSchemaWithDDOSSecurityGroup] + | Iterable[interface_attach_params.NewInterfaceSpecificSubnetSchemaSecurityGroup] + | Iterable[interface_attach_params.NewInterfaceAnySubnetSchemaSecurityGroup] + | Iterable[interface_attach_params.NewInterfaceReservedFixedIPSchemaSecurityGroup] | NotGiven = NOT_GIVEN, type: str | NotGiven = NOT_GIVEN, subnet_id: str | NotGiven = NOT_GIVEN, @@ -684,6 +989,221 @@ async def attach( cast_to=TaskIDList, ) + @overload + async def attach_and_poll( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + ddos_profile: interface_attach_params.NewInterfaceExternalExtendSchemaWithDDOSDDOSProfile + | NotGiven = NOT_GIVEN, + interface_name: str | NotGiven = NOT_GIVEN, + ip_family: Literal["dual", "ipv4", "ipv6"] | NotGiven = NOT_GIVEN, + port_group: int | NotGiven = NOT_GIVEN, + security_groups: Iterable[interface_attach_params.NewInterfaceExternalExtendSchemaWithDDOSSecurityGroup] + | NotGiven = NOT_GIVEN, + type: str | NotGiven = NOT_GIVEN, + polling_interval_seconds: int | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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: + """ + Attach interface to instance using external extend and poll for completion. Only the first task will be polled. + If you need to poll more tasks, use the `tasks.poll` method. + """ + ... + + @overload + async def attach_and_poll( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + subnet_id: str, + ddos_profile: interface_attach_params.NewInterfaceSpecificSubnetSchemaDDOSProfile | NotGiven = NOT_GIVEN, + interface_name: str | NotGiven = NOT_GIVEN, + port_group: int | NotGiven = NOT_GIVEN, + security_groups: Iterable[interface_attach_params.NewInterfaceSpecificSubnetSchemaSecurityGroup] + | NotGiven = NOT_GIVEN, + type: str | NotGiven = NOT_GIVEN, + polling_interval_seconds: int | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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: + """ + Attach interface to instance using specific subnet and poll for completion. Only the first task will be polled. + If you need to poll more tasks, use the `tasks.poll` method. + """ + ... + + @overload + async def attach_and_poll( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + network_id: str, + ddos_profile: interface_attach_params.NewInterfaceAnySubnetSchemaDDOSProfile | NotGiven = NOT_GIVEN, + interface_name: str | NotGiven = NOT_GIVEN, + ip_family: Literal["dual", "ipv4", "ipv6"] | NotGiven = NOT_GIVEN, + port_group: int | NotGiven = NOT_GIVEN, + security_groups: Iterable[interface_attach_params.NewInterfaceAnySubnetSchemaSecurityGroup] + | NotGiven = NOT_GIVEN, + type: str | NotGiven = NOT_GIVEN, + polling_interval_seconds: int | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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: + """ + Attach interface to instance using any subnet and poll for completion. Only the first task will be polled. + If you need to poll more tasks, use the `tasks.poll` method. + """ + ... + + @overload + async def attach_and_poll( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + port_id: str, + ddos_profile: interface_attach_params.NewInterfaceReservedFixedIPSchemaDDOSProfile | NotGiven = NOT_GIVEN, + interface_name: str | NotGiven = NOT_GIVEN, + port_group: int | NotGiven = NOT_GIVEN, + security_groups: Iterable[interface_attach_params.NewInterfaceReservedFixedIPSchemaSecurityGroup] + | NotGiven = NOT_GIVEN, + type: str | NotGiven = NOT_GIVEN, + polling_interval_seconds: int | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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: + """ + Attach interface to instance using reserved fixed IP and poll for completion. Only the first task will be polled. + If you need to poll more tasks, use the `tasks.poll` method. + """ + ... + + async def attach_and_poll( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + ddos_profile: interface_attach_params.NewInterfaceExternalExtendSchemaWithDDOSDDOSProfile + | NotGiven = NOT_GIVEN, + interface_name: str | NotGiven = NOT_GIVEN, + ip_family: Literal["dual", "ipv4", "ipv6"] | NotGiven = NOT_GIVEN, + port_group: int | NotGiven = NOT_GIVEN, + security_groups: Iterable[interface_attach_params.NewInterfaceExternalExtendSchemaWithDDOSSecurityGroup] + | NotGiven = NOT_GIVEN, + type: str | NotGiven = NOT_GIVEN, + subnet_id: str | NotGiven = NOT_GIVEN, + network_id: str | NotGiven = NOT_GIVEN, + port_id: str | NotGiven = NOT_GIVEN, + polling_interval_seconds: int | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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: + if project_id is None: + project_id = self._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}") + response = 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, + ) + if not response.tasks: + raise ValueError("Expected at least one task to be created") + await self._client.cloud.tasks.poll( + task_id=response.tasks[0], + extra_headers=extra_headers, + polling_interval_seconds=polling_interval_seconds, + ) + return await self.list(instance_id, project_id=project_id, region_id=region_id, extra_headers=extra_headers) + + async def detach_and_poll( + self, + instance_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + ip_address: str, + port_id: str, + polling_interval_seconds: int | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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: + """ + Detach interface from instance and poll for completion. Only the first task will be polled. + If you need to poll more tasks, use the `tasks.poll` method. + """ + response = await self.detach( + instance_id=instance_id, + project_id=project_id, + region_id=region_id, + ip_address=ip_address, + port_id=port_id, + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + ) + if not response.tasks: + raise ValueError("Expected at least one task to be created") + await self._client.cloud.tasks.poll( + task_id=response.tasks[0], + extra_headers=extra_headers, + polling_interval_seconds=polling_interval_seconds, + ) + return await self.list(instance_id, project_id=project_id, region_id=region_id, extra_headers=extra_headers) + async def detach( self, instance_id: str, @@ -747,9 +1267,15 @@ def __init__(self, interfaces: InterfacesResource) -> None: self.attach = to_raw_response_wrapper( interfaces.attach, ) + self.attach_and_poll = to_raw_response_wrapper( + interfaces.attach_and_poll, + ) self.detach = to_raw_response_wrapper( interfaces.detach, ) + self.detach_and_poll = to_raw_response_wrapper( + interfaces.detach_and_poll, + ) class AsyncInterfacesResourceWithRawResponse: @@ -762,9 +1288,15 @@ def __init__(self, interfaces: AsyncInterfacesResource) -> None: self.attach = async_to_raw_response_wrapper( interfaces.attach, ) + self.attach_and_poll = async_to_raw_response_wrapper( + interfaces.attach_and_poll, + ) self.detach = async_to_raw_response_wrapper( interfaces.detach, ) + self.detach_and_poll = async_to_raw_response_wrapper( + interfaces.detach_and_poll, + ) class InterfacesResourceWithStreamingResponse: @@ -777,9 +1309,15 @@ def __init__(self, interfaces: InterfacesResource) -> None: self.attach = to_streamed_response_wrapper( interfaces.attach, ) + self.attach_and_poll = to_streamed_response_wrapper( + interfaces.attach_and_poll, + ) self.detach = to_streamed_response_wrapper( interfaces.detach, ) + self.detach_and_poll = to_streamed_response_wrapper( + interfaces.detach_and_poll, + ) class AsyncInterfacesResourceWithStreamingResponse: @@ -792,6 +1330,12 @@ def __init__(self, interfaces: AsyncInterfacesResource) -> None: self.attach = async_to_streamed_response_wrapper( interfaces.attach, ) + self.attach_and_poll = async_to_streamed_response_wrapper( + interfaces.attach_and_poll, + ) self.detach = async_to_streamed_response_wrapper( interfaces.detach, ) + self.detach_and_poll = async_to_streamed_response_wrapper( + interfaces.detach_and_poll, + ) diff --git a/src/gcore/resources/cloud/k8s/__init__.py b/src/gcore/resources/cloud/k8s/__init__.py new file mode 100644 index 00000000..6b5f189d --- /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..a778a3b9 --- /dev/null +++ b/src/gcore/resources/cloud/k8s/clusters/clusters.py @@ -0,0 +1,1391 @@ +# 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 NOT_GIVEN, Body, Query, Headers, NotGiven +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, + authentication: Optional[cluster_create_params.Authentication] | NotGiven = NOT_GIVEN, + autoscaler_config: Optional[Dict[str, str]] | NotGiven = NOT_GIVEN, + cni: Optional[cluster_create_params.Cni] | NotGiven = NOT_GIVEN, + csi: cluster_create_params.Csi | NotGiven = NOT_GIVEN, + ddos_profile: Optional[cluster_create_params.DDOSProfile] | NotGiven = NOT_GIVEN, + fixed_network: Optional[str] | NotGiven = NOT_GIVEN, + fixed_subnet: Optional[str] | NotGiven = NOT_GIVEN, + is_ipv6: Optional[bool] | NotGiven = NOT_GIVEN, + logging: Optional[cluster_create_params.Logging] | NotGiven = NOT_GIVEN, + pods_ip_pool: Optional[str] | NotGiven = NOT_GIVEN, + pods_ipv6_pool: Optional[str] | NotGiven = NOT_GIVEN, + services_ip_pool: Optional[str] | NotGiven = NOT_GIVEN, + services_ipv6_pool: Optional[str] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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: + 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 + + 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, + "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, + authentication: Optional[cluster_update_params.Authentication] | NotGiven = NOT_GIVEN, + autoscaler_config: Optional[Dict[str, str]] | NotGiven = NOT_GIVEN, + cni: Optional[cluster_update_params.Cni] | NotGiven = NOT_GIVEN, + ddos_profile: Optional[cluster_update_params.DDOSProfile] | NotGiven = NOT_GIVEN, + logging: Optional[cluster_update_params.Logging] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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: + 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( + { + "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: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_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 | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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: + 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: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._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: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._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: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._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: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._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: + 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, + authentication: Optional[cluster_create_params.Authentication] | NotGiven = NOT_GIVEN, + autoscaler_config: Optional[Dict[str, str]] | NotGiven = NOT_GIVEN, + cni: Optional[cluster_create_params.Cni] | NotGiven = NOT_GIVEN, + csi: cluster_create_params.Csi | NotGiven = NOT_GIVEN, + ddos_profile: Optional[cluster_create_params.DDOSProfile] | NotGiven = NOT_GIVEN, + fixed_network: Optional[str] | NotGiven = NOT_GIVEN, + fixed_subnet: Optional[str] | NotGiven = NOT_GIVEN, + is_ipv6: Optional[bool] | NotGiven = NOT_GIVEN, + logging: Optional[cluster_create_params.Logging] | NotGiven = NOT_GIVEN, + pods_ip_pool: Optional[str] | NotGiven = NOT_GIVEN, + pods_ipv6_pool: Optional[str] | NotGiven = NOT_GIVEN, + services_ip_pool: Optional[str] | NotGiven = NOT_GIVEN, + services_ipv6_pool: Optional[str] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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: + 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 + + 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, + "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, + authentication: Optional[cluster_update_params.Authentication] | NotGiven = NOT_GIVEN, + autoscaler_config: Optional[Dict[str, str]] | NotGiven = NOT_GIVEN, + cni: Optional[cluster_update_params.Cni] | NotGiven = NOT_GIVEN, + ddos_profile: Optional[cluster_update_params.DDOSProfile] | NotGiven = NOT_GIVEN, + logging: Optional[cluster_update_params.Logging] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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: + 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( + { + "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: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_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 | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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: + 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: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._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: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._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: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._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: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._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: + 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..b3bd95d8 --- /dev/null +++ b/src/gcore/resources/cloud/k8s/clusters/nodes.py @@ -0,0 +1,291 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ....._types import NOT_GIVEN, Body, Query, Headers, NoneType, NotGiven +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 | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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: + 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: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._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 | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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: + 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: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._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..903c428e --- /dev/null +++ b/src/gcore/resources/cloud/k8s/clusters/pools/nodes.py @@ -0,0 +1,303 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ......_types import NOT_GIVEN, Body, Query, Headers, NoneType, NotGiven +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 | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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: + 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: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._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 | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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: + 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: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._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..0cb81d5a --- /dev/null +++ b/src/gcore/resources/cloud/k8s/clusters/pools/pools.py @@ -0,0 +1,870 @@ +# 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 NOT_GIVEN, Body, Query, Headers, NotGiven +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 +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 + +__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] | NotGiven = NOT_GIVEN, + boot_volume_size: Optional[int] | NotGiven = NOT_GIVEN, + boot_volume_type: Optional[Literal["cold", "ssd_hiiops", "ssd_local", "ssd_lowlatency", "standard", "ultra"]] + | NotGiven = NOT_GIVEN, + crio_config: Optional[Dict[str, str]] | NotGiven = NOT_GIVEN, + is_public_ipv4: Optional[bool] | NotGiven = NOT_GIVEN, + kubelet_config: Optional[Dict[str, str]] | NotGiven = NOT_GIVEN, + labels: Optional[Dict[str, str]] | NotGiven = NOT_GIVEN, + max_node_count: Optional[int] | NotGiven = NOT_GIVEN, + servergroup_policy: Optional[Literal["affinity", "anti-affinity", "soft-anti-affinity"]] | NotGiven = NOT_GIVEN, + taints: Optional[Dict[str, str]] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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: + 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] | NotGiven = NOT_GIVEN, + labels: Optional[Dict[str, str]] | NotGiven = NOT_GIVEN, + max_node_count: Optional[int] | NotGiven = NOT_GIVEN, + min_node_count: Optional[int] | NotGiven = NOT_GIVEN, + node_count: Optional[int] | NotGiven = NOT_GIVEN, + taints: Optional[Dict[str, str]] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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: + 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: Current node count + + 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: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._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: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._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 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: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._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: + 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] | NotGiven = NOT_GIVEN, + boot_volume_size: Optional[int] | NotGiven = NOT_GIVEN, + boot_volume_type: Optional[Literal["cold", "ssd_hiiops", "ssd_local", "ssd_lowlatency", "standard", "ultra"]] + | NotGiven = NOT_GIVEN, + crio_config: Optional[Dict[str, str]] | NotGiven = NOT_GIVEN, + is_public_ipv4: Optional[bool] | NotGiven = NOT_GIVEN, + kubelet_config: Optional[Dict[str, str]] | NotGiven = NOT_GIVEN, + labels: Optional[Dict[str, str]] | NotGiven = NOT_GIVEN, + max_node_count: Optional[int] | NotGiven = NOT_GIVEN, + servergroup_policy: Optional[Literal["affinity", "anti-affinity", "soft-anti-affinity"]] | NotGiven = NOT_GIVEN, + taints: Optional[Dict[str, str]] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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: + 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] | NotGiven = NOT_GIVEN, + labels: Optional[Dict[str, str]] | NotGiven = NOT_GIVEN, + max_node_count: Optional[int] | NotGiven = NOT_GIVEN, + min_node_count: Optional[int] | NotGiven = NOT_GIVEN, + node_count: Optional[int] | NotGiven = NOT_GIVEN, + taints: Optional[Dict[str, str]] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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: + 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: Current node count + + 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: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._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: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._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 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: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_id = self._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: + 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.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.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.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.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..71781231 --- /dev/null +++ b/src/gcore/resources/cloud/k8s/flavors.py @@ -0,0 +1,209 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven +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 | NotGiven = NOT_GIVEN, + include_prices: bool | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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: + exclude_gpu: Set to false to include GPU flavors. Default is True. + + 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_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 | NotGiven = NOT_GIVEN, + include_prices: bool | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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: + exclude_gpu: Set to false to include GPU flavors. Default is True. + + 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_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..ad74c5fd --- /dev/null +++ b/src/gcore/resources/cloud/k8s/k8s.py @@ -0,0 +1,233 @@ +# 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 NOT_GIVEN, Body, Query, Headers, NotGiven +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: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_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: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if project_id is None: + project_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/l7_policies/l7_policies.py b/src/gcore/resources/cloud/load_balancers/l7_policies/l7_policies.py index ba9f4b28..fdecdef4 100644 --- a/src/gcore/resources/cloud/load_balancers/l7_policies/l7_policies.py +++ b/src/gcore/resources/cloud/load_balancers/l7_policies/l7_policies.py @@ -2,7 +2,6 @@ from __future__ import annotations -from typing import List from typing_extensions import Literal import httpx @@ -15,7 +14,7 @@ RulesResourceWithStreamingResponse, AsyncRulesResourceWithStreamingResponse, ) -from ....._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ....._types import NOT_GIVEN, Body, Query, Headers, NotGiven, SequenceNotStr from ....._utils import maybe_transform, async_maybe_transform from ....._compat import cached_property from ....._resource import SyncAPIResource, AsyncAPIResource @@ -71,7 +70,7 @@ def create( redirect_pool_id: str | NotGiven = NOT_GIVEN, redirect_prefix: str | NotGiven = NOT_GIVEN, redirect_url: str | NotGiven = NOT_GIVEN, - tags: List[str] | NotGiven = NOT_GIVEN, + tags: SequenceNotStr[str] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -267,7 +266,7 @@ def replace( redirect_pool_id: str | NotGiven = NOT_GIVEN, redirect_prefix: str | NotGiven = NOT_GIVEN, redirect_url: str | NotGiven = NOT_GIVEN, - tags: List[str] | NotGiven = NOT_GIVEN, + tags: SequenceNotStr[str] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -276,7 +275,7 @@ def replace( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> TaskIDList: """ - Replace load balancer L7 policy properties + Replace load balancer L7 policy Args: action: Action @@ -348,7 +347,7 @@ def create_and_poll( redirect_pool_id: str | NotGiven = NOT_GIVEN, redirect_prefix: str | NotGiven = NOT_GIVEN, redirect_url: str | NotGiven = NOT_GIVEN, - tags: List[str] | NotGiven = NOT_GIVEN, + tags: SequenceNotStr[str] | NotGiven = NOT_GIVEN, polling_interval_seconds: int | NotGiven = NOT_GIVEN, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -439,7 +438,7 @@ def replace_and_poll( redirect_pool_id: str | NotGiven = NOT_GIVEN, redirect_prefix: str | NotGiven = NOT_GIVEN, redirect_url: str | NotGiven = NOT_GIVEN, - tags: List[str] | NotGiven = NOT_GIVEN, + tags: SequenceNotStr[str] | NotGiven = NOT_GIVEN, polling_interval_seconds: int | NotGiven = NOT_GIVEN, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -518,7 +517,7 @@ async def create( redirect_pool_id: str | NotGiven = NOT_GIVEN, redirect_prefix: str | NotGiven = NOT_GIVEN, redirect_url: str | NotGiven = NOT_GIVEN, - tags: List[str] | NotGiven = NOT_GIVEN, + tags: SequenceNotStr[str] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -714,7 +713,7 @@ async def replace( redirect_pool_id: str | NotGiven = NOT_GIVEN, redirect_prefix: str | NotGiven = NOT_GIVEN, redirect_url: str | NotGiven = NOT_GIVEN, - tags: List[str] | NotGiven = NOT_GIVEN, + tags: SequenceNotStr[str] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -723,7 +722,7 @@ async def replace( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> TaskIDList: """ - Replace load balancer L7 policy properties + Replace load balancer L7 policy Args: action: Action @@ -795,7 +794,7 @@ async def create_and_poll( redirect_pool_id: str | NotGiven = NOT_GIVEN, redirect_prefix: str | NotGiven = NOT_GIVEN, redirect_url: str | NotGiven = NOT_GIVEN, - tags: List[str] | NotGiven = NOT_GIVEN, + tags: SequenceNotStr[str] | NotGiven = NOT_GIVEN, polling_interval_seconds: int | NotGiven = NOT_GIVEN, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -886,7 +885,7 @@ async def replace_and_poll( redirect_pool_id: str | NotGiven = NOT_GIVEN, redirect_prefix: str | NotGiven = NOT_GIVEN, redirect_url: str | NotGiven = NOT_GIVEN, - tags: List[str] | NotGiven = NOT_GIVEN, + tags: SequenceNotStr[str] | NotGiven = NOT_GIVEN, polling_interval_seconds: int | NotGiven = NOT_GIVEN, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. diff --git a/src/gcore/resources/cloud/load_balancers/l7_policies/rules.py b/src/gcore/resources/cloud/load_balancers/l7_policies/rules.py index 26c51d4a..626bddc8 100644 --- a/src/gcore/resources/cloud/load_balancers/l7_policies/rules.py +++ b/src/gcore/resources/cloud/load_balancers/l7_policies/rules.py @@ -2,12 +2,11 @@ from __future__ import annotations -from typing import List from typing_extensions import Literal import httpx -from ....._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ....._types import NOT_GIVEN, Body, Query, Headers, NotGiven, SequenceNotStr from ....._utils import maybe_transform, async_maybe_transform from ....._compat import cached_property from ....._resource import SyncAPIResource, AsyncAPIResource @@ -66,7 +65,7 @@ def create( value: str, invert: bool | NotGiven = NOT_GIVEN, key: str | NotGiven = NOT_GIVEN, - tags: List[str] | NotGiven = NOT_GIVEN, + tags: SequenceNotStr[str] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -258,7 +257,7 @@ def replace( compare_type: Literal["CONTAINS", "ENDS_WITH", "EQUAL_TO", "REGEX", "STARTS_WITH"] | NotGiven = NOT_GIVEN, invert: bool | NotGiven = NOT_GIVEN, key: str | NotGiven = NOT_GIVEN, - tags: List[str] | NotGiven = NOT_GIVEN, + tags: SequenceNotStr[str] | NotGiven = NOT_GIVEN, type: Literal[ "COOKIE", "FILE_TYPE", @@ -351,7 +350,7 @@ def create_and_poll( value: str, invert: bool | NotGiven = NOT_GIVEN, key: str | NotGiven = NOT_GIVEN, - tags: List[str] | NotGiven = NOT_GIVEN, + tags: SequenceNotStr[str] | NotGiven = NOT_GIVEN, polling_interval_seconds: int | NotGiven = NOT_GIVEN, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -450,7 +449,7 @@ def replace_and_poll( value: str, invert: bool | NotGiven = NOT_GIVEN, key: str | NotGiven = NOT_GIVEN, - tags: List[str] | NotGiven = NOT_GIVEN, + tags: SequenceNotStr[str] | NotGiven = NOT_GIVEN, polling_interval_seconds: int | NotGiven = NOT_GIVEN, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -535,7 +534,7 @@ async def create( value: str, invert: bool | NotGiven = NOT_GIVEN, key: str | NotGiven = NOT_GIVEN, - tags: List[str] | NotGiven = NOT_GIVEN, + tags: SequenceNotStr[str] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -727,7 +726,7 @@ async def replace( compare_type: Literal["CONTAINS", "ENDS_WITH", "EQUAL_TO", "REGEX", "STARTS_WITH"] | NotGiven = NOT_GIVEN, invert: bool | NotGiven = NOT_GIVEN, key: str | NotGiven = NOT_GIVEN, - tags: List[str] | NotGiven = NOT_GIVEN, + tags: SequenceNotStr[str] | NotGiven = NOT_GIVEN, type: Literal[ "COOKIE", "FILE_TYPE", @@ -820,7 +819,7 @@ async def create_and_poll( value: str, invert: bool | NotGiven = NOT_GIVEN, key: str | NotGiven = NOT_GIVEN, - tags: List[str] | NotGiven = NOT_GIVEN, + tags: SequenceNotStr[str] | NotGiven = NOT_GIVEN, polling_interval_seconds: int | NotGiven = NOT_GIVEN, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -919,7 +918,7 @@ async def replace_and_poll( value: str, invert: bool | NotGiven = NOT_GIVEN, key: str | NotGiven = NOT_GIVEN, - tags: List[str] | NotGiven = NOT_GIVEN, + tags: SequenceNotStr[str] | NotGiven = NOT_GIVEN, polling_interval_seconds: int | NotGiven = NOT_GIVEN, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. diff --git a/src/gcore/resources/cloud/load_balancers/listeners.py b/src/gcore/resources/cloud/load_balancers/listeners.py index ec138c0c..729fe7fe 100644 --- a/src/gcore/resources/cloud/load_balancers/listeners.py +++ b/src/gcore/resources/cloud/load_balancers/listeners.py @@ -2,11 +2,11 @@ from __future__ import annotations -from typing import List, Iterable, Optional +from typing import Iterable, Optional import httpx -from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven, SequenceNotStr from ...._utils import maybe_transform, async_maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource @@ -61,11 +61,11 @@ def create( name: str, protocol: LbListenerProtocol, protocol_port: int, - allowed_cidrs: Optional[List[str]] | NotGiven = NOT_GIVEN, + allowed_cidrs: Optional[SequenceNotStr[str]] | NotGiven = NOT_GIVEN, connection_limit: int | NotGiven = NOT_GIVEN, insert_x_forwarded: bool | NotGiven = NOT_GIVEN, secret_id: str | NotGiven = NOT_GIVEN, - sni_secret_id: List[str] | NotGiven = NOT_GIVEN, + sni_secret_id: SequenceNotStr[str] | NotGiven = NOT_GIVEN, timeout_client_data: Optional[int] | NotGiven = NOT_GIVEN, timeout_member_connect: Optional[int] | NotGiven = NOT_GIVEN, timeout_member_data: Optional[int] | NotGiven = NOT_GIVEN, @@ -158,11 +158,11 @@ def update( *, project_id: int | None = None, region_id: int | None = None, - allowed_cidrs: Optional[List[str]] | NotGiven = NOT_GIVEN, + allowed_cidrs: Optional[SequenceNotStr[str]] | NotGiven = NOT_GIVEN, connection_limit: int | NotGiven = NOT_GIVEN, name: str | NotGiven = NOT_GIVEN, secret_id: Optional[str] | NotGiven = NOT_GIVEN, - sni_secret_id: Optional[List[str]] | NotGiven = NOT_GIVEN, + sni_secret_id: Optional[SequenceNotStr[str]] | NotGiven = NOT_GIVEN, timeout_client_data: Optional[int] | NotGiven = NOT_GIVEN, timeout_member_connect: Optional[int] | NotGiven = NOT_GIVEN, timeout_member_data: Optional[int] | NotGiven = NOT_GIVEN, @@ -402,11 +402,11 @@ def create_and_poll( name: str, protocol: LbListenerProtocol, protocol_port: int, - allowed_cidrs: Optional[List[str]] | NotGiven = NOT_GIVEN, + allowed_cidrs: Optional[SequenceNotStr[str]] | NotGiven = NOT_GIVEN, connection_limit: int | NotGiven = NOT_GIVEN, insert_x_forwarded: bool | NotGiven = NOT_GIVEN, secret_id: str | NotGiven = NOT_GIVEN, - sni_secret_id: List[str] | NotGiven = NOT_GIVEN, + sni_secret_id: SequenceNotStr[str] | NotGiven = NOT_GIVEN, timeout_client_data: Optional[int] | NotGiven = NOT_GIVEN, timeout_member_connect: Optional[int] | NotGiven = NOT_GIVEN, timeout_member_data: Optional[int] | NotGiven = NOT_GIVEN, @@ -501,11 +501,11 @@ def update_and_poll( *, project_id: int | None = None, region_id: int | None = None, - allowed_cidrs: Optional[List[str]] | NotGiven = NOT_GIVEN, + allowed_cidrs: Optional[SequenceNotStr[str]] | NotGiven = NOT_GIVEN, connection_limit: int | NotGiven = NOT_GIVEN, name: str | NotGiven = NOT_GIVEN, secret_id: Optional[str] | NotGiven = NOT_GIVEN, - sni_secret_id: Optional[List[str]] | NotGiven = NOT_GIVEN, + sni_secret_id: Optional[SequenceNotStr[str]] | NotGiven = NOT_GIVEN, timeout_client_data: Optional[int] | NotGiven = NOT_GIVEN, timeout_member_connect: Optional[int] | NotGiven = NOT_GIVEN, timeout_member_data: Optional[int] | NotGiven = NOT_GIVEN, @@ -584,11 +584,11 @@ async def create( name: str, protocol: LbListenerProtocol, protocol_port: int, - allowed_cidrs: Optional[List[str]] | NotGiven = NOT_GIVEN, + allowed_cidrs: Optional[SequenceNotStr[str]] | NotGiven = NOT_GIVEN, connection_limit: int | NotGiven = NOT_GIVEN, insert_x_forwarded: bool | NotGiven = NOT_GIVEN, secret_id: str | NotGiven = NOT_GIVEN, - sni_secret_id: List[str] | NotGiven = NOT_GIVEN, + sni_secret_id: SequenceNotStr[str] | NotGiven = NOT_GIVEN, timeout_client_data: Optional[int] | NotGiven = NOT_GIVEN, timeout_member_connect: Optional[int] | NotGiven = NOT_GIVEN, timeout_member_data: Optional[int] | NotGiven = NOT_GIVEN, @@ -681,11 +681,11 @@ async def update( *, project_id: int | None = None, region_id: int | None = None, - allowed_cidrs: Optional[List[str]] | NotGiven = NOT_GIVEN, + allowed_cidrs: Optional[SequenceNotStr[str]] | NotGiven = NOT_GIVEN, connection_limit: int | NotGiven = NOT_GIVEN, name: str | NotGiven = NOT_GIVEN, secret_id: Optional[str] | NotGiven = NOT_GIVEN, - sni_secret_id: Optional[List[str]] | NotGiven = NOT_GIVEN, + sni_secret_id: Optional[SequenceNotStr[str]] | NotGiven = NOT_GIVEN, timeout_client_data: Optional[int] | NotGiven = NOT_GIVEN, timeout_member_connect: Optional[int] | NotGiven = NOT_GIVEN, timeout_member_data: Optional[int] | NotGiven = NOT_GIVEN, @@ -925,11 +925,11 @@ async def create_and_poll( name: str, protocol: LbListenerProtocol, protocol_port: int, - allowed_cidrs: Optional[List[str]] | NotGiven = NOT_GIVEN, + allowed_cidrs: Optional[SequenceNotStr[str]] | NotGiven = NOT_GIVEN, connection_limit: int | NotGiven = NOT_GIVEN, insert_x_forwarded: bool | NotGiven = NOT_GIVEN, secret_id: str | NotGiven = NOT_GIVEN, - sni_secret_id: List[str] | NotGiven = NOT_GIVEN, + sni_secret_id: SequenceNotStr[str] | NotGiven = NOT_GIVEN, timeout_client_data: Optional[int] | NotGiven = NOT_GIVEN, timeout_member_connect: Optional[int] | NotGiven = NOT_GIVEN, timeout_member_data: Optional[int] | NotGiven = NOT_GIVEN, @@ -1024,11 +1024,11 @@ async def update_and_poll( *, project_id: int | None = None, region_id: int | None = None, - allowed_cidrs: Optional[List[str]] | NotGiven = NOT_GIVEN, + allowed_cidrs: Optional[SequenceNotStr[str]] | NotGiven = NOT_GIVEN, connection_limit: int | NotGiven = NOT_GIVEN, name: str | NotGiven = NOT_GIVEN, secret_id: Optional[str] | NotGiven = NOT_GIVEN, - sni_secret_id: Optional[List[str]] | NotGiven = NOT_GIVEN, + sni_secret_id: Optional[SequenceNotStr[str]] | NotGiven = NOT_GIVEN, timeout_client_data: Optional[int] | NotGiven = NOT_GIVEN, timeout_member_connect: Optional[int] | NotGiven = NOT_GIVEN, timeout_member_data: Optional[int] | NotGiven = NOT_GIVEN, diff --git a/src/gcore/resources/cloud/load_balancers/load_balancers.py b/src/gcore/resources/cloud/load_balancers/load_balancers.py index b54df5d7..9f5f7bce 100644 --- a/src/gcore/resources/cloud/load_balancers/load_balancers.py +++ b/src/gcore/resources/cloud/load_balancers/load_balancers.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Dict, List, Iterable, Optional +from typing import Dict, Iterable, Optional import httpx @@ -30,7 +30,7 @@ StatusesResourceWithStreamingResponse, AsyncStatusesResourceWithStreamingResponse, ) -from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven, SequenceNotStr from ...._utils import maybe_transform, async_maybe_transform from .listeners import ( ListenersResource, @@ -325,7 +325,7 @@ def list( offset: int | NotGiven = NOT_GIVEN, order_by: str | NotGiven = NOT_GIVEN, show_stats: bool | NotGiven = NOT_GIVEN, - tag_key: List[str] | NotGiven = NOT_GIVEN, + tag_key: SequenceNotStr[str] | NotGiven = NOT_GIVEN, tag_key_value: str | NotGiven = NOT_GIVEN, with_ddos: bool | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -1008,7 +1008,7 @@ def list( offset: int | NotGiven = NOT_GIVEN, order_by: str | NotGiven = NOT_GIVEN, show_stats: bool | NotGiven = NOT_GIVEN, - tag_key: List[str] | NotGiven = NOT_GIVEN, + tag_key: SequenceNotStr[str] | NotGiven = NOT_GIVEN, tag_key_value: str | NotGiven = NOT_GIVEN, with_ddos: bool | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. diff --git a/src/gcore/resources/cloud/load_balancers/pools/health_monitors.py b/src/gcore/resources/cloud/load_balancers/pools/health_monitors.py index 81aab472..bae1858c 100644 --- a/src/gcore/resources/cloud/load_balancers/pools/health_monitors.py +++ b/src/gcore/resources/cloud/load_balancers/pools/health_monitors.py @@ -68,7 +68,10 @@ def create( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> TaskIDList: """ - Create load balancer pool health monitor + 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 @@ -145,8 +148,11 @@ def delete( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> None: - """ - Delete load balancer pool health monitor + """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 @@ -221,7 +227,10 @@ async def create( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> TaskIDList: """ - Create load balancer pool health monitor + 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 @@ -298,8 +307,11 @@ async def delete( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> None: - """ - Delete load balancer pool health monitor + """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 diff --git a/src/gcore/resources/cloud/load_balancers/pools/members.py b/src/gcore/resources/cloud/load_balancers/pools/members.py index a2a9ba94..05091a8b 100644 --- a/src/gcore/resources/cloud/load_balancers/pools/members.py +++ b/src/gcore/resources/cloud/load_balancers/pools/members.py @@ -99,7 +99,22 @@ def add( 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. + 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 @@ -264,7 +279,22 @@ async def add( 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. + 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 diff --git a/src/gcore/resources/cloud/load_balancers/pools/pools.py b/src/gcore/resources/cloud/load_balancers/pools/pools.py index 630912dc..e15c696f 100644 --- a/src/gcore/resources/cloud/load_balancers/pools/pools.py +++ b/src/gcore/resources/cloud/load_balancers/pools/pools.py @@ -199,9 +199,21 @@ def update( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> TaskIDList: """ - Changes provided here will overwrite existing load balancer pool settings. - Undefined fields will be kept as is. Complex objects need to be specified fully, - they will be overwritten. + 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 @@ -250,7 +262,7 @@ def update( 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/v1/lbpools/{project_id}/{region_id}/{pool_id}", + f"/cloud/v2/lbpools/{project_id}/{region_id}/{pool_id}", body=maybe_transform( { "ca_secret_id": ca_secret_id, @@ -745,9 +757,21 @@ async def update( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> TaskIDList: """ - Changes provided here will overwrite existing load balancer pool settings. - Undefined fields will be kept as is. Complex objects need to be specified fully, - they will be overwritten. + 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 @@ -796,7 +820,7 @@ async def update( 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/v1/lbpools/{project_id}/{region_id}/{pool_id}", + f"/cloud/v2/lbpools/{project_id}/{region_id}/{pool_id}", body=await async_maybe_transform( { "ca_secret_id": ca_secret_id, diff --git a/src/gcore/resources/cloud/networks/networks.py b/src/gcore/resources/cloud/networks/networks.py index 13f2084d..09de9d55 100644 --- a/src/gcore/resources/cloud/networks/networks.py +++ b/src/gcore/resources/cloud/networks/networks.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Dict, List, Optional +from typing import Dict, Optional from typing_extensions import Literal import httpx @@ -23,7 +23,7 @@ SubnetsResourceWithStreamingResponse, AsyncSubnetsResourceWithStreamingResponse, ) -from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven, SequenceNotStr from ...._utils import maybe_transform, async_maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource @@ -136,6 +136,56 @@ def create( cast_to=TaskIDList, ) + def create_and_poll( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + name: str, + create_router: bool | NotGiven = NOT_GIVEN, + tags: Dict[str, str] | NotGiven = NOT_GIVEN, + type: Literal["vlan", "vxlan"] | NotGiven = NOT_GIVEN, + polling_interval_seconds: int | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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: + """Create network and poll for the result.""" + response = self.create( + project_id=project_id, + region_id=region_id, + name=name, + create_router=create_router, + tags=tags, + type=type, + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + ) + if not response.tasks or len(response.tasks) != 1: + raise ValueError(f"Expected exactly one task to be created") + task = self._client.cloud.tasks.poll( + task_id=response.tasks[0], + extra_headers=extra_headers, + polling_interval_seconds=polling_interval_seconds, + ) + if ( + not task.created_resources + or not task.created_resources.networks + or len(task.created_resources.networks) != 1 + ): + raise ValueError(f"Expected exactly one resource to be created in a task") + return self.get( + network_id=task.created_resources.networks[0], + project_id=project_id, + region_id=region_id, + extra_headers=extra_headers, + ) + def update( self, network_id: str, @@ -224,7 +274,7 @@ def list( name: str | NotGiven = NOT_GIVEN, offset: int | NotGiven = NOT_GIVEN, order_by: Literal["created_at.asc", "created_at.desc", "name.asc", "name.desc"] | NotGiven = NOT_GIVEN, - tag_key: List[str] | NotGiven = NOT_GIVEN, + tag_key: SequenceNotStr[str] | NotGiven = NOT_GIVEN, tag_key_value: str | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -335,6 +385,38 @@ def delete( cast_to=TaskIDList, ) + def delete_and_poll( + self, + network_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + polling_interval_seconds: int | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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 network and poll for the result.""" + response = self.delete( + network_id=network_id, + project_id=project_id, + region_id=region_id, + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + ) + if not response.tasks: + raise ValueError("Expected at least one task to be created") + self._client.cloud.tasks.poll( + task_id=response.tasks[0], + extra_headers=extra_headers, + polling_interval_seconds=polling_interval_seconds, + ) + def get( self, network_id: str, @@ -474,6 +556,56 @@ async def create( cast_to=TaskIDList, ) + async def create_and_poll( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + name: str, + create_router: bool | NotGiven = NOT_GIVEN, + tags: Dict[str, str] | NotGiven = NOT_GIVEN, + type: Literal["vlan", "vxlan"] | NotGiven = NOT_GIVEN, + polling_interval_seconds: int | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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: + """Create network and poll for the result.""" + response = await self.create( + project_id=project_id, + region_id=region_id, + name=name, + create_router=create_router, + tags=tags, + type=type, + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + ) + if not response.tasks or len(response.tasks) != 1: + raise ValueError(f"Expected exactly one task to be created") + task = await self._client.cloud.tasks.poll( + task_id=response.tasks[0], + extra_headers=extra_headers, + polling_interval_seconds=polling_interval_seconds, + ) + if ( + not task.created_resources + or not task.created_resources.networks + or len(task.created_resources.networks) != 1 + ): + raise ValueError(f"Expected exactly one resource to be created in a task") + return await self.get( + network_id=task.created_resources.networks[0], + project_id=project_id, + region_id=region_id, + extra_headers=extra_headers, + ) + async def update( self, network_id: str, @@ -562,7 +694,7 @@ def list( name: str | NotGiven = NOT_GIVEN, offset: int | NotGiven = NOT_GIVEN, order_by: Literal["created_at.asc", "created_at.desc", "name.asc", "name.desc"] | NotGiven = NOT_GIVEN, - tag_key: List[str] | NotGiven = NOT_GIVEN, + tag_key: SequenceNotStr[str] | NotGiven = NOT_GIVEN, tag_key_value: str | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -673,6 +805,38 @@ async def delete( cast_to=TaskIDList, ) + async def delete_and_poll( + self, + network_id: str, + *, + project_id: int | None = None, + region_id: int | None = None, + polling_interval_seconds: int | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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 network and poll for the result.""" + response = await self.delete( + network_id=network_id, + project_id=project_id, + region_id=region_id, + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + ) + if not response.tasks: + raise ValueError("Expected at least one task to be created") + await self._client.cloud.tasks.poll( + task_id=response.tasks[0], + extra_headers=extra_headers, + polling_interval_seconds=polling_interval_seconds, + ) + async def get( self, network_id: str, @@ -726,6 +890,9 @@ def __init__(self, networks: NetworksResource) -> None: self.create = to_raw_response_wrapper( networks.create, ) + self.create_and_poll = to_raw_response_wrapper( + networks.create_and_poll, + ) self.update = to_raw_response_wrapper( networks.update, ) @@ -735,6 +902,9 @@ def __init__(self, networks: NetworksResource) -> None: self.delete = to_raw_response_wrapper( networks.delete, ) + self.delete_and_poll = to_raw_response_wrapper( + networks.delete_and_poll, + ) self.get = to_raw_response_wrapper( networks.get, ) @@ -755,6 +925,9 @@ def __init__(self, networks: AsyncNetworksResource) -> None: self.create = async_to_raw_response_wrapper( networks.create, ) + self.create_and_poll = async_to_raw_response_wrapper( + networks.create_and_poll, + ) self.update = async_to_raw_response_wrapper( networks.update, ) @@ -764,6 +937,9 @@ def __init__(self, networks: AsyncNetworksResource) -> None: self.delete = async_to_raw_response_wrapper( networks.delete, ) + self.delete_and_poll = async_to_raw_response_wrapper( + networks.delete_and_poll, + ) self.get = async_to_raw_response_wrapper( networks.get, ) @@ -784,6 +960,9 @@ def __init__(self, networks: NetworksResource) -> None: self.create = to_streamed_response_wrapper( networks.create, ) + self.create_and_poll = to_streamed_response_wrapper( + networks.create_and_poll, + ) self.update = to_streamed_response_wrapper( networks.update, ) @@ -793,6 +972,9 @@ def __init__(self, networks: NetworksResource) -> None: self.delete = to_streamed_response_wrapper( networks.delete, ) + self.delete_and_poll = to_streamed_response_wrapper( + networks.delete_and_poll, + ) self.get = to_streamed_response_wrapper( networks.get, ) @@ -813,6 +995,9 @@ def __init__(self, networks: AsyncNetworksResource) -> None: self.create = async_to_streamed_response_wrapper( networks.create, ) + self.create_and_poll = async_to_streamed_response_wrapper( + networks.create_and_poll, + ) self.update = async_to_streamed_response_wrapper( networks.update, ) @@ -822,6 +1007,9 @@ def __init__(self, networks: AsyncNetworksResource) -> None: self.delete = async_to_streamed_response_wrapper( networks.delete, ) + self.delete_and_poll = async_to_streamed_response_wrapper( + networks.delete_and_poll, + ) self.get = async_to_streamed_response_wrapper( networks.get, ) diff --git a/src/gcore/resources/cloud/networks/subnets.py b/src/gcore/resources/cloud/networks/subnets.py index 1f61c9b2..1b66df06 100644 --- a/src/gcore/resources/cloud/networks/subnets.py +++ b/src/gcore/resources/cloud/networks/subnets.py @@ -2,12 +2,12 @@ from __future__ import annotations -from typing import Dict, List, Iterable, Optional +from typing import Dict, Iterable, Optional from typing_extensions import Literal import httpx -from ...._types import NOT_GIVEN, Body, Query, Headers, NoneType, NotGiven +from ...._types import NOT_GIVEN, Body, Query, Headers, NoneType, NotGiven, SequenceNotStr from ...._utils import maybe_transform, async_maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource @@ -58,7 +58,7 @@ def create( name: str, network_id: str, connect_to_network_router: bool | NotGiven = NOT_GIVEN, - dns_nameservers: Optional[List[str]] | NotGiven = NOT_GIVEN, + dns_nameservers: Optional[SequenceNotStr[str]] | NotGiven = NOT_GIVEN, enable_dhcp: bool | NotGiven = NOT_GIVEN, gateway_ip: Optional[str] | NotGiven = NOT_GIVEN, host_routes: Optional[Iterable[subnet_create_params.HostRoute]] | NotGiven = NOT_GIVEN, @@ -148,13 +148,73 @@ def create( cast_to=TaskIDList, ) + def create_and_poll( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + cidr: str, + name: str, + network_id: str, + connect_to_network_router: bool | NotGiven = NOT_GIVEN, + dns_nameservers: Optional[SequenceNotStr[str]] | NotGiven = NOT_GIVEN, + enable_dhcp: bool | NotGiven = NOT_GIVEN, + gateway_ip: Optional[str] | NotGiven = NOT_GIVEN, + host_routes: Optional[Iterable[subnet_create_params.HostRoute]] | NotGiven = NOT_GIVEN, + ip_version: IPVersion | NotGiven = NOT_GIVEN, + router_id_to_connect: Optional[str] | NotGiven = NOT_GIVEN, + tags: Dict[str, str] | NotGiven = NOT_GIVEN, + polling_interval_seconds: int | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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: + """Create subnet and poll for the result.""" + response = self.create( + project_id=project_id, + region_id=region_id, + 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, + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + ) + if not response.tasks or len(response.tasks) != 1: + raise ValueError(f"Expected exactly one task to be created") + task = self._client.cloud.tasks.poll( + task_id=response.tasks[0], + extra_headers=extra_headers, + polling_interval_seconds=polling_interval_seconds, + ) + if not task.created_resources or not task.created_resources.subnets or len(task.created_resources.subnets) != 1: + raise ValueError(f"Expected exactly one resource to be created in a task") + return self.get( + subnet_id=task.created_resources.subnets[0], + project_id=project_id, + region_id=region_id, + extra_headers=extra_headers, + ) + def update( self, subnet_id: str, *, project_id: int | None = None, region_id: int | None = None, - dns_nameservers: Optional[List[str]] | NotGiven = NOT_GIVEN, + dns_nameservers: Optional[SequenceNotStr[str]] | NotGiven = NOT_GIVEN, enable_dhcp: Optional[bool] | NotGiven = NOT_GIVEN, gateway_ip: Optional[str] | NotGiven = NOT_GIVEN, host_routes: Optional[Iterable[subnet_update_params.HostRoute]] | NotGiven = NOT_GIVEN, @@ -266,7 +326,7 @@ def list( "updated_at.desc", ] | NotGiven = NOT_GIVEN, - tag_key: List[str] | NotGiven = NOT_GIVEN, + tag_key: SequenceNotStr[str] | NotGiven = NOT_GIVEN, tag_key_value: str | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -454,7 +514,7 @@ async def create( name: str, network_id: str, connect_to_network_router: bool | NotGiven = NOT_GIVEN, - dns_nameservers: Optional[List[str]] | NotGiven = NOT_GIVEN, + dns_nameservers: Optional[SequenceNotStr[str]] | NotGiven = NOT_GIVEN, enable_dhcp: bool | NotGiven = NOT_GIVEN, gateway_ip: Optional[str] | NotGiven = NOT_GIVEN, host_routes: Optional[Iterable[subnet_create_params.HostRoute]] | NotGiven = NOT_GIVEN, @@ -544,13 +604,73 @@ async def create( cast_to=TaskIDList, ) + async def create_and_poll( + self, + *, + project_id: int | None = None, + region_id: int | None = None, + cidr: str, + name: str, + network_id: str, + connect_to_network_router: bool | NotGiven = NOT_GIVEN, + dns_nameservers: Optional[SequenceNotStr[str]] | NotGiven = NOT_GIVEN, + enable_dhcp: bool | NotGiven = NOT_GIVEN, + gateway_ip: Optional[str] | NotGiven = NOT_GIVEN, + host_routes: Optional[Iterable[subnet_create_params.HostRoute]] | NotGiven = NOT_GIVEN, + ip_version: IPVersion | NotGiven = NOT_GIVEN, + router_id_to_connect: Optional[str] | NotGiven = NOT_GIVEN, + tags: Dict[str, str] | NotGiven = NOT_GIVEN, + polling_interval_seconds: int | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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: + """Create subnet and poll for the result.""" + response = await self.create( + project_id=project_id, + region_id=region_id, + 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, + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + ) + if not response.tasks or len(response.tasks) != 1: + raise ValueError(f"Expected exactly one task to be created") + task = await self._client.cloud.tasks.poll( + task_id=response.tasks[0], + extra_headers=extra_headers, + polling_interval_seconds=polling_interval_seconds, + ) + if not task.created_resources or not task.created_resources.subnets or len(task.created_resources.subnets) != 1: + raise ValueError(f"Expected exactly one resource to be created in a task") + return await self.get( + subnet_id=task.created_resources.subnets[0], + project_id=project_id, + region_id=region_id, + extra_headers=extra_headers, + ) + async def update( self, subnet_id: str, *, project_id: int | None = None, region_id: int | None = None, - dns_nameservers: Optional[List[str]] | NotGiven = NOT_GIVEN, + dns_nameservers: Optional[SequenceNotStr[str]] | NotGiven = NOT_GIVEN, enable_dhcp: Optional[bool] | NotGiven = NOT_GIVEN, gateway_ip: Optional[str] | NotGiven = NOT_GIVEN, host_routes: Optional[Iterable[subnet_update_params.HostRoute]] | NotGiven = NOT_GIVEN, @@ -662,7 +782,7 @@ def list( "updated_at.desc", ] | NotGiven = NOT_GIVEN, - tag_key: List[str] | NotGiven = NOT_GIVEN, + tag_key: SequenceNotStr[str] | NotGiven = NOT_GIVEN, tag_key_value: str | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -828,6 +948,9 @@ def __init__(self, subnets: SubnetsResource) -> None: self.create = to_raw_response_wrapper( subnets.create, ) + self.create_and_poll = to_raw_response_wrapper( + subnets.create_and_poll, + ) self.update = to_raw_response_wrapper( subnets.update, ) @@ -849,6 +972,9 @@ def __init__(self, subnets: AsyncSubnetsResource) -> None: self.create = async_to_raw_response_wrapper( subnets.create, ) + self.create_and_poll = async_to_raw_response_wrapper( + subnets.create_and_poll, + ) self.update = async_to_raw_response_wrapper( subnets.update, ) @@ -870,6 +996,9 @@ def __init__(self, subnets: SubnetsResource) -> None: self.create = to_streamed_response_wrapper( subnets.create, ) + self.create_and_poll = to_streamed_response_wrapper( + subnets.create_and_poll, + ) self.update = to_streamed_response_wrapper( subnets.update, ) @@ -891,6 +1020,9 @@ def __init__(self, subnets: AsyncSubnetsResource) -> None: self.create = async_to_streamed_response_wrapper( subnets.create, ) + self.create_and_poll = async_to_streamed_response_wrapper( + subnets.create_and_poll, + ) self.update = async_to_streamed_response_wrapper( subnets.update, ) diff --git a/src/gcore/resources/cloud/reserved_fixed_ips/vip.py b/src/gcore/resources/cloud/reserved_fixed_ips/vip.py index 6d3c91f3..1d6c76e2 100644 --- a/src/gcore/resources/cloud/reserved_fixed_ips/vip.py +++ b/src/gcore/resources/cloud/reserved_fixed_ips/vip.py @@ -2,11 +2,9 @@ from __future__ import annotations -from typing import List - import httpx -from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven, SequenceNotStr from ...._utils import maybe_transform, async_maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource @@ -133,7 +131,7 @@ def replace_connected_ports( *, project_id: int | None = None, region_id: int | None = None, - port_ids: List[str] | NotGiven = NOT_GIVEN, + port_ids: SequenceNotStr[str] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -221,7 +219,7 @@ def update_connected_ports( *, project_id: int | None = None, region_id: int | None = None, - port_ids: List[str] | NotGiven = NOT_GIVEN, + port_ids: SequenceNotStr[str] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -365,7 +363,7 @@ async def replace_connected_ports( *, project_id: int | None = None, region_id: int | None = None, - port_ids: List[str] | NotGiven = NOT_GIVEN, + port_ids: SequenceNotStr[str] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -453,7 +451,7 @@ async def update_connected_ports( *, project_id: int | None = None, region_id: int | None = None, - port_ids: List[str] | NotGiven = NOT_GIVEN, + port_ids: SequenceNotStr[str] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, diff --git a/src/gcore/resources/cloud/security_groups/security_groups.py b/src/gcore/resources/cloud/security_groups/security_groups.py index 034bbe2b..ac4d9bc3 100644 --- a/src/gcore/resources/cloud/security_groups/security_groups.py +++ b/src/gcore/resources/cloud/security_groups/security_groups.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import List, Iterable, Optional +from typing import Iterable, Optional import httpx @@ -14,7 +14,7 @@ RulesResourceWithStreamingResponse, AsyncRulesResourceWithStreamingResponse, ) -from ...._types import NOT_GIVEN, Body, Query, Headers, NoneType, NotGiven +from ...._types import NOT_GIVEN, Body, Query, Headers, NoneType, NotGiven, SequenceNotStr from ...._utils import maybe_transform, async_maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource @@ -68,7 +68,7 @@ def create( project_id: int | None = None, region_id: int | None = None, security_group: security_group_create_params.SecurityGroup, - instances: List[str] | NotGiven = NOT_GIVEN, + instances: SequenceNotStr[str] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -192,7 +192,7 @@ def list( region_id: int | None = None, limit: int | NotGiven = NOT_GIVEN, offset: int | NotGiven = NOT_GIVEN, - tag_key: List[str] | NotGiven = NOT_GIVEN, + tag_key: SequenceNotStr[str] | NotGiven = NOT_GIVEN, tag_key_value: str | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -438,7 +438,7 @@ async def create( project_id: int | None = None, region_id: int | None = None, security_group: security_group_create_params.SecurityGroup, - instances: List[str] | NotGiven = NOT_GIVEN, + instances: SequenceNotStr[str] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -562,7 +562,7 @@ def list( region_id: int | None = None, limit: int | NotGiven = NOT_GIVEN, offset: int | NotGiven = NOT_GIVEN, - tag_key: List[str] | NotGiven = NOT_GIVEN, + tag_key: SequenceNotStr[str] | NotGiven = NOT_GIVEN, tag_key_value: str | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. diff --git a/src/gcore/resources/cloud/tasks.py b/src/gcore/resources/cloud/tasks.py index f4f96fbc..2fbc8d91 100644 --- a/src/gcore/resources/cloud/tasks.py +++ b/src/gcore/resources/cloud/tasks.py @@ -142,25 +142,25 @@ def list( '`create_faas_function`', '`create_faas_namespace`', '`create_fip`', '`create_gpu_virtual_cluster`', '`create_image`', '`create_inference_application`', '`create_inference_instance`', - '`create_inference_instance_key`', '`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_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_reserved_fixed_ip`', '`delete_router`', - '`delete_secret`', '`delete_servergroup`', '`delete_sfs`', '`delete_snapshot`', - '`delete_subnet`', '`delete_vm`', '`delete_volume`', '`detach_vm_interface`', - '`detach_volume`', '`download_image`', '`downscale_ai_cluster_gpu`', + '`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_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_reserved_fixed_ip`', '`delete_router`', '`delete_secret`', + '`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`', @@ -177,10 +177,10 @@ def list( '`stop_gpu_virtual_cluster`', '`stop_gpu_virtual_server`', '`stop_vm`', '`suspend_vm`', '`sync_private_flavors`', '`update_ddos_profile`', '`update_inference_application`', '`update_inference_instance`', - '`update_inference_instance_key`', '`update_k8s_cluster_v2`', - '`update_lbmetadata`', '`update_port_allowed_address_pairs`', - '`update_tags_gpu_virtual_cluster`', '`upgrade_k8s_cluster_v2`', - '`upscale_ai_cluster_gpu`', '`upscale_gpu_virtual_cluster`'] + '`update_k8s_cluster_v2`', '`update_lbmetadata`', + '`update_port_allowed_address_pairs`', '`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` @@ -451,25 +451,25 @@ def list( '`create_faas_function`', '`create_faas_namespace`', '`create_fip`', '`create_gpu_virtual_cluster`', '`create_image`', '`create_inference_application`', '`create_inference_instance`', - '`create_inference_instance_key`', '`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_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_reserved_fixed_ip`', '`delete_router`', - '`delete_secret`', '`delete_servergroup`', '`delete_sfs`', '`delete_snapshot`', - '`delete_subnet`', '`delete_vm`', '`delete_volume`', '`detach_vm_interface`', - '`detach_volume`', '`download_image`', '`downscale_ai_cluster_gpu`', + '`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_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_reserved_fixed_ip`', '`delete_router`', '`delete_secret`', + '`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`', @@ -486,10 +486,10 @@ def list( '`stop_gpu_virtual_cluster`', '`stop_gpu_virtual_server`', '`stop_vm`', '`suspend_vm`', '`sync_private_flavors`', '`update_ddos_profile`', '`update_inference_application`', '`update_inference_instance`', - '`update_inference_instance_key`', '`update_k8s_cluster_v2`', - '`update_lbmetadata`', '`update_port_allowed_address_pairs`', - '`update_tags_gpu_virtual_cluster`', '`upgrade_k8s_cluster_v2`', - '`upscale_ai_cluster_gpu`', '`upscale_gpu_virtual_cluster`'] + '`update_k8s_cluster_v2`', '`update_lbmetadata`', + '`update_port_allowed_address_pairs`', '`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` diff --git a/src/gcore/resources/cloud/users/role_assignments.py b/src/gcore/resources/cloud/users/role_assignments.py index 1b09de11..5294d3a7 100644 --- a/src/gcore/resources/cloud/users/role_assignments.py +++ b/src/gcore/resources/cloud/users/role_assignments.py @@ -3,6 +3,7 @@ from __future__ import annotations from typing import Optional +from typing_extensions import Literal import httpx @@ -52,7 +53,7 @@ def with_streaming_response(self) -> RoleAssignmentsResourceWithStreamingRespons def create( self, *, - role: str, + role: Literal["ClientAdministrator", "InternalNetworkOnlyUser", "Observer", "ProjectAdministrator", "User"], user_id: int, client_id: Optional[int] | NotGiven = NOT_GIVEN, project_id: Optional[int] | NotGiven = NOT_GIVEN, @@ -104,7 +105,7 @@ def update( self, assignment_id: int, *, - role: str, + role: Literal["ClientAdministrator", "InternalNetworkOnlyUser", "Observer", "ProjectAdministrator", "User"], user_id: int, client_id: Optional[int] | NotGiven = NOT_GIVEN, project_id: Optional[int] | NotGiven = NOT_GIVEN, @@ -267,7 +268,7 @@ def with_streaming_response(self) -> AsyncRoleAssignmentsResourceWithStreamingRe async def create( self, *, - role: str, + role: Literal["ClientAdministrator", "InternalNetworkOnlyUser", "Observer", "ProjectAdministrator", "User"], user_id: int, client_id: Optional[int] | NotGiven = NOT_GIVEN, project_id: Optional[int] | NotGiven = NOT_GIVEN, @@ -319,7 +320,7 @@ async def update( self, assignment_id: int, *, - role: str, + role: Literal["ClientAdministrator", "InternalNetworkOnlyUser", "Observer", "ProjectAdministrator", "User"], user_id: int, client_id: Optional[int] | NotGiven = NOT_GIVEN, project_id: Optional[int] | NotGiven = NOT_GIVEN, diff --git a/src/gcore/resources/cloud/volumes.py b/src/gcore/resources/cloud/volumes.py index 06159e25..ed0babaa 100644 --- a/src/gcore/resources/cloud/volumes.py +++ b/src/gcore/resources/cloud/volumes.py @@ -2,12 +2,12 @@ from __future__ import annotations -from typing import List, Iterable, Optional +from typing import Iterable, Optional from typing_extensions import Literal, overload import httpx -from ..._types import NOT_GIVEN, Body, Query, Headers, NoneType, NotGiven +from ..._types import NOT_GIVEN, Body, Query, Headers, NoneType, NotGiven, SequenceNotStr from ..._utils import required_args, maybe_transform, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource @@ -403,7 +403,7 @@ def list( limit: int | NotGiven = NOT_GIVEN, name_part: str | NotGiven = NOT_GIVEN, offset: int | NotGiven = NOT_GIVEN, - tag_key: List[str] | NotGiven = NOT_GIVEN, + tag_key: SequenceNotStr[str] | NotGiven = NOT_GIVEN, tag_key_value: str | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -1212,7 +1212,7 @@ def list( limit: int | NotGiven = NOT_GIVEN, name_part: str | NotGiven = NOT_GIVEN, offset: int | NotGiven = NOT_GIVEN, - tag_key: List[str] | NotGiven = NOT_GIVEN, + tag_key: SequenceNotStr[str] | NotGiven = NOT_GIVEN, tag_key_value: str | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. diff --git a/src/gcore/resources/dns/__init__.py b/src/gcore/resources/dns/__init__.py new file mode 100644 index 00000000..12d75f5f --- /dev/null +++ b/src/gcore/resources/dns/__init__.py @@ -0,0 +1,75 @@ +# 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, +) + +__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", + "DNSResource", + "AsyncDNSResource", + "DNSResourceWithRawResponse", + "AsyncDNSResourceWithRawResponse", + "DNSResourceWithStreamingResponse", + "AsyncDNSResourceWithStreamingResponse", +] diff --git a/src/gcore/resources/dns/dns.py b/src/gcore/resources/dns/dns.py new file mode 100644 index 00000000..3e6485d0 --- /dev/null +++ b/src/gcore/resources/dns/dns.py @@ -0,0 +1,374 @@ +# 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 NOT_GIVEN, Body, Query, Headers, NotGiven +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 ...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 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 | NotGiven = NOT_GIVEN, + request_server: Literal["authoritative_dns", "google", "cloudflare", "open_dns", "quad9", "gcore"] + | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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 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 | NotGiven = NOT_GIVEN, + request_server: Literal["authoritative_dns", "google", "cloudflare", "open_dns", "quad9", "gcore"] + | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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) + + +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) + + +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) + + +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) diff --git a/src/gcore/resources/dns/locations.py b/src/gcore/resources/dns/locations.py new file mode 100644 index 00000000..20dcea5a --- /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 NOT_GIVEN, Body, Query, Headers, NotGiven +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..8eef7aeb --- /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 NOT_GIVEN, Body, Query, Headers, NotGiven, SequenceNotStr +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] | NotGiven = NOT_GIVEN, + zone_names: SequenceNotStr[str] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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] | NotGiven = NOT_GIVEN, + zone_names: SequenceNotStr[str] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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/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..3078c7f2 --- /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 NOT_GIVEN, Body, Query, Headers, NotGiven +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..aebd10ff --- /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 NOT_GIVEN, Body, Query, Headers, NotGiven +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/cloud/inference/models.py b/src/gcore/resources/dns/zones/dnssec.py similarity index 53% rename from src/gcore/resources/cloud/inference/models.py rename to src/gcore/resources/dns/zones/dnssec.py index b28decb5..8c747071 100644 --- a/src/gcore/resources/cloud/inference/models.py +++ b/src/gcore/resources/dns/zones/dnssec.py @@ -2,12 +2,10 @@ from __future__ import annotations -from typing_extensions import Literal - import httpx from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven -from ...._utils import maybe_transform +from ...._utils import maybe_transform, async_maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource from ...._response import ( @@ -16,59 +14,50 @@ 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 model_list_params -from ....types.cloud.inference.inference_model import InferenceModel +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__ = ["ModelsResource", "AsyncModelsResource"] +__all__ = ["DnssecResource", "AsyncDnssecResource"] -class ModelsResource(SyncAPIResource): +class DnssecResource(SyncAPIResource): @cached_property - def with_raw_response(self) -> ModelsResourceWithRawResponse: + 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 ModelsResourceWithRawResponse(self) + return DnssecResourceWithRawResponse(self) @cached_property - def with_streaming_response(self) -> ModelsResourceWithStreamingResponse: + 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 ModelsResourceWithStreamingResponse(self) + return DnssecResourceWithStreamingResponse(self) - def list( + def update( self, + name: str, *, - limit: int | NotGiven = NOT_GIVEN, - offset: int | NotGiven = NOT_GIVEN, - order_by: Literal["name.asc", "name.desc"] | NotGiven = NOT_GIVEN, + enabled: bool | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this 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[InferenceModel]: - """List models from catalog + ) -> DnssecUpdateResponse: + """ + Enable or disable DNSSEC for a DNS zone. 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 - - order_by: Order instances by transmitted fields and directions - extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -77,29 +66,20 @@ def list( timeout: Override the client-level default timeout for this request, in seconds """ - return self._get_api_list( - "/cloud/v3/inference/models", - page=SyncOffsetPage[InferenceModel], + 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, - query=maybe_transform( - { - "limit": limit, - "offset": offset, - "order_by": order_by, - }, - model_list_params.ModelListParams, - ), + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - model=InferenceModel, + cast_to=DnssecUpdateResponse, ) def get( self, - model_id: str, + 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. @@ -107,13 +87,11 @@ def get( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> InferenceModel: + ) -> DnssecGetResponse: """ - Get model from catalog + Get DNSSEC DS for a DNS zone. Args: - model_id: Model ID - extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -122,62 +100,53 @@ def get( timeout: Override the client-level default timeout for this request, in seconds """ - if not model_id: - raise ValueError(f"Expected a non-empty value for `model_id` but received {model_id!r}") + if not name: + raise ValueError(f"Expected a non-empty value for `name` but received {name!r}") return self._get( - f"/cloud/v3/inference/models/{model_id}", + 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=InferenceModel, + cast_to=DnssecGetResponse, ) -class AsyncModelsResource(AsyncAPIResource): +class AsyncDnssecResource(AsyncAPIResource): @cached_property - def with_raw_response(self) -> AsyncModelsResourceWithRawResponse: + 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 AsyncModelsResourceWithRawResponse(self) + return AsyncDnssecResourceWithRawResponse(self) @cached_property - def with_streaming_response(self) -> AsyncModelsResourceWithStreamingResponse: + 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 AsyncModelsResourceWithStreamingResponse(self) + return AsyncDnssecResourceWithStreamingResponse(self) - def list( + async def update( self, + name: str, *, - limit: int | NotGiven = NOT_GIVEN, - offset: int | NotGiven = NOT_GIVEN, - order_by: Literal["name.asc", "name.desc"] | NotGiven = NOT_GIVEN, + enabled: bool | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this 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[InferenceModel, AsyncOffsetPage[InferenceModel]]: - """List models from catalog + ) -> DnssecUpdateResponse: + """ + Enable or disable DNSSEC for a DNS zone. 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 - - order_by: Order instances by transmitted fields and directions - extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -186,29 +155,20 @@ def list( timeout: Override the client-level default timeout for this request, in seconds """ - return self._get_api_list( - "/cloud/v3/inference/models", - page=AsyncOffsetPage[InferenceModel], + 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, - query=maybe_transform( - { - "limit": limit, - "offset": offset, - "order_by": order_by, - }, - model_list_params.ModelListParams, - ), + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), - model=InferenceModel, + cast_to=DnssecUpdateResponse, ) async def get( self, - model_id: str, + 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. @@ -216,13 +176,11 @@ async def get( extra_query: Query | None = None, extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> InferenceModel: + ) -> DnssecGetResponse: """ - Get model from catalog + Get DNSSEC DS for a DNS zone. Args: - model_id: Model ID - extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -231,60 +189,60 @@ async def get( timeout: Override the client-level default timeout for this request, in seconds """ - if not model_id: - raise ValueError(f"Expected a non-empty value for `model_id` but received {model_id!r}") + if not name: + raise ValueError(f"Expected a non-empty value for `name` but received {name!r}") return await self._get( - f"/cloud/v3/inference/models/{model_id}", + 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=InferenceModel, + cast_to=DnssecGetResponse, ) -class ModelsResourceWithRawResponse: - def __init__(self, models: ModelsResource) -> None: - self._models = models +class DnssecResourceWithRawResponse: + def __init__(self, dnssec: DnssecResource) -> None: + self._dnssec = dnssec - self.list = to_raw_response_wrapper( - models.list, + self.update = to_raw_response_wrapper( + dnssec.update, ) self.get = to_raw_response_wrapper( - models.get, + dnssec.get, ) -class AsyncModelsResourceWithRawResponse: - def __init__(self, models: AsyncModelsResource) -> None: - self._models = models +class AsyncDnssecResourceWithRawResponse: + def __init__(self, dnssec: AsyncDnssecResource) -> None: + self._dnssec = dnssec - self.list = async_to_raw_response_wrapper( - models.list, + self.update = async_to_raw_response_wrapper( + dnssec.update, ) self.get = async_to_raw_response_wrapper( - models.get, + dnssec.get, ) -class ModelsResourceWithStreamingResponse: - def __init__(self, models: ModelsResource) -> None: - self._models = models +class DnssecResourceWithStreamingResponse: + def __init__(self, dnssec: DnssecResource) -> None: + self._dnssec = dnssec - self.list = to_streamed_response_wrapper( - models.list, + self.update = to_streamed_response_wrapper( + dnssec.update, ) self.get = to_streamed_response_wrapper( - models.get, + dnssec.get, ) -class AsyncModelsResourceWithStreamingResponse: - def __init__(self, models: AsyncModelsResource) -> None: - self._models = models +class AsyncDnssecResourceWithStreamingResponse: + def __init__(self, dnssec: AsyncDnssecResource) -> None: + self._dnssec = dnssec - self.list = async_to_streamed_response_wrapper( - models.list, + self.update = async_to_streamed_response_wrapper( + dnssec.update, ) self.get = async_to_streamed_response_wrapper( - models.get, + 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..e1d136b1 --- /dev/null +++ b/src/gcore/resources/dns/zones/rrsets.py @@ -0,0 +1,1005 @@ +# 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 NOT_GIVEN, Body, Query, Headers, NotGiven +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] | NotGiven = NOT_GIVEN, + pickers: Iterable[rrset_create_params.Picker] | NotGiven = NOT_GIVEN, + ttl: int | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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 | NotGiven = NOT_GIVEN, + offset: int | NotGiven = NOT_GIVEN, + order_by: str | NotGiven = NOT_GIVEN, + order_direction: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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 | NotGiven = NOT_GIVEN, + offset: int | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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] | NotGiven = NOT_GIVEN, + pickers: Iterable[rrset_replace_params.Picker] | NotGiven = NOT_GIVEN, + ttl: int | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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] | NotGiven = NOT_GIVEN, + pickers: Iterable[rrset_create_params.Picker] | NotGiven = NOT_GIVEN, + ttl: int | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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 | NotGiven = NOT_GIVEN, + offset: int | NotGiven = NOT_GIVEN, + order_by: str | NotGiven = NOT_GIVEN, + order_direction: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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 | NotGiven = NOT_GIVEN, + offset: int | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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] | NotGiven = NOT_GIVEN, + pickers: Iterable[rrset_replace_params.Picker] | NotGiven = NOT_GIVEN, + ttl: int | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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..75e11dde --- /dev/null +++ b/src/gcore/resources/dns/zones/zones.py @@ -0,0 +1,1493 @@ +# 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 NOT_GIVEN, Body, Query, Headers, NotGiven, SequenceNotStr +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 | NotGiven = NOT_GIVEN, + enabled: bool | NotGiven = NOT_GIVEN, + expiry: int | NotGiven = NOT_GIVEN, + meta: Dict[str, object] | NotGiven = NOT_GIVEN, + nx_ttl: int | NotGiven = NOT_GIVEN, + primary_server: str | NotGiven = NOT_GIVEN, + refresh: int | NotGiven = NOT_GIVEN, + retry: int | NotGiven = NOT_GIVEN, + serial: int | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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] | NotGiven = NOT_GIVEN, + case_sensitive: bool | NotGiven = NOT_GIVEN, + client_id: Iterable[int] | NotGiven = NOT_GIVEN, + dynamic: bool | NotGiven = NOT_GIVEN, + enabled: bool | NotGiven = NOT_GIVEN, + exact_match: bool | NotGiven = NOT_GIVEN, + healthcheck: bool | NotGiven = NOT_GIVEN, + iam_reseller_id: Iterable[int] | NotGiven = NOT_GIVEN, + limit: int | NotGiven = NOT_GIVEN, + name: SequenceNotStr[str] | NotGiven = NOT_GIVEN, + offset: int | NotGiven = NOT_GIVEN, + order_by: str | NotGiven = NOT_GIVEN, + order_direction: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, + reseller_id: Iterable[int] | NotGiven = NOT_GIVEN, + status: str | NotGiven = NOT_GIVEN, + updated_at_from: Union[str, datetime] | NotGiven = NOT_GIVEN, + updated_at_to: Union[str, datetime] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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._post( + 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 | NotGiven = NOT_GIVEN, + granularity: str | NotGiven = NOT_GIVEN, + record_type: str | NotGiven = NOT_GIVEN, + to: int | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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 | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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 | NotGiven = NOT_GIVEN, + enabled: bool | NotGiven = NOT_GIVEN, + expiry: int | NotGiven = NOT_GIVEN, + meta: Dict[str, object] | NotGiven = NOT_GIVEN, + nx_ttl: int | NotGiven = NOT_GIVEN, + primary_server: str | NotGiven = NOT_GIVEN, + refresh: int | NotGiven = NOT_GIVEN, + retry: int | NotGiven = NOT_GIVEN, + serial: int | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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 | NotGiven = NOT_GIVEN, + enabled: bool | NotGiven = NOT_GIVEN, + expiry: int | NotGiven = NOT_GIVEN, + meta: Dict[str, object] | NotGiven = NOT_GIVEN, + nx_ttl: int | NotGiven = NOT_GIVEN, + primary_server: str | NotGiven = NOT_GIVEN, + refresh: int | NotGiven = NOT_GIVEN, + retry: int | NotGiven = NOT_GIVEN, + serial: int | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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] | NotGiven = NOT_GIVEN, + case_sensitive: bool | NotGiven = NOT_GIVEN, + client_id: Iterable[int] | NotGiven = NOT_GIVEN, + dynamic: bool | NotGiven = NOT_GIVEN, + enabled: bool | NotGiven = NOT_GIVEN, + exact_match: bool | NotGiven = NOT_GIVEN, + healthcheck: bool | NotGiven = NOT_GIVEN, + iam_reseller_id: Iterable[int] | NotGiven = NOT_GIVEN, + limit: int | NotGiven = NOT_GIVEN, + name: SequenceNotStr[str] | NotGiven = NOT_GIVEN, + offset: int | NotGiven = NOT_GIVEN, + order_by: str | NotGiven = NOT_GIVEN, + order_direction: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, + reseller_id: Iterable[int] | NotGiven = NOT_GIVEN, + status: str | NotGiven = NOT_GIVEN, + updated_at_from: Union[str, datetime] | NotGiven = NOT_GIVEN, + updated_at_to: Union[str, datetime] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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._post( + 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 | NotGiven = NOT_GIVEN, + granularity: str | NotGiven = NOT_GIVEN, + record_type: str | NotGiven = NOT_GIVEN, + to: int | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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 | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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 | NotGiven = NOT_GIVEN, + enabled: bool | NotGiven = NOT_GIVEN, + expiry: int | NotGiven = NOT_GIVEN, + meta: Dict[str, object] | NotGiven = NOT_GIVEN, + nx_ttl: int | NotGiven = NOT_GIVEN, + primary_server: str | NotGiven = NOT_GIVEN, + refresh: int | NotGiven = NOT_GIVEN, + retry: int | NotGiven = NOT_GIVEN, + serial: int | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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/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/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..d8c41393 --- /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 NOT_GIVEN, Body, Query, Headers, NoneType, NotGiven +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 | NotGiven = NOT_GIVEN, + offset: int | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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 | NotGiven = NOT_GIVEN, + offset: int | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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..3869e78e --- /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 NOT_GIVEN, Body, Query, Headers, NoneType, NotGiven, SequenceNotStr +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] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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..a4940ef7 --- /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 NOT_GIVEN, Body, Query, Headers, NoneType, NotGiven +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 | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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 | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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..f84d2653 --- /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 NOT_GIVEN, Body, Query, Headers, NoneType, NotGiven +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..5cc7224a --- /dev/null +++ b/src/gcore/resources/storage/credentials.py @@ -0,0 +1,221 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven +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 | NotGiven = NOT_GIVEN, + generate_s3_keys: bool | NotGiven = NOT_GIVEN, + generate_sftp_password: bool | NotGiven = NOT_GIVEN, + reset_sftp_keys: bool | NotGiven = NOT_GIVEN, + sftp_password: str | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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: + delete_sftp_password: Remove the SFTP password, disabling password authentication. Only applicable to + SFTP storage type. + + generate_s3_keys: Generate new S3 access and secret keys for S3 storage. Only applicable to S3 + storage type. + + generate_sftp_password: Generate a new random password for SFTP access. Only applicable to SFTP storage + type. + + reset_sftp_keys: Reset/remove all SSH keys associated with the SFTP storage. Only applicable to + SFTP storage type. + + sftp_password: Set a custom password for SFTP access. Only applicable to SFTP 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._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 | NotGiven = NOT_GIVEN, + generate_s3_keys: bool | NotGiven = NOT_GIVEN, + generate_sftp_password: bool | NotGiven = NOT_GIVEN, + reset_sftp_keys: bool | NotGiven = NOT_GIVEN, + sftp_password: str | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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: + delete_sftp_password: Remove the SFTP password, disabling password authentication. Only applicable to + SFTP storage type. + + generate_s3_keys: Generate new S3 access and secret keys for S3 storage. Only applicable to S3 + storage type. + + generate_sftp_password: Generate a new random password for SFTP access. Only applicable to SFTP storage + type. + + reset_sftp_keys: Reset/remove all SSH keys associated with the SFTP storage. Only applicable to + SFTP storage type. + + sftp_password: Set a custom password for SFTP access. Only applicable to SFTP 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 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..5e2a2d96 --- /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 NOT_GIVEN, Body, Query, Headers, NotGiven +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 | NotGiven = NOT_GIVEN, + offset: int | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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 | NotGiven = NOT_GIVEN, + offset: int | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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..980c1410 --- /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 NOT_GIVEN, Body, Query, Headers, NotGiven, SequenceNotStr +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 | NotGiven = NOT_GIVEN, + locations: SequenceNotStr[str] | NotGiven = NOT_GIVEN, + storages: SequenceNotStr[str] | NotGiven = NOT_GIVEN, + to: str | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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 | NotGiven = NOT_GIVEN, + granularity: str | NotGiven = NOT_GIVEN, + locations: SequenceNotStr[str] | NotGiven = NOT_GIVEN, + source: int | NotGiven = NOT_GIVEN, + storages: SequenceNotStr[str] | NotGiven = NOT_GIVEN, + to: str | NotGiven = NOT_GIVEN, + ts_string: bool | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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 | NotGiven = NOT_GIVEN, + locations: SequenceNotStr[str] | NotGiven = NOT_GIVEN, + storages: SequenceNotStr[str] | NotGiven = NOT_GIVEN, + to: str | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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 | NotGiven = NOT_GIVEN, + granularity: str | NotGiven = NOT_GIVEN, + locations: SequenceNotStr[str] | NotGiven = NOT_GIVEN, + source: int | NotGiven = NOT_GIVEN, + storages: SequenceNotStr[str] | NotGiven = NOT_GIVEN, + to: str | NotGiven = NOT_GIVEN, + ts_string: bool | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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..4f0b3a82 --- /dev/null +++ b/src/gcore/resources/storage/storage.py @@ -0,0 +1,1042 @@ +# 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 NOT_GIVEN, Body, Query, Headers, NoneType, NotGiven +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: Literal["s-ed1", "s-drc2", "s-sgc1", "s-nhn2", "s-darz", "s-ws1", "ams", "sin", "fra", "mia"], + name: str, + type: Literal["sftp", "s3"], + generate_sftp_password: bool | NotGiven = NOT_GIVEN, + sftp_password: str | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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 | NotGiven = NOT_GIVEN, + server_alias: str | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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. + + Args: + expires: ISO 8601 timestamp when the storage should expire. Leave empty to remove + expiration. + + server_alias: Custom domain alias for accessing the storage. Leave 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._post( + f"/storage/provisioning/v1/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 | NotGiven = NOT_GIVEN, + limit: int | NotGiven = NOT_GIVEN, + location: str | NotGiven = NOT_GIVEN, + name: str | NotGiven = NOT_GIVEN, + offset: int | NotGiven = NOT_GIVEN, + order_by: str | NotGiven = NOT_GIVEN, + order_direction: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, + show_deleted: bool | NotGiven = NOT_GIVEN, + status: Literal["active", "suspended", "deleted", "pending"] | NotGiven = NOT_GIVEN, + type: Literal["s3", "sftp"] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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 | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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: Literal["s-ed1", "s-drc2", "s-sgc1", "s-nhn2", "s-darz", "s-ws1", "ams", "sin", "fra", "mia"], + name: str, + type: Literal["sftp", "s3"], + generate_sftp_password: bool | NotGiven = NOT_GIVEN, + sftp_password: str | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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 | NotGiven = NOT_GIVEN, + server_alias: str | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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. + + Args: + expires: ISO 8601 timestamp when the storage should expire. Leave empty to remove + expiration. + + server_alias: Custom domain alias for accessing the storage. Leave 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._post( + f"/storage/provisioning/v1/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 | NotGiven = NOT_GIVEN, + limit: int | NotGiven = NOT_GIVEN, + location: str | NotGiven = NOT_GIVEN, + name: str | NotGiven = NOT_GIVEN, + offset: int | NotGiven = NOT_GIVEN, + order_by: str | NotGiven = NOT_GIVEN, + order_direction: Literal["asc", "desc"] | NotGiven = NOT_GIVEN, + show_deleted: bool | NotGiven = NOT_GIVEN, + status: Literal["active", "suspended", "deleted", "pending"] | NotGiven = NOT_GIVEN, + type: Literal["s3", "sftp"] | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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 | NotGiven = NOT_GIVEN, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this 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/ai_tasks.py b/src/gcore/resources/streaming/ai_tasks.py index 9b612e98..0b63144c 100644 --- a/src/gcore/resources/streaming/ai_tasks.py +++ b/src/gcore/resources/streaming/ai_tasks.py @@ -54,8 +54,7 @@ def create( task_name: Literal["transcription", "content-moderation"], url: str, audio_language: str | NotGiven = NOT_GIVEN, - category: Literal["sport", "weapon", "nsfw", "hard_nudity", "soft_nudity", "child_pornography"] - | NotGiven = NOT_GIVEN, + category: Literal["sport", "nsfw", "hard_nudity", "soft_nudity"] | NotGiven = NOT_GIVEN, client_entity_data: str | NotGiven = NOT_GIVEN, client_user_id: str | NotGiven = NOT_GIVEN, subtitles_language: str | NotGiven = NOT_GIVEN, @@ -74,17 +73,15 @@ def create( - ASR: Transcribe video - ASR: Translate subtitles - CM: Sports detection - - CM: Weapon detection - CM: Not Safe For Work (NSFW) content detection - CM: Soft nudity detection - CM: Hard nudity detection - - CM: Child Sexual Abuse Material (CSAM) 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 + - 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 @@ -105,21 +102,21 @@ def create( ``` { - "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 - } - }, ... + "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 + } + }, ... } ``` @@ -137,14 +134,11 @@ def create( - `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. - - `child_pornography`: Detects child sexual abuse materials (CASM). - - `sport`: Recognizes various sporting activities. - - `weapon`: Identifies the presence of weapons in the video content. 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: + - `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 @@ -158,9 +152,9 @@ def create( { "status": "SUCCESS", "result": { - "`nsfw_detected`": true, - "`detection_results`": ["nsfw"], - "frames": [{"label": "nsfw", "confidence": 1.0, "`frame_number`": 24}, ...], + "nsfw_detected": true, + "detection_results": ["nsfw"], + "frames": [{"label": "nsfw", "confidence": 1.0, "frame_number": 24}, ...], }, } ``` @@ -312,7 +306,7 @@ def create( - 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 /ai/tasks#transcribe](https://api.gcore.com/docs/streaming/docs/api-reference/streaming/ai/create-ai-asr-task). + [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). @@ -484,11 +478,9 @@ def get( - ASR: Transcribe video - ASR: Translate subtitles - CM: Sports detection - - CM: Weapon detection - CM: Not Safe For Work (NSFW) content detection - CM: Soft nudity detection - CM: Hard nudity detection - - CM: Child Sexual Abuse Material (CSAM) detection - CM: Objects recognition (soon) - etc... (see other methods from /ai/ domain) @@ -564,7 +556,8 @@ def get_ai_settings( determination. Example: ``` - curl -L 'https://api.gcore.com/streaming/ai/info?type=`language_support`&`audio_language`=eng&`subtitles_language`=fre' + curl -L 'https://api.gcore.com/streaming/ai/info?type=language_support&audio_language=eng&subtitles_language=fre' + { "supported": true } ``` @@ -642,8 +635,7 @@ async def create( task_name: Literal["transcription", "content-moderation"], url: str, audio_language: str | NotGiven = NOT_GIVEN, - category: Literal["sport", "weapon", "nsfw", "hard_nudity", "soft_nudity", "child_pornography"] - | NotGiven = NOT_GIVEN, + category: Literal["sport", "nsfw", "hard_nudity", "soft_nudity"] | NotGiven = NOT_GIVEN, client_entity_data: str | NotGiven = NOT_GIVEN, client_user_id: str | NotGiven = NOT_GIVEN, subtitles_language: str | NotGiven = NOT_GIVEN, @@ -662,17 +654,15 @@ async def create( - ASR: Transcribe video - ASR: Translate subtitles - CM: Sports detection - - CM: Weapon detection - CM: Not Safe For Work (NSFW) content detection - CM: Soft nudity detection - CM: Hard nudity detection - - CM: Child Sexual Abuse Material (CSAM) 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 + - 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 @@ -693,21 +683,21 @@ async def create( ``` { - "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 - } - }, ... + "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 + } + }, ... } ``` @@ -725,14 +715,11 @@ async def create( - `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. - - `child_pornography`: Detects child sexual abuse materials (CASM). - - `sport`: Recognizes various sporting activities. - - `weapon`: Identifies the presence of weapons in the video content. 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: + - `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 @@ -746,9 +733,9 @@ async def create( { "status": "SUCCESS", "result": { - "`nsfw_detected`": true, - "`detection_results`": ["nsfw"], - "frames": [{"label": "nsfw", "confidence": 1.0, "`frame_number`": 24}, ...], + "nsfw_detected": true, + "detection_results": ["nsfw"], + "frames": [{"label": "nsfw", "confidence": 1.0, "frame_number": 24}, ...], }, } ``` @@ -900,7 +887,7 @@ async def create( - 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 /ai/tasks#transcribe](https://api.gcore.com/docs/streaming/docs/api-reference/streaming/ai/create-ai-asr-task). + [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). @@ -1072,11 +1059,9 @@ async def get( - ASR: Transcribe video - ASR: Translate subtitles - CM: Sports detection - - CM: Weapon detection - CM: Not Safe For Work (NSFW) content detection - CM: Soft nudity detection - CM: Hard nudity detection - - CM: Child Sexual Abuse Material (CSAM) detection - CM: Objects recognition (soon) - etc... (see other methods from /ai/ domain) @@ -1152,7 +1137,8 @@ async def get_ai_settings( determination. Example: ``` - curl -L 'https://api.gcore.com/streaming/ai/info?type=`language_support`&`audio_language`=eng&`subtitles_language`=fre' + curl -L 'https://api.gcore.com/streaming/ai/info?type=language_support&audio_language=eng&subtitles_language=fre' + { "supported": true } ``` diff --git a/src/gcore/resources/streaming/playlists.py b/src/gcore/resources/streaming/playlists.py index f8994ca0..fba76526 100644 --- a/src/gcore/resources/streaming/playlists.py +++ b/src/gcore/resources/streaming/playlists.py @@ -104,9 +104,9 @@ def create( 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)" + 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 @@ -122,10 +122,10 @@ def create( 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" + 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: @@ -160,7 +160,7 @@ def create( 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 `` + `/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 @@ -291,7 +291,7 @@ def update( 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 `` + `/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 @@ -572,9 +572,9 @@ async def create( 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)" + 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 @@ -590,10 +590,10 @@ async def create( 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" + 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: @@ -628,7 +628,7 @@ async def create( 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 `` + `/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 @@ -759,7 +759,7 @@ async def update( 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 `` + `/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 diff --git a/src/gcore/resources/streaming/quality_sets.py b/src/gcore/resources/streaming/quality_sets.py index 40bf6368..825c12da 100644 --- a/src/gcore/resources/streaming/quality_sets.py +++ b/src/gcore/resources/streaming/quality_sets.py @@ -65,10 +65,10 @@ def list( [documentation](https://gcore.com/docs/streaming-platform/live-streams-and-videos-protocols-and-codecs/output-parameters-after-transcoding-bitrate-frame-rate-and-codecs). 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: + [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. @@ -196,10 +196,10 @@ async def list( [documentation](https://gcore.com/docs/streaming-platform/live-streams-and-videos-protocols-and-codecs/output-parameters-after-transcoding-bitrate-frame-rate-and-codecs). 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: + [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. diff --git a/src/gcore/resources/streaming/statistics.py b/src/gcore/resources/streaming/statistics.py index 7a763cdc..4e8cb182 100644 --- a/src/gcore/resources/streaming/statistics.py +++ b/src/gcore/resources/streaming/statistics.py @@ -21,7 +21,6 @@ from ...types.streaming import ( statistic_get_views_params, statistic_get_ffprobes_params, - statistic_get_meet_series_params, statistic_get_stream_series_params, statistic_get_views_heatmap_params, statistic_get_popular_videos_params, @@ -46,7 +45,6 @@ ) from ...types.streaming.views import Views from ...types.streaming.ffprobes import Ffprobes -from ...types.streaming.meet_series import MeetSeries from ...types.streaming.stream_series import StreamSeries from ...types.streaming.views_heatmap import ViewsHeatmap from ...types.streaming.popular_videos import PopularVideos @@ -168,7 +166,7 @@ def get_live_unique_viewers( 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) + ![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 @@ -388,58 +386,6 @@ def get_max_streams_series( cast_to=MaxStreamSeries, ) - def get_meet_series( - self, - *, - from_: str, - to: str, - granularity: Literal["1m", "5m", "15m", "1h", "1d"] | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> MeetSeries: - """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/meet", - 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_meet_series_params.StatisticGetMeetSeriesParams, - ), - ), - cast_to=MeetSeries, - ) - def get_popular_videos( self, *, @@ -1321,7 +1267,7 @@ def get_vod_unique_viewers_cdn( 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) + ![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 @@ -1590,7 +1536,7 @@ async def get_live_unique_viewers( 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) + ![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 @@ -1810,58 +1756,6 @@ async def get_max_streams_series( cast_to=MaxStreamSeries, ) - async def get_meet_series( - self, - *, - from_: str, - to: str, - granularity: Literal["1m", "5m", "15m", "1h", "1d"] | NotGiven = NOT_GIVEN, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, - ) -> MeetSeries: - """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/meet", - 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_meet_series_params.StatisticGetMeetSeriesParams, - ), - ), - cast_to=MeetSeries, - ) - async def get_popular_videos( self, *, @@ -2743,7 +2637,7 @@ async def get_vod_unique_viewers_cdn( 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) + ![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 @@ -2931,9 +2825,6 @@ def __init__(self, statistics: StatisticsResource) -> None: self.get_max_streams_series = to_raw_response_wrapper( statistics.get_max_streams_series, ) - self.get_meet_series = to_raw_response_wrapper( - statistics.get_meet_series, - ) self.get_popular_videos = to_raw_response_wrapper( statistics.get_popular_videos, ) @@ -3009,9 +2900,6 @@ def __init__(self, statistics: AsyncStatisticsResource) -> None: self.get_max_streams_series = async_to_raw_response_wrapper( statistics.get_max_streams_series, ) - self.get_meet_series = async_to_raw_response_wrapper( - statistics.get_meet_series, - ) self.get_popular_videos = async_to_raw_response_wrapper( statistics.get_popular_videos, ) @@ -3087,9 +2975,6 @@ def __init__(self, statistics: StatisticsResource) -> None: self.get_max_streams_series = to_streamed_response_wrapper( statistics.get_max_streams_series, ) - self.get_meet_series = to_streamed_response_wrapper( - statistics.get_meet_series, - ) self.get_popular_videos = to_streamed_response_wrapper( statistics.get_popular_videos, ) @@ -3165,9 +3050,6 @@ def __init__(self, statistics: AsyncStatisticsResource) -> None: self.get_max_streams_series = async_to_streamed_response_wrapper( statistics.get_max_streams_series, ) - self.get_meet_series = async_to_streamed_response_wrapper( - statistics.get_meet_series, - ) self.get_popular_videos = async_to_streamed_response_wrapper( statistics.get_popular_videos, ) diff --git a/src/gcore/resources/streaming/streams/overlays.py b/src/gcore/resources/streaming/streams/overlays.py index 6ca214f9..f52cfee4 100644 --- a/src/gcore/resources/streaming/streams/overlays.py +++ b/src/gcore/resources/streaming/streams/overlays.py @@ -65,7 +65,7 @@ def create( 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) + ![HTML Overlays](https://demo-files.gvideo.io/apidocs/coffee_run_overlays.gif) How to activate and use in simple steps: @@ -150,7 +150,7 @@ def update( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> Overlay: """ - Updates overlay's settings + Updates overlay settings Args: height: Height of the widget @@ -270,7 +270,7 @@ def get( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> Overlay: """ - Returns overlay details + Get overlay details Args: extra_headers: Send extra headers @@ -362,7 +362,7 @@ async def create( 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) + ![HTML Overlays](https://demo-files.gvideo.io/apidocs/coffee_run_overlays.gif) How to activate and use in simple steps: @@ -447,7 +447,7 @@ async def update( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> Overlay: """ - Updates overlay's settings + Updates overlay settings Args: height: Height of the widget @@ -567,7 +567,7 @@ async def get( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> Overlay: """ - Returns overlay details + Get overlay details Args: extra_headers: Send extra headers diff --git a/src/gcore/resources/streaming/streams/streams.py b/src/gcore/resources/streaming/streams/streams.py index ede9698b..30c0c23b 100644 --- a/src/gcore/resources/streaming/streams/streams.py +++ b/src/gcore/resources/streaming/streams/streams.py @@ -80,7 +80,6 @@ def create( dvr_enabled: bool | NotGiven = NOT_GIVEN, hls_mpegts_endlist_tag: bool | NotGiven = NOT_GIVEN, html_overlay: bool | NotGiven = NOT_GIVEN, - low_latency_enabled: bool | NotGiven = NOT_GIVEN, projection: Literal["regular", "vr360", "vr180", "vr360tb"] | NotGiven = NOT_GIVEN, pull: bool | NotGiven = NOT_GIVEN, quality_set_id: int | NotGiven = NOT_GIVEN, @@ -113,7 +112,7 @@ def create( 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 MPEGTS delivery below. + HLS MPEG-TS delivery below. You have access to additional functions such as: @@ -162,7 +161,7 @@ def create( 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_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` @@ -184,19 +183,6 @@ def create( html_overlay: Switch on mode to insert and display real-time HTML overlay widgets on top of live streams - low_latency_enabled: Deprecated, always returns "true". The only exception is that the attribute can - only be used by clients that have previously used the old stream format. This - method is outdated since we've made it easier to manage streams. For your - convenience, you no longer need to set this parameter at the stage of creating a - stream. Now all streams are prepared in 2 formats simultaniously: Low Latency - and Legacy. You can get the desired output format in the attributes - "`dash_url`", "`hls_cmaf_url`", "`hls_mpegts_url`". Or use them all at once. - - --- - - Note: Links /streams/{id}/playlist.m3u8 are depricated too. Use value of the - "`hls_mpegts_url`" attribute instead. - 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: @@ -210,9 +196,10 @@ def create( values: - true – stream is received by PULL method. Use this when need to get stream - from external server by srt, rtmp\\ss, hls, dash, etc protocols. + 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 mobile app or OBS Studio. + 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 @@ -230,10 +217,11 @@ def create( 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 24 hours of - inactivity of your streams we will stop PULL-ing, and will switch "active" field - 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. + 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 @@ -258,7 +246,6 @@ def create( "dvr_enabled": dvr_enabled, "hls_mpegts_endlist_tag": hls_mpegts_endlist_tag, "html_overlay": html_overlay, - "low_latency_enabled": low_latency_enabled, "projection": projection, "pull": pull, "quality_set_id": quality_set_id, @@ -318,7 +305,7 @@ def list( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> SyncPageStreaming[Stream]: - """Returns a list of streams. + """Returns a list of streams Args: page: Query parameter. @@ -379,8 +366,8 @@ def delete( Perhaps, instead of deleting, you may use the stream deactivation: ``` - PATCH /videos/{`stream_id`} - { "active": false } + PATCH / videos / {stream_id} + {"active": false} ``` For details, see the Product Documentation. @@ -462,7 +449,7 @@ def create_clip( - 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) + ![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 @@ -516,7 +503,8 @@ def create_clip( 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: + `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. @@ -606,13 +594,13 @@ def list_clips( 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 `` + `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 `` + `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 `` + `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 `` + `https://CID.domain.com/rec/111_1000/rec_d7bsli54p8n4_qsid42_media_1_360.mp4` Args: extra_headers: Send extra headers @@ -775,7 +763,6 @@ async def create( dvr_enabled: bool | NotGiven = NOT_GIVEN, hls_mpegts_endlist_tag: bool | NotGiven = NOT_GIVEN, html_overlay: bool | NotGiven = NOT_GIVEN, - low_latency_enabled: bool | NotGiven = NOT_GIVEN, projection: Literal["regular", "vr360", "vr180", "vr360tb"] | NotGiven = NOT_GIVEN, pull: bool | NotGiven = NOT_GIVEN, quality_set_id: int | NotGiven = NOT_GIVEN, @@ -808,7 +795,7 @@ async def create( 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 MPEGTS delivery below. + HLS MPEG-TS delivery below. You have access to additional functions such as: @@ -857,7 +844,7 @@ async def create( 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_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` @@ -879,19 +866,6 @@ async def create( html_overlay: Switch on mode to insert and display real-time HTML overlay widgets on top of live streams - low_latency_enabled: Deprecated, always returns "true". The only exception is that the attribute can - only be used by clients that have previously used the old stream format. This - method is outdated since we've made it easier to manage streams. For your - convenience, you no longer need to set this parameter at the stage of creating a - stream. Now all streams are prepared in 2 formats simultaniously: Low Latency - and Legacy. You can get the desired output format in the attributes - "`dash_url`", "`hls_cmaf_url`", "`hls_mpegts_url`". Or use them all at once. - - --- - - Note: Links /streams/{id}/playlist.m3u8 are depricated too. Use value of the - "`hls_mpegts_url`" attribute instead. - 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: @@ -905,9 +879,10 @@ async def create( values: - true – stream is received by PULL method. Use this when need to get stream - from external server by srt, rtmp\\ss, hls, dash, etc protocols. + 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 mobile app or OBS Studio. + 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 @@ -925,10 +900,11 @@ async def create( 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 24 hours of - inactivity of your streams we will stop PULL-ing, and will switch "active" field - 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. + 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 @@ -953,7 +929,6 @@ async def create( "dvr_enabled": dvr_enabled, "hls_mpegts_endlist_tag": hls_mpegts_endlist_tag, "html_overlay": html_overlay, - "low_latency_enabled": low_latency_enabled, "projection": projection, "pull": pull, "quality_set_id": quality_set_id, @@ -1013,7 +988,7 @@ def list( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> AsyncPaginator[Stream, AsyncPageStreaming[Stream]]: - """Returns a list of streams. + """Returns a list of streams Args: page: Query parameter. @@ -1074,8 +1049,8 @@ async def delete( Perhaps, instead of deleting, you may use the stream deactivation: ``` - PATCH /videos/{`stream_id`} - { "active": false } + PATCH / videos / {stream_id} + {"active": false} ``` For details, see the Product Documentation. @@ -1157,7 +1132,7 @@ async def create_clip( - 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) + ![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 @@ -1211,7 +1186,8 @@ async def create_clip( 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: + `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. @@ -1301,13 +1277,13 @@ async def list_clips( 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 `` + `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 `` + `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 `` + `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 `` + `https://CID.domain.com/rec/111_1000/rec_d7bsli54p8n4_qsid42_media_1_360.mp4` Args: extra_headers: Send extra headers diff --git a/src/gcore/resources/streaming/videos/subtitles.py b/src/gcore/resources/streaming/videos/subtitles.py index 58864fc4..4e59615e 100644 --- a/src/gcore/resources/streaming/videos/subtitles.py +++ b/src/gcore/resources/streaming/videos/subtitles.py @@ -62,18 +62,18 @@ def create( 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 + [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`). + [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 Transcribe"](https://api.gcore.com/docs/streaming/docs/api-reference/streaming/ai/create-ai-asr-task). + ["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. @@ -84,18 +84,19 @@ def create( subtitles based on AI. Read more: - What is - ["AI Transcribe"](https://api.gcore.com/docs/streaming/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. + ["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. + `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 @@ -320,18 +321,18 @@ async def create( 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 + [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`). + [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 Transcribe"](https://api.gcore.com/docs/streaming/docs/api-reference/streaming/ai/create-ai-asr-task). + ["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. @@ -342,18 +343,19 @@ async def create( subtitles based on AI. Read more: - What is - ["AI Transcribe"](https://api.gcore.com/docs/streaming/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. + ["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. + `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 diff --git a/src/gcore/resources/streaming/videos/videos.py b/src/gcore/resources/streaming/videos/videos.py index 24d654e6..c77320db 100644 --- a/src/gcore/resources/streaming/videos/videos.py +++ b/src/gcore/resources/streaming/videos/videos.py @@ -107,17 +107,18 @@ def create( subtitles based on AI. Read more: - What is - ["AI Transcribe"](https://api.gcore.com/docs/streaming/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. + ["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. + `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"](https://api.gcore.com/docs/streaming/docs/api-reference/streaming/subtitles/add-subtitle). + ["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 @@ -194,9 +195,9 @@ def update( "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, + - 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. @@ -218,16 +219,16 @@ def update( attribute of API POST /streaming/ai/transcribe . Example: ``` - `auto_transcribe_audio_language`: "auto" - `auto_transcribe_audio_language`: "ger" + auto_transcribe_audio_language: "auto" + auto_transcribe_audio_language: "ger" ``` More details: - List of AI tasks – API - [GET /streaming/ai/tasks](https://api.gcore.com/docs/streaming/docs/api-reference/streaming/ai/get-ai-task-result) + [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](https://api.gcore.com/docs/streaming/docs/api-reference/streaming/subtitles/add-subtitle). + [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` @@ -242,8 +243,8 @@ def update( subtitle will be generated for each language. Example: ``` - `auto_translate_subtitles_language`: default - `auto_translate_subtitles_language`: eng,fre,ger + auto_translate_subtitles_language: default + auto_translate_subtitles_language: eng,fre,ger ``` Please note that subtitle translation is done separately and after @@ -268,7 +269,8 @@ def update( 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: + external server. Syntax: + `Authorization: ` Examples: - "`origin_http_headers`": "Authorization: Basic ..." - "`origin_http_headers`": "Authorization: Bearer ..." @@ -277,10 +279,11 @@ def update( ``` 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" + "name": "IBC 2024 intro.mp4", + "origin_url": "https://www.googleapis.com/drive/v3/files/...?alt=media", + "origin_http_headers": "Authorization: Bearer ABC" } ``` @@ -295,8 +298,8 @@ def update( 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: + 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==` @@ -657,19 +660,19 @@ def get_parameters_for_direct_upload( 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(); + 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: @@ -792,17 +795,18 @@ async def create( subtitles based on AI. Read more: - What is - ["AI Transcribe"](https://api.gcore.com/docs/streaming/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. + ["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. + `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"](https://api.gcore.com/docs/streaming/docs/api-reference/streaming/subtitles/add-subtitle). + ["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 @@ -879,9 +883,9 @@ async def update( "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, + - 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. @@ -903,16 +907,16 @@ async def update( attribute of API POST /streaming/ai/transcribe . Example: ``` - `auto_transcribe_audio_language`: "auto" - `auto_transcribe_audio_language`: "ger" + auto_transcribe_audio_language: "auto" + auto_transcribe_audio_language: "ger" ``` More details: - List of AI tasks – API - [GET /streaming/ai/tasks](https://api.gcore.com/docs/streaming/docs/api-reference/streaming/ai/get-ai-task-result) + [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](https://api.gcore.com/docs/streaming/docs/api-reference/streaming/subtitles/add-subtitle). + [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` @@ -927,8 +931,8 @@ async def update( subtitle will be generated for each language. Example: ``` - `auto_translate_subtitles_language`: default - `auto_translate_subtitles_language`: eng,fre,ger + auto_translate_subtitles_language: default + auto_translate_subtitles_language: eng,fre,ger ``` Please note that subtitle translation is done separately and after @@ -953,7 +957,8 @@ async def update( 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: + external server. Syntax: + `Authorization: ` Examples: - "`origin_http_headers`": "Authorization: Basic ..." - "`origin_http_headers`": "Authorization: Bearer ..." @@ -962,10 +967,11 @@ async def update( ``` 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" + "name": "IBC 2024 intro.mp4", + "origin_url": "https://www.googleapis.com/drive/v3/files/...?alt=media", + "origin_http_headers": "Authorization: Bearer ABC" } ``` @@ -980,8 +986,8 @@ async def update( 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: + 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==` @@ -1346,19 +1352,19 @@ async def get_parameters_for_direct_upload( 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(); + 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: diff --git a/src/gcore/resources/waap/domains/advanced_rules.py b/src/gcore/resources/waap/domains/advanced_rules.py index 75992d93..e22a838f 100644 --- a/src/gcore/resources/waap/domains/advanced_rules.py +++ b/src/gcore/resources/waap/domains/advanced_rules.py @@ -68,7 +68,7 @@ def create( Args: domain_id: The domain ID - action: The action that a WAAP rule takes when triggered + action: The action that the rule takes when triggered enabled: Whether or not the rule is enabled @@ -444,7 +444,7 @@ async def create( Args: domain_id: The domain ID - action: The action that a WAAP rule takes when triggered + action: The action that the rule takes when triggered enabled: Whether or not the rule is enabled diff --git a/src/gcore/resources/waap/domains/api_paths.py b/src/gcore/resources/waap/domains/api_paths.py index 70381593..fc1dd68c 100644 --- a/src/gcore/resources/waap/domains/api_paths.py +++ b/src/gcore/resources/waap/domains/api_paths.py @@ -7,7 +7,7 @@ import httpx -from ...._types import NOT_GIVEN, Body, Query, Headers, NoneType, NotGiven +from ...._types import NOT_GIVEN, Body, Query, Headers, NoneType, NotGiven, SequenceNotStr from ...._utils import maybe_transform, async_maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource @@ -52,9 +52,9 @@ def create( http_scheme: Literal["HTTP", "HTTPS"], method: Literal["GET", "POST", "PUT", "PATCH", "DELETE", "TRACE", "HEAD", "OPTIONS"], path: str, - api_groups: List[str] | NotGiven = NOT_GIVEN, + api_groups: SequenceNotStr[str] | NotGiven = NOT_GIVEN, api_version: str | NotGiven = NOT_GIVEN, - tags: List[str] | NotGiven = NOT_GIVEN, + tags: SequenceNotStr[str] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -113,10 +113,10 @@ def update( path_id: str, *, domain_id: int, - api_groups: List[str] | NotGiven = NOT_GIVEN, + api_groups: SequenceNotStr[str] | NotGiven = NOT_GIVEN, path: str | NotGiven = NOT_GIVEN, status: Literal["CONFIRMED_API", "POTENTIAL_API", "NOT_API", "DELISTED_API"] | NotGiven = NOT_GIVEN, - tags: List[str] | NotGiven = NOT_GIVEN, + tags: SequenceNotStr[str] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -137,7 +137,7 @@ def update( 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 + status: The status of the discovered API path tags: An array of tags associated with the API path @@ -176,7 +176,7 @@ def list( api_group: Optional[str] | NotGiven = NOT_GIVEN, api_version: Optional[str] | NotGiven = NOT_GIVEN, http_scheme: Optional[Literal["HTTP", "HTTPS"]] | NotGiven = NOT_GIVEN, - ids: Optional[List[str]] | NotGiven = NOT_GIVEN, + ids: Optional[SequenceNotStr[str]] | NotGiven = NOT_GIVEN, limit: int | NotGiven = NOT_GIVEN, method: Optional[Literal["GET", "POST", "PUT", "PATCH", "DELETE", "TRACE", "HEAD", "OPTIONS"]] | NotGiven = NOT_GIVEN, @@ -382,9 +382,9 @@ async def create( http_scheme: Literal["HTTP", "HTTPS"], method: Literal["GET", "POST", "PUT", "PATCH", "DELETE", "TRACE", "HEAD", "OPTIONS"], path: str, - api_groups: List[str] | NotGiven = NOT_GIVEN, + api_groups: SequenceNotStr[str] | NotGiven = NOT_GIVEN, api_version: str | NotGiven = NOT_GIVEN, - tags: List[str] | NotGiven = NOT_GIVEN, + tags: SequenceNotStr[str] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -443,10 +443,10 @@ async def update( path_id: str, *, domain_id: int, - api_groups: List[str] | NotGiven = NOT_GIVEN, + api_groups: SequenceNotStr[str] | NotGiven = NOT_GIVEN, path: str | NotGiven = NOT_GIVEN, status: Literal["CONFIRMED_API", "POTENTIAL_API", "NOT_API", "DELISTED_API"] | NotGiven = NOT_GIVEN, - tags: List[str] | NotGiven = NOT_GIVEN, + tags: SequenceNotStr[str] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -467,7 +467,7 @@ async def update( 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 + status: The status of the discovered API path tags: An array of tags associated with the API path @@ -506,7 +506,7 @@ def list( api_group: Optional[str] | NotGiven = NOT_GIVEN, api_version: Optional[str] | NotGiven = NOT_GIVEN, http_scheme: Optional[Literal["HTTP", "HTTPS"]] | NotGiven = NOT_GIVEN, - ids: Optional[List[str]] | NotGiven = NOT_GIVEN, + ids: Optional[SequenceNotStr[str]] | NotGiven = NOT_GIVEN, limit: int | NotGiven = NOT_GIVEN, method: Optional[Literal["GET", "POST", "PUT", "PATCH", "DELETE", "TRACE", "HEAD", "OPTIONS"]] | NotGiven = NOT_GIVEN, diff --git a/src/gcore/resources/waap/domains/custom_rules.py b/src/gcore/resources/waap/domains/custom_rules.py index 4a5acac5..f175a192 100644 --- a/src/gcore/resources/waap/domains/custom_rules.py +++ b/src/gcore/resources/waap/domains/custom_rules.py @@ -72,7 +72,7 @@ def create( Args: domain_id: The domain ID - action: The action that a WAAP rule takes when triggered + action: The action that the 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 @@ -446,7 +446,7 @@ async def create( Args: domain_id: The domain ID - action: The action that a WAAP rule takes when triggered + action: The action that the 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 diff --git a/src/gcore/resources/waap/domains/domains.py b/src/gcore/resources/waap/domains/domains.py index ad004706..cf4135cc 100644 --- a/src/gcore/resources/waap/domains/domains.py +++ b/src/gcore/resources/waap/domains/domains.py @@ -186,7 +186,7 @@ def update( Args: domain_id: The domain ID - status: Domain statuses that can be used when updating a domain + status: The current status of the domain extra_headers: Send extra headers @@ -237,7 +237,7 @@ def list( ordering: Sort the response by given field. - status: The different statuses a domain can have + status: Filter domains based on the domain status extra_headers: Send extra headers @@ -489,7 +489,7 @@ async def update( Args: domain_id: The domain ID - status: Domain statuses that can be used when updating a domain + status: The current status of the domain extra_headers: Send extra headers @@ -540,7 +540,7 @@ def list( ordering: Sort the response by given field. - status: The different statuses a domain can have + status: Filter domains based on the domain status extra_headers: Send extra headers diff --git a/src/gcore/resources/waap/domains/firewall_rules.py b/src/gcore/resources/waap/domains/firewall_rules.py index 90bbe131..b8600359 100644 --- a/src/gcore/resources/waap/domains/firewall_rules.py +++ b/src/gcore/resources/waap/domains/firewall_rules.py @@ -72,7 +72,7 @@ def create( Args: domain_id: The domain ID - action: The action that a firewall rule takes when triggered + action: The action that the rule takes when triggered conditions: The condition required for the WAAP engine to trigger the rule. @@ -444,7 +444,7 @@ async def create( Args: domain_id: The domain ID - action: The action that a firewall rule takes when triggered + action: The action that the rule takes when triggered conditions: The condition required for the WAAP engine to trigger the rule. diff --git a/src/gcore/resources/waap/domains/insight_silences.py b/src/gcore/resources/waap/domains/insight_silences.py index 151e3d04..577332e9 100644 --- a/src/gcore/resources/waap/domains/insight_silences.py +++ b/src/gcore/resources/waap/domains/insight_silences.py @@ -2,13 +2,13 @@ from __future__ import annotations -from typing import Dict, List, Union, Optional +from typing import Dict, Union, Optional from datetime import datetime from typing_extensions import Literal import httpx -from ...._types import NOT_GIVEN, Body, Query, Headers, NoneType, NotGiven +from ...._types import NOT_GIVEN, Body, Query, Headers, NoneType, NotGiven, SequenceNotStr from ...._utils import maybe_transform, async_maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource @@ -173,10 +173,10 @@ def list( self, domain_id: int, *, - id: Optional[List[str]] | NotGiven = NOT_GIVEN, + id: Optional[SequenceNotStr[str]] | NotGiven = NOT_GIVEN, author: Optional[str] | NotGiven = NOT_GIVEN, comment: Optional[str] | NotGiven = NOT_GIVEN, - insight_type: Optional[List[str]] | NotGiven = NOT_GIVEN, + insight_type: Optional[SequenceNotStr[str]] | NotGiven = NOT_GIVEN, limit: int | NotGiven = NOT_GIVEN, offset: int | NotGiven = NOT_GIVEN, ordering: Literal[ @@ -472,10 +472,10 @@ def list( self, domain_id: int, *, - id: Optional[List[str]] | NotGiven = NOT_GIVEN, + id: Optional[SequenceNotStr[str]] | NotGiven = NOT_GIVEN, author: Optional[str] | NotGiven = NOT_GIVEN, comment: Optional[str] | NotGiven = NOT_GIVEN, - insight_type: Optional[List[str]] | NotGiven = NOT_GIVEN, + insight_type: Optional[SequenceNotStr[str]] | NotGiven = NOT_GIVEN, limit: int | NotGiven = NOT_GIVEN, offset: int | NotGiven = NOT_GIVEN, ordering: Literal[ diff --git a/src/gcore/resources/waap/domains/insights.py b/src/gcore/resources/waap/domains/insights.py index fcd628e4..8fb4ab52 100644 --- a/src/gcore/resources/waap/domains/insights.py +++ b/src/gcore/resources/waap/domains/insights.py @@ -7,7 +7,7 @@ import httpx -from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven, SequenceNotStr from ...._utils import maybe_transform, async_maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource @@ -49,9 +49,9 @@ def list( self, domain_id: int, *, - id: Optional[List[str]] | NotGiven = NOT_GIVEN, + id: Optional[SequenceNotStr[str]] | NotGiven = NOT_GIVEN, description: Optional[str] | NotGiven = NOT_GIVEN, - insight_type: Optional[List[str]] | NotGiven = NOT_GIVEN, + insight_type: Optional[SequenceNotStr[str]] | NotGiven = NOT_GIVEN, limit: int | NotGiven = NOT_GIVEN, offset: int | NotGiven = NOT_GIVEN, ordering: Literal[ @@ -186,7 +186,7 @@ def replace( insight_id: The ID of the insight - status: The different statuses an insight can have + status: The status of the insight extra_headers: Send extra headers @@ -232,9 +232,9 @@ def list( self, domain_id: int, *, - id: Optional[List[str]] | NotGiven = NOT_GIVEN, + id: Optional[SequenceNotStr[str]] | NotGiven = NOT_GIVEN, description: Optional[str] | NotGiven = NOT_GIVEN, - insight_type: Optional[List[str]] | NotGiven = NOT_GIVEN, + insight_type: Optional[SequenceNotStr[str]] | NotGiven = NOT_GIVEN, limit: int | NotGiven = NOT_GIVEN, offset: int | NotGiven = NOT_GIVEN, ordering: Literal[ @@ -369,7 +369,7 @@ async def replace( insight_id: The ID of the insight - status: The different statuses an insight can have + status: The status of the insight extra_headers: Send extra headers diff --git a/src/gcore/resources/waap/domains/statistics.py b/src/gcore/resources/waap/domains/statistics.py index 13776e62..f23b048b 100644 --- a/src/gcore/resources/waap/domains/statistics.py +++ b/src/gcore/resources/waap/domains/statistics.py @@ -8,7 +8,7 @@ import httpx -from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ...._types import NOT_GIVEN, Body, Query, Headers, NotGiven, SequenceNotStr from ...._utils import maybe_transform, async_maybe_transform from ...._compat import cached_property from ...._resource import SyncAPIResource, AsyncAPIResource @@ -124,8 +124,8 @@ def get_ddos_info( domain_id: int, *, group_by: Literal["URL", "User-Agent", "IP"], - start: Union[str, datetime], - end: Union[str, datetime] | NotGiven = NOT_GIVEN, + start: str, + end: Optional[str] | NotGiven = NOT_GIVEN, limit: int | NotGiven = NOT_GIVEN, offset: int | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -143,10 +143,10 @@ def get_ddos_info( group_by: The identity of the requests to group by - start: Filter traffic starting from a specified date in ISO 8601 format + start: Filter data items starting from a specified date in ISO 8601 format - end: Filter traffic up to a specified end date in ISO 8601 format. If not provided, - defaults to the current date and time. + 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 @@ -186,11 +186,11 @@ def get_events_aggregated( self, domain_id: int, *, - start: Union[str, datetime], + start: str, action: Optional[List[Literal["block", "captcha", "handshake", "monitor"]]] | NotGiven = NOT_GIVEN, - end: Union[str, datetime] | NotGiven = NOT_GIVEN, - ip: Optional[List[str]] | NotGiven = NOT_GIVEN, - reference_id: Optional[List[str]] | NotGiven = NOT_GIVEN, + end: Optional[str] | NotGiven = NOT_GIVEN, + ip: Optional[SequenceNotStr[str]] | NotGiven = NOT_GIVEN, + reference_id: Optional[SequenceNotStr[str]] | NotGiven = NOT_GIVEN, result: Optional[List[Literal["passed", "blocked", "monitored", "allowed"]]] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -205,12 +205,12 @@ def get_events_aggregated( Args: domain_id: The domain ID - start: Filter traffic starting from a specified date in ISO 8601 format + start: Filter data items starting from a specified date in ISO 8601 format action: A list of action names to filter on. - end: Filter traffic up to a specified end date in ISO 8601 format. If not provided, - defaults to the current date and time. + 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. @@ -291,10 +291,10 @@ def get_requests_series( self, domain_id: int, *, - start: Union[str, datetime], + start: str, actions: List[Literal["allow", "block", "captcha", "handshake"]] | NotGiven = NOT_GIVEN, - countries: List[str] | NotGiven = NOT_GIVEN, - end: Union[str, datetime] | NotGiven = NOT_GIVEN, + countries: SequenceNotStr[str] | NotGiven = NOT_GIVEN, + end: Optional[str] | NotGiven = NOT_GIVEN, ip: str | NotGiven = NOT_GIVEN, limit: int | NotGiven = NOT_GIVEN, offset: int | NotGiven = NOT_GIVEN, @@ -340,14 +340,14 @@ def get_requests_series( Args: domain_id: The domain ID - start: Filter traffic starting from a specified date in ISO 8601 format + 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 traffic up to a specified end date in ISO 8601 format. If not provided, - defaults to the current date and time. + 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. @@ -407,8 +407,8 @@ def get_traffic_series( domain_id: int, *, resolution: Literal["daily", "hourly", "minutely"], - start: Union[str, datetime], - end: Union[str, datetime] | NotGiven = NOT_GIVEN, + start: str, + end: Optional[str] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -426,10 +426,10 @@ def get_traffic_series( resolution: Specifies the granularity of the result data. - start: Filter traffic starting from a specified date in ISO 8601 format + start: Filter data items starting from a specified date in ISO 8601 format - end: Filter traffic up to a specified end date in ISO 8601 format. If not provided, - defaults to the current date and time. + 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 @@ -546,8 +546,8 @@ def get_ddos_info( domain_id: int, *, group_by: Literal["URL", "User-Agent", "IP"], - start: Union[str, datetime], - end: Union[str, datetime] | NotGiven = NOT_GIVEN, + start: str, + end: Optional[str] | NotGiven = NOT_GIVEN, limit: int | NotGiven = NOT_GIVEN, offset: int | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -565,10 +565,10 @@ def get_ddos_info( group_by: The identity of the requests to group by - start: Filter traffic starting from a specified date in ISO 8601 format + start: Filter data items starting from a specified date in ISO 8601 format - end: Filter traffic up to a specified end date in ISO 8601 format. If not provided, - defaults to the current date and time. + 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 @@ -608,11 +608,11 @@ async def get_events_aggregated( self, domain_id: int, *, - start: Union[str, datetime], + start: str, action: Optional[List[Literal["block", "captcha", "handshake", "monitor"]]] | NotGiven = NOT_GIVEN, - end: Union[str, datetime] | NotGiven = NOT_GIVEN, - ip: Optional[List[str]] | NotGiven = NOT_GIVEN, - reference_id: Optional[List[str]] | NotGiven = NOT_GIVEN, + end: Optional[str] | NotGiven = NOT_GIVEN, + ip: Optional[SequenceNotStr[str]] | NotGiven = NOT_GIVEN, + reference_id: Optional[SequenceNotStr[str]] | NotGiven = NOT_GIVEN, result: Optional[List[Literal["passed", "blocked", "monitored", "allowed"]]] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -627,12 +627,12 @@ async def get_events_aggregated( Args: domain_id: The domain ID - start: Filter traffic starting from a specified date in ISO 8601 format + start: Filter data items starting from a specified date in ISO 8601 format action: A list of action names to filter on. - end: Filter traffic up to a specified end date in ISO 8601 format. If not provided, - defaults to the current date and time. + 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. @@ -713,10 +713,10 @@ def get_requests_series( self, domain_id: int, *, - start: Union[str, datetime], + start: str, actions: List[Literal["allow", "block", "captcha", "handshake"]] | NotGiven = NOT_GIVEN, - countries: List[str] | NotGiven = NOT_GIVEN, - end: Union[str, datetime] | NotGiven = NOT_GIVEN, + countries: SequenceNotStr[str] | NotGiven = NOT_GIVEN, + end: Optional[str] | NotGiven = NOT_GIVEN, ip: str | NotGiven = NOT_GIVEN, limit: int | NotGiven = NOT_GIVEN, offset: int | NotGiven = NOT_GIVEN, @@ -762,14 +762,14 @@ def get_requests_series( Args: domain_id: The domain ID - start: Filter traffic starting from a specified date in ISO 8601 format + 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 traffic up to a specified end date in ISO 8601 format. If not provided, - defaults to the current date and time. + 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. @@ -829,8 +829,8 @@ async def get_traffic_series( domain_id: int, *, resolution: Literal["daily", "hourly", "minutely"], - start: Union[str, datetime], - end: Union[str, datetime] | NotGiven = NOT_GIVEN, + start: str, + end: Optional[str] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -848,10 +848,10 @@ async def get_traffic_series( resolution: Specifies the granularity of the result data. - start: Filter traffic starting from a specified date in ISO 8601 format + start: Filter data items starting from a specified date in ISO 8601 format - end: Filter traffic up to a specified end date in ISO 8601 format. If not provided, - defaults to the current date and time. + 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 diff --git a/src/gcore/types/cloud/__init__.py b/src/gcore/types/cloud/__init__.py index 9c735955..586c4473 100644 --- a/src/gcore/types/cloud/__init__.py +++ b/src/gcore/types/cloud/__init__.py @@ -65,6 +65,7 @@ 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 @@ -73,7 +74,6 @@ from .ssh_key_list_params import SSHKeyListParams as SSHKeyListParams from .cost_report_detailed import CostReportDetailed as CostReportDetailed from .floating_ip_detailed import FloatingIPDetailed as FloatingIPDetailed -from .gpu_baremetal_flavor import GPUBaremetalFlavor as GPUBaremetalFlavor from .instance_list_params import InstanceListParams as InstanceListParams from .lb_listener_protocol import LbListenerProtocol as LbListenerProtocol from .load_balancer_status import LoadBalancerStatus as LoadBalancerStatus @@ -117,11 +117,11 @@ 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 .gpu_baremetal_flavor_list import GPUBaremetalFlavorList as GPUBaremetalFlavorList 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 @@ -145,7 +145,6 @@ 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 .gpu_baremetal_cluster_server import GPUBaremetalClusterServer as GPUBaremetalClusterServer 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 @@ -163,7 +162,6 @@ from .volume_attach_to_instance_params import VolumeAttachToInstanceParams as VolumeAttachToInstanceParams from .cost_report_get_aggregated_params import CostReportGetAggregatedParams as CostReportGetAggregatedParams from .gpu_baremetal_cluster_list_params import GPUBaremetalClusterListParams as GPUBaremetalClusterListParams -from .gpu_baremetal_cluster_server_list import GPUBaremetalClusterServerList as GPUBaremetalClusterServerList 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 diff --git a/src/gcore/types/cloud/audit_log_list_params.py b/src/gcore/types/cloud/audit_log_list_params.py index 6f5ac1aa..09a75554 100644 --- a/src/gcore/types/cloud/audit_log_list_params.py +++ b/src/gcore/types/cloud/audit_log_list_params.py @@ -6,6 +6,7 @@ from datetime import datetime from typing_extensions import Literal, Annotated, TypedDict +from ..._types import SequenceNotStr from ..._utils import PropertyInfo __all__ = ["AuditLogListParams"] @@ -136,7 +137,7 @@ class AuditLogListParams(TypedDict, total=False): region_id: Iterable[int] """Region ID. Several options can be specified.""" - resource_id: List[str] + resource_id: SequenceNotStr[str] """Resource ID. Several options can be specified.""" search_field: str diff --git a/src/gcore/types/cloud/baremetal/image_list_params.py b/src/gcore/types/cloud/baremetal/image_list_params.py index 075fe52e..1e1d2903 100644 --- a/src/gcore/types/cloud/baremetal/image_list_params.py +++ b/src/gcore/types/cloud/baremetal/image_list_params.py @@ -2,9 +2,10 @@ from __future__ import annotations -from typing import List from typing_extensions import Literal, TypedDict +from ...._types import SequenceNotStr + __all__ = ["ImageListParams"] @@ -19,7 +20,7 @@ class ImageListParams(TypedDict, total=False): private: str """Any value to show private images""" - tag_key: List[str] + tag_key: SequenceNotStr[str] """Filter by tag keys.""" tag_key_value: str diff --git a/src/gcore/types/cloud/baremetal/server_create_params.py b/src/gcore/types/cloud/baremetal/server_create_params.py index e6afbd0b..ba70700a 100644 --- a/src/gcore/types/cloud/baremetal/server_create_params.py +++ b/src/gcore/types/cloud/baremetal/server_create_params.py @@ -346,13 +346,12 @@ class InterfaceCreateBareMetalReservedFixedIPInterfaceSerializer(TypedDict, tota class DDOSProfileField(TypedDict, total=False): base_field: Optional[int] - """ID of DDoS profile field""" + """Unique identifier of the DDoS protection field being configured""" field_name: Optional[str] - """Name of DDoS profile field""" + """Human-readable name of the DDoS protection field being configured""" - field_value: Union[Iterable[object], int, str, None] - """Complex value. Only one of 'value' or '`field_value`' must be specified.""" + field_value: object value: Optional[str] """Basic type value. Only one of 'value' or '`field_value`' must be specified.""" @@ -360,7 +359,10 @@ class DDOSProfileField(TypedDict, total=False): class DDOSProfile(TypedDict, total=False): profile_template: Required[int] - """Advanced DDoS template ID""" + """Unique identifier of the DDoS protection template to use for this profile""" fields: Iterable[DDOSProfileField] - """DDoS profile parameters""" + """ + 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 index 1ddb1c48..75547dff 100644 --- a/src/gcore/types/cloud/baremetal/server_list_params.py +++ b/src/gcore/types/cloud/baremetal/server_list_params.py @@ -2,10 +2,11 @@ from __future__ import annotations -from typing import List, Union +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"] @@ -87,7 +88,7 @@ class ServerListParams(TypedDict, total=False): tag_key_value: str """Optional. Filter by tag key-value pairs.""" - tag_value: List[str] + tag_value: SequenceNotStr[str] """Optional. Filter by tag values. ?`tag_value`=value1&`tag_value`=value2""" type_ddos_profile: Literal["basic", "advanced"] diff --git a/src/gcore/types/cloud/baremetal/server_rebuild_params.py b/src/gcore/types/cloud/baremetal/server_rebuild_params.py index 5a6e2be6..9addcb49 100644 --- a/src/gcore/types/cloud/baremetal/server_rebuild_params.py +++ b/src/gcore/types/cloud/baremetal/server_rebuild_params.py @@ -9,8 +9,10 @@ class ServerRebuildParams(TypedDict, total=False): project_id: int + """Project ID""" region_id: int + """Region ID""" image_id: str """Image ID""" 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 index e28efb98..6b9a4389 100644 --- a/src/gcore/types/cloud/cost_report_get_aggregated_monthly_params.py +++ b/src/gcore/types/cloud/cost_report_get_aggregated_monthly_params.py @@ -6,6 +6,7 @@ from datetime import datetime from typing_extensions import Literal, Required, Annotated, TypeAlias, TypedDict +from ..._types import SequenceNotStr from ..._utils import PropertyInfo __all__ = [ @@ -42,12 +43,6 @@ class CostReportGetAggregatedMonthlyParams(TypedDict, total=False): - time_from: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """Beginning of the period: YYYY-mm""" - - time_to: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """End of the period: YYYY-mm""" - regions: Iterable[int] """List of region IDs.""" @@ -63,6 +58,12 @@ class CostReportGetAggregatedMonthlyParams(TypedDict, total=False): 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", @@ -94,6 +95,9 @@ class CostReportGetAggregatedMonthlyParams(TypedDict, total=False): ] """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"]] @@ -101,7 +105,7 @@ class SchemaFilterSchemaFilterSnapshotSerializer(TypedDict, total=False): type: Required[Literal["snapshot"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -111,7 +115,7 @@ class SchemaFilterSchemaFilterInstanceSerializer(TypedDict, total=False): type: Required[Literal["instance"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -121,7 +125,7 @@ class SchemaFilterSchemaFilterAIClusterSerializer(TypedDict, total=False): type: Required[Literal["ai_cluster"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -131,7 +135,7 @@ class SchemaFilterSchemaFilterAIVirtualClusterSerializer(TypedDict, total=False) type: Required[Literal["ai_virtual_cluster"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -141,7 +145,7 @@ class SchemaFilterSchemaFilterBasicVmSerializer(TypedDict, total=False): type: Required[Literal["basic_vm"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -151,7 +155,7 @@ class SchemaFilterSchemaFilterBaremetalSerializer(TypedDict, total=False): type: Required[Literal["baremetal"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -161,7 +165,7 @@ class SchemaFilterSchemaFilterVolumeSerializer(TypedDict, total=False): type: Required[Literal["volume"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -171,7 +175,7 @@ class SchemaFilterSchemaFilterFileShareSerializer(TypedDict, total=False): type: Required[Literal["file_share"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -181,7 +185,7 @@ class SchemaFilterSchemaFilterImageSerializer(TypedDict, total=False): type: Required[Literal["image"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -191,7 +195,7 @@ class SchemaFilterSchemaFilterFloatingIPSerializer(TypedDict, total=False): type: Required[Literal["floatingip"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -201,7 +205,7 @@ class SchemaFilterSchemaFilterEgressTrafficSerializer(TypedDict, total=False): type: Required[Literal["egress_traffic"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -211,7 +215,7 @@ class SchemaFilterSchemaFilterLoadBalancerSerializer(TypedDict, total=False): type: Required[Literal["load_balancer"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -221,7 +225,7 @@ class SchemaFilterSchemaFilterExternalIPSerializer(TypedDict, total=False): type: Required[Literal["external_ip"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -231,7 +235,7 @@ class SchemaFilterSchemaFilterBackupSerializer(TypedDict, total=False): type: Required[Literal["backup"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -241,7 +245,7 @@ class SchemaFilterSchemaFilterLogIndexSerializer(TypedDict, total=False): type: Required[Literal["log_index"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -251,7 +255,7 @@ class SchemaFilterSchemaFilterFunctionsSerializer(TypedDict, total=False): type: Required[Literal["functions"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -261,7 +265,7 @@ class SchemaFilterSchemaFilterFunctionsCallsSerializer(TypedDict, total=False): type: Required[Literal["functions_calls"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -271,7 +275,7 @@ class SchemaFilterSchemaFilterFunctionsTrafficSerializer(TypedDict, total=False) type: Required[Literal["functions_traffic"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -281,7 +285,7 @@ class SchemaFilterSchemaFilterContainersSerializer(TypedDict, total=False): type: Required[Literal["containers"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -291,7 +295,7 @@ class SchemaFilterSchemaFilterInferenceSerializer(TypedDict, total=False): type: Required[Literal["inference"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -301,7 +305,7 @@ class SchemaFilterSchemaFilterDbaasPostgreSQLVolumeSerializer(TypedDict, total=F type: Required[Literal["dbaas_postgresql_volume"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -311,7 +315,7 @@ class SchemaFilterSchemaFilterDbaasPostgreSQLPublicNetworkSerializer(TypedDict, type: Required[Literal["dbaas_postgresql_public_network"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -321,7 +325,7 @@ class SchemaFilterSchemaFilterDbaasPostgreSqlcpuSerializer(TypedDict, total=Fals type: Required[Literal["dbaas_postgresql_cpu"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -331,7 +335,7 @@ class SchemaFilterSchemaFilterDbaasPostgreSQLMemorySerializer(TypedDict, total=F type: Required[Literal["dbaas_postgresql_memory"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -341,7 +345,7 @@ class SchemaFilterSchemaFilterDbaasPostgreSQLPoolerSerializer(TypedDict, total=F type: Required[Literal["dbaas_postgresql_connection_pooler"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" diff --git a/src/gcore/types/cloud/cost_report_get_aggregated_params.py b/src/gcore/types/cloud/cost_report_get_aggregated_params.py index aa099ae9..1d79bba8 100644 --- a/src/gcore/types/cloud/cost_report_get_aggregated_params.py +++ b/src/gcore/types/cloud/cost_report_get_aggregated_params.py @@ -6,6 +6,7 @@ from datetime import datetime from typing_extensions import Literal, Required, Annotated, TypeAlias, TypedDict +from ..._types import SequenceNotStr from ..._utils import PropertyInfo __all__ = [ @@ -116,7 +117,7 @@ class SchemaFilterSchemaFilterSnapshotSerializer(TypedDict, total=False): type: Required[Literal["snapshot"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -126,7 +127,7 @@ class SchemaFilterSchemaFilterInstanceSerializer(TypedDict, total=False): type: Required[Literal["instance"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -136,7 +137,7 @@ class SchemaFilterSchemaFilterAIClusterSerializer(TypedDict, total=False): type: Required[Literal["ai_cluster"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -146,7 +147,7 @@ class SchemaFilterSchemaFilterAIVirtualClusterSerializer(TypedDict, total=False) type: Required[Literal["ai_virtual_cluster"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -156,7 +157,7 @@ class SchemaFilterSchemaFilterBasicVmSerializer(TypedDict, total=False): type: Required[Literal["basic_vm"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -166,7 +167,7 @@ class SchemaFilterSchemaFilterBaremetalSerializer(TypedDict, total=False): type: Required[Literal["baremetal"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -176,7 +177,7 @@ class SchemaFilterSchemaFilterVolumeSerializer(TypedDict, total=False): type: Required[Literal["volume"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -186,7 +187,7 @@ class SchemaFilterSchemaFilterFileShareSerializer(TypedDict, total=False): type: Required[Literal["file_share"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -196,7 +197,7 @@ class SchemaFilterSchemaFilterImageSerializer(TypedDict, total=False): type: Required[Literal["image"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -206,7 +207,7 @@ class SchemaFilterSchemaFilterFloatingIPSerializer(TypedDict, total=False): type: Required[Literal["floatingip"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -216,7 +217,7 @@ class SchemaFilterSchemaFilterEgressTrafficSerializer(TypedDict, total=False): type: Required[Literal["egress_traffic"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -226,7 +227,7 @@ class SchemaFilterSchemaFilterLoadBalancerSerializer(TypedDict, total=False): type: Required[Literal["load_balancer"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -236,7 +237,7 @@ class SchemaFilterSchemaFilterExternalIPSerializer(TypedDict, total=False): type: Required[Literal["external_ip"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -246,7 +247,7 @@ class SchemaFilterSchemaFilterBackupSerializer(TypedDict, total=False): type: Required[Literal["backup"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -256,7 +257,7 @@ class SchemaFilterSchemaFilterLogIndexSerializer(TypedDict, total=False): type: Required[Literal["log_index"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -266,7 +267,7 @@ class SchemaFilterSchemaFilterFunctionsSerializer(TypedDict, total=False): type: Required[Literal["functions"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -276,7 +277,7 @@ class SchemaFilterSchemaFilterFunctionsCallsSerializer(TypedDict, total=False): type: Required[Literal["functions_calls"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -286,7 +287,7 @@ class SchemaFilterSchemaFilterFunctionsTrafficSerializer(TypedDict, total=False) type: Required[Literal["functions_traffic"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -296,7 +297,7 @@ class SchemaFilterSchemaFilterContainersSerializer(TypedDict, total=False): type: Required[Literal["containers"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -306,7 +307,7 @@ class SchemaFilterSchemaFilterInferenceSerializer(TypedDict, total=False): type: Required[Literal["inference"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -316,7 +317,7 @@ class SchemaFilterSchemaFilterDbaasPostgreSQLVolumeSerializer(TypedDict, total=F type: Required[Literal["dbaas_postgresql_volume"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -326,7 +327,7 @@ class SchemaFilterSchemaFilterDbaasPostgreSQLPublicNetworkSerializer(TypedDict, type: Required[Literal["dbaas_postgresql_public_network"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -336,7 +337,7 @@ class SchemaFilterSchemaFilterDbaasPostgreSqlcpuSerializer(TypedDict, total=Fals type: Required[Literal["dbaas_postgresql_cpu"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -346,7 +347,7 @@ class SchemaFilterSchemaFilterDbaasPostgreSQLMemorySerializer(TypedDict, total=F type: Required[Literal["dbaas_postgresql_memory"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -356,7 +357,7 @@ class SchemaFilterSchemaFilterDbaasPostgreSQLPoolerSerializer(TypedDict, total=F type: Required[Literal["dbaas_postgresql_connection_pooler"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" diff --git a/src/gcore/types/cloud/cost_report_get_detailed_params.py b/src/gcore/types/cloud/cost_report_get_detailed_params.py index f3d65950..a55d3a37 100644 --- a/src/gcore/types/cloud/cost_report_get_detailed_params.py +++ b/src/gcore/types/cloud/cost_report_get_detailed_params.py @@ -6,6 +6,7 @@ from datetime import datetime from typing_extensions import Literal, Required, Annotated, TypeAlias, TypedDict +from ..._types import SequenceNotStr from ..._utils import PropertyInfo __all__ = [ @@ -126,7 +127,7 @@ class SchemaFilterSchemaFilterSnapshotSerializer(TypedDict, total=False): type: Required[Literal["snapshot"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -136,7 +137,7 @@ class SchemaFilterSchemaFilterInstanceSerializer(TypedDict, total=False): type: Required[Literal["instance"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -146,7 +147,7 @@ class SchemaFilterSchemaFilterAIClusterSerializer(TypedDict, total=False): type: Required[Literal["ai_cluster"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -156,7 +157,7 @@ class SchemaFilterSchemaFilterAIVirtualClusterSerializer(TypedDict, total=False) type: Required[Literal["ai_virtual_cluster"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -166,7 +167,7 @@ class SchemaFilterSchemaFilterBasicVmSerializer(TypedDict, total=False): type: Required[Literal["basic_vm"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -176,7 +177,7 @@ class SchemaFilterSchemaFilterBaremetalSerializer(TypedDict, total=False): type: Required[Literal["baremetal"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -186,7 +187,7 @@ class SchemaFilterSchemaFilterVolumeSerializer(TypedDict, total=False): type: Required[Literal["volume"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -196,7 +197,7 @@ class SchemaFilterSchemaFilterFileShareSerializer(TypedDict, total=False): type: Required[Literal["file_share"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -206,7 +207,7 @@ class SchemaFilterSchemaFilterImageSerializer(TypedDict, total=False): type: Required[Literal["image"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -216,7 +217,7 @@ class SchemaFilterSchemaFilterFloatingIPSerializer(TypedDict, total=False): type: Required[Literal["floatingip"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -226,7 +227,7 @@ class SchemaFilterSchemaFilterEgressTrafficSerializer(TypedDict, total=False): type: Required[Literal["egress_traffic"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -236,7 +237,7 @@ class SchemaFilterSchemaFilterLoadBalancerSerializer(TypedDict, total=False): type: Required[Literal["load_balancer"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -246,7 +247,7 @@ class SchemaFilterSchemaFilterExternalIPSerializer(TypedDict, total=False): type: Required[Literal["external_ip"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -256,7 +257,7 @@ class SchemaFilterSchemaFilterBackupSerializer(TypedDict, total=False): type: Required[Literal["backup"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -266,7 +267,7 @@ class SchemaFilterSchemaFilterLogIndexSerializer(TypedDict, total=False): type: Required[Literal["log_index"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -276,7 +277,7 @@ class SchemaFilterSchemaFilterFunctionsSerializer(TypedDict, total=False): type: Required[Literal["functions"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -286,7 +287,7 @@ class SchemaFilterSchemaFilterFunctionsCallsSerializer(TypedDict, total=False): type: Required[Literal["functions_calls"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -296,7 +297,7 @@ class SchemaFilterSchemaFilterFunctionsTrafficSerializer(TypedDict, total=False) type: Required[Literal["functions_traffic"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -306,7 +307,7 @@ class SchemaFilterSchemaFilterContainersSerializer(TypedDict, total=False): type: Required[Literal["containers"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -316,7 +317,7 @@ class SchemaFilterSchemaFilterInferenceSerializer(TypedDict, total=False): type: Required[Literal["inference"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -326,7 +327,7 @@ class SchemaFilterSchemaFilterDbaasPostgreSQLVolumeSerializer(TypedDict, total=F type: Required[Literal["dbaas_postgresql_volume"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -336,7 +337,7 @@ class SchemaFilterSchemaFilterDbaasPostgreSQLPublicNetworkSerializer(TypedDict, type: Required[Literal["dbaas_postgresql_public_network"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -346,7 +347,7 @@ class SchemaFilterSchemaFilterDbaasPostgreSqlcpuSerializer(TypedDict, total=Fals type: Required[Literal["dbaas_postgresql_cpu"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -356,7 +357,7 @@ class SchemaFilterSchemaFilterDbaasPostgreSQLMemorySerializer(TypedDict, total=F type: Required[Literal["dbaas_postgresql_memory"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -366,7 +367,7 @@ class SchemaFilterSchemaFilterDbaasPostgreSQLPoolerSerializer(TypedDict, total=F type: Required[Literal["dbaas_postgresql_connection_pooler"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" diff --git a/src/gcore/types/cloud/ddos_profile.py b/src/gcore/types/cloud/ddos_profile.py index bc242300..2db25f56 100644 --- a/src/gcore/types/cloud/ddos_profile.py +++ b/src/gcore/types/cloud/ddos_profile.py @@ -13,27 +13,33 @@ 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 - """DDoS protection profile ID""" + """Unique identifier for the DDoS protection profile""" - profile_template: Optional[DDOSProfileTemplate] = None - """Template data""" + fields: List[DDOSProfileField] + """List of configured field values for the protection profile""" - fields: Optional[List[DDOSProfileField]] = None + options: DDOSProfileOptionList + """Configuration options controlling profile activation and BGP routing""" - options: Optional[DDOSProfileOptionList] = None + profile_template: Optional[DDOSProfileTemplate] = None + """Complete template configuration data used for this profile""" profile_template_description: Optional[str] = None - """DDoS profile template description""" + """Detailed description of the protection template used for this profile""" protocols: Optional[List[Protocol]] = None - """List of protocols""" + """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 index 6ec1b6c8..f0d03515 100644 --- a/src/gcore/types/cloud/ddos_profile_field.py +++ b/src/gcore/types/cloud/ddos_profile_field.py @@ -9,23 +9,36 @@ class DDOSProfileField(BaseModel): id: int + """Unique identifier for the DDoS protection field""" - default: object - - description: str - - field_value: object + base_field: Optional[int] = None + """ID of DDoS profile field""" - name: str + default: Optional[str] = None + """Predefined default value for the field if not specified""" - base_field: Optional[int] = None + 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: Optional[object] = None + 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 index d3638aa9..cd7729a0 100644 --- a/src/gcore/types/cloud/ddos_profile_option_list.py +++ b/src/gcore/types/cloud/ddos_profile_option_list.py @@ -1,15 +1,16 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Optional - from ..._models import BaseModel __all__ = ["DDOSProfileOptionList"] class DDOSProfileOptionList(BaseModel): - active: Optional[bool] = None - """Activate profile.""" + active: bool + """ + Controls whether the DDoS protection profile is enabled and actively protecting + the resource + """ - bgp: Optional[bool] = None - """Activate BGP protocol.""" + 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 index b6b7ea5f..d76982fd 100644 --- a/src/gcore/types/cloud/ddos_profile_status.py +++ b/src/gcore/types/cloud/ddos_profile_status.py @@ -7,7 +7,7 @@ class DDOSProfileStatus(BaseModel): error_description: str - """Description of the error, if it exists""" + """Detailed error message describing any issues with the profile operation""" status: str - """Profile status""" + """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 index f3154487..5fcaa343 100644 --- a/src/gcore/types/cloud/ddos_profile_template.py +++ b/src/gcore/types/cloud/ddos_profile_template.py @@ -10,9 +10,13 @@ class DDOSProfileTemplate(BaseModel): id: int - - name: str + """Unique identifier for the DDoS protection template""" description: Optional[str] = None + """Detailed description explaining the template's purpose and use cases""" - fields: Optional[List[DDOSProfileTemplateField]] = None + 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 index df9a9078..96256752 100644 --- a/src/gcore/types/cloud/ddos_profile_template_field.py +++ b/src/gcore/types/cloud/ddos_profile_template_field.py @@ -9,15 +9,24 @@ class DDOSProfileTemplateField(BaseModel): id: int - - name: str + """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: Optional[object] = None + 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 index 7f19bba3..288e66db 100644 --- a/src/gcore/types/cloud/file_share.py +++ b/src/gcore/types/cloud/file_share.py @@ -84,7 +84,7 @@ class FileShare(BaseModel): """Share settings specific to the file share type""" size: int - """File share size, GiB""" + """File share size in GiB""" status: Literal[ "available", @@ -145,4 +145,4 @@ class FileShare(BaseModel): """File share type name""" volume_type: Literal["default_share_type", "vast_share_type"] - """File share disk 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 index 7d6f2c49..90fb2abc 100644 --- a/src/gcore/types/cloud/file_share_create_params.py +++ b/src/gcore/types/cloud/file_share_create_params.py @@ -32,7 +32,7 @@ class CreateStandardFileShareSerializer(TypedDict, total=False): """File share protocol""" size: Required[int] - """File share size""" + """File share size in GiB""" access: Iterable[CreateStandardFileShareSerializerAccess] """Access Rules""" @@ -47,8 +47,11 @@ class CreateStandardFileShareSerializer(TypedDict, total=False): values. """ + type_name: Literal["standard"] + """Standard file share type""" + volume_type: Literal["default_share_type"] - """File share volume type""" + """Deprecated. Use `type_name` instead.""" class CreateStandardFileShareSerializerNetwork(TypedDict, total=False): @@ -84,10 +87,7 @@ class CreateVastFileShareSerializer(TypedDict, total=False): """File share protocol""" size: Required[int] - """File share size""" - - volume_type: Required[Literal["vast_share_type"]] - """File share volume type""" + """File share size in GiB""" share_settings: CreateVastFileShareSerializerShareSettings """Configuration settings for the share""" @@ -102,6 +102,12 @@ class CreateVastFileShareSerializer(TypedDict, total=False): 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): root_squash: bool diff --git a/src/gcore/types/cloud/floating_ip_list_params.py b/src/gcore/types/cloud/floating_ip_list_params.py index 825b2de1..97017a38 100644 --- a/src/gcore/types/cloud/floating_ip_list_params.py +++ b/src/gcore/types/cloud/floating_ip_list_params.py @@ -2,9 +2,10 @@ from __future__ import annotations -from typing import List from typing_extensions import TypedDict +from ..._types import SequenceNotStr + __all__ = ["FloatingIPListParams"] @@ -24,7 +25,7 @@ class FloatingIPListParams(TypedDict, total=False): Offset value is used to exclude the first set of records from the result """ - tag_key: List[str] + tag_key: SequenceNotStr[str] """Optional. Filter by tag keys. ?`tag_key`=key1&`tag_key`=key2""" tag_key_value: str diff --git a/src/gcore/types/cloud/gpu_baremetal_cluster.py b/src/gcore/types/cloud/gpu_baremetal_cluster.py index 910960ad..aa310a9b 100644 --- a/src/gcore/types/cloud/gpu_baremetal_cluster.py +++ b/src/gcore/types/cloud/gpu_baremetal_cluster.py @@ -1,78 +1,133 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List, Optional -from typing_extensions import Literal +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 -from .gpu_baremetal_cluster_server import GPUBaremetalClusterServer -__all__ = ["GPUBaremetalCluster", "Interface"] +__all__ = [ + "GPUBaremetalCluster", + "ServersSettings", + "ServersSettingsInterface", + "ServersSettingsInterfaceExternalInterfaceOutputSerializer", + "ServersSettingsInterfaceSubnetInterfaceOutputSerializer", + "ServersSettingsInterfaceSubnetInterfaceOutputSerializerFloatingIP", + "ServersSettingsInterfaceAnySubnetInterfaceOutputSerializer", + "ServersSettingsInterfaceAnySubnetInterfaceOutputSerializerFloatingIP", + "ServersSettingsSecurityGroup", +] -class Interface(BaseModel): - network_id: str - """Network ID""" +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): + source: Literal["new"] - port_id: str + +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 to IP address from the subnet""" + """Port is assigned an IP address from this subnet""" - type: str - """Network type""" + type: Literal["subnet"] -class GPUBaremetalCluster(BaseModel): - cluster_id: str - """GPU Cluster ID""" +class ServersSettingsInterfaceAnySubnetInterfaceOutputSerializerFloatingIP(BaseModel): + source: Literal["new"] - cluster_name: str - """GPU Cluster Name""" - cluster_status: Literal["ACTIVE", "ERROR", "PENDING", "SUSPENDED"] - """GPU Cluster status""" +class ServersSettingsInterfaceAnySubnetInterfaceOutputSerializer(BaseModel): + floating_ip: Optional[ServersSettingsInterfaceAnySubnetInterfaceOutputSerializerFloatingIP] = None + """Floating IP config for this subnet attachment""" - created_at: Optional[str] = None - """Datetime when the cluster was created""" + ip_address: Optional[str] = None + """Fixed IP address""" - creator_task_id: Optional[str] = None - """Task that created this entity""" + ip_family: Literal["dual", "ipv4", "ipv6"] + """Which subnets should be selected: IPv4, IPv6, or use dual stack""" - flavor: str - """Flavor ID is the same as the name""" + name: Optional[str] = None + """Interface name""" - image_id: str - """Image ID""" + network_id: str + """Network ID the subnet belongs to. Port will be plugged in this network""" - image_name: Optional[str] = None - """Image name""" + type: Literal["any_subnet"] - interfaces: Optional[List[Interface]] = None - """Networks managed by user and associated with the cluster""" - password: Optional[str] = None - """A password for a bare metal server. +ServersSettingsInterface: TypeAlias = Annotated[ + Union[ + ServersSettingsInterfaceExternalInterfaceOutputSerializer, + ServersSettingsInterfaceSubnetInterfaceOutputSerializer, + ServersSettingsInterfaceAnySubnetInterfaceOutputSerializer, + ], + PropertyInfo(discriminator="type"), +] - This parameter is used to set a password for the "Admin" user on a Windows - instance, a default user or a new user on a Linux instance - """ - project_id: int - """Project ID""" +class ServersSettingsSecurityGroup(BaseModel): + name: str + """Name.""" - region: str - """Region name""" - region_id: int - """Region ID""" +class ServersSettings(BaseModel): + interfaces: List[ServersSettingsInterface] - servers: List[GPUBaremetalClusterServer] - """GPU cluster servers""" + security_groups: List[ServersSettingsSecurityGroup] + """Security groups names""" ssh_key_name: Optional[str] = None - """Keypair name to inject into new cluster(s)""" + """SSH key name""" + + user_data: Optional[str] = None + """Optional custom user data (Base64-encoded) Mutually exclusive with 'password'.""" + + +class GPUBaremetalCluster(BaseModel): + id: str + """Cluster unique identifier""" + + created_at: datetime + """Cluster creation date time""" + + flavor: str + """Cluster flavor name""" + + 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", "deleting", "error", "new", "resizing"] + """Cluster status""" tags: List[Tag] """List of key-value tags associated with the resource. @@ -84,33 +139,5 @@ class GPUBaremetalCluster(BaseModel): values. """ - task_id: Optional[str] = None - """Task ID associated with the cluster""" - - task_status: Literal[ - "CLUSTER_CLEAN_UP", - "CLUSTER_RESIZE", - "CLUSTER_RESUME", - "CLUSTER_SUSPEND", - "ERROR", - "FINISHED", - "IPU_SERVERS", - "NETWORK", - "POPLAR_SERVERS", - "POST_DEPLOY_SETUP", - "VIPU_CONTROLLER", - ] - """Task status""" - - user_data: Optional[str] = None - """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 - """ - - username: Optional[str] = None - """A name of a new user in the Linux instance. - - It may be passed with a 'password' parameter - """ + updated_at: Optional[datetime] = None + """Cluster update date time""" diff --git a/src/gcore/types/cloud/gpu_baremetal_cluster_create_params.py b/src/gcore/types/cloud/gpu_baremetal_cluster_create_params.py index 959700a0..2dd61b2c 100644 --- a/src/gcore/types/cloud/gpu_baremetal_cluster_create_params.py +++ b/src/gcore/types/cloud/gpu_baremetal_cluster_create_params.py @@ -2,61 +2,44 @@ from __future__ import annotations -from typing import Dict, Union, Iterable, Optional +from typing import Dict, Union, Iterable from typing_extensions import Literal, Required, TypeAlias, TypedDict -from .interface_ip_family import InterfaceIPFamily - __all__ = [ "GPUBaremetalClusterCreateParams", - "Interface", - "InterfaceCreateGPUClusterExternalInterfaceSerializer", - "InterfaceCreateGPUClusterSubnetInterfaceSerializer", - "InterfaceCreateGPUClusterSubnetInterfaceSerializerFloatingIP", - "InterfaceCreateGPUClusterAnySubnetInterfaceSerializer", - "InterfaceCreateGPUClusterAnySubnetInterfaceSerializerFloatingIP", - "SecurityGroup", + "ServersSettings", + "ServersSettingsInterface", + "ServersSettingsInterfaceExternalInterfaceInputSerializer", + "ServersSettingsInterfaceSubnetInterfaceInputSerializer", + "ServersSettingsInterfaceSubnetInterfaceInputSerializerFloatingIP", + "ServersSettingsInterfaceAnySubnetInterfaceInputSerializer", + "ServersSettingsInterfaceAnySubnetInterfaceInputSerializerFloatingIP", + "ServersSettingsCredentials", + "ServersSettingsSecurityGroup", ] class GPUBaremetalClusterCreateParams(TypedDict, total=False): project_id: int + """Project ID""" region_id: int + """Region ID""" flavor: Required[str] - """Flavor name""" + """Cluster flavor ID""" image_id: Required[str] - """Image ID""" - - interfaces: Required[Iterable[Interface]] - """A list of network interfaces for the server. - - You can create one or more interfaces - private, public, or both. - """ + """System image ID""" name: Required[str] - """GPU Cluster name""" + """Cluster name""" - instances_count: int - """Number of servers to create""" + servers_count: Required[int] + """Number of servers in the cluster""" - password: str - """A password for a bare metal server. - - This parameter is used to set a password for the "Admin" user on a Windows - instance, a default user or a new user on a Linux instance - """ - - security_groups: Iterable[SecurityGroup] - """Security group UUIDs""" - - 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). - """ + servers_settings: Required[ServersSettings] + """Configuration settings for the servers in the cluster""" tags: Dict[str, str] """Key-value tags to associate with the resource. @@ -68,96 +51,96 @@ class GPUBaremetalClusterCreateParams(TypedDict, total=False): values. """ - 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 - """ - - username: str - """A name of a new user in the Linux instance. - - It may be passed with a 'password' parameter - """ - -class InterfaceCreateGPUClusterExternalInterfaceSerializer(TypedDict, total=False): +class ServersSettingsInterfaceExternalInterfaceInputSerializer(TypedDict, total=False): type: Required[Literal["external"]] - """A public IP address will be assigned to the server.""" - interface_name: str - """Interface name. + ip_family: Literal["dual", "ipv4", "ipv6"] + """Which subnets should be selected: IPv4, IPv6, or use dual stack.""" - 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.""" + name: str + """Interface name""" -class InterfaceCreateGPUClusterSubnetInterfaceSerializerFloatingIP(TypedDict, total=False): +class ServersSettingsInterfaceSubnetInterfaceInputSerializerFloatingIP(TypedDict, total=False): source: Required[Literal["new"]] -class InterfaceCreateGPUClusterSubnetInterfaceSerializer(TypedDict, total=False): +class ServersSettingsInterfaceSubnetInterfaceInputSerializer(TypedDict, total=False): network_id: Required[str] - """The network where the server will be connected.""" + """Network ID the subnet belongs to. Port will be plugged in this network""" subnet_id: Required[str] - """The server will get an IP address from this subnet.""" + """Port is assigned 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: InterfaceCreateGPUClusterSubnetInterfaceSerializerFloatingIP + floating_ip: ServersSettingsInterfaceSubnetInterfaceInputSerializerFloatingIP """Floating IP config for this subnet attachment""" - interface_name: str - """Interface name. - - Defaults to `null` and is returned as `null` in the API response if not set. - """ + name: str + """Interface name""" -class InterfaceCreateGPUClusterAnySubnetInterfaceSerializerFloatingIP(TypedDict, total=False): +class ServersSettingsInterfaceAnySubnetInterfaceInputSerializerFloatingIP(TypedDict, total=False): source: Required[Literal["new"]] -class InterfaceCreateGPUClusterAnySubnetInterfaceSerializer(TypedDict, total=False): +class ServersSettingsInterfaceAnySubnetInterfaceInputSerializer(TypedDict, total=False): network_id: Required[str] - """The network where the server will be connected.""" + """Network ID the subnet belongs to. Port will be plugged in this network""" type: Required[Literal["any_subnet"]] - """Server will be attached to a subnet with the largest count of free IPs.""" - floating_ip: InterfaceCreateGPUClusterAnySubnetInterfaceSerializerFloatingIP - """Allows the server to have a public IP that can be reached from the internet.""" + floating_ip: ServersSettingsInterfaceAnySubnetInterfaceInputSerializerFloatingIP + """Floating IP config for this subnet attachment""" - interface_name: str - """Interface name. + ip_family: Literal["dual", "ipv4", "ipv6"] + """Which subnets should be selected: IPv4, IPv6, or use dual stack""" + + 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.""" +ServersSettingsInterface: TypeAlias = Union[ + ServersSettingsInterfaceExternalInterfaceInputSerializer, + ServersSettingsInterfaceSubnetInterfaceInputSerializer, + ServersSettingsInterfaceAnySubnetInterfaceInputSerializer, +] - ip_family: InterfaceIPFamily - """Specify `ipv4`, `ipv6`, or `dual` to enable both.""" +class ServersSettingsCredentials(TypedDict, total=False): + password: str + """Used to set the password for the specified 'username' on Linux instances. -Interface: TypeAlias = Union[ - InterfaceCreateGPUClusterExternalInterfaceSerializer, - InterfaceCreateGPUClusterSubnetInterfaceSerializer, - InterfaceCreateGPUClusterAnySubnetInterfaceSerializer, -] + 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 SecurityGroup(TypedDict, total=False): +class ServersSettingsSecurityGroup(TypedDict, total=False): id: Required[str] """Resource ID""" + + +class ServersSettings(TypedDict, total=False): + interfaces: Required[Iterable[ServersSettingsInterface]] + """Subnet IPs and floating IPs""" + + credentials: ServersSettingsCredentials + """Optional server access credentials""" + + 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 index d3c1b9b1..dc737d14 100644 --- a/src/gcore/types/cloud/gpu_baremetal_cluster_delete_params.py +++ b/src/gcore/types/cloud/gpu_baremetal_cluster_delete_params.py @@ -4,25 +4,32 @@ from typing_extensions import TypedDict +from ..._types import SequenceNotStr + __all__ = ["GPUBaremetalClusterDeleteParams"] class GPUBaremetalClusterDeleteParams(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 servers. - - Can't be used with floatings. + all_floating_ips: bool + """ + Flag indicating whether the floating ips associated with server / cluster are + deleted """ - floatings: str - """Comma separated list of floating ids that should be deleted. - - Can't be used with `delete_floatings`. + all_reserved_fixed_ips: bool + """ + Flag indicating whether the reserved fixed ips associated with server / cluster + are deleted """ - reserved_fixed_ips: str - """Comma separated list of port IDs to be deleted with the servers""" + 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 index 98549a17..8112f690 100644 --- a/src/gcore/types/cloud/gpu_baremetal_cluster_list_params.py +++ b/src/gcore/types/cloud/gpu_baremetal_cluster_list_params.py @@ -2,18 +2,29 @@ from __future__ import annotations -from typing_extensions import TypedDict +from typing import List +from typing_extensions import Literal, TypedDict __all__ = ["GPUBaremetalClusterListParams"] class GPUBaremetalClusterListParams(TypedDict, total=False): project_id: int + """Project ID""" region_id: int + """Region ID""" limit: int - """Limit the number of returned clusters""" + """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 value is used to exclude the first set of records from the result""" + """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 index e25da560..f4d27f43 100644 --- a/src/gcore/types/cloud/gpu_baremetal_cluster_rebuild_params.py +++ b/src/gcore/types/cloud/gpu_baremetal_cluster_rebuild_params.py @@ -2,9 +2,11 @@ from __future__ import annotations -from typing import List, Optional +from typing import Optional from typing_extensions import Required, TypedDict +from ..._types import SequenceNotStr + __all__ = ["GPUBaremetalClusterRebuildParams"] @@ -13,7 +15,7 @@ class GPUBaremetalClusterRebuildParams(TypedDict, total=False): region_id: int - nodes: Required[List[str]] + nodes: Required[SequenceNotStr[str]] """List of nodes uuids to be rebuild""" image_id: Optional[str] diff --git a/src/gcore/types/cloud/gpu_baremetal_clusters/__init__.py b/src/gcore/types/cloud/gpu_baremetal_clusters/__init__.py index 7d30e274..30aeddac 100644 --- a/src/gcore/types/cloud/gpu_baremetal_clusters/__init__.py +++ b/src/gcore/types/cloud/gpu_baremetal_clusters/__init__.py @@ -3,7 +3,13 @@ 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 .gpu_baremetal_flavor_list import GPUBaremetalFlavorList as GPUBaremetalFlavorList +from .gpu_baremetal_cluster_server import GPUBaremetalClusterServer as GPUBaremetalClusterServer from .server_attach_interface_params import ServerAttachInterfaceParams as ServerAttachInterfaceParams from .server_detach_interface_params import ServerDetachInterfaceParams as ServerDetachInterfaceParams +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/gpu_baremetal_cluster_server.py b/src/gcore/types/cloud/gpu_baremetal_clusters/gpu_baremetal_cluster_server.py new file mode 100644 index 00000000..58a99830 --- /dev/null +++ b/src/gcore/types/cloud/gpu_baremetal_clusters/gpu_baremetal_cluster_server.py @@ -0,0 +1,74 @@ +# 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): + name: str + """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 names""" + + 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_cluster_server.py b/src/gcore/types/cloud/gpu_baremetal_clusters/gpu_baremetal_cluster_server_v1.py similarity index 91% rename from src/gcore/types/cloud/gpu_baremetal_cluster_server.py rename to src/gcore/types/cloud/gpu_baremetal_clusters/gpu_baremetal_cluster_server_v1.py index 328c2d69..72debc0b 100644 --- a/src/gcore/types/cloud/gpu_baremetal_cluster_server.py +++ b/src/gcore/types/cloud/gpu_baremetal_clusters/gpu_baremetal_cluster_server_v1.py @@ -4,17 +4,17 @@ 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 +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__ = [ - "GPUBaremetalClusterServer", + "GPUBaremetalClusterServerV1", "Address", "FixedIPAssignment", "Flavor", @@ -87,7 +87,7 @@ class SecurityGroup(BaseModel): """Name.""" -class GPUBaremetalClusterServer(BaseModel): +class GPUBaremetalClusterServerV1(BaseModel): id: str """GPU server ID""" 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..a6c6a2f2 --- /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_flavor.py b/src/gcore/types/cloud/gpu_baremetal_clusters/gpu_baremetal_flavor.py similarity index 99% rename from src/gcore/types/cloud/gpu_baremetal_flavor.py rename to src/gcore/types/cloud/gpu_baremetal_clusters/gpu_baremetal_flavor.py index 9c6471c8..19278108 100644 --- a/src/gcore/types/cloud/gpu_baremetal_flavor.py +++ b/src/gcore/types/cloud/gpu_baremetal_clusters/gpu_baremetal_flavor.py @@ -3,7 +3,7 @@ from typing import Union, Optional from typing_extensions import Literal, TypeAlias -from ..._models import BaseModel +from ...._models import BaseModel __all__ = [ "GPUBaremetalFlavor", diff --git a/src/gcore/types/cloud/gpu_baremetal_flavor_list.py b/src/gcore/types/cloud/gpu_baremetal_clusters/gpu_baremetal_flavor_list.py similarity index 91% rename from src/gcore/types/cloud/gpu_baremetal_flavor_list.py rename to src/gcore/types/cloud/gpu_baremetal_clusters/gpu_baremetal_flavor_list.py index 8b241544..2cc4ee84 100644 --- a/src/gcore/types/cloud/gpu_baremetal_flavor_list.py +++ b/src/gcore/types/cloud/gpu_baremetal_clusters/gpu_baremetal_flavor_list.py @@ -2,7 +2,7 @@ from typing import List -from ..._models import BaseModel +from ...._models import BaseModel from .gpu_baremetal_flavor import GPUBaremetalFlavor __all__ = ["GPUBaremetalFlavorList"] 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..35c7f374 --- /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/inference/__init__.py b/src/gcore/types/cloud/inference/__init__.py index e692efab..95023b65 100644 --- a/src/gcore/types/cloud/inference/__init__.py +++ b/src/gcore/types/cloud/inference/__init__.py @@ -6,12 +6,10 @@ from .probe_exec import ProbeExec as ProbeExec from .probe_config import ProbeConfig as ProbeConfig from .probe_http_get import ProbeHTTPGet as ProbeHTTPGet -from .inference_model import InferenceModel as InferenceModel 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 .model_list_params import ModelListParams as ModelListParams 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 @@ -29,6 +27,3 @@ 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 -from .inference_registry_credentials_create import ( - InferenceRegistryCredentialsCreate as InferenceRegistryCredentialsCreate, -) 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..1671486c --- /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_patch_params import DeploymentPatchParams as DeploymentPatchParams +from .deployment_create_params import DeploymentCreateParams as DeploymentCreateParams +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..537480cf --- /dev/null +++ b/src/gcore/types/cloud/inference/applications/deployment_create_params.py @@ -0,0 +1,68 @@ +# 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): + 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_patch_params.py b/src/gcore/types/cloud/inference/applications/deployment_patch_params.py new file mode 100644 index 00000000..0ce4395d --- /dev/null +++ b/src/gcore/types/cloud/inference/applications/deployment_patch_params.py @@ -0,0 +1,62 @@ +# 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__ = [ + "DeploymentPatchParams", + "ComponentsConfiguration", + "ComponentsConfigurationParameterOverrides", + "ComponentsConfigurationScale", +] + + +class DeploymentPatchParams(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): + 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..b6333e6b --- /dev/null +++ b/src/gcore/types/cloud/inference/applications/inference_application_deployment.py @@ -0,0 +1,111 @@ +# 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): + 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): + 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 index 38dfafb4..9886738e 100644 --- a/src/gcore/types/cloud/inference/deployment_create_params.py +++ b/src/gcore/types/cloud/inference/deployment_create_params.py @@ -2,9 +2,10 @@ from __future__ import annotations -from typing import Dict, List, Iterable, Optional +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 @@ -64,7 +65,7 @@ class DeploymentCreateParams(TypedDict, total=False): name: Required[str] """Inference instance name.""" - api_keys: List[str] + 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` @@ -80,7 +81,7 @@ class DeploymentCreateParams(TypedDict, total=False): `api_keys` are both specified, a ValidationError will be raised. """ - command: Optional[List[str]] + command: Optional[SequenceNotStr[str]] """Command to be executed when running a container from an image.""" credentials_name: Optional[str] @@ -246,7 +247,7 @@ class Logging(TypedDict, total=False): class ProbesLivenessProbeProbeExec(TypedDict, total=False): - command: Required[List[str]] + command: Required[SequenceNotStr[str]] """Command to be executed inside the running container.""" @@ -307,7 +308,7 @@ class ProbesLivenessProbe(TypedDict, total=False): class ProbesReadinessProbeProbeExec(TypedDict, total=False): - command: Required[List[str]] + command: Required[SequenceNotStr[str]] """Command to be executed inside the running container.""" @@ -368,7 +369,7 @@ class ProbesReadinessProbe(TypedDict, total=False): class ProbesStartupProbeProbeExec(TypedDict, total=False): - command: Required[List[str]] + command: Required[SequenceNotStr[str]] """Command to be executed inside the running container.""" diff --git a/src/gcore/types/cloud/inference/deployment_update_params.py b/src/gcore/types/cloud/inference/deployment_update_params.py index e23312d9..047799c7 100644 --- a/src/gcore/types/cloud/inference/deployment_update_params.py +++ b/src/gcore/types/cloud/inference/deployment_update_params.py @@ -2,9 +2,10 @@ from __future__ import annotations -from typing import Dict, List, Iterable, Optional +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 @@ -44,7 +45,7 @@ class DeploymentUpdateParams(TypedDict, total=False): project_id: int """Project ID""" - api_keys: Optional[List[str]] + 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` @@ -61,7 +62,7 @@ class DeploymentUpdateParams(TypedDict, total=False): `api_keys` are both specified, a ValidationError will be raised. """ - command: Optional[List[str]] + command: Optional[SequenceNotStr[str]] """Command to be executed when running a container from an image.""" containers: Optional[Iterable[Container]] @@ -240,7 +241,7 @@ class Logging(TypedDict, total=False): class ProbesLivenessProbeProbeExec(TypedDict, total=False): - command: List[str] + command: SequenceNotStr[str] """Command to be executed inside the running container.""" @@ -301,7 +302,7 @@ class ProbesLivenessProbe(TypedDict, total=False): class ProbesReadinessProbeProbeExec(TypedDict, total=False): - command: List[str] + command: SequenceNotStr[str] """Command to be executed inside the running container.""" @@ -362,7 +363,7 @@ class ProbesReadinessProbe(TypedDict, total=False): class ProbesStartupProbeProbeExec(TypedDict, total=False): - command: List[str] + command: SequenceNotStr[str] """Command to be executed inside the running container.""" diff --git a/src/gcore/types/cloud/inference/inference_model.py b/src/gcore/types/cloud/inference/inference_model.py deleted file mode 100644 index 9de2dbe3..00000000 --- a/src/gcore/types/cloud/inference/inference_model.py +++ /dev/null @@ -1,65 +0,0 @@ -# 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__ = ["InferenceModel"] - - -class InferenceModel(BaseModel): - id: str - """Model ID.""" - - category: Optional[str] = None - """Category of the model.""" - - default_flavor_name: Optional[str] = None - """Default flavor for the model.""" - - description: str - """Description of the model.""" - - developer: Optional[str] = None - """Developer of the model.""" - - documentation_page: Optional[str] = None - """Path to the documentation page.""" - - eula_url: Optional[str] = None - """URL to the EULA text.""" - - example_curl_request: Optional[str] = None - """Example curl request to the model.""" - - has_eula: bool - """Whether the model has an EULA.""" - - image_registry_id: Optional[str] = None - """Image registry of the model.""" - - image_url: str - """Image URL of the model.""" - - inference_backend: Optional[str] = None - """Describing underlying inference engine.""" - - inference_frontend: Optional[str] = None - """Describing model frontend type.""" - - api_model_id: Optional[str] = FieldInfo(alias="model_id", default=None) - """Model name to perform inference call.""" - - name: str - """Name of the model.""" - - openai_compatibility: Optional[str] = None - """OpenAI compatibility level.""" - - port: int - """Port on which the model runs.""" - - version: Optional[str] = None - """Version of the model.""" diff --git a/src/gcore/types/cloud/inference/inference_registry_credentials_create.py b/src/gcore/types/cloud/inference/inference_registry_credentials_create.py deleted file mode 100644 index ff24063f..00000000 --- a/src/gcore/types/cloud/inference/inference_registry_credentials_create.py +++ /dev/null @@ -1,22 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ...._models import BaseModel - -__all__ = ["InferenceRegistryCredentialsCreate"] - - -class InferenceRegistryCredentialsCreate(BaseModel): - name: str - """Registry credential name.""" - - password: str - """Registry password.""" - - 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/model_list_params.py b/src/gcore/types/cloud/inference/model_list_params.py deleted file mode 100644 index 8bfaf71d..00000000 --- a/src/gcore/types/cloud/inference/model_list_params.py +++ /dev/null @@ -1,21 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, TypedDict - -__all__ = ["ModelListParams"] - - -class ModelListParams(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 - """ - - order_by: Literal["name.asc", "name.desc"] - """Order instances by transmitted fields and directions""" diff --git a/src/gcore/types/cloud/instance_assign_security_group_params.py b/src/gcore/types/cloud/instance_assign_security_group_params.py index 4947252e..a9af1025 100644 --- a/src/gcore/types/cloud/instance_assign_security_group_params.py +++ b/src/gcore/types/cloud/instance_assign_security_group_params.py @@ -2,9 +2,11 @@ from __future__ import annotations -from typing import List, Iterable, Optional +from typing import Iterable, Optional from typing_extensions import Required, TypedDict +from ..._types import SequenceNotStr + __all__ = ["InstanceAssignSecurityGroupParams", "PortsSecurityGroupName"] @@ -24,5 +26,5 @@ class PortsSecurityGroupName(TypedDict, total=False): port_id: Required[Optional[str]] """Port ID. If None, security groups will be applied to all ports""" - security_group_names: Required[List[str]] + security_group_names: Required[SequenceNotStr[str]] """List of security group names""" diff --git a/src/gcore/types/cloud/instance_list_params.py b/src/gcore/types/cloud/instance_list_params.py index 54ca4270..17c76f8f 100644 --- a/src/gcore/types/cloud/instance_list_params.py +++ b/src/gcore/types/cloud/instance_list_params.py @@ -2,10 +2,11 @@ from __future__ import annotations -from typing import List, Union +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"] @@ -120,7 +121,7 @@ class InstanceListParams(TypedDict, total=False): tag_key_value: str """Optional. Filter by tag key-value pairs.""" - tag_value: List[str] + tag_value: SequenceNotStr[str] """Optional. Filter by tag values. ?`tag_value`=value1&`tag_value`=value2""" type_ddos_profile: Literal["basic", "advanced"] diff --git a/src/gcore/types/cloud/instance_unassign_security_group_params.py b/src/gcore/types/cloud/instance_unassign_security_group_params.py index 0ff60506..17e978a7 100644 --- a/src/gcore/types/cloud/instance_unassign_security_group_params.py +++ b/src/gcore/types/cloud/instance_unassign_security_group_params.py @@ -2,9 +2,11 @@ from __future__ import annotations -from typing import List, Iterable, Optional +from typing import Iterable, Optional from typing_extensions import Required, TypedDict +from ..._types import SequenceNotStr + __all__ = ["InstanceUnassignSecurityGroupParams", "PortsSecurityGroupName"] @@ -24,5 +26,5 @@ class PortsSecurityGroupName(TypedDict, total=False): port_id: Required[Optional[str]] """Port ID. If None, security groups will be applied to all ports""" - security_group_names: Required[List[str]] + security_group_names: Required[SequenceNotStr[str]] """List of security group names""" diff --git a/src/gcore/types/cloud/instances/image_list_params.py b/src/gcore/types/cloud/instances/image_list_params.py index 075fe52e..1e1d2903 100644 --- a/src/gcore/types/cloud/instances/image_list_params.py +++ b/src/gcore/types/cloud/instances/image_list_params.py @@ -2,9 +2,10 @@ from __future__ import annotations -from typing import List from typing_extensions import Literal, TypedDict +from ...._types import SequenceNotStr + __all__ = ["ImageListParams"] @@ -19,7 +20,7 @@ class ImageListParams(TypedDict, total=False): private: str """Any value to show private images""" - tag_key: List[str] + tag_key: SequenceNotStr[str] """Filter by tag keys.""" tag_key_value: str diff --git a/src/gcore/types/cloud/k8s/__init__.py b/src/gcore/types/cloud/k8s/__init__.py new file mode 100644 index 00000000..2ce45d68 --- /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..d7c9497b --- /dev/null +++ b/src/gcore/types/cloud/k8s/cluster_create_params.py @@ -0,0 +1,299 @@ +# 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 ..laas_index_retention_policy_param import LaasIndexRetentionPolicyParam + +__all__ = [ + "ClusterCreateParams", + "Pool", + "Authentication", + "AuthenticationOidc", + "Cni", + "CniCilium", + "Csi", + "CsiNfs", + "DDOSProfile", + "DDOSProfileField", + "Logging", +] + + +class ClusterCreateParams(TypedDict, total=False): + project_id: int + + region_id: int + + 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""" + + 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 AuthenticationOidc(TypedDict, total=False): + 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): + oidc: Optional[AuthenticationOidc] + """OIDC authentication settings""" + + +class CniCilium(TypedDict, total=False): + 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): + cilium: Optional[CniCilium] + """Cilium settings""" + + provider: Literal["calico", "cilium"] + """CNI provider""" + + +class CsiNfs(TypedDict, total=False): + 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): + 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): + 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): + 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..49b5e580 --- /dev/null +++ b/src/gcore/types/cloud/k8s/cluster_delete_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__ = ["ClusterDeleteParams"] + + +class ClusterDeleteParams(TypedDict, total=False): + project_id: int + + region_id: int + + 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..74a40789 --- /dev/null +++ b/src/gcore/types/cloud/k8s/cluster_update_params.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 Dict, List, Iterable, Optional +from typing_extensions import Literal, Required, TypedDict + +from ..laas_index_retention_policy_param import LaasIndexRetentionPolicyParam + +__all__ = [ + "ClusterUpdateParams", + "Authentication", + "AuthenticationOidc", + "Cni", + "CniCilium", + "DDOSProfile", + "DDOSProfileField", + "Logging", +] + + +class ClusterUpdateParams(TypedDict, total=False): + project_id: int + + region_id: int + + 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 AuthenticationOidc(TypedDict, total=False): + 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): + oidc: Optional[AuthenticationOidc] + """OIDC authentication settings""" + + +class CniCilium(TypedDict, total=False): + 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): + 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): + 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): + 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..5301fc15 --- /dev/null +++ b/src/gcore/types/cloud/k8s/cluster_upgrade_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__ = ["ClusterUpgradeParams"] + + +class ClusterUpgradeParams(TypedDict, total=False): + project_id: int + + region_id: int + + 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..0ffb0b08 --- /dev/null +++ b/src/gcore/types/cloud/k8s/clusters/__init__.py @@ -0,0 +1,10 @@ +# 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 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..d8aa59e6 --- /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..9ec5299d --- /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/node_list_params.py b/src/gcore/types/cloud/k8s/clusters/node_list_params.py new file mode 100644 index 00000000..027c6cf4 --- /dev/null +++ b/src/gcore/types/cloud/k8s/clusters/node_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_extensions import TypedDict + +__all__ = ["NodeListParams"] + + +class NodeListParams(TypedDict, total=False): + project_id: int + + region_id: int + + with_ddos: bool + """Include DDoS profile information if set to true. Default is false.""" 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..f7b626a9 --- /dev/null +++ b/src/gcore/types/cloud/k8s/clusters/pool_create_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 import Dict, Optional +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["PoolCreateParams"] + + +class PoolCreateParams(TypedDict, total=False): + project_id: int + + region_id: int + + 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..60450f3e --- /dev/null +++ b/src/gcore/types/cloud/k8s/clusters/pool_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__ = ["PoolResizeParams"] + + +class PoolResizeParams(TypedDict, total=False): + project_id: int + + region_id: int + + cluster_name: Required[str] + + 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..877e80ca --- /dev/null +++ b/src/gcore/types/cloud/k8s/clusters/pool_update_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 Dict, Optional +from typing_extensions import Required, TypedDict + +__all__ = ["PoolUpdateParams"] + + +class PoolUpdateParams(TypedDict, total=False): + project_id: int + + region_id: int + + cluster_name: Required[str] + + 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] + """Current node count""" + + 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..9a31c51b --- /dev/null +++ b/src/gcore/types/cloud/k8s/clusters/pools/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 Required, TypedDict + +__all__ = ["NodeListParams"] + + +class NodeListParams(TypedDict, total=False): + project_id: int + + region_id: int + + cluster_name: Required[str] + + 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..26890db9 --- /dev/null +++ b/src/gcore/types/cloud/k8s/flavor_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__ = ["FlavorListParams"] + + +class FlavorListParams(TypedDict, total=False): + project_id: int + + region_id: int + + exclude_gpu: bool + """Set to false to include GPU flavors. Default is True.""" + + 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..621ef6e5 --- /dev/null +++ b/src/gcore/types/cloud/k8s/k8s_cluster.py @@ -0,0 +1,209 @@ +# 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", + "Csi", + "CsiNfs", + "Authentication", + "AuthenticationOidc", + "Cni", + "CniCilium", + "DDOSProfile", + "DDOSProfileField", +] + + +class CsiNfs(BaseModel): + vast_enabled: bool + """Indicates the status of VAST NFS integration""" + + +class Csi(BaseModel): + nfs: CsiNfs + """NFS settings""" + + +class AuthenticationOidc(BaseModel): + 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): + 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): + 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): + 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): + 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""" + + 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..c7965b6c --- /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..38aaabe4 --- /dev/null +++ b/src/gcore/types/cloud/k8s/k8s_cluster_kubeconfig.py @@ -0,0 +1,19 @@ +# 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__ = ["K8sClusterKubeconfig"] + + +class K8sClusterKubeconfig(BaseModel): + config: str + """Cluster kubeconfig""" + + created_at: Optional[datetime] = None + """Kubeconfig creation date""" + + expires_at: Optional[datetime] = None + """Kubeconfig expiration date""" 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..b3ed3df7 --- /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..6f8c1ddf --- /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/gpu_baremetal_cluster_server_list.py b/src/gcore/types/cloud/k8s_cluster_version_list.py similarity index 50% rename from src/gcore/types/cloud/gpu_baremetal_cluster_server_list.py rename to src/gcore/types/cloud/k8s_cluster_version_list.py index 01c531f5..27a17073 100644 --- a/src/gcore/types/cloud/gpu_baremetal_cluster_server_list.py +++ b/src/gcore/types/cloud/k8s_cluster_version_list.py @@ -3,14 +3,14 @@ from typing import List from ..._models import BaseModel -from .gpu_baremetal_cluster_server import GPUBaremetalClusterServer +from .k8s_cluster_version import K8sClusterVersion -__all__ = ["GPUBaremetalClusterServerList"] +__all__ = ["K8sClusterVersionList"] -class GPUBaremetalClusterServerList(BaseModel): +class K8sClusterVersionList(BaseModel): count: int """Number of objects""" - results: List[GPUBaremetalClusterServer] + results: List[K8sClusterVersion] """Objects""" diff --git a/src/gcore/types/cloud/load_balancer_create_params.py b/src/gcore/types/cloud/load_balancer_create_params.py index 6b2f7564..7a4c3051 100644 --- a/src/gcore/types/cloud/load_balancer_create_params.py +++ b/src/gcore/types/cloud/load_balancer_create_params.py @@ -2,9 +2,10 @@ from __future__ import annotations -from typing import Dict, List, Union, Iterable, Optional +from typing import Dict, 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 @@ -216,7 +217,25 @@ class ListenerPoolMember(TypedDict, total=False): """ weight: int - """Member weight. Valid values are 0 < `weight` <= 256, defaults to 1.""" + """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): @@ -295,7 +314,7 @@ class Listener(TypedDict, total=False): protocol_port: Required[int] """Protocol port""" - allowed_cidrs: Optional[List[str]] + allowed_cidrs: Optional[SequenceNotStr[str]] """Network CIDRs from which service will be accessible""" connection_limit: int @@ -316,7 +335,7 @@ class Listener(TypedDict, total=False): PROMETHEUS listener """ - sni_secret_id: List[str] + sni_secret_id: SequenceNotStr[str] """ List of secrets IDs containing PKCS12 format certificate/key bundles for `TERMINATED_HTTPS` or PROMETHEUS listeners diff --git a/src/gcore/types/cloud/load_balancer_list_params.py b/src/gcore/types/cloud/load_balancer_list_params.py index 704c2eb3..81ab5ea7 100644 --- a/src/gcore/types/cloud/load_balancer_list_params.py +++ b/src/gcore/types/cloud/load_balancer_list_params.py @@ -2,9 +2,10 @@ from __future__ import annotations -from typing import List from typing_extensions import TypedDict +from ..._types import SequenceNotStr + __all__ = ["LoadBalancerListParams"] @@ -39,7 +40,7 @@ class LoadBalancerListParams(TypedDict, total=False): show_stats: bool """Show statistics""" - tag_key: List[str] + tag_key: SequenceNotStr[str] """Filter by tag keys.""" tag_key_value: str 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 index c7209f66..a15d72e2 100644 --- 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 @@ -2,9 +2,10 @@ from __future__ import annotations -from typing import List from typing_extensions import Literal, Required, TypedDict +from ....._types import SequenceNotStr + __all__ = ["RuleCreateParams"] @@ -46,5 +47,5 @@ class RuleCreateParams(TypedDict, total=False): For example, the name of the cookie to evaluate. """ - tags: List[str] + 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 index f2c7004b..4694d1b8 100644 --- 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 @@ -2,9 +2,10 @@ from __future__ import annotations -from typing import List from typing_extensions import Literal, Required, TypedDict +from ....._types import SequenceNotStr + __all__ = ["RuleReplaceParams"] @@ -31,7 +32,7 @@ class RuleReplaceParams(TypedDict, total=False): For example, the name of the cookie to evaluate. """ - tags: List[str] + tags: SequenceNotStr[str] """A list of simple strings assigned to the l7 rule""" type: Literal[ 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 index f4bb93b8..2ffea9c0 100644 --- a/src/gcore/types/cloud/load_balancers/l7_policy_create_params.py +++ b/src/gcore/types/cloud/load_balancers/l7_policy_create_params.py @@ -2,9 +2,10 @@ from __future__ import annotations -from typing import List from typing_extensions import Literal, Required, TypedDict +from ...._types import SequenceNotStr + __all__ = ["L7PolicyCreateParams"] @@ -50,5 +51,5 @@ class L7PolicyCreateParams(TypedDict, total=False): Only valid if action is `REDIRECT_TO_URL`. """ - tags: List[str] + tags: SequenceNotStr[str] """A list of simple strings assigned to the resource.""" diff --git a/src/gcore/types/cloud/load_balancers/l7_policy_replace_params.py b/src/gcore/types/cloud/load_balancers/l7_policy_replace_params.py index 697b0954..2ed23ebc 100644 --- a/src/gcore/types/cloud/load_balancers/l7_policy_replace_params.py +++ b/src/gcore/types/cloud/load_balancers/l7_policy_replace_params.py @@ -2,9 +2,10 @@ from __future__ import annotations -from typing import List from typing_extensions import Literal, Required, TypedDict +from ...._types import SequenceNotStr + __all__ = ["L7PolicyReplaceParams"] @@ -47,5 +48,5 @@ class L7PolicyReplaceParams(TypedDict, total=False): Only valid if action is `REDIRECT_TO_URL`. """ - tags: List[str] + tags: SequenceNotStr[str] """A list of simple strings assigned to the resource.""" diff --git a/src/gcore/types/cloud/load_balancers/listener_create_params.py b/src/gcore/types/cloud/load_balancers/listener_create_params.py index 5afdc99f..7f7bf451 100644 --- a/src/gcore/types/cloud/load_balancers/listener_create_params.py +++ b/src/gcore/types/cloud/load_balancers/listener_create_params.py @@ -2,9 +2,10 @@ from __future__ import annotations -from typing import List, Iterable, Optional +from typing import Iterable, Optional from typing_extensions import Required, TypedDict +from ...._types import SequenceNotStr from ..lb_listener_protocol import LbListenerProtocol __all__ = ["ListenerCreateParams", "UserList"] @@ -29,7 +30,7 @@ class ListenerCreateParams(TypedDict, total=False): protocol_port: Required[int] """Protocol port""" - allowed_cidrs: Optional[List[str]] + allowed_cidrs: Optional[SequenceNotStr[str]] """Network CIDRs from which service will be accessible""" connection_limit: int @@ -47,7 +48,7 @@ class ListenerCreateParams(TypedDict, total=False): PROMETHEUS listener """ - sni_secret_id: List[str] + sni_secret_id: SequenceNotStr[str] """ List of secrets IDs containing PKCS12 format certificate/key bundles for `TERMINATED_HTTPS` or PROMETHEUS listeners diff --git a/src/gcore/types/cloud/load_balancers/listener_update_params.py b/src/gcore/types/cloud/load_balancers/listener_update_params.py index 8c520b8f..492c990d 100644 --- a/src/gcore/types/cloud/load_balancers/listener_update_params.py +++ b/src/gcore/types/cloud/load_balancers/listener_update_params.py @@ -2,9 +2,11 @@ from __future__ import annotations -from typing import List, Iterable, Optional +from typing import Iterable, Optional from typing_extensions import Required, TypedDict +from ...._types import SequenceNotStr + __all__ = ["ListenerUpdateParams", "UserList"] @@ -15,7 +17,7 @@ class ListenerUpdateParams(TypedDict, total=False): region_id: int """Region ID""" - allowed_cidrs: Optional[List[str]] + allowed_cidrs: Optional[SequenceNotStr[str]] """Network CIDRs from which service will be accessible""" connection_limit: int @@ -30,7 +32,7 @@ class ListenerUpdateParams(TypedDict, total=False): PROMETHEUS load balancer """ - sni_secret_id: Optional[List[str]] + sni_secret_id: Optional[SequenceNotStr[str]] """ List of secret's ID containing PKCS12 format certificate/key bundfles for `TERMINATED_HTTPS` or PROMETHEUS listeners diff --git a/src/gcore/types/cloud/load_balancers/pool_create_params.py b/src/gcore/types/cloud/load_balancers/pool_create_params.py index 28f38cf5..b19fb813 100644 --- a/src/gcore/types/cloud/load_balancers/pool_create_params.py +++ b/src/gcore/types/cloud/load_balancers/pool_create_params.py @@ -147,7 +147,25 @@ class Member(TypedDict, total=False): """ weight: int - """Member weight. Valid values are 0 < `weight` <= 256, defaults to 1.""" + """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): diff --git a/src/gcore/types/cloud/load_balancers/pool_update_params.py b/src/gcore/types/cloud/load_balancers/pool_update_params.py index 490b704e..088d3cec 100644 --- a/src/gcore/types/cloud/load_balancers/pool_update_params.py +++ b/src/gcore/types/cloud/load_balancers/pool_update_params.py @@ -145,7 +145,25 @@ class Member(TypedDict, total=False): """ weight: int - """Member weight. Valid values are 0 < `weight` <= 256, defaults to 1.""" + """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): diff --git a/src/gcore/types/cloud/load_balancers/pools/member_add_params.py b/src/gcore/types/cloud/load_balancers/pools/member_add_params.py index 08af2d6c..7b62edc9 100644 --- a/src/gcore/types/cloud/load_balancers/pools/member_add_params.py +++ b/src/gcore/types/cloud/load_balancers/pools/member_add_params.py @@ -59,4 +59,22 @@ class MemberAddParams(TypedDict, total=False): """ weight: int - """Member weight. Valid values are 0 < `weight` <= 256, defaults to 1.""" + """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/member.py b/src/gcore/types/cloud/member.py index 71e0be9a..98acfa1e 100644 --- a/src/gcore/types/cloud/member.py +++ b/src/gcore/types/cloud/member.py @@ -45,7 +45,25 @@ class Member(BaseModel): """`subnet_id` in which `address` is present.""" weight: int - """Member weight. Valid values are 0 < `weight` <= 256.""" + """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. diff --git a/src/gcore/types/cloud/network_list_params.py b/src/gcore/types/cloud/network_list_params.py index fd80aecd..a690ab5b 100644 --- a/src/gcore/types/cloud/network_list_params.py +++ b/src/gcore/types/cloud/network_list_params.py @@ -2,9 +2,10 @@ from __future__ import annotations -from typing import List from typing_extensions import Literal, TypedDict +from ..._types import SequenceNotStr + __all__ = ["NetworkListParams"] @@ -33,7 +34,7 @@ class NetworkListParams(TypedDict, total=False): directions (`created_at.desc`). """ - tag_key: List[str] + tag_key: SequenceNotStr[str] """Optional. Filter by tag keys. ?`tag_key`=key1&`tag_key`=key2""" tag_key_value: str diff --git a/src/gcore/types/cloud/networks/subnet_create_params.py b/src/gcore/types/cloud/networks/subnet_create_params.py index 9fd4a938..6d8b3749 100644 --- a/src/gcore/types/cloud/networks/subnet_create_params.py +++ b/src/gcore/types/cloud/networks/subnet_create_params.py @@ -2,9 +2,10 @@ from __future__ import annotations -from typing import Dict, List, Iterable, Optional +from typing import Dict, Iterable, Optional from typing_extensions import Required, TypedDict +from ...._types import SequenceNotStr from ..ip_version import IPVersion __all__ = ["SubnetCreateParams", "HostRoute"] @@ -32,7 +33,7 @@ class SubnetCreateParams(TypedDict, total=False): Must be explicitly 'false' when `gateway_ip` is null. """ - dns_nameservers: Optional[List[str]] + dns_nameservers: Optional[SequenceNotStr[str]] """List IP addresses of DNS servers to advertise via DHCP.""" enable_dhcp: bool diff --git a/src/gcore/types/cloud/networks/subnet_list_params.py b/src/gcore/types/cloud/networks/subnet_list_params.py index ecae30b7..4327998f 100644 --- a/src/gcore/types/cloud/networks/subnet_list_params.py +++ b/src/gcore/types/cloud/networks/subnet_list_params.py @@ -2,9 +2,10 @@ from __future__ import annotations -from typing import List from typing_extensions import Literal, TypedDict +from ...._types import SequenceNotStr + __all__ = ["SubnetListParams"] @@ -47,7 +48,7 @@ class SubnetListParams(TypedDict, total=False): directions (`name.asc`). """ - tag_key: List[str] + tag_key: SequenceNotStr[str] """Optional. Filter by tag keys. ?`tag_key`=key1&`tag_key`=key2""" tag_key_value: str diff --git a/src/gcore/types/cloud/networks/subnet_update_params.py b/src/gcore/types/cloud/networks/subnet_update_params.py index 966b3ccf..455119cc 100644 --- a/src/gcore/types/cloud/networks/subnet_update_params.py +++ b/src/gcore/types/cloud/networks/subnet_update_params.py @@ -2,9 +2,10 @@ from __future__ import annotations -from typing import List, Iterable, Optional +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"] @@ -17,7 +18,7 @@ class SubnetUpdateParams(TypedDict, total=False): region_id: int """Region ID""" - dns_nameservers: Optional[List[str]] + dns_nameservers: Optional[SequenceNotStr[str]] """List IP addresses of DNS servers to advertise via DHCP.""" enable_dhcp: Optional[bool] diff --git a/src/gcore/types/cloud/project.py b/src/gcore/types/cloud/project.py index 8d978657..ce547c1a 100644 --- a/src/gcore/types/cloud/project.py +++ b/src/gcore/types/cloud/project.py @@ -18,6 +18,15 @@ class Project(BaseModel): 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. @@ -30,15 +39,6 @@ class Project(BaseModel): state: str """The state of the project.""" - 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.""" - task_id: Optional[str] = None """The UUID of the active task that currently holds a lock on the resource. diff --git a/src/gcore/types/cloud/reserved_fixed_ips/vip_replace_connected_ports_params.py b/src/gcore/types/cloud/reserved_fixed_ips/vip_replace_connected_ports_params.py index 84c497bb..cb8aa477 100644 --- a/src/gcore/types/cloud/reserved_fixed_ips/vip_replace_connected_ports_params.py +++ b/src/gcore/types/cloud/reserved_fixed_ips/vip_replace_connected_ports_params.py @@ -2,9 +2,10 @@ from __future__ import annotations -from typing import List from typing_extensions import TypedDict +from ...._types import SequenceNotStr + __all__ = ["VipReplaceConnectedPortsParams"] @@ -13,5 +14,5 @@ class VipReplaceConnectedPortsParams(TypedDict, total=False): region_id: int - port_ids: List[str] + port_ids: SequenceNotStr[str] """List of port IDs that will share one VIP""" diff --git a/src/gcore/types/cloud/reserved_fixed_ips/vip_update_connected_ports_params.py b/src/gcore/types/cloud/reserved_fixed_ips/vip_update_connected_ports_params.py index d93b4303..d11d10a0 100644 --- a/src/gcore/types/cloud/reserved_fixed_ips/vip_update_connected_ports_params.py +++ b/src/gcore/types/cloud/reserved_fixed_ips/vip_update_connected_ports_params.py @@ -2,9 +2,10 @@ from __future__ import annotations -from typing import List from typing_extensions import TypedDict +from ...._types import SequenceNotStr + __all__ = ["VipUpdateConnectedPortsParams"] @@ -13,5 +14,5 @@ class VipUpdateConnectedPortsParams(TypedDict, total=False): region_id: int - port_ids: List[str] + port_ids: SequenceNotStr[str] """List of port IDs that will share one VIP""" diff --git a/src/gcore/types/cloud/security_group_create_params.py b/src/gcore/types/cloud/security_group_create_params.py index 4431da3c..4721a5dc 100644 --- a/src/gcore/types/cloud/security_group_create_params.py +++ b/src/gcore/types/cloud/security_group_create_params.py @@ -2,9 +2,11 @@ from __future__ import annotations -from typing import Dict, List, Iterable, Optional +from typing import Dict, Iterable, Optional from typing_extensions import Literal, Required, TypedDict +from ..._types import SequenceNotStr + __all__ = ["SecurityGroupCreateParams", "SecurityGroup", "SecurityGroupSecurityGroupRule"] @@ -16,7 +18,7 @@ class SecurityGroupCreateParams(TypedDict, total=False): security_group: Required[SecurityGroup] """Security group""" - instances: List[str] + instances: SequenceNotStr[str] """List of instances""" diff --git a/src/gcore/types/cloud/security_group_list_params.py b/src/gcore/types/cloud/security_group_list_params.py index 8ba036cc..676a5d48 100644 --- a/src/gcore/types/cloud/security_group_list_params.py +++ b/src/gcore/types/cloud/security_group_list_params.py @@ -2,9 +2,10 @@ from __future__ import annotations -from typing import List from typing_extensions import TypedDict +from ..._types import SequenceNotStr + __all__ = ["SecurityGroupListParams"] @@ -19,7 +20,7 @@ class SecurityGroupListParams(TypedDict, total=False): offset: int """Offset value is used to exclude the first set of records from the result""" - tag_key: List[str] + tag_key: SequenceNotStr[str] """Filter by tag keys.""" tag_key_value: str diff --git a/src/gcore/types/cloud/task_id_list.py b/src/gcore/types/cloud/task_id_list.py index 957deed7..7796e645 100644 --- a/src/gcore/types/cloud/task_id_list.py +++ b/src/gcore/types/cloud/task_id_list.py @@ -9,4 +9,11 @@ class TaskIDList(BaseModel): tasks: List[str] - """List of task IDs""" + """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 index 3835a7f4..22a319d3 100644 --- a/src/gcore/types/cloud/task_list_params.py +++ b/src/gcore/types/cloud/task_list_params.py @@ -67,25 +67,25 @@ class TaskListParams(TypedDict, total=False): '`create_faas_function`', '`create_faas_namespace`', '`create_fip`', '`create_gpu_virtual_cluster`', '`create_image`', '`create_inference_application`', '`create_inference_instance`', - '`create_inference_instance_key`', '`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_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_reserved_fixed_ip`', '`delete_router`', - '`delete_secret`', '`delete_servergroup`', '`delete_sfs`', '`delete_snapshot`', - '`delete_subnet`', '`delete_vm`', '`delete_volume`', '`detach_vm_interface`', - '`detach_volume`', '`download_image`', '`downscale_ai_cluster_gpu`', + '`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_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_reserved_fixed_ip`', '`delete_router`', '`delete_secret`', + '`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`', @@ -102,10 +102,10 @@ class TaskListParams(TypedDict, total=False): '`stop_gpu_virtual_cluster`', '`stop_gpu_virtual_server`', '`stop_vm`', '`suspend_vm`', '`sync_private_flavors`', '`update_ddos_profile`', '`update_inference_application`', '`update_inference_instance`', - '`update_inference_instance_key`', '`update_k8s_cluster_v2`', - '`update_lbmetadata`', '`update_port_allowed_address_pairs`', - '`update_tags_gpu_virtual_cluster`', '`upgrade_k8s_cluster_v2`', - '`upscale_ai_cluster_gpu`', '`upscale_gpu_virtual_cluster`'] + '`update_k8s_cluster_v2`', '`update_lbmetadata`', + '`update_port_allowed_address_pairs`', '`update_tags_gpu_virtual_cluster`', + '`upgrade_k8s_cluster_v2`', '`upscale_ai_cluster_gpu`', + '`upscale_gpu_virtual_cluster`'] """ to_timestamp: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")] diff --git a/src/gcore/types/cloud/usage_report_get_params.py b/src/gcore/types/cloud/usage_report_get_params.py index 336bcd46..ea7a3e0e 100644 --- a/src/gcore/types/cloud/usage_report_get_params.py +++ b/src/gcore/types/cloud/usage_report_get_params.py @@ -6,6 +6,7 @@ from datetime import datetime from typing_extensions import Literal, Required, Annotated, TypeAlias, TypedDict +from ..._types import SequenceNotStr from ..._utils import PropertyInfo __all__ = [ @@ -120,7 +121,7 @@ class SchemaFilterSchemaFilterSnapshotSerializer(TypedDict, total=False): type: Required[Literal["snapshot"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -130,7 +131,7 @@ class SchemaFilterSchemaFilterInstanceSerializer(TypedDict, total=False): type: Required[Literal["instance"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -140,7 +141,7 @@ class SchemaFilterSchemaFilterAIClusterSerializer(TypedDict, total=False): type: Required[Literal["ai_cluster"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -150,7 +151,7 @@ class SchemaFilterSchemaFilterAIVirtualClusterSerializer(TypedDict, total=False) type: Required[Literal["ai_virtual_cluster"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -160,7 +161,7 @@ class SchemaFilterSchemaFilterBasicVmSerializer(TypedDict, total=False): type: Required[Literal["basic_vm"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -170,7 +171,7 @@ class SchemaFilterSchemaFilterBaremetalSerializer(TypedDict, total=False): type: Required[Literal["baremetal"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -180,7 +181,7 @@ class SchemaFilterSchemaFilterVolumeSerializer(TypedDict, total=False): type: Required[Literal["volume"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -190,7 +191,7 @@ class SchemaFilterSchemaFilterFileShareSerializer(TypedDict, total=False): type: Required[Literal["file_share"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -200,7 +201,7 @@ class SchemaFilterSchemaFilterImageSerializer(TypedDict, total=False): type: Required[Literal["image"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -210,7 +211,7 @@ class SchemaFilterSchemaFilterFloatingIPSerializer(TypedDict, total=False): type: Required[Literal["floatingip"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -220,7 +221,7 @@ class SchemaFilterSchemaFilterEgressTrafficSerializer(TypedDict, total=False): type: Required[Literal["egress_traffic"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -230,7 +231,7 @@ class SchemaFilterSchemaFilterLoadBalancerSerializer(TypedDict, total=False): type: Required[Literal["load_balancer"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -240,7 +241,7 @@ class SchemaFilterSchemaFilterExternalIPSerializer(TypedDict, total=False): type: Required[Literal["external_ip"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -250,7 +251,7 @@ class SchemaFilterSchemaFilterBackupSerializer(TypedDict, total=False): type: Required[Literal["backup"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -260,7 +261,7 @@ class SchemaFilterSchemaFilterLogIndexSerializer(TypedDict, total=False): type: Required[Literal["log_index"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -270,7 +271,7 @@ class SchemaFilterSchemaFilterFunctionsSerializer(TypedDict, total=False): type: Required[Literal["functions"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -280,7 +281,7 @@ class SchemaFilterSchemaFilterFunctionsCallsSerializer(TypedDict, total=False): type: Required[Literal["functions_calls"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -290,7 +291,7 @@ class SchemaFilterSchemaFilterFunctionsTrafficSerializer(TypedDict, total=False) type: Required[Literal["functions_traffic"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -300,7 +301,7 @@ class SchemaFilterSchemaFilterContainersSerializer(TypedDict, total=False): type: Required[Literal["containers"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -310,7 +311,7 @@ class SchemaFilterSchemaFilterInferenceSerializer(TypedDict, total=False): type: Required[Literal["inference"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -320,7 +321,7 @@ class SchemaFilterSchemaFilterDbaasPostgreSQLVolumeSerializer(TypedDict, total=F type: Required[Literal["dbaas_postgresql_volume"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -330,7 +331,7 @@ class SchemaFilterSchemaFilterDbaasPostgreSQLPublicNetworkSerializer(TypedDict, type: Required[Literal["dbaas_postgresql_public_network"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -340,7 +341,7 @@ class SchemaFilterSchemaFilterDbaasPostgreSqlcpuSerializer(TypedDict, total=Fals type: Required[Literal["dbaas_postgresql_cpu"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -350,7 +351,7 @@ class SchemaFilterSchemaFilterDbaasPostgreSQLMemorySerializer(TypedDict, total=F type: Required[Literal["dbaas_postgresql_memory"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" @@ -360,7 +361,7 @@ class SchemaFilterSchemaFilterDbaasPostgreSQLPoolerSerializer(TypedDict, total=F type: Required[Literal["dbaas_postgresql_connection_pooler"]] - values: Required[List[str]] + values: Required[SequenceNotStr[str]] """List of field values to filter""" diff --git a/src/gcore/types/cloud/users/role_assignment.py b/src/gcore/types/cloud/users/role_assignment.py index 774c5ede..03497395 100644 --- a/src/gcore/types/cloud/users/role_assignment.py +++ b/src/gcore/types/cloud/users/role_assignment.py @@ -2,6 +2,7 @@ from typing import Optional from datetime import datetime +from typing_extensions import Literal from ...._models import BaseModel @@ -23,7 +24,7 @@ class RoleAssignment(BaseModel): project_id: Optional[int] = None """Project ID""" - role: str + role: Literal["ClientAdministrator", "InternalNetworkOnlyUser", "Observer", "ProjectAdministrator", "User"] """User role""" updated_at: Optional[datetime] = None diff --git a/src/gcore/types/cloud/users/role_assignment_create_params.py b/src/gcore/types/cloud/users/role_assignment_create_params.py index d5b33f73..3799fac3 100644 --- a/src/gcore/types/cloud/users/role_assignment_create_params.py +++ b/src/gcore/types/cloud/users/role_assignment_create_params.py @@ -3,13 +3,15 @@ from __future__ import annotations from typing import Optional -from typing_extensions import Required, TypedDict +from typing_extensions import Literal, Required, TypedDict __all__ = ["RoleAssignmentCreateParams"] class RoleAssignmentCreateParams(TypedDict, total=False): - role: Required[str] + role: Required[ + Literal["ClientAdministrator", "InternalNetworkOnlyUser", "Observer", "ProjectAdministrator", "User"] + ] """User role""" user_id: Required[int] diff --git a/src/gcore/types/cloud/users/role_assignment_update_params.py b/src/gcore/types/cloud/users/role_assignment_update_params.py index fb9051cf..10b6dc82 100644 --- a/src/gcore/types/cloud/users/role_assignment_update_params.py +++ b/src/gcore/types/cloud/users/role_assignment_update_params.py @@ -3,13 +3,15 @@ from __future__ import annotations from typing import Optional -from typing_extensions import Required, TypedDict +from typing_extensions import Literal, Required, TypedDict __all__ = ["RoleAssignmentUpdateParams"] class RoleAssignmentUpdateParams(TypedDict, total=False): - role: Required[str] + role: Required[ + Literal["ClientAdministrator", "InternalNetworkOnlyUser", "Observer", "ProjectAdministrator", "User"] + ] """User role""" user_id: Required[int] diff --git a/src/gcore/types/cloud/volume_list_params.py b/src/gcore/types/cloud/volume_list_params.py index 18573ee7..11fac11f 100644 --- a/src/gcore/types/cloud/volume_list_params.py +++ b/src/gcore/types/cloud/volume_list_params.py @@ -2,9 +2,10 @@ from __future__ import annotations -from typing import List from typing_extensions import TypedDict +from ..._types import SequenceNotStr + __all__ = ["VolumeListParams"] @@ -45,7 +46,7 @@ class VolumeListParams(TypedDict, total=False): Offset value is used to exclude the first set of records from the result """ - tag_key: List[str] + tag_key: SequenceNotStr[str] """Optional. Filter by tag keys. ?`tag_key`=key1&`tag_key`=key2""" tag_key_value: str diff --git a/src/gcore/types/dns/__init__.py b/src/gcore/types/dns/__init__.py new file mode 100644 index 00000000..f72384a3 --- /dev/null +++ b/src/gcore/types/dns/__init__.py @@ -0,0 +1,31 @@ +# 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 .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 .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_location_translations import DNSLocationTranslations as DNSLocationTranslations +from .zone_get_statistics_params import ZoneGetStatisticsParams as ZoneGetStatisticsParams +from .zone_get_statistics_response import ZoneGetStatisticsResponse as ZoneGetStatisticsResponse +from .location_list_regions_response import LocationListRegionsResponse as LocationListRegionsResponse +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_name_server.py b/src/gcore/types/dns/dns_name_server.py new file mode 100644 index 00000000..619c4943 --- /dev/null +++ b/src/gcore/types/dns/dns_name_server.py @@ -0,0 +1,17 @@ +# 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): + 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/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/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..912d6f73 --- /dev/null +++ b/src/gcore/types/dns/zone_get_response.py @@ -0,0 +1,106 @@ +# 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__ = ["ZoneGetResponse", "Zone", "ZoneRecord", "ZoneRrsetsAmount", "ZoneRrsetsAmountDynamic"] + + +class ZoneRecord(BaseModel): + name: Optional[str] = None + + short_answers: Optional[List[str]] = None + + ttl: Optional[int] = None + + type: Optional[str] = None + + +class ZoneRrsetsAmountDynamic(BaseModel): + 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): + 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 + """ + + expiry: Optional[int] = None + """ + number of seconds after which secondary name servers should stop answering + request for this zone + """ + + meta: Optional[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 ZoneGetResponse(BaseModel): + zone: Optional[Zone] = FieldInfo(alias="Zone", default=None) + """OutputZone""" 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..ee528101 --- /dev/null +++ b/src/gcore/types/dns/zone_get_statistics_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 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..6798692d --- /dev/null +++ b/src/gcore/types/dns/zone_get_statistics_response.py @@ -0,0 +1,19 @@ +# 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): + 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..ca009f38 --- /dev/null +++ b/src/gcore/types/dns/zone_import_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 + +__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..d3a365ed --- /dev/null +++ b/src/gcore/types/dns/zone_import_response.py @@ -0,0 +1,26 @@ +# 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): + 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..256ed922 --- /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..6a3826f3 --- /dev/null +++ b/src/gcore/types/dns/zone_list_response.py @@ -0,0 +1,105 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from ..._models import BaseModel + +__all__ = ["ZoneListResponse", "Zone", "ZoneRecord", "ZoneRrsetsAmount", "ZoneRrsetsAmountDynamic"] + + +class ZoneRecord(BaseModel): + name: Optional[str] = None + + short_answers: Optional[List[str]] = None + + ttl: Optional[int] = None + + type: Optional[str] = None + + +class ZoneRrsetsAmountDynamic(BaseModel): + 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): + 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 + """ + + expiry: Optional[int] = None + """ + number of seconds after which secondary name servers should stop answering + request for this zone + """ + + meta: Optional[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..a329325a --- /dev/null +++ b/src/gcore/types/dns/zones/dns_failover_log.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__ = ["DNSFailoverLog", "DNSFailoverLogItem"] + + +class DNSFailoverLogItem(BaseModel): + 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..8ff63143 --- /dev/null +++ b/src/gcore/types/dns/zones/dns_output_rrset.py @@ -0,0 +1,123 @@ +# 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. `fallback` (bool) + 6. `backup` (bool) + 7. `notes` (string) + 8. `weight` (float) + 9. `ip` (string) 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..16facb7e --- /dev/null +++ b/src/gcore/types/dns/zones/rrset_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 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): + 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..e258f9b9 --- /dev/null +++ b/src/gcore/types/dns/zones/rrset_replace_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 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): + 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/security/client_profile.py b/src/gcore/types/security/client_profile.py index e440f21b..e02111b5 100644 --- a/src/gcore/types/security/client_profile.py +++ b/src/gcore/types/security/client_profile.py @@ -25,7 +25,7 @@ class Field(BaseModel): validation_schema: Dict[str, object] - field_value: Optional[Dict[str, object]] = None + field_value: Optional[object] = None class Options(BaseModel): diff --git a/src/gcore/types/security/profile_create_params.py b/src/gcore/types/security/profile_create_params.py index fbefd31e..d4bd6d61 100644 --- a/src/gcore/types/security/profile_create_params.py +++ b/src/gcore/types/security/profile_create_params.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Dict, Iterable, Optional +from typing import Iterable, Optional from typing_extensions import Required, TypedDict __all__ = ["ProfileCreateParams", "Field"] @@ -21,4 +21,4 @@ class ProfileCreateParams(TypedDict, total=False): class Field(TypedDict, total=False): base_field: Required[int] - field_value: Optional[Dict[str, object]] + field_value: object diff --git a/src/gcore/types/security/profile_recreate_params.py b/src/gcore/types/security/profile_recreate_params.py index b8418275..e1dd3d10 100644 --- a/src/gcore/types/security/profile_recreate_params.py +++ b/src/gcore/types/security/profile_recreate_params.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Dict, Iterable, Optional +from typing import Iterable, Optional from typing_extensions import Required, TypedDict __all__ = ["ProfileRecreateParams", "Field"] @@ -21,4 +21,4 @@ class ProfileRecreateParams(TypedDict, total=False): class Field(TypedDict, total=False): base_field: Required[int] - field_value: Optional[Dict[str, object]] + field_value: object diff --git a/src/gcore/types/security/profile_replace_params.py b/src/gcore/types/security/profile_replace_params.py index d4304a67..9684dffd 100644 --- a/src/gcore/types/security/profile_replace_params.py +++ b/src/gcore/types/security/profile_replace_params.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Dict, Iterable, Optional +from typing import Iterable, Optional from typing_extensions import Required, TypedDict __all__ = ["ProfileReplaceParams", "Field"] @@ -21,4 +21,4 @@ class ProfileReplaceParams(TypedDict, total=False): class Field(TypedDict, total=False): base_field: Required[int] - field_value: Optional[Dict[str, object]] + field_value: object 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..e2cc7ae4 --- /dev/null +++ b/src/gcore/types/storage/bucket.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__ = ["Bucket"] + + +class Bucket(BaseModel): + 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..42a3e527 --- /dev/null +++ b/src/gcore/types/storage/buckets/bucket_cors.py @@ -0,0 +1,18 @@ +# 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): + 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..d0b7c608 --- /dev/null +++ b/src/gcore/types/storage/credential_recreate_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_extensions import TypedDict + +__all__ = ["CredentialRecreateParams"] + + +class CredentialRecreateParams(TypedDict, total=False): + delete_sftp_password: bool + """Remove the SFTP password, disabling password authentication. + + Only applicable to SFTP storage type. + """ + + generate_s3_keys: bool + """Generate new S3 access and secret keys for S3 storage. + + Only applicable to S3 storage type. + """ + + generate_sftp_password: bool + """Generate a new random password for SFTP access. + + Only applicable to SFTP storage type. + """ + + reset_sftp_keys: bool + """Reset/remove all SSH keys associated with the SFTP storage. + + Only applicable to SFTP storage type. + """ + + sftp_password: str + """Set a custom password for SFTP access. Only applicable to SFTP storage type.""" diff --git a/src/gcore/types/storage/location.py b/src/gcore/types/storage/location.py new file mode 100644 index 00000000..0dda2627 --- /dev/null +++ b/src/gcore/types/storage/location.py @@ -0,0 +1,24 @@ +# 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): + 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..6c02f31b --- /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: Literal["s-ed1", "s-drc2", "s-sgc1", "s-nhn2", "s-darz", "s-ws1", "ams", "sin", "fra", "mia"] + """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..b3a6cc62 --- /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[Literal["s-ed1", "s-drc2", "s-sgc1", "s-nhn2", "s-darz", "s-ws1", "ams", "sin", "fra", "mia"]] + """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..5454b294 --- /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 + """ISO 8601 timestamp when the storage should expire. + + Leave empty to remove expiration. + """ + + server_alias: str + """Custom domain alias for accessing the storage. Leave 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..ae2288f7 --- /dev/null +++ b/src/gcore/types/storage/usage_total.py @@ -0,0 +1,54 @@ +# 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): + 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 index d64adf6e..b58b2e1d 100644 --- a/src/gcore/types/streaming/__init__.py +++ b/src/gcore/types/streaming/__init__.py @@ -13,7 +13,6 @@ from .restream import Restream as Restream from .subtitle import Subtitle as Subtitle from .broadcast import Broadcast as Broadcast -from .meet_series import MeetSeries as MeetSeries from .player_param import PlayerParam as PlayerParam from .quality_sets import QualitySets as QualitySets from .stream_series import StreamSeries as StreamSeries @@ -67,7 +66,6 @@ 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_casm import AIContentmoderationCasm as AIContentmoderationCasm 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 @@ -75,7 +73,6 @@ 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 .ai_contentmoderation_weapon import AIContentmoderationWeapon as AIContentmoderationWeapon 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 @@ -86,7 +83,6 @@ 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 .statistic_get_meet_series_params import StatisticGetMeetSeriesParams as StatisticGetMeetSeriesParams 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 diff --git a/src/gcore/types/streaming/ai_contentmoderation_casm.py b/src/gcore/types/streaming/ai_contentmoderation_casm.py deleted file mode 100644 index be44029f..00000000 --- a/src/gcore/types/streaming/ai_contentmoderation_casm.py +++ /dev/null @@ -1,39 +0,0 @@ -# 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__ = ["AIContentmoderationCasm"] - - -class AIContentmoderationCasm(BaseModel): - category: Literal["child_pornography", "sport", "weapon", "nsfw", "hard_nudity", "soft_nudity"] - """AI content moderation with child pornography 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_hardnudity.py b/src/gcore/types/streaming/ai_contentmoderation_hardnudity.py index 4dd49d55..61517f1a 100644 --- a/src/gcore/types/streaming/ai_contentmoderation_hardnudity.py +++ b/src/gcore/types/streaming/ai_contentmoderation_hardnudity.py @@ -9,7 +9,7 @@ class AIContentmoderationHardnudity(BaseModel): - category: Literal["hard_nudity", "sport", "weapon", "nsfw", "soft_nudity", "child_pornography"] + category: Literal["hard_nudity", "sport", "nsfw", "soft_nudity"] """AI content moderation with "`hard_nudity`" algorithm""" task_name: Literal["content-moderation"] diff --git a/src/gcore/types/streaming/ai_contentmoderation_nsfw.py b/src/gcore/types/streaming/ai_contentmoderation_nsfw.py index c2df5d03..e7c3436b 100644 --- a/src/gcore/types/streaming/ai_contentmoderation_nsfw.py +++ b/src/gcore/types/streaming/ai_contentmoderation_nsfw.py @@ -9,7 +9,7 @@ class AIContentmoderationNsfw(BaseModel): - category: Literal["nsfw", "sport", "weapon", "hard_nudity", "soft_nudity", "child_pornography"] + category: Literal["nsfw", "sport", "hard_nudity", "soft_nudity"] """AI content moderation with NSFW detection algorithm""" task_name: Literal["content-moderation"] diff --git a/src/gcore/types/streaming/ai_contentmoderation_softnudity.py b/src/gcore/types/streaming/ai_contentmoderation_softnudity.py index 8c169401..5c0b7f3c 100644 --- a/src/gcore/types/streaming/ai_contentmoderation_softnudity.py +++ b/src/gcore/types/streaming/ai_contentmoderation_softnudity.py @@ -9,7 +9,7 @@ class AIContentmoderationSoftnudity(BaseModel): - category: Literal["soft_nudity", "sport", "weapon", "nsfw", "hard_nudity", "child_pornography"] + category: Literal["soft_nudity", "sport", "nsfw", "hard_nudity"] """AI content moderation with "`soft_nudity`" algorithm""" task_name: Literal["content-moderation"] diff --git a/src/gcore/types/streaming/ai_contentmoderation_sport.py b/src/gcore/types/streaming/ai_contentmoderation_sport.py index 34c8974e..78c5b629 100644 --- a/src/gcore/types/streaming/ai_contentmoderation_sport.py +++ b/src/gcore/types/streaming/ai_contentmoderation_sport.py @@ -9,7 +9,7 @@ class AIContentmoderationSport(BaseModel): - category: Literal["sport", "weapon", "nsfw", "hard_nudity", "soft_nudity", "child_pornography"] + category: Literal["sport", "nsfw", "hard_nudity", "soft_nudity"] """AI content moderation with types of sports activity detection""" task_name: Literal["content-moderation"] diff --git a/src/gcore/types/streaming/ai_contentmoderation_weapon.py b/src/gcore/types/streaming/ai_contentmoderation_weapon.py deleted file mode 100644 index b0e8c452..00000000 --- a/src/gcore/types/streaming/ai_contentmoderation_weapon.py +++ /dev/null @@ -1,39 +0,0 @@ -# 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__ = ["AIContentmoderationWeapon"] - - -class AIContentmoderationWeapon(BaseModel): - category: Literal["weapon", "sport", "nsfw", "hard_nudity", "soft_nudity", "child_pornography"] - """AI content moderation with weapon 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_task.py b/src/gcore/types/streaming/ai_task.py index acf9b2ee..fd114dea 100644 --- a/src/gcore/types/streaming/ai_task.py +++ b/src/gcore/types/streaming/ai_task.py @@ -4,10 +4,8 @@ from typing_extensions import Literal, TypeAlias from ..._models import BaseModel -from .ai_contentmoderation_casm import AIContentmoderationCasm from .ai_contentmoderation_nsfw import AIContentmoderationNsfw from .ai_contentmoderation_sport import AIContentmoderationSport -from .ai_contentmoderation_weapon import AIContentmoderationWeapon from .ai_contentmoderation_hardnudity import AIContentmoderationHardnudity from .ai_contentmoderation_softnudity import AIContentmoderationSoftnudity @@ -163,7 +161,7 @@ class TaskDataAITranscribe(BaseModel): - 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 /ai/tasks#transcribe](https://api.gcore.com/docs/streaming/docs/api-reference/streaming/ai/create-ai-asr-task). + [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). """ @@ -174,9 +172,7 @@ class TaskDataAITranscribe(BaseModel): AIContentmoderationNsfw, AIContentmoderationHardnudity, AIContentmoderationSoftnudity, - AIContentmoderationCasm, AIContentmoderationSport, - AIContentmoderationWeapon, ] diff --git a/src/gcore/types/streaming/ai_task_create_params.py b/src/gcore/types/streaming/ai_task_create_params.py index f0fe134f..11bddf89 100644 --- a/src/gcore/types/streaming/ai_task_create_params.py +++ b/src/gcore/types/streaming/ai_task_create_params.py @@ -130,7 +130,7 @@ class AITaskCreateParams(TypedDict, total=False): - 'yor': Yoruba """ - category: Literal["sport", "weapon", "nsfw", "hard_nudity", "soft_nudity", "child_pornography"] + category: Literal["sport", "nsfw", "hard_nudity", "soft_nudity"] """Model for analysis (content-moderation only). Determines what exactly needs to be found in the video. @@ -162,7 +162,7 @@ class AITaskCreateParams(TypedDict, total=False): - 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 /ai/tasks#transcribe](https://api.gcore.com/docs/streaming/docs/api-reference/streaming/ai/create-ai-asr-task). + [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_get_response.py b/src/gcore/types/streaming/ai_task_get_response.py index e9179a3c..8bd63299 100644 --- a/src/gcore/types/streaming/ai_task_get_response.py +++ b/src/gcore/types/streaming/ai_task_get_response.py @@ -16,16 +16,12 @@ "AITaskGetResponseResultAIResultsTranscribeSubtitle", "AITaskGetResponseResultAIResultsContentmoderationSport", "AITaskGetResponseResultAIResultsContentmoderationSportFrame", - "AITaskGetResponseResultAIResultsContentmoderationWeapon", - "AITaskGetResponseResultAIResultsContentmoderationWeaponFrame", "AITaskGetResponseResultAIResultsContentmoderationNsfw", "AITaskGetResponseResultAIResultsContentmoderationNsfwFrame", "AITaskGetResponseResultAIResultsContentmoderationHardnudity", "AITaskGetResponseResultAIResultsContentmoderationHardnudityFrame", "AITaskGetResponseResultAIResultsContentmoderationSoftnudity", "AITaskGetResponseResultAIResultsContentmoderationSoftnudityFrame", - "AITaskGetResponseResultAIResultsContentmoderationCasm", - "AITaskGetResponseResultAIResultsContentmoderationCasmFrame", "AITaskGetResponseResultAIResultsFailure", ] @@ -157,26 +153,6 @@ class AITaskGetResponseResultAIResultsContentmoderationSport(BaseModel): """A boolean value whether any sports were detected""" -class AITaskGetResponseResultAIResultsContentmoderationWeaponFrame(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 AITaskGetResponseResultAIResultsContentmoderationWeapon(BaseModel): - detection_results: Optional[List[Literal["gun", "heavy weapon", "knife"]]] = None - - frames: Optional[List[AITaskGetResponseResultAIResultsContentmoderationWeaponFrame]] = None - - weapon_detected: Optional[bool] = None - """A boolean value whether any weapon was detected""" - - class AITaskGetResponseResultAIResultsContentmoderationNsfwFrame(BaseModel): confidence: Optional[float] = None """Percentage of probability of identifying the object""" @@ -271,26 +247,6 @@ class AITaskGetResponseResultAIResultsContentmoderationSoftnudity(BaseModel): """A boolean value whether any nudity and other body part was detected""" -class AITaskGetResponseResultAIResultsContentmoderationCasmFrame(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 AITaskGetResponseResultAIResultsContentmoderationCasm(BaseModel): - child_pornography_detected: Optional[bool] = None - """A boolean value whether child pornography was detected""" - - detection_results: Optional[List[Literal["0-2", "3-9", "10-19"]]] = None - - frames: Optional[List[AITaskGetResponseResultAIResultsContentmoderationCasmFrame]] = None - - class AITaskGetResponseResultAIResultsFailure(BaseModel): error: str @@ -298,11 +254,9 @@ class AITaskGetResponseResultAIResultsFailure(BaseModel): AITaskGetResponseResult: TypeAlias = Union[ AITaskGetResponseResultAIResultsTranscribe, AITaskGetResponseResultAIResultsContentmoderationSport, - AITaskGetResponseResultAIResultsContentmoderationWeapon, AITaskGetResponseResultAIResultsContentmoderationNsfw, AITaskGetResponseResultAIResultsContentmoderationHardnudity, AITaskGetResponseResultAIResultsContentmoderationSoftnudity, - AITaskGetResponseResultAIResultsContentmoderationCasm, AITaskGetResponseResultAIResultsFailure, ] diff --git a/src/gcore/types/streaming/clip.py b/src/gcore/types/streaming/clip.py index 3a8e444c..f5c0135a 100644 --- a/src/gcore/types/streaming/clip.py +++ b/src/gcore/types/streaming/clip.py @@ -38,7 +38,8 @@ class Clip(BaseModel): 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: + `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` """ diff --git a/src/gcore/types/streaming/create_video_param.py b/src/gcore/types/streaming/create_video_param.py index a4ce231a..aed1f153 100644 --- a/src/gcore/types/streaming/create_video_param.py +++ b/src/gcore/types/streaming/create_video_param.py @@ -25,16 +25,16 @@ class CreateVideoParam(TypedDict, total=False): attribute of API POST /streaming/ai/transcribe . Example: ``` - `auto_transcribe_audio_language`: "auto" - `auto_transcribe_audio_language`: "ger" + auto_transcribe_audio_language: "auto" + auto_transcribe_audio_language: "ger" ``` More details: - List of AI tasks – API - [GET /streaming/ai/tasks](https://api.gcore.com/docs/streaming/docs/api-reference/streaming/ai/get-ai-task-result) + [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](https://api.gcore.com/docs/streaming/docs/api-reference/streaming/subtitles/add-subtitle). + [POST /streaming/videos/{`video_id`}/subtitles](/docs/api-reference/streaming/subtitles/add-subtitle). """ auto_translate_subtitles_language: Literal["disable", "default", ""] @@ -53,8 +53,8 @@ class CreateVideoParam(TypedDict, total=False): subtitle will be generated for each language. Example: ``` - `auto_translate_subtitles_language`: default - `auto_translate_subtitles_language`: eng,fre,ger + auto_translate_subtitles_language: default + auto_translate_subtitles_language: eng,fre,ger ``` Please note that subtitle translation is done separately and after @@ -95,7 +95,7 @@ class CreateVideoParam(TypedDict, total=False): 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: + `Authorization: ` Examples: - "`origin_http_headers`": "Authorization: Basic ..." - "`origin_http_headers`": "Authorization: Bearer ..." @@ -104,10 +104,11 @@ class CreateVideoParam(TypedDict, total=False): ``` 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" + "name": "IBC 2024 intro.mp4", + "origin_url": "https://www.googleapis.com/drive/v3/files/...?alt=media", + "origin_http_headers": "Authorization: Bearer ABC" } ``` """ @@ -128,8 +129,8 @@ class CreateVideoParam(TypedDict, total=False): 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: + 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==` diff --git a/src/gcore/types/streaming/max_stream_series.py b/src/gcore/types/streaming/max_stream_series.py index 13cd4451..bd2166bf 100644 --- a/src/gcore/types/streaming/max_stream_series.py +++ b/src/gcore/types/streaming/max_stream_series.py @@ -5,17 +5,17 @@ from ..._models import BaseModel -__all__ = ["MaxStreamSeries", "MaxStreamSeryItem", "MaxStreamSeryItemMetrics"] +__all__ = ["MaxStreamSeries", "MaxStreamSeriesItem", "MaxStreamSeriesItemMetrics"] -class MaxStreamSeryItemMetrics(BaseModel): +class MaxStreamSeriesItemMetrics(BaseModel): streams: List[int] -class MaxStreamSeryItem(BaseModel): +class MaxStreamSeriesItem(BaseModel): client: int - metrics: MaxStreamSeryItemMetrics + metrics: MaxStreamSeriesItemMetrics -MaxStreamSeries: TypeAlias = List[MaxStreamSeryItem] +MaxStreamSeries: TypeAlias = List[MaxStreamSeriesItem] diff --git a/src/gcore/types/streaming/meet_series.py b/src/gcore/types/streaming/meet_series.py deleted file mode 100644 index 1b35d0f7..00000000 --- a/src/gcore/types/streaming/meet_series.py +++ /dev/null @@ -1,23 +0,0 @@ -# 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__ = ["MeetSeries", "MeetSeryItem", "MeetSeryItemMetrics"] - - -class MeetSeryItemMetrics(BaseModel): - max_meet_usage: Optional[List[int]] = None - - meet: Optional[List[List[int]]] = None - - -class MeetSeryItem(BaseModel): - client: int - - metrics: MeetSeryItemMetrics - - -MeetSeries: TypeAlias = List[MeetSeryItem] diff --git a/src/gcore/types/streaming/playlist.py b/src/gcore/types/streaming/playlist.py index 4e814af1..677306e0 100644 --- a/src/gcore/types/streaming/playlist.py +++ b/src/gcore/types/streaming/playlist.py @@ -49,7 +49,7 @@ class Playlist(BaseModel): 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 `` + `/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 diff --git a/src/gcore/types/streaming/playlist_create_params.py b/src/gcore/types/streaming/playlist_create_params.py index 48fcffe0..f8043bbe 100644 --- a/src/gcore/types/streaming/playlist_create_params.py +++ b/src/gcore/types/streaming/playlist_create_params.py @@ -49,7 +49,7 @@ class PlaylistCreateParams(TypedDict, total=False): 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 `` + `/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 diff --git a/src/gcore/types/streaming/playlist_update_params.py b/src/gcore/types/streaming/playlist_update_params.py index bf2e1489..a8f2a06e 100644 --- a/src/gcore/types/streaming/playlist_update_params.py +++ b/src/gcore/types/streaming/playlist_update_params.py @@ -49,7 +49,7 @@ class PlaylistUpdateParams(TypedDict, total=False): 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 `` + `/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 diff --git a/src/gcore/types/streaming/playlist_video.py b/src/gcore/types/streaming/playlist_video.py index 52c65b05..309b5362 100644 --- a/src/gcore/types/streaming/playlist_video.py +++ b/src/gcore/types/streaming/playlist_video.py @@ -26,16 +26,16 @@ class PlaylistVideo(BaseModel): attribute of API POST /streaming/ai/transcribe . Example: ``` - `auto_transcribe_audio_language`: "auto" - `auto_transcribe_audio_language`: "ger" + auto_transcribe_audio_language: "auto" + auto_transcribe_audio_language: "ger" ``` More details: - List of AI tasks – API - [GET /streaming/ai/tasks](https://api.gcore.com/docs/streaming/docs/api-reference/streaming/ai/get-ai-task-result) + [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](https://api.gcore.com/docs/streaming/docs/api-reference/streaming/subtitles/add-subtitle). + [POST /streaming/videos/{`video_id`}/subtitles](/docs/api-reference/streaming/subtitles/add-subtitle). """ auto_translate_subtitles_language: Optional[Literal["disable", "default", ""]] = None @@ -54,8 +54,8 @@ class PlaylistVideo(BaseModel): subtitle will be generated for each language. Example: ``` - `auto_translate_subtitles_language`: default - `auto_translate_subtitles_language`: eng,fre,ger + auto_translate_subtitles_language: default + auto_translate_subtitles_language: eng,fre,ger ``` Please note that subtitle translation is done separately and after @@ -96,7 +96,7 @@ class PlaylistVideo(BaseModel): 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: + `Authorization: ` Examples: - "`origin_http_headers`": "Authorization: Basic ..." - "`origin_http_headers`": "Authorization: Bearer ..." @@ -105,10 +105,11 @@ class PlaylistVideo(BaseModel): ``` 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" + "name": "IBC 2024 intro.mp4", + "origin_url": "https://www.googleapis.com/drive/v3/files/...?alt=media", + "origin_http_headers": "Authorization: Bearer ABC" } ``` """ @@ -129,8 +130,8 @@ class PlaylistVideo(BaseModel): 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: + 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==` diff --git a/src/gcore/types/streaming/statistic_get_meet_series_params.py b/src/gcore/types/streaming/statistic_get_meet_series_params.py deleted file mode 100644 index 7c3e36ce..00000000 --- a/src/gcore/types/streaming/statistic_get_meet_series_params.py +++ /dev/null @@ -1,20 +0,0 @@ -# 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__ = ["StatisticGetMeetSeriesParams"] - - -class StatisticGetMeetSeriesParams(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/storage_series.py b/src/gcore/types/streaming/storage_series.py index 64b971d9..34d459e0 100644 --- a/src/gcore/types/streaming/storage_series.py +++ b/src/gcore/types/streaming/storage_series.py @@ -5,19 +5,19 @@ from ..._models import BaseModel -__all__ = ["StorageSeries", "StorageSeryItem", "StorageSeryItemMetrics"] +__all__ = ["StorageSeries", "StorageSeriesItem", "StorageSeriesItemMetrics"] -class StorageSeryItemMetrics(BaseModel): +class StorageSeriesItemMetrics(BaseModel): max_volume_usage: List[int] storage: List[List[int]] -class StorageSeryItem(BaseModel): +class StorageSeriesItem(BaseModel): client: int - metrics: StorageSeryItemMetrics + metrics: StorageSeriesItemMetrics -StorageSeries: TypeAlias = List[StorageSeryItem] +StorageSeries: TypeAlias = List[StorageSeriesItem] diff --git a/src/gcore/types/streaming/stream.py b/src/gcore/types/streaming/stream.py index 4aadef8a..903a1515 100644 --- a/src/gcore/types/streaming/stream.py +++ b/src/gcore/types/streaming/stream.py @@ -89,7 +89,7 @@ class Stream(BaseModel): 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_entity_data = '{ "seq_id": "1234567890", "name": "John Doe", "iat": 1516239022 }'` """ client_user_id: Optional[int] = None @@ -168,7 +168,7 @@ class Stream(BaseModel): - 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 MPEGTS (.ts) chunks, look at + "`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 @@ -184,13 +184,13 @@ class Stream(BaseModel): hls_mpegts_url: Optional[str] = None """HLS output for legacy devices. - URL for transcoded result of stream in HLS MPEGTS (.ts) format, with .m3u8 link. - Low Latency support: NO. Some legacy devices or software may require MPEGTS - (.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 MPEGTS segmenter in parallel with main HLS CMAF. Both formats are - sharing same segments size, manifest length (DVR), etc. + 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: @@ -202,8 +202,8 @@ class Stream(BaseModel): 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` + this field. I.e. `?get_duration_sec=true` Example: + `https://demo.gvideo.io/mpegts/2675_19146/master_mpegts.m3u8?get_duration_sec=true` ``` #EXTM3U @@ -212,7 +212,7 @@ class Stream(BaseModel): ... #EXTINF:2.000000, #EXT-X-PROGRAM-DATE-TIME:2025-08-14T08:15:00 - seg1.ts?`duration_sec`=2 + seg1.ts?duration_sec=2 ... ``` """ @@ -239,28 +239,12 @@ class Stream(BaseModel): 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""" - low_latency_enabled: Optional[bool] = None - """ - Deprecated, always returns "true". The only exception is that the attribute can - only be used by clients that have previously used the old stream format. This - method is outdated since we've made it easier to manage streams. For your - convenience, you no longer need to set this parameter at the stage of creating a - stream. Now all streams are prepared in 2 formats simultaniously: Low Latency - and Legacy. You can get the desired output format in the attributes - "`dash_url`", "`hls_cmaf_url`", "`hls_mpegts_url`". Or use them all at once. - - --- - - Note: Links /streams/{id}/playlist.m3u8 are depricated too. Use value of the - "`hls_mpegts_url`" attribute instead. - """ - projection: Optional[Literal["regular", "vr360", "vr180", "vr360tb"]] = None """ Visualization mode for 360° streams, how the stream is rendered in our web @@ -279,15 +263,19 @@ class Stream(BaseModel): Has two possible values: - true – stream is received by PULL method. Use this when need to get stream - from external server by srt, rtmp\\ss, hls, dash, etc protocols. + 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 mobile app or OBS Studio. + 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://". @@ -295,20 +283,58 @@ class Stream(BaseModel): 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. 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. + 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 + `push_url` to once, 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: either only SRT (`push_url_srt`), or only - RTMP (`push_url`). + 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 + `push_url_srt` to once, 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 @@ -321,9 +347,9 @@ class Stream(BaseModel): 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). **WebRTC stream encoding - parameters** At least one video and audio track both must be present in the - stream: + 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 @@ -339,8 +365,18 @@ class Stream(BaseModel): 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. More information in the Product Documentation on the - website. + 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 + `push_url_whip` to once, 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 @@ -407,10 +443,11 @@ class Stream(BaseModel): 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 24 hours of - inactivity of your streams we will stop PULL-ing, and will switch "active" field - 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. + 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 diff --git a/src/gcore/types/streaming/stream_create_clip_params.py b/src/gcore/types/streaming/stream_create_clip_params.py index 345d35b2..e8f0b107 100644 --- a/src/gcore/types/streaming/stream_create_clip_params.py +++ b/src/gcore/types/streaming/stream_create_clip_params.py @@ -32,7 +32,8 @@ class StreamCreateClipParams(TypedDict, total=False): 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: + `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` """ diff --git a/src/gcore/types/streaming/stream_create_params.py b/src/gcore/types/streaming/stream_create_params.py index 827874ce..a8254826 100644 --- a/src/gcore/types/streaming/stream_create_params.py +++ b/src/gcore/types/streaming/stream_create_params.py @@ -57,7 +57,7 @@ class StreamCreateParams(TypedDict, total=False): 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_entity_data = '{ "seq_id": "1234567890", "name": "John Doe", "iat": 1516239022 }'` """ client_user_id: int @@ -94,22 +94,6 @@ class StreamCreateParams(TypedDict, total=False): live streams """ - low_latency_enabled: bool - """ - Deprecated, always returns "true". The only exception is that the attribute can - only be used by clients that have previously used the old stream format. This - method is outdated since we've made it easier to manage streams. For your - convenience, you no longer need to set this parameter at the stage of creating a - stream. Now all streams are prepared in 2 formats simultaniously: Low Latency - and Legacy. You can get the desired output format in the attributes - "`dash_url`", "`hls_cmaf_url`", "`hls_mpegts_url`". Or use them all at once. - - --- - - Note: Links /streams/{id}/playlist.m3u8 are depricated too. Use value of the - "`hls_mpegts_url`" attribute instead. - """ - projection: Literal["regular", "vr360", "vr180", "vr360tb"] """ Visualization mode for 360° streams, how the stream is rendered in our web @@ -128,9 +112,10 @@ class StreamCreateParams(TypedDict, total=False): Has two possible values: - true – stream is received by PULL method. Use this when need to get stream - from external server by srt, rtmp\\ss, hls, dash, etc protocols. + 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 mobile app or OBS Studio. + from end-device to our Streaming Platform, i.e. from your encoder, mobile app + or OBS Studio. """ quality_set_id: int @@ -158,8 +143,9 @@ class StreamCreateParams(TypedDict, total=False): 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 24 hours of - inactivity of your streams we will stop PULL-ing, and will switch "active" field - 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. + 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_series.py b/src/gcore/types/streaming/stream_series.py index 0d941224..4e14f573 100644 --- a/src/gcore/types/streaming/stream_series.py +++ b/src/gcore/types/streaming/stream_series.py @@ -5,17 +5,17 @@ from ..._models import BaseModel -__all__ = ["StreamSeries", "StreamSeryItem", "StreamSeryItemMetrics"] +__all__ = ["StreamSeries", "StreamSeriesItem", "StreamSeriesItemMetrics"] -class StreamSeryItemMetrics(BaseModel): +class StreamSeriesItemMetrics(BaseModel): streams: List[int] -class StreamSeryItem(BaseModel): +class StreamSeriesItem(BaseModel): client: int - metrics: StreamSeryItemMetrics + metrics: StreamSeriesItemMetrics -StreamSeries: TypeAlias = List[StreamSeryItem] +StreamSeries: TypeAlias = List[StreamSeriesItem] diff --git a/src/gcore/types/streaming/stream_update_params.py b/src/gcore/types/streaming/stream_update_params.py index 55a3430f..ecff938d 100644 --- a/src/gcore/types/streaming/stream_update_params.py +++ b/src/gcore/types/streaming/stream_update_params.py @@ -61,7 +61,7 @@ class Stream(TypedDict, total=False): 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_entity_data = '{ "seq_id": "1234567890", "name": "John Doe", "iat": 1516239022 }'` """ client_user_id: int @@ -98,22 +98,6 @@ class Stream(TypedDict, total=False): live streams """ - low_latency_enabled: bool - """ - Deprecated, always returns "true". The only exception is that the attribute can - only be used by clients that have previously used the old stream format. This - method is outdated since we've made it easier to manage streams. For your - convenience, you no longer need to set this parameter at the stage of creating a - stream. Now all streams are prepared in 2 formats simultaniously: Low Latency - and Legacy. You can get the desired output format in the attributes - "`dash_url`", "`hls_cmaf_url`", "`hls_mpegts_url`". Or use them all at once. - - --- - - Note: Links /streams/{id}/playlist.m3u8 are depricated too. Use value of the - "`hls_mpegts_url`" attribute instead. - """ - projection: Literal["regular", "vr360", "vr180", "vr360tb"] """ Visualization mode for 360° streams, how the stream is rendered in our web @@ -132,9 +116,10 @@ class Stream(TypedDict, total=False): Has two possible values: - true – stream is received by PULL method. Use this when need to get stream - from external server by srt, rtmp\\ss, hls, dash, etc protocols. + 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 mobile app or OBS Studio. + from end-device to our Streaming Platform, i.e. from your encoder, mobile app + or OBS Studio. """ quality_set_id: int @@ -162,8 +147,9 @@ class Stream(TypedDict, total=False): 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 24 hours of - inactivity of your streams we will stop PULL-ing, and will switch "active" field - 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. + 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/video.py b/src/gcore/types/streaming/video.py index cb2a3026..42fff728 100644 --- a/src/gcore/types/streaming/video.py +++ b/src/gcore/types/streaming/video.py @@ -32,41 +32,64 @@ class ConvertedVideo(BaseModel): - /videos/{`client_id`}\\__{slug}/{filename}.mp4 - /videos/{`client_id`}\\__{slug}/{filename}.mp4/download - /videos/{`client_id`}\\__{slug}/{filename}.mp4/download={`custom_filename`} The - first option returns the file as is. The following options respond with the - header that directly tells browsers to download the file instead of playing it - in the browser. + first option returns the file as is. Response will be: ``` - Content-Disposition: attachment + 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 + 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` - - **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. + - First character cannot be .(dot) + - Example valid filenames: `holiday2025`, `_backup.final`, `clip-v1.2` - ``` - - ```– Codec name that was used to encode the video, or audio codec if it is an audio-only file. + ``` + GET .mp4/download={custom_filename} + ... + content-type: video/mp4 + content-disposition: attachment; filename="{custom_filename}.mp4" + access-control-expose-headers: Content-Disposition + ``` - ``` - - ```– Encoding bitrate in Kbps. + Examples: - ``` - - ````– 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 ``` + - Video: + `https://demo-public.gvideo.io/videos/2675_1OFgHZ1FWZNNvx1A/qid3567v1_h264_4050_1080.mp4/download` + - Video 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 @@ -88,15 +111,6 @@ class ConvertedVideo(BaseModel): - ip: The user’s IP address Example: `?md5=QX39c77lbQKvYgMMAvpyMQ&expires=1743167062` Read more in Product Documentation in Streaming section "Protected temporarily link". - - **Examples** - - - Audio-only: - `` https://demo-public.gvideo.io/videos/`2675_JNnccG5l97XPxsov`/`qid3585v1_aac_128_audio`.mp4 `` - - Video: - `` https://demo-public.gvideo.io/videos/`2675_3MlggU4xDb1Ssa5Y`/`qid3567v1_h264_4050_1080`.mp4/download `` - - Video with custom download filename: - `` https://demo-public.gvideo.io/videos/`2675_XtMKxzJM6Xt7SBUV`/1080.mp4/download=`highlights_v1`.`1_2025`-05-30 `` """ name: Optional[str] = None @@ -171,8 +185,8 @@ class Video(BaseModel): 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: + `/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. @@ -231,7 +245,7 @@ class Video(BaseModel): 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 `` + `/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` @@ -270,10 +284,10 @@ class Video(BaseModel): 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. + - ?`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. @@ -312,13 +326,10 @@ class Video(BaseModel): 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. - ``` + 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 diff --git a/src/gcore/types/streaming/video_update_params.py b/src/gcore/types/streaming/video_update_params.py index bdf6f4ec..db5ed39f 100644 --- a/src/gcore/types/streaming/video_update_params.py +++ b/src/gcore/types/streaming/video_update_params.py @@ -25,16 +25,16 @@ class VideoUpdateParams(TypedDict, total=False): attribute of API POST /streaming/ai/transcribe . Example: ``` - `auto_transcribe_audio_language`: "auto" - `auto_transcribe_audio_language`: "ger" + auto_transcribe_audio_language: "auto" + auto_transcribe_audio_language: "ger" ``` More details: - List of AI tasks – API - [GET /streaming/ai/tasks](https://api.gcore.com/docs/streaming/docs/api-reference/streaming/ai/get-ai-task-result) + [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](https://api.gcore.com/docs/streaming/docs/api-reference/streaming/subtitles/add-subtitle). + [POST /streaming/videos/{`video_id`}/subtitles](/docs/api-reference/streaming/subtitles/add-subtitle). """ auto_translate_subtitles_language: Literal["disable", "default", ""] @@ -53,8 +53,8 @@ class VideoUpdateParams(TypedDict, total=False): subtitle will be generated for each language. Example: ``` - `auto_translate_subtitles_language`: default - `auto_translate_subtitles_language`: eng,fre,ger + auto_translate_subtitles_language: default + auto_translate_subtitles_language: eng,fre,ger ``` Please note that subtitle translation is done separately and after @@ -95,7 +95,7 @@ class VideoUpdateParams(TypedDict, total=False): 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: + `Authorization: ` Examples: - "`origin_http_headers`": "Authorization: Basic ..." - "`origin_http_headers`": "Authorization: Bearer ..." @@ -104,10 +104,11 @@ class VideoUpdateParams(TypedDict, total=False): ``` 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" + "name": "IBC 2024 intro.mp4", + "origin_url": "https://www.googleapis.com/drive/v3/files/...?alt=media", + "origin_http_headers": "Authorization: Bearer ABC" } ``` """ @@ -128,8 +129,8 @@ class VideoUpdateParams(TypedDict, total=False): 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: + 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==` diff --git a/src/gcore/types/streaming/vod_statistics_series.py b/src/gcore/types/streaming/vod_statistics_series.py index 2e82bbb3..7b268b3f 100644 --- a/src/gcore/types/streaming/vod_statistics_series.py +++ b/src/gcore/types/streaming/vod_statistics_series.py @@ -5,17 +5,17 @@ from ..._models import BaseModel -__all__ = ["VodStatisticsSeries", "VodStatisticsSeryItem", "VodStatisticsSeryItemMetrics"] +__all__ = ["VodStatisticsSeries", "VodStatisticsSeriesItem", "VodStatisticsSeriesItemMetrics"] -class VodStatisticsSeryItemMetrics(BaseModel): +class VodStatisticsSeriesItemMetrics(BaseModel): vod: List[int] -class VodStatisticsSeryItem(BaseModel): +class VodStatisticsSeriesItem(BaseModel): client: int - metrics: VodStatisticsSeryItemMetrics + metrics: VodStatisticsSeriesItemMetrics -VodStatisticsSeries: TypeAlias = List[VodStatisticsSeryItem] +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 index a938a1fe..28dc7dda 100644 --- a/src/gcore/types/streaming/vod_total_stream_duration_series.py +++ b/src/gcore/types/streaming/vod_total_stream_duration_series.py @@ -5,10 +5,10 @@ from ..._models import BaseModel -__all__ = ["VodTotalStreamDurationSeries", "VodTotalStreamDurationSeryItem"] +__all__ = ["VodTotalStreamDurationSeries", "VodTotalStreamDurationSeriesItem"] -class VodTotalStreamDurationSeryItem(BaseModel): +class VodTotalStreamDurationSeriesItem(BaseModel): client: int duration: int @@ -19,4 +19,4 @@ class VodTotalStreamDurationSeryItem(BaseModel): stream_id: Optional[str] = None -VodTotalStreamDurationSeries: TypeAlias = List[VodTotalStreamDurationSeryItem] +VodTotalStreamDurationSeries: TypeAlias = List[VodTotalStreamDurationSeriesItem] diff --git a/src/gcore/types/waap/domain_list_params.py b/src/gcore/types/waap/domain_list_params.py index c0d65852..767d4eaa 100644 --- a/src/gcore/types/waap/domain_list_params.py +++ b/src/gcore/types/waap/domain_list_params.py @@ -25,4 +25,4 @@ class DomainListParams(TypedDict, total=False): """Sort the response by given field.""" status: Literal["active", "bypass", "monitor", "locked"] - """The different statuses a domain can have""" + """Filter domains based on the domain status""" diff --git a/src/gcore/types/waap/domain_update_params.py b/src/gcore/types/waap/domain_update_params.py index a9b8d477..cd2134bd 100644 --- a/src/gcore/types/waap/domain_update_params.py +++ b/src/gcore/types/waap/domain_update_params.py @@ -9,4 +9,4 @@ class DomainUpdateParams(TypedDict, total=False): status: Literal["active", "monitor"] - """Domain statuses that can be used when updating a domain""" + """The current status of the domain""" diff --git a/src/gcore/types/waap/domains/advanced_rule_create_params.py b/src/gcore/types/waap/domains/advanced_rule_create_params.py index 52e32ad8..a1edf88a 100644 --- a/src/gcore/types/waap/domains/advanced_rule_create_params.py +++ b/src/gcore/types/waap/domains/advanced_rule_create_params.py @@ -2,15 +2,17 @@ from __future__ import annotations -from typing import List, Optional +from typing import 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 a WAAP rule takes when triggered""" + """The action that the rule takes when triggered""" enabled: Required[bool] """Whether or not the rule is enabled""" @@ -45,7 +47,8 @@ class ActionBlock(TypedDict, total=False): """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) + 'd' to represent time format (seconds, minutes, hours, or days). Empty time + intervals are not allowed. """ status_code: Optional[Literal[403, 405, 418, 429]] @@ -53,7 +56,7 @@ class ActionBlock(TypedDict, total=False): class ActionTag(TypedDict, total=False): - tags: Required[List[str]] + tags: Required[SequenceNotStr[str]] """The list of user defined tags to tag the request with""" diff --git a/src/gcore/types/waap/domains/advanced_rule_update_params.py b/src/gcore/types/waap/domains/advanced_rule_update_params.py index a592c6f8..f158d460 100644 --- a/src/gcore/types/waap/domains/advanced_rule_update_params.py +++ b/src/gcore/types/waap/domains/advanced_rule_update_params.py @@ -2,9 +2,11 @@ from __future__ import annotations -from typing import List, Optional +from typing import Optional from typing_extensions import Literal, Required, TypedDict +from ...._types import SequenceNotStr + __all__ = ["AdvancedRuleUpdateParams", "Action", "ActionBlock", "ActionTag"] @@ -48,7 +50,8 @@ class ActionBlock(TypedDict, total=False): """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) + 'd' to represent time format (seconds, minutes, hours, or days). Empty time + intervals are not allowed. """ status_code: Optional[Literal[403, 405, 418, 429]] @@ -56,7 +59,7 @@ class ActionBlock(TypedDict, total=False): class ActionTag(TypedDict, total=False): - tags: Required[List[str]] + tags: Required[SequenceNotStr[str]] """The list of user defined tags to tag the request with""" diff --git a/src/gcore/types/waap/domains/api_path_create_params.py b/src/gcore/types/waap/domains/api_path_create_params.py index 59bd8cb2..bec29966 100644 --- a/src/gcore/types/waap/domains/api_path_create_params.py +++ b/src/gcore/types/waap/domains/api_path_create_params.py @@ -2,9 +2,10 @@ from __future__ import annotations -from typing import List from typing_extensions import Literal, Required, TypedDict +from ...._types import SequenceNotStr + __all__ = ["APIPathCreateParams"] @@ -21,11 +22,11 @@ class APIPathCreateParams(TypedDict, total=False): brackets """ - api_groups: List[str] + api_groups: SequenceNotStr[str] """An array of api groups associated with the API path""" api_version: str """The API version""" - tags: List[str] + tags: SequenceNotStr[str] """An array of tags 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 index 31d1e176..b819dc8b 100644 --- a/src/gcore/types/waap/domains/api_path_list_params.py +++ b/src/gcore/types/waap/domains/api_path_list_params.py @@ -5,6 +5,8 @@ from typing import List, Optional from typing_extensions import Literal, TypedDict +from ...._types import SequenceNotStr + __all__ = ["APIPathListParams"] @@ -18,7 +20,7 @@ class APIPathListParams(TypedDict, total=False): http_scheme: Optional[Literal["HTTP", "HTTPS"]] """The different HTTP schemes an API path can have""" - ids: Optional[List[str]] + ids: Optional[SequenceNotStr[str]] """Filter by the path ID""" limit: int diff --git a/src/gcore/types/waap/domains/api_path_update_params.py b/src/gcore/types/waap/domains/api_path_update_params.py index fcd2f8de..71c995ba 100644 --- a/src/gcore/types/waap/domains/api_path_update_params.py +++ b/src/gcore/types/waap/domains/api_path_update_params.py @@ -2,9 +2,10 @@ from __future__ import annotations -from typing import List from typing_extensions import Literal, Required, TypedDict +from ...._types import SequenceNotStr + __all__ = ["APIPathUpdateParams"] @@ -12,7 +13,7 @@ class APIPathUpdateParams(TypedDict, total=False): domain_id: Required[int] """The domain ID""" - api_groups: List[str] + api_groups: SequenceNotStr[str] """An array of api groups associated with the API path""" path: str @@ -23,7 +24,7 @@ class APIPathUpdateParams(TypedDict, total=False): """ status: Literal["CONFIRMED_API", "POTENTIAL_API", "NOT_API", "DELISTED_API"] - """The different statuses an API path can have""" + """The status of the discovered API path""" - tags: List[str] + tags: SequenceNotStr[str] """An array of tags associated with the API path""" diff --git a/src/gcore/types/waap/domains/custom_rule_create_params.py b/src/gcore/types/waap/domains/custom_rule_create_params.py index 3ad3b32d..13bd6574 100644 --- a/src/gcore/types/waap/domains/custom_rule_create_params.py +++ b/src/gcore/types/waap/domains/custom_rule_create_params.py @@ -5,6 +5,8 @@ from typing import List, Iterable, Optional from typing_extensions import Literal, Required, TypedDict +from ...._types import SequenceNotStr + __all__ = [ "CustomRuleCreateParams", "Action", @@ -34,7 +36,7 @@ class CustomRuleCreateParams(TypedDict, total=False): action: Required[Action] - """The action that a WAAP rule takes when triggered""" + """The action that the rule takes when triggered""" conditions: Required[Iterable[Condition]] """The conditions required for the WAAP engine to trigger the rule. @@ -58,7 +60,8 @@ class ActionBlock(TypedDict, total=False): """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) + 'd' to represent time format (seconds, minutes, hours, or days). Empty time + intervals are not allowed. """ status_code: Optional[Literal[403, 405, 418, 429]] @@ -66,7 +69,7 @@ class ActionBlock(TypedDict, total=False): class ActionTag(TypedDict, total=False): - tags: Required[List[str]] + tags: Required[SequenceNotStr[str]] """The list of user defined tags to tag the request with""" @@ -94,7 +97,7 @@ class Action(TypedDict, total=False): class ConditionContentType(TypedDict, total=False): - content_type: Required[List[str]] + content_type: Required[SequenceNotStr[str]] """The list of content types to match against""" negation: bool @@ -102,7 +105,7 @@ class ConditionContentType(TypedDict, total=False): class ConditionCountry(TypedDict, total=False): - country_code: Required[List[str]] + country_code: Required[SequenceNotStr[str]] """ A list of ISO 3166-1 alpha-2 formatted strings representing the countries to match against @@ -113,7 +116,7 @@ class ConditionCountry(TypedDict, total=False): class ConditionFileExtension(TypedDict, total=False): - file_extension: Required[List[str]] + file_extension: Required[SequenceNotStr[str]] """The list of file extensions to match against""" negation: bool @@ -144,11 +147,7 @@ class ConditionHeaderExists(TypedDict, total=False): class ConditionHTTPMethod(TypedDict, total=False): http_method: Required[Literal["CONNECT", "DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT", "TRACE"]] - """HTTP methods and descriptions Methods from the following RFCs are all observed: - - - RFC 7231: Hypertext Transfer Protocol (HTTP/1.1), obsoletes 2616 - - RFC 5789: PATCH Method for HTTP - """ + """HTTP methods of a request""" negation: bool """Whether or not to apply a boolean NOT operation to the rule's condition""" @@ -224,7 +223,7 @@ class ConditionRequestRate(TypedDict, total=False): ] """Possible HTTP request methods that can trigger a request rate condition""" - ips: Optional[List[str]] + ips: Optional[SequenceNotStr[str]] """A list of source IPs that can trigger a request rate condition""" user_defined_tag: Optional[str] @@ -265,7 +264,7 @@ class ConditionSessionRequestCount(TypedDict, total=False): class ConditionTags(TypedDict, total=False): - tags: Required[List[str]] + tags: Required[SequenceNotStr[str]] """A list of tags to match against the request tags""" negation: bool @@ -303,7 +302,7 @@ class ConditionUserAgent(TypedDict, total=False): class ConditionUserDefinedTags(TypedDict, total=False): - tags: Required[List[str]] + tags: Required[SequenceNotStr[str]] """A list of user-defined tags to match against the request tags""" negation: bool diff --git a/src/gcore/types/waap/domains/custom_rule_update_params.py b/src/gcore/types/waap/domains/custom_rule_update_params.py index d5de1dd1..2978bc66 100644 --- a/src/gcore/types/waap/domains/custom_rule_update_params.py +++ b/src/gcore/types/waap/domains/custom_rule_update_params.py @@ -5,6 +5,8 @@ from typing import List, Iterable, Optional from typing_extensions import Literal, Required, TypedDict +from ...._types import SequenceNotStr + __all__ = [ "CustomRuleUpdateParams", "Action", @@ -61,7 +63,8 @@ class ActionBlock(TypedDict, total=False): """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) + 'd' to represent time format (seconds, minutes, hours, or days). Empty time + intervals are not allowed. """ status_code: Optional[Literal[403, 405, 418, 429]] @@ -69,7 +72,7 @@ class ActionBlock(TypedDict, total=False): class ActionTag(TypedDict, total=False): - tags: Required[List[str]] + tags: Required[SequenceNotStr[str]] """The list of user defined tags to tag the request with""" @@ -97,7 +100,7 @@ class Action(TypedDict, total=False): class ConditionContentType(TypedDict, total=False): - content_type: Required[List[str]] + content_type: Required[SequenceNotStr[str]] """The list of content types to match against""" negation: bool @@ -105,7 +108,7 @@ class ConditionContentType(TypedDict, total=False): class ConditionCountry(TypedDict, total=False): - country_code: Required[List[str]] + country_code: Required[SequenceNotStr[str]] """ A list of ISO 3166-1 alpha-2 formatted strings representing the countries to match against @@ -116,7 +119,7 @@ class ConditionCountry(TypedDict, total=False): class ConditionFileExtension(TypedDict, total=False): - file_extension: Required[List[str]] + file_extension: Required[SequenceNotStr[str]] """The list of file extensions to match against""" negation: bool @@ -147,11 +150,7 @@ class ConditionHeaderExists(TypedDict, total=False): class ConditionHTTPMethod(TypedDict, total=False): http_method: Required[Literal["CONNECT", "DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT", "TRACE"]] - """HTTP methods and descriptions Methods from the following RFCs are all observed: - - - RFC 7231: Hypertext Transfer Protocol (HTTP/1.1), obsoletes 2616 - - RFC 5789: PATCH Method for HTTP - """ + """HTTP methods of a request""" negation: bool """Whether or not to apply a boolean NOT operation to the rule's condition""" @@ -227,7 +226,7 @@ class ConditionRequestRate(TypedDict, total=False): ] """Possible HTTP request methods that can trigger a request rate condition""" - ips: Optional[List[str]] + ips: Optional[SequenceNotStr[str]] """A list of source IPs that can trigger a request rate condition""" user_defined_tag: Optional[str] @@ -268,7 +267,7 @@ class ConditionSessionRequestCount(TypedDict, total=False): class ConditionTags(TypedDict, total=False): - tags: Required[List[str]] + tags: Required[SequenceNotStr[str]] """A list of tags to match against the request tags""" negation: bool @@ -306,7 +305,7 @@ class ConditionUserAgent(TypedDict, total=False): class ConditionUserDefinedTags(TypedDict, total=False): - tags: Required[List[str]] + tags: Required[SequenceNotStr[str]] """A list of user-defined tags to match against the request tags""" negation: bool diff --git a/src/gcore/types/waap/domains/firewall_rule_create_params.py b/src/gcore/types/waap/domains/firewall_rule_create_params.py index c56a608d..84b671fb 100644 --- a/src/gcore/types/waap/domains/firewall_rule_create_params.py +++ b/src/gcore/types/waap/domains/firewall_rule_create_params.py @@ -10,7 +10,7 @@ class FirewallRuleCreateParams(TypedDict, total=False): action: Required[Action] - """The action that a firewall rule takes when triggered""" + """The action that the rule takes when triggered""" conditions: Required[Iterable[Condition]] """The condition required for the WAAP engine to trigger the rule.""" @@ -30,7 +30,8 @@ class ActionBlock(TypedDict, total=False): """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) + 'd' to represent time format (seconds, minutes, hours, or days). Empty time + intervals are not allowed. """ status_code: Optional[Literal[403, 405, 418, 429]] diff --git a/src/gcore/types/waap/domains/firewall_rule_update_params.py b/src/gcore/types/waap/domains/firewall_rule_update_params.py index ca5eb4fa..478d257c 100644 --- a/src/gcore/types/waap/domains/firewall_rule_update_params.py +++ b/src/gcore/types/waap/domains/firewall_rule_update_params.py @@ -33,7 +33,8 @@ class ActionBlock(TypedDict, total=False): """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) + 'd' to represent time format (seconds, minutes, hours, or days). Empty time + intervals are not allowed. """ status_code: Optional[Literal[403, 405, 418, 429]] diff --git a/src/gcore/types/waap/domains/insight_list_params.py b/src/gcore/types/waap/domains/insight_list_params.py index d0f6c156..7163f181 100644 --- a/src/gcore/types/waap/domains/insight_list_params.py +++ b/src/gcore/types/waap/domains/insight_list_params.py @@ -5,17 +5,19 @@ from typing import List, Optional from typing_extensions import Literal, TypedDict +from ...._types import SequenceNotStr + __all__ = ["InsightListParams"] class InsightListParams(TypedDict, total=False): - id: Optional[List[str]] + id: Optional[SequenceNotStr[str]] """The ID of the insight""" description: Optional[str] """The description of the insight. Supports '\\**' as a wildcard.""" - insight_type: Optional[List[str]] + insight_type: Optional[SequenceNotStr[str]] """The type of the insight""" limit: int diff --git a/src/gcore/types/waap/domains/insight_replace_params.py b/src/gcore/types/waap/domains/insight_replace_params.py index 18ded249..46dc81b4 100644 --- a/src/gcore/types/waap/domains/insight_replace_params.py +++ b/src/gcore/types/waap/domains/insight_replace_params.py @@ -12,4 +12,4 @@ class InsightReplaceParams(TypedDict, total=False): """The domain ID""" status: Required[Literal["OPEN", "ACKED", "CLOSED"]] - """The different statuses an insight can have""" + """The status of the insight""" diff --git a/src/gcore/types/waap/domains/insight_silence_list_params.py b/src/gcore/types/waap/domains/insight_silence_list_params.py index b36d9315..affcad4d 100644 --- a/src/gcore/types/waap/domains/insight_silence_list_params.py +++ b/src/gcore/types/waap/domains/insight_silence_list_params.py @@ -2,14 +2,16 @@ from __future__ import annotations -from typing import List, Optional +from typing import Optional from typing_extensions import Literal, TypedDict +from ...._types import SequenceNotStr + __all__ = ["InsightSilenceListParams"] class InsightSilenceListParams(TypedDict, total=False): - id: Optional[List[str]] + id: Optional[SequenceNotStr[str]] """The ID of the insight silence""" author: Optional[str] @@ -18,7 +20,7 @@ class InsightSilenceListParams(TypedDict, total=False): comment: Optional[str] """The comment of the insight silence""" - insight_type: Optional[List[str]] + insight_type: Optional[SequenceNotStr[str]] """The type of the insight silence""" limit: int diff --git a/src/gcore/types/waap/domains/setting_update_params.py b/src/gcore/types/waap/domains/setting_update_params.py index 2336f7e1..2b3ea5de 100644 --- a/src/gcore/types/waap/domains/setting_update_params.py +++ b/src/gcore/types/waap/domains/setting_update_params.py @@ -2,9 +2,10 @@ from __future__ import annotations -from typing import List from typing_extensions import TypedDict +from ...._types import SequenceNotStr + __all__ = ["SettingUpdateParams", "API", "DDOS"] @@ -17,7 +18,7 @@ class SettingUpdateParams(TypedDict, total=False): class API(TypedDict, total=False): - api_urls: List[str] + 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 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 index 399c4044..3b8406b8 100644 --- a/src/gcore/types/waap/domains/statistic_get_ddos_info_params.py +++ b/src/gcore/types/waap/domains/statistic_get_ddos_info_params.py @@ -2,11 +2,8 @@ from __future__ import annotations -from typing import Union -from datetime import datetime -from typing_extensions import Literal, Required, Annotated, TypedDict - -from ...._utils import PropertyInfo +from typing import Optional +from typing_extensions import Literal, Required, TypedDict __all__ = ["StatisticGetDDOSInfoParams"] @@ -15,11 +12,11 @@ class StatisticGetDDOSInfoParams(TypedDict, total=False): group_by: Required[Literal["URL", "User-Agent", "IP"]] """The identity of the requests to group by""" - start: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """Filter traffic starting from a specified date in ISO 8601 format""" + start: Required[str] + """Filter data items starting from a specified date in ISO 8601 format""" - end: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """Filter traffic up to a specified end 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_events_aggregated_params.py b/src/gcore/types/waap/domains/statistic_get_events_aggregated_params.py index cdf4b82d..ff19e38c 100644 --- a/src/gcore/types/waap/domains/statistic_get_events_aggregated_params.py +++ b/src/gcore/types/waap/domains/statistic_get_events_aggregated_params.py @@ -2,32 +2,31 @@ from __future__ import annotations -from typing import List, Union, Optional -from datetime import datetime -from typing_extensions import Literal, Required, Annotated, TypedDict +from typing import List, Optional +from typing_extensions import Literal, Required, TypedDict -from ...._utils import PropertyInfo +from ...._types import SequenceNotStr __all__ = ["StatisticGetEventsAggregatedParams"] class StatisticGetEventsAggregatedParams(TypedDict, total=False): - start: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """Filter traffic starting from a specified date in ISO 8601 format""" + start: Required[str] + """Filter data items starting from a specified date in ISO 8601 format""" action: Optional[List[Literal["block", "captcha", "handshake", "monitor"]]] """A list of action names to filter on.""" - end: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """Filter traffic up to a specified end 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. """ - ip: Optional[List[str]] + ip: Optional[SequenceNotStr[str]] """A list of IPs to filter event statistics.""" - reference_id: Optional[List[str]] + reference_id: Optional[SequenceNotStr[str]] """A list of reference IDs to filter event statistics.""" result: Optional[List[Literal["passed", "blocked", "monitored", "allowed"]]] 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 index 6007c368..ef36b532 100644 --- a/src/gcore/types/waap/domains/statistic_get_requests_series_params.py +++ b/src/gcore/types/waap/domains/statistic_get_requests_series_params.py @@ -2,27 +2,26 @@ from __future__ import annotations -from typing import List, Union -from datetime import datetime -from typing_extensions import Literal, Required, Annotated, TypedDict +from typing import List, Optional +from typing_extensions import Literal, Required, TypedDict -from ...._utils import PropertyInfo +from ...._types import SequenceNotStr __all__ = ["StatisticGetRequestsSeriesParams"] class StatisticGetRequestsSeriesParams(TypedDict, total=False): - start: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """Filter traffic starting from a specified date in ISO 8601 format""" + 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: List[str] + countries: SequenceNotStr[str] """Filter the response by country codes in ISO 3166-1 alpha-2 format.""" - end: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """Filter traffic up to a specified end 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_params.py b/src/gcore/types/waap/domains/statistic_get_traffic_series_params.py index 11bb32df..18b815fb 100644 --- a/src/gcore/types/waap/domains/statistic_get_traffic_series_params.py +++ b/src/gcore/types/waap/domains/statistic_get_traffic_series_params.py @@ -2,11 +2,8 @@ from __future__ import annotations -from typing import Union -from datetime import datetime -from typing_extensions import Literal, Required, Annotated, TypedDict - -from ...._utils import PropertyInfo +from typing import Optional +from typing_extensions import Literal, Required, TypedDict __all__ = ["StatisticGetTrafficSeriesParams"] @@ -15,11 +12,11 @@ class StatisticGetTrafficSeriesParams(TypedDict, total=False): resolution: Required[Literal["daily", "hourly", "minutely"]] """Specifies the granularity of the result data.""" - start: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """Filter traffic starting from a specified date in ISO 8601 format""" + start: Required[str] + """Filter data items starting from a specified date in ISO 8601 format""" - end: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """Filter traffic up to a specified end 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/waap_advanced_rule.py b/src/gcore/types/waap/domains/waap_advanced_rule.py index 5b6d5d07..fc264a1a 100644 --- a/src/gcore/types/waap/domains/waap_advanced_rule.py +++ b/src/gcore/types/waap/domains/waap_advanced_rule.py @@ -13,7 +13,8 @@ class ActionBlock(BaseModel): """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) + '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 @@ -53,7 +54,7 @@ class WaapAdvancedRule(BaseModel): """The unique identifier for the rule""" action: Action - """The action that a WAAP rule takes when triggered""" + """The action that the rule takes when triggered""" enabled: bool """Whether or not the rule is enabled""" diff --git a/src/gcore/types/waap/domains/waap_api_path.py b/src/gcore/types/waap/domains/waap_api_path.py index 5b4622d1..23abac76 100644 --- a/src/gcore/types/waap/domains/waap_api_path.py +++ b/src/gcore/types/waap/domains/waap_api_path.py @@ -23,13 +23,13 @@ class WaapAPIPath(BaseModel): """The date and time in ISO 8601 format the API path was first detected.""" http_scheme: Literal["HTTP", "HTTPS"] - """The different HTTP schemes an API path can have""" + """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 different methods an API path can have""" + """The API RESTful method""" path: str """ @@ -41,10 +41,10 @@ class WaapAPIPath(BaseModel): """The number of requests for this path in the last 24 hours""" source: Literal["API_DESCRIPTION_FILE", "TRAFFIC_SCAN", "USER_DEFINED"] - """The different sources an API path can have""" + """The source of the discovered API""" status: Literal["CONFIRMED_API", "POTENTIAL_API", "NOT_API", "DELISTED_API"] - """The different statuses an API path can have""" + """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 index 408230c8..9e8b7efc 100644 --- a/src/gcore/types/waap/domains/waap_api_scan_result.py +++ b/src/gcore/types/waap/domains/waap_api_scan_result.py @@ -23,7 +23,7 @@ class WaapAPIScanResult(BaseModel): """The date and time the scan started""" status: Literal["SUCCESS", "FAILURE", "IN_PROGRESS"] - """The different statuses a task result can have""" + """The status of the scan""" type: Literal["TRAFFIC_SCAN", "API_DESCRIPTION_FILE_SCAN"] - """The different types of scans that can be performed""" + """The type of scan""" diff --git a/src/gcore/types/waap/domains/waap_custom_rule.py b/src/gcore/types/waap/domains/waap_custom_rule.py index 3ee80d02..aec81343 100644 --- a/src/gcore/types/waap/domains/waap_custom_rule.py +++ b/src/gcore/types/waap/domains/waap_custom_rule.py @@ -37,7 +37,8 @@ class ActionBlock(BaseModel): """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) + '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 @@ -123,11 +124,7 @@ class ConditionHeaderExists(BaseModel): class ConditionHTTPMethod(BaseModel): http_method: Literal["CONNECT", "DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT", "TRACE"] - """HTTP methods and descriptions Methods from the following RFCs are all observed: - - - RFC 7231: Hypertext Transfer Protocol (HTTP/1.1), obsoletes 2616 - - RFC 5789: PATCH Method for HTTP - """ + """HTTP methods of a request""" negation: Optional[bool] = None """Whether or not to apply a boolean NOT operation to the rule's condition""" @@ -358,7 +355,7 @@ class WaapCustomRule(BaseModel): """The unique identifier for the rule""" action: Action - """The action that a WAAP rule takes when triggered""" + """The action that the rule takes when triggered""" conditions: List[Condition] """The conditions required for the WAAP engine to trigger the rule. diff --git a/src/gcore/types/waap/domains/waap_firewall_rule.py b/src/gcore/types/waap/domains/waap_firewall_rule.py index 88deda6e..d9ffa8dc 100644 --- a/src/gcore/types/waap/domains/waap_firewall_rule.py +++ b/src/gcore/types/waap/domains/waap_firewall_rule.py @@ -13,7 +13,8 @@ class ActionBlock(BaseModel): """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) + '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 @@ -63,7 +64,7 @@ class WaapFirewallRule(BaseModel): """The unique identifier of the rule""" action: Action - """The action that a firewall rule takes when triggered""" + """The action that the rule takes when triggered""" conditions: List[Condition] """The condition required for the WAAP engine to trigger the rule.""" diff --git a/src/gcore/types/waap/domains/waap_insight.py b/src/gcore/types/waap/domains/waap_insight.py index 9beca2a1..f5ca2825 100644 --- a/src/gcore/types/waap/domains/waap_insight.py +++ b/src/gcore/types/waap/domains/waap_insight.py @@ -35,4 +35,4 @@ class WaapInsight(BaseModel): """The recommended action to perform to resolve the insight""" status: Literal["OPEN", "ACKED", "CLOSED"] - """The different statuses an insight can have""" + """The status of the insight""" diff --git a/src/gcore/types/waap/domains/waap_request_details.py b/src/gcore/types/waap/domains/waap_request_details.py index 29b4b30c..e3a1d9cd 100644 --- a/src/gcore/types/waap/domains/waap_request_details.py +++ b/src/gcore/types/waap/domains/waap_request_details.py @@ -1,6 +1,7 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List +from typing import Dict, List +from datetime import datetime from typing_extensions import Literal from ...._models import BaseModel @@ -148,10 +149,10 @@ class WaapRequestDetails(BaseModel): reference_id: str """Reference ID to identify user sanction""" - request_headers: object + request_headers: Dict[str, object] """HTTP request headers""" - request_time: str + request_time: datetime """The time of the request""" request_type: str @@ -182,4 +183,4 @@ class WaapRequestDetails(BaseModel): """List of traffic types""" user_agent: UserAgent - """User agent details""" + """User agent""" diff --git a/src/gcore/types/waap/waap_ip_ddos_info_model.py b/src/gcore/types/waap/waap_ip_ddos_info_model.py index 03be1722..14450304 100644 --- a/src/gcore/types/waap/waap_ip_ddos_info_model.py +++ b/src/gcore/types/waap/waap_ip_ddos_info_model.py @@ -4,10 +4,10 @@ from ..._models import BaseModel -__all__ = ["WaapIPDDOSInfoModel", "TimeSery"] +__all__ = ["WaapIPDDOSInfoModel", "TimeSeries"] -class TimeSery(BaseModel): +class TimeSeries(BaseModel): count: int """The number of attacks""" @@ -19,5 +19,5 @@ class WaapIPDDOSInfoModel(BaseModel): botnet_client: bool """Indicates if the IP is tagged as a botnet client""" - time_series: List[TimeSery] + time_series: List[TimeSeries] """The time series data for the DDoS attacks from the IP address""" diff --git a/src/gcore/types/waap/waap_rule_set.py b/src/gcore/types/waap/waap_rule_set.py index 25de7087..e5e33e10 100644 --- a/src/gcore/types/waap/waap_rule_set.py +++ b/src/gcore/types/waap/waap_rule_set.py @@ -24,7 +24,7 @@ class Rule(BaseModel): """Unique identifier for the security rule""" action: Literal["Allow", "Block", "Captcha", "Gateway", "Handshake", "Monitor", "Composite"] - """The action taken by the WAAP upon rule activation.""" + """Specifies the action taken by the WAAP upon rule activation""" description: str """Detailed description of the security rule""" diff --git a/tests/api_resources/cloud/baremetal/test_servers.py b/tests/api_resources/cloud/baremetal/test_servers.py index db10a5ea..355896d0 100644 --- a/tests/api_resources/cloud/baremetal/test_servers.py +++ b/tests/api_resources/cloud/baremetal/test_servers.py @@ -164,18 +164,18 @@ def test_streaming_response_list(self, client: Gcore) -> None: @parametrize def test_method_rebuild(self, client: Gcore) -> None: server = client.cloud.baremetal.servers.rebuild( - server_id="server_id", - project_id=0, - region_id=0, + 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="server_id", - project_id=0, - region_id=0, + server_id="024a29e-b4b7-4c91-9a46-505be123d9f8", + project_id=1, + region_id=1, image_id="b5b4d65d-945f-4b98-ab6f-332319c724ef", user_data="aGVsbG9fd29ybGQ=", ) @@ -184,9 +184,9 @@ def test_method_rebuild_with_all_params(self, client: Gcore) -> None: @parametrize def test_raw_response_rebuild(self, client: Gcore) -> None: response = client.cloud.baremetal.servers.with_raw_response.rebuild( - server_id="server_id", - project_id=0, - region_id=0, + server_id="024a29e-b4b7-4c91-9a46-505be123d9f8", + project_id=1, + region_id=1, ) assert response.is_closed is True @@ -197,9 +197,9 @@ def test_raw_response_rebuild(self, client: Gcore) -> None: @parametrize def test_streaming_response_rebuild(self, client: Gcore) -> None: with client.cloud.baremetal.servers.with_streaming_response.rebuild( - server_id="server_id", - project_id=0, - region_id=0, + 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" @@ -214,8 +214,8 @@ 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=0, - region_id=0, + project_id=1, + region_id=1, ) @@ -368,18 +368,18 @@ async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: @parametrize async def test_method_rebuild(self, async_client: AsyncGcore) -> None: server = await async_client.cloud.baremetal.servers.rebuild( - server_id="server_id", - project_id=0, - region_id=0, + 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="server_id", - project_id=0, - region_id=0, + server_id="024a29e-b4b7-4c91-9a46-505be123d9f8", + project_id=1, + region_id=1, image_id="b5b4d65d-945f-4b98-ab6f-332319c724ef", user_data="aGVsbG9fd29ybGQ=", ) @@ -388,9 +388,9 @@ async def test_method_rebuild_with_all_params(self, async_client: AsyncGcore) -> @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="server_id", - project_id=0, - region_id=0, + server_id="024a29e-b4b7-4c91-9a46-505be123d9f8", + project_id=1, + region_id=1, ) assert response.is_closed is True @@ -401,9 +401,9 @@ async def test_raw_response_rebuild(self, async_client: AsyncGcore) -> None: @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="server_id", - project_id=0, - region_id=0, + 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" @@ -418,6 +418,6 @@ 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=0, - region_id=0, + project_id=1, + region_id=1, ) diff --git a/tests/api_resources/cloud/gpu_baremetal_clusters/test_flavors.py b/tests/api_resources/cloud/gpu_baremetal_clusters/test_flavors.py index 6b7e5324..9cb9018c 100644 --- a/tests/api_resources/cloud/gpu_baremetal_clusters/test_flavors.py +++ b/tests/api_resources/cloud/gpu_baremetal_clusters/test_flavors.py @@ -9,7 +9,7 @@ from gcore import Gcore, AsyncGcore from tests.utils import assert_matches_type -from gcore.types.cloud import GPUBaremetalFlavorList +from gcore.types.cloud.gpu_baremetal_clusters import GPUBaremetalFlavorList base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") diff --git a/tests/api_resources/cloud/gpu_baremetal_clusters/test_servers.py b/tests/api_resources/cloud/gpu_baremetal_clusters/test_servers.py index 993a16f9..204a8ffb 100644 --- a/tests/api_resources/cloud/gpu_baremetal_clusters/test_servers.py +++ b/tests/api_resources/cloud/gpu_baremetal_clusters/test_servers.py @@ -9,7 +9,13 @@ from gcore import Gcore, AsyncGcore from tests.utils import assert_matches_type -from gcore.types.cloud import Console, TaskIDList, GPUBaremetalClusterServer +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") @@ -17,6 +23,70 @@ 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( @@ -506,7 +576,7 @@ def test_method_powercycle(self, client: Gcore) -> None: project_id=0, region_id=0, ) - assert_matches_type(GPUBaremetalClusterServer, server, path=["response"]) + assert_matches_type(GPUBaremetalClusterServerV1, server, path=["response"]) @parametrize def test_raw_response_powercycle(self, client: Gcore) -> None: @@ -519,7 +589,7 @@ def test_raw_response_powercycle(self, client: Gcore) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" server = response.parse() - assert_matches_type(GPUBaremetalClusterServer, server, path=["response"]) + assert_matches_type(GPUBaremetalClusterServerV1, server, path=["response"]) @parametrize def test_streaming_response_powercycle(self, client: Gcore) -> None: @@ -532,7 +602,7 @@ def test_streaming_response_powercycle(self, client: Gcore) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" server = response.parse() - assert_matches_type(GPUBaremetalClusterServer, server, path=["response"]) + assert_matches_type(GPUBaremetalClusterServerV1, server, path=["response"]) assert cast(Any, response.is_closed) is True @@ -552,7 +622,7 @@ def test_method_reboot(self, client: Gcore) -> None: project_id=0, region_id=0, ) - assert_matches_type(GPUBaremetalClusterServer, server, path=["response"]) + assert_matches_type(GPUBaremetalClusterServerV1, server, path=["response"]) @parametrize def test_raw_response_reboot(self, client: Gcore) -> None: @@ -565,7 +635,7 @@ def test_raw_response_reboot(self, client: Gcore) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" server = response.parse() - assert_matches_type(GPUBaremetalClusterServer, server, path=["response"]) + assert_matches_type(GPUBaremetalClusterServerV1, server, path=["response"]) @parametrize def test_streaming_response_reboot(self, client: Gcore) -> None: @@ -578,7 +648,7 @@ def test_streaming_response_reboot(self, client: Gcore) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" server = response.parse() - assert_matches_type(GPUBaremetalClusterServer, server, path=["response"]) + assert_matches_type(GPUBaremetalClusterServerV1, server, path=["response"]) assert cast(Any, response.is_closed) is True @@ -597,6 +667,70 @@ class TestAsyncServers: "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( @@ -1086,7 +1220,7 @@ async def test_method_powercycle(self, async_client: AsyncGcore) -> None: project_id=0, region_id=0, ) - assert_matches_type(GPUBaremetalClusterServer, server, path=["response"]) + assert_matches_type(GPUBaremetalClusterServerV1, server, path=["response"]) @parametrize async def test_raw_response_powercycle(self, async_client: AsyncGcore) -> None: @@ -1099,7 +1233,7 @@ async def test_raw_response_powercycle(self, async_client: AsyncGcore) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" server = await response.parse() - assert_matches_type(GPUBaremetalClusterServer, server, path=["response"]) + assert_matches_type(GPUBaremetalClusterServerV1, server, path=["response"]) @parametrize async def test_streaming_response_powercycle(self, async_client: AsyncGcore) -> None: @@ -1112,7 +1246,7 @@ async def test_streaming_response_powercycle(self, async_client: AsyncGcore) -> assert response.http_request.headers.get("X-Stainless-Lang") == "python" server = await response.parse() - assert_matches_type(GPUBaremetalClusterServer, server, path=["response"]) + assert_matches_type(GPUBaremetalClusterServerV1, server, path=["response"]) assert cast(Any, response.is_closed) is True @@ -1132,7 +1266,7 @@ async def test_method_reboot(self, async_client: AsyncGcore) -> None: project_id=0, region_id=0, ) - assert_matches_type(GPUBaremetalClusterServer, server, path=["response"]) + assert_matches_type(GPUBaremetalClusterServerV1, server, path=["response"]) @parametrize async def test_raw_response_reboot(self, async_client: AsyncGcore) -> None: @@ -1145,7 +1279,7 @@ async def test_raw_response_reboot(self, async_client: AsyncGcore) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" server = await response.parse() - assert_matches_type(GPUBaremetalClusterServer, server, path=["response"]) + assert_matches_type(GPUBaremetalClusterServerV1, server, path=["response"]) @parametrize async def test_streaming_response_reboot(self, async_client: AsyncGcore) -> None: @@ -1158,7 +1292,7 @@ async def test_streaming_response_reboot(self, async_client: AsyncGcore) -> None assert response.http_request.headers.get("X-Stainless-Lang") == "python" server = await response.parse() - assert_matches_type(GPUBaremetalClusterServer, server, path=["response"]) + assert_matches_type(GPUBaremetalClusterServerV1, server, path=["response"]) assert cast(Any, response.is_closed) is True 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..850cc9e8 --- /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_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, + ) + + @parametrize + def test_method_patch(self, client: Gcore) -> None: + deployment = client.cloud.inference.applications.deployments.patch( + deployment_name="deployment_name", + project_id=1, + ) + assert_matches_type(TaskIDList, deployment, path=["response"]) + + @parametrize + def test_method_patch_with_all_params(self, client: Gcore) -> None: + deployment = client.cloud.inference.applications.deployments.patch( + 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_patch(self, client: Gcore) -> None: + response = client.cloud.inference.applications.deployments.with_raw_response.patch( + 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_patch(self, client: Gcore) -> None: + with client.cloud.inference.applications.deployments.with_streaming_response.patch( + 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_patch(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.patch( + 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_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, + ) + + @parametrize + async def test_method_patch(self, async_client: AsyncGcore) -> None: + deployment = await async_client.cloud.inference.applications.deployments.patch( + deployment_name="deployment_name", + project_id=1, + ) + assert_matches_type(TaskIDList, deployment, path=["response"]) + + @parametrize + async def test_method_patch_with_all_params(self, async_client: AsyncGcore) -> None: + deployment = await async_client.cloud.inference.applications.deployments.patch( + 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_patch(self, async_client: AsyncGcore) -> None: + response = await async_client.cloud.inference.applications.deployments.with_raw_response.patch( + 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_patch(self, async_client: AsyncGcore) -> None: + async with async_client.cloud.inference.applications.deployments.with_streaming_response.patch( + 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_patch(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.patch( + 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/test_deployments.py b/tests/api_resources/cloud/inference/test_deployments.py index 7090d25d..6b9b0802 100644 --- a/tests/api_resources/cloud/inference/test_deployments.py +++ b/tests/api_resources/cloud/inference/test_deployments.py @@ -16,6 +16,8 @@ InferenceDeploymentAPIKey, ) +# pyright: reportDeprecated=false + base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -496,18 +498,21 @@ def test_path_params_get(self, client: Gcore) -> None: @parametrize def test_method_get_api_key(self, client: Gcore) -> None: - deployment = client.cloud.inference.deployments.get_api_key( - deployment_name="my-instance", - project_id=1, - ) + 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: - response = client.cloud.inference.deployments.with_raw_response.get_api_key( - deployment_name="my-instance", - project_id=1, - ) + 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" @@ -516,25 +521,27 @@ def test_raw_response_get_api_key(self, client: Gcore) -> None: @parametrize def test_streaming_response_get_api_key(self, client: Gcore) -> None: - 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" + 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"]) + 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.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, - ) + 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: @@ -1100,18 +1107,21 @@ async def test_path_params_get(self, async_client: AsyncGcore) -> None: @parametrize async def test_method_get_api_key(self, async_client: AsyncGcore) -> None: - deployment = await async_client.cloud.inference.deployments.get_api_key( - deployment_name="my-instance", - project_id=1, - ) + 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: - response = await async_client.cloud.inference.deployments.with_raw_response.get_api_key( - deployment_name="my-instance", - project_id=1, - ) + 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" @@ -1120,25 +1130,27 @@ async def test_raw_response_get_api_key(self, async_client: AsyncGcore) -> None: @parametrize async def test_streaming_response_get_api_key(self, async_client: AsyncGcore) -> None: - 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" + 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"]) + 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.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, - ) + 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: diff --git a/tests/api_resources/cloud/inference/test_models.py b/tests/api_resources/cloud/inference/test_models.py deleted file mode 100644 index cde90416..00000000 --- a/tests/api_resources/cloud/inference/test_models.py +++ /dev/null @@ -1,169 +0,0 @@ -# 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 InferenceModel - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestModels: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - def test_method_list(self, client: Gcore) -> None: - model = client.cloud.inference.models.list() - assert_matches_type(SyncOffsetPage[InferenceModel], model, path=["response"]) - - @parametrize - def test_method_list_with_all_params(self, client: Gcore) -> None: - model = client.cloud.inference.models.list( - limit=1000, - offset=0, - order_by="name.desc", - ) - assert_matches_type(SyncOffsetPage[InferenceModel], model, path=["response"]) - - @parametrize - def test_raw_response_list(self, client: Gcore) -> None: - response = client.cloud.inference.models.with_raw_response.list() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - model = response.parse() - assert_matches_type(SyncOffsetPage[InferenceModel], model, path=["response"]) - - @parametrize - def test_streaming_response_list(self, client: Gcore) -> None: - with client.cloud.inference.models.with_streaming_response.list() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - model = response.parse() - assert_matches_type(SyncOffsetPage[InferenceModel], model, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_get(self, client: Gcore) -> None: - model = client.cloud.inference.models.get( - "model_id", - ) - assert_matches_type(InferenceModel, model, path=["response"]) - - @parametrize - def test_raw_response_get(self, client: Gcore) -> None: - response = client.cloud.inference.models.with_raw_response.get( - "model_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - model = response.parse() - assert_matches_type(InferenceModel, model, path=["response"]) - - @parametrize - def test_streaming_response_get(self, client: Gcore) -> None: - with client.cloud.inference.models.with_streaming_response.get( - "model_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - model = response.parse() - assert_matches_type(InferenceModel, model, 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 `model_id` but received ''"): - client.cloud.inference.models.with_raw_response.get( - "", - ) - - -class TestAsyncModels: - 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: - model = await async_client.cloud.inference.models.list() - assert_matches_type(AsyncOffsetPage[InferenceModel], model, path=["response"]) - - @parametrize - async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: - model = await async_client.cloud.inference.models.list( - limit=1000, - offset=0, - order_by="name.desc", - ) - assert_matches_type(AsyncOffsetPage[InferenceModel], model, path=["response"]) - - @parametrize - async def test_raw_response_list(self, async_client: AsyncGcore) -> None: - response = await async_client.cloud.inference.models.with_raw_response.list() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - model = await response.parse() - assert_matches_type(AsyncOffsetPage[InferenceModel], model, path=["response"]) - - @parametrize - async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: - async with async_client.cloud.inference.models.with_streaming_response.list() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - model = await response.parse() - assert_matches_type(AsyncOffsetPage[InferenceModel], model, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_get(self, async_client: AsyncGcore) -> None: - model = await async_client.cloud.inference.models.get( - "model_id", - ) - assert_matches_type(InferenceModel, model, path=["response"]) - - @parametrize - async def test_raw_response_get(self, async_client: AsyncGcore) -> None: - response = await async_client.cloud.inference.models.with_raw_response.get( - "model_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - model = await response.parse() - assert_matches_type(InferenceModel, model, path=["response"]) - - @parametrize - async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: - async with async_client.cloud.inference.models.with_streaming_response.get( - "model_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - model = await response.parse() - assert_matches_type(InferenceModel, model, 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 `model_id` but received ''"): - await async_client.cloud.inference.models.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 index 3ebaa989..2726feb8 100644 --- a/tests/api_resources/cloud/inference/test_registry_credentials.py +++ b/tests/api_resources/cloud/inference/test_registry_credentials.py @@ -12,7 +12,6 @@ from gcore.pagination import SyncOffsetPage, AsyncOffsetPage from gcore.types.cloud.inference import ( InferenceRegistryCredentials, - InferenceRegistryCredentialsCreate, ) base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -30,7 +29,7 @@ def test_method_create(self, client: Gcore) -> None: registry_url="registry.example.com", username="username", ) - assert_matches_type(InferenceRegistryCredentialsCreate, registry_credential, path=["response"]) + assert_matches_type(InferenceRegistryCredentials, registry_credential, path=["response"]) @parametrize def test_raw_response_create(self, client: Gcore) -> None: @@ -45,7 +44,7 @@ def test_raw_response_create(self, client: Gcore) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" registry_credential = response.parse() - assert_matches_type(InferenceRegistryCredentialsCreate, registry_credential, path=["response"]) + assert_matches_type(InferenceRegistryCredentials, registry_credential, path=["response"]) @parametrize def test_streaming_response_create(self, client: Gcore) -> None: @@ -60,7 +59,7 @@ def test_streaming_response_create(self, client: Gcore) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" registry_credential = response.parse() - assert_matches_type(InferenceRegistryCredentialsCreate, registry_credential, path=["response"]) + assert_matches_type(InferenceRegistryCredentials, registry_credential, path=["response"]) assert cast(Any, response.is_closed) is True @@ -197,7 +196,7 @@ def test_method_replace(self, client: Gcore) -> None: registry_url="registry.example.com", username="username", ) - assert_matches_type(InferenceRegistryCredentialsCreate, registry_credential, path=["response"]) + assert_matches_type(InferenceRegistryCredentials, registry_credential, path=["response"]) @parametrize def test_raw_response_replace(self, client: Gcore) -> None: @@ -212,7 +211,7 @@ def test_raw_response_replace(self, client: Gcore) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" registry_credential = response.parse() - assert_matches_type(InferenceRegistryCredentialsCreate, registry_credential, path=["response"]) + assert_matches_type(InferenceRegistryCredentials, registry_credential, path=["response"]) @parametrize def test_streaming_response_replace(self, client: Gcore) -> None: @@ -227,7 +226,7 @@ def test_streaming_response_replace(self, client: Gcore) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" registry_credential = response.parse() - assert_matches_type(InferenceRegistryCredentialsCreate, registry_credential, path=["response"]) + assert_matches_type(InferenceRegistryCredentials, registry_credential, path=["response"]) assert cast(Any, response.is_closed) is True @@ -257,7 +256,7 @@ async def test_method_create(self, async_client: AsyncGcore) -> None: registry_url="registry.example.com", username="username", ) - assert_matches_type(InferenceRegistryCredentialsCreate, registry_credential, path=["response"]) + assert_matches_type(InferenceRegistryCredentials, registry_credential, path=["response"]) @parametrize async def test_raw_response_create(self, async_client: AsyncGcore) -> None: @@ -272,7 +271,7 @@ async def test_raw_response_create(self, async_client: AsyncGcore) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" registry_credential = await response.parse() - assert_matches_type(InferenceRegistryCredentialsCreate, registry_credential, path=["response"]) + assert_matches_type(InferenceRegistryCredentials, registry_credential, path=["response"]) @parametrize async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: @@ -287,7 +286,7 @@ async def test_streaming_response_create(self, async_client: AsyncGcore) -> None assert response.http_request.headers.get("X-Stainless-Lang") == "python" registry_credential = await response.parse() - assert_matches_type(InferenceRegistryCredentialsCreate, registry_credential, path=["response"]) + assert_matches_type(InferenceRegistryCredentials, registry_credential, path=["response"]) assert cast(Any, response.is_closed) is True @@ -424,7 +423,7 @@ async def test_method_replace(self, async_client: AsyncGcore) -> None: registry_url="registry.example.com", username="username", ) - assert_matches_type(InferenceRegistryCredentialsCreate, registry_credential, path=["response"]) + assert_matches_type(InferenceRegistryCredentials, registry_credential, path=["response"]) @parametrize async def test_raw_response_replace(self, async_client: AsyncGcore) -> None: @@ -439,7 +438,7 @@ async def test_raw_response_replace(self, async_client: AsyncGcore) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" registry_credential = await response.parse() - assert_matches_type(InferenceRegistryCredentialsCreate, registry_credential, path=["response"]) + assert_matches_type(InferenceRegistryCredentials, registry_credential, path=["response"]) @parametrize async def test_streaming_response_replace(self, async_client: AsyncGcore) -> None: @@ -454,7 +453,7 @@ async def test_streaming_response_replace(self, async_client: AsyncGcore) -> Non assert response.http_request.headers.get("X-Stainless-Lang") == "python" registry_credential = await response.parse() - assert_matches_type(InferenceRegistryCredentialsCreate, registry_credential, path=["response"]) + assert_matches_type(InferenceRegistryCredentials, registry_credential, path=["response"]) assert cast(Any, response.is_closed) is True 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..1f283cc8 --- /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="pool_name", + project_id=0, + region_id=0, + cluster_name="cluster_name", + ) + 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="pool_name", + project_id=0, + region_id=0, + cluster_name="cluster_name", + with_ddos=True, + ) + 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="pool_name", + 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" + 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="pool_name", + 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" + + 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="pool_name", + project_id=0, + region_id=0, + 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=0, + region_id=0, + cluster_name="cluster_name", + ) + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + node = client.cloud.k8s.clusters.pools.nodes.delete( + instance_id="instance_id", + project_id=0, + region_id=0, + cluster_name="cluster_name", + pool_name="pool_name", + ) + 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="instance_id", + project_id=0, + region_id=0, + cluster_name="cluster_name", + pool_name="pool_name", + ) + + 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="instance_id", + project_id=0, + region_id=0, + cluster_name="cluster_name", + pool_name="pool_name", + ) 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="instance_id", + project_id=0, + region_id=0, + cluster_name="", + pool_name="pool_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.delete( + instance_id="instance_id", + project_id=0, + region_id=0, + cluster_name="cluster_name", + 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=0, + region_id=0, + cluster_name="cluster_name", + pool_name="pool_name", + ) + + +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="pool_name", + project_id=0, + region_id=0, + cluster_name="cluster_name", + ) + 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="pool_name", + project_id=0, + region_id=0, + cluster_name="cluster_name", + with_ddos=True, + ) + 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="pool_name", + 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" + 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="pool_name", + 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" + + 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="pool_name", + project_id=0, + region_id=0, + 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=0, + region_id=0, + cluster_name="cluster_name", + ) + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + node = await async_client.cloud.k8s.clusters.pools.nodes.delete( + instance_id="instance_id", + project_id=0, + region_id=0, + cluster_name="cluster_name", + pool_name="pool_name", + ) + 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="instance_id", + project_id=0, + region_id=0, + cluster_name="cluster_name", + pool_name="pool_name", + ) + + 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="instance_id", + project_id=0, + region_id=0, + cluster_name="cluster_name", + pool_name="pool_name", + ) 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="instance_id", + project_id=0, + region_id=0, + cluster_name="", + pool_name="pool_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.delete( + instance_id="instance_id", + project_id=0, + region_id=0, + cluster_name="cluster_name", + 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=0, + region_id=0, + cluster_name="cluster_name", + pool_name="pool_name", + ) 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..624fdf56 --- /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="cluster_name", + project_id=0, + region_id=0, + ) + 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="cluster_name", + project_id=0, + region_id=0, + with_ddos=True, + ) + 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="cluster_name", + project_id=0, + region_id=0, + ) + + 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="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" + + 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=0, + region_id=0, + ) + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + node = client.cloud.k8s.clusters.nodes.delete( + instance_id="instance_id", + project_id=0, + region_id=0, + cluster_name="cluster_name", + ) + 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="instance_id", + 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" + 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="instance_id", + 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" + + 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="instance_id", + project_id=0, + region_id=0, + 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=0, + region_id=0, + cluster_name="cluster_name", + ) + + +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="cluster_name", + project_id=0, + region_id=0, + ) + 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="cluster_name", + project_id=0, + region_id=0, + with_ddos=True, + ) + 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="cluster_name", + project_id=0, + region_id=0, + ) + + 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="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" + + 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=0, + region_id=0, + ) + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + node = await async_client.cloud.k8s.clusters.nodes.delete( + instance_id="instance_id", + project_id=0, + region_id=0, + cluster_name="cluster_name", + ) + 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="instance_id", + 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" + 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="instance_id", + 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" + + 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="instance_id", + project_id=0, + region_id=0, + 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=0, + region_id=0, + cluster_name="cluster_name", + ) 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..e8e7e5b8 --- /dev/null +++ b/tests/api_resources/cloud/k8s/clusters/test_pools.py @@ -0,0 +1,786 @@ +# 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, +) + +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="cluster_name", + project_id=0, + region_id=0, + 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="cluster_name", + project_id=0, + region_id=0, + 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="cluster_name", + project_id=0, + region_id=0, + 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="cluster_name", + project_id=0, + region_id=0, + 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=0, + region_id=0, + 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="pool_name", + project_id=0, + region_id=0, + cluster_name="cluster_name", + ) + 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="pool_name", + project_id=0, + region_id=0, + cluster_name="cluster_name", + 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="pool_name", + 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" + 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="pool_name", + 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" + + 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="pool_name", + project_id=0, + region_id=0, + 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=0, + region_id=0, + cluster_name="cluster_name", + ) + + @parametrize + def test_method_list(self, client: Gcore) -> None: + pool = client.cloud.k8s.clusters.pools.list( + cluster_name="cluster_name", + project_id=0, + region_id=0, + ) + 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="cluster_name", + project_id=0, + region_id=0, + ) + + 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="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" + + 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=0, + region_id=0, + ) + + @parametrize + def test_method_delete(self, client: Gcore) -> None: + pool = client.cloud.k8s.clusters.pools.delete( + pool_name="pool_name", + project_id=0, + region_id=0, + cluster_name="cluster_name", + ) + 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="pool_name", + 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" + 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="pool_name", + 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" + + 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="pool_name", + project_id=0, + region_id=0, + 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=0, + region_id=0, + cluster_name="cluster_name", + ) + + @parametrize + def test_method_get(self, client: Gcore) -> None: + pool = client.cloud.k8s.clusters.pools.get( + pool_name="pool_name", + project_id=0, + region_id=0, + cluster_name="cluster_name", + ) + 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="pool_name", + 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" + 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="pool_name", + 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" + + 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="pool_name", + project_id=0, + region_id=0, + 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=0, + region_id=0, + cluster_name="cluster_name", + ) + + @parametrize + def test_method_resize(self, client: Gcore) -> None: + pool = client.cloud.k8s.clusters.pools.resize( + pool_name="pool_name", + project_id=0, + region_id=0, + cluster_name="cluster_name", + 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="pool_name", + project_id=0, + region_id=0, + cluster_name="cluster_name", + 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="pool_name", + project_id=0, + region_id=0, + cluster_name="cluster_name", + 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="pool_name", + project_id=0, + region_id=0, + 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=0, + region_id=0, + cluster_name="cluster_name", + 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="cluster_name", + project_id=0, + region_id=0, + 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="cluster_name", + project_id=0, + region_id=0, + 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="cluster_name", + project_id=0, + region_id=0, + 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="cluster_name", + project_id=0, + region_id=0, + 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=0, + region_id=0, + 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="pool_name", + project_id=0, + region_id=0, + cluster_name="cluster_name", + ) + 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="pool_name", + project_id=0, + region_id=0, + cluster_name="cluster_name", + 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="pool_name", + 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" + 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="pool_name", + 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" + + 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="pool_name", + project_id=0, + region_id=0, + 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=0, + region_id=0, + cluster_name="cluster_name", + ) + + @parametrize + async def test_method_list(self, async_client: AsyncGcore) -> None: + pool = await async_client.cloud.k8s.clusters.pools.list( + cluster_name="cluster_name", + project_id=0, + region_id=0, + ) + 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="cluster_name", + project_id=0, + region_id=0, + ) + + 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="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" + + 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=0, + region_id=0, + ) + + @parametrize + async def test_method_delete(self, async_client: AsyncGcore) -> None: + pool = await async_client.cloud.k8s.clusters.pools.delete( + pool_name="pool_name", + project_id=0, + region_id=0, + cluster_name="cluster_name", + ) + 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="pool_name", + 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" + 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="pool_name", + 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" + + 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="pool_name", + project_id=0, + region_id=0, + 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=0, + region_id=0, + cluster_name="cluster_name", + ) + + @parametrize + async def test_method_get(self, async_client: AsyncGcore) -> None: + pool = await async_client.cloud.k8s.clusters.pools.get( + pool_name="pool_name", + project_id=0, + region_id=0, + cluster_name="cluster_name", + ) + 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="pool_name", + 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" + 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="pool_name", + 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" + + 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="pool_name", + project_id=0, + region_id=0, + 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=0, + region_id=0, + cluster_name="cluster_name", + ) + + @parametrize + async def test_method_resize(self, async_client: AsyncGcore) -> None: + pool = await async_client.cloud.k8s.clusters.pools.resize( + pool_name="pool_name", + project_id=0, + region_id=0, + cluster_name="cluster_name", + 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="pool_name", + project_id=0, + region_id=0, + cluster_name="cluster_name", + 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="pool_name", + project_id=0, + region_id=0, + cluster_name="cluster_name", + 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="pool_name", + project_id=0, + region_id=0, + 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=0, + region_id=0, + cluster_name="cluster_name", + 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..1cb521cd --- /dev/null +++ b/tests/api_resources/cloud/k8s/test_clusters.py @@ -0,0 +1,1168 @@ +# 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=0, + region_id=0, + 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=0, + region_id=0, + 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", + 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": "value", + } + ], + "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=0, + region_id=0, + 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=0, + region_id=0, + 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="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.k8s.clusters.update( + cluster_name="cluster_name", + project_id=0, + region_id=0, + 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": "value", + } + ], + "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="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.k8s.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.k8s.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.k8s.clusters.list( + project_id=0, + region_id=0, + ) + 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=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(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=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(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="cluster_name", + project_id=0, + region_id=0, + ) + 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="cluster_name", + project_id=0, + region_id=0, + volumes="volumes", + ) + 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="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.k8s.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.k8s.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.k8s.clusters.get( + cluster_name="cluster_name", + project_id=0, + region_id=0, + ) + 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="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(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="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(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=0, + region_id=0, + ) + + @parametrize + def test_method_get_certificate(self, client: Gcore) -> None: + cluster = client.cloud.k8s.clusters.get_certificate( + cluster_name="cluster_name", + project_id=0, + region_id=0, + ) + 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="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(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="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(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=0, + region_id=0, + ) + + @parametrize + def test_method_get_kubeconfig(self, client: Gcore) -> None: + cluster = client.cloud.k8s.clusters.get_kubeconfig( + cluster_name="cluster_name", + project_id=0, + region_id=0, + ) + 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="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(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="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(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=0, + region_id=0, + ) + + @parametrize + def test_method_list_versions_for_upgrade(self, client: Gcore) -> None: + cluster = client.cloud.k8s.clusters.list_versions_for_upgrade( + cluster_name="cluster_name", + project_id=0, + region_id=0, + ) + 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="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(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="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(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=0, + region_id=0, + ) + + @parametrize + def test_method_upgrade(self, client: Gcore) -> None: + cluster = client.cloud.k8s.clusters.upgrade( + cluster_name="cluster_name", + project_id=0, + region_id=0, + 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="cluster_name", + project_id=0, + region_id=0, + 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="cluster_name", + project_id=0, + region_id=0, + 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=0, + region_id=0, + 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=0, + region_id=0, + 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=0, + region_id=0, + 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", + 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": "value", + } + ], + "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=0, + region_id=0, + 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=0, + region_id=0, + 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="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.k8s.clusters.update( + cluster_name="cluster_name", + project_id=0, + region_id=0, + 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": "value", + } + ], + "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="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.k8s.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.k8s.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.k8s.clusters.list( + project_id=0, + region_id=0, + ) + 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=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(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=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(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="cluster_name", + project_id=0, + region_id=0, + ) + 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="cluster_name", + project_id=0, + region_id=0, + volumes="volumes", + ) + 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="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.k8s.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.k8s.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.k8s.clusters.get( + cluster_name="cluster_name", + project_id=0, + region_id=0, + ) + 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="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(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="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(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=0, + region_id=0, + ) + + @parametrize + async def test_method_get_certificate(self, async_client: AsyncGcore) -> None: + cluster = await async_client.cloud.k8s.clusters.get_certificate( + cluster_name="cluster_name", + project_id=0, + region_id=0, + ) + 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="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(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="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(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=0, + region_id=0, + ) + + @parametrize + async def test_method_get_kubeconfig(self, async_client: AsyncGcore) -> None: + cluster = await async_client.cloud.k8s.clusters.get_kubeconfig( + cluster_name="cluster_name", + project_id=0, + region_id=0, + ) + 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="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(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="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(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=0, + region_id=0, + ) + + @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="cluster_name", + project_id=0, + region_id=0, + ) + 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="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(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="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(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=0, + region_id=0, + ) + + @parametrize + async def test_method_upgrade(self, async_client: AsyncGcore) -> None: + cluster = await async_client.cloud.k8s.clusters.upgrade( + cluster_name="cluster_name", + project_id=0, + region_id=0, + 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="cluster_name", + project_id=0, + region_id=0, + 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="cluster_name", + project_id=0, + region_id=0, + 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=0, + region_id=0, + 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..4aabd062 --- /dev/null +++ b/tests/api_resources/cloud/k8s/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 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=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.k8s.flavors.list( + project_id=0, + region_id=0, + exclude_gpu=True, + include_prices=True, + ) + 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=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.k8s.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.k8s.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.k8s.flavors.list( + project_id=0, + region_id=0, + exclude_gpu=True, + include_prices=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.k8s.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.k8s.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/load_balancers/test_statuses.py b/tests/api_resources/cloud/load_balancers/test_statuses.py index 3a8602ec..cf38797d 100644 --- a/tests/api_resources/cloud/load_balancers/test_statuses.py +++ b/tests/api_resources/cloud/load_balancers/test_statuses.py @@ -14,7 +14,6 @@ base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") -@pytest.mark.skip(reason="Skipping tests due to Prism routing request to the wrong path") class TestStatuses: parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) @@ -99,7 +98,6 @@ def test_path_params_get(self, client: Gcore) -> None: ) -@pytest.mark.skip(reason="Skipping tests due to Prism routing request to the wrong path") class TestAsyncStatuses: parametrize = pytest.mark.parametrize( "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] diff --git a/tests/api_resources/cloud/test_cost_reports.py b/tests/api_resources/cloud/test_cost_reports.py index b6df051a..1e3a60b8 100644 --- a/tests/api_resources/cloud/test_cost_reports.py +++ b/tests/api_resources/cloud/test_cost_reports.py @@ -92,17 +92,12 @@ def test_streaming_response_get_aggregated(self, client: Gcore) -> None: @parametrize def test_method_get_aggregated_monthly(self, client: Gcore) -> None: - cost_report = client.cloud.cost_reports.get_aggregated_monthly( - time_from=parse_datetime("2019-12-27T18:11:19.117Z"), - time_to=parse_datetime("2019-12-27T18:11:19.117Z"), - ) + 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( - time_from=parse_datetime("2019-12-27T18:11:19.117Z"), - time_to=parse_datetime("2019-12-27T18:11:19.117Z"), regions=[1, 2, 3], response_format="csv_totals", rounding=True, @@ -126,16 +121,16 @@ def test_method_get_aggregated_monthly_with_all_params(self, client: Gcore) -> N ], "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( - time_from=parse_datetime("2019-12-27T18:11:19.117Z"), - time_to=parse_datetime("2019-12-27T18:11:19.117Z"), - ) + 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" @@ -144,10 +139,7 @@ def test_raw_response_get_aggregated_monthly(self, client: Gcore) -> None: @parametrize def test_streaming_response_get_aggregated_monthly(self, client: Gcore) -> None: - with client.cloud.cost_reports.with_streaming_response.get_aggregated_monthly( - time_from=parse_datetime("2019-12-27T18:11:19.117Z"), - time_to=parse_datetime("2019-12-27T18:11:19.117Z"), - ) as response: + 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" @@ -313,17 +305,12 @@ async def test_streaming_response_get_aggregated(self, async_client: AsyncGcore) @parametrize async def test_method_get_aggregated_monthly(self, async_client: AsyncGcore) -> None: - cost_report = await async_client.cloud.cost_reports.get_aggregated_monthly( - time_from=parse_datetime("2019-12-27T18:11:19.117Z"), - time_to=parse_datetime("2019-12-27T18:11:19.117Z"), - ) + 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( - time_from=parse_datetime("2019-12-27T18:11:19.117Z"), - time_to=parse_datetime("2019-12-27T18:11:19.117Z"), regions=[1, 2, 3], response_format="csv_totals", rounding=True, @@ -347,16 +334,16 @@ async def test_method_get_aggregated_monthly_with_all_params(self, async_client: ], "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( - time_from=parse_datetime("2019-12-27T18:11:19.117Z"), - time_to=parse_datetime("2019-12-27T18:11:19.117Z"), - ) + 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" @@ -365,10 +352,7 @@ async def test_raw_response_get_aggregated_monthly(self, async_client: AsyncGcor @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( - time_from=parse_datetime("2019-12-27T18:11:19.117Z"), - time_to=parse_datetime("2019-12-27T18:11:19.117Z"), - ) as response: + 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" diff --git a/tests/api_resources/cloud/test_file_shares.py b/tests/api_resources/cloud/test_file_shares.py index ea13776e..8e02d137 100644 --- a/tests/api_resources/cloud/test_file_shares.py +++ b/tests/api_resources/cloud/test_file_shares.py @@ -52,6 +52,7 @@ def test_method_create_with_all_params_overload_1(self, client: Gcore) -> None: } ], tags={"my-tag": "my-tag-value"}, + type_name="standard", volume_type="default_share_type", ) assert_matches_type(TaskIDList, file_share, path=["response"]) @@ -98,7 +99,6 @@ def test_method_create_overload_2(self, client: Gcore) -> None: name="test-share-file-system", protocol="NFS", size=5, - volume_type="vast_share_type", ) assert_matches_type(TaskIDList, file_share, path=["response"]) @@ -110,9 +110,10 @@ def test_method_create_with_all_params_overload_2(self, client: Gcore) -> None: name="test-share-file-system", protocol="NFS", size=5, - volume_type="vast_share_type", share_settings={"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"]) @@ -124,7 +125,6 @@ def test_raw_response_create_overload_2(self, client: Gcore) -> None: name="test-share-file-system", protocol="NFS", size=5, - volume_type="vast_share_type", ) assert response.is_closed is True @@ -140,7 +140,6 @@ def test_streaming_response_create_overload_2(self, client: Gcore) -> None: name="test-share-file-system", protocol="NFS", size=5, - volume_type="vast_share_type", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -432,6 +431,7 @@ async def test_method_create_with_all_params_overload_1(self, async_client: Asyn } ], tags={"my-tag": "my-tag-value"}, + type_name="standard", volume_type="default_share_type", ) assert_matches_type(TaskIDList, file_share, path=["response"]) @@ -478,7 +478,6 @@ async def test_method_create_overload_2(self, async_client: AsyncGcore) -> None: name="test-share-file-system", protocol="NFS", size=5, - volume_type="vast_share_type", ) assert_matches_type(TaskIDList, file_share, path=["response"]) @@ -490,9 +489,10 @@ async def test_method_create_with_all_params_overload_2(self, async_client: Asyn name="test-share-file-system", protocol="NFS", size=5, - volume_type="vast_share_type", share_settings={"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"]) @@ -504,7 +504,6 @@ async def test_raw_response_create_overload_2(self, async_client: AsyncGcore) -> name="test-share-file-system", protocol="NFS", size=5, - volume_type="vast_share_type", ) assert response.is_closed is True @@ -520,7 +519,6 @@ async def test_streaming_response_create_overload_2(self, async_client: AsyncGco name="test-share-file-system", protocol="NFS", size=5, - volume_type="vast_share_type", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" diff --git a/tests/api_resources/cloud/test_gpu_baremetal_clusters.py b/tests/api_resources/cloud/test_gpu_baremetal_clusters.py index 1cf6cb78..b6a7547c 100644 --- a/tests/api_resources/cloud/test_gpu_baremetal_clusters.py +++ b/tests/api_resources/cloud/test_gpu_baremetal_clusters.py @@ -13,10 +13,8 @@ from gcore.types.cloud import ( TaskIDList, GPUBaremetalCluster, - GPUBaremetalClusterServerList, ) - -# pyright: reportDeprecated=false +from gcore.types.cloud.gpu_baremetal_clusters import GPUBaremetalClusterServerV1List base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -27,63 +25,55 @@ class TestGPUBaremetalClusters: @parametrize def test_method_create(self, client: Gcore) -> None: gpu_baremetal_cluster = client.cloud.gpu_baremetal_clusters.create( - project_id=0, - region_id=0, - flavor="bm3-ai-1xlarge-h100-80-8", - image_id="f01fd9a0-9548-48ba-82dc-a8c8b2d6f2f1", - interfaces=[ - { - "network_id": "024a29e9-b4b7-4c91-9a46-505be123d9f8", - "subnet_id": "91200a6c-07e0-42aa-98da-32d1f6545ae7", - "type": "subnet", - } - ], - name="my-gpu-cluster", + 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, gpu_baremetal_cluster, path=["response"]) @parametrize def test_method_create_with_all_params(self, client: Gcore) -> None: gpu_baremetal_cluster = client.cloud.gpu_baremetal_clusters.create( - project_id=0, - region_id=0, - flavor="bm3-ai-1xlarge-h100-80-8", - image_id="f01fd9a0-9548-48ba-82dc-a8c8b2d6f2f1", - interfaces=[ - { - "network_id": "024a29e9-b4b7-4c91-9a46-505be123d9f8", - "subnet_id": "91200a6c-07e0-42aa-98da-32d1f6545ae7", - "type": "subnet", - "floating_ip": {"source": "new"}, - "interface_name": "interface_name", - } - ], - name="my-gpu-cluster", - instances_count=1, - password="password", - security_groups=[{"id": "ae74714c-c380-48b4-87f8-758d656cdad6"}], - ssh_key_name="my-ssh-key", + 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", + }, + "security_groups": [{"id": "b4849ffa-89f2-45a1-951f-0ae5b7809d98"}], + "user_data": "eyJ0ZXN0IjogImRhdGEifQ==", + }, tags={"my-tag": "my-tag-value"}, - user_data="user_data", - username="username", ) assert_matches_type(TaskIDList, gpu_baremetal_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=0, - region_id=0, - flavor="bm3-ai-1xlarge-h100-80-8", - image_id="f01fd9a0-9548-48ba-82dc-a8c8b2d6f2f1", - interfaces=[ - { - "network_id": "024a29e9-b4b7-4c91-9a46-505be123d9f8", - "subnet_id": "91200a6c-07e0-42aa-98da-32d1f6545ae7", - "type": "subnet", - } - ], - name="my-gpu-cluster", + 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 @@ -94,18 +84,13 @@ def test_raw_response_create(self, client: Gcore) -> None: @parametrize def test_streaming_response_create(self, client: Gcore) -> None: with client.cloud.gpu_baremetal_clusters.with_streaming_response.create( - project_id=0, - region_id=0, - flavor="bm3-ai-1xlarge-h100-80-8", - image_id="f01fd9a0-9548-48ba-82dc-a8c8b2d6f2f1", - interfaces=[ - { - "network_id": "024a29e9-b4b7-4c91-9a46-505be123d9f8", - "subnet_id": "91200a6c-07e0-42aa-98da-32d1f6545ae7", - "type": "subnet", - } - ], - name="my-gpu-cluster", + 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" @@ -117,33 +102,29 @@ def test_streaming_response_create(self, client: Gcore) -> None: @parametrize def test_method_list(self, client: Gcore) -> None: - with pytest.warns(DeprecationWarning): - gpu_baremetal_cluster = client.cloud.gpu_baremetal_clusters.list( - project_id=0, - region_id=0, - ) - + gpu_baremetal_cluster = client.cloud.gpu_baremetal_clusters.list( + project_id=1, + region_id=7, + ) assert_matches_type(SyncOffsetPage[GPUBaremetalCluster], gpu_baremetal_cluster, path=["response"]) @parametrize def test_method_list_with_all_params(self, client: Gcore) -> None: - with pytest.warns(DeprecationWarning): - gpu_baremetal_cluster = client.cloud.gpu_baremetal_clusters.list( - project_id=0, - region_id=0, - limit=0, - offset=0, - ) - + gpu_baremetal_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], gpu_baremetal_cluster, path=["response"]) @parametrize def test_raw_response_list(self, client: Gcore) -> None: - with pytest.warns(DeprecationWarning): - response = client.cloud.gpu_baremetal_clusters.with_raw_response.list( - project_id=0, - region_id=0, - ) + 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" @@ -152,46 +133,46 @@ def test_raw_response_list(self, client: Gcore) -> None: @parametrize def test_streaming_response_list(self, client: Gcore) -> None: - with pytest.warns(DeprecationWarning): - with client.cloud.gpu_baremetal_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" + 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" - gpu_baremetal_cluster = response.parse() - assert_matches_type(SyncOffsetPage[GPUBaremetalCluster], gpu_baremetal_cluster, path=["response"]) + gpu_baremetal_cluster = response.parse() + assert_matches_type(SyncOffsetPage[GPUBaremetalCluster], gpu_baremetal_cluster, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize def test_method_delete(self, client: Gcore) -> None: gpu_baremetal_cluster = client.cloud.gpu_baremetal_clusters.delete( - cluster_id="cluster_id", - project_id=0, - region_id=0, + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, ) assert_matches_type(TaskIDList, gpu_baremetal_cluster, path=["response"]) @parametrize def test_method_delete_with_all_params(self, client: Gcore) -> None: gpu_baremetal_cluster = client.cloud.gpu_baremetal_clusters.delete( - cluster_id="cluster_id", - project_id=0, - region_id=0, - delete_floatings=True, - floatings="floatings", - reserved_fixed_ips="reserved_fixed_ips", + 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, gpu_baremetal_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="cluster_id", - project_id=0, - region_id=0, + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, ) assert response.is_closed is True @@ -202,9 +183,9 @@ def test_raw_response_delete(self, client: Gcore) -> None: @parametrize def test_streaming_response_delete(self, client: Gcore) -> None: with client.cloud.gpu_baremetal_clusters.with_streaming_response.delete( - cluster_id="cluster_id", - project_id=0, - region_id=0, + 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" @@ -219,29 +200,26 @@ 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=0, - region_id=0, + project_id=1, + region_id=7, ) @parametrize def test_method_get(self, client: Gcore) -> None: - with pytest.warns(DeprecationWarning): - gpu_baremetal_cluster = client.cloud.gpu_baremetal_clusters.get( - cluster_id="cluster_id", - project_id=0, - region_id=0, - ) - + gpu_baremetal_cluster = client.cloud.gpu_baremetal_clusters.get( + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, + ) assert_matches_type(GPUBaremetalCluster, gpu_baremetal_cluster, path=["response"]) @parametrize def test_raw_response_get(self, client: Gcore) -> None: - with pytest.warns(DeprecationWarning): - response = client.cloud.gpu_baremetal_clusters.with_raw_response.get( - cluster_id="cluster_id", - project_id=0, - region_id=0, - ) + 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" @@ -250,29 +228,27 @@ def test_raw_response_get(self, client: Gcore) -> None: @parametrize def test_streaming_response_get(self, client: Gcore) -> None: - with pytest.warns(DeprecationWarning): - with client.cloud.gpu_baremetal_clusters.with_streaming_response.get( - 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" + 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" - gpu_baremetal_cluster = response.parse() - assert_matches_type(GPUBaremetalCluster, gpu_baremetal_cluster, path=["response"]) + gpu_baremetal_cluster = response.parse() + assert_matches_type(GPUBaremetalCluster, gpu_baremetal_cluster, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize def test_path_params_get(self, client: Gcore) -> None: - with pytest.warns(DeprecationWarning): - 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=0, - region_id=0, - ) + 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: @@ -281,7 +257,7 @@ def test_method_powercycle_all_servers(self, client: Gcore) -> None: project_id=0, region_id=0, ) - assert_matches_type(GPUBaremetalClusterServerList, gpu_baremetal_cluster, path=["response"]) + assert_matches_type(GPUBaremetalClusterServerV1List, gpu_baremetal_cluster, path=["response"]) @parametrize def test_raw_response_powercycle_all_servers(self, client: Gcore) -> None: @@ -294,7 +270,7 @@ def test_raw_response_powercycle_all_servers(self, client: Gcore) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" gpu_baremetal_cluster = response.parse() - assert_matches_type(GPUBaremetalClusterServerList, gpu_baremetal_cluster, path=["response"]) + assert_matches_type(GPUBaremetalClusterServerV1List, gpu_baremetal_cluster, path=["response"]) @parametrize def test_streaming_response_powercycle_all_servers(self, client: Gcore) -> None: @@ -307,7 +283,7 @@ def test_streaming_response_powercycle_all_servers(self, client: Gcore) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" gpu_baremetal_cluster = response.parse() - assert_matches_type(GPUBaremetalClusterServerList, gpu_baremetal_cluster, path=["response"]) + assert_matches_type(GPUBaremetalClusterServerV1List, gpu_baremetal_cluster, path=["response"]) assert cast(Any, response.is_closed) is True @@ -327,7 +303,7 @@ def test_method_reboot_all_servers(self, client: Gcore) -> None: project_id=0, region_id=0, ) - assert_matches_type(GPUBaremetalClusterServerList, gpu_baremetal_cluster, path=["response"]) + assert_matches_type(GPUBaremetalClusterServerV1List, gpu_baremetal_cluster, path=["response"]) @parametrize def test_raw_response_reboot_all_servers(self, client: Gcore) -> None: @@ -340,7 +316,7 @@ def test_raw_response_reboot_all_servers(self, client: Gcore) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" gpu_baremetal_cluster = response.parse() - assert_matches_type(GPUBaremetalClusterServerList, gpu_baremetal_cluster, path=["response"]) + assert_matches_type(GPUBaremetalClusterServerV1List, gpu_baremetal_cluster, path=["response"]) @parametrize def test_streaming_response_reboot_all_servers(self, client: Gcore) -> None: @@ -353,7 +329,7 @@ def test_streaming_response_reboot_all_servers(self, client: Gcore) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" gpu_baremetal_cluster = response.parse() - assert_matches_type(GPUBaremetalClusterServerList, gpu_baremetal_cluster, path=["response"]) + assert_matches_type(GPUBaremetalClusterServerV1List, gpu_baremetal_cluster, path=["response"]) assert cast(Any, response.is_closed) is True @@ -487,63 +463,55 @@ class TestAsyncGPUBaremetalClusters: @parametrize async def test_method_create(self, async_client: AsyncGcore) -> None: gpu_baremetal_cluster = await async_client.cloud.gpu_baremetal_clusters.create( - project_id=0, - region_id=0, - flavor="bm3-ai-1xlarge-h100-80-8", - image_id="f01fd9a0-9548-48ba-82dc-a8c8b2d6f2f1", - interfaces=[ - { - "network_id": "024a29e9-b4b7-4c91-9a46-505be123d9f8", - "subnet_id": "91200a6c-07e0-42aa-98da-32d1f6545ae7", - "type": "subnet", - } - ], - name="my-gpu-cluster", + 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, gpu_baremetal_cluster, path=["response"]) @parametrize async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> None: gpu_baremetal_cluster = await async_client.cloud.gpu_baremetal_clusters.create( - project_id=0, - region_id=0, - flavor="bm3-ai-1xlarge-h100-80-8", - image_id="f01fd9a0-9548-48ba-82dc-a8c8b2d6f2f1", - interfaces=[ - { - "network_id": "024a29e9-b4b7-4c91-9a46-505be123d9f8", - "subnet_id": "91200a6c-07e0-42aa-98da-32d1f6545ae7", - "type": "subnet", - "floating_ip": {"source": "new"}, - "interface_name": "interface_name", - } - ], - name="my-gpu-cluster", - instances_count=1, - password="password", - security_groups=[{"id": "ae74714c-c380-48b4-87f8-758d656cdad6"}], - ssh_key_name="my-ssh-key", + 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", + }, + "security_groups": [{"id": "b4849ffa-89f2-45a1-951f-0ae5b7809d98"}], + "user_data": "eyJ0ZXN0IjogImRhdGEifQ==", + }, tags={"my-tag": "my-tag-value"}, - user_data="user_data", - username="username", ) assert_matches_type(TaskIDList, gpu_baremetal_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=0, - region_id=0, - flavor="bm3-ai-1xlarge-h100-80-8", - image_id="f01fd9a0-9548-48ba-82dc-a8c8b2d6f2f1", - interfaces=[ - { - "network_id": "024a29e9-b4b7-4c91-9a46-505be123d9f8", - "subnet_id": "91200a6c-07e0-42aa-98da-32d1f6545ae7", - "type": "subnet", - } - ], - name="my-gpu-cluster", + 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 @@ -554,18 +522,13 @@ async def test_raw_response_create(self, async_client: AsyncGcore) -> None: @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=0, - region_id=0, - flavor="bm3-ai-1xlarge-h100-80-8", - image_id="f01fd9a0-9548-48ba-82dc-a8c8b2d6f2f1", - interfaces=[ - { - "network_id": "024a29e9-b4b7-4c91-9a46-505be123d9f8", - "subnet_id": "91200a6c-07e0-42aa-98da-32d1f6545ae7", - "type": "subnet", - } - ], - name="my-gpu-cluster", + 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" @@ -577,33 +540,29 @@ async def test_streaming_response_create(self, async_client: AsyncGcore) -> None @parametrize async def test_method_list(self, async_client: AsyncGcore) -> None: - with pytest.warns(DeprecationWarning): - gpu_baremetal_cluster = await async_client.cloud.gpu_baremetal_clusters.list( - project_id=0, - region_id=0, - ) - + gpu_baremetal_cluster = await async_client.cloud.gpu_baremetal_clusters.list( + project_id=1, + region_id=7, + ) assert_matches_type(AsyncOffsetPage[GPUBaremetalCluster], gpu_baremetal_cluster, path=["response"]) @parametrize async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: - with pytest.warns(DeprecationWarning): - gpu_baremetal_cluster = await async_client.cloud.gpu_baremetal_clusters.list( - project_id=0, - region_id=0, - limit=0, - offset=0, - ) - + gpu_baremetal_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], gpu_baremetal_cluster, path=["response"]) @parametrize async def test_raw_response_list(self, async_client: AsyncGcore) -> None: - with pytest.warns(DeprecationWarning): - response = await async_client.cloud.gpu_baremetal_clusters.with_raw_response.list( - project_id=0, - region_id=0, - ) + 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" @@ -612,46 +571,46 @@ async def test_raw_response_list(self, async_client: AsyncGcore) -> None: @parametrize async def test_streaming_response_list(self, async_client: AsyncGcore) -> None: - with pytest.warns(DeprecationWarning): - async with async_client.cloud.gpu_baremetal_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" + 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" - gpu_baremetal_cluster = await response.parse() - assert_matches_type(AsyncOffsetPage[GPUBaremetalCluster], gpu_baremetal_cluster, path=["response"]) + gpu_baremetal_cluster = await response.parse() + assert_matches_type(AsyncOffsetPage[GPUBaremetalCluster], gpu_baremetal_cluster, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize async def test_method_delete(self, async_client: AsyncGcore) -> None: gpu_baremetal_cluster = await async_client.cloud.gpu_baremetal_clusters.delete( - cluster_id="cluster_id", - project_id=0, - region_id=0, + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, ) assert_matches_type(TaskIDList, gpu_baremetal_cluster, path=["response"]) @parametrize async def test_method_delete_with_all_params(self, async_client: AsyncGcore) -> None: gpu_baremetal_cluster = await async_client.cloud.gpu_baremetal_clusters.delete( - cluster_id="cluster_id", - project_id=0, - region_id=0, - delete_floatings=True, - floatings="floatings", - reserved_fixed_ips="reserved_fixed_ips", + 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, gpu_baremetal_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="cluster_id", - project_id=0, - region_id=0, + cluster_id="1aaaab48-10d0-46d9-80cc-85209284ceb4", + project_id=1, + region_id=7, ) assert response.is_closed is True @@ -662,9 +621,9 @@ async def test_raw_response_delete(self, async_client: AsyncGcore) -> None: @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="cluster_id", - project_id=0, - region_id=0, + 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" @@ -679,29 +638,26 @@ 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=0, - region_id=0, + project_id=1, + region_id=7, ) @parametrize async def test_method_get(self, async_client: AsyncGcore) -> None: - with pytest.warns(DeprecationWarning): - gpu_baremetal_cluster = await async_client.cloud.gpu_baremetal_clusters.get( - cluster_id="cluster_id", - project_id=0, - region_id=0, - ) - + gpu_baremetal_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, gpu_baremetal_cluster, path=["response"]) @parametrize async def test_raw_response_get(self, async_client: AsyncGcore) -> None: - with pytest.warns(DeprecationWarning): - response = await async_client.cloud.gpu_baremetal_clusters.with_raw_response.get( - cluster_id="cluster_id", - project_id=0, - region_id=0, - ) + 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" @@ -710,29 +666,27 @@ async def test_raw_response_get(self, async_client: AsyncGcore) -> None: @parametrize async def test_streaming_response_get(self, async_client: AsyncGcore) -> None: - with pytest.warns(DeprecationWarning): - async with async_client.cloud.gpu_baremetal_clusters.with_streaming_response.get( - 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" + 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" - gpu_baremetal_cluster = await response.parse() - assert_matches_type(GPUBaremetalCluster, gpu_baremetal_cluster, path=["response"]) + gpu_baremetal_cluster = await response.parse() + assert_matches_type(GPUBaremetalCluster, gpu_baremetal_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.warns(DeprecationWarning): - 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=0, - region_id=0, - ) + 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: @@ -741,7 +695,7 @@ async def test_method_powercycle_all_servers(self, async_client: AsyncGcore) -> project_id=0, region_id=0, ) - assert_matches_type(GPUBaremetalClusterServerList, gpu_baremetal_cluster, path=["response"]) + assert_matches_type(GPUBaremetalClusterServerV1List, gpu_baremetal_cluster, path=["response"]) @parametrize async def test_raw_response_powercycle_all_servers(self, async_client: AsyncGcore) -> None: @@ -754,7 +708,7 @@ async def test_raw_response_powercycle_all_servers(self, async_client: AsyncGcor assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" gpu_baremetal_cluster = await response.parse() - assert_matches_type(GPUBaremetalClusterServerList, gpu_baremetal_cluster, path=["response"]) + assert_matches_type(GPUBaremetalClusterServerV1List, gpu_baremetal_cluster, path=["response"]) @parametrize async def test_streaming_response_powercycle_all_servers(self, async_client: AsyncGcore) -> None: @@ -767,7 +721,7 @@ async def test_streaming_response_powercycle_all_servers(self, async_client: Asy assert response.http_request.headers.get("X-Stainless-Lang") == "python" gpu_baremetal_cluster = await response.parse() - assert_matches_type(GPUBaremetalClusterServerList, gpu_baremetal_cluster, path=["response"]) + assert_matches_type(GPUBaremetalClusterServerV1List, gpu_baremetal_cluster, path=["response"]) assert cast(Any, response.is_closed) is True @@ -787,7 +741,7 @@ async def test_method_reboot_all_servers(self, async_client: AsyncGcore) -> None project_id=0, region_id=0, ) - assert_matches_type(GPUBaremetalClusterServerList, gpu_baremetal_cluster, path=["response"]) + assert_matches_type(GPUBaremetalClusterServerV1List, gpu_baremetal_cluster, path=["response"]) @parametrize async def test_raw_response_reboot_all_servers(self, async_client: AsyncGcore) -> None: @@ -800,7 +754,7 @@ async def test_raw_response_reboot_all_servers(self, async_client: AsyncGcore) - assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" gpu_baremetal_cluster = await response.parse() - assert_matches_type(GPUBaremetalClusterServerList, gpu_baremetal_cluster, path=["response"]) + assert_matches_type(GPUBaremetalClusterServerV1List, gpu_baremetal_cluster, path=["response"]) @parametrize async def test_streaming_response_reboot_all_servers(self, async_client: AsyncGcore) -> None: @@ -813,7 +767,7 @@ async def test_streaming_response_reboot_all_servers(self, async_client: AsyncGc assert response.http_request.headers.get("X-Stainless-Lang") == "python" gpu_baremetal_cluster = await response.parse() - assert_matches_type(GPUBaremetalClusterServerList, gpu_baremetal_cluster, path=["response"]) + assert_matches_type(GPUBaremetalClusterServerV1List, gpu_baremetal_cluster, 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..6bd73971 --- /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: + k8 = client.cloud.k8s.list_versions( + project_id=0, + region_id=0, + ) + assert_matches_type(K8sClusterVersionList, k8, path=["response"]) + + @parametrize + def test_raw_response_list_versions(self, client: Gcore) -> None: + response = client.cloud.k8s.with_raw_response.list_versions( + project_id=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + k8 = response.parse() + assert_matches_type(K8sClusterVersionList, k8, path=["response"]) + + @parametrize + def test_streaming_response_list_versions(self, client: Gcore) -> None: + with client.cloud.k8s.with_streaming_response.list_versions( + project_id=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + k8 = response.parse() + assert_matches_type(K8sClusterVersionList, k8, 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: + k8 = await async_client.cloud.k8s.list_versions( + project_id=0, + region_id=0, + ) + assert_matches_type(K8sClusterVersionList, k8, 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=0, + region_id=0, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + k8 = await response.parse() + assert_matches_type(K8sClusterVersionList, k8, 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=0, + region_id=0, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + k8 = await response.parse() + assert_matches_type(K8sClusterVersionList, k8, 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_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/security/test_profiles.py b/tests/api_resources/security/test_profiles.py index 429291ae..ae9ed3b3 100644 --- a/tests/api_resources/security/test_profiles.py +++ b/tests/api_resources/security/test_profiles.py @@ -34,7 +34,7 @@ def test_method_create_with_all_params(self, client: Gcore) -> None: fields=[ { "base_field": 1, - "field_value": {"key": "bar"}, + "field_value": {}, } ], profile_template=1, @@ -182,7 +182,7 @@ def test_method_recreate_with_all_params(self, client: Gcore) -> None: fields=[ { "base_field": 1, - "field_value": {"key": "bar"}, + "field_value": {}, } ], profile_template=1, @@ -235,7 +235,7 @@ def test_method_replace_with_all_params(self, client: Gcore) -> None: fields=[ { "base_field": 1, - "field_value": {"key": "bar"}, + "field_value": {}, } ], profile_template=1, @@ -292,7 +292,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> fields=[ { "base_field": 1, - "field_value": {"key": "bar"}, + "field_value": {}, } ], profile_template=1, @@ -440,7 +440,7 @@ async def test_method_recreate_with_all_params(self, async_client: AsyncGcore) - fields=[ { "base_field": 1, - "field_value": {"key": "bar"}, + "field_value": {}, } ], profile_template=1, @@ -493,7 +493,7 @@ async def test_method_replace_with_all_params(self, async_client: AsyncGcore) -> fields=[ { "base_field": 1, - "field_value": {"key": "bar"}, + "field_value": {}, } ], profile_template=1, 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..caf6bc59 --- /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=False, + generate_s3_keys=True, + generate_sftp_password=True, + reset_sftp_keys=False, + sftp_password="MyNewSecurePassword123", + ) + 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=False, + generate_s3_keys=True, + generate_sftp_password=True, + reset_sftp_keys=False, + sftp_password="MyNewSecurePassword123", + ) + 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..4c4739fd --- /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-ed1", "s-drc2", "s-sgc1"], + 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-ed1", "s-drc2", "s-sgc1"], + 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-ed1", "s-drc2", "s-sgc1"], + 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-ed1", "s-drc2", "s-sgc1"], + 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/test_ai_tasks.py b/tests/api_resources/streaming/test_ai_tasks.py index 641c59f4..ee5239b7 100644 --- a/tests/api_resources/streaming/test_ai_tasks.py +++ b/tests/api_resources/streaming/test_ai_tasks.py @@ -25,7 +25,8 @@ class TestAITasks: parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) @pytest.mark.skip( - reason="Skipping test due to 422 Unprocessable Entity {\"error\":\"Feature is disabled. Contact support to enable.\"}") + reason='Skipping test due to 422 Unprocessable Entity {"error":"Feature is disabled. Contact support to enable."}' + ) @parametrize def test_method_create(self, client: Gcore) -> None: ai_task = client.streaming.ai_tasks.create( @@ -35,7 +36,8 @@ def test_method_create(self, client: Gcore) -> None: assert_matches_type(AITaskCreateResponse, ai_task, path=["response"]) @pytest.mark.skip( - reason="Skipping test due to 422 Unprocessable Entity {\"error\":\"Feature is disabled. Contact support to enable.\"}") + reason='Skipping test due to 422 Unprocessable Entity {"error":"Feature is disabled. Contact support to enable."}' + ) @parametrize def test_method_create_with_all_params(self, client: Gcore) -> None: ai_task = client.streaming.ai_tasks.create( @@ -49,7 +51,9 @@ def test_method_create_with_all_params(self, client: Gcore) -> None: ) assert_matches_type(AITaskCreateResponse, ai_task, path=["response"]) - @pytest.mark.skip(reason="Skipping test due to 422 Unprocessable Entity {\"error\":\"Feature is disabled. Contact support to enable.\"}") + @pytest.mark.skip( + reason='Skipping test due to 422 Unprocessable Entity {"error":"Feature is disabled. Contact support to enable."}' + ) @parametrize def test_raw_response_create(self, client: Gcore) -> None: response = client.streaming.ai_tasks.with_raw_response.create( @@ -63,7 +67,8 @@ def test_raw_response_create(self, client: Gcore) -> None: assert_matches_type(AITaskCreateResponse, ai_task, path=["response"]) @pytest.mark.skip( - reason="Skipping test due to 422 Unprocessable Entity {\"error\":\"Feature is disabled. Contact support to enable.\"}") + reason='Skipping test due to 422 Unprocessable Entity {"error":"Feature is disabled. Contact support to enable."}' + ) @parametrize def test_streaming_response_create(self, client: Gcore) -> None: with client.streaming.ai_tasks.with_streaming_response.create( @@ -240,7 +245,8 @@ class TestAsyncAITasks: ) @pytest.mark.skip( - reason="Skipping test due to 422 Unprocessable Entity {\"error\":\"Feature is disabled. Contact support to enable.\"}") + reason='Skipping test due to 422 Unprocessable Entity {"error":"Feature is disabled. Contact support to enable."}' + ) @parametrize async def test_method_create(self, async_client: AsyncGcore) -> None: ai_task = await async_client.streaming.ai_tasks.create( @@ -250,7 +256,8 @@ async def test_method_create(self, async_client: AsyncGcore) -> None: assert_matches_type(AITaskCreateResponse, ai_task, path=["response"]) @pytest.mark.skip( - reason="Skipping test due to 422 Unprocessable Entity {\"error\":\"Feature is disabled. Contact support to enable.\"}") + reason='Skipping test due to 422 Unprocessable Entity {"error":"Feature is disabled. Contact support to enable."}' + ) @parametrize async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> None: ai_task = await async_client.streaming.ai_tasks.create( @@ -265,7 +272,8 @@ async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> assert_matches_type(AITaskCreateResponse, ai_task, path=["response"]) @pytest.mark.skip( - reason="Skipping test due to 422 Unprocessable Entity {\"error\":\"Feature is disabled. Contact support to enable.\"}") + reason='Skipping test due to 422 Unprocessable Entity {"error":"Feature is disabled. Contact support to enable."}' + ) @parametrize async def test_raw_response_create(self, async_client: AsyncGcore) -> None: response = await async_client.streaming.ai_tasks.with_raw_response.create( @@ -279,7 +287,8 @@ async def test_raw_response_create(self, async_client: AsyncGcore) -> None: assert_matches_type(AITaskCreateResponse, ai_task, path=["response"]) @pytest.mark.skip( - reason="Skipping test due to 422 Unprocessable Entity {\"error\":\"Feature is disabled. Contact support to enable.\"}") + reason='Skipping test due to 422 Unprocessable Entity {"error":"Feature is disabled. Contact support to enable."}' + ) @parametrize async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: async with async_client.streaming.ai_tasks.with_streaming_response.create( diff --git a/tests/api_resources/streaming/test_directories.py b/tests/api_resources/streaming/test_directories.py index 5514d615..e7a661c2 100644 --- a/tests/api_resources/streaming/test_directories.py +++ b/tests/api_resources/streaming/test_directories.py @@ -17,12 +17,14 @@ try: import pydantic - pydantic_v2 = hasattr(pydantic, '__version__') and pydantic.__version__.startswith('2.') + + pydantic_v2 = hasattr(pydantic, "__version__") and pydantic.__version__.startswith("2.") except ImportError: pydantic_v2 = False base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + @pytest.mark.skipif(not pydantic_v2, reason="Requires Pydantic v2") class TestDirectories: parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) diff --git a/tests/api_resources/streaming/test_statistics.py b/tests/api_resources/streaming/test_statistics.py index 72546277..bae1314e 100644 --- a/tests/api_resources/streaming/test_statistics.py +++ b/tests/api_resources/streaming/test_statistics.py @@ -12,7 +12,6 @@ from gcore.types.streaming import ( Views, Ffprobes, - MeetSeries, StreamSeries, ViewsHeatmap, PopularVideos, @@ -251,49 +250,6 @@ def test_streaming_response_get_max_streams_series(self, client: Gcore) -> None: assert cast(Any, response.is_closed) is True - @parametrize - def test_method_get_meet_series(self, client: Gcore) -> None: - statistic = client.streaming.statistics.get_meet_series( - from_="from", - to="to", - ) - assert_matches_type(MeetSeries, statistic, path=["response"]) - - @parametrize - def test_method_get_meet_series_with_all_params(self, client: Gcore) -> None: - statistic = client.streaming.statistics.get_meet_series( - from_="from", - to="to", - granularity="1m", - ) - assert_matches_type(MeetSeries, statistic, path=["response"]) - - @parametrize - def test_raw_response_get_meet_series(self, client: Gcore) -> None: - response = client.streaming.statistics.with_raw_response.get_meet_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(MeetSeries, statistic, path=["response"]) - - @parametrize - def test_streaming_response_get_meet_series(self, client: Gcore) -> None: - with client.streaming.statistics.with_streaming_response.get_meet_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(MeetSeries, 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( @@ -1209,49 +1165,6 @@ async def test_streaming_response_get_max_streams_series(self, async_client: Asy assert cast(Any, response.is_closed) is True - @parametrize - async def test_method_get_meet_series(self, async_client: AsyncGcore) -> None: - statistic = await async_client.streaming.statistics.get_meet_series( - from_="from", - to="to", - ) - assert_matches_type(MeetSeries, statistic, path=["response"]) - - @parametrize - async def test_method_get_meet_series_with_all_params(self, async_client: AsyncGcore) -> None: - statistic = await async_client.streaming.statistics.get_meet_series( - from_="from", - to="to", - granularity="1m", - ) - assert_matches_type(MeetSeries, statistic, path=["response"]) - - @parametrize - async def test_raw_response_get_meet_series(self, async_client: AsyncGcore) -> None: - response = await async_client.streaming.statistics.with_raw_response.get_meet_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(MeetSeries, statistic, path=["response"]) - - @parametrize - async def test_streaming_response_get_meet_series(self, async_client: AsyncGcore) -> None: - async with async_client.streaming.statistics.with_streaming_response.get_meet_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(MeetSeries, 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( diff --git a/tests/api_resources/streaming/test_streams.py b/tests/api_resources/streaming/test_streams.py index f9a5aff1..ca08569d 100644 --- a/tests/api_resources/streaming/test_streams.py +++ b/tests/api_resources/streaming/test_streams.py @@ -45,7 +45,6 @@ def test_method_create_with_all_params(self, client: Gcore) -> None: dvr_enabled=True, hls_mpegts_endlist_tag=True, html_overlay=False, - low_latency_enabled=True, projection="regular", pull=True, quality_set_id=0, @@ -101,7 +100,6 @@ def test_method_update_with_all_params(self, client: Gcore) -> None: "dvr_enabled": True, "hls_mpegts_endlist_tag": True, "html_overlay": False, - "low_latency_enabled": True, "projection": "regular", "pull": True, "quality_set_id": 0, @@ -433,7 +431,6 @@ async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> dvr_enabled=True, hls_mpegts_endlist_tag=True, html_overlay=False, - low_latency_enabled=True, projection="regular", pull=True, quality_set_id=0, @@ -489,7 +486,6 @@ async def test_method_update_with_all_params(self, async_client: AsyncGcore) -> "dvr_enabled": True, "hls_mpegts_endlist_tag": True, "html_overlay": False, - "low_latency_enabled": True, "projection": "regular", "pull": True, "quality_set_id": 0, diff --git a/tests/api_resources/streaming/videos/test_subtitles.py b/tests/api_resources/streaming/videos/test_subtitles.py index 0ef60a44..0d1d03e9 100644 --- a/tests/api_resources/streaming/videos/test_subtitles.py +++ b/tests/api_resources/streaming/videos/test_subtitles.py @@ -19,7 +19,8 @@ class TestSubtitles: parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) @pytest.mark.skip( - reason="Skipping test due to 422 Unprocessable Entity {\"error\":\"Language code is not recognized.\"}") + reason='Skipping test due to 422 Unprocessable Entity {"error":"Language code is not recognized."}' + ) @parametrize def test_method_create(self, client: Gcore) -> None: subtitle = client.streaming.videos.subtitles.create( @@ -41,7 +42,8 @@ def test_method_create_with_all_params(self, client: Gcore) -> None: assert_matches_type(Subtitle, subtitle, path=["response"]) @pytest.mark.skip( - reason="Skipping test due to 422 Unprocessable Entity {\"error\":\"Language code is not recognized.\"}") + reason='Skipping test due to 422 Unprocessable Entity {"error":"Language code is not recognized."}' + ) @parametrize def test_raw_response_create(self, client: Gcore) -> None: response = client.streaming.videos.subtitles.with_raw_response.create( @@ -55,7 +57,8 @@ def test_raw_response_create(self, client: Gcore) -> None: assert_matches_type(Subtitle, subtitle, path=["response"]) @pytest.mark.skip( - reason="Skipping test due to 422 Unprocessable Entity {\"error\":\"Language code is not recognized.\"}") + reason='Skipping test due to 422 Unprocessable Entity {"error":"Language code is not recognized."}' + ) @parametrize def test_streaming_response_create(self, client: Gcore) -> None: with client.streaming.videos.subtitles.with_streaming_response.create( @@ -221,7 +224,8 @@ class TestAsyncSubtitles: ) @pytest.mark.skip( - reason="Skipping test due to 422 Unprocessable Entity {\"error\":\"Language code is not recognized.\"}") + reason='Skipping test due to 422 Unprocessable Entity {"error":"Language code is not recognized."}' + ) @parametrize async def test_method_create(self, async_client: AsyncGcore) -> None: subtitle = await async_client.streaming.videos.subtitles.create( @@ -243,7 +247,8 @@ async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> assert_matches_type(Subtitle, subtitle, path=["response"]) @pytest.mark.skip( - reason="Skipping test due to 422 Unprocessable Entity {\"error\":\"Language code is not recognized.\"}") + reason='Skipping test due to 422 Unprocessable Entity {"error":"Language code is not recognized."}' + ) @parametrize async def test_raw_response_create(self, async_client: AsyncGcore) -> None: response = await async_client.streaming.videos.subtitles.with_raw_response.create( @@ -257,7 +262,8 @@ async def test_raw_response_create(self, async_client: AsyncGcore) -> None: assert_matches_type(Subtitle, subtitle, path=["response"]) @pytest.mark.skip( - reason="Skipping test due to 422 Unprocessable Entity {\"error\":\"Language code is not recognized.\"}") + reason='Skipping test due to 422 Unprocessable Entity {"error":"Language code is not recognized."}' + ) @parametrize async def test_streaming_response_create(self, async_client: AsyncGcore) -> None: async with async_client.streaming.videos.subtitles.with_streaming_response.create( 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_storage.py b/tests/api_resources/test_storage.py new file mode 100644 index 00000000..3a087e65 --- /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-ed1", + 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-ed1", + 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-ed1", + 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-ed1", + 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="2026-12-31 23:59:59+00:00", + 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-ed1", + 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-ed1", + 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-ed1", + 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-ed1", + 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="2026-12-31 23:59:59+00:00", + 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/waap/domains/test_advanced_rules.py b/tests/api_resources/waap/domains/test_advanced_rules.py index bb99d81b..fe8f806f 100644 --- a/tests/api_resources/waap/domains/test_advanced_rules.py +++ b/tests/api_resources/waap/domains/test_advanced_rules.py @@ -26,7 +26,7 @@ def test_method_create(self, client: Gcore) -> None: domain_id=1, action={}, enabled=True, - name="name", + 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"]) @@ -47,7 +47,7 @@ def test_method_create_with_all_params(self, client: Gcore) -> None: "tag": {"tags": ["string"]}, }, enabled=True, - name="name", + 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", @@ -60,7 +60,7 @@ def test_raw_response_create(self, client: Gcore) -> None: domain_id=1, action={}, enabled=True, - name="name", + 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']", ) @@ -75,7 +75,7 @@ def test_streaming_response_create(self, client: Gcore) -> None: domain_id=1, action={}, enabled=True, - name="name", + 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 @@ -112,7 +112,7 @@ def test_method_update_with_all_params(self, client: Gcore) -> None: }, description="description", enabled=True, - name="name", + name="Block foobar bot", phase="access", source="x", ) @@ -161,7 +161,7 @@ def test_method_list_with_all_params(self, client: Gcore) -> None: limit=0, name="Block by specific IP rule", offset=0, - ordering="id", + ordering="-id", phase="access", ) assert_matches_type(SyncOffsetPage[WaapAdvancedRule], advanced_rule, path=["response"]) @@ -307,7 +307,7 @@ async def test_method_create(self, async_client: AsyncGcore) -> None: domain_id=1, action={}, enabled=True, - name="name", + 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"]) @@ -328,7 +328,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> "tag": {"tags": ["string"]}, }, enabled=True, - name="name", + 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", @@ -341,7 +341,7 @@ async def test_raw_response_create(self, async_client: AsyncGcore) -> None: domain_id=1, action={}, enabled=True, - name="name", + 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']", ) @@ -356,7 +356,7 @@ async def test_streaming_response_create(self, async_client: AsyncGcore) -> None domain_id=1, action={}, enabled=True, - name="name", + 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 @@ -393,7 +393,7 @@ async def test_method_update_with_all_params(self, async_client: AsyncGcore) -> }, description="description", enabled=True, - name="name", + name="Block foobar bot", phase="access", source="x", ) @@ -442,7 +442,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> No limit=0, name="Block by specific IP rule", offset=0, - ordering="id", + ordering="-id", phase="access", ) assert_matches_type(AsyncOffsetPage[WaapAdvancedRule], advanced_rule, path=["response"]) diff --git a/tests/api_resources/waap/domains/test_custom_rules.py b/tests/api_resources/waap/domains/test_custom_rules.py index 70f4c5b2..62327ad7 100644 --- a/tests/api_resources/waap/domains/test_custom_rules.py +++ b/tests/api_resources/waap/domains/test_custom_rules.py @@ -27,7 +27,7 @@ def test_method_create(self, client: Gcore) -> None: action={}, conditions=[{}], enabled=True, - name="name", + name="Block foobar bot", ) assert_matches_type(WaapCustomRule, custom_rule, path=["response"]) @@ -134,7 +134,7 @@ def test_method_create_with_all_params(self, client: Gcore) -> None: } ], enabled=True, - name="name", + name="Block foobar bot", description="description", ) assert_matches_type(WaapCustomRule, custom_rule, path=["response"]) @@ -146,7 +146,7 @@ def test_raw_response_create(self, client: Gcore) -> None: action={}, conditions=[{}], enabled=True, - name="name", + name="Block foobar bot", ) assert response.is_closed is True @@ -161,7 +161,7 @@ def test_streaming_response_create(self, client: Gcore) -> None: action={}, conditions=[{}], enabled=True, - name="name", + name="Block foobar bot", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -284,7 +284,7 @@ def test_method_update_with_all_params(self, client: Gcore) -> None: ], description="description", enabled=True, - name="name", + name="Block foobar bot", ) assert custom_rule is None @@ -511,7 +511,7 @@ async def test_method_create(self, async_client: AsyncGcore) -> None: action={}, conditions=[{}], enabled=True, - name="name", + name="Block foobar bot", ) assert_matches_type(WaapCustomRule, custom_rule, path=["response"]) @@ -618,7 +618,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> } ], enabled=True, - name="name", + name="Block foobar bot", description="description", ) assert_matches_type(WaapCustomRule, custom_rule, path=["response"]) @@ -630,7 +630,7 @@ async def test_raw_response_create(self, async_client: AsyncGcore) -> None: action={}, conditions=[{}], enabled=True, - name="name", + name="Block foobar bot", ) assert response.is_closed is True @@ -645,7 +645,7 @@ async def test_streaming_response_create(self, async_client: AsyncGcore) -> None action={}, conditions=[{}], enabled=True, - name="name", + name="Block foobar bot", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -768,7 +768,7 @@ async def test_method_update_with_all_params(self, async_client: AsyncGcore) -> ], description="description", enabled=True, - name="name", + name="Block foobar bot", ) assert custom_rule is None diff --git a/tests/api_resources/waap/domains/test_firewall_rules.py b/tests/api_resources/waap/domains/test_firewall_rules.py index 0be72d1a..72064193 100644 --- a/tests/api_resources/waap/domains/test_firewall_rules.py +++ b/tests/api_resources/waap/domains/test_firewall_rules.py @@ -27,7 +27,7 @@ def test_method_create(self, client: Gcore) -> None: action={}, conditions=[{}], enabled=True, - name="name", + name="Block foobar bot", ) assert_matches_type(WaapFirewallRule, firewall_rule, path=["response"]) @@ -56,7 +56,7 @@ def test_method_create_with_all_params(self, client: Gcore) -> None: } ], enabled=True, - name="name", + name="Block foobar bot", description="description", ) assert_matches_type(WaapFirewallRule, firewall_rule, path=["response"]) @@ -68,7 +68,7 @@ def test_raw_response_create(self, client: Gcore) -> None: action={}, conditions=[{}], enabled=True, - name="name", + name="Block foobar bot", ) assert response.is_closed is True @@ -83,7 +83,7 @@ def test_streaming_response_create(self, client: Gcore) -> None: action={}, conditions=[{}], enabled=True, - name="name", + name="Block foobar bot", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -128,7 +128,7 @@ def test_method_update_with_all_params(self, client: Gcore) -> None: ], description="description", enabled=True, - name="name", + name="Block foobar bot", ) assert firewall_rule is None @@ -170,10 +170,10 @@ 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="description", - enabled=True, + description="This rule blocks all the requests coming form a specific IP address.", + enabled=False, limit=0, - name="name", + name="Block by specific IP rule.", offset=0, ordering="-id", ) @@ -355,7 +355,7 @@ async def test_method_create(self, async_client: AsyncGcore) -> None: action={}, conditions=[{}], enabled=True, - name="name", + name="Block foobar bot", ) assert_matches_type(WaapFirewallRule, firewall_rule, path=["response"]) @@ -384,7 +384,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncGcore) -> } ], enabled=True, - name="name", + name="Block foobar bot", description="description", ) assert_matches_type(WaapFirewallRule, firewall_rule, path=["response"]) @@ -396,7 +396,7 @@ async def test_raw_response_create(self, async_client: AsyncGcore) -> None: action={}, conditions=[{}], enabled=True, - name="name", + name="Block foobar bot", ) assert response.is_closed is True @@ -411,7 +411,7 @@ async def test_streaming_response_create(self, async_client: AsyncGcore) -> None action={}, conditions=[{}], enabled=True, - name="name", + name="Block foobar bot", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -456,7 +456,7 @@ async def test_method_update_with_all_params(self, async_client: AsyncGcore) -> ], description="description", enabled=True, - name="name", + name="Block foobar bot", ) assert firewall_rule is None @@ -498,10 +498,10 @@ async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> No firewall_rule = await async_client.waap.domains.firewall_rules.list( domain_id=1, action="allow", - description="description", - enabled=True, + description="This rule blocks all the requests coming form a specific IP address.", + enabled=False, limit=0, - name="name", + name="Block by specific IP rule.", offset=0, ordering="-id", ) diff --git a/tests/api_resources/waap/domains/test_statistics.py b/tests/api_resources/waap/domains/test_statistics.py index 11ac75e3..f46a30a2 100644 --- a/tests/api_resources/waap/domains/test_statistics.py +++ b/tests/api_resources/waap/domains/test_statistics.py @@ -37,11 +37,11 @@ def test_method_get_ddos_attacks(self, client: Gcore) -> None: 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("2019-12-27T18:11:19.117Z"), + end_time=parse_datetime("2024-04-27T13:00:00Z"), limit=0, offset=0, ordering="start_time", - start_time=parse_datetime("2019-12-27T18:11:19.117Z"), + start_time=parse_datetime("2024-04-26T13:32:49Z"), ) assert_matches_type(SyncOffsetPage[WaapDDOSAttack], statistic, path=["response"]) @@ -74,7 +74,7 @@ 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=parse_datetime("2019-12-27T18:11:19.117Z"), + start="2024-04-13T00:00:00+01:00", ) assert_matches_type(SyncOffsetPage[WaapDDOSInfo], statistic, path=["response"]) @@ -83,8 +83,8 @@ 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=parse_datetime("2019-12-27T18:11:19.117Z"), - end=parse_datetime("2019-12-27T18:11:19.117Z"), + start="2024-04-13T00:00:00+01:00", + end="2024-04-14T12:00:00Z", limit=0, offset=0, ) @@ -95,7 +95,7 @@ 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=parse_datetime("2019-12-27T18:11:19.117Z"), + start="2024-04-13T00:00:00+01:00", ) assert response.is_closed is True @@ -108,7 +108,7 @@ 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=parse_datetime("2019-12-27T18:11:19.117Z"), + 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" @@ -122,7 +122,7 @@ def test_streaming_response_get_ddos_info(self, client: Gcore) -> None: def test_method_get_events_aggregated(self, client: Gcore) -> None: statistic = client.waap.domains.statistics.get_events_aggregated( domain_id=1, - start=parse_datetime("2019-12-27T18:11:19.117Z"), + start="2024-04-13T00:00:00+01:00", ) assert_matches_type(WaapEventStatistics, statistic, path=["response"]) @@ -130,9 +130,9 @@ def test_method_get_events_aggregated(self, client: Gcore) -> None: 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=parse_datetime("2019-12-27T18:11:19.117Z"), + start="2024-04-13T00:00:00+01:00", action=["block", "captcha"], - end=parse_datetime("2019-12-27T18:11:19.117Z"), + end="2024-04-14T12:00:00Z", ip=["string", "string"], reference_id=["string", "string"], result=["passed", "blocked"], @@ -143,7 +143,7 @@ def test_method_get_events_aggregated_with_all_params(self, client: Gcore) -> No 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=parse_datetime("2019-12-27T18:11:19.117Z"), + start="2024-04-13T00:00:00+01:00", ) assert response.is_closed is True @@ -155,7 +155,7 @@ def test_raw_response_get_events_aggregated(self, client: Gcore) -> None: 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=parse_datetime("2019-12-27T18:11:19.117Z"), + 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" @@ -211,7 +211,7 @@ def test_path_params_get_request_details(self, client: Gcore) -> None: def test_method_get_requests_series(self, client: Gcore) -> None: statistic = client.waap.domains.statistics.get_requests_series( domain_id=1, - start=parse_datetime("2019-12-27T18:11:19.117Z"), + start="2024-04-13T00:00:00+01:00", ) assert_matches_type(SyncOffsetPage[WaapRequestSummary], statistic, path=["response"]) @@ -219,15 +219,15 @@ def test_method_get_requests_series(self, client: Gcore) -> None: def test_method_get_requests_series_with_all_params(self, client: Gcore) -> None: statistic = client.waap.domains.statistics.get_requests_series( domain_id=1, - start=parse_datetime("2019-12-27T18:11:19.117Z"), + start="2024-04-13T00:00:00+01:00", actions=["allow"], countries=["Mv"], - end=parse_datetime("2019-12-27T18:11:19.117Z"), + end="2024-04-14T12:00:00Z", ip=".:", limit=0, offset=0, ordering="ordering", - reference_id="2c02efDd09B3BA1AEaDd3dCAa7aC7A37", + reference_id="ad07c06f19054e484974fa22e9fb6bb1", security_rule_name="security_rule_name", status_code=100, traffic_types=["policy_allowed"], @@ -238,7 +238,7 @@ def test_method_get_requests_series_with_all_params(self, client: Gcore) -> None def test_raw_response_get_requests_series(self, client: Gcore) -> None: response = client.waap.domains.statistics.with_raw_response.get_requests_series( domain_id=1, - start=parse_datetime("2019-12-27T18:11:19.117Z"), + start="2024-04-13T00:00:00+01:00", ) assert response.is_closed is True @@ -250,7 +250,7 @@ def test_raw_response_get_requests_series(self, client: Gcore) -> None: def test_streaming_response_get_requests_series(self, client: Gcore) -> None: with client.waap.domains.statistics.with_streaming_response.get_requests_series( domain_id=1, - start=parse_datetime("2019-12-27T18:11:19.117Z"), + 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" @@ -265,7 +265,7 @@ def test_method_get_traffic_series(self, client: Gcore) -> None: statistic = client.waap.domains.statistics.get_traffic_series( domain_id=1, resolution="daily", - start=parse_datetime("2019-12-27T18:11:19.117Z"), + start="2024-04-13T00:00:00+01:00", ) assert_matches_type(StatisticGetTrafficSeriesResponse, statistic, path=["response"]) @@ -274,8 +274,8 @@ def test_method_get_traffic_series_with_all_params(self, client: Gcore) -> None: statistic = client.waap.domains.statistics.get_traffic_series( domain_id=1, resolution="daily", - start=parse_datetime("2019-12-27T18:11:19.117Z"), - end=parse_datetime("2019-12-27T18:11:19.117Z"), + start="2024-04-13T00:00:00+01:00", + end="2024-04-14T12:00:00Z", ) assert_matches_type(StatisticGetTrafficSeriesResponse, statistic, path=["response"]) @@ -284,7 +284,7 @@ def test_raw_response_get_traffic_series(self, client: Gcore) -> None: response = client.waap.domains.statistics.with_raw_response.get_traffic_series( domain_id=1, resolution="daily", - start=parse_datetime("2019-12-27T18:11:19.117Z"), + start="2024-04-13T00:00:00+01:00", ) assert response.is_closed is True @@ -297,7 +297,7 @@ def test_streaming_response_get_traffic_series(self, client: Gcore) -> None: with client.waap.domains.statistics.with_streaming_response.get_traffic_series( domain_id=1, resolution="daily", - start=parse_datetime("2019-12-27T18:11:19.117Z"), + 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" @@ -324,11 +324,11 @@ async def test_method_get_ddos_attacks(self, async_client: AsyncGcore) -> None: 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("2019-12-27T18:11:19.117Z"), + end_time=parse_datetime("2024-04-27T13:00:00Z"), limit=0, offset=0, ordering="start_time", - start_time=parse_datetime("2019-12-27T18:11:19.117Z"), + start_time=parse_datetime("2024-04-26T13:32:49Z"), ) assert_matches_type(AsyncOffsetPage[WaapDDOSAttack], statistic, path=["response"]) @@ -361,7 +361,7 @@ 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=parse_datetime("2019-12-27T18:11:19.117Z"), + start="2024-04-13T00:00:00+01:00", ) assert_matches_type(AsyncOffsetPage[WaapDDOSInfo], statistic, path=["response"]) @@ -370,8 +370,8 @@ async def test_method_get_ddos_info_with_all_params(self, async_client: AsyncGco statistic = await async_client.waap.domains.statistics.get_ddos_info( domain_id=1, group_by="URL", - start=parse_datetime("2019-12-27T18:11:19.117Z"), - end=parse_datetime("2019-12-27T18:11:19.117Z"), + start="2024-04-13T00:00:00+01:00", + end="2024-04-14T12:00:00Z", limit=0, offset=0, ) @@ -382,7 +382,7 @@ async def test_raw_response_get_ddos_info(self, async_client: AsyncGcore) -> Non response = await async_client.waap.domains.statistics.with_raw_response.get_ddos_info( domain_id=1, group_by="URL", - start=parse_datetime("2019-12-27T18:11:19.117Z"), + start="2024-04-13T00:00:00+01:00", ) assert response.is_closed is True @@ -395,7 +395,7 @@ async def test_streaming_response_get_ddos_info(self, async_client: AsyncGcore) async with async_client.waap.domains.statistics.with_streaming_response.get_ddos_info( domain_id=1, group_by="URL", - start=parse_datetime("2019-12-27T18:11:19.117Z"), + 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" @@ -409,7 +409,7 @@ async def test_streaming_response_get_ddos_info(self, async_client: AsyncGcore) 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=parse_datetime("2019-12-27T18:11:19.117Z"), + start="2024-04-13T00:00:00+01:00", ) assert_matches_type(WaapEventStatistics, statistic, path=["response"]) @@ -417,9 +417,9 @@ async def test_method_get_events_aggregated(self, async_client: AsyncGcore) -> N 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=parse_datetime("2019-12-27T18:11:19.117Z"), + start="2024-04-13T00:00:00+01:00", action=["block", "captcha"], - end=parse_datetime("2019-12-27T18:11:19.117Z"), + end="2024-04-14T12:00:00Z", ip=["string", "string"], reference_id=["string", "string"], result=["passed", "blocked"], @@ -430,7 +430,7 @@ async def test_method_get_events_aggregated_with_all_params(self, async_client: 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=parse_datetime("2019-12-27T18:11:19.117Z"), + start="2024-04-13T00:00:00+01:00", ) assert response.is_closed is True @@ -442,7 +442,7 @@ async def test_raw_response_get_events_aggregated(self, async_client: AsyncGcore 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=parse_datetime("2019-12-27T18:11:19.117Z"), + 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" @@ -498,7 +498,7 @@ async def test_path_params_get_request_details(self, async_client: AsyncGcore) - async def test_method_get_requests_series(self, async_client: AsyncGcore) -> None: statistic = await async_client.waap.domains.statistics.get_requests_series( domain_id=1, - start=parse_datetime("2019-12-27T18:11:19.117Z"), + start="2024-04-13T00:00:00+01:00", ) assert_matches_type(AsyncOffsetPage[WaapRequestSummary], statistic, path=["response"]) @@ -506,15 +506,15 @@ async def test_method_get_requests_series(self, async_client: AsyncGcore) -> Non async def test_method_get_requests_series_with_all_params(self, async_client: AsyncGcore) -> None: statistic = await async_client.waap.domains.statistics.get_requests_series( domain_id=1, - start=parse_datetime("2019-12-27T18:11:19.117Z"), + start="2024-04-13T00:00:00+01:00", actions=["allow"], countries=["Mv"], - end=parse_datetime("2019-12-27T18:11:19.117Z"), + end="2024-04-14T12:00:00Z", ip=".:", limit=0, offset=0, ordering="ordering", - reference_id="2c02efDd09B3BA1AEaDd3dCAa7aC7A37", + reference_id="ad07c06f19054e484974fa22e9fb6bb1", security_rule_name="security_rule_name", status_code=100, traffic_types=["policy_allowed"], @@ -525,7 +525,7 @@ async def test_method_get_requests_series_with_all_params(self, async_client: As async def test_raw_response_get_requests_series(self, async_client: AsyncGcore) -> None: response = await async_client.waap.domains.statistics.with_raw_response.get_requests_series( domain_id=1, - start=parse_datetime("2019-12-27T18:11:19.117Z"), + start="2024-04-13T00:00:00+01:00", ) assert response.is_closed is True @@ -537,7 +537,7 @@ async def test_raw_response_get_requests_series(self, async_client: AsyncGcore) async def test_streaming_response_get_requests_series(self, async_client: AsyncGcore) -> None: async with async_client.waap.domains.statistics.with_streaming_response.get_requests_series( domain_id=1, - start=parse_datetime("2019-12-27T18:11:19.117Z"), + 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" @@ -552,7 +552,7 @@ async def test_method_get_traffic_series(self, async_client: AsyncGcore) -> None statistic = await async_client.waap.domains.statistics.get_traffic_series( domain_id=1, resolution="daily", - start=parse_datetime("2019-12-27T18:11:19.117Z"), + start="2024-04-13T00:00:00+01:00", ) assert_matches_type(StatisticGetTrafficSeriesResponse, statistic, path=["response"]) @@ -561,8 +561,8 @@ async def test_method_get_traffic_series_with_all_params(self, async_client: Asy statistic = await async_client.waap.domains.statistics.get_traffic_series( domain_id=1, resolution="daily", - start=parse_datetime("2019-12-27T18:11:19.117Z"), - end=parse_datetime("2019-12-27T18:11:19.117Z"), + start="2024-04-13T00:00:00+01:00", + end="2024-04-14T12:00:00Z", ) assert_matches_type(StatisticGetTrafficSeriesResponse, statistic, path=["response"]) @@ -571,7 +571,7 @@ async def test_raw_response_get_traffic_series(self, async_client: AsyncGcore) - response = await async_client.waap.domains.statistics.with_raw_response.get_traffic_series( domain_id=1, resolution="daily", - start=parse_datetime("2019-12-27T18:11:19.117Z"), + start="2024-04-13T00:00:00+01:00", ) assert response.is_closed is True @@ -584,7 +584,7 @@ async def test_streaming_response_get_traffic_series(self, async_client: AsyncGc async with async_client.waap.domains.statistics.with_streaming_response.get_traffic_series( domain_id=1, resolution="daily", - start=parse_datetime("2019-12-27T18:11:19.117Z"), + 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" diff --git a/tests/api_resources/waap/test_custom_page_sets.py b/tests/api_resources/waap/test_custom_page_sets.py index 204fbc21..1d26207e 100644 --- a/tests/api_resources/waap/test_custom_page_sets.py +++ b/tests/api_resources/waap/test_custom_page_sets.py @@ -186,7 +186,7 @@ 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="name", + name="*example", offset=0, ordering="name", ) @@ -488,7 +488,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> No custom_page_set = await async_client.waap.custom_page_sets.list( ids=[0], limit=0, - name="name", + name="*example", offset=0, ordering="name", ) diff --git a/tests/api_resources/waap/test_domains.py b/tests/api_resources/waap/test_domains.py index 8c4234e4..f311215b 100644 --- a/tests/api_resources/waap/test_domains.py +++ b/tests/api_resources/waap/test_domains.py @@ -72,7 +72,7 @@ def test_method_list_with_all_params(self, client: Gcore) -> None: domain = client.waap.domains.list( ids=[1], limit=0, - name="name", + name="*example.com", offset=0, ordering="id", status="active", @@ -289,7 +289,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> No domain = await async_client.waap.domains.list( ids=[1], limit=0, - name="name", + name="*example.com", offset=0, ordering="id", status="active", diff --git a/tests/api_resources/waap/test_organizations.py b/tests/api_resources/waap/test_organizations.py index d4d2c516..ce01cf82 100644 --- a/tests/api_resources/waap/test_organizations.py +++ b/tests/api_resources/waap/test_organizations.py @@ -27,7 +27,7 @@ def test_method_list(self, client: Gcore) -> None: def test_method_list_with_all_params(self, client: Gcore) -> None: organization = client.waap.organizations.list( limit=0, - name="name", + name="Comcast", offset=0, ordering="name", ) @@ -68,7 +68,7 @@ async def test_method_list(self, async_client: AsyncGcore) -> None: async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: organization = await async_client.waap.organizations.list( limit=0, - name="name", + name="Comcast", offset=0, ordering="name", ) diff --git a/tests/api_resources/waap/test_tags.py b/tests/api_resources/waap/test_tags.py index 00753147..cb4474d8 100644 --- a/tests/api_resources/waap/test_tags.py +++ b/tests/api_resources/waap/test_tags.py @@ -27,10 +27,10 @@ def test_method_list(self, client: Gcore) -> None: def test_method_list_with_all_params(self, client: Gcore) -> None: tag = client.waap.tags.list( limit=0, - name="name", + name="xss", offset=0, ordering="name", - readable_name="readable_name", + readable_name="Cross-Site Scripting", reserved=True, ) assert_matches_type(SyncOffsetPage[WaapTag], tag, path=["response"]) @@ -70,10 +70,10 @@ async def test_method_list(self, async_client: AsyncGcore) -> None: async def test_method_list_with_all_params(self, async_client: AsyncGcore) -> None: tag = await async_client.waap.tags.list( limit=0, - name="name", + name="xss", offset=0, ordering="name", - readable_name="readable_name", + readable_name="Cross-Site Scripting", reserved=True, ) assert_matches_type(AsyncOffsetPage[WaapTag], tag, path=["response"]) diff --git a/tests/test_client.py b/tests/test_client.py index b0d1e897..17903dc2 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -6,13 +6,10 @@ import os import sys import json -import time import asyncio import inspect -import subprocess import tracemalloc from typing import Any, Union, cast -from textwrap import dedent from unittest import mock from typing_extensions import Literal @@ -23,14 +20,17 @@ 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, ) @@ -1671,50 +1671,9 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: assert response.http_request.headers.get("x-stainless-retry-count") == "42" - def test_get_platform(self) -> None: - # A previous implementation of asyncify could leave threads unterminated when - # used with nest_asyncio. - # - # Since nest_asyncio.apply() is global and cannot be un-applied, this - # test is run in a separate process to avoid affecting other tests. - test_code = dedent(""" - import asyncio - import nest_asyncio - import threading - - from gcore._utils import asyncify - from gcore._base_client import get_platform - - async def test_main() -> None: - result = await asyncify(get_platform)() - print(result) - for thread in threading.enumerate(): - print(thread.name) - - nest_asyncio.apply() - asyncio.run(test_main()) - """) - with subprocess.Popen( - [sys.executable, "-c", test_code], - text=True, - ) as process: - timeout = 10 # seconds - - start_time = time.monotonic() - while True: - return_code = process.poll() - if return_code is not None: - if return_code != 0: - raise AssertionError("calling get_platform using asyncify resulted in a non-zero exit code") - - # success - break - - if time.monotonic() - start_time > timeout: - process.kill() - raise AssertionError("calling get_platform using asyncify resulted in a hung process") - - time.sleep(0.1) + 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 diff --git a/tests/test_models.py b/tests/test_models.py index c891c772..7b21d517 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -8,7 +8,7 @@ from pydantic import Field from gcore._utils import PropertyInfo -from gcore._compat import PYDANTIC_V2, parse_obj, model_dump, model_json +from gcore._compat import PYDANTIC_V1, parse_obj, model_dump, model_json from gcore._models import BaseModel, construct_type @@ -294,12 +294,12 @@ class Model(BaseModel): assert cast(bool, m.foo) is True m = Model.construct(foo={"name": 3}) - if PYDANTIC_V2: - assert isinstance(m.foo, Submodel1) - assert m.foo.name == 3 # type: ignore - else: + 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: @@ -426,10 +426,10 @@ class Model(BaseModel): expected = datetime(2019, 12, 27, 18, 11, 19, 117000, tzinfo=timezone.utc) - if PYDANTIC_V2: - expected_json = '{"created_at":"2019-12-27T18:11:19.117000Z"}' - else: + 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 @@ -531,7 +531,7 @@ class Model2(BaseModel): assert m4.to_dict(mode="python") == {"created_at": datetime.fromisoformat(time_str)} assert m4.to_dict(mode="json") == {"created_at": time_str} - if not PYDANTIC_V2: + if PYDANTIC_V1: with pytest.raises(ValueError, match="warnings is only supported in Pydantic v2"): m.to_dict(warnings=False) @@ -556,7 +556,7 @@ class Model(BaseModel): assert m3.model_dump() == {"foo": None} assert m3.model_dump(exclude_none=True) == {} - if not PYDANTIC_V2: + if PYDANTIC_V1: with pytest.raises(ValueError, match="round_trip is only supported in Pydantic v2"): m.model_dump(round_trip=True) @@ -580,10 +580,10 @@ class Model(BaseModel): assert json.loads(m.to_json()) == {"FOO": "hello"} assert json.loads(m.to_json(use_api_names=False)) == {"foo": "hello"} - if PYDANTIC_V2: - assert m.to_json(indent=None) == '{"FOO":"hello"}' - else: + 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()) == {} @@ -595,7 +595,7 @@ class Model(BaseModel): assert json.loads(m3.to_json()) == {"FOO": None} assert json.loads(m3.to_json(exclude_none=True)) == {} - if not PYDANTIC_V2: + if PYDANTIC_V1: with pytest.raises(ValueError, match="warnings is only supported in Pydantic v2"): m.to_json(warnings=False) @@ -622,7 +622,7 @@ class Model(BaseModel): assert json.loads(m3.model_dump_json()) == {"foo": None} assert json.loads(m3.model_dump_json(exclude_none=True)) == {} - if not PYDANTIC_V2: + if PYDANTIC_V1: with pytest.raises(ValueError, match="round_trip is only supported in Pydantic v2"): m.model_dump_json(round_trip=True) @@ -679,12 +679,12 @@ class B(BaseModel): ) assert isinstance(m, A) assert m.type == "a" - if PYDANTIC_V2: - assert m.data == 100 # type: ignore[comparison-overlap] - else: + 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: @@ -768,12 +768,12 @@ class B(BaseModel): ) assert isinstance(m, A) assert m.foo_type == "a" - if PYDANTIC_V2: - assert m.data == 100 # type: ignore[comparison-overlap] - else: + 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: @@ -833,7 +833,7 @@ class B(BaseModel): assert UnionType.__discriminator__ is discriminator -@pytest.mark.skipif(not PYDANTIC_V2, reason="TypeAliasType is not supported in Pydantic v1") +@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 @@ -849,7 +849,7 @@ class Model(BaseModel): assert m.union == "bar" -@pytest.mark.skipif(not PYDANTIC_V2, reason="TypeAliasType is not supported in Pydantic v1") +@pytest.mark.skipif(PYDANTIC_V1, reason="TypeAliasType is not supported in Pydantic v1") def test_field_named_cls() -> None: class Model(BaseModel): cls: str @@ -936,7 +936,7 @@ class Type2(BaseModel): assert isinstance(model.value, InnerType2) -@pytest.mark.skipif(not PYDANTIC_V2, reason="this is only supported in pydantic v2 for now") +@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 diff --git a/tests/test_transform.py b/tests/test_transform.py index 987047c5..a2beb233 100644 --- a/tests/test_transform.py +++ b/tests/test_transform.py @@ -15,7 +15,7 @@ parse_datetime, async_transform as _async_transform, ) -from gcore._compat import PYDANTIC_V2 +from gcore._compat import PYDANTIC_V1 from gcore._models import BaseModel _T = TypeVar("_T") @@ -189,7 +189,7 @@ class DateModel(BaseModel): @pytest.mark.asyncio async def test_iso8601_format(use_async: bool) -> None: dt = datetime.fromisoformat("2023-02-23T14:16:36.337692+00:00") - tz = "Z" if PYDANTIC_V2 else "+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] @@ -297,11 +297,11 @@ async def test_pydantic_unknown_field(use_async: bool) -> None: @pytest.mark.asyncio async def test_pydantic_mismatched_types(use_async: bool) -> None: model = MyModel.construct(foo=True) - if PYDANTIC_V2: + if PYDANTIC_V1: + params = await transform(model, Any, use_async) + else: with pytest.warns(UserWarning): params = await transform(model, Any, use_async) - else: - params = await transform(model, Any, use_async) assert cast(Any, params) == {"foo": True} @@ -309,11 +309,11 @@ async def test_pydantic_mismatched_types(use_async: bool) -> None: @pytest.mark.asyncio async def test_pydantic_mismatched_object_type(use_async: bool) -> None: model = MyModel.construct(foo=MyModel.construct(hello="world")) - if PYDANTIC_V2: + if PYDANTIC_V1: + params = await transform(model, Any, use_async) + else: with pytest.warns(UserWarning): params = await transform(model, Any, use_async) - else: - params = await transform(model, Any, use_async) assert cast(Any, params) == {"foo": {"hello": "world"}} 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/utils.py b/tests/utils.py index 6a13fa7d..a391741f 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -4,7 +4,7 @@ import inspect import traceback import contextlib -from typing import Any, TypeVar, Iterator, cast +from typing import Any, TypeVar, Iterator, Sequence, cast from datetime import date, datetime from typing_extensions import Literal, get_args, get_origin, assert_type @@ -15,10 +15,11 @@ is_list_type, is_union_type, extract_type_arg, + is_sequence_type, is_annotated_type, is_type_alias_type, ) -from gcore._compat import PYDANTIC_V2, field_outer_type, get_model_fields +from gcore._compat import PYDANTIC_V1, field_outer_type, get_model_fields from gcore._models import BaseModel BaseModelT = TypeVar("BaseModelT", bound=BaseModel) @@ -27,12 +28,12 @@ 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_V2: - allow_none = False - else: + 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), @@ -71,6 +72,13 @@ def assert_matches_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: