├── tests ├── __init__.py ├── test_unit │ ├── __init__.py │ ├── test_core │ │ ├── __init__.py │ │ ├── consts.py │ │ ├── test_deco.py │ │ ├── test_exc.py │ │ ├── test_encoder.py │ │ ├── test_auth.py │ │ ├── test_fields.py │ │ ├── test_client.py │ │ └── test_transport.py │ ├── test_helpers │ │ ├── __init__.py │ │ ├── test_utils.py │ │ └── test_wait.py │ └── test_testing │ │ ├── __init__.py │ │ └── test_utest.py ├── test_services │ ├── __init__.py │ ├── conftest.py │ └── test_set_2935.py └── test_acceptance │ └── conftest.py ├── ucloud ├── __init__.py ├── core │ ├── __init__.py │ ├── utils │ │ ├── __init__.py │ │ ├── compat.py │ │ ├── log.py │ │ ├── deco.py │ │ └── middleware.py │ ├── typesystem │ │ ├── __init__.py │ │ ├── encoder.py │ │ ├── abstract.py │ │ ├── schema.py │ │ └── fields.py │ ├── auth │ │ ├── __init__.py │ │ └── _cfg.py │ ├── client │ │ ├── __init__.py │ │ └── _cfg.py │ ├── transport │ │ ├── __init__.py │ │ ├── utils.py │ │ ├── http.py │ │ └── _requests.py │ └── exc │ │ ├── __init__.py │ │ └── _exc.py ├── helpers │ ├── __init__.py │ ├── utils.py │ └── wait.py ├── services │ ├── __init__.py │ ├── cube │ │ ├── __init__.py │ │ └── schemas │ │ │ ├── __init__.py │ │ │ └── models.py │ ├── iam │ │ ├── __init__.py │ │ └── schemas │ │ │ └── __init__.py │ ├── isms │ │ ├── __init__.py │ │ └── schemas │ │ │ ├── __init__.py │ │ │ └── models.py │ ├── pathx │ │ ├── __init__.py │ │ └── schemas │ │ │ └── __init__.py │ ├── sts │ │ ├── __init__.py │ │ ├── schemas │ │ │ ├── __init__.py │ │ │ ├── models.py │ │ │ └── apis.py │ │ └── client.py │ ├── tidb │ │ ├── __init__.py │ │ ├── schemas │ │ │ ├── __init__.py │ │ │ ├── models.py │ │ │ └── apis.py │ │ └── client.py │ ├── uaaa │ │ ├── __init__.py │ │ └── schemas │ │ │ ├── __init__.py │ │ │ └── models.py │ ├── uads │ │ ├── __init__.py │ │ └── schemas │ │ │ └── __init__.py │ ├── ubill │ │ ├── __init__.py │ │ └── schemas │ │ │ ├── __init__.py │ │ │ └── models.py │ ├── ucdn │ │ ├── __init__.py │ │ └── schemas │ │ │ └── __init__.py │ ├── udb │ │ ├── __init__.py │ │ └── schemas │ │ │ └── __init__.py │ ├── uddb │ │ ├── __init__.py │ │ └── schemas │ │ │ ├── __init__.py │ │ │ └── models.py │ ├── udi │ │ ├── __init__.py │ │ └── schemas │ │ │ ├── __init__.py │ │ │ └── models.py │ ├── udisk │ │ ├── __init__.py │ │ └── schemas │ │ │ └── __init__.py │ ├── udns │ │ ├── __init__.py │ │ └── schemas │ │ │ ├── __init__.py │ │ │ └── models.py │ ├── udpn │ │ ├── __init__.py │ │ └── schemas │ │ │ ├── __init__.py │ │ │ └── models.py │ ├── udts │ │ ├── __init__.py │ │ └── schemas │ │ │ ├── __init__.py │ │ │ └── models.py │ ├── uec │ │ ├── __init__.py │ │ └── schemas │ │ │ └── __init__.py │ ├── ufile │ │ ├── __init__.py │ │ └── schemas │ │ │ └── __init__.py │ ├── ufs │ │ ├── __init__.py │ │ └── schemas │ │ │ ├── __init__.py │ │ │ └── models.py │ ├── ugn │ │ ├── __init__.py │ │ └── schemas │ │ │ └── __init__.py │ ├── uhost │ │ ├── __init__.py │ │ └── schemas │ │ │ └── __init__.py │ ├── uhub │ │ ├── __init__.py │ │ └── schemas │ │ │ ├── __init__.py │ │ │ └── models.py │ ├── uk8s │ │ ├── __init__.py │ │ └── schemas │ │ │ └── __init__.py │ ├── ulb │ │ ├── __init__.py │ │ └── schemas │ │ │ └── __init__.py │ ├── umem │ │ ├── __init__.py │ │ └── schemas │ │ │ └── __init__.py │ ├── unet │ │ ├── __init__.py │ │ └── schemas │ │ │ └── __init__.py │ ├── unvs │ │ ├── __init__.py │ │ ├── schemas │ │ │ ├── __init__.py │ │ │ ├── models.py │ │ │ └── apis.py │ │ └── client.py │ ├── upfs │ │ ├── __init__.py │ │ └── schemas │ │ │ ├── __init__.py │ │ │ └── models.py │ ├── uslk │ │ ├── __init__.py │ │ └── schemas │ │ │ ├── __init__.py │ │ │ └── models.py │ ├── usms │ │ ├── __init__.py │ │ └── schemas │ │ │ └── __init__.py │ ├── utsdb │ │ ├── __init__.py │ │ └── schemas │ │ │ ├── __init__.py │ │ │ └── models.py │ ├── uvms │ │ ├── __init__.py │ │ ├── schemas │ │ │ ├── __init__.py │ │ │ ├── models.py │ │ │ └── apis.py │ │ └── client.py │ ├── vpc │ │ ├── __init__.py │ │ └── schemas │ │ │ └── __init__.py │ ├── ipsecvpn │ │ ├── __init__.py │ │ └── schemas │ │ │ └── __init__.py │ ├── ipv6gw │ │ ├── __init__.py │ │ ├── schemas │ │ │ ├── __init__.py │ │ │ ├── models.py │ │ │ └── apis.py │ │ └── client.py │ ├── stepflow │ │ ├── __init__.py │ │ ├── schemas │ │ │ ├── __init__.py │ │ │ ├── models.py │ │ │ └── apis.py │ │ └── client.py │ ├── uaccount │ │ ├── __init__.py │ │ └── schemas │ │ │ └── __init__.py │ ├── ucompshare │ │ ├── __init__.py │ │ └── schemas │ │ │ └── __init__.py │ ├── udbproxy │ │ ├── __init__.py │ │ ├── schemas │ │ │ ├── __init__.py │ │ │ ├── apis.py │ │ │ └── models.py │ │ └── client.py │ ├── ulighthost │ │ ├── __init__.py │ │ └── schemas │ │ │ └── __init__.py │ ├── umongodb │ │ ├── __init__.py │ │ └── schemas │ │ │ └── __init__.py │ ├── upgsql │ │ ├── __init__.py │ │ └── schemas │ │ │ └── __init__.py │ ├── uphone │ │ ├── __init__.py │ │ └── schemas │ │ │ └── __init__.py │ ├── uphost │ │ ├── __init__.py │ │ └── schemas │ │ │ └── __init__.py │ ├── urocketmq │ │ ├── __init__.py │ │ ├── schemas │ │ │ ├── __init__.py │ │ │ ├── models.py │ │ │ └── apis.py │ │ └── client.py │ └── ucloudstack │ │ ├── __init__.py │ │ └── schemas │ │ └── __init__.py ├── testing │ ├── __init__.py │ ├── driver │ │ ├── __init__.py │ │ ├── _specification.py │ │ └── _scenario.py │ ├── exc.py │ ├── env.py │ ├── mock.py │ ├── funcs.py │ └── op.py └── version.py ├── VERSION ├── docs ├── _static │ └── .gitkeep ├── helpers.rst ├── core.rst ├── Makefile ├── index.rst ├── quick_start.rst ├── conf.py └── usage.rst ├── examples ├── auth │ ├── __init__.py │ ├── README.md │ └── main.py ├── uhost │ ├── __init__.py │ ├── README.md │ └── main.py └── two-tier │ ├── __init__.py │ ├── README.md │ └── main.py ├── requirements.txt ├── pytest.ini ├── .github └── PULL_REQUEST_TEMPLATE.md ├── .editorconfig ├── .travis.yml ├── scripts └── codegen.sh ├── README.md ├── .gitignore ├── Makefile └── setup.py /tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | 0.11.34 2 | -------------------------------------------------------------------------------- /docs/_static/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/core/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/auth/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/uhost/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/test_unit/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/helpers/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/testing/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/two-tier/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | requests 2 | -------------------------------------------------------------------------------- /tests/test_services/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/core/utils/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/cube/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/iam/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/isms/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/pathx/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/sts/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/tidb/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/uaaa/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/uads/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/ubill/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/ucdn/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/udb/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/uddb/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/udi/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/udisk/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/udns/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/udpn/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/udts/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/uec/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/ufile/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/ufs/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/ugn/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/uhost/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/uhub/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/uk8s/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/ulb/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/umem/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/unet/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/unvs/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/upfs/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/uslk/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/usms/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/utsdb/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/uvms/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/vpc/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/test_unit/test_core/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/core/typesystem/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/ipsecvpn/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/ipv6gw/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/stepflow/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/uaccount/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/ucompshare/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/udbproxy/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/ulighthost/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/umongodb/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/upgsql/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/uphone/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/uphost/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/urocketmq/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/test_unit/test_helpers/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/test_unit/test_testing/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/cube/schemas/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/iam/schemas/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/ipv6gw/schemas/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/isms/schemas/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/pathx/schemas/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/sts/schemas/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/tidb/schemas/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/uaaa/schemas/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/uads/schemas/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/ubill/schemas/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/ucdn/schemas/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/ucloudstack/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/udb/schemas/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/uddb/schemas/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/udi/schemas/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/udisk/schemas/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/udns/schemas/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/udpn/schemas/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/udts/schemas/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/uec/schemas/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/ufile/schemas/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/ufs/schemas/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/ugn/schemas/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/uhost/schemas/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/uhub/schemas/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/uk8s/schemas/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/ulb/schemas/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/umem/schemas/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/unet/schemas/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/unvs/schemas/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/upfs/schemas/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/upgsql/schemas/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/uphone/schemas/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/uphost/schemas/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/uslk/schemas/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/usms/schemas/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/utsdb/schemas/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/uvms/schemas/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/vpc/schemas/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/version.py: -------------------------------------------------------------------------------- 1 | version = "0.11.81" 2 | -------------------------------------------------------------------------------- /ucloud/services/ipsecvpn/schemas/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/stepflow/schemas/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/uaccount/schemas/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/ucloudstack/schemas/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/ucompshare/schemas/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/udbproxy/schemas/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/ulighthost/schemas/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/umongodb/schemas/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ucloud/services/urocketmq/schemas/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/test_unit/test_core/consts.py: -------------------------------------------------------------------------------- 1 | TEST_URL = "https://api.ucloud.cn/" 2 | -------------------------------------------------------------------------------- /pytest.ini: -------------------------------------------------------------------------------- 1 | [pytest] 2 | log_cli = 1 3 | log_cli_level = INFO 4 | testpaths = tests 5 | addopts = -v 6 | -------------------------------------------------------------------------------- /ucloud/core/auth/__init__.py: -------------------------------------------------------------------------------- 1 | from ucloud.core.auth._cfg import Credential 2 | 3 | __all__ = ["Credential"] 4 | -------------------------------------------------------------------------------- /ucloud/services/ipv6gw/schemas/models.py: -------------------------------------------------------------------------------- 1 | """ Code is generated by ucloud-model, DO NOT EDIT IT. """ 2 | 3 | from ucloud.core.typesystem import schema, fields 4 | -------------------------------------------------------------------------------- /ucloud/testing/driver/__init__.py: -------------------------------------------------------------------------------- 1 | from ._specification import Specification 2 | from ._scenario import Scenario 3 | from ._step import Step 4 | 5 | spec = Specification() 6 | -------------------------------------------------------------------------------- /ucloud/core/client/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Client 3 | """ 4 | 5 | from ucloud.core.client._cfg import Config 6 | from ucloud.core.client._client import Client 7 | 8 | __all__ = ["Config", "Client"] 9 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | FEATURES: 4 | 5 | ENHANCEMENTS: 6 | 7 | BUG FIXES: 8 | -------------------------------------------------------------------------------- /examples/auth/README.md: -------------------------------------------------------------------------------- 1 | # UCloud SDK Auth Example 2 | 3 | ## What is the goal 4 | 5 | Create signature from request payload. 6 | 7 | ## Setup Environment 8 | 9 | Don't need. 10 | 11 | ## How to run 12 | 13 | ```sh 14 | python main.py 15 | ``` 16 | -------------------------------------------------------------------------------- /docs/helpers.rst: -------------------------------------------------------------------------------- 1 | Helpers 2 | ======= 3 | 4 | Wait Resource State 5 | ------------------- 6 | 7 | .. autofunction:: ucloud.helpers.wait.wait_for_state 8 | 9 | Utilities 10 | --------- 11 | 12 | .. automodule:: ucloud.helpers.utils 13 | :members: 14 | -------------------------------------------------------------------------------- /ucloud/core/transport/__init__.py: -------------------------------------------------------------------------------- 1 | from ucloud.core.transport.http import Request, Response, Transport, SSLOption 2 | from ucloud.core.transport._requests import RequestsTransport 3 | 4 | __all__ = ["Request", "Response", "Transport", "RequestsTransport", "SSLOption"] 5 | -------------------------------------------------------------------------------- /tests/test_unit/test_core/test_deco.py: -------------------------------------------------------------------------------- 1 | from ucloud.core.utils.deco import deprecated 2 | 3 | 4 | @deprecated(instead_of="bar") 5 | def foo(): 6 | pass 7 | 8 | 9 | def test_deprecated_deco(caplog): 10 | foo() 11 | assert "deprecated" in caplog.text 12 | -------------------------------------------------------------------------------- /ucloud/core/exc/__init__.py: -------------------------------------------------------------------------------- 1 | from ucloud.core.exc._exc import ( 2 | UCloudException, 3 | ValidationException, 4 | RetCodeException, 5 | RetryTimeoutException, 6 | TransportException, 7 | HTTPStatusException, 8 | InvalidResponseException, 9 | ) 10 | -------------------------------------------------------------------------------- /tests/test_unit/test_helpers/test_utils.py: -------------------------------------------------------------------------------- 1 | from ucloud.helpers import utils 2 | 3 | 4 | def test_b64encode(): 5 | encoded = utils.b64encode("foobar42") 6 | assert encoded == "Zm9vYmFyNDI=" 7 | 8 | 9 | def test_b64decode(): 10 | decoded = utils.b64decode("Zm9vYmFyNDI=") 11 | assert decoded == "foobar42" 12 | -------------------------------------------------------------------------------- /ucloud/services/tidb/schemas/models.py: -------------------------------------------------------------------------------- 1 | """ Code is generated by ucloud-model, DO NOT EDIT IT. """ 2 | 3 | from ucloud.core.typesystem import schema, fields 4 | 5 | 6 | class ServiceIDSchema(schema.ResponseSchema): 7 | """ServiceID - 服务ID""" 8 | 9 | fields = { 10 | "Id": fields.Str(required=True, load_from="Id"), 11 | } 12 | -------------------------------------------------------------------------------- /ucloud/core/utils/compat.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | PY3 = sys.version_info[0] == 3 4 | 5 | if PY3: 6 | str = str 7 | string_types = (str,) 8 | from collections.abc import Callable 9 | else: 10 | import types 11 | 12 | str = unicode # noqa: F821 13 | string_types = types.StringTypes 14 | 15 | from collections import Callable 16 | -------------------------------------------------------------------------------- /ucloud/testing/exc.py: -------------------------------------------------------------------------------- 1 | class UTestError(Exception): 2 | pass 3 | 4 | 5 | class ValidateError(UTestError): 6 | def __init__(self, errors): 7 | self.errors = errors 8 | 9 | def __str__(self): 10 | return str(self.errors) 11 | 12 | 13 | class ValueNotFoundError(UTestError): 14 | pass 15 | 16 | 17 | class CompareError(UTestError): 18 | pass 19 | -------------------------------------------------------------------------------- /examples/auth/main.py: -------------------------------------------------------------------------------- 1 | from ucloud.core import auth 2 | 3 | 4 | def main(): 5 | cred = auth.Credential( 6 | "ucloudsomeone@example.com1296235120854146120", 7 | "46f09bb9fab4f12dfc160dae12273d5332b5debe", 8 | ) 9 | d = {"Action": "DescribeUHostInstance", "Region": "cn-bj2", "Limit": 10} 10 | print(cred.verify_ac(d)) 11 | 12 | 13 | if __name__ == "__main__": 14 | main() 15 | -------------------------------------------------------------------------------- /examples/uhost/README.md: -------------------------------------------------------------------------------- 1 | # UCloud SDK UHost Example 2 | 3 | ## What is the goal 4 | 5 | Create an uhost, wait it created, and remove all example data. 6 | 7 | ## Setup Environment 8 | 9 | ```go 10 | export UCLOUD_PUBLIC_KEY="your public key" 11 | export UCLOUD_PRIVATE_KEY="your private key" 12 | export UCLOUD_PROJECT_ID="your project id" 13 | ``` 14 | 15 | ## How to run 16 | 17 | ```sh 18 | python main.py 19 | ``` 20 | -------------------------------------------------------------------------------- /examples/two-tier/README.md: -------------------------------------------------------------------------------- 1 | # UCloud SDK Two-Tier Example 2 | 3 | ## What is the goal 4 | 5 | Build a two-tier architecture with ulb and uhost, and remove all example data. 6 | 7 | ## Setup Environment 8 | 9 | ```go 10 | export UCLOUD_PUBLIC_KEY="your public key" 11 | export UCLOUD_PRIVATE_KEY="your private key" 12 | export UCLOUD_PROJECT_ID="your project id" 13 | ``` 14 | 15 | ## How to run 16 | 17 | ```sh 18 | python main.py 19 | ``` 20 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | indent_style = space 7 | indent_size = 4 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | charset = utf-8 11 | end_of_line = lf 12 | 13 | [*.bat] 14 | indent_style = tab 15 | end_of_line = crlf 16 | 17 | [LICENSE] 18 | insert_final_newline = false 19 | 20 | [Makefile] 21 | indent_style = tab 22 | 23 | [*.{diff,patch}] 24 | trim_trailing_whitespace = false 25 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # Config file for automatic testing at travis-ci.org 2 | 3 | language: python 4 | python: 5 | - 3.7 6 | - 3.6 7 | - 3.5 8 | dist: xenial 9 | sudo: true 10 | 11 | # command to install dependencies, e.g. pip install -r requirements.txt --use-mirrors 12 | install: pip install -e .[ci] 13 | 14 | # command to run tests, e.g. python setup.py test 15 | script: 16 | - make lint 17 | - make test-cov 18 | # - make release-check 19 | 20 | after_success: 21 | - bash <(curl -s https://codecov.io/bash) 22 | -------------------------------------------------------------------------------- /tests/test_unit/test_core/test_exc.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from ucloud.core import exc 3 | 4 | 5 | def test_ret_code_error(): 6 | assert not exc.UCloudException().retryable 7 | 8 | code_error = exc.RetCodeException("Foo", 1, "") 9 | assert str(code_error) 10 | assert not code_error.retryable 11 | assert code_error.json() == {"Action": "Foo", "Message": "", "RetCode": 1} 12 | 13 | validate_error = exc.ValidationException(ValueError("invalid type")) 14 | assert not validate_error.retryable 15 | assert str(validate_error) 16 | -------------------------------------------------------------------------------- /tests/test_unit/test_helpers/test_wait.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from ucloud.helpers import wait 4 | 5 | 6 | def test_wait(): 7 | with pytest.raises(wait.WaitTimeoutException): 8 | wait.wait_for_state( 9 | pending=["pending"], 10 | target=["running"], 11 | refresh=lambda: "pending", 12 | timeout=0.5, 13 | ) 14 | 15 | wait.wait_for_state( 16 | pending=["pending"], 17 | target=["running"], 18 | refresh=lambda: "running", 19 | timeout=0.5, 20 | ) 21 | -------------------------------------------------------------------------------- /ucloud/services/unvs/schemas/models.py: -------------------------------------------------------------------------------- 1 | """ Code is generated by ucloud-model, DO NOT EDIT IT. """ 2 | 3 | from ucloud.core.typesystem import schema, fields 4 | 5 | 6 | class PhoneInfoSchema(schema.ResponseSchema): 7 | """PhoneInfo - 号码信息""" 8 | 9 | fields = { 10 | "Phone": fields.Str(required=False, load_from="Phone"), 11 | } 12 | 13 | 14 | class VerifyInfoSchema(schema.ResponseSchema): 15 | """VerifyInfo - 检测结果信息""" 16 | 17 | fields = { 18 | "VerifyResult": fields.Str(required=False, load_from="VerifyResult"), 19 | } 20 | -------------------------------------------------------------------------------- /ucloud/services/urocketmq/schemas/models.py: -------------------------------------------------------------------------------- 1 | """ Code is generated by ucloud-model, DO NOT EDIT IT. """ 2 | 3 | from ucloud.core.typesystem import schema, fields 4 | 5 | 6 | class GroupBaseInfoSchema(schema.ResponseSchema): 7 | """GroupBaseInfo - Group基础信息""" 8 | 9 | fields = { 10 | "CreateTime": fields.Int(required=True, load_from="CreateTime"), 11 | "GroupName": fields.Str(required=True, load_from="GroupName"), 12 | "Id": fields.Str(required=True, load_from="Id"), 13 | "Remark": fields.Str(required=True, load_from="Remark"), 14 | } 15 | -------------------------------------------------------------------------------- /docs/core.rst: -------------------------------------------------------------------------------- 1 | Core 2 | ==== 3 | 4 | Config 5 | ------ 6 | 7 | .. autoclass:: ucloud.core.auth.Credential 8 | :members: 9 | 10 | .. autoclass:: ucloud.core.client.Config 11 | :members: 12 | 13 | Client 14 | ------ 15 | 16 | .. autoclass:: ucloud.core.client.Client 17 | :members: 18 | 19 | Transport 20 | --------- 21 | 22 | .. autoclass:: ucloud.core.transport.RequestsTransport 23 | :members: 24 | 25 | Middleware 26 | ---------- 27 | 28 | .. autoclass:: ucloud.core.utils.middleware.Middleware 29 | :members: 30 | 31 | Testing 32 | ------- 33 | 34 | .. automodule:: ucloud.core.testing.env 35 | :members: 36 | -------------------------------------------------------------------------------- /ucloud/services/sts/schemas/models.py: -------------------------------------------------------------------------------- 1 | """ Code is generated by ucloud-model, DO NOT EDIT IT. """ 2 | 3 | from ucloud.core.typesystem import schema, fields 4 | 5 | 6 | class CredentialsSchema(schema.ResponseSchema): 7 | """Credentials -""" 8 | 9 | fields = { 10 | "AccessKeyId": fields.Str(required=True, load_from="AccessKeyId"), 11 | "AccessKeySecret": fields.Str( 12 | required=True, load_from="AccessKeySecret" 13 | ), 14 | "Expiration": fields.Str(required=True, load_from="Expiration"), 15 | "SecurityToken": fields.Str(required=True, load_from="SecurityToken"), 16 | } 17 | -------------------------------------------------------------------------------- /scripts/codegen.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | #set -u 4 | set -e 5 | 6 | if [ -n "$PRODUCT" ]; then 7 | ucloud-model sync --lang python --product "$PRODUCT" 8 | ucloud-model sdk apis --type public --product "$PRODUCT" --lang python --template "$U_MODEL_HOME"/providers/python/templates/scripts-api.tpl --output scripts/gen-apis.sh 9 | bash ./scripts/gen-apis.sh 10 | fi 11 | 12 | if [ -n "$TEST" ]; then 13 | IFS=',' read -ra TL <<< "$TEST" 14 | for i in "${TL[@]}"; do 15 | ucloud-model sdk test --name "$i" --lang python --template "$U_MODEL_HOME"/providers/python/templates/testing.tpl --output tests/test_services/test_set_"$i".py 16 | done 17 | fi 18 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | SOURCEDIR = . 8 | BUILDDIR = build 9 | 10 | # Put it first so that "make" without argument is like "make help". 11 | help: 12 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 13 | 14 | .PHONY: help Makefile 15 | 16 | # Catch-all target: route all unknown targets to Sphinx using the new 17 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 18 | %: Makefile 19 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 20 | -------------------------------------------------------------------------------- /ucloud/core/utils/log.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | DEFAULT_LOGGER_NAME = "ucloud" 4 | DEFAULT_FORMAT = "%(asctime)s [%(levelname)8s] %(message)s (%(filename)s:%(lineno)s %(name)s)" 5 | DEFAULT_LEVEL = logging.INFO 6 | 7 | 8 | def init_default_logger(): 9 | logger = logging.getLogger(DEFAULT_LOGGER_NAME) 10 | logger.setLevel(DEFAULT_LEVEL) 11 | 12 | # create console handler and set level to debug 13 | ch = logging.StreamHandler() 14 | ch.setLevel(DEFAULT_LEVEL) 15 | 16 | # create formatter 17 | formatter = logging.Formatter(DEFAULT_FORMAT) 18 | 19 | # add formatter to ch 20 | ch.setFormatter(formatter) 21 | 22 | # add ch to logger 23 | logger.removeHandler(ch) 24 | logger.addHandler(ch) 25 | 26 | return logger 27 | 28 | 29 | default_logger = init_default_logger() 30 | -------------------------------------------------------------------------------- /ucloud/testing/env.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | ACC_ENV_KEY = "USDKACC" 4 | ACC_SKIP_REASON = "skip test for non-acc environment" 5 | 6 | 7 | def get_skip_reason(): 8 | return ACC_SKIP_REASON 9 | 10 | 11 | def is_acc() -> bool: 12 | """check test env is acceptance testing or not""" 13 | return os.getenv(ACC_ENV_KEY) 14 | 15 | 16 | def is_ut() -> bool: 17 | """check test env is unit testing or not""" 18 | return not is_acc() 19 | 20 | 21 | def pre_check_env(): 22 | """pre check environment for testing 23 | 24 | NOTE: system environment variables credential is required for test environment 25 | """ 26 | assert os.getenv("UCLOUD_PUBLIC_KEY"), "invalid public key" 27 | assert os.getenv("UCLOUD_PRIVATE_KEY"), "invalid private key" 28 | assert os.getenv("UCLOUD_PROJECT_ID"), "invalid region" 29 | -------------------------------------------------------------------------------- /tests/test_services/conftest.py: -------------------------------------------------------------------------------- 1 | import os 2 | import pytest 3 | 4 | from ucloud.client import Client 5 | 6 | 7 | @pytest.fixture(scope="session", autouse=True, name="client") 8 | def client_factory() -> Client: 9 | return Client( 10 | { 11 | "region": "cn-bj2", 12 | "project_id": os.getenv("UCLOUD_PROJECT_ID"), 13 | "public_key": os.getenv("UCLOUD_PUBLIC_KEY"), 14 | "private_key": os.getenv("UCLOUD_PRIVATE_KEY"), 15 | "max_retries": 10, 16 | "timeout": 60, 17 | } 18 | ) 19 | 20 | 21 | @pytest.fixture(scope="module", autouse=True, name="variables") 22 | def variables_factory() -> dict: 23 | return { 24 | "Region": "cn-bj2", 25 | "Zone": "cn-bj2-05", 26 | "ProjectId": os.getenv("UCLOUD_PROJECT_ID"), 27 | } 28 | -------------------------------------------------------------------------------- /tests/test_unit/test_core/test_encoder.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from ucloud.core.typesystem import encoder 4 | 5 | 6 | @pytest.mark.parametrize( 7 | "input_vector,expected", 8 | [ 9 | ({"foo": "bar"}, {"foo": "bar"}), 10 | ({"foo": 42}, {"foo": "42"}), 11 | ({"foo": 42.42}, {"foo": "42.42"}), 12 | ({"foo": 42.0}, {"foo": "42"}), 13 | ({"foo": True}, {"foo": "true"}), 14 | ({"foo": False}, {"foo": "false"}), 15 | ({"IP": ["127.0.0.1"]}, {"IP.0": "127.0.0.1"}), 16 | ({"TemplateParams": ["中文"]}, {"TemplateParams.0": "中文"}), 17 | ({"IP": ["foo", "bar"]}, {"IP.0": "foo", "IP.1": "bar"}), 18 | ({"IP": [{"foo": "bar"}]}, {"IP.0.foo": "bar"}), 19 | ], 20 | ) 21 | def test_params_encode(input_vector, expected): 22 | result = encoder.encode(input_vector) 23 | assert result == expected 24 | -------------------------------------------------------------------------------- /ucloud/core/utils/deco.py: -------------------------------------------------------------------------------- 1 | import functools 2 | import logging 3 | 4 | logger = logging.getLogger("ucloud") 5 | 6 | 7 | def deprecated(instead_of="", message=""): 8 | """deprecated is a decorator to mark a function is deprecated. 9 | it will logging warning when this function called 10 | 11 | >>> @deprecated(instead_of="new_function") 12 | ... def an_old_function(): 13 | ... pass 14 | """ 15 | 16 | def deco(fn): 17 | @functools.wraps(fn) 18 | def wrapper(*args, **kwargs): 19 | msg = [ 20 | "this function/method `{}` is deprecated".format(fn.__name__) 21 | ] 22 | instead_of and msg.append( 23 | "please use `{}` instead".format(instead_of) 24 | ) 25 | message and msg.append(message) 26 | logger.warning(", ".join(msg)) 27 | return fn(*args, **kwargs) 28 | 29 | return wrapper 30 | 31 | return deco 32 | -------------------------------------------------------------------------------- /ucloud/services/sts/schemas/apis.py: -------------------------------------------------------------------------------- 1 | """ Code is generated by ucloud-model, DO NOT EDIT IT. """ 2 | 3 | from ucloud.core.typesystem import schema, fields 4 | from ucloud.services.sts.schemas import models 5 | 6 | """ STS API Schema 7 | """ 8 | 9 | 10 | """ 11 | API: AssumeRole 12 | 13 | 获取扮演角色的临时身份凭证 14 | """ 15 | 16 | 17 | class AssumeRoleRequestSchema(schema.RequestSchema): 18 | """AssumeRole - 获取扮演角色的临时身份凭证""" 19 | 20 | fields = { 21 | "DurationSeconds": fields.Int( 22 | required=False, dump_to="DurationSeconds" 23 | ), 24 | "Policy": fields.Str(required=False, dump_to="Policy"), 25 | "RoleSessionName": fields.Str(required=True, dump_to="RoleSessionName"), 26 | "RoleUrn": fields.Str(required=True, dump_to="RoleUrn"), 27 | } 28 | 29 | 30 | class AssumeRoleResponseSchema(schema.ResponseSchema): 31 | """AssumeRole - 获取扮演角色的临时身份凭证""" 32 | 33 | fields = { 34 | "Credentials": models.CredentialsSchema(), 35 | } 36 | -------------------------------------------------------------------------------- /ucloud/testing/mock.py: -------------------------------------------------------------------------------- 1 | import json 2 | import typing 3 | 4 | from ucloud.core.transport import Transport, Request, Response 5 | 6 | 7 | class MockedTransport(Transport): 8 | def __init__(self): 9 | super(MockedTransport, self).__init__() 10 | self.transport_handlers = [] 11 | self.client_handler = [] 12 | 13 | def send(self, req: Request, **options: typing.Any) -> Response: 14 | resp = Response(req.url, req.method) 15 | for handler in self.transport_handlers: 16 | resp = handler(req) 17 | 18 | for handler in self.client_handler: 19 | payload = handler(req.payload()) 20 | resp.content = json.dumps(payload).encode("utf-8") 21 | 22 | return resp 23 | 24 | def mock(self, handler: typing.Callable[[Request], Response]): 25 | self.transport_handlers.append(handler) 26 | 27 | def mock_data(self, handler: typing.Callable[[dict], dict]): 28 | self.client_handler.append(handler) 29 | -------------------------------------------------------------------------------- /tests/test_unit/test_testing/test_utest.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from ucloud.testing import utest, env 4 | 5 | 6 | @pytest.mark.skipif(env.is_ut(), reason=env.get_skip_reason()) 7 | def test_acc_pre_check(self, client): 8 | assert str(client) 9 | assert client.config.to_dict() 10 | assert client.credential.to_dict() 11 | env.pre_check_env() 12 | 13 | 14 | def test_value_at_path(): 15 | d = { 16 | "Action": "DescribeEIPResponse", 17 | "EIPSet": [ 18 | { 19 | "Resource": { 20 | "ResourceID": "uhost-war3png3", 21 | "ResourceName": "eip-s1-bgp", 22 | "ResourceType": "uhost", 23 | "Zone": "cn-bj2-05", 24 | } 25 | } 26 | ], 27 | "RetCode": 0, 28 | "TotalBandwidth": 6, 29 | "TotalCount": 3, 30 | } 31 | assert ( 32 | utest.value_at_path(d, "EIPSet.0.Resource.ResourceID") 33 | == "uhost-war3png3" 34 | ) 35 | -------------------------------------------------------------------------------- /tests/test_unit/test_core/test_auth.py: -------------------------------------------------------------------------------- 1 | from ucloud.core import auth 2 | 3 | 4 | def test_verify_ac(): 5 | d = { 6 | "Action": "CreateUHostInstance", 7 | "CPU": 2, 8 | "ChargeType": "Month", 9 | "DiskSpace": 10, 10 | "ImageId": "f43736e1-65a5-4bea-ad2e-8a46e18883c2", 11 | "LoginMode": "Password", 12 | "Memory": 2048, 13 | "Name": "Host01", 14 | "Password": "VUNsb3VkLmNu", 15 | "PublicKey": "ucloudsomeone@example.com1296235120854146120", 16 | "Quantity": 1, 17 | "Region": "cn-bj2", 18 | "Zone": "cn-bj2-04", 19 | } 20 | cred = auth.Credential( 21 | "ucloudsomeone@example.com1296235120854146120", 22 | "46f09bb9fab4f12dfc160dae12273d5332b5debe", 23 | ) 24 | assert cred.verify_ac(d) == "4f9ef5df2abab2c6fccd1e9515cb7e2df8c6bb65" 25 | assert cred.to_dict() == { 26 | "public_key": "ucloudsomeone@example.com1296235120854146120", 27 | "private_key": "46f09bb9fab4f12dfc160dae12273d5332b5debe", 28 | } 29 | -------------------------------------------------------------------------------- /ucloud/services/ipv6gw/schemas/apis.py: -------------------------------------------------------------------------------- 1 | """ Code is generated by ucloud-model, DO NOT EDIT IT. """ 2 | 3 | from ucloud.core.typesystem import schema, fields 4 | from ucloud.services.ipv6gw.schemas import models 5 | 6 | """ ipv6gw API Schema 7 | """ 8 | 9 | 10 | """ 11 | API: ModifyIpv6InternetBandwidth 12 | 13 | 修改ipv6公网带宽值 14 | """ 15 | 16 | 17 | class ModifyIpv6InternetBandwidthRequestSchema(schema.RequestSchema): 18 | """ModifyIpv6InternetBandwidth - 修改ipv6公网带宽值""" 19 | 20 | fields = { 21 | "Bandwidth": fields.Int(required=False, dump_to="Bandwidth"), 22 | "InternetBandwidthId": fields.Str( 23 | required=False, dump_to="InternetBandwidthId" 24 | ), 25 | "Ipv6AddressId": fields.Str(required=False, dump_to="Ipv6AddressId"), 26 | "ProjectId": fields.Str(required=True, dump_to="ProjectId"), 27 | "Region": fields.Str(required=True, dump_to="Region"), 28 | } 29 | 30 | 31 | class ModifyIpv6InternetBandwidthResponseSchema(schema.ResponseSchema): 32 | """ModifyIpv6InternetBandwidth - 修改ipv6公网带宽值""" 33 | 34 | fields = {} 35 | -------------------------------------------------------------------------------- /ucloud/core/typesystem/encoder.py: -------------------------------------------------------------------------------- 1 | from ucloud.core.utils.compat import str 2 | 3 | 4 | def encode(d: dict) -> dict: 5 | result = {} 6 | 7 | for k, v in d.items(): 8 | if isinstance(v, dict): 9 | for ek, ev in encode(v).items(): 10 | result["{}.{}".format(k, ek)] = encode_value(ev) 11 | elif isinstance(v, list): 12 | for i, item in enumerate(v): 13 | if isinstance(item, dict): 14 | for ek, ev in encode(item).items(): 15 | result["{}.{}.{}".format(k, i, ek)] = encode_value(ev) 16 | else: 17 | result["{}.{}".format(k, i)] = encode_value(item) 18 | else: 19 | result[k] = encode_value(v) 20 | 21 | return result 22 | 23 | 24 | def encode_value(v): 25 | # bool only accept lower case 26 | if isinstance(v, bool): 27 | return "true" if v else "false" 28 | 29 | # api gateway will try to decode float as int in lua syntax 30 | if isinstance(v, float): 31 | return str(int(v)) if v % 1 == 0 else str(v) 32 | 33 | return str(v) 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | 5 |

UCloud SDK Python 3

6 | 7 |

8 | Latest Stable Version 9 | Travis CI Status 10 | Codecov Status 11 | Doc Status 12 |

13 | 14 | UCloud SDK is a Python client library for accessing the UCloud API. 15 | 16 | This client can run on Linux, macOS and Windows. 17 | 18 | - Website: https://www.ucloud.cn/ 19 | - Free software: Apache 2.0 license 20 | - [Documentation](https://docs.ucloud.cn/opensdk-python/) 21 | -------------------------------------------------------------------------------- /ucloud/services/udbproxy/schemas/apis.py: -------------------------------------------------------------------------------- 1 | """ Code is generated by ucloud-model, DO NOT EDIT IT. """ 2 | 3 | from ucloud.core.typesystem import schema, fields 4 | from ucloud.services.udbproxy.schemas import models 5 | 6 | """ UDBProxy API Schema 7 | """ 8 | 9 | 10 | """ 11 | API: ListUDBProxyClient 12 | 13 | 查询代理客户端连接IP信息(实时) 14 | """ 15 | 16 | 17 | class ListUDBProxyClientRequestSchema(schema.RequestSchema): 18 | """ListUDBProxyClient - 查询代理客户端连接IP信息(实时)""" 19 | 20 | fields = { 21 | "ProjectId": fields.Str(required=False, dump_to="ProjectId"), 22 | "Region": fields.Str(required=True, dump_to="Region"), 23 | "UDBProxyID": fields.Str(required=True, dump_to="UDBProxyID"), 24 | "Zone": fields.Str(required=True, dump_to="Zone"), 25 | } 26 | 27 | 28 | class ListUDBProxyClientResponseSchema(schema.ResponseSchema): 29 | """ListUDBProxyClient - 查询代理客户端连接IP信息(实时)""" 30 | 31 | fields = { 32 | "NodeClientInfos": fields.List( 33 | models.NodeClientInfoSchema(), 34 | required=True, 35 | load_from="NodeClientInfos", 36 | ), 37 | "UDBProxyID": fields.Str(required=True, load_from="UDBProxyID"), 38 | } 39 | -------------------------------------------------------------------------------- /ucloud/services/udpn/schemas/models.py: -------------------------------------------------------------------------------- 1 | """ Code is generated by ucloud-model, DO NOT EDIT IT. """ 2 | 3 | from ucloud.core.typesystem import schema, fields 4 | 5 | 6 | class UDPNDataSchema(schema.ResponseSchema): 7 | """UDPNData - UDPN 详细信息""" 8 | 9 | fields = { 10 | "Bandwidth": fields.Int(required=True, load_from="Bandwidth"), 11 | "ChargeType": fields.Str(required=True, load_from="ChargeType"), 12 | "CreateTime": fields.Int(required=True, load_from="CreateTime"), 13 | "ExpireTime": fields.Int(required=True, load_from="ExpireTime"), 14 | "Peer1": fields.Str(required=True, load_from="Peer1"), 15 | "Peer2": fields.Str(required=True, load_from="Peer2"), 16 | "UDPNId": fields.Str(required=True, load_from="UDPNId"), 17 | } 18 | 19 | 20 | class UDPNLineSetSchema(schema.ResponseSchema): 21 | """UDPNLineSet - GetUDPNLineList""" 22 | 23 | fields = { 24 | "BandwidthUpperLimit": fields.Int( 25 | required=True, load_from="BandwidthUpperLimit" 26 | ), 27 | "LocalRegion": fields.Str(required=True, load_from="LocalRegion"), 28 | "RemoteRegion": fields.Str(required=True, load_from="RemoteRegion"), 29 | } 30 | -------------------------------------------------------------------------------- /ucloud/services/udbproxy/schemas/models.py: -------------------------------------------------------------------------------- 1 | """ Code is generated by ucloud-model, DO NOT EDIT IT. """ 2 | 3 | from ucloud.core.typesystem import schema, fields 4 | 5 | 6 | class ProxyProcesslistSchema(schema.ResponseSchema): 7 | """ProxyProcesslist - 连接代理信息""" 8 | 9 | fields = { 10 | "ClientHost": fields.Str(required=True, load_from="ClientHost"), 11 | "Command": fields.Str(required=True, load_from="Command"), 12 | "DB": fields.Str(required=True, load_from="DB"), 13 | "DBID": fields.Str(required=True, load_from="DBID"), 14 | "Host": fields.Str(required=True, load_from="Host"), 15 | "ID": fields.Int(required=True, load_from="ID"), 16 | "Info": fields.Str(required=True, load_from="Info"), 17 | "Role": fields.Str(required=True, load_from="Role"), 18 | "State": fields.Str(required=True, load_from="State"), 19 | "Time": fields.Int(required=True, load_from="Time"), 20 | "User": fields.Str(required=True, load_from="User"), 21 | } 22 | 23 | 24 | class NodeClientInfoSchema(schema.ResponseSchema): 25 | """NodeClientInfo - 代理节点来源IP信息""" 26 | 27 | fields = { 28 | "ID": fields.Str(required=False, load_from="ID"), 29 | "IP": fields.Str(required=False, load_from="IP"), 30 | "Records": fields.List(ProxyProcesslistSchema()), 31 | } 32 | -------------------------------------------------------------------------------- /ucloud/services/stepflow/schemas/models.py: -------------------------------------------------------------------------------- 1 | """ Code is generated by ucloud-model, DO NOT EDIT IT. """ 2 | 3 | from ucloud.core.typesystem import schema, fields 4 | 5 | 6 | class ParamSchema(schema.ResponseSchema): 7 | """Param - 工作流参数""" 8 | 9 | fields = { 10 | "Name": fields.Str(required=False, load_from="Name"), 11 | "Type": fields.Str(required=False, load_from="Type"), 12 | "Value": fields.Str(required=False, load_from="Value"), 13 | } 14 | 15 | 16 | class ActivityTemplateSchema(schema.ResponseSchema): 17 | """ActivityTemplate - 工作流的Activity定义""" 18 | 19 | fields = { 20 | "Input": fields.Str(), 21 | "Name": fields.Str(required=False, load_from="Name"), 22 | "Next": fields.Str(required=False, load_from="Next"), 23 | "Output": fields.List(fields.Str()), 24 | "RetryTimes": fields.Str(required=False, load_from="RetryTimes"), 25 | "Timeout": fields.Str(required=False, load_from="Timeout"), 26 | "Type": fields.Str(required=False, load_from="Type"), 27 | } 28 | 29 | 30 | class WorkflowTemplateSchema(schema.ResponseSchema): 31 | """WorkflowTemplate - Workflow对象定义""" 32 | 33 | fields = { 34 | "Activites": fields.List(ActivityTemplateSchema()), 35 | "Input": fields.List(ParamSchema()), 36 | "Output": fields.List(ParamSchema()), 37 | } 38 | -------------------------------------------------------------------------------- /ucloud/services/sts/client.py: -------------------------------------------------------------------------------- 1 | """ Code is generated by ucloud-model, DO NOT EDIT IT. """ 2 | 3 | import typing 4 | 5 | 6 | from ucloud.core.client import Client 7 | from ucloud.services.sts.schemas import apis 8 | 9 | 10 | class STSClient(Client): 11 | def __init__( 12 | self, config: dict, transport=None, middleware=None, logger=None 13 | ): 14 | super(STSClient, self).__init__(config, transport, middleware, logger) 15 | 16 | def assume_role(self, req: typing.Optional[dict] = None, **kwargs) -> dict: 17 | """AssumeRole - 获取扮演角色的临时身份凭证 18 | 19 | **Request** 20 | 21 | - **RoleSessionName** (str) - (Required) 角色会话名称。 22 | - **RoleUrn** (str) - (Required) 要扮演的RAM角色URN。 23 | - **DurationSeconds** (int) - Token有效期。 24 | - **Policy** (str) - 为STS Token额外添加的一个权限策略,进一步限制STS Token的权限。 25 | 26 | **Response** 27 | 28 | - **Credentials** (dict) - 见 **Credentials** 模型定义 29 | 30 | **Response Model** 31 | 32 | **Credentials** 33 | - **AccessKeyId** (str) - 密钥ID。 34 | - **AccessKeySecret** (str) - 密钥Secret。 35 | - **Expiration** (str) - Token到期失效时间(UTC时间)。 36 | - **SecurityToken** (str) - 安全令牌。 37 | 38 | 39 | """ 40 | # build request 41 | d = {} 42 | req and d.update(req) 43 | d = apis.AssumeRoleRequestSchema().dumps(d) 44 | 45 | resp = self.invoke("AssumeRole", d, **kwargs) 46 | return apis.AssumeRoleResponseSchema().loads(resp) 47 | -------------------------------------------------------------------------------- /tests/test_acceptance/conftest.py: -------------------------------------------------------------------------------- 1 | import json 2 | import os 3 | import pytest 4 | 5 | from ucloud.testing.driver import spec 6 | from ucloud.client import Client 7 | 8 | 9 | @pytest.fixture(scope="session", autouse=True) 10 | def ustack_client() -> Client: 11 | return Client( 12 | { 13 | "base_url": "http://console.pre.ucloudstack.com/api", 14 | "region": "cn", 15 | "public_key": os.getenv("UCLOUDSTACK_PUBLIC_KEY"), 16 | "private_key": os.getenv("UCLOUDSTACK_PRIVATE_KEY"), 17 | "max_retries": 10, 18 | "timeout": 60, 19 | } 20 | ) 21 | 22 | 23 | @pytest.fixture(scope="session", autouse=True) 24 | def client() -> Client: 25 | return Client( 26 | { 27 | "region": "cn-bj2", 28 | "project_id": os.getenv("UCLOUD_PROJECT_ID"), 29 | "public_key": os.getenv("UCLOUD_PUBLIC_KEY"), 30 | "private_key": os.getenv("UCLOUD_PRIVATE_KEY"), 31 | "max_retries": 10, 32 | "timeout": 60, 33 | } 34 | ) 35 | 36 | 37 | @pytest.fixture(scope="module", autouse=True, name="variables") 38 | def variables_factory() -> dict: 39 | return { 40 | "Region": "cn-bj2", 41 | "Zone": "cn-bj2-05", 42 | "ProjectId": os.getenv("UCLOUD_PROJECT_ID"), 43 | } 44 | 45 | 46 | @pytest.fixture(scope="session", autouse=True) 47 | def save_report(request): 48 | def save_report_handler(): 49 | with open("./report.json", "w") as f: 50 | json.dump(spec.json(), f) 51 | 52 | request.addfinalizer(save_report_handler) 53 | -------------------------------------------------------------------------------- /ucloud/core/transport/utils.py: -------------------------------------------------------------------------------- 1 | import codecs 2 | 3 | # Null bytes; no need to recreate these on each call to guess_json_utf 4 | _null = "\x00".encode("ascii") # encoding to ASCII for Python 3 5 | _null2 = _null * 2 6 | _null3 = _null * 3 7 | 8 | 9 | def guess_json_utf(data): 10 | """guess_json_utf will detect the encoding of bytes, 11 | see `requests.utils.guess_json_utf` 12 | 13 | :rtype: str 14 | """ 15 | # JSON always starts with two ASCII characters, so detection is as 16 | # easy as counting the nulls and from their location and count 17 | # determine the encoding. Also detect a BOM, if present. 18 | sample = data[:4] 19 | if sample in (codecs.BOM_UTF32_LE, codecs.BOM_UTF32_BE): 20 | return "utf-32" # BOM included 21 | if sample[:3] == codecs.BOM_UTF8: 22 | return "utf-8-sig" # BOM included, MS style (discouraged) 23 | if sample[:2] in (codecs.BOM_UTF16_LE, codecs.BOM_UTF16_BE): 24 | return "utf-16" # BOM included 25 | nullcount = sample.count(_null) 26 | if nullcount == 0: 27 | return "utf-8" 28 | if nullcount == 2: 29 | if sample[::2] == _null2: # 1st and 3rd are null 30 | return "utf-16-be" 31 | if sample[1::2] == _null2: # 2nd and 4th are null 32 | return "utf-16-le" 33 | # Did not detect 2 valid UTF-16 ascii-range characters 34 | if nullcount == 3: 35 | if sample[:3] == _null3: 36 | return "utf-32-be" 37 | if sample[1:] == _null3: 38 | return "utf-32-le" 39 | # Did not detect a valid UTF-32 ascii-range character 40 | return None 41 | -------------------------------------------------------------------------------- /ucloud/services/uhub/schemas/models.py: -------------------------------------------------------------------------------- 1 | """ Code is generated by ucloud-model, DO NOT EDIT IT. """ 2 | 3 | from ucloud.core.typesystem import schema, fields 4 | 5 | 6 | class TagSetSchema(schema.ResponseSchema): 7 | """TagSet - Tag详细信息""" 8 | 9 | fields = { 10 | "Digest": fields.Str(required=False, load_from="Digest"), 11 | "TagName": fields.Str(required=True, load_from="TagName"), 12 | "UpdateTime": fields.Str(required=True, load_from="UpdateTime"), 13 | } 14 | 15 | 16 | class RepoSetSchema(schema.ResponseSchema): 17 | """RepoSet - 镜像仓库""" 18 | 19 | fields = { 20 | "CreateTime": fields.Str(required=True, load_from="CreateTime"), 21 | "Description": fields.Str(required=True, load_from="Description"), 22 | "IsOutSide": fields.Str(required=True, load_from="IsOutSide"), 23 | "IsShared": fields.Str(required=True, load_from="IsShared"), 24 | "RepoName": fields.Str(required=True, load_from="RepoName"), 25 | "UpdateTime": fields.Str(required=True, load_from="UpdateTime"), 26 | } 27 | 28 | 29 | class ImageSetSchema(schema.ResponseSchema): 30 | """ImageSet - 镜像信息""" 31 | 32 | fields = { 33 | "CreateTime": fields.Str(required=True, load_from="CreateTime"), 34 | "ImageName": fields.Str(required=True, load_from="ImageName"), 35 | "LatestTag": fields.Str(required=True, load_from="LatestTag"), 36 | "PullCount": fields.Int(required=True, load_from="PullCount"), 37 | "RepoName": fields.Str(required=True, load_from="RepoName"), 38 | "UpdateTime": fields.Str(required=True, load_from="UpdateTime"), 39 | } 40 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | UCloud SDK Python 3 2 | =================== 3 | 4 | UCloud SDK is a Python client library for accessing the UCloud API. 5 | 6 | This client can run on Linux, macOS and Windows. 7 | 8 | - Website: https://www.ucloud.cn/ 9 | - Free software: Apache 2.0 license 10 | - `Documentation `_ 11 | 12 | .. image:: https://img.shields.io/pypi/v/ucloud-sdk-python3.svg 13 | :target: https://pypi.python.org/pypi/ucloud-sdk-python3/ 14 | :alt: Latest Version 15 | .. image:: https://travis-ci.org/ucloud/ucloud-sdk-python3.svg?branch=master 16 | :target: https://travis-ci.org/ucloud/ucloud-sdk-python3 17 | :alt: Travis CI Status 18 | .. image:: https://codecov.io/github/ucloud/ucloud-sdk-python3/coverage.svg?branch=master 19 | :target: https://codecov.io/github/ucloud/ucloud-sdk-python3?branch=master 20 | :alt: Codecov Status 21 | .. image:: https://img.shields.io/badge/docs-passing-brightgreen.svg 22 | :target: https://ucloud.github.io/ucloud-sdk-python3/ 23 | :alt: Doc Status 24 | 25 | Guide 26 | ----- 27 | 28 | .. toctree:: 29 | :maxdepth: 2 30 | 31 | quick_start 32 | usage 33 | 34 | .. include:: quick_start.rst 35 | 36 | API Reference 37 | ------------- 38 | 39 | .. toctree:: 40 | :maxdepth: 2 41 | 42 | services 43 | helpers 44 | core 45 | 46 | Indices and tables 47 | ------------------ 48 | 49 | * :ref:`genindex` 50 | * :ref:`search` 51 | 52 | Feedback & Contribution 53 | ----------------------- 54 | 55 | - `Issue `_ 56 | - `Pull Request `_ 57 | -------------------------------------------------------------------------------- /ucloud/services/ipv6gw/client.py: -------------------------------------------------------------------------------- 1 | """ Code is generated by ucloud-model, DO NOT EDIT IT. """ 2 | 3 | import typing 4 | 5 | 6 | from ucloud.core.client import Client 7 | from ucloud.services.ipv6gw.schemas import apis 8 | 9 | 10 | class ipv6gwClient(Client): 11 | def __init__( 12 | self, config: dict, transport=None, middleware=None, logger=None 13 | ): 14 | super(ipv6gwClient, self).__init__( 15 | config, transport, middleware, logger 16 | ) 17 | 18 | def modify_ipv_6internet_bandwidth( 19 | self, req: typing.Optional[dict] = None, **kwargs 20 | ) -> dict: 21 | """ModifyIpv6InternetBandwidth - 修改ipv6公网带宽值 22 | 23 | **Request** 24 | 25 | - **ProjectId** (str) - (Config) 项目ID。不填写为默认项目,子帐号必须填写。 请参考 `GetProjectList接口 `_ 26 | - **Region** (str) - (Config) 地域。 参见 `地域和可用区列表 `_ 27 | - **Bandwidth** (int) - 要修改为的出向带宽峰值。带宽值范围[1, 2000] 28 | - **InternetBandwidthId** (str) - ipv6公网带宽Id;与Ipv6AddressId二选一必填 29 | - **Ipv6AddressId** (str) - Ipv6地址 id;与InternetBandwidthId二选一必填 30 | 31 | **Response** 32 | 33 | 34 | """ 35 | # build request 36 | d = { 37 | "ProjectId": self.config.project_id, 38 | "Region": self.config.region, 39 | } 40 | req and d.update(req) 41 | d = apis.ModifyIpv6InternetBandwidthRequestSchema().dumps(d) 42 | 43 | resp = self.invoke("ModifyIpv6InternetBandwidth", d, **kwargs) 44 | return apis.ModifyIpv6InternetBandwidthResponseSchema().loads(resp) 45 | -------------------------------------------------------------------------------- /docs/quick_start.rst: -------------------------------------------------------------------------------- 1 | QuickStart 2 | ========== 3 | 4 | Installation 5 | ------------ 6 | 7 | Install with pip: 8 | 9 | .. code:: shell 10 | 11 | pip install ucloud-sdk-python3 12 | 13 | Install with source code: 14 | 15 | .. code:: shell 16 | 17 | clone https://github.com/ucloud/ucloud-sdk-python3.git 18 | cd ucloud-sdk-python3 19 | python setup.py install 20 | 21 | QuickStart 22 | ---------- 23 | 24 | Currently, user public key & private key is the only method of authenticating with the API. You could get your keys here: 25 | 26 | - `Key Generation `_ 27 | 28 | You can then use your keys to create a new client of uhost service: 29 | 30 | .. code-block:: python 31 | 32 | from ucloud.core import exc 33 | from ucloud.client import Client 34 | 35 | client = Client({ 36 | "region": "cn-bj2", 37 | "project_id": "...", 38 | "public_key": "...", 39 | "private_key": "...", 40 | }) 41 | 42 | try: 43 | resp = client.uhost().create_uhost_instance({ 44 | 'Name': 'sdk-python-quickstart', 45 | 'Zone': image["zone"], 46 | 'ImageId': image["image_id"], 47 | 'LoginMode': "Password", 48 | 'Password': utils.b64encode(utils.gen_password(20)), 49 | 'CPU': 1, 50 | 'Memory': 1, 51 | 'Disks': [{ 52 | 'Size': 10, 53 | 'Type': 'CLOUD_SSD' 54 | }], 55 | }) 56 | except exc.UCloudException as e: 57 | print(e) 58 | else: 59 | print(resp) 60 | 61 | .. note:: UHost created above cannot be accessed via Internet unless an EIP is created and bind to the UHost. 62 | -------------------------------------------------------------------------------- /ucloud/services/upfs/schemas/models.py: -------------------------------------------------------------------------------- 1 | """ Code is generated by ucloud-model, DO NOT EDIT IT. """ 2 | 3 | from ucloud.core.typesystem import schema, fields 4 | 5 | 6 | class UPFSVolumeInfoSchema(schema.ResponseSchema): 7 | """UPFSVolumeInfo - UPFS文件系统信息""" 8 | 9 | fields = { 10 | "ChargeType": fields.Str(required=False, load_from="ChargeType"), 11 | "CreateTime": fields.Int(required=False, load_from="CreateTime"), 12 | "ExpiredTime": fields.Int(required=False, load_from="ExpiredTime"), 13 | "IsExpired": fields.Str(required=False, load_from="IsExpired"), 14 | "MountAddress": fields.Str(required=False, load_from="MountAddress"), 15 | "MountStatus": fields.Int(required=False, load_from="MountStatus"), 16 | "ProtocolType": fields.Str(required=False, load_from="ProtocolType"), 17 | "Remark": fields.Str(required=False, load_from="Remark"), 18 | "Size": fields.Int(required=False, load_from="Size"), 19 | "Tag": fields.Str(required=False, load_from="Tag"), 20 | "VolumeId": fields.Str(required=False, load_from="VolumeId"), 21 | "VolumeName": fields.Str(required=False, load_from="VolumeName"), 22 | "Zone": fields.Str(required=False, load_from="Zone"), 23 | } 24 | 25 | 26 | class UPFSPriceDataSetSchema(schema.ResponseSchema): 27 | """UPFSPriceDataSet - upfs 价格信息""" 28 | 29 | fields = { 30 | "ChargeName": fields.Str(required=False, load_from="ChargeName"), 31 | "ChargeType": fields.Str(required=False, load_from="ChargeType"), 32 | "OriginalPrice": fields.Float( 33 | required=False, load_from="OriginalPrice" 34 | ), 35 | "Price": fields.Float(required=False, load_from="Price"), 36 | } 37 | -------------------------------------------------------------------------------- /ucloud/services/uaaa/schemas/models.py: -------------------------------------------------------------------------------- 1 | """ Code is generated by ucloud-model, DO NOT EDIT IT. """ 2 | 3 | from ucloud.core.typesystem import schema, fields 4 | 5 | 6 | class AppRepoInstanceSchema(schema.ResponseSchema): 7 | """AppRepoInstance - 应用仓库实例""" 8 | 9 | fields = { 10 | "ChargeType": fields.Str(required=True, load_from="ChargeType"), 11 | "CreateTime": fields.Int(required=True, load_from="CreateTime"), 12 | "Description": fields.Str(required=True, load_from="Description"), 13 | "ExpireTime": fields.Int(required=True, load_from="ExpireTime"), 14 | "InstanceId": fields.Str(required=True, load_from="InstanceId"), 15 | "Name": fields.Str(required=True, load_from="Name"), 16 | "RecordName": fields.List(fields.Str()), 17 | "VPC": fields.List(fields.Str()), 18 | } 19 | 20 | 21 | class DomainInfoSchema(schema.ResponseSchema): 22 | """DomainInfo - 域名信息""" 23 | 24 | fields = { 25 | "Desc": fields.Str(required=False, load_from="Desc"), 26 | "DomainName": fields.Str(required=False, load_from="DomainName"), 27 | } 28 | 29 | 30 | class DomainDetailSchema(schema.ResponseSchema): 31 | """DomainDetail - 域名详细信息""" 32 | 33 | fields = { 34 | "Info": DomainInfoSchema(), 35 | "Redirect": fields.List(DomainInfoSchema()), 36 | } 37 | 38 | 39 | class TPostpaidBaseSchema(schema.ResponseSchema): 40 | """TPostpaidBase - 后付费记录""" 41 | 42 | fields = { 43 | "EndTime": fields.Int(required=True, load_from="EndTime"), 44 | "InstanceId": fields.Str(required=True, load_from="InstanceId"), 45 | "StartTime": fields.Int(required=True, load_from="StartTime"), 46 | "TrafficSum": fields.Int(required=True, load_from="TrafficSum"), 47 | } 48 | -------------------------------------------------------------------------------- /ucloud/core/typesystem/abstract.py: -------------------------------------------------------------------------------- 1 | import typing 2 | 3 | from ucloud.core import exc 4 | 5 | 6 | class Field(object): 7 | def __init__( 8 | self, 9 | required: bool = False, 10 | default: typing.Any = None, 11 | dump_to: str = None, 12 | load_from: str = None, 13 | strict: bool = None, 14 | **kwargs 15 | ): 16 | self.required = required 17 | self.default = default 18 | self.dump_to = dump_to 19 | self.load_from = load_from 20 | self.options = kwargs 21 | self.strict = bool(strict) # None as False 22 | 23 | def dumps(self, value, **kwargs): 24 | raise NotImplementedError 25 | 26 | def loads(self, value, **kwargs): 27 | raise NotImplementedError 28 | 29 | @staticmethod 30 | def fail(name, expected, got): 31 | msg = "invalid field {}, expect {}, got {}".format(name, expected, got) 32 | raise exc.ValidationException(msg) 33 | 34 | 35 | class Schema(object): 36 | fields = {} 37 | 38 | def __init__( 39 | self, 40 | required: bool = False, 41 | default: typing.Union[typing.Callable, typing.Any] = dict, 42 | dump_to: str = None, 43 | load_from: str = None, 44 | strict: bool = False, 45 | case_sensitive: bool = False, 46 | **kwargs 47 | ): 48 | self.required = required 49 | self.default = default 50 | self.dump_to = dump_to 51 | self.load_from = load_from 52 | self.options = kwargs 53 | self.strict = strict 54 | self.case_sensitive = case_sensitive 55 | 56 | def dumps(self, d: dict) -> dict: 57 | raise NotImplementedError 58 | 59 | def loads(self, d: dict) -> dict: 60 | raise NotImplementedError 61 | -------------------------------------------------------------------------------- /ucloud/testing/driver/_specification.py: -------------------------------------------------------------------------------- 1 | from ucloud.testing.driver import _scenario 2 | 3 | 4 | class Specification: 5 | def __init__(self): 6 | self.scenarios = [] 7 | 8 | def scenario(self, id_, title="", owners=None): 9 | scenario = _scenario.Scenario(self, id_, title, owners) 10 | self.scenarios.append(scenario) 11 | return scenario 12 | 13 | @property 14 | def status(self): 15 | if all([item.status == "skipped" for item in self.scenarios]): 16 | status = "skipped" 17 | elif any([item.status == "failed" for item in self.scenarios]): 18 | status = "failed" 19 | else: 20 | status = "passed" 21 | return status 22 | 23 | @property 24 | def start_time(self): 25 | times = [ 26 | item.start_time 27 | for item in self.scenarios 28 | if item.status != "skipped" 29 | ] 30 | return min(times) if times else 0 31 | 32 | @property 33 | def end_time(self): 34 | times = [ 35 | item.end_time for item in self.scenarios if item.status != "skipped" 36 | ] 37 | return max(times) if times else 0 38 | 39 | def json(self): 40 | return { 41 | "status": self.status, 42 | "execution": { 43 | "duration": self.end_time - self.start_time, 44 | "start_time": self.start_time, 45 | "end_time": self.end_time, 46 | }, 47 | "scenarios": [item.json() for item in self.scenarios], 48 | "passed_count": len( 49 | [1 for item in self.scenarios if item.status == "passed"] 50 | ), 51 | "failed_count": len( 52 | [1 for item in self.scenarios if item.status == "failed"] 53 | ), 54 | "skipped_count": len( 55 | [1 for item in self.scenarios if item.status == "skipped"] 56 | ), 57 | } 58 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | .pytest_cache/ 49 | .allure/ 50 | 51 | # Translations 52 | *.mo 53 | *.pot 54 | 55 | # Django stuff: 56 | *.log 57 | local_settings.py 58 | db.sqlite3 59 | 60 | # Flask stuff: 61 | instance/ 62 | .webassets-cache 63 | 64 | # Scrapy stuff: 65 | .scrapy 66 | 67 | # Sphinx documentation 68 | docs/build/ 69 | 70 | # PyBuilder 71 | target/ 72 | 73 | # Jupyter Notebook 74 | .ipynb_checkpoints 75 | 76 | # pyenv 77 | .python-version 78 | 79 | # celery beat schedule file 80 | celerybeat-schedule 81 | 82 | # SageMath parsed files 83 | *.sage.py 84 | 85 | # Environments 86 | .env 87 | .venv 88 | env/ 89 | venv/ 90 | ENV/ 91 | env.bak/ 92 | venv.bak/ 93 | 94 | # Spyder project settings 95 | .spyderproject 96 | .spyproject 97 | 98 | # Rope project settings 99 | .ropeproject 100 | 101 | # mkdocs documentation 102 | /site 103 | 104 | # mypy 105 | .mypy_cache/ 106 | 107 | # IDE / Editor 108 | .idea/ 109 | .vscode/ 110 | ~* 111 | 112 | # Debug 113 | *.stackdump 114 | examples/debug 115 | bdd/ 116 | .version 117 | 118 | scripts/gen-apis.sh 119 | report.json 120 | -------------------------------------------------------------------------------- /ucloud/testing/funcs.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | import time 3 | 4 | 5 | def concat(*args): 6 | """cancat strings 7 | 8 | >>> concat(42, 'foo', 'bar') 9 | '42foobar' 10 | """ 11 | return "".join([str(s) for s in args]) 12 | 13 | 14 | def concat_without_dot(args): 15 | """replace blank 16 | 17 | >>> concat_without_dot('42foo bar') 18 | '42foobar' 19 | """ 20 | return "".join([str(s) for s in args.split()]) 21 | 22 | 23 | def search_value(array, origin_key, origin_value, dest_key): 24 | """given origin key and value,search dest_value form array by dest_key 25 | 26 | >>> d = [{"UHostId": "foo", "Name": "testing"}] 27 | >>> search_value(d, "Name", "testing", "UHostId") 28 | 'foo' 29 | """ 30 | arr = [i.get(dest_key, "") for i in array if i[origin_key] == origin_value] 31 | if arr: 32 | return arr[0] 33 | return "" 34 | 35 | 36 | def timedelta(timestamp, value, typ="days"): 37 | """given timestamp(10bit) and calculate relative delta time 38 | 39 | >>> timedelta(0, 1, "days") 40 | 86400.0 41 | 42 | :param timestamp: timestamp (round to second) 43 | :param value: float, can as positive or negative 44 | :param typ: days/hours 45 | :return: timestamp 46 | """ 47 | value = int(value) 48 | dt = datetime.datetime.fromtimestamp(float(timestamp)) 49 | if typ == "days": 50 | dt += datetime.timedelta(days=value) 51 | elif typ == "hours": 52 | dt += datetime.timedelta(hours=value) 53 | return time.mktime(dt.timetuple()) 54 | 55 | 56 | def get_timestamp(length=13): 57 | """get current timestamp string 58 | 59 | >>> len(str(int(get_timestamp(10)))) 60 | 10 61 | 62 | :param length: length of timestamp, can only between 0 and 16 63 | :return: 64 | """ 65 | if isinstance(length, int) and 0 < length < 17: 66 | return int("{:.6f}".format(time.time()).replace(".", "")[:length]) 67 | 68 | raise ValueError("timestamp length can only between 0 and 16.") 69 | -------------------------------------------------------------------------------- /tests/test_unit/test_core/test_fields.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | import pytest 4 | 5 | from ucloud.core import exc 6 | from ucloud.core.typesystem import fields 7 | 8 | logger = logging.getLogger(__name__) 9 | 10 | 11 | def test_field_str(): 12 | s = fields.Str() 13 | assert s.dumps(s.loads("foo")) == "foo" 14 | 15 | with pytest.raises(exc.ValidationException): 16 | fields.Str(strict=True).loads(42) 17 | 18 | 19 | def test_field_int(): 20 | i = fields.Int() 21 | assert i.dumps(i.loads("42")) == 42 22 | 23 | with pytest.raises(exc.ValidationException): 24 | fields.Int().dumps("foo") 25 | 26 | with pytest.raises(exc.ValidationException): 27 | fields.Int(strict=True).loads("42") 28 | 29 | 30 | def test_field_float(): 31 | f = fields.Float() 32 | assert f.dumps(f.loads("42.0")) == 42.0 33 | 34 | with pytest.raises(exc.ValidationException): 35 | fields.Float().dumps("foo") 36 | 37 | with pytest.raises(exc.ValidationException): 38 | fields.Float(strict=True).loads("42.0") 39 | 40 | 41 | def test_field_bool(): 42 | b = fields.Bool() 43 | assert b.dumps(b.loads("true")) 44 | assert not b.dumps(b.loads("false")) 45 | 46 | with pytest.raises(exc.ValidationException): 47 | fields.Bool().dumps("foo") 48 | 49 | with pytest.raises(exc.ValidationException): 50 | fields.Bool(strict=True).loads("true") 51 | 52 | 53 | def test_field_list(): 54 | l = fields.List(fields.Int()) 55 | assert l.dumps(l.loads(["42"])) == [42] 56 | 57 | with pytest.raises(exc.ValidationException): 58 | fields.List(fields.Int(), strict=True).dumps(42) 59 | 60 | with pytest.raises(exc.ValidationException): 61 | fields.List(fields.Int()).dumps(["foo"]) 62 | 63 | with pytest.raises(exc.ValidationException): 64 | fields.List(fields.Int(strict=True)).loads(["42"]) 65 | 66 | 67 | def test_field_base64(): 68 | b64 = fields.Base64() 69 | assert b64.loads("Zm9v") == "foo" 70 | assert b64.dumps("foo") == "Zm9v" 71 | -------------------------------------------------------------------------------- /ucloud/services/unvs/schemas/apis.py: -------------------------------------------------------------------------------- 1 | """ Code is generated by ucloud-model, DO NOT EDIT IT. """ 2 | 3 | from ucloud.core.typesystem import schema, fields 4 | from ucloud.services.unvs.schemas import models 5 | 6 | """ UNVS API Schema 7 | """ 8 | 9 | 10 | """ 11 | API: GetMobile 12 | 13 | 一键登录 14 | """ 15 | 16 | 17 | class GetMobileRequestSchema(schema.RequestSchema): 18 | """GetMobile - 一键登录""" 19 | 20 | fields = { 21 | "BusinessId": fields.Str(required=True, dump_to="BusinessId"), 22 | "ProjectId": fields.Str(required=False, dump_to="ProjectId"), 23 | "Region": fields.Str(required=False, dump_to="Region"), 24 | "Token": fields.Str(required=True, dump_to="Token"), 25 | "Zone": fields.Str(required=False, dump_to="Zone"), 26 | } 27 | 28 | 29 | class GetMobileResponseSchema(schema.ResponseSchema): 30 | """GetMobile - 一键登录""" 31 | 32 | fields = { 33 | "Data": models.PhoneInfoSchema(), 34 | "Message": fields.Str(required=False, load_from="Message"), 35 | "ReqUuid": fields.Str(required=False, load_from="ReqUuid"), 36 | } 37 | 38 | 39 | """ 40 | API: VerifyMobile 41 | 42 | 号码检测 43 | """ 44 | 45 | 46 | class VerifyMobileRequestSchema(schema.RequestSchema): 47 | """VerifyMobile - 号码检测""" 48 | 49 | fields = { 50 | "BusinessId": fields.Str(required=True, dump_to="BusinessId"), 51 | "Phone": fields.Str(required=True, dump_to="Phone"), 52 | "ProjectId": fields.Str(required=False, dump_to="ProjectId"), 53 | "Region": fields.Str(required=False, dump_to="Region"), 54 | "Token": fields.Str(required=True, dump_to="Token"), 55 | "Zone": fields.Str(required=False, dump_to="Zone"), 56 | } 57 | 58 | 59 | class VerifyMobileResponseSchema(schema.ResponseSchema): 60 | """VerifyMobile - 号码检测""" 61 | 62 | fields = { 63 | "Data": models.VerifyInfoSchema(), 64 | "Message": fields.Str(required=False, load_from="Message"), 65 | "ReqUuid": fields.Str(required=False, load_from="ReqUuid"), 66 | } 67 | -------------------------------------------------------------------------------- /ucloud/services/isms/schemas/models.py: -------------------------------------------------------------------------------- 1 | """ Code is generated by ucloud-model, DO NOT EDIT IT. """ 2 | 3 | from ucloud.core.typesystem import schema, fields 4 | 5 | 6 | class ReceiptPerPhoneSchema(schema.ResponseSchema): 7 | """ReceiptPerPhone - 每个目的手机号的发送回执信息""" 8 | 9 | fields = { 10 | "Phone": fields.Str(required=True, load_from="Phone"), 11 | "ReceiptCode": fields.Str(required=True, load_from="ReceiptCode"), 12 | "ReceiptDesc": fields.Str(required=True, load_from="ReceiptDesc"), 13 | "ReceiptResult": fields.Str(required=True, load_from="ReceiptResult"), 14 | "ReceiptTime": fields.Int(required=True, load_from="ReceiptTime"), 15 | "SessionId": fields.Str(required=True, load_from="SessionId"), 16 | } 17 | 18 | 19 | class ReceiptPerTaskSchema(schema.ResponseSchema): 20 | """ReceiptPerTask - 每个提交任务的视频短信的回执结果集合""" 21 | 22 | fields = { 23 | "ReceiptSet": fields.List(ReceiptPerPhoneSchema()), 24 | "TaskId": fields.Str(required=True, load_from="TaskId"), 25 | } 26 | 27 | 28 | class OutSignatureSchema(schema.ResponseSchema): 29 | """OutSignature - 短信签名""" 30 | 31 | fields = { 32 | "ErrDesc": fields.Str(required=True, load_from="ErrDesc"), 33 | "SigContent": fields.Str(required=True, load_from="SigContent"), 34 | "SigId": fields.Str(required=True, load_from="SigId"), 35 | "Status": fields.Int(required=True, load_from="Status"), 36 | } 37 | 38 | 39 | class OutTemplateSchema(schema.ResponseSchema): 40 | """OutTemplate - 模板状态""" 41 | 42 | fields = { 43 | "CreateTime": fields.Int(required=False, load_from="CreateTime"), 44 | "ExpireTime": fields.Int(required=False, load_from="ExpireTime"), 45 | "Purpose": fields.Int(required=False, load_from="Purpose"), 46 | "Remark": fields.Str(required=False, load_from="Remark"), 47 | "StatusDesc": fields.Str(required=False, load_from="StatusDesc"), 48 | "TemplateId": fields.Str(required=False, load_from="TemplateId"), 49 | "TemplateName": fields.Str(required=False, load_from="TemplateName"), 50 | } 51 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | # Configuration file for the Sphinx documentation builder. 2 | # 3 | # This file only contains a selection of the most common options. For a full 4 | # list see the documentation: 5 | # http://www.sphinx-doc.org/en/master/config 6 | 7 | # -- Path setup -------------------------------------------------------------- 8 | 9 | # If extensions (or modules to document with autodoc) are in another directory, 10 | # add these directories to sys.path here. If the directory is relative to the 11 | # documentation root, use os.path.abspath to make it absolute, like shown here. 12 | # 13 | # import os 14 | # import sys 15 | # sys.path.insert(0, os.path.abspath('.')) 16 | 17 | 18 | # -- Project information ----------------------------------------------------- 19 | 20 | project = "ucloud-sdk-python3" 21 | copyright = "2019, ucloud" 22 | author = "ucloud" 23 | 24 | 25 | # -- General configuration --------------------------------------------------- 26 | 27 | # Add any Sphinx extension module names here, as strings. They can be 28 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 29 | # ones. 30 | extensions = [ 31 | "sphinx.ext.autodoc", 32 | "sphinx.ext.doctest", 33 | "sphinx.ext.todo", 34 | "sphinx.ext.viewcode", 35 | ] 36 | 37 | # Add any paths that contain templates here, relative to this directory. 38 | templates_path = ["_templates"] 39 | 40 | # List of patterns, relative to source directory, that match files and 41 | # directories to ignore when looking for source files. 42 | # This pattern also affects html_static_path and html_extra_path. 43 | exclude_patterns = [] 44 | 45 | 46 | # -- Options for HTML output ------------------------------------------------- 47 | 48 | # The theme to use for HTML and HTML Help pages. See the documentation for 49 | # a list of builtin themes. 50 | # 51 | html_theme = "alabaster" 52 | 53 | # Add any paths that contain custom static files (such as style sheets) here, 54 | # relative to this directory. They are copied after the builtin static files, 55 | # so a file named "default.css" will overwrite the builtin "default.css". 56 | html_static_path = ["_static"] 57 | -------------------------------------------------------------------------------- /ucloud/services/uvms/schemas/models.py: -------------------------------------------------------------------------------- 1 | """ Code is generated by ucloud-model, DO NOT EDIT IT. """ 2 | 3 | from ucloud.core.typesystem import schema, fields 4 | 5 | 6 | class SendRecordItemSchema(schema.ResponseSchema): 7 | """SendRecordItem - 发送记录条目""" 8 | 9 | fields = { 10 | "BillPeriod": fields.Int(required=False, load_from="BillPeriod"), 11 | "BillSecond": fields.Int(required=False, load_from="BillSecond"), 12 | "BrevityCode": fields.Str(required=False, load_from="BrevityCode"), 13 | "CallEndTime": fields.Float(required=False, load_from="CallEndTime"), 14 | "CallStartTime": fields.Float( 15 | required=False, load_from="CallStartTime" 16 | ), 17 | "CalledCityCode": fields.Str( 18 | required=False, load_from="CalledCityCode" 19 | ), 20 | "CalledOperatorCode": fields.Str( 21 | required=False, load_from="CalledOperatorCode" 22 | ), 23 | "CallingCityCode": fields.Str( 24 | required=False, load_from="CallingCityCode" 25 | ), 26 | "ChannelId": fields.Str(required=False, load_from="ChannelId"), 27 | "CountryCode": fields.Str(required=False, load_from="CountryCode"), 28 | "Duration": fields.Int(required=False, load_from="Duration"), 29 | "GroupType": fields.Int(required=False, load_from="GroupType"), 30 | "Phone": fields.Str(required=False, load_from="Phone"), 31 | "PreCost": fields.Int(required=False, load_from="PreCost"), 32 | "Purpose": fields.Int(required=False, load_from="Purpose"), 33 | "ReceiptDesc": fields.Str(required=False, load_from="ReceiptDesc"), 34 | "ReceiptResult": fields.Int(required=False, load_from="ReceiptResult"), 35 | "ReceiveTime": fields.Float(required=False, load_from="ReceiveTime"), 36 | "ShowNumber": fields.Str(required=False, load_from="ShowNumber"), 37 | "SubmitTime": fields.Float(required=False, load_from="SubmitTime"), 38 | "TaskNo": fields.Str(required=False, load_from="TaskNo"), 39 | "TemplateId": fields.Str(required=False, load_from="TemplateId"), 40 | } 41 | -------------------------------------------------------------------------------- /ucloud/services/cube/schemas/models.py: -------------------------------------------------------------------------------- 1 | """ Code is generated by ucloud-model, DO NOT EDIT IT. """ 2 | 3 | from ucloud.core.typesystem import schema, fields 4 | 5 | 6 | class EIPAddrSchema(schema.ResponseSchema): 7 | """EIPAddr - EIP地址""" 8 | 9 | fields = { 10 | "IP": fields.Str(required=False, load_from="IP"), 11 | "OperatorName": fields.Str(required=False, load_from="OperatorName"), 12 | } 13 | 14 | 15 | class EIPSetSchema(schema.ResponseSchema): 16 | """EIPSet - EIP信息""" 17 | 18 | fields = { 19 | "Bandwidth": fields.Int(required=False, load_from="Bandwidth"), 20 | "BandwidthType": fields.Int(required=False, load_from="BandwidthType"), 21 | "CreateTime": fields.Int(required=False, load_from="CreateTime"), 22 | "EIPAddr": fields.List(EIPAddrSchema()), 23 | "EIPId": fields.Str(required=False, load_from="EIPId"), 24 | "PayMode": fields.Str(required=False, load_from="PayMode"), 25 | "Resource": fields.Str(required=False, load_from="Resource"), 26 | "Status": fields.Str(required=False, load_from="Status"), 27 | "Weight": fields.Int(required=False, load_from="Weight"), 28 | } 29 | 30 | 31 | class CubeExtendInfoSchema(schema.ResponseSchema): 32 | """CubeExtendInfo - Cube的额外信息""" 33 | 34 | fields = { 35 | "CubeId": fields.Str(required=True, load_from="CubeId"), 36 | "Eip": fields.List(EIPSetSchema()), 37 | "Expiration": fields.Int(required=False, load_from="Expiration"), 38 | "Name": fields.Str(required=False, load_from="Name"), 39 | "Tag": fields.Str(required=False, load_from="Tag"), 40 | } 41 | 42 | 43 | class ValueSetSchema(schema.ResponseSchema): 44 | """ValueSet -""" 45 | 46 | fields = { 47 | "Timestamp": fields.Int(required=False, load_from="Timestamp"), 48 | "Value": fields.Float(required=True, load_from="Value"), 49 | } 50 | 51 | 52 | class MetricDataSetSchema(schema.ResponseSchema): 53 | """MetricDataSet - 监控数据集合""" 54 | 55 | fields = { 56 | "MetricName": fields.Str(required=False, load_from="MetricName"), 57 | "Values": fields.List(ValueSetSchema()), 58 | } 59 | -------------------------------------------------------------------------------- /ucloud/services/udi/schemas/models.py: -------------------------------------------------------------------------------- 1 | """ Code is generated by ucloud-model, DO NOT EDIT IT. """ 2 | 3 | from ucloud.core.typesystem import schema, fields 4 | 5 | 6 | class FunctionTemplateSchema(schema.ResponseSchema): 7 | """FunctionTemplate -""" 8 | 9 | fields = { 10 | "FunctionName": fields.Str(required=False, load_from="FunctionName"), 11 | "Id": fields.Str(required=False, load_from="Id"), 12 | "Name": fields.Str(required=False, load_from="Name"), 13 | } 14 | 15 | 16 | class ParamCustomSchema(schema.ResponseSchema): 17 | """ParamCustom -""" 18 | 19 | fields = { 20 | "Max": fields.Int(required=False, load_from="Max"), 21 | "Min": fields.Int(required=False, load_from="Min"), 22 | "ParamName": fields.Str(required=False, load_from="ParamName"), 23 | "ParamType": fields.Str(required=False, load_from="ParamType"), 24 | } 25 | 26 | 27 | class ParamOptionSchema(schema.ResponseSchema): 28 | """ParamOption -""" 29 | 30 | fields = { 31 | "DisplayName": fields.Str(required=False, load_from="DisplayName"), 32 | "OptionalValues": fields.List(fields.Str()), 33 | "ParamName": fields.Str(required=False, load_from="ParamName"), 34 | "Required": fields.Bool(required=False, load_from="Required"), 35 | "WhenValueCustom": fields.List(ParamCustomSchema()), 36 | } 37 | 38 | 39 | class FunctionSchema(schema.ResponseSchema): 40 | """Function -""" 41 | 42 | fields = { 43 | "DisplayName": fields.Str(required=False, load_from="DisplayName"), 44 | "FunctionName": fields.Str(required=False, load_from="FunctionName"), 45 | "InputType": fields.Str(required=False, load_from="InputType"), 46 | "OutputType": fields.Str(required=False, load_from="OutputType"), 47 | "SupportParams": fields.List(ParamOptionSchema()), 48 | } 49 | 50 | 51 | class MediaTaskSchema(schema.ResponseSchema): 52 | """MediaTask -""" 53 | 54 | fields = { 55 | "Function": fields.Str(required=False, load_from="Function"), 56 | "Id": fields.Str(required=False, load_from="Id"), 57 | "Status": fields.Str(required=False, load_from="Status"), 58 | } 59 | -------------------------------------------------------------------------------- /ucloud/services/stepflow/schemas/apis.py: -------------------------------------------------------------------------------- 1 | """ Code is generated by ucloud-model, DO NOT EDIT IT. """ 2 | 3 | from ucloud.core.typesystem import schema, fields 4 | from ucloud.services.stepflow.schemas import models 5 | 6 | 7 | """ StepFlow API Schema 8 | """ 9 | 10 | 11 | """ 12 | API: CreateSFWorkflowFromTemplate 13 | 14 | 导入工作流定义 15 | """ 16 | 17 | 18 | class CreateSFWorkflowFromTemplateRequestSchema(schema.RequestSchema): 19 | """CreateSFWorkflowFromTemplate - 导入工作流定义""" 20 | 21 | fields = { 22 | "Namespace": fields.Str(required=True, dump_to="Namespace"), 23 | "ProjectId": fields.Str(required=False, dump_to="ProjectId"), 24 | "Region": fields.Str(required=True, dump_to="Region"), 25 | "Workflow": fields.Base64(required=True, dump_to="Workflow"), 26 | "WorkflowName": fields.Str(required=True, dump_to="WorkflowName"), 27 | } 28 | 29 | 30 | class CreateSFWorkflowFromTemplateResponseSchema(schema.ResponseSchema): 31 | """CreateSFWorkflowFromTemplate - 导入工作流定义""" 32 | 33 | fields = { 34 | "Message": fields.Str(required=True, load_from="Message"), 35 | "Version": fields.Int(required=True, load_from="Version"), 36 | } 37 | 38 | 39 | """ 40 | API: GetSFWorkflowTemplate 41 | 42 | 导出工作流定义 43 | """ 44 | 45 | 46 | class GetSFWorkflowTemplateRequestSchema(schema.RequestSchema): 47 | """GetSFWorkflowTemplate - 导出工作流定义""" 48 | 49 | fields = { 50 | "ProjectId": fields.Str(required=False, dump_to="ProjectId"), 51 | "Region": fields.Str(required=True, dump_to="Region"), 52 | "WorkflowId": fields.Str(required=True, dump_to="WorkflowId"), 53 | "WorkflowVersion": fields.Int( 54 | required=False, dump_to="WorkflowVersion" 55 | ), 56 | } 57 | 58 | 59 | class GetSFWorkflowTemplateResponseSchema(schema.ResponseSchema): 60 | """GetSFWorkflowTemplate - 导出工作流定义""" 61 | 62 | fields = { 63 | "Message": fields.Str(required=False, load_from="Message"), 64 | "Version": fields.Int(required=True, load_from="Version"), 65 | "Workflow": models.WorkflowTemplateSchema(), 66 | "WorkflowId": fields.Str(required=True, load_from="WorkflowId"), 67 | } 68 | -------------------------------------------------------------------------------- /ucloud/services/ufs/schemas/models.py: -------------------------------------------------------------------------------- 1 | """ Code is generated by ucloud-model, DO NOT EDIT IT. """ 2 | 3 | from ucloud.core.typesystem import schema, fields 4 | 5 | 6 | class UFSVolumeInfo2Schema(schema.ResponseSchema): 7 | """UFSVolumeInfo2 - 文件系统信息""" 8 | 9 | fields = { 10 | "CreateTime": fields.Int(required=False, load_from="CreateTime"), 11 | "ExpiredTime": fields.Int(required=False, load_from="ExpiredTime"), 12 | "IsExpired": fields.Str(required=False, load_from="IsExpired"), 13 | "MaxMountPointNum": fields.Int( 14 | required=True, load_from="MaxMountPointNum" 15 | ), 16 | "ProtocolType": fields.Str(required=True, load_from="ProtocolType"), 17 | "Remark": fields.Str(required=False, load_from="Remark"), 18 | "Size": fields.Int(required=False, load_from="Size"), 19 | "StorageType": fields.Str(required=True, load_from="StorageType"), 20 | "Tag": fields.Str(required=False, load_from="Tag"), 21 | "TotalMountPointNum": fields.Int( 22 | required=True, load_from="TotalMountPointNum" 23 | ), 24 | "UsedSize": fields.Int(required=False, load_from="UsedSize"), 25 | "VolumeId": fields.Str(required=True, load_from="VolumeId"), 26 | "VolumeName": fields.Str(required=True, load_from="VolumeName"), 27 | } 28 | 29 | 30 | class MountPointInfoSchema(schema.ResponseSchema): 31 | """MountPointInfo - 挂载点信息""" 32 | 33 | fields = { 34 | "CreateTime": fields.Int(required=True, load_from="CreateTime"), 35 | "MountPointIp": fields.Str(required=True, load_from="MountPointIp"), 36 | "MountPointName": fields.Str(required=True, load_from="MountPointName"), 37 | "SubnetDescription": fields.Str( 38 | required=True, load_from="SubnetDescription" 39 | ), 40 | "SubnetId": fields.Str(required=True, load_from="SubnetId"), 41 | "VpcId": fields.Str(required=True, load_from="VpcId"), 42 | } 43 | 44 | 45 | class UFSPriceDataSetSchema(schema.ResponseSchema): 46 | """UFSPriceDataSet - ufs 价格信息""" 47 | 48 | fields = { 49 | "ChargeName": fields.Str(required=False, load_from="ChargeName"), 50 | "ChargeType": fields.Str(required=False, load_from="ChargeType"), 51 | "Price": fields.Float(required=False, load_from="Price"), 52 | } 53 | -------------------------------------------------------------------------------- /ucloud/core/utils/middleware.py: -------------------------------------------------------------------------------- 1 | class Middleware: 2 | """middleware is the object to store request/response handlers 3 | 4 | >>> middleware = Middleware() 5 | 6 | Add a request handler to prepare the request 7 | 8 | >>> @middleware.request 9 | ... def prepare(req): 10 | ... req['Region'] = 'cn-bj2' 11 | ... return req 12 | 13 | Add a response handler to log the response detail 14 | 15 | >>> @middleware.response 16 | ... def logged(resp): 17 | ... print(resp) 18 | ... return resp 19 | 20 | >>> len(middleware.request_handlers), len(middleware.response_handlers) 21 | (1, 1) 22 | """ 23 | 24 | def __init__(self): 25 | self.request_handlers = [] 26 | self.response_handlers = [] 27 | self.exception_handlers = [] 28 | 29 | def request(self, handler, index=-1): 30 | """request is the request handler register to add request handler. 31 | 32 | :param handler: request handler function, receive request object 33 | and return a new request 34 | :param int index: the position of request in the handler list, 35 | default is append it to end 36 | :return: 37 | """ 38 | self.request_handlers.insert(index, handler) 39 | return handler 40 | 41 | def response(self, handler, index=-1): 42 | """response is the response handler register to add response handler. 43 | 44 | :param handler: response handler function, receive response object 45 | and return a new response 46 | :param int index: the position of response in the handler list, 47 | default is append it to end 48 | :return: 49 | """ 50 | self.response_handlers.insert(index, handler) 51 | return handler 52 | 53 | def exception(self, handler, index=-1): 54 | """exception is the exception handler register to add exception handler. 55 | 56 | :param handler: exception handler function, receive exception object 57 | and raise a new exception or ignore it 58 | :param int index: the position of handler in the handler list, 59 | default is append it to end 60 | :return: 61 | """ 62 | self.exception_handlers.insert(index, handler) 63 | return handler 64 | -------------------------------------------------------------------------------- /ucloud/core/auth/_cfg.py: -------------------------------------------------------------------------------- 1 | import hashlib 2 | from collections import OrderedDict 3 | from ucloud.core.typesystem import schema, fields, encoder 4 | 5 | 6 | class CredentialSchema(schema.Schema): 7 | fields = { 8 | "public_key": fields.Str(required=True), 9 | "private_key": fields.Str(required=True), 10 | } 11 | 12 | 13 | def verify_ac(private_key: str, params: dict) -> str: 14 | """calculate signature by private_key/public_key 15 | 16 | the keys can be found on `APIKey documentation `__ 17 | 18 | >>> verify_ac("my_private_key", {"foo": "bar"}) 19 | '634edc1bb957c0d65e5ab5494cf3b7784fbc87af' 20 | 21 | >>> verify_ac("my_private_key", {"foo": "bar"}) 22 | '634edc1bb957c0d65e5ab5494cf3b7784fbc87af' 23 | 24 | :param private_key: private key 25 | :param params: 26 | :return: 27 | """ 28 | params = OrderedDict(sorted(params.items(), key=lambda item: item[0])) 29 | 30 | simplified = "" 31 | for key, value in params.items(): 32 | simplified += str(key) + encoder.encode_value(value) 33 | simplified += private_key 34 | 35 | hash_new = hashlib.sha1() 36 | hash_new.update(simplified.encode("utf-8")) 37 | hash_value = hash_new.hexdigest() 38 | return hash_value 39 | 40 | 41 | class Credential: 42 | """credential is the object to store credential information 43 | 44 | the keys can be found on `APIKey documentation `__ 45 | 46 | it can calculate signature for OpenAPI: 47 | 48 | >>> cred = Credential('my_public_key', 'my_private_key') 49 | >>> cred.verify_ac({"foo": "bar"}) 50 | 'd4411ab30953fb0bbcb1e7313081f05e4e91a394' 51 | 52 | :param public_key: 53 | :param private_key: 54 | """ 55 | 56 | PUBLIC_KEY_NAME = "PublicKey" 57 | 58 | def __init__(self, public_key: str, private_key: str, **kwargs): 59 | self.public_key = public_key 60 | self.private_key = private_key 61 | 62 | def verify_ac(self, args: dict) -> str: 63 | args[Credential.PUBLIC_KEY_NAME] = self.public_key 64 | return verify_ac(self.private_key, args) 65 | 66 | @classmethod 67 | def from_dict(cls, d: dict): 68 | parsed = CredentialSchema().dumps(d) 69 | return cls(**parsed) 70 | 71 | def to_dict(self) -> dict: 72 | return {"public_key": self.public_key, "private_key": self.private_key} 73 | -------------------------------------------------------------------------------- /ucloud/services/udbproxy/client.py: -------------------------------------------------------------------------------- 1 | """ Code is generated by ucloud-model, DO NOT EDIT IT. """ 2 | 3 | import typing 4 | 5 | 6 | from ucloud.core.client import Client 7 | from ucloud.services.udbproxy.schemas import apis 8 | 9 | 10 | class UDBProxyClient(Client): 11 | def __init__( 12 | self, config: dict, transport=None, middleware=None, logger=None 13 | ): 14 | super(UDBProxyClient, self).__init__( 15 | config, transport, middleware, logger 16 | ) 17 | 18 | def list_udb_proxy_client( 19 | self, req: typing.Optional[dict] = None, **kwargs 20 | ) -> dict: 21 | """ListUDBProxyClient - 查询代理客户端连接IP信息(实时) 22 | 23 | **Request** 24 | 25 | - **ProjectId** (str) - (Config) 项目ID。不填写为默认项目,子帐号必须填写。 请参考 `GetProjectList接口 `_ 26 | - **Region** (str) - (Config) 地域。 参见 `地域和可用区列表 `_ 27 | - **UDBProxyID** (str) - (Required) 代理ID 28 | - **Zone** (str) - (Required) 可用区。参见 `可用区列表 `_ 29 | 30 | **Response** 31 | 32 | - **NodeClientInfos** (list) - 见 **NodeClientInfo** 模型定义 33 | - **UDBProxyID** (str) - 代理ID 34 | 35 | **Response Model** 36 | 37 | **NodeClientInfo** 38 | - **ID** (str) - 代理节点ID 39 | - **IP** (str) - 代理节点IP 40 | - **Records** (list) - 见 **ProxyProcesslist** 模型定义 41 | 42 | 43 | **ProxyProcesslist** 44 | - **ClientHost** (str) - 代理连接DB地址 45 | - **Command** (str) - 显示当前连接的执行的命令 46 | - **DB** (str) - 当前执行的命令是在哪一个数据库上。如果没有指定数据库,则该值为 NULL 47 | - **DBID** (str) - 数据库资源ID 48 | - **Host** (str) - 代理连接DB地址 49 | - **ID** (int) - 当前连接DB进程ID 50 | - **Info** (str) - 一般记录的是线程执行的语句 51 | - **Role** (str) - 数据库角色(主库/从库) 52 | - **State** (str) - 线程的状态,和 Command 对应 53 | - **Time** (int) - 表示该线程处于当前状态的时间 54 | - **User** (str) - 启动这个线程的用户 55 | 56 | 57 | """ 58 | # build request 59 | d = { 60 | "ProjectId": self.config.project_id, 61 | "Region": self.config.region, 62 | } 63 | req and d.update(req) 64 | d = apis.ListUDBProxyClientRequestSchema().dumps(d) 65 | 66 | resp = self.invoke("ListUDBProxyClient", d, **kwargs) 67 | return apis.ListUDBProxyClientResponseSchema().loads(resp) 68 | -------------------------------------------------------------------------------- /ucloud/services/udns/schemas/models.py: -------------------------------------------------------------------------------- 1 | """ Code is generated by ucloud-model, DO NOT EDIT IT. """ 2 | 3 | from ucloud.core.typesystem import schema, fields 4 | 5 | 6 | class ValueSetSchema(schema.ResponseSchema): 7 | """ValueSet - RecordInfos""" 8 | 9 | fields = { 10 | "Data": fields.Str(required=True, load_from="Data"), 11 | "IsEnabled": fields.Int(required=True, load_from="IsEnabled"), 12 | "Weight": fields.Int(required=True, load_from="Weight"), 13 | } 14 | 15 | 16 | class RecordInfoSchema(schema.ResponseSchema): 17 | """RecordInfo - DescribeUDNSRecord""" 18 | 19 | fields = { 20 | "Name": fields.Str(required=True, load_from="Name"), 21 | "RecordId": fields.Str(required=True, load_from="RecordId"), 22 | "Remark": fields.Str(required=True, load_from="Remark"), 23 | "TTL": fields.Int(required=True, load_from="TTL"), 24 | "Type": fields.Str(required=True, load_from="Type"), 25 | "ValueSet": fields.List(ValueSetSchema()), 26 | "ValueType": fields.Str(required=True, load_from="ValueType"), 27 | } 28 | 29 | 30 | class VPCInfoSchema(schema.ResponseSchema): 31 | """VPCInfo - ZoneInfo""" 32 | 33 | fields = { 34 | "Name": fields.Str(required=False, load_from="Name"), 35 | "Network": fields.List(fields.Str()), 36 | "VPCId": fields.Str(required=False, load_from="VPCId"), 37 | "VPCProjectId": fields.Str(required=False, load_from="VPCProjectId"), 38 | "VPCType": fields.Str(required=False, load_from="VPCType"), 39 | } 40 | 41 | 42 | class ZoneInfoSchema(schema.ResponseSchema): 43 | """ZoneInfo - DescribeUDNSZone""" 44 | 45 | fields = { 46 | "ChargeType": fields.Str(required=True, load_from="ChargeType"), 47 | "CreateTime": fields.Int(required=True, load_from="CreateTime"), 48 | "DNSZoneName": fields.Str(required=True, load_from="DNSZoneName"), 49 | "ExpireTime": fields.Int(required=True, load_from="ExpireTime"), 50 | "IsAutoRenew": fields.Str(required=True, load_from="IsAutoRenew"), 51 | "IsRecursionEnabled": fields.Str( 52 | required=True, load_from="IsRecursionEnabled" 53 | ), 54 | "RecordInfos": fields.List(fields.Str()), 55 | "Remark": fields.Str(required=True, load_from="Remark"), 56 | "Tag": fields.Str(required=True, load_from="Tag"), 57 | "VPCInfos": fields.List(VPCInfoSchema()), 58 | } 59 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: clean-pyc clean-build docs clean 2 | 3 | # Browser Tools 4 | define BROWSER_PYSCRIPT 5 | import os, webbrowser, sys 6 | try: 7 | from urllib import pathname2url 8 | except: 9 | from urllib.request import pathname2url 10 | 11 | webbrowser.open("file://" + pathname2url(os.path.abspath(sys.argv[1]))) 12 | endef 13 | export BROWSER_PYSCRIPT 14 | BROWSER := python -c "$$BROWSER_PYSCRIPT" 15 | 16 | # UCloud Tools Path 17 | UCLOUD_TEMPLATE_PATH=../ucloud-api-model-v2/apisdk/lang/python/templates 18 | 19 | help: 20 | @echo "clean - remove all build, test, coverage and Python artifacts" 21 | @echo "clean-build - remove build artifacts" 22 | @echo "clean-pyc - remove Python file artifacts" 23 | @echo "clean-test - remove test and coverage artifacts" 24 | @echo "lint - check style with flake8" 25 | @echo "test - run tests quickly with the default Python" 26 | @echo "test-all - run tests on every Python version with tox" 27 | @echo "coverage - check code coverage quickly with the default Python" 28 | @echo "docs - generate Sphinx HTML documentation, including API docs" 29 | @echo "release - package and upload a release" 30 | @echo "dist - package" 31 | @echo "install - install the package to the active Python's site-packages" 32 | 33 | # unit test 34 | test: clean 35 | pytest 36 | 37 | test-cov: clean 38 | pytest --cov=ucloud/core tests 39 | 40 | test-cov-html: 41 | pytest --cov=ucloud/core tests --cov-report html 42 | $(BROWSER) htmlcov/index.html 43 | 44 | test-acc: clean 45 | USDKACC=1 pytest --cov=ucloud 46 | 47 | test-all: clean 48 | tox 49 | 50 | lint: 51 | @flake8 --exclude=ucloud/services ucloud --ignore=E501,F401 52 | 53 | fmt: 54 | @black -l 80 ucloud tests examples 55 | 56 | dev: 57 | @pip install -e .[dev] 58 | 59 | docs: 60 | #sphinx-apidoc -o docs/services ucloud/services 61 | $(MAKE) -C docs clean 62 | $(MAKE) -C docs html 63 | 64 | docs-preview: 65 | $(BROWSER) docs/_build/html/index.html 66 | 67 | clean: clean-build clean-pyc clean-test 68 | 69 | clean-build: 70 | rm -fr build/ 71 | rm -fr dist/ 72 | rm -fr .eggs/ 73 | 74 | clean-pyc: 75 | find . -name '*.pyc' -exec rm -f {} + 76 | find . -name '*.pyo' -exec rm -f {} + 77 | find . -name '*~' -exec rm -f {} + 78 | find . -name '__pycache__' -exec rm -fr {} + 79 | 80 | clean-test: 81 | rm -fr .tox/ 82 | rm -f .coverage 83 | rm -fr htmlcov/ 84 | 85 | version: 86 | @python -c 'from ucloud.version import version; print(version)' 87 | 88 | codegen: 89 | @bash ./scripts/codegen.sh 90 | 91 | release-check: 92 | @python scripts/release.py --dry-run 93 | 94 | release: 95 | @python scripts/release.py 96 | -------------------------------------------------------------------------------- /ucloud/services/utsdb/schemas/models.py: -------------------------------------------------------------------------------- 1 | """ Code is generated by ucloud-model, DO NOT EDIT IT. """ 2 | 3 | from ucloud.core.typesystem import schema, fields 4 | 5 | 6 | class AccountInfoSchema(schema.ResponseSchema): 7 | """AccountInfo - UInfluxdb 账户信息""" 8 | 9 | fields = { 10 | "Account": fields.Str(required=False, load_from="Account"), 11 | "Password": fields.Str(required=False, load_from="Password"), 12 | "Privilege": fields.Str(required=False, load_from="Privilege"), 13 | } 14 | 15 | 16 | class DatabaseInfoSchema(schema.ResponseSchema): 17 | """DatabaseInfo -""" 18 | 19 | fields = { 20 | "AccountInfo": fields.List(AccountInfoSchema()), 21 | "DatabaseName": fields.Str(required=False, load_from="DatabaseName"), 22 | "Description": fields.Str(required=False, load_from="Description"), 23 | "RetentionPolicy": fields.Str( 24 | required=False, load_from="RetentionPolicy" 25 | ), 26 | "State": fields.Str(required=False, load_from="State"), 27 | } 28 | 29 | 30 | class RpDataSchema(schema.ResponseSchema): 31 | """RpData - 保留策略信息""" 32 | 33 | fields = { 34 | "Policy": fields.Str(required=True, load_from="Policy"), 35 | "RetentionPolicyName": fields.Str( 36 | required=True, load_from="RetentionPolicyName" 37 | ), 38 | } 39 | 40 | 41 | class UInfluxdbDataSetSchema(schema.ResponseSchema): 42 | """UInfluxdbDataSet - UInfluxdb信息的DataSet""" 43 | 44 | fields = { 45 | "AccountName": fields.Str(required=True, load_from="AccountName"), 46 | "CPULimit": fields.Int(required=False, load_from="CPULimit"), 47 | "ChargeType": fields.Str(required=False, load_from="ChargeType"), 48 | "CreateTime": fields.Int(required=False, load_from="CreateTime"), 49 | "ExpiredTime": fields.Int(required=False, load_from="ExpiredTime"), 50 | "MemoryLimit": fields.Int(required=False, load_from="MemoryLimit"), 51 | "Name": fields.Str(required=False, load_from="Name"), 52 | "Port": fields.Int(required=False, load_from="Port"), 53 | "State": fields.Str(required=False, load_from="State"), 54 | "SubnetId": fields.Str(required=True, load_from="SubnetId"), 55 | "Tag": fields.Str(required=True, load_from="Tag"), 56 | "UInfluxdbId": fields.Str(required=False, load_from="UInfluxdbId"), 57 | "UsedSize": fields.Int(required=True, load_from="UsedSize"), 58 | "VPCId": fields.Str(required=True, load_from="VPCId"), 59 | "VirtualIP": fields.Str(required=False, load_from="VirtualIP"), 60 | "Zone": fields.Str(required=False, load_from="Zone"), 61 | } 62 | -------------------------------------------------------------------------------- /ucloud/core/exc/_exc.py: -------------------------------------------------------------------------------- 1 | from collections.abc import Iterable 2 | 3 | from ucloud.core.utils import compat 4 | 5 | 6 | class UCloudException(Exception): 7 | @property 8 | def retryable(self): 9 | return False 10 | 11 | 12 | MAX_COMMON_RET_CODE = 2000 13 | 14 | 15 | class TransportException(UCloudException): 16 | pass 17 | 18 | 19 | class HTTPStatusException(TransportException): 20 | def __init__(self, status_code: int, request_uuid: str = None): 21 | self.status_code = status_code 22 | self.request_uuid = request_uuid 23 | 24 | @property 25 | def retryable(self): 26 | return self.status_code in [429, 502, 503, 504] 27 | 28 | def __str__(self): 29 | return "[{uuid}] {self.status_code} http status error".format( 30 | self=self, uuid=self.request_uuid or "*" 31 | ) 32 | 33 | 34 | class InvalidResponseException(TransportException): 35 | def __init__(self, content: bytes, message: str, request_uuid: str = None): 36 | self.content = content 37 | self.message = message 38 | self.request_uuid = request_uuid 39 | 40 | @property 41 | def retryable(self): 42 | return False 43 | 44 | def __str__(self): 45 | return "[{uuid}] {self.message}: {self.content}".format( 46 | self=self, uuid=self.request_uuid or "*" 47 | ) 48 | 49 | 50 | class RetCodeException(UCloudException): 51 | def __init__( 52 | self, action: str, code: int, message: str, request_uuid: str = None 53 | ): 54 | self.action = action 55 | self.code = code 56 | self.message = message 57 | self.request_uuid = request_uuid 58 | 59 | @property 60 | def retryable(self): 61 | return self.code > MAX_COMMON_RET_CODE 62 | 63 | def __str__(self): 64 | return "[{uuid}] {self.action} - {self.code}: {self.message}".format( 65 | self=self, uuid=self.request_uuid or "*" 66 | ) 67 | 68 | def json(self): 69 | return { 70 | "RetCode": self.code, 71 | "Message": self.message or "", 72 | "Action": self.action or "", 73 | } 74 | 75 | 76 | class RetryTimeoutException(UCloudException): 77 | pass 78 | 79 | 80 | class ValidationException(UCloudException): 81 | def __init__(self, e=None): 82 | if isinstance(e, compat.string_types): 83 | self.errors = [e] 84 | elif isinstance(e, Iterable): 85 | self.errors = e or [] 86 | else: 87 | self.errors = [e] 88 | 89 | @property 90 | def retryable(self): 91 | return False 92 | 93 | def __str__(self): 94 | return str([str(e) for e in self.errors]) 95 | -------------------------------------------------------------------------------- /docs/usage.rst: -------------------------------------------------------------------------------- 1 | Usage 2 | ===== 3 | 4 | Type System 5 | ----------- 6 | 7 | UCloud Python SDK has type system for runtime checking. 8 | 9 | For example: 10 | 11 | .. code-block:: python 12 | 13 | client.uhost().create_uhost_instance({ 14 | 'CPU': "i am not a integer", 15 | }) 16 | 17 | it will raise :class:`ValidationException` with invalid integer and some required field is miss matched. 18 | 19 | Wait State Changed 20 | ------------------ 21 | 22 | SDK also provide state waiter helper to improver usage experience. 23 | 24 | **When using it?** 25 | 26 | Waiter can wait for remote state is achieved to target state. such as, 27 | 28 | - create and wait for resource state is completed. 29 | - invoke/start/stop a resource and wait for it is finished. 30 | - custom retry policies and wait for retrying is finished. 31 | 32 | For example: 33 | 34 | .. code-block:: python 35 | 36 | def mget_uhost_states(uhost_ids): 37 | resp = client.uhost().describe_uhost_instance({'UHostIds': uhost_ids}) 38 | return [inst.get('State') for inst in resp.get('UHostSet')] 39 | 40 | # Stop all instances 41 | for uhost_id in uhost_ids: 42 | client.uhost().stop_uhost_instance({'UHostId': uhost_id}) 43 | 44 | # Wait all instances is stopped 45 | wait.wait_for_state( 46 | target=['stopped'], pending=['pending'], 47 | timeout=300, # wait 5min 48 | refresh=lambda: ( 49 | 'stopped' if all([state == 'Stopped' for state in mget_uhost_states(uhost_ids)]) else 'pending' 50 | ), 51 | ) 52 | 53 | # Remove all instances 54 | for uhost_id in uhost_ids: 55 | client.uhost().terminate_uhost_instance({'UHostId': uhost_id}) 56 | 57 | By the default, waiter will use exponential back-off delay between twice request. 58 | it will raise :class:`WaitTimeoutException` when timeout is reached. 59 | 60 | Client/Transport Middleware 61 | --------------------------- 62 | 63 | UCloud SDK provide middleware feature to client or transport level request. 64 | 65 | It allowed to add custom logic into the lifecycle of request/response. 66 | 67 | For example: 68 | 69 | .. code-block:: python 70 | 71 | @client.middleware.request 72 | def log_params(req): 73 | print('[REQ]', req) 74 | 75 | @client.middleware.response 76 | def log_response(resp): 77 | print('[RESP]', resp) 78 | 79 | 80 | or transport: 81 | 82 | .. code-block:: python 83 | 84 | from ucloud.core.transport import RequestsTransport 85 | 86 | transport = RequestsTransport() 87 | 88 | @transport.middleware.request 89 | def log_request(req): 90 | print('[REQ]', req) 91 | 92 | @transport.middleware.response 93 | def log_response(resp): 94 | print('[RESP]', resp) 95 | 96 | Client({'Region': 'cn-bj2'}, transport=transport) 97 | -------------------------------------------------------------------------------- /ucloud/helpers/utils.py: -------------------------------------------------------------------------------- 1 | import random 2 | import base64 3 | import typing 4 | 5 | _lowercase = "abcdefghijklmnopqrstuvwxyz" 6 | _uppercase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 7 | _numbers = "0123456789" 8 | _specials = "_" 9 | 10 | 11 | def gen_password( 12 | n: int, 13 | lower_letters: str = _lowercase, 14 | upper_letters: str = _uppercase, 15 | number_letters: str = _numbers, 16 | special_letters: str = _specials, 17 | min_lower: int = 1, 18 | min_upper: int = 1, 19 | min_number: int = 1, 20 | min_specials: int = 1, 21 | ): 22 | """generate password for any resource 23 | 24 | >>> len(gen_password(20)) 25 | 20 26 | 27 | :param int n: password total length 28 | :param str lower_letters: all lowercase letters 29 | :param str upper_letters: all uppercase letters 30 | :param str number_letters: all number letters 31 | :param str special_letters: all special letters 32 | :param int min_lower: minimal number of lowercase letters 33 | :param int min_upper: minimal number of uppercase letters 34 | :param int min_number: minimal number of number letters 35 | :param int min_specials: minimal number of special letters 36 | :return: 37 | """ 38 | all_letters = "".join( 39 | [lower_letters, upper_letters, number_letters, special_letters] 40 | ) 41 | minimal_total = min_lower + min_upper + min_number + min_specials 42 | if n < minimal_total: 43 | raise ValueError( 44 | ( 45 | "the length of password must be larger than " 46 | "total minimal letters number" 47 | ) 48 | ) 49 | 50 | minimal_letters = "".join( 51 | [ 52 | gen_string(lower_letters, min_lower), 53 | gen_string(upper_letters, min_upper), 54 | gen_string(number_letters, min_number), 55 | gen_string(special_letters, min_specials), 56 | ] 57 | ) 58 | 59 | additional_letters = random.sample(all_letters, n - minimal_total) 60 | results = list(minimal_letters) + additional_letters 61 | random.shuffle(results) 62 | return "".join(results) 63 | 64 | 65 | def gen_string(letters: str, length: int): 66 | return "".join([random.choice(letters) for i in range(length)]) 67 | 68 | 69 | def first(arr: typing.List[typing.Any]) -> typing.Any: 70 | if len(arr) == 0: 71 | return None 72 | return arr[0] 73 | 74 | 75 | def b64encode(s: str) -> str: 76 | """base64 encode 77 | 78 | :param str s: input string 79 | :return: base64 string 80 | """ 81 | return base64.b64encode(s.encode()).decode() 82 | 83 | 84 | def b64decode(s: str) -> str: 85 | """base64 decode 86 | 87 | :param str s: base64 string 88 | :return: output string 89 | """ 90 | return base64.b64decode(s.encode()).decode() 91 | -------------------------------------------------------------------------------- /ucloud/testing/driver/_scenario.py: -------------------------------------------------------------------------------- 1 | import functools 2 | 3 | from ucloud.testing.driver import _step 4 | 5 | 6 | class Scenario: 7 | def __init__(self, spec, id_, title=None, owners=None): 8 | self.id = id_ 9 | self.title = title 10 | self.store = {} 11 | self.errors = [] 12 | self.steps = [] 13 | self.spec = spec 14 | self.owners = owners 15 | 16 | def step(self, invoker, *args, **kwargs): 17 | step = _step.Step(self, invoker, *args, **kwargs) 18 | self.steps.append(step) 19 | return step 20 | 21 | def api(self, **step_kwargs): 22 | def deco(fn): 23 | step = self.step(fn, **step_kwargs) 24 | 25 | @functools.wraps(fn) 26 | def wrapped(*args, **kwargs): 27 | return step.run_api(*args, **kwargs) 28 | 29 | return wrapped 30 | 31 | return deco 32 | 33 | def func(self, **step_kwargs): 34 | def deco(fn): 35 | step = self.step(fn, **step_kwargs) 36 | 37 | @functools.wraps(fn) 38 | def wrapped(*args, **kwargs): 39 | return step.run_func(*args, **kwargs) 40 | 41 | return wrapped 42 | 43 | return deco 44 | 45 | @property 46 | def status(self): 47 | if all([item.status == "skipped" for item in self.steps]): 48 | status = "skipped" 49 | elif any([item.status == "failed" for item in self.steps]): 50 | status = "failed" 51 | else: 52 | status = "passed" 53 | return status 54 | 55 | @property 56 | def start_time(self): 57 | times = [ 58 | item.start_time for item in self.steps if item.status != "skipped" 59 | ] 60 | return min(times) if times else 0 61 | 62 | @property 63 | def end_time(self): 64 | times = [ 65 | item.end_time for item in self.steps if item.status != "skipped" 66 | ] 67 | return max(times) if times else 0 68 | 69 | def json(self): 70 | return { 71 | "title": self.title, 72 | "status": self.status, 73 | "steps": [item.json() for item in self.steps], 74 | "owners": self.owners, 75 | "execution": { 76 | "duration": self.end_time - self.start_time, 77 | "start_time": self.start_time, 78 | "end_time": self.end_time, 79 | }, 80 | "passed_count": len( 81 | [1 for item in self.steps if item.status == "passed"] 82 | ), 83 | "failed_count": len( 84 | [1 for item in self.steps if item.status == "failed"] 85 | ), 86 | "skipped_count": len( 87 | [1 for item in self.steps if item.status == "skipped"] 88 | ), 89 | } 90 | 91 | def __call__(self, *args, **kwargs): 92 | for step in self.steps: 93 | step(step, *args, **kwargs) 94 | -------------------------------------------------------------------------------- /examples/uhost/main.py: -------------------------------------------------------------------------------- 1 | import os 2 | import logging 3 | import random 4 | 5 | from ucloud.client import Client 6 | from ucloud.helpers import wait, utils 7 | 8 | logger = logging.getLogger("ucloud") 9 | logger.setLevel(logging.DEBUG) 10 | 11 | 12 | def main(): 13 | client = Client( 14 | { 15 | "region": "cn-bj2", 16 | "project_id": os.getenv("UCLOUD_PROJECT_ID"), 17 | "public_key": os.getenv("UCLOUD_PUBLIC_KEY"), 18 | "private_key": os.getenv("UCLOUD_PRIVATE_KEY"), 19 | } 20 | ) 21 | 22 | logger.info("finding image, random choice one") 23 | images = ( 24 | client.uhost() 25 | .describe_image({"ImageType": "Base", "OsType": "Linux"}) 26 | .get("ImageSet", []) 27 | ) 28 | 29 | assert len(images) > 0 30 | 31 | logger.info("creating uhost instance ...") 32 | image = random.choice(images) 33 | 34 | resp = client.uhost().create_uhost_instance( 35 | { 36 | "Name": "sdk-python-example", 37 | "Zone": image["Zone"], 38 | "ImageId": image["ImageId"], 39 | "LoginMode": "Password", 40 | "Password": utils.gen_password(20), 41 | "CPU": 1, 42 | "Memory": 1024, 43 | "Disks": [ 44 | { 45 | "Size": image["ImageSize"], 46 | "Type": "LOCAL_NORMAL", 47 | "IsBoot": "True", 48 | } 49 | ], 50 | } 51 | ) 52 | uhost_id = utils.first(resp["UHostIds"]) 53 | logger.info("uhost instance is created") 54 | 55 | def refresh_state(): 56 | uhost = utils.first( 57 | client.uhost() 58 | .describe_uhost_instance({"UHostIds": [uhost_id]}) 59 | .get("UHostSet", []) 60 | ) 61 | if uhost.get("State") in ["Running", "Stopped"]: 62 | return uhost["State"].lower() 63 | return "pending" 64 | 65 | logger.info("wait uhost state is running ...") 66 | try: 67 | wait.wait_for_state( 68 | pending=["pending"], 69 | target=["running"], 70 | timeout=300, 71 | refresh=refresh_state, 72 | ) 73 | except wait.WaitTimeoutException as e: 74 | logger.error(e) 75 | logger.info("uhost instance is running") 76 | 77 | logger.info("stopping uhost for clean up resources ...") 78 | client.uhost().stop_uhost_instance({"UHostId": uhost_id}) 79 | 80 | try: 81 | wait.wait_for_state( 82 | pending=["pending"], 83 | target=["stopped"], 84 | timeout=180, 85 | refresh=refresh_state, 86 | ) 87 | except wait.WaitTimeoutException as e: 88 | logger.error(e) 89 | else: 90 | logger.info("uhost instance is stopped") 91 | 92 | logger.info("remove uhost instance from cloud") 93 | client.uhost().terminate_uhost_instance({"UHostId": uhost_id}) 94 | 95 | 96 | if __name__ == "__main__": 97 | main() 98 | -------------------------------------------------------------------------------- /ucloud/core/typesystem/schema.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from ucloud.core.typesystem import abstract 3 | from ucloud.core.exc import ValidationException 4 | from ucloud.core.utils import compat 5 | 6 | logger = logging.getLogger(__name__) 7 | 8 | 9 | class Schema(abstract.Schema): 10 | fields = {} # noqa: F811 11 | 12 | def dumps(self, d: dict, name=None, **kwargs) -> dict: 13 | result = {} 14 | errors = [] 15 | 16 | for k, field in self.fields.items(): 17 | v = d.get(k) 18 | 19 | # resolve value is empty 20 | if v is None: 21 | if field.required: 22 | errors.append( 23 | ValidationException( 24 | "the field {k} is required".format(k=k) 25 | ) 26 | ) 27 | continue 28 | 29 | if field.default is None: 30 | continue 31 | 32 | if isinstance(field.default, compat.Callable): 33 | v = field.default() 34 | else: 35 | v = field.default 36 | 37 | try: 38 | serialized = field.dumps(v, name=k) 39 | except ValidationException as e: 40 | errors.extend(e.errors) 41 | continue 42 | 43 | result[field.dump_to or k] = serialized 44 | 45 | if len(errors) > 0: 46 | raise ValidationException(errors) 47 | 48 | return result 49 | 50 | def loads(self, d: dict, name=None, **kwargs) -> dict: 51 | result = {} 52 | errors = [] 53 | 54 | if not self.case_sensitive: 55 | d = {k.lower(): v for k, v in d.items()} 56 | 57 | for k, field in self.fields.items(): 58 | load_key = field.load_from or k 59 | v = d.get(load_key if self.case_sensitive else load_key.lower()) 60 | if v is None: 61 | if field.default is None: 62 | continue 63 | 64 | if isinstance(field.default, compat.Callable): 65 | v = field.default() 66 | else: 67 | v = field.default 68 | 69 | try: 70 | serialized = field.loads(v, name=k) 71 | except ValidationException as e: 72 | errors.extend(e.errors) 73 | continue 74 | 75 | result[k] = serialized 76 | 77 | if len(errors) > 0: 78 | raise ValidationException(errors) 79 | 80 | return result 81 | 82 | 83 | class RequestSchema(Schema): 84 | fields = {} # noqa: F811 85 | 86 | def dumps(self, d: dict, name=None, **kwargs) -> dict: 87 | if not isinstance(d, dict): 88 | raise ValidationException( 89 | "invalid field {}, expect dict, got {}".format(name, type(d)) 90 | ) 91 | 92 | result = super(RequestSchema, self).dumps(d, name=name, **kwargs) 93 | return result 94 | 95 | 96 | class ResponseSchema(Schema): 97 | pass 98 | -------------------------------------------------------------------------------- /ucloud/services/urocketmq/schemas/apis.py: -------------------------------------------------------------------------------- 1 | """ Code is generated by ucloud-model, DO NOT EDIT IT. """ 2 | 3 | from ucloud.core.typesystem import schema, fields 4 | from ucloud.services.urocketmq.schemas import models 5 | 6 | """ URocketMQ API Schema 7 | """ 8 | 9 | 10 | """ 11 | API: CreateURocketMQGroup 12 | 13 | 创建一个 Group, 如果同名 Group 在当前 Service 中已存在, 则会失败. 14 | """ 15 | 16 | 17 | class CreateURocketMQGroupRequestSchema(schema.RequestSchema): 18 | """CreateURocketMQGroup - 创建一个 Group, 如果同名 Group 在当前 Service 中已存在, 则会失败.""" 19 | 20 | fields = { 21 | "Name": fields.Str(required=True, dump_to="Name"), 22 | "ProjectId": fields.Str(required=True, dump_to="ProjectId"), 23 | "Region": fields.Str(required=True, dump_to="Region"), 24 | "Remark": fields.Str(required=False, dump_to="Remark"), 25 | "ServiceId": fields.Str(required=True, dump_to="ServiceId"), 26 | } 27 | 28 | 29 | class CreateURocketMQGroupResponseSchema(schema.ResponseSchema): 30 | """CreateURocketMQGroup - 创建一个 Group, 如果同名 Group 在当前 Service 中已存在, 则会失败.""" 31 | 32 | fields = { 33 | "GroupId": fields.Str(required=True, load_from="GroupId"), 34 | "Message": fields.Str(required=False, load_from="Message"), 35 | } 36 | 37 | 38 | """ 39 | API: DeleteURocketMQGroup 40 | 41 | 删除一个已存在的 Group 42 | """ 43 | 44 | 45 | class DeleteURocketMQGroupRequestSchema(schema.RequestSchema): 46 | """DeleteURocketMQGroup - 删除一个已存在的 Group""" 47 | 48 | fields = { 49 | "GroupName": fields.Str(required=True, dump_to="GroupName"), 50 | "ProjectId": fields.Str(required=True, dump_to="ProjectId"), 51 | "Region": fields.Str(required=True, dump_to="Region"), 52 | "ServiceId": fields.Str(required=True, dump_to="ServiceId"), 53 | } 54 | 55 | 56 | class DeleteURocketMQGroupResponseSchema(schema.ResponseSchema): 57 | """DeleteURocketMQGroup - 删除一个已存在的 Group""" 58 | 59 | fields = { 60 | "Message": fields.Str(required=False, load_from="Message"), 61 | } 62 | 63 | 64 | """ 65 | API: ListURocketMQGroup 66 | 67 | 获取一个 RocketMQ 服务下的所有 Group 68 | """ 69 | 70 | 71 | class ListURocketMQGroupRequestSchema(schema.RequestSchema): 72 | """ListURocketMQGroup - 获取一个 RocketMQ 服务下的所有 Group""" 73 | 74 | fields = { 75 | "Limit": fields.Int(required=False, dump_to="Limit"), 76 | "Offset": fields.Int(required=False, dump_to="Offset"), 77 | "ProjectId": fields.Str(required=True, dump_to="ProjectId"), 78 | "Region": fields.Str(required=True, dump_to="Region"), 79 | "ServiceId": fields.Str(required=True, dump_to="ServiceId"), 80 | } 81 | 82 | 83 | class ListURocketMQGroupResponseSchema(schema.ResponseSchema): 84 | """ListURocketMQGroup - 获取一个 RocketMQ 服务下的所有 Group""" 85 | 86 | fields = { 87 | "GroupList": fields.List( 88 | models.GroupBaseInfoSchema(), required=False, load_from="GroupList" 89 | ), 90 | "Message": fields.Str(required=False, load_from="Message"), 91 | "TotalCount": fields.Int(required=False, load_from="TotalCount"), 92 | } 93 | -------------------------------------------------------------------------------- /ucloud/services/unvs/client.py: -------------------------------------------------------------------------------- 1 | """ Code is generated by ucloud-model, DO NOT EDIT IT. """ 2 | 3 | import typing 4 | 5 | 6 | from ucloud.core.client import Client 7 | from ucloud.services.unvs.schemas import apis 8 | 9 | 10 | class UNVSClient(Client): 11 | def __init__( 12 | self, config: dict, transport=None, middleware=None, logger=None 13 | ): 14 | super(UNVSClient, self).__init__(config, transport, middleware, logger) 15 | 16 | def get_mobile(self, req: typing.Optional[dict] = None, **kwargs) -> dict: 17 | """GetMobile - 一键登录 18 | 19 | **Request** 20 | 21 | - **ProjectId** (str) - (Config) 项目ID。不填写为默认项目,子帐号必须填写。 请参考 `GetProjectList接口 `_ 22 | - **Region** (str) - (Config) 地域。 参见 `地域和可用区列表 `_ 23 | - **BusinessId** (str) - (Required) 业务ID 24 | - **Token** (str) - (Required) token 25 | - **Zone** (str) - 可用区。参见 `可用区列表 `_ 26 | 27 | **Response** 28 | 29 | - **Data** (dict) - 见 **PhoneInfo** 模型定义 30 | - **Message** (str) - 发生错误时表示错误字符串 31 | - **ReqUuid** (str) - 本次请求Uuid 32 | 33 | **Response Model** 34 | 35 | **PhoneInfo** 36 | - **Phone** (str) - 返回的电话号码 37 | 38 | 39 | """ 40 | # build request 41 | d = { 42 | "ProjectId": self.config.project_id, 43 | "Region": self.config.region, 44 | } 45 | req and d.update(req) 46 | d = apis.GetMobileRequestSchema().dumps(d) 47 | 48 | resp = self.invoke("GetMobile", d, **kwargs) 49 | return apis.GetMobileResponseSchema().loads(resp) 50 | 51 | def verify_mobile( 52 | self, req: typing.Optional[dict] = None, **kwargs 53 | ) -> dict: 54 | """VerifyMobile - 号码检测 55 | 56 | **Request** 57 | 58 | - **ProjectId** (str) - (Config) 项目ID。不填写为默认项目,子帐号必须填写。 请参考 `GetProjectList接口 `_ 59 | - **Region** (str) - (Config) 地域。 参见 `地域和可用区列表 `_ 60 | - **BusinessId** (str) - (Required) 业务ID 61 | - **Phone** (str) - (Required) 需要检测的手机号 62 | - **Token** (str) - (Required) token 63 | - **Zone** (str) - 可用区。参见 `可用区列表 `_ 64 | 65 | **Response** 66 | 67 | - **Data** (dict) - 见 **VerifyInfo** 模型定义 68 | - **Message** (str) - 发生错误时表示错误字符串 69 | - **ReqUuid** (str) - 本次请求Uuid 70 | 71 | **Response Model** 72 | 73 | **VerifyInfo** 74 | - **VerifyResult** (str) - 检测结果:PASS:一致,REJECT:不一致 75 | 76 | 77 | """ 78 | # build request 79 | d = { 80 | "ProjectId": self.config.project_id, 81 | "Region": self.config.region, 82 | } 83 | req and d.update(req) 84 | d = apis.VerifyMobileRequestSchema().dumps(d) 85 | 86 | resp = self.invoke("VerifyMobile", d, **kwargs) 87 | return apis.VerifyMobileResponseSchema().loads(resp) 88 | -------------------------------------------------------------------------------- /ucloud/services/tidb/schemas/apis.py: -------------------------------------------------------------------------------- 1 | """ Code is generated by ucloud-model, DO NOT EDIT IT. """ 2 | 3 | from ucloud.core.typesystem import schema, fields 4 | from ucloud.services.tidb.schemas import models 5 | 6 | """ TiDB API Schema 7 | """ 8 | 9 | 10 | """ 11 | API: CreateTiDBService 12 | 13 | 创建TiDB服务 14 | """ 15 | 16 | 17 | class CreateTiDBServiceRequestSchema(schema.RequestSchema): 18 | """CreateTiDBService - 创建TiDB服务""" 19 | 20 | fields = { 21 | "DTType": fields.Str(required=False, dump_to="DTType"), 22 | "Ip": fields.Str(required=False, dump_to="Ip"), 23 | "Name": fields.Str(required=True, dump_to="Name"), 24 | "Password": fields.Str(required=True, dump_to="Password"), 25 | "Port": fields.Str(required=False, dump_to="Port"), 26 | "ProjectId": fields.Str(required=True, dump_to="ProjectId"), 27 | "Region": fields.Str(required=True, dump_to="Region"), 28 | "SubnetId": fields.Str(required=True, dump_to="SubnetId"), 29 | "TikvMemoryHardTh": fields.Str( 30 | required=False, dump_to="TikvMemoryHardTh" 31 | ), 32 | "VPCId": fields.Str(required=True, dump_to="VPCId"), 33 | } 34 | 35 | 36 | class CreateTiDBServiceResponseSchema(schema.ResponseSchema): 37 | """CreateTiDBService - 创建TiDB服务""" 38 | 39 | fields = { 40 | "Data": models.ServiceIDSchema(), 41 | "Message": fields.Str(required=False, load_from="Message"), 42 | "ServiceId": fields.Str(required=False, load_from="ServiceId"), 43 | } 44 | 45 | 46 | """ 47 | API: DeleteTiDBService 48 | 49 | 删除一个服务 50 | """ 51 | 52 | 53 | class DeleteTiDBServiceRequestSchema(schema.RequestSchema): 54 | """DeleteTiDBService - 删除一个服务""" 55 | 56 | fields = { 57 | "Id": fields.Str(required=True, dump_to="Id"), 58 | "Region": fields.Str(required=True, dump_to="Region"), 59 | } 60 | 61 | 62 | class DeleteTiDBServiceResponseSchema(schema.ResponseSchema): 63 | """DeleteTiDBService - 删除一个服务""" 64 | 65 | fields = { 66 | "Message": fields.Str(required=True, load_from="Message"), 67 | "ServiceId": fields.Str(required=False, load_from="ServiceId"), 68 | } 69 | 70 | 71 | """ 72 | API: SetTiDBConfig 73 | 74 | 设置TiDB服务实例参数 75 | """ 76 | 77 | 78 | class SetTiDBConfigParamConfigsSchema(schema.RequestSchema): 79 | """SetTiDBConfigParamConfigs -""" 80 | 81 | fields = { 82 | "Name": fields.Str(required=True, dump_to="Name"), 83 | "Value": fields.Str(required=True, dump_to="Value"), 84 | } 85 | 86 | 87 | class SetTiDBConfigRequestSchema(schema.RequestSchema): 88 | """SetTiDBConfig - 设置TiDB服务实例参数""" 89 | 90 | fields = { 91 | "Configs": fields.List(SetTiDBConfigParamConfigsSchema()), 92 | "Id": fields.Str(required=True, dump_to="Id"), 93 | "ProjectId": fields.Str(required=False, dump_to="ProjectId"), 94 | "Region": fields.Str(required=True, dump_to="Region"), 95 | } 96 | 97 | 98 | class SetTiDBConfigResponseSchema(schema.ResponseSchema): 99 | """SetTiDBConfig - 设置TiDB服务实例参数""" 100 | 101 | fields = { 102 | "ServiceId": fields.Str(required=False, load_from="ServiceId"), 103 | } 104 | -------------------------------------------------------------------------------- /tests/test_unit/test_core/test_client.py: -------------------------------------------------------------------------------- 1 | import json 2 | import uuid 3 | 4 | import pytest 5 | import logging 6 | import collections 7 | import requests_mock 8 | 9 | from ucloud.client import Client 10 | from ucloud.core import exc 11 | from ucloud.core.transport import RequestsTransport, http 12 | from ucloud.testing.mock import MockedTransport 13 | 14 | from tests.test_unit.test_core import consts 15 | 16 | logger = logging.getLogger(__name__) 17 | 18 | 19 | @pytest.fixture(scope="function", autouse=True) 20 | def client(): 21 | return Client( 22 | { 23 | "region": "cn-bj2", 24 | "public_key": "foo", 25 | "private_key": "foo", 26 | "timeout": 10, 27 | "ssl_verify": False, 28 | } 29 | ) 30 | 31 | 32 | @pytest.fixture(scope="function", autouse=True) 33 | def transport(): 34 | return MockedTransport() 35 | 36 | 37 | def test_client_invoke(client): 38 | expected = {"RetCode": 0, "Action": "Foo"} 39 | with requests_mock.Mocker() as m: 40 | m.post( 41 | consts.TEST_URL, 42 | text=json.dumps(expected), 43 | headers={http.REQUEST_UUID_HEADER_KEY: str(uuid.uuid4())}, 44 | ) 45 | assert client.invoke("Foo") == expected 46 | 47 | 48 | def test_client_invoke_code_error(client): 49 | expected = {"RetCode": 171, "Action": "Foo", "Message": "签名错误"} 50 | 51 | with requests_mock.Mocker() as m: 52 | m.post( 53 | consts.TEST_URL, 54 | text=json.dumps(expected), 55 | headers={http.REQUEST_UUID_HEADER_KEY: str(uuid.uuid4())}, 56 | ) 57 | 58 | with pytest.raises(exc.RetCodeException): 59 | try: 60 | client.invoke("Foo") 61 | except exc.RetCodeException as e: 62 | assert e.retryable is False 63 | assert e.json() == { 64 | "RetCode": 171, 65 | "Action": "Foo", 66 | "Message": "签名错误", 67 | } 68 | raise e 69 | 70 | 71 | def test_client_invoke_with_retryable_error(client): 72 | # RetCodeError is retryable when code is greater than 2000 73 | with requests_mock.Mocker() as m: 74 | m.post( 75 | consts.TEST_URL, 76 | text=json.dumps({"RetCode": 10000, "Action": "Foo"}), 77 | ) 78 | with pytest.raises(exc.RetCodeException): 79 | client.invoke("Foo") 80 | 81 | 82 | def test_client_invoke_with_unexpected_error(client): 83 | def raise_error(_): 84 | raise ValueError("temporary error") 85 | 86 | transport = RequestsTransport() 87 | transport.middleware.request(raise_error) 88 | client.transport = transport 89 | 90 | with pytest.raises(ValueError): 91 | client.invoke("Foo") 92 | 93 | 94 | def test_client_try_import(client): 95 | for name in dir(client): 96 | if name.startswith("_") or name in [ 97 | "invoke", 98 | "logged_request_handler", 99 | "logged_response_handler", 100 | "logged_exception_handler", 101 | ]: 102 | continue 103 | 104 | client_factory = getattr(client, name) 105 | if isinstance(client_factory, collections.Callable): 106 | print(client_factory()) 107 | -------------------------------------------------------------------------------- /ucloud/services/uvms/schemas/apis.py: -------------------------------------------------------------------------------- 1 | """ Code is generated by ucloud-model, DO NOT EDIT IT. """ 2 | 3 | from ucloud.core.typesystem import schema, fields 4 | from ucloud.services.uvms.schemas import models 5 | 6 | """ UVMS API Schema 7 | """ 8 | 9 | 10 | """ 11 | API: GetUVMSSendRecord 12 | 13 | 获取语音发送记录 14 | """ 15 | 16 | 17 | class GetUVMSSendRecordRequestSchema(schema.RequestSchema): 18 | """GetUVMSSendRecord - 获取语音发送记录""" 19 | 20 | fields = { 21 | "BrevityCode": fields.Str(required=False, dump_to="BrevityCode"), 22 | "CalledCityCode": fields.Str(required=False, dump_to="CalledCityCode"), 23 | "CalledOperatorCode": fields.Str( 24 | required=False, dump_to="CalledOperatorCode" 25 | ), 26 | "CallingCityCode": fields.Str( 27 | required=False, dump_to="CallingCityCode" 28 | ), 29 | "EndTime": fields.Float(required=False, dump_to="EndTime"), 30 | "ExcludeBrevityCode": fields.Str( 31 | required=False, dump_to="ExcludeBrevityCode" 32 | ), 33 | "FuzzySearch": fields.Str(required=False, dump_to="FuzzySearch"), 34 | "NumPerPage": fields.Int(required=False, dump_to="NumPerPage"), 35 | "OrderBy": fields.Str(required=False, dump_to="OrderBy"), 36 | "OrderType": fields.Str(required=False, dump_to="OrderType"), 37 | "Page": fields.Int(required=False, dump_to="Page"), 38 | "PhoneNumber": fields.Str(required=False, dump_to="PhoneNumber"), 39 | "ProjectId": fields.Str(required=False, dump_to="ProjectId"), 40 | "Purpose": fields.Int(required=False, dump_to="Purpose"), 41 | "StartTime": fields.Float(required=False, dump_to="StartTime"), 42 | "TaskNo": fields.Str(required=False, dump_to="TaskNo"), 43 | "TemplateId": fields.Str(required=False, dump_to="TemplateId"), 44 | } 45 | 46 | 47 | class GetUVMSSendRecordResponseSchema(schema.ResponseSchema): 48 | """GetUVMSSendRecord - 获取语音发送记录""" 49 | 50 | fields = { 51 | "Data": fields.List( 52 | models.SendRecordItemSchema(), required=False, load_from="Data" 53 | ), 54 | "Total": fields.Int(required=False, load_from="Total"), 55 | } 56 | 57 | 58 | """ 59 | API: SendUVMSMessage 60 | 61 | 向指定号码拨打电话 62 | """ 63 | 64 | 65 | class SendUVMSMessageRequestSchema(schema.RequestSchema): 66 | """SendUVMSMessage - 向指定号码拨打电话""" 67 | 68 | fields = { 69 | "CalledNumber": fields.Str(required=True, dump_to="CalledNumber"), 70 | "DispatchRule": fields.Int(required=False, dump_to="DispatchRule"), 71 | "FromNumber": fields.Str(required=False, dump_to="FromNumber"), 72 | "GroupType": fields.Int(required=False, dump_to="GroupType"), 73 | "ProjectId": fields.Str(required=False, dump_to="ProjectId"), 74 | "TemplateId": fields.Str(required=True, dump_to="TemplateId"), 75 | "TemplateParams": fields.List(fields.Str()), 76 | "UserId": fields.Str(required=False, dump_to="UserId"), 77 | } 78 | 79 | 80 | class SendUVMSMessageResponseSchema(schema.ResponseSchema): 81 | """SendUVMSMessage - 向指定号码拨打电话""" 82 | 83 | fields = { 84 | "Message": fields.Str(required=True, load_from="Message"), 85 | "ReqUuid": fields.Str(required=True, load_from="ReqUuid"), 86 | "SessionNo": fields.Str(required=False, load_from="SessionNo"), 87 | "UserId": fields.Str(required=False, load_from="UserId"), 88 | } 89 | -------------------------------------------------------------------------------- /ucloud/services/udts/schemas/models.py: -------------------------------------------------------------------------------- 1 | """ Code is generated by ucloud-model, DO NOT EDIT IT. """ 2 | 3 | from ucloud.core.typesystem import schema, fields 4 | 5 | 6 | class CheckResultItemSchema(schema.ResponseSchema): 7 | """CheckResultItem - 预检查结果项""" 8 | 9 | fields = { 10 | "ErrMessage": fields.Str(required=True, load_from="ErrMessage"), 11 | "State": fields.Str(required=True, load_from="State"), 12 | } 13 | 14 | 15 | class CheckResultSchema(schema.ResponseSchema): 16 | """CheckResult - 预检查结果""" 17 | 18 | fields = { 19 | "Config": CheckResultItemSchema(), 20 | "Connection": CheckResultItemSchema(), 21 | "Privileges": CheckResultItemSchema(), 22 | } 23 | 24 | 25 | class CheckUDTSTaskResultSchema(schema.ResponseSchema): 26 | """CheckUDTSTaskResult - 预检查返回的结果""" 27 | 28 | fields = { 29 | "Source": CheckResultSchema(), 30 | "Target": CheckResultSchema(), 31 | } 32 | 33 | 34 | class TaskHistoryItemSchema(schema.ResponseSchema): 35 | """TaskHistoryItem - 任务历史记录中一条数据对应的 Model""" 36 | 37 | fields = { 38 | "AntID": fields.Str(required=False, load_from="AntID"), 39 | "AntState": fields.Str(required=False, load_from="AntState"), 40 | "CreateTime": fields.Int(required=False, load_from="CreateTime"), 41 | "CreateTimeH": fields.Str(required=False, load_from="CreateTimeH"), 42 | } 43 | 44 | 45 | class SyncDataSchema(schema.ResponseSchema): 46 | """SyncData - 增量同步数据""" 47 | 48 | fields = { 49 | "BinlogGTID": fields.Str(required=False, load_from="BinlogGTID"), 50 | "BinlogName": fields.Str(required=True, load_from="BinlogName"), 51 | "BinlogPos": fields.Int(required=True, load_from="BinlogPos"), 52 | "ServerId": fields.Int(required=True, load_from="ServerId"), 53 | } 54 | 55 | 56 | class ProgressSchema(schema.ResponseSchema): 57 | """Progress - 进度信息""" 58 | 59 | fields = { 60 | "CurCount": fields.Int(required=False, load_from="CurCount"), 61 | "CurDuration": fields.Int(required=False, load_from="CurDuration"), 62 | "Percentage": fields.Float(required=False, load_from="Percentage"), 63 | "TotalCount": fields.Int(required=False, load_from="TotalCount"), 64 | "TotalDuration": fields.Int(required=False, load_from="TotalDuration"), 65 | } 66 | 67 | 68 | class StatusDataSchema(schema.ResponseSchema): 69 | """StatusData - 动态状态信息""" 70 | 71 | fields = { 72 | "CurRetryCount": fields.Int(required=False, load_from="CurRetryCount"), 73 | "FailedMessage": fields.Str(required=False, load_from="FailedMessage"), 74 | "MaxRetryCount": fields.Int(required=False, load_from="MaxRetryCount"), 75 | "Progress": ProgressSchema(), 76 | "Status": fields.Str(required=False, load_from="Status"), 77 | "Sync": SyncDataSchema(), 78 | } 79 | 80 | 81 | class ListDataItemSchema(schema.ResponseSchema): 82 | """ListDataItem - 返回列表的一个 Task 的信息""" 83 | 84 | fields = { 85 | "CreateTime": fields.Int(required=False, load_from="CreateTime"), 86 | "CurRetryCount": fields.Int(required=False, load_from="CurRetryCount"), 87 | "MaxRetryCount": fields.Int(required=False, load_from="MaxRetryCount"), 88 | "Name": fields.Str(required=False, load_from="Name"), 89 | "Progress": ProgressSchema(), 90 | "Status": fields.Str(required=False, load_from="Status"), 91 | "TaskId": fields.Str(required=False, load_from="TaskId"), 92 | "Type": fields.Str(required=False, load_from="Type"), 93 | } 94 | -------------------------------------------------------------------------------- /ucloud/services/uslk/schemas/models.py: -------------------------------------------------------------------------------- 1 | """ Code is generated by ucloud-model, DO NOT EDIT IT. """ 2 | 3 | from ucloud.core.typesystem import schema, fields 4 | 5 | 6 | class RedirectRecordsSchema(schema.ResponseSchema): 7 | """RedirectRecords - 访问明细""" 8 | 9 | fields = { 10 | "AccountID": fields.Int(required=True, load_from="AccountID"), 11 | "Browser": fields.Str(required=True, load_from="Browser"), 12 | "ClientIP": fields.Str(required=True, load_from="ClientIP"), 13 | "Os": fields.Str(required=True, load_from="Os"), 14 | "ProvinceCode": fields.Str(required=True, load_from="ProvinceCode"), 15 | "RedirectTime": fields.Int(required=True, load_from="RedirectTime"), 16 | "RequestTime": fields.Int(required=True, load_from="RequestTime"), 17 | "Scenario": fields.Str(required=True, load_from="Scenario"), 18 | "ScenarioID": fields.Int(required=True, load_from="ScenarioID"), 19 | "ShortLink": fields.Str(required=True, load_from="ShortLink"), 20 | "ShortLinkDomain": fields.Str( 21 | required=True, load_from="ShortLinkDomain" 22 | ), 23 | } 24 | 25 | 26 | class SecondaryLinkForQuerySchema(schema.ResponseSchema): 27 | """SecondaryLinkForQuery - SecondaryLink查询实体""" 28 | 29 | fields = { 30 | "IsSecondary": fields.Bool(required=True, load_from="IsSecondary"), 31 | "LongLink": fields.Str(required=True, load_from="LongLink"), 32 | "LongLinkID": fields.Int(required=True, load_from="LongLinkID"), 33 | "Oses": fields.Str(required=True, load_from="Oses"), 34 | "ProvinceCodes": fields.Str(required=True, load_from="ProvinceCodes"), 35 | "Scenario": fields.Str(required=True, load_from="Scenario"), 36 | "ScenarioID": fields.Int(required=True, load_from="ScenarioID"), 37 | "ShortLongMapID": fields.Int(required=True, load_from="ShortLongMapID"), 38 | } 39 | 40 | 41 | class ShortLinkSchema(schema.ResponseSchema): 42 | """ShortLink - 短链接返回模型""" 43 | 44 | fields = { 45 | "ClickCount": fields.Int(required=True, load_from="ClickCount"), 46 | "ClickCountToday": fields.Int( 47 | required=True, load_from="ClickCountToday" 48 | ), 49 | "CreateTime": fields.Int(required=True, load_from="CreateTime"), 50 | "DeleteTime": fields.Int(required=True, load_from="DeleteTime"), 51 | "EndTime": fields.Int(required=True, load_from="EndTime"), 52 | "ID": fields.Int(required=True, load_from="ID"), 53 | "LongLinks": fields.List(fields.Str()), 54 | "Operator": fields.Str(required=True, load_from="Operator"), 55 | "Remark": fields.Str(required=True, load_from="Remark"), 56 | "Scenario": fields.Str(required=True, load_from="Scenario"), 57 | "ScenarioDesc": fields.Str(required=True, load_from="ScenarioDesc"), 58 | "ScenarioID": fields.Int(required=True, load_from="ScenarioID"), 59 | "SecondaryLinks": fields.List(SecondaryLinkForQuerySchema()), 60 | "ShortLink": fields.Str(required=True, load_from="ShortLink"), 61 | "ShortLinkDomain": fields.Str( 62 | required=True, load_from="ShortLinkDomain" 63 | ), 64 | "StartTime": fields.Int(required=True, load_from="StartTime"), 65 | "Status": fields.Int(required=True, load_from="Status"), 66 | "Type": fields.Int(required=True, load_from="Type"), 67 | "UniqueClickCount": fields.Int( 68 | required=True, load_from="UniqueClickCount" 69 | ), 70 | "UniqueClickCountToday": fields.Int( 71 | required=True, load_from="UniqueClickCountToday" 72 | ), 73 | "UpdateTime": fields.Int(required=True, load_from="UpdateTime"), 74 | } 75 | -------------------------------------------------------------------------------- /ucloud/core/transport/http.py: -------------------------------------------------------------------------------- 1 | import typing 2 | import logging 3 | import json as json_mod 4 | 5 | from ucloud.core import exc 6 | from ucloud.core.transport import utils 7 | from ucloud.core.utils.compat import str 8 | 9 | logger = logging.getLogger(__name__) 10 | 11 | 12 | class Request: 13 | def __init__( 14 | self, 15 | url: str, 16 | method: str = "GET", 17 | params: dict = None, 18 | data: dict = None, 19 | json: dict = None, 20 | headers: dict = None, 21 | **kwargs 22 | ): 23 | self.url = url 24 | self.method = method 25 | self.params = params 26 | self.data = data 27 | self.json = json 28 | self.headers = headers 29 | self.request_time = 0 30 | 31 | def payload(self): 32 | payload = (self.params or {}).copy() 33 | payload.update(self.data or {}) 34 | payload.update(self.json or {}) 35 | return payload 36 | 37 | 38 | REQUEST_UUID_HEADER_KEY = "X-UCLOUD-REQUEST-UUID" 39 | 40 | 41 | class Response: 42 | def __init__( 43 | self, 44 | url: str, 45 | method: str, 46 | request: Request = None, 47 | status_code: int = None, 48 | reason: str = None, 49 | headers: dict = None, 50 | content: bytes = None, 51 | encoding: str = None, 52 | **kwargs 53 | ): 54 | self.url = url 55 | self.method = method 56 | self.request = request 57 | self.status_code = status_code 58 | self.reason = reason 59 | self.content = content 60 | self.encoding = encoding 61 | self.response_time = 0 62 | self.headers = headers or {} 63 | self.request_uuid = self.headers.get(REQUEST_UUID_HEADER_KEY) 64 | 65 | def json(self, **kwargs) -> typing.Optional[dict]: 66 | """json will return the bytes of content""" 67 | if not self.content: 68 | return None 69 | 70 | try: 71 | return self._decode_json(**kwargs) 72 | except Exception as e: 73 | raise exc.InvalidResponseException( 74 | self.content, str(e), request_uuid=self.request_uuid 75 | ) 76 | 77 | @property 78 | def text(self): 79 | """text will return the unicode string of content, 80 | see `requests.Response.text` 81 | """ 82 | if not self.content: 83 | return str("") 84 | 85 | # Decode unicode from given encoding. 86 | try: 87 | content = str(self.content, self.encoding, errors="replace") 88 | except (LookupError, TypeError): 89 | content = str(self.content, errors="replace") 90 | return content 91 | 92 | def _decode_json(self, **kwargs): 93 | encoding = utils.guess_json_utf(self.content) 94 | if encoding is not None: 95 | try: 96 | return json_mod.loads(self.content.decode(encoding), **kwargs) 97 | except UnicodeDecodeError: 98 | pass 99 | return json_mod.loads(self.text, **kwargs) 100 | 101 | 102 | class SSLOption: 103 | def __init__( 104 | self, 105 | ssl_verify: bool = True, 106 | ssl_cacert: str = None, 107 | ssl_cert: str = None, 108 | ssl_key: str = None, 109 | ): 110 | self.ssl_verify = ssl_verify 111 | self.ssl_cacert = ssl_cacert 112 | self.ssl_cert = ssl_cert 113 | self.ssl_key = ssl_key 114 | 115 | 116 | class Transport: 117 | """the abstract class of transport implementation""" 118 | 119 | def send(self, req: Request, **options: typing.Any) -> Response: 120 | raise NotImplementedError 121 | -------------------------------------------------------------------------------- /ucloud/services/stepflow/client.py: -------------------------------------------------------------------------------- 1 | """ Code is generated by ucloud-model, DO NOT EDIT IT. """ 2 | 3 | import typing 4 | 5 | 6 | from ucloud.core.client import Client 7 | from ucloud.services.stepflow.schemas import apis 8 | 9 | 10 | class StepFlowClient(Client): 11 | def __init__( 12 | self, config: dict, transport=None, middleware=None, logger=None 13 | ): 14 | super(StepFlowClient, self).__init__( 15 | config, transport, middleware, logger 16 | ) 17 | 18 | def create_sf_workflow_from_template( 19 | self, req: typing.Optional[dict] = None, **kwargs 20 | ) -> dict: 21 | """CreateSFWorkflowFromTemplate - 导入工作流定义 22 | 23 | **Request** 24 | 25 | - **ProjectId** (str) - (Config) 项目ID。不填写为默认项目,子帐号必须填写。 请参考 `GetProjectList接口 `_ 26 | - **Region** (str) - (Config) 地域。 参见 `地域和可用区列表 `_ 27 | - **Namespace** (str) - (Required) 需要创建的工作流namespace 28 | - **Workflow** (str) - (Required) 描述工作流定义的base64字符串 29 | - **WorkflowName** (str) - (Required) 需要创建的工作流名称 30 | 31 | **Response** 32 | 33 | - **Message** (str) - 返回消息 34 | - **Version** (int) - 创建的工作流版本号 35 | 36 | """ 37 | # build request 38 | d = {"ProjectId": self.config.project_id, "Region": self.config.region} 39 | req and d.update(req) 40 | d = apis.CreateSFWorkflowFromTemplateRequestSchema().dumps(d) 41 | 42 | # build options 43 | kwargs["max_retries"] = 0 # ignore retry when api is not idempotent 44 | 45 | resp = self.invoke("CreateSFWorkflowFromTemplate", d, **kwargs) 46 | return apis.CreateSFWorkflowFromTemplateResponseSchema().loads(resp) 47 | 48 | def get_sf_workflow_template( 49 | self, req: typing.Optional[dict] = None, **kwargs 50 | ) -> dict: 51 | """GetSFWorkflowTemplate - 导出工作流定义 52 | 53 | **Request** 54 | 55 | - **ProjectId** (str) - (Config) 项目ID。不填写为默认项目,子帐号必须填写。 请参考 `GetProjectList接口 `_ 56 | - **Region** (str) - (Config) 地域。 参见 `地域和可用区列表 `_ 57 | - **WorkflowId** (str) - (Required) 被导出工作流的Id 58 | - **WorkflowVersion** (int) - 被导出工作流的版本号。取值范围:WorkflowVersion >= 1;默认会获取发布版本对应的workflow;超过最大版本会返回错误 59 | 60 | **Response** 61 | 62 | - **Message** (str) - 返回消息 63 | - **Version** (int) - 导出工作流的版本号 64 | - **Workflow** (dict) - 见 **WorkflowTemplate** 模型定义 65 | - **WorkflowId** (str) - 导出工作流的Id 66 | 67 | **Response Model** 68 | 69 | **Param** 70 | 71 | - **Name** (str) - 参数名称 72 | - **Type** (str) - 参数类型 73 | - **Value** (str) - 参数值 74 | 75 | **ActivityTemplate** 76 | 77 | - **Input** (dict) - Activity的输入 78 | - **Name** (str) - Activity的名字 79 | - **Next** (str) - 下一个Activity的名字 80 | - **Output** (list) - Activity的输出,详见Param 81 | - **RetryTimes** (str) - Activity的重试次数 82 | - **Timeout** (str) - Activity的超时时间 83 | - **Type** (str) - Activity的类型 84 | 85 | **WorkflowTemplate** 86 | 87 | - **Activites** (list) - 见 **ActivityTemplate** 模型定义 88 | - **Input** (list) - 见 **Param** 模型定义 89 | - **Output** (list) - 见 **Param** 模型定义 90 | 91 | """ 92 | # build request 93 | d = {"ProjectId": self.config.project_id, "Region": self.config.region} 94 | req and d.update(req) 95 | d = apis.GetSFWorkflowTemplateRequestSchema().dumps(d) 96 | 97 | resp = self.invoke("GetSFWorkflowTemplate", d, **kwargs) 98 | return apis.GetSFWorkflowTemplateResponseSchema().loads(resp) 99 | -------------------------------------------------------------------------------- /ucloud/helpers/wait.py: -------------------------------------------------------------------------------- 1 | import time 2 | import typing 3 | import logging 4 | from ucloud.core import exc 5 | 6 | 7 | MAX_BACKOFF_INTERVAL = 10 8 | 9 | logger = logging.getLogger(__name__) 10 | 11 | 12 | class WaitTimeoutException(exc.UCloudException): 13 | pass 14 | 15 | 16 | class StateConf: 17 | """StateConf is the utilities class to wait the state return by refresh function achieve the specific state, 18 | the generally usage is wait the cloud resource, such as uhost, udb ... is 19 | ready after created. 20 | """ 21 | 22 | def __init__( 23 | self, 24 | pending: typing.List[str], 25 | target: typing.List[str], 26 | refresh: typing.Callable, 27 | timeout: float, 28 | startup_delay: float = 0, 29 | min_backoff_interval: float = 0.1, 30 | max_backoff_interval: float = MAX_BACKOFF_INTERVAL, 31 | ): 32 | self.pending = pending 33 | self.target = target 34 | self.refresh = refresh 35 | self.timeout = timeout 36 | self.startup_delay = startup_delay 37 | self.min_backoff_interval = min_backoff_interval 38 | self.max_backoff_interval = max_backoff_interval 39 | 40 | def wait(self): 41 | start_time = time.time() 42 | interval = self.min_backoff_interval 43 | 44 | # delay on start up 45 | time.sleep(self.startup_delay) 46 | 47 | # waiting for state changed to target state 48 | while time.time() - start_time < self.timeout: 49 | state = self.refresh() 50 | 51 | if state in self.pending: 52 | time.sleep(interval) 53 | interval *= 2 54 | if interval > self.max_backoff_interval: 55 | interval = self.max_backoff_interval 56 | logger.info( 57 | "waiting state for {self.refresh}, got state {state}".format( 58 | self=self, state=state 59 | ) 60 | ) 61 | continue 62 | 63 | if state in self.target: 64 | return 65 | 66 | raise WaitTimeoutException( 67 | "wait timeout {self.timeout}s for {self.refresh}".format(self=self) 68 | ) 69 | 70 | 71 | def wait_for_state( 72 | pending: typing.List[str], 73 | target: typing.List[str], 74 | refresh: typing.Callable, 75 | timeout: float, 76 | startup_delay: float = 0, 77 | min_backoff_interval: float = 0.1, 78 | max_backoff_interval: float = MAX_BACKOFF_INTERVAL, 79 | ): 80 | """wait_for_state is a utilities function to wait the state return by refresh function achieve the specific state, 81 | the generally usage is wait the cloud resource, such as uhost, udb ... is 82 | ready after created. 83 | 84 | >>> wait_for_state( 85 | ... pending=["pending"], 86 | ... target=["running"], 87 | ... refresh=lambda: "running", 88 | ... timeout=0.5, 89 | ... ) 90 | 91 | :param pending: pending is the list of pending state, the state is returned by refresh function 92 | :param target: target is the list of target state, it is usually the terminate state, eg. running and fail 93 | :param refresh: the customized refresh function, expect no arguments and return a state 94 | :param timeout: timeout is the total time to wait state is achieved 95 | :param startup_delay: the time to wait before first refresh function is called 96 | :param min_backoff_interval: the backoff time for first refresh interval 97 | :param max_backoff_interval: the max backoff time for refresh interval 98 | """ 99 | conf = StateConf( 100 | pending=pending, 101 | target=target, 102 | refresh=refresh, 103 | timeout=timeout, 104 | startup_delay=startup_delay, 105 | min_backoff_interval=min_backoff_interval, 106 | max_backoff_interval=max_backoff_interval, 107 | ) 108 | return conf.wait() 109 | -------------------------------------------------------------------------------- /ucloud/services/uddb/schemas/models.py: -------------------------------------------------------------------------------- 1 | """ Code is generated by ucloud-model, DO NOT EDIT IT. """ 2 | 3 | from ucloud.core.typesystem import schema, fields 4 | 5 | 6 | class SlaveInfoSchema(schema.ResponseSchema): 7 | """SlaveInfo - UDDB只读实例信息""" 8 | 9 | fields = { 10 | "DataNodeId": fields.Str(required=False, load_from="DataNodeId"), 11 | "Id": fields.Str(required=False, load_from="Id"), 12 | "State": fields.Str(required=False, load_from="State"), 13 | } 14 | 15 | 16 | class DataNodeInfoSchema(schema.ResponseSchema): 17 | """DataNodeInfo - UDDB存储节点和下挂的只读实例信息""" 18 | 19 | fields = { 20 | "CreateTime": fields.Str(required=False, load_from="CreateTime"), 21 | "DiskSpace": fields.Str(required=False, load_from="DiskSpace"), 22 | "Id": fields.Str(required=False, load_from="Id"), 23 | "LastTransTaskId": fields.Str( 24 | required=False, load_from="LastTransTaskId" 25 | ), 26 | "Memory": fields.Str(required=False, load_from="Memory"), 27 | "SlaveCount": fields.Str(required=False, load_from="SlaveCount"), 28 | "SlaveInfos": fields.List(SlaveInfoSchema()), 29 | "State": fields.Str(required=False, load_from="State"), 30 | } 31 | 32 | 33 | class DataSetUDDBSchema(schema.ResponseSchema): 34 | """DataSetUDDB - UDDB信息的DataSet""" 35 | 36 | fields = { 37 | "AdminUser": fields.Str(required=False, load_from="AdminUser"), 38 | "ChargeType": fields.Str(required=False, load_from="ChargeType"), 39 | "CreateTime": fields.Str(required=False, load_from="CreateTime"), 40 | "DBTypeId": fields.Str(required=False, load_from="DBTypeId"), 41 | "DataNodeCount": fields.Str(required=False, load_from="DataNodeCount"), 42 | "DataNodeDiskSpace": fields.Str( 43 | required=False, load_from="DataNodeDiskSpace" 44 | ), 45 | "DataNodeList": fields.List(DataNodeInfoSchema()), 46 | "DataNodeMemory": fields.Str( 47 | required=False, load_from="DataNodeMemory" 48 | ), 49 | "DataNodeSlaveCount": fields.Str( 50 | required=False, load_from="DataNodeSlaveCount" 51 | ), 52 | "ExpiredTime": fields.Str(required=False, load_from="ExpiredTime"), 53 | "InstanceMode": fields.Str(required=False, load_from="InstanceMode"), 54 | "InstanceType": fields.Str(required=False, load_from="InstanceType"), 55 | "Name": fields.Str(required=False, load_from="Name"), 56 | "Port": fields.Str(required=False, load_from="Port"), 57 | "RefQps": fields.Int(required=False, load_from="RefQps"), 58 | "RouterNodeNum": fields.Int(required=False, load_from="RouterNodeNum"), 59 | "RouterVersion": fields.Str(required=False, load_from="RouterVersion"), 60 | "State": fields.Str(required=False, load_from="State"), 61 | "UDDBId": fields.Str(required=False, load_from="UDDBId"), 62 | "VirtualIP": fields.Str(required=False, load_from="VirtualIP"), 63 | "Zone": fields.Str(required=False, load_from="Zone"), 64 | } 65 | 66 | 67 | class PriceDetailInfoSchema(schema.ResponseSchema): 68 | """PriceDetailInfo - UDDB实例计费详情""" 69 | 70 | fields = { 71 | "DataNodePrice": fields.Float( 72 | required=False, load_from="DataNodePrice" 73 | ), 74 | "DataNodeSlavePrice": fields.Float( 75 | required=False, load_from="DataNodeSlavePrice" 76 | ), 77 | "MiddlewarePrice": fields.Float( 78 | required=False, load_from="MiddlewarePrice" 79 | ), 80 | } 81 | 82 | 83 | class PriceInfoSchema(schema.ResponseSchema): 84 | """PriceInfo - UDDB实例计费详情""" 85 | 86 | fields = { 87 | "DataNodePrice": fields.Float( 88 | required=False, load_from="DataNodePrice" 89 | ), 90 | "DataNodeSlavePrice": fields.Float( 91 | required=False, load_from="DataNodeSlavePrice" 92 | ), 93 | "MiddlewarePrice": fields.Float( 94 | required=False, load_from="MiddlewarePrice" 95 | ), 96 | } 97 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Licensed to the Apache Software Foundation (ASF) under one 4 | # or more contributor license agreements. See the NOTICE file 5 | # distributed with this work for additional information 6 | # regarding copyright ownership. The ASF licenses this file 7 | # to you under the Apache License, Version 2.0 (the 8 | # "License"); you may not use this file except in compliance 9 | # with the License. You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, 14 | # software distributed under the License is distributed on an 15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | # KIND, either express or implied. See the License for the 17 | # specific language governing permissions and limitations 18 | # under the License. 19 | 20 | from setuptools import setup, find_packages 21 | 22 | import importlib 23 | import io 24 | import logging 25 | import os 26 | import sys 27 | 28 | logger = logging.getLogger(__name__) 29 | 30 | PY3 = sys.version_info[0] == 3 and sys.version_info[1] >= 5 31 | 32 | if not PY3: 33 | raise NotImplementedError( 34 | ("ucloud-sdk-python3 should be used in 3.5 " "and above of python interpreter") 35 | ) 36 | 37 | 38 | def load_version(): 39 | return importlib.import_module( 40 | "ucloud.version", os.path.join("ucloud", "version.py") 41 | ).version 42 | 43 | 44 | def load_long_description(): 45 | try: 46 | with io.open("README.md", encoding="utf-8") as f: 47 | return f.read() 48 | except FileNotFoundError: 49 | return "" 50 | 51 | 52 | def load_requirements(requirements_file): 53 | try: 54 | with io.open(requirements_file, encoding="utf-8") as f: 55 | return list(f.readlines()) 56 | except FileNotFoundError: 57 | return [] 58 | 59 | 60 | dependencies = load_requirements("requirements.txt") 61 | 62 | dependencies_test = dependencies + ["flake8>=3.6.0", "pytest>=4.6", "pytest-cov", "requests_mock"] 63 | 64 | dependencies_doc = dependencies + ["sphinx"] 65 | 66 | dependencies_ci = list(set(dependencies_test + dependencies_doc)) 67 | 68 | dependencies_dev = list(set(dependencies_ci + ["black"])) 69 | 70 | 71 | def do_setup(): 72 | setup( 73 | name="ucloud-sdk-python3", 74 | description="UCloud Service Development Kit - Python", 75 | long_description=load_long_description(), 76 | long_description_content_type="text/markdown", 77 | license="Apache License 2.0", 78 | version=load_version(), 79 | packages=find_packages(exclude=["tests*"]), 80 | package_data={"": []}, 81 | include_package_data=True, 82 | zip_safe=False, 83 | install_requires=dependencies, 84 | extras_require={ 85 | "test": dependencies_test, 86 | "doc": dependencies_doc, 87 | "dev": dependencies_dev, 88 | "ci": dependencies_ci, 89 | }, 90 | dependencies_test=dependencies_test, 91 | classifiers=[ 92 | "Development Status :: 3 - Alpha", 93 | "Environment :: Console", 94 | "Environment :: Web Environment", 95 | "Intended Audience :: Developers", 96 | "Intended Audience :: System Administrators", 97 | "License :: OSI Approved :: Apache Software License", 98 | "Programming Language :: Python :: 3 :: Only", 99 | "Programming Language :: Python :: 3.5", 100 | "Programming Language :: Python :: 3.6", 101 | "Programming Language :: Python :: 3.7", 102 | "Topic :: Software Development", 103 | ], 104 | author="ucloud", 105 | author_email="esl_ipdd@ucloud.cn", 106 | url="https://github.com/ucloud/ucloud-sdk-python3", 107 | python_requires=">=3.5", 108 | ) 109 | 110 | 111 | if __name__ == "__main__": 112 | do_setup() 113 | -------------------------------------------------------------------------------- /ucloud/core/client/_cfg.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | from ucloud.core.typesystem import schema, fields 4 | 5 | 6 | class ConfigSchema(schema.Schema): 7 | fields = { 8 | "region": fields.Str(), 9 | "project_id": fields.Str(), 10 | "base_url": fields.Str(default="https://api.ucloud.cn"), 11 | "user_agent": fields.Str(), 12 | "timeout": fields.Int(default=30), 13 | "max_retries": fields.Int(default=0), 14 | "log_level": fields.Int(default=logging.INFO), 15 | "validate_request": fields.Bool(default=True), 16 | "ssl_verify": fields.Bool(default=True), 17 | "ssl_cacert": fields.Str(), 18 | "ssl_cert": fields.Str(), 19 | "ssl_key": fields.Str(), 20 | } 21 | 22 | 23 | class Config: 24 | """ 25 | Config is the config of ucloud sdk, use for setting up 26 | 27 | :type region: str 28 | :param region: Region is the region of backend service, 29 | See also `Region list Documentation `_ 30 | :type project_id: str 31 | :param project_id: ProjectId is the unique identify of project, used for organize resources, 32 | Most of resources should belong to a project. Sub-Account must have an project id. 33 | See also `Project list Documentation `_ 34 | :type base_url: str 35 | :param base_url: BaseUrl is the url of backend api 36 | :param user_agent: UserAgent is an attribute for sdk client, used for distinguish who is using sdk. 37 | See also `User Agent `_ 38 | It will be appended to the end of sdk user-agent. 39 | eg. "MyAPP/0.10.1" -> "Python/3.7.0 Python-SDK/0.1.0 MyAPP/0.10.1" 40 | :type timeout: int 41 | :param timeout: Timeout is timeout for every request. 42 | :type max_retries: int 43 | :param max_retries: MaxRetries is the number of max retry times. 44 | Set MaxRetries more than 0 to enable auto-retry for network and service availability problem 45 | if auto-retry is enabled, it will enable default retry policy using exponential backoff. 46 | :type log_level: int 47 | :param log_level: LogLevel is equal to builtin logging level, 48 | if logLevel not be set, use INFO level as default. 49 | """ 50 | 51 | def __init__( 52 | self, 53 | region: str = None, 54 | project_id: str = None, 55 | base_url: str = "https://api.ucloud.cn", 56 | user_agent: str = None, 57 | timeout: int = 30, 58 | max_retries: int = 3, 59 | log_level: int = logging.INFO, 60 | ssl_verify: bool = True, 61 | ssl_cacert: str = None, 62 | ssl_cert: str = None, 63 | ssl_key: str = None, 64 | **kwargs 65 | ): 66 | self.region = region 67 | self.project_id = project_id 68 | self.base_url = base_url 69 | self.user_agent = user_agent 70 | self.timeout = timeout 71 | self.max_retries = max_retries 72 | self.log_level = log_level 73 | self.ssl_verify = ssl_verify 74 | self.ssl_cacert = ssl_cacert 75 | self.ssl_cert = ssl_cert 76 | self.ssl_key = ssl_key 77 | 78 | @classmethod 79 | def from_dict(cls, d: dict): 80 | parsed = ConfigSchema().dumps(d) 81 | return cls(**parsed) 82 | 83 | def to_dict(self) -> dict: 84 | return { 85 | "region": self.region, 86 | "project_id": self.project_id, 87 | "base_url": self.base_url, 88 | "user_agent": self.user_agent, 89 | "timeout": self.timeout, 90 | "max_retries": self.max_retries, 91 | "log_level": self.log_level, 92 | "ssl_verify": self.ssl_verify, 93 | "ssl_cacert": self.ssl_cacert, 94 | "ssl_cert": self.ssl_cert, 95 | "ssl_key": self.ssl_key, 96 | } 97 | -------------------------------------------------------------------------------- /tests/test_unit/test_core/test_transport.py: -------------------------------------------------------------------------------- 1 | import json 2 | import uuid 3 | 4 | import pytest 5 | import logging 6 | import requests_mock 7 | from collections import Counter 8 | 9 | from tests.test_unit.test_core.consts import TEST_URL 10 | from ucloud.core import exc 11 | from ucloud.core.transport import ( 12 | RequestsTransport, 13 | Request, 14 | Response, 15 | utils, 16 | http, 17 | ) 18 | 19 | logger = logging.getLogger(__name__) 20 | 21 | 22 | @pytest.fixture(name="transport", scope="function", autouse=True) 23 | def transport_factory(): 24 | return RequestsTransport() 25 | 26 | 27 | @pytest.mark.parametrize( 28 | argnames=("status_code", "content", "expect", "expect_exc", "retryable"), 29 | argvalues=( 30 | ( 31 | 200, 32 | '{"Action": "Mock", "RetCode": 0}', 33 | {"Action": "Mock", "RetCode": 0}, 34 | None, 35 | False, 36 | ), 37 | (500, "{}", None, exc.HTTPStatusException, False), 38 | (429, "{}", None, exc.HTTPStatusException, True), 39 | (500, "x", None, exc.HTTPStatusException, False), 40 | (200, "x", None, exc.InvalidResponseException, False), 41 | ), 42 | ) 43 | def test_transport( 44 | transport, status_code, content, expect, expect_exc, retryable 45 | ): 46 | with requests_mock.Mocker() as m: 47 | m.post(TEST_URL, text=content, status_code=status_code) 48 | 49 | got_exc = None 50 | try: 51 | resp = transport.send(Request(url=TEST_URL, method="post", json={})) 52 | assert resp.json() == expect 53 | except Exception as e: 54 | got_exc = e 55 | 56 | if expect_exc: 57 | assert str(got_exc) 58 | assert got_exc.retryable == retryable 59 | assert isinstance(got_exc, expect_exc) 60 | 61 | 62 | def test_transport_handler(transport): 63 | req_key, resp_key, exc_key = "req", "resp", "exc" 64 | counter = Counter({req_key: 0, resp_key: 0, exc_key: 0}) 65 | 66 | def request_handler(r): 67 | counter[req_key] += 1 68 | return r 69 | 70 | def response_handler(r): 71 | counter[resp_key] += 1 72 | return r 73 | 74 | def exception_handler(r): 75 | counter[exc_key] += 1 76 | return r 77 | 78 | transport.middleware.request(handler=request_handler) 79 | transport.middleware.response(handler=response_handler) 80 | transport.middleware.exception(handler=exception_handler) 81 | 82 | expect = {"foo": "bar"} 83 | req = Request(url=TEST_URL, method="post", json=expect) 84 | 85 | with requests_mock.Mocker() as m: 86 | request_uuid = str(uuid.uuid4()) 87 | m.post( 88 | TEST_URL, 89 | text=json.dumps(expect), 90 | status_code=200, 91 | headers={http.REQUEST_UUID_HEADER_KEY: request_uuid}, 92 | ) 93 | resp = transport.send(req) 94 | assert resp.text 95 | assert resp.json() == expect 96 | assert resp.request_uuid == request_uuid 97 | 98 | with pytest.raises(Exception): 99 | transport.send(Request(url="/")) 100 | 101 | assert counter[req_key] == 2 102 | assert counter[resp_key] == 1 103 | assert counter[exc_key] == 1 104 | 105 | 106 | def test_guess_json_utf(): 107 | encodings = [ 108 | "utf-32", 109 | "utf-8-sig", 110 | "utf-16", 111 | "utf-8", 112 | "utf-16-be", 113 | "utf-16-le", 114 | "utf-32-be", 115 | "utf-32-le", 116 | ] 117 | for e in encodings: 118 | s = json.dumps("表意字符").encode(e) 119 | assert utils.guess_json_utf(s) == e 120 | 121 | 122 | def test_request_methods(): 123 | req = Request( 124 | TEST_URL, data={"foo": 42}, json={"bar": 42}, params={"q": "search"} 125 | ) 126 | assert req.payload() == {"foo": 42, "bar": 42, "q": "search"} 127 | 128 | 129 | def test_response_methods(): 130 | r = Response(TEST_URL, "post") 131 | assert not r.text 132 | assert r.json() is None 133 | 134 | r = Response(TEST_URL, "post", content=b"\xd6", encoding="utf-8") 135 | with pytest.raises(exc.InvalidResponseException): 136 | assert r.json() is None 137 | -------------------------------------------------------------------------------- /ucloud/services/tidb/client.py: -------------------------------------------------------------------------------- 1 | """ Code is generated by ucloud-model, DO NOT EDIT IT. """ 2 | 3 | import typing 4 | 5 | 6 | from ucloud.core.client import Client 7 | from ucloud.services.tidb.schemas import apis 8 | 9 | 10 | class TiDBClient(Client): 11 | def __init__( 12 | self, config: dict, transport=None, middleware=None, logger=None 13 | ): 14 | super(TiDBClient, self).__init__(config, transport, middleware, logger) 15 | 16 | def create_ti_db_service( 17 | self, req: typing.Optional[dict] = None, **kwargs 18 | ) -> dict: 19 | """CreateTiDBService - 创建TiDB服务 20 | 21 | **Request** 22 | 23 | - **ProjectId** (str) - (Config) 项目 ID 24 | - **Region** (str) - (Config) 地域。 参见 `地域和可用区列表 `_ 25 | - **Name** (str) - (Required) 服务名称, 长度不超过64 26 | - **Password** (str) - (Required) 服务root账号的密码, 长度不超过32 27 | - **SubnetId** (str) - (Required) 子网 ID 28 | - **VPCId** (str) - (Required) VPC ID 29 | - **DTType** (str) - 容灾类型:10:同可用区,20:跨可用区,默认是同可用区 30 | - **Ip** (str) - ipv4 31 | - **Port** (str) - 端口 32 | - **TikvMemoryHardTh** (str) - 实例类型: 0: 旗舰版,30: 体验版,60: 轻量版 33 | 34 | **Response** 35 | 36 | - **Data** (dict) - 见 **ServiceID** 模型定义 37 | - **Message** (str) - 返回信息 38 | - **ServiceId** (str) - 服务ID 39 | 40 | **Response Model** 41 | 42 | **ServiceID** 43 | - **Id** (str) - 服务ID 44 | 45 | 46 | """ 47 | # build request 48 | d = { 49 | "ProjectId": self.config.project_id, 50 | "Region": self.config.region, 51 | } 52 | req and d.update(req) 53 | d = apis.CreateTiDBServiceRequestSchema().dumps(d) 54 | 55 | # build options 56 | kwargs["max_retries"] = 0 # ignore retry when api is not idempotent 57 | 58 | resp = self.invoke("CreateTiDBService", d, **kwargs) 59 | return apis.CreateTiDBServiceResponseSchema().loads(resp) 60 | 61 | def delete_ti_db_service( 62 | self, req: typing.Optional[dict] = None, **kwargs 63 | ) -> dict: 64 | """DeleteTiDBService - 删除一个服务 65 | 66 | **Request** 67 | 68 | - **Region** (str) - (Config) 地域。 参见 `地域和可用区列表 `_ 69 | - **Id** (str) - (Required) 资源ID 70 | 71 | **Response** 72 | 73 | - **Message** (str) - 返回信息 74 | - **ServiceId** (str) - ServiceId 75 | 76 | """ 77 | # build request 78 | d = { 79 | "Region": self.config.region, 80 | } 81 | req and d.update(req) 82 | d = apis.DeleteTiDBServiceRequestSchema().dumps(d) 83 | 84 | resp = self.invoke("DeleteTiDBService", d, **kwargs) 85 | return apis.DeleteTiDBServiceResponseSchema().loads(resp) 86 | 87 | def set_ti_db_config( 88 | self, req: typing.Optional[dict] = None, **kwargs 89 | ) -> dict: 90 | """SetTiDBConfig - 设置TiDB服务实例参数 91 | 92 | **Request** 93 | 94 | - **ProjectId** (str) - (Config) 项目ID。不填写为默认项目,子帐号必须填写。 请参考 `GetProjectList接口 `_ 95 | - **Region** (str) - (Config) 地域。 参见 `地域和可用区列表 `_ 96 | - **Id** (str) - (Required) 资源Id 97 | - **Configs** (list) - 见 **SetTiDBConfigParamConfigs** 模型定义 98 | 99 | **Response** 100 | 101 | - **ServiceId** (str) - ServiceId 102 | 103 | **Request Model** 104 | 105 | **SetTiDBConfigParamConfigs** 106 | - **Name** (str) - 修改的参数名: proxysql_mysql-max_connections:类型:string, 描述: 所有用户总共的最大连接数 。proxysql_max_connections: 类型:string, 描述: 每个用户的最大连接数。tidb_gc: 类型:string, 描述: tikv_gc_life_time。 107 | - **Value** (str) - 对应修改的参数值: string 108 | 109 | 110 | """ 111 | # build request 112 | d = { 113 | "ProjectId": self.config.project_id, 114 | "Region": self.config.region, 115 | } 116 | req and d.update(req) 117 | d = apis.SetTiDBConfigRequestSchema().dumps(d) 118 | 119 | resp = self.invoke("SetTiDBConfig", d, **kwargs) 120 | return apis.SetTiDBConfigResponseSchema().loads(resp) 121 | -------------------------------------------------------------------------------- /ucloud/services/urocketmq/client.py: -------------------------------------------------------------------------------- 1 | """ Code is generated by ucloud-model, DO NOT EDIT IT. """ 2 | 3 | import typing 4 | 5 | 6 | from ucloud.core.client import Client 7 | from ucloud.services.urocketmq.schemas import apis 8 | 9 | 10 | class URocketMQClient(Client): 11 | def __init__( 12 | self, config: dict, transport=None, middleware=None, logger=None 13 | ): 14 | super(URocketMQClient, self).__init__( 15 | config, transport, middleware, logger 16 | ) 17 | 18 | def create_u_rocket_mq_group( 19 | self, req: typing.Optional[dict] = None, **kwargs 20 | ) -> dict: 21 | """CreateURocketMQGroup - 创建一个 Group, 如果同名 Group 在当前 Service 中已存在, 则会失败. 22 | 23 | **Request** 24 | 25 | - **ProjectId** (str) - (Config) 项目ID。 请参考 `GetProjectList接口 `_ 26 | - **Region** (str) - (Config) 地域。 参见 `地域和可用区列表 `_ 27 | - **Name** (str) - (Required) Group 名称,支持大小写字母、数字及-, _ ,长度1~36 28 | - **ServiceId** (str) - (Required) Service ID 29 | - **Remark** (str) - Group 描述. 30 | 31 | **Response** 32 | 33 | - **GroupId** (str) - 新建 Group 的 ID 34 | - **Message** (str) - 返回信息 35 | 36 | """ 37 | # build request 38 | d = { 39 | "ProjectId": self.config.project_id, 40 | "Region": self.config.region, 41 | } 42 | req and d.update(req) 43 | d = apis.CreateURocketMQGroupRequestSchema().dumps(d) 44 | 45 | # build options 46 | kwargs["max_retries"] = 0 # ignore retry when api is not idempotent 47 | 48 | resp = self.invoke("CreateURocketMQGroup", d, **kwargs) 49 | return apis.CreateURocketMQGroupResponseSchema().loads(resp) 50 | 51 | def delete_u_rocket_mq_group( 52 | self, req: typing.Optional[dict] = None, **kwargs 53 | ) -> dict: 54 | """DeleteURocketMQGroup - 删除一个已存在的 Group 55 | 56 | **Request** 57 | 58 | - **ProjectId** (str) - (Config) 项目ID。 请参考 `GetProjectList接口 `_ 59 | - **Region** (str) - (Config) 地域。 参见 `地域和可用区列表 `_ 60 | - **GroupName** (str) - (Required) Group名称 61 | - **ServiceId** (str) - (Required) Service ID 62 | 63 | **Response** 64 | 65 | - **Message** (str) - 返回信息 66 | 67 | """ 68 | # build request 69 | d = { 70 | "ProjectId": self.config.project_id, 71 | "Region": self.config.region, 72 | } 73 | req and d.update(req) 74 | d = apis.DeleteURocketMQGroupRequestSchema().dumps(d) 75 | 76 | resp = self.invoke("DeleteURocketMQGroup", d, **kwargs) 77 | return apis.DeleteURocketMQGroupResponseSchema().loads(resp) 78 | 79 | def list_u_rocket_mq_group( 80 | self, req: typing.Optional[dict] = None, **kwargs 81 | ) -> dict: 82 | """ListURocketMQGroup - 获取一个 RocketMQ 服务下的所有 Group 83 | 84 | **Request** 85 | 86 | - **ProjectId** (str) - (Config) 项目ID。 请参考 `GetProjectList接口 `_ 87 | - **Region** (str) - (Config) 地域。 参见 `地域和可用区列表 `_ 88 | - **ServiceId** (str) - (Required) Service ID 89 | - **Limit** (int) - 最多返回的条目数量, (0, 1000], 默认 50 条 90 | - **Offset** (int) - 查询起始位置, [0, ∞) 91 | 92 | **Response** 93 | 94 | - **GroupList** (list) - 见 **GroupBaseInfo** 模型定义 95 | - **Message** (str) - 返回信息 96 | - **TotalCount** (int) - 记录总数 97 | 98 | **Response Model** 99 | 100 | **GroupBaseInfo** 101 | - **CreateTime** (int) - Group 创建时间 102 | - **GroupName** (str) - Group 名称 103 | - **Id** (str) - Group ID 104 | - **Remark** (str) - Group 描述 105 | 106 | 107 | """ 108 | # build request 109 | d = { 110 | "ProjectId": self.config.project_id, 111 | "Region": self.config.region, 112 | } 113 | req and d.update(req) 114 | d = apis.ListURocketMQGroupRequestSchema().dumps(d) 115 | 116 | resp = self.invoke("ListURocketMQGroup", d, **kwargs) 117 | return apis.ListURocketMQGroupResponseSchema().loads(resp) 118 | -------------------------------------------------------------------------------- /examples/two-tier/main.py: -------------------------------------------------------------------------------- 1 | import os 2 | import logging 3 | import random 4 | 5 | from ucloud.client import Client 6 | from ucloud.helpers import wait, utils 7 | 8 | logger = logging.getLogger("ucloud") 9 | logger.setLevel(logging.DEBUG) 10 | 11 | # NOTE: find your public/private key at 12 | # website `UAPI `_ 13 | client = Client( 14 | { 15 | "region": "cn-bj2", 16 | "project_id": os.getenv("UCLOUD_PROJECT_ID"), 17 | "public_key": os.getenv("UCLOUD_PUBLIC_KEY"), 18 | "private_key": os.getenv("UCLOUD_PRIVATE_KEY"), 19 | } 20 | ) 21 | 22 | 23 | def main(): 24 | image_id = describe_image() 25 | 26 | uhost_ids = create_uhost_batch(image_id, 2) 27 | 28 | ulb_id = create_ulb() 29 | 30 | vserver_id = create_vserver(ulb_id) 31 | 32 | backend_ids = allocate_backend_batch(ulb_id, vserver_id, uhost_ids) 33 | 34 | backend_ids and release_backend_batch(ulb_id, vserver_id, backend_ids) 35 | 36 | vserver_id and delete_vserver(ulb_id, vserver_id) 37 | 38 | ulb_id and delete_ulb(ulb_id) 39 | 40 | uhost_ids and delete_uhost_batch(uhost_ids) 41 | 42 | 43 | def describe_image(): 44 | images = ( 45 | client.uhost().describe_image({"ImageType": "Base"}).get("ImageSet", []) 46 | ) 47 | if not images: 48 | return 49 | image = random.choice(images) 50 | return image.get("ImageId") 51 | 52 | 53 | def mget_uhost_states(uhost_ids): 54 | resp = client.uhost().describe_uhost_instance({"UHostIds": uhost_ids}) 55 | return [inst.get("State") for inst in resp.get("UHostSet")] 56 | 57 | 58 | def create_uhost_batch(image_id, count): 59 | resp = client.uhost().create_uhost_instance( 60 | { 61 | "Name": "sdk-python3-example-two-tier", 62 | "Zone": "cn-bj2-05", 63 | "ImageId": image_id, 64 | "LoginMode": "Password", 65 | "Password": utils.gen_password(20), 66 | "CPU": 1, 67 | "Memory": 1024, 68 | "MaxCount": count, 69 | } 70 | ) 71 | uhost_ids = resp.get("UHostIds", []) 72 | wait.wait_for_state( 73 | target=["running"], 74 | pending=["pending"], 75 | timeout=300, 76 | refresh=lambda: ( 77 | "running" 78 | if all( 79 | [state == "Running" for state in mget_uhost_states(uhost_ids)] 80 | ) 81 | else "pending" 82 | ), 83 | ) 84 | return uhost_ids 85 | 86 | 87 | def create_ulb(): 88 | resp = client.ulb().create_ulb({"Name": "sdk-python3-example-two-tier"}) 89 | return resp.get("ULBId") 90 | 91 | 92 | def create_vserver(ulb_id): 93 | resp = client.ulb().create_vserver( 94 | {"Name": "sdk-python3-example-two-tier", "ULBId": ulb_id} 95 | ) 96 | return resp.get("VServerId") 97 | 98 | 99 | def allocate_backend_batch(ulb_id, vserver_id, uhost_ids): 100 | backend_ids = [] 101 | for uhost_id in uhost_ids: 102 | resp = client.ulb().allocate_backend( 103 | { 104 | "ULBId": ulb_id, 105 | "VServerId": vserver_id, 106 | "ResourceId": uhost_id, 107 | "ResourceType": "UHost", 108 | } 109 | ) 110 | backend_ids.append(resp.get("BackendId")) 111 | return backend_ids 112 | 113 | 114 | def release_backend_batch(ulb_id, vserver_id, backend_ids): 115 | for backend_id in backend_ids: 116 | client.ulb().release_backend( 117 | {"ULBId": ulb_id, "VServerId": vserver_id, "BackendId": backend_id} 118 | ) 119 | 120 | 121 | def delete_vserver(ulb_id, vserver_id): 122 | client.ulb().delete_vserver({"ULBId": ulb_id, "VServerId": vserver_id}) 123 | 124 | 125 | def delete_ulb(ulb_id): 126 | client.ulb().delete_ulb({"ULBId": ulb_id}) 127 | 128 | 129 | def delete_uhost_batch(uhost_ids): 130 | for uhost_id in uhost_ids: 131 | client.uhost().stop_uhost_instance({"UHostId": uhost_id}) 132 | 133 | wait.wait_for_state( 134 | target=["stopped"], 135 | pending=["pending"], 136 | timeout=300, 137 | refresh=lambda: ( 138 | "stopped" 139 | if all( 140 | [state == "Stopped" for state in mget_uhost_states(uhost_ids)] 141 | ) 142 | else "pending" 143 | ), 144 | ) 145 | 146 | for uhost_id in uhost_ids: 147 | client.uhost().terminate_uhost_instance({"UHostId": uhost_id}) 148 | 149 | 150 | if __name__ == "__main__": 151 | main() 152 | -------------------------------------------------------------------------------- /ucloud/core/typesystem/fields.py: -------------------------------------------------------------------------------- 1 | import base64 2 | import typing 3 | from collections.abc import Iterable 4 | 5 | from ucloud.core.typesystem import abstract 6 | from ucloud.core.exc import ValidationException 7 | from ucloud.core.utils.compat import str 8 | 9 | 10 | class List(abstract.Field): 11 | """array param is the custom field to parse custom param such as: 12 | 13 | - IP.N 14 | - UDisk.N.Size 15 | - NetInterface.N.EIP.Bandwidth 16 | """ 17 | 18 | def __init__( 19 | self, 20 | item: typing.Union[abstract.Field, abstract.Schema], 21 | default=list, 22 | **kwargs 23 | ): 24 | super(List, self).__init__(default=default, **kwargs) 25 | self.item = item 26 | 27 | def dumps(self, value, name=None, **kwargs): 28 | if not isinstance(value, Iterable): 29 | raise ValidationException( 30 | "invalid field {}, expect list, got {}".format( 31 | name, type(value) 32 | ) 33 | ) 34 | 35 | errors = [] 36 | values = [] 37 | for each in value: 38 | try: 39 | v = self.item.dumps(each) 40 | except ValidationException as e: 41 | errors.extend(e.errors) 42 | else: 43 | values.append(v) 44 | 45 | if len(errors) > 0: 46 | raise ValidationException(errors) 47 | 48 | return values 49 | 50 | def loads(self, value, name=None, **kwargs): 51 | if not isinstance(value, Iterable): 52 | raise ValidationException( 53 | "invalid field {}, expect list, got {}".format( 54 | name, type(value) 55 | ) 56 | ) 57 | 58 | errors = [] 59 | values = [] 60 | for each in value: 61 | try: 62 | v = self.item.loads(each) 63 | except ValidationException as e: 64 | errors.extend(e.errors) 65 | else: 66 | values.append(v) 67 | 68 | if len(errors) > 0: 69 | raise ValidationException(errors) 70 | 71 | return values 72 | 73 | 74 | class Str(abstract.Field): 75 | def dumps(self, value, name=None, **kwargs): 76 | return self._convert(value, name) 77 | 78 | def loads(self, value, name=None, **kwargs): 79 | return self._convert(value, name) 80 | 81 | def _convert(self, value, name=None): 82 | if self.strict and not isinstance(value, str): 83 | self.fail(name, "str", type(value)) 84 | 85 | return str(value) 86 | 87 | 88 | class Base64(Str): 89 | def dumps(self, value, name=None, **kwargs): 90 | s = super(Base64, self).dumps(value, name) 91 | return base64.b64encode(s.encode()).decode() 92 | 93 | def loads(self, value, name=None, **kwargs): 94 | s = super(Base64, self).loads(value, name) 95 | return base64.b64decode(s.encode()).decode() 96 | 97 | 98 | class Int(abstract.Field): 99 | def dumps(self, value, name=None, **kwargs): 100 | return self._convert(value, name) 101 | 102 | def loads(self, value, name=None, **kwargs): 103 | return self._convert(value, name) 104 | 105 | def _convert(self, value, name=None): 106 | if self.strict and not isinstance(value, int): 107 | self.fail(name, "int", type(value)) 108 | 109 | try: 110 | return int(value) 111 | except ValueError: 112 | self.fail(name, "int", type(value)) 113 | 114 | 115 | class Float(abstract.Field): 116 | def dumps(self, value, name=None, **kwargs): 117 | return self._convert(value, name) 118 | 119 | def loads(self, value, name=None, **kwargs): 120 | return self._convert(value, name) 121 | 122 | def _convert(self, value, name=None): 123 | if self.strict and not isinstance(value, float): 124 | self.fail(name, "float", type(value)) 125 | 126 | try: 127 | return float(value) 128 | except ValueError: 129 | self.fail(name, "float", type(value)) 130 | 131 | 132 | class Bool(abstract.Field): 133 | def dumps(self, value, name=None, **kwargs): 134 | return self._convert(value, name) 135 | 136 | def loads(self, value, name=None, **kwargs): 137 | return self._convert(value, name) 138 | 139 | def _convert(self, value, name=None): 140 | if self.strict and not isinstance(value, bool): 141 | self.fail(name, "bool", type(value)) 142 | 143 | if value == "true" or value is True: 144 | return True 145 | 146 | if value == "false" or value is False: 147 | return False 148 | 149 | self.fail(name, "bool", type(value)) 150 | -------------------------------------------------------------------------------- /tests/test_services/test_set_2935.py: -------------------------------------------------------------------------------- 1 | """ Code is generated by ucloud-model, DO NOT EDIT IT. """ 2 | 3 | import pytest 4 | import logging 5 | 6 | from ucloud.core import exc 7 | from ucloud.testing import env, funcs, op, utest 8 | 9 | logger = logging.getLogger(__name__) 10 | 11 | 12 | scenario = utest.Scenario(2935) 13 | 14 | 15 | @pytest.mark.skipif(env.is_ut(), reason=env.get_skip_reason()) 16 | def test_set_2935(client: utest.Client, variables: dict): 17 | scenario.initial(variables) 18 | 19 | scenario.variables["Image_Id_ucloud"] = ( 20 | "#{u_get_image_resource($Region,$Zone)}" 21 | ) 22 | scenario.variables["saopaulo_image"] = "uimage-1bkjka" 23 | 24 | scenario.run(client) 25 | 26 | 27 | @scenario.step( 28 | max_retries=3, 29 | retry_interval=1, 30 | startup_delay=0, 31 | fast_fail=False, 32 | validators=lambda variables: [ 33 | ("str_eq", "RetCode", 0), 34 | ("str_eq", "Action", "DescribeImageResponse"), 35 | ], 36 | action="DescribeImage", 37 | ) 38 | def describe_image_00(client: utest.Client, variables: dict): 39 | d = { 40 | "Zone": variables.get("Zone"), 41 | "Region": variables.get("Region"), 42 | "OsType": "Linux", 43 | "ImageType": "Base", 44 | } 45 | 46 | try: 47 | resp = client.uhost().describe_image(d) 48 | except exc.RetCodeException as e: 49 | resp = e.json() 50 | 51 | variables["Image_Id_ucloud"] = utest.value_at_path( 52 | resp, "ImageSet.0.ImageId" 53 | ) 54 | return resp 55 | 56 | 57 | @scenario.step( 58 | max_retries=10, 59 | retry_interval=10, 60 | startup_delay=0, 61 | fast_fail=False, 62 | validators=lambda variables: [("str_eq", "RetCode", 0)], 63 | action="CreateULB", 64 | ) 65 | def create_ulb_01(client: utest.Client, variables: dict): 66 | d = { 67 | "ULBName": "测试", 68 | "Tag": "Default", 69 | "Region": variables.get("Region"), 70 | "InnerMode": "No", 71 | } 72 | 73 | try: 74 | resp = client.ulb().create_ulb(d) 75 | except exc.RetCodeException as e: 76 | resp = e.json() 77 | 78 | variables["ULBId"] = utest.value_at_path(resp, "ULBId") 79 | return resp 80 | 81 | 82 | @scenario.step( 83 | max_retries=10, 84 | retry_interval=10, 85 | startup_delay=5, 86 | fast_fail=False, 87 | validators=lambda variables: [ 88 | ("str_eq", "RetCode", 0), 89 | ("len_ge", "DataSet", 1), 90 | ], 91 | action="DescribeULBSimple", 92 | ) 93 | def describe_ulb_simple_02(client: utest.Client, variables: dict): 94 | d = {"Region": variables.get("Region")} 95 | 96 | try: 97 | resp = client.invoke("DescribeULBSimple", d) 98 | except exc.RetCodeException as e: 99 | resp = e.json() 100 | 101 | return resp 102 | 103 | 104 | @scenario.step( 105 | max_retries=10, 106 | retry_interval=1, 107 | startup_delay=0, 108 | fast_fail=False, 109 | validators=lambda variables: [ 110 | ("str_eq", "RetCode", 0), 111 | ("len_eq", "DataSet", 1), 112 | ], 113 | action="DescribeULBSimple", 114 | ) 115 | def describe_ulb_simple_03(client: utest.Client, variables: dict): 116 | d = {"ULBId": variables.get("ULBId"), "Region": variables.get("Region")} 117 | 118 | try: 119 | resp = client.invoke("DescribeULBSimple", d) 120 | except exc.RetCodeException as e: 121 | resp = e.json() 122 | 123 | return resp 124 | 125 | 126 | @scenario.step( 127 | max_retries=10, 128 | retry_interval=10, 129 | startup_delay=3, 130 | fast_fail=False, 131 | validators=lambda variables: [ 132 | ("str_eq", "RetCode", 0), 133 | ("str_eq", "DataSet.0.ULBId", variables.get("ULBId")), 134 | ], 135 | action="DescribeULB", 136 | ) 137 | def describe_ulb_04(client: utest.Client, variables: dict): 138 | d = { 139 | "ULBId": variables.get("ULBId"), 140 | "Region": variables.get("Region"), 141 | "Offset": 0, 142 | "Limit": 60, 143 | } 144 | 145 | try: 146 | resp = client.ulb().describe_ulb(d) 147 | except exc.RetCodeException as e: 148 | resp = e.json() 149 | 150 | return resp 151 | 152 | 153 | @scenario.step( 154 | max_retries=10, 155 | retry_interval=10, 156 | startup_delay=0, 157 | fast_fail=False, 158 | validators=lambda variables: [("str_eq", "RetCode", 0)], 159 | action="DeleteULB", 160 | ) 161 | def delete_ulb_05(client: utest.Client, variables: dict): 162 | d = {"ULBId": variables.get("ULBId"), "Region": variables.get("Region")} 163 | 164 | try: 165 | resp = client.ulb().delete_ulb(d) 166 | except exc.RetCodeException as e: 167 | resp = e.json() 168 | 169 | return resp 170 | -------------------------------------------------------------------------------- /ucloud/services/ubill/schemas/models.py: -------------------------------------------------------------------------------- 1 | """ Code is generated by ucloud-model, DO NOT EDIT IT. """ 2 | 3 | from ucloud.core.typesystem import schema, fields 4 | 5 | 6 | class AccountInfoSchema(schema.ResponseSchema): 7 | """AccountInfo - 账户信息""" 8 | 9 | fields = { 10 | "Amount": fields.Str(required=False, load_from="Amount"), 11 | "AmountAvailable": fields.Str( 12 | required=False, load_from="AmountAvailable" 13 | ), 14 | "AmountCredit": fields.Str(required=False, load_from="AmountCredit"), 15 | "AmountFree": fields.Str(required=False, load_from="AmountFree"), 16 | "AmountFreeze": fields.Str(required=False, load_from="AmountFreeze"), 17 | } 18 | 19 | 20 | class ItemDetailSchema(schema.ResponseSchema): 21 | """ItemDetail - 产品配置""" 22 | 23 | fields = { 24 | "ProductName": fields.Str(required=True, load_from="ProductName"), 25 | "Value": fields.Str(required=True, load_from="Value"), 26 | } 27 | 28 | 29 | class ResourceExtendInfoSchema(schema.ResponseSchema): 30 | """ResourceExtendInfo - 资源标识""" 31 | 32 | fields = { 33 | "KeyId": fields.Str(required=True, load_from="KeyId"), 34 | "Value": fields.Str(required=True, load_from="Value"), 35 | } 36 | 37 | 38 | class BillDetailItemSchema(schema.ResponseSchema): 39 | """BillDetailItem - 账单详情数据""" 40 | 41 | fields = { 42 | "Admin": fields.Int(required=True, load_from="Admin"), 43 | "Amount": fields.Str(required=True, load_from="Amount"), 44 | "AmountCoupon": fields.Str(required=True, load_from="AmountCoupon"), 45 | "AmountFree": fields.Str(required=True, load_from="AmountFree"), 46 | "AmountReal": fields.Str(required=True, load_from="AmountReal"), 47 | "AzGroupCName": fields.Str(required=True, load_from="AzGroupCName"), 48 | "BusinessGroup": fields.Str(required=True, load_from="BusinessGroup"), 49 | "ChargeType": fields.Str(required=True, load_from="ChargeType"), 50 | "CreateTime": fields.Int(required=True, load_from="CreateTime"), 51 | "EndTime": fields.Int(required=True, load_from="EndTime"), 52 | "ItemDetails": fields.List(ItemDetailSchema()), 53 | "OrderNo": fields.Str(required=True, load_from="OrderNo"), 54 | "OrderType": fields.Str(required=True, load_from="OrderType"), 55 | "ProjectId": fields.Str(required=True, load_from="ProjectId"), 56 | "ProjectName": fields.Str(required=True, load_from="ProjectName"), 57 | "ResourceExtendInfo": fields.List(ResourceExtendInfoSchema()), 58 | "ResourceId": fields.Str(required=True, load_from="ResourceId"), 59 | "ResourceLabel": fields.Str(), 60 | "ResourceType": fields.Str(required=True, load_from="ResourceType"), 61 | "ResourceTypeCode": fields.Int( 62 | required=True, load_from="ResourceTypeCode" 63 | ), 64 | "ShowHover": fields.Int(required=True, load_from="ShowHover"), 65 | "StartTime": fields.Int(required=True, load_from="StartTime"), 66 | "UserDisplayName": fields.Str( 67 | required=True, load_from="UserDisplayName" 68 | ), 69 | "UserEmail": fields.Str(required=True, load_from="UserEmail"), 70 | "UserName": fields.Str(required=True, load_from="UserName"), 71 | } 72 | 73 | 74 | class BillOverviewItemSchema(schema.ResponseSchema): 75 | """BillOverviewItem - 账单总览数组内单个结构体数据""" 76 | 77 | fields = { 78 | "Admin": fields.Int(required=False, load_from="Admin"), 79 | "Amount": fields.Str(required=True, load_from="Amount"), 80 | "AmountCoupon": fields.Str(required=False, load_from="AmountCoupon"), 81 | "AmountFree": fields.Str(required=False, load_from="AmountFree"), 82 | "AmountReal": fields.Str(required=False, load_from="AmountReal"), 83 | "Dimension": fields.Str(required=True, load_from="Dimension"), 84 | "ProductCategory": fields.Str( 85 | required=False, load_from="ProductCategory" 86 | ), 87 | "ProjectName": fields.Str(required=False, load_from="ProjectName"), 88 | "ResourceType": fields.Str(required=False, load_from="ResourceType"), 89 | "ResourceTypeCode": fields.Int( 90 | required=False, load_from="ResourceTypeCode" 91 | ), 92 | "UserDisplayName": fields.Str( 93 | required=False, load_from="UserDisplayName" 94 | ), 95 | "UserEmail": fields.Str(required=False, load_from="UserEmail"), 96 | "UserName": fields.Str(required=False, load_from="UserName"), 97 | } 98 | 99 | 100 | class ResultSetSchema(schema.ResponseSchema): 101 | """ResultSet - 结果集""" 102 | 103 | fields = { 104 | "Message": fields.Str(required=False, load_from="Message"), 105 | "ResourceId": fields.Str(required=False, load_from="ResourceId"), 106 | "RetCode": fields.Int(required=False, load_from="RetCode"), 107 | } 108 | -------------------------------------------------------------------------------- /ucloud/testing/op.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | from ucloud.testing.exc import CompareError 4 | 5 | 6 | def eq(value, expected): 7 | """value is equal to expected""" 8 | assert value == expected 9 | 10 | 11 | def ne(value, expected): 12 | """value is equal to expected""" 13 | assert value != expected 14 | 15 | 16 | def gt(value, expected): 17 | """value is greater than expected""" 18 | assert float(value) > float(expected) 19 | 20 | 21 | def ge(value, expected): 22 | """value is greater than or equal to expected""" 23 | assert float(value) >= float(expected) 24 | 25 | 26 | def abs_eq(value, expected): 27 | """value is approx equal to expected""" 28 | assert round(float(value), 2) == round(float(expected), 2) 29 | 30 | 31 | def lt(value, expected): 32 | """value is less than excepted""" 33 | assert float(value) < float(expected) 34 | 35 | 36 | def le(value, expected): 37 | """value is less than or equal to excepted""" 38 | assert float(value) <= float(expected) 39 | 40 | 41 | def str_eq(value, expected): 42 | """value is equal to excepted as string""" 43 | assert str(value) == str(expected) 44 | 45 | 46 | def float_eq(value, expected): 47 | """value is equal to excepted as float""" 48 | assert round(float(value), 2) == round(float(expected), 2) 49 | 50 | 51 | def len_eq(value, expected): 52 | """length of value is equal to excepted""" 53 | assert isinstance(expected, int) 54 | assert len(value) == expected 55 | 56 | 57 | def len_gt(value, expected): 58 | """length of value is greater than excepted""" 59 | assert isinstance(expected, int) 60 | assert len(value) > expected 61 | 62 | 63 | def len_ge(value, expected): 64 | """length of value is greater than or equal to excepted""" 65 | assert isinstance(expected, int) 66 | assert len(value) >= expected 67 | 68 | 69 | def len_lt(value, expected): 70 | """length of value is less than excepted""" 71 | assert isinstance(expected, int) 72 | assert len(value) < expected 73 | 74 | 75 | def len_le(value, expected): 76 | """length of value is less than or equal to excepted""" 77 | assert isinstance(expected, int) 78 | assert len(value) <= expected 79 | 80 | 81 | def contains(value, expected): 82 | """value is contains expected""" 83 | assert expected in value 84 | 85 | 86 | def contained_by(value, expected): 87 | """value is contained by expected""" 88 | assert value in expected 89 | 90 | 91 | def type_eq(value, expected): 92 | assert isinstance(value, expected) 93 | 94 | 95 | def regex(value, expected): 96 | assert isinstance(expected, str) 97 | assert isinstance(value, str) 98 | assert re.match(expected, value) 99 | 100 | 101 | def startswith(value, expected): 102 | assert str(value).startswith(expected) 103 | 104 | 105 | def endswith(value, expected): 106 | assert str(value).endswith(expected) 107 | 108 | 109 | def object_contains(value, expected): 110 | assert str(expected) in str(value) 111 | 112 | 113 | def object_not_contains(value, expected): 114 | assert str(expected) not in str(value) 115 | 116 | 117 | mapper = { 118 | "eq": eq, 119 | "equals": eq, 120 | "==": eq, 121 | "abs_eq": abs_eq, 122 | "abs_equals": abs_eq, 123 | "lt": lt, 124 | "less_than": lt, 125 | "le": le, 126 | "less_than_or_equals": le, 127 | "gt": gt, 128 | "greater_than": gt, 129 | "ge": ge, 130 | "greater_than_or_equals": ge, 131 | "ne": ne, 132 | "not_equals": ne, 133 | "str_eq": str_eq, 134 | "string_equals": str_eq, 135 | "float_eq": float_eq, 136 | "float_equals": float_eq, 137 | "len_eq": len_eq, 138 | "length_equals": len_eq, 139 | "count_eq": len_eq, 140 | "len_gt": len_gt, 141 | "count_gt": len_gt, 142 | "length_greater_than": len_gt, 143 | "count_greater_than": len_gt, 144 | "len_ge": len_ge, 145 | "count_ge": len_ge, 146 | "length_greater_than_or_equals": len_ge, 147 | "count_greater_than_or_equals": len_ge, 148 | "len_lt": len_lt, 149 | "count_lt": len_lt, 150 | "length_less_than": len_lt, 151 | "count_less_than": len_lt, 152 | "len_le": len_le, 153 | "count_le": len_le, 154 | "length_less_than_or_equals": len_le, 155 | "count_less_than_or_equals": len_le, 156 | "contains": contains, 157 | "contained_by": contained_by, 158 | "type": type_eq, 159 | "regex": regex, 160 | "startswith": startswith, 161 | "endswith": endswith, 162 | "object_contains": object_contains, 163 | "object_not_contains": object_not_contains, 164 | } 165 | 166 | 167 | def check(name, value, expected): 168 | if name not in mapper: 169 | raise CompareError("comparator {} is not found".format(name)) 170 | 171 | try: 172 | return mapper.get(name)(value, expected) 173 | except AssertionError as e: 174 | msg = "assert error, expect {} {} {}, got error {}".format( 175 | value, name, expected, e 176 | ) 177 | raise CompareError(msg) 178 | -------------------------------------------------------------------------------- /ucloud/services/uvms/client.py: -------------------------------------------------------------------------------- 1 | """ Code is generated by ucloud-model, DO NOT EDIT IT. """ 2 | 3 | import typing 4 | 5 | 6 | from ucloud.core.client import Client 7 | from ucloud.services.uvms.schemas import apis 8 | 9 | 10 | class UVMSClient(Client): 11 | def __init__( 12 | self, config: dict, transport=None, middleware=None, logger=None 13 | ): 14 | super(UVMSClient, self).__init__(config, transport, middleware, logger) 15 | 16 | def get_uvms_send_record( 17 | self, req: typing.Optional[dict] = None, **kwargs 18 | ) -> dict: 19 | """GetUVMSSendRecord - 获取语音发送记录 20 | 21 | **Request** 22 | 23 | - **ProjectId** (str) - (Config) 项目ID。不填写为默认项目,子帐号必须填写。 请参考 `GetProjectList接口 `_ 24 | - **BrevityCode** (str) - 国际码,国内CN 25 | - **CalledCityCode** (str) - 被叫城市编码 26 | - **CalledOperatorCode** (str) - 被叫运营商 cmcc中国移动,cucc中国联通,ctcc中国电信 27 | - **CallingCityCode** (str) - 主叫城市编码 28 | - **EndTime** (float) - 结束时间-拨打时间,时间戳(秒),默认当前 29 | - **ExcludeBrevityCode** (str) - 排除国际码 30 | - **FuzzySearch** (str) - 模糊搜索,支持 主叫号码和被叫号码 31 | - **NumPerPage** (int) - 每页数量,默认10 32 | - **OrderBy** (str) - call_start_time(拨打时间)/receive_time(回执时间) 33 | - **OrderType** (str) - asc\desc 34 | - **Page** (int) - 页码,默认0 35 | - **PhoneNumber** (str) - 被叫号码,精确查询 36 | - **Purpose** (int) - 目标1验证码2通知3营销 37 | - **StartTime** (float) - 开始时间-拨打时间,时间戳(秒),默认最近7天 38 | - **TaskNo** (str) - 任务编号 39 | - **TemplateId** (str) - 目标ID 40 | 41 | **Response** 42 | 43 | - **Data** (list) - 见 **SendRecordItem** 模型定义 44 | - **Total** (int) - 总数 45 | 46 | **Response Model** 47 | 48 | **SendRecordItem** 49 | - **BillPeriod** (int) - 计费周期(秒) 50 | - **BillSecond** (int) - 计费时长(秒) 51 | - **BrevityCode** (str) - 国际码 52 | - **CallEndTime** (float) - 呼叫结束时间(毫秒时间戳) 53 | - **CallStartTime** (float) - 呼叫开始时间(毫秒时间戳) 54 | - **CalledCityCode** (str) - 被叫所属城市码 55 | - **CalledOperatorCode** (str) - 被叫供应商码 cmcc中国移动,cucc中国联通,ctcc中国电信 56 | - **CallingCityCode** (str) - 主叫所属城市码 57 | - **ChannelId** (str) - 通道ID 58 | - **CountryCode** (str) - 国家码 59 | - **Duration** (int) - 呼叫持续时间 60 | - **GroupType** (int) - 1随机号码组2专属号码组 61 | - **Phone** (str) - 被叫号码 62 | - **PreCost** (int) - 预扣量 63 | - **Purpose** (int) - 目标1验证码2通知3营销 64 | - **ReceiptDesc** (str) - 回执描述 65 | - **ReceiptResult** (int) - 回执结果1成功2失败3未知 66 | - **ReceiveTime** (float) - 回执时间 67 | - **ShowNumber** (str) - 主叫号码,如果是随机,可能为空 68 | - **SubmitTime** (float) - 客户提交时间 69 | - **TaskNo** (str) - 任务编号 70 | - **TemplateId** (str) - 模板ID 71 | 72 | 73 | """ 74 | # build request 75 | d = { 76 | "ProjectId": self.config.project_id, 77 | } 78 | req and d.update(req) 79 | d = apis.GetUVMSSendRecordRequestSchema().dumps(d) 80 | 81 | resp = self.invoke("GetUVMSSendRecord", d, **kwargs) 82 | return apis.GetUVMSSendRecordResponseSchema().loads(resp) 83 | 84 | def send_uvms_message( 85 | self, req: typing.Optional[dict] = None, **kwargs 86 | ) -> dict: 87 | """SendUVMSMessage - 向指定号码拨打电话 88 | 89 | **Request** 90 | 91 | - **ProjectId** (str) - (Config) 项目ID。不填写为默认项目,子帐号必须填写。 请参考 `GetProjectList接口 `_ 92 | - **CalledNumber** (str) - (Required) 被叫号码,采用 E.164 标准,格式为+[国家代码][用户号码]。例如:+8613512345678, 其中前面有一个+号 ,86为国家码,13512345678为手机号 93 | - **TemplateId** (str) - (Required) 模板 ID,在控制台审核通过的模板 ID。 94 | - **DispatchRule** (int) - 调度规则,0-默认(归属地优先),1-随机。当不指定外显号码(主叫号码为空)时生效。如不填写,默认为归属地优先。 95 | - **FromNumber** (str) - 主叫号码,号码随机时不填。专属号码时传入已购买的号码,仅支持一个号码,在控制台查看已购买的号码。 96 | - **GroupType** (int) - 号码组类型,1-随机组,2-专属组。如不填写则根据主叫号码判断,若主叫号码为空,则为随机组,若不为空,则为专属组。 97 | - **TemplateParams** (list) - 模板可变参数,以数组的方式填写,举例,TemplateParams.0,TemplateParams.1,... 若模板中无可变参数,则该项可不填写;若模板中有可变参数,则该项为必填项,参数个数需与变量个数保持一致,否则无法发送; 98 | - **UserId** (str) - 自定义的业务标识ID,字符串( 长度不能超过32 位),不支持 单引号、表情包符号等特殊字符 99 | 100 | **Response** 101 | 102 | - **Message** (str) - 状态码的描述 103 | - **ReqUuid** (str) - 唯一请求 ID,每次请求都会返回。定位问题时需要提供该次请求的 ReqUuid。 104 | - **SessionNo** (str) - 本次提交发送语音的唯一ID,可根据该值查询本次发送详情 105 | - **UserId** (str) - 本次提交的自定义业务标识ID,仅当发送时传入有效的UserId,才返回该字段。 106 | 107 | """ 108 | # build request 109 | d = { 110 | "ProjectId": self.config.project_id, 111 | } 112 | req and d.update(req) 113 | d = apis.SendUVMSMessageRequestSchema().dumps(d) 114 | 115 | # build options 116 | kwargs["max_retries"] = 0 # ignore retry when api is not idempotent 117 | 118 | resp = self.invoke("SendUVMSMessage", d, **kwargs) 119 | return apis.SendUVMSMessageResponseSchema().loads(resp) 120 | -------------------------------------------------------------------------------- /ucloud/core/transport/_requests.py: -------------------------------------------------------------------------------- 1 | import time 2 | import typing 3 | import requests 4 | from urllib3.util.retry import Retry 5 | from requests.adapters import HTTPAdapter 6 | from ucloud.core.transport import http 7 | from ucloud.core.transport.http import Request, Response, SSLOption 8 | from ucloud.core.utils.middleware import Middleware 9 | from ucloud.core import exc 10 | 11 | 12 | class RequestsTransport(http.Transport): 13 | """transport is the implementation of http client, use for send a request and return a http response 14 | 15 | :type max_retries: int 16 | :param max_retries: max retries is the max number of transport request when occur http error 17 | :type backoff_factor: float 18 | :param backoff_factor: backoff factor will calculate the backoff delay during retrying, 19 | the backoff delay = {backoff factor} * (2 ^ ({number of total retries} - 1)) 20 | :type status_forcelist: tuple 21 | :param status_forcelist: the status code list that could be retried 22 | """ 23 | 24 | def __init__( 25 | self, 26 | max_retries: int = 3, 27 | backoff_factor: float = 0.3, 28 | status_forcelist: typing.Tuple[int] = (500, 502, 504), 29 | ): 30 | self.max_retries = max_retries 31 | self.backoff_factor = backoff_factor 32 | self.status_forcelist = status_forcelist 33 | 34 | self._adapter = self._load_adapter(max_retries) 35 | self._middleware = Middleware() 36 | 37 | def send(self, req: Request, **options: typing.Any) -> http.Response: 38 | """send request and return the response 39 | 40 | :param req: the full http request descriptor 41 | :return: the response of http request 42 | """ 43 | for handler in self.middleware.request_handlers: 44 | req = handler(req) 45 | 46 | try: 47 | resp = self._send(req, **options) 48 | except Exception as e: 49 | for handler in self.middleware.exception_handlers: 50 | handler(e) 51 | raise e 52 | 53 | for handler in self.middleware.response_handlers: 54 | resp = handler(resp) 55 | 56 | return resp 57 | 58 | @property 59 | def middleware(self) -> Middleware: 60 | """the middleware object, see :mod: 61 | 62 | :return: the transport middleware 63 | """ 64 | return self._middleware 65 | 66 | def _send(self, req: Request, **options: typing.Any) -> requests.Response: 67 | with requests.Session() as session: 68 | adapter = self._load_adapter(options.get("max_retries")) 69 | session.mount("http://", adapter=adapter) 70 | session.mount("https://", adapter=adapter) 71 | 72 | ssl_option = options.get("ssl_option") 73 | kwargs = self._build_ssl_option(ssl_option) if ssl_option else {} 74 | 75 | req.request_time = time.time() 76 | session_resp = session.request( 77 | method=req.method.upper(), 78 | url=req.url, 79 | json=req.json, 80 | data=req.data, 81 | params=req.params, 82 | headers=req.headers, 83 | timeout=options.get("timeout"), 84 | **kwargs 85 | ) 86 | resp = self.convert_response(session_resp) 87 | resp.request = req 88 | resp.response_time = time.time() 89 | 90 | if resp.status_code >= 400: 91 | raise exc.HTTPStatusException( 92 | resp.status_code, resp.request_uuid 93 | ) 94 | return resp 95 | 96 | @staticmethod 97 | def _build_ssl_option(ssl_option): 98 | kwargs = {"verify": ssl_option.ssl_verify and ssl_option.ssl_cacert} 99 | if not ssl_option.ssl_cert: 100 | return kwargs 101 | 102 | if ssl_option.ssl_key: 103 | kwargs["cert"] = (ssl_option.ssl_cert, ssl_option.ssl_key) 104 | else: 105 | kwargs["cert"] = ssl_option.ssl_cert 106 | return kwargs 107 | 108 | def _load_adapter( 109 | self, max_retries: typing.Optional[int] = None 110 | ) -> HTTPAdapter: 111 | if max_retries is None and self._adapter is not None: 112 | return self._adapter 113 | 114 | max_retries = max_retries or 0 115 | adapter = HTTPAdapter() 116 | adapter.max_retries = Retry( 117 | total=max_retries, 118 | read=max_retries, 119 | connect=max_retries, 120 | backoff_factor=self.backoff_factor, 121 | status_forcelist=self.status_forcelist, 122 | ) 123 | return adapter 124 | 125 | @staticmethod 126 | def convert_response(r: requests.Response) -> Response: 127 | return Response( 128 | url=r.url, 129 | method=r.request.method, 130 | status_code=r.status_code, 131 | reason=r.reason, 132 | headers=r.headers, 133 | content=r.content, 134 | encoding=r.encoding or r.apparent_encoding, 135 | ) 136 | --------------------------------------------------------------------------------