├── docs
├── contents.rst
├── _static
│ └── .gitkeep
├── helpers.rst
├── conf.py
├── core.rst
├── Makefile
├── index.rst
├── quick_start.rst
├── services.rst
└── usage.rst
├── scripts
├── __init__.py
└── migrate
│ ├── __init__.py
│ ├── requirements.txt
│ ├── _plugin_doc.py
│ ├── config.json
│ ├── __main__.py
│ ├── test_migrate.py
│ ├── _plugin_py3to2.py
│ └── _migrate.py
├── requirements.txt
├── tests
├── __init__.py
├── test_core
│ ├── __init__.py
│ ├── test_exc.py
│ ├── test_encoder.py
│ ├── test_auth.py
│ ├── test_fields.py
│ ├── test_transport.py
│ └── test_client.py
├── test_unit
│ ├── __init__.py
│ ├── test_core
│ │ ├── __init__.py
│ │ ├── test_deco.py
│ │ ├── test_exc.py
│ │ ├── test_encoder.py
│ │ ├── test_auth.py
│ │ ├── test_fields.py
│ │ ├── test_transport.py
│ │ └── test_client.py
│ ├── test_helpers
│ │ ├── __init__.py
│ │ ├── test_utils.py
│ │ └── test_wait.py
│ └── test_testing
│ │ ├── __init__.py
│ │ └── test_utest.py
├── test_helpers
│ ├── __init__.py
│ ├── test_utils.py
│ └── test_wait.py
├── test_services
│ ├── __init__.py
│ ├── conftest.py
│ ├── test_set_2935.py
│ └── test_set_1202.py
├── test_testing
│ ├── __init__.py
│ └── test_utest.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
│ │ └── _client.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
│ ├── pathx
│ │ ├── __init__.py
│ │ └── schemas
│ │ │ ├── __init__.py
│ │ │ ├── models.py
│ │ │ └── apis.py
│ ├── ucdn
│ │ ├── __init__.py
│ │ └── schemas
│ │ │ └── __init__.py
│ ├── udb
│ │ ├── __init__.py
│ │ └── schemas
│ │ │ └── __init__.py
│ ├── udisk
│ │ ├── __init__.py
│ │ └── schemas
│ │ │ ├── __init__.py
│ │ │ └── models.py
│ ├── udpn
│ │ ├── __init__.py
│ │ └── schemas
│ │ │ ├── __init__.py
│ │ │ └── models.py
│ ├── ufs
│ │ ├── __init__.py
│ │ └── schemas
│ │ │ ├── __init__.py
│ │ │ ├── models.py
│ │ │ └── apis.py
│ ├── uhost
│ │ ├── __init__.py
│ │ └── schemas
│ │ │ └── __init__.py
│ ├── uhub
│ │ ├── __init__.py
│ │ └── schemas
│ │ │ ├── __init__.py
│ │ │ ├── models.py
│ │ │ └── apis.py
│ ├── ulb
│ │ ├── __init__.py
│ │ └── schemas
│ │ │ └── __init__.py
│ ├── umem
│ │ ├── __init__.py
│ │ └── schemas
│ │ │ └── __init__.py
│ ├── unet
│ │ ├── __init__.py
│ │ └── schemas
│ │ │ └── __init__.py
│ ├── uphost
│ │ ├── __init__.py
│ │ └── schemas
│ │ │ ├── __init__.py
│ │ │ └── models.py
│ ├── usms
│ │ ├── __init__.py
│ │ └── schemas
│ │ │ ├── __init__.py
│ │ │ └── models.py
│ ├── vpc
│ │ ├── __init__.py
│ │ └── schemas
│ │ │ ├── __init__.py
│ │ │ └── models.py
│ ├── ipsecvpn
│ │ ├── __init__.py
│ │ ├── schemas
│ │ │ ├── __init__.py
│ │ │ ├── apis.py
│ │ │ └── models.py
│ │ └── client.py
│ ├── stepflow
│ │ ├── __init__.py
│ │ ├── schemas
│ │ │ ├── __init__.py
│ │ │ ├── models.py
│ │ │ └── apis.py
│ │ └── client.py
│ ├── uaccount
│ │ ├── __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
├── _compat.py
└── client.py
├── examples
├── two-tier
│ ├── __init__.py
│ ├── README.md
│ └── main.py
└── uhost
│ ├── __init__.py
│ ├── README.md
│ └── main.py
├── pytest.ini
├── .editorconfig
├── .travis.yml
├── README.md
├── .gitignore
├── Makefile
└── setup.py
/docs/contents.rst:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docs/_static/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/scripts/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/scripts/migrate/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | requests
2 |
--------------------------------------------------------------------------------
/scripts/migrate/requirements.txt:
--------------------------------------------------------------------------------
1 | astor
2 |
--------------------------------------------------------------------------------
/tests/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
--------------------------------------------------------------------------------
/ucloud/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
--------------------------------------------------------------------------------
/ucloud/core/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
--------------------------------------------------------------------------------
/examples/two-tier/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
--------------------------------------------------------------------------------
/examples/uhost/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
--------------------------------------------------------------------------------
/tests/test_core/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
--------------------------------------------------------------------------------
/tests/test_unit/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
--------------------------------------------------------------------------------
/ucloud/core/utils/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
--------------------------------------------------------------------------------
/ucloud/helpers/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
--------------------------------------------------------------------------------
/ucloud/services/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
--------------------------------------------------------------------------------
/ucloud/testing/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
--------------------------------------------------------------------------------
/tests/test_helpers/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
--------------------------------------------------------------------------------
/tests/test_services/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
--------------------------------------------------------------------------------
/tests/test_testing/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
--------------------------------------------------------------------------------
/ucloud/core/typesystem/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
--------------------------------------------------------------------------------
/ucloud/services/pathx/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
--------------------------------------------------------------------------------
/ucloud/services/ucdn/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
--------------------------------------------------------------------------------
/ucloud/services/udb/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
--------------------------------------------------------------------------------
/ucloud/services/udisk/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
--------------------------------------------------------------------------------
/ucloud/services/udpn/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
--------------------------------------------------------------------------------
/ucloud/services/ufs/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
--------------------------------------------------------------------------------
/ucloud/services/uhost/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
--------------------------------------------------------------------------------
/ucloud/services/uhub/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
--------------------------------------------------------------------------------
/ucloud/services/ulb/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
--------------------------------------------------------------------------------
/ucloud/services/umem/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
--------------------------------------------------------------------------------
/ucloud/services/unet/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
--------------------------------------------------------------------------------
/ucloud/services/uphost/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
--------------------------------------------------------------------------------
/ucloud/services/usms/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
--------------------------------------------------------------------------------
/ucloud/services/vpc/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
--------------------------------------------------------------------------------
/tests/test_unit/test_core/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
--------------------------------------------------------------------------------
/tests/test_unit/test_helpers/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
--------------------------------------------------------------------------------
/tests/test_unit/test_testing/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
--------------------------------------------------------------------------------
/ucloud/services/ipsecvpn/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
--------------------------------------------------------------------------------
/ucloud/services/stepflow/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
--------------------------------------------------------------------------------
/ucloud/services/uaccount/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
--------------------------------------------------------------------------------
/ucloud/services/ucdn/schemas/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
--------------------------------------------------------------------------------
/ucloud/services/ucloudstack/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
--------------------------------------------------------------------------------
/ucloud/services/udb/schemas/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
--------------------------------------------------------------------------------
/ucloud/services/udpn/schemas/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
--------------------------------------------------------------------------------
/ucloud/services/ufs/schemas/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
--------------------------------------------------------------------------------
/ucloud/services/uhub/schemas/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
--------------------------------------------------------------------------------
/ucloud/services/ulb/schemas/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
--------------------------------------------------------------------------------
/ucloud/services/umem/schemas/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
--------------------------------------------------------------------------------
/ucloud/services/unet/schemas/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
--------------------------------------------------------------------------------
/ucloud/services/usms/schemas/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
--------------------------------------------------------------------------------
/ucloud/services/vpc/schemas/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
--------------------------------------------------------------------------------
/ucloud/services/ipsecvpn/schemas/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
--------------------------------------------------------------------------------
/ucloud/services/pathx/schemas/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
--------------------------------------------------------------------------------
/ucloud/services/stepflow/schemas/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
--------------------------------------------------------------------------------
/ucloud/services/uaccount/schemas/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
--------------------------------------------------------------------------------
/ucloud/services/udisk/schemas/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
--------------------------------------------------------------------------------
/ucloud/services/uhost/schemas/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
--------------------------------------------------------------------------------
/ucloud/services/uphost/schemas/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
--------------------------------------------------------------------------------
/ucloud/version.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | version = "0.9.2"
4 |
--------------------------------------------------------------------------------
/ucloud/services/ucloudstack/schemas/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
--------------------------------------------------------------------------------
/ucloud/core/auth/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | from ucloud.core.auth._cfg import Credential
4 |
5 | __all__ = ["Credential"]
6 |
--------------------------------------------------------------------------------
/ucloud/testing/driver/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | from ._specification import Specification
4 | from ._scenario import Scenario
5 | from ._step import Step
6 |
7 | spec = Specification()
8 |
--------------------------------------------------------------------------------
/pytest.ini:
--------------------------------------------------------------------------------
1 | [pytest]
2 | log_cli = 1
3 | log_cli_level = INFO
4 | log_cli_format = %(asctime)s [%(levelname)8s] %(message)s (%(filename)s:%(lineno)s %(name)s)
5 | testpaths = ucloud tests
6 | addopts = --doctest-modules
7 |
--------------------------------------------------------------------------------
/ucloud/core/client/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | """
4 | Client
5 | """
6 | from ucloud.core.client._cfg import Config
7 | from ucloud.core.client._client import Client
8 |
9 | __all__ = ["Config", "Client"]
10 |
--------------------------------------------------------------------------------
/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 | # -*- coding: utf-8 -*-
2 |
3 | from ucloud.core.transport.http import Request, Response, Transport, SSLOption
4 | from ucloud.core.transport._requests import RequestsTransport
5 |
6 | __all__ = ["Request", "Response", "Transport", "RequestsTransport", "SSLOption"]
7 |
--------------------------------------------------------------------------------
/tests/test_unit/test_core/test_deco.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | from ucloud.core.utils.deco import deprecated
4 |
5 |
6 | @deprecated(instead_of="bar")
7 | def foo():
8 | pass
9 |
10 |
11 | def test_deprecated_deco(caplog):
12 | foo()
13 | assert "deprecated" in caplog.text
14 |
--------------------------------------------------------------------------------
/scripts/migrate/_plugin_doc.py:
--------------------------------------------------------------------------------
1 |
2 |
3 | class DocTransformer:
4 | def __init__(self, replaces=None):
5 | self.replaces = replaces
6 |
7 | def convert(self, source: str) -> str:
8 | result = source
9 | for r in self.replaces:
10 | result = result.replace(r['from'], r['to'])
11 | return result
12 |
--------------------------------------------------------------------------------
/tests/test_unit/test_helpers/test_utils.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | from ucloud.helpers import utils
4 |
5 |
6 | def test_b64encode():
7 | encoded = utils.b64encode("foobar42")
8 | assert encoded == "Zm9vYmFyNDI="
9 |
10 |
11 | def test_b64decode():
12 | decoded = utils.b64decode("Zm9vYmFyNDI=")
13 | assert decoded == "foobar42"
14 |
--------------------------------------------------------------------------------
/tests/test_helpers/test_utils.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | from ucloud.helpers import utils
4 |
5 |
6 | def test_b64encode():
7 | encoded = utils.b64encode("foobar42")
8 | assert encoded == "Zm9vYmFyNDI="
9 |
10 |
11 | def test_b64decode():
12 | decoded = utils.b64decode("Zm9vYmFyNDI=")
13 | assert decoded == "foobar42"
14 |
--------------------------------------------------------------------------------
/ucloud/core/exc/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | from ucloud.core.exc._exc import (
4 | UCloudException,
5 | ValidationException,
6 | RetCodeException,
7 | RetryTimeoutException,
8 | )
9 |
10 | __all__ = [
11 | "UCloudException",
12 | "ValidationException",
13 | "RetCodeException",
14 | "RetryTimeoutException",
15 | ]
16 |
--------------------------------------------------------------------------------
/docs/conf.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | project = 'ucloud-sdk-python3'
4 | copyright = '2019, ucloud'
5 | author = 'ucloud'
6 | extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.todo',
7 | 'sphinx.ext.viewcode']
8 | templates_path = ['_templates']
9 | exclude_patterns = []
10 | html_theme = 'alabaster'
11 | html_static_path = ['_static']
12 |
--------------------------------------------------------------------------------
/ucloud/core/utils/compat.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | import sys
4 |
5 | PY3 = sys.version_info[0] == 3
6 | if PY3:
7 | str = str
8 | string_types = (str,)
9 | from collections.abc import Callable
10 | else:
11 | import types
12 |
13 | str = unicode # noqa: F821 # noqa: F821
14 | string_types = types.StringTypes
15 | from collections import Callable
16 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/ucloud/testing/exc.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 |
4 | class UTestError(Exception):
5 | pass
6 |
7 |
8 | class ValidateError(UTestError):
9 | def __init__(self, errors):
10 | self.errors = errors
11 |
12 | def __str__(self):
13 | return str(self.errors)
14 |
15 |
16 | class ValueNotFoundError(UTestError):
17 | pass
18 |
19 |
20 | class CompareError(UTestError):
21 | pass
22 |
--------------------------------------------------------------------------------
/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 | - 2.7
6 | dist: xenial
7 | sudo: true
8 |
9 | # command to install dependencies, e.g. pip install -r requirements.txt --use-mirrors
10 | install: pip install -e .[ci]
11 |
12 | # command to run tests, e.g. python setup.py test
13 | script:
14 | - make lint
15 | - make test-cov
16 |
17 | after_success:
18 | - bash <(curl -s https://codecov.io/bash)
19 |
--------------------------------------------------------------------------------
/tests/test_core/test_exc.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | import pytest
4 | from ucloud.core import exc
5 |
6 |
7 | def test_ret_code_error():
8 | assert not exc.UCloudException().retryable
9 | code_error = exc.RetCodeException("Foo", 1, "")
10 | assert str(code_error)
11 | assert not code_error.retryable
12 | assert code_error.json() == {"Action": "Foo", "Message": "", "RetCode": 1}
13 | validate_error = exc.ValidationException(ValueError("invalid type"))
14 | assert not validate_error.retryable
15 | assert str(validate_error)
16 |
--------------------------------------------------------------------------------
/tests/test_unit/test_core/test_exc.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | import pytest
4 | from ucloud.core import exc
5 |
6 |
7 | def test_ret_code_error():
8 | assert not exc.UCloudException().retryable
9 | code_error = exc.RetCodeException("Foo", 1, "")
10 | assert str(code_error)
11 | assert not code_error.retryable
12 | assert code_error.json() == {"Action": "Foo", "Message": "", "RetCode": 1}
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 | # -*- coding: utf-8 -*-
2 |
3 | import pytest
4 | from ucloud.helpers import wait
5 |
6 |
7 | def test_wait():
8 | with pytest.raises(wait.WaitTimeoutException):
9 | wait.wait_for_state(
10 | pending=["pending"],
11 | target=["running"],
12 | refresh=lambda: "pending",
13 | timeout=0.5,
14 | )
15 | wait.wait_for_state(
16 | pending=["pending"],
17 | target=["running"],
18 | refresh=lambda: "running",
19 | timeout=0.5,
20 | )
21 |
--------------------------------------------------------------------------------
/tests/test_helpers/test_wait.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | import pytest
4 | from ucloud.helpers import wait
5 |
6 |
7 | def test_wait():
8 | with pytest.raises(wait.WaitTimeoutException):
9 | wait.wait_for_state(
10 | pending=["pending"],
11 | target=["running"],
12 | refresh=lambda: "pending",
13 | timeout=0.5,
14 | )
15 | wait.wait_for_state(
16 | pending=["pending"],
17 | target=["running"],
18 | refresh=lambda: "running",
19 | timeout=0.5,
20 | )
21 |
--------------------------------------------------------------------------------
/scripts/migrate/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "plugins": [
3 | {
4 | "name": "py3to2",
5 | "ext": [
6 | ".py"
7 | ]
8 | },
9 | {
10 | "name": "doc",
11 | "ext": [
12 | ".md",
13 | ".rst"
14 | ],
15 | "options": {
16 | "replaces": [
17 | {
18 | "from": "ucloud-sdk-python3",
19 | "to": "ucloud-sdk-python2"
20 | },
21 | {
22 | "from": "UCloud SDK Python 3",
23 | "to": "UCloud SDK Python 2"
24 | }
25 | ]
26 | }
27 | }
28 | ]
29 | }
30 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 | # -*- coding: utf-8 -*-
2 |
3 | import logging
4 |
5 | DEFAULT_LOGGER_NAME = "ucloud"
6 | DEFAULT_FORMAT = "%(asctime)s [%(levelname)8s] %(message)s (%(filename)s:%(lineno)s %(name)s)"
7 | DEFAULT_LEVEL = logging.INFO
8 |
9 |
10 | def init_default_logger():
11 | logger = logging.getLogger(DEFAULT_LOGGER_NAME)
12 | logger.setLevel(DEFAULT_LEVEL)
13 | ch = logging.StreamHandler()
14 | ch.setLevel(DEFAULT_LEVEL)
15 | formatter = logging.Formatter(DEFAULT_FORMAT)
16 | ch.setFormatter(formatter)
17 | logger.removeHandler(ch)
18 | logger.addHandler(ch)
19 | return logger
20 |
21 |
22 | default_logger = init_default_logger()
23 |
--------------------------------------------------------------------------------
/ucloud/_compat.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | from ucloud.core import client
4 |
5 |
6 | class CompactClient(client.Client):
7 | def __init__(self, config, transport=None, middleware=None):
8 | self._config = config
9 | super(CompactClient, self).__init__(config, transport, middleware)
10 |
11 | def pathx(self):
12 | from ucloud.services.pathx.client import PathXClient
13 |
14 | return PathXClient(
15 | self._config, self.transport, self.middleware, self.logger
16 | )
17 |
18 | def vpc(self):
19 | from ucloud.services.vpc.client import VPCClient
20 |
21 | return VPCClient(
22 | self._config, self.transport, self.middleware, self.logger
23 | )
24 |
--------------------------------------------------------------------------------
/tests/test_unit/test_core/test_encoder.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | import pytest
4 | from ucloud.core.typesystem import encoder
5 |
6 |
7 | @pytest.mark.parametrize(
8 | "input_vector,expected",
9 | [
10 | ({"foo": "bar"}, {"foo": "bar"}),
11 | ({"foo": 42}, {"foo": "42"}),
12 | ({"foo": 42.42}, {"foo": "42.42"}),
13 | ({"foo": 42.0}, {"foo": "42"}),
14 | ({"foo": True}, {"foo": "true"}),
15 | ({"foo": False}, {"foo": "false"}),
16 | ({"IP": ["127.0.0.1"]}, {"IP.0": "127.0.0.1"}),
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 |
--------------------------------------------------------------------------------
/tests/test_services/conftest.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | import os
4 | import pytest
5 | from ucloud.client import Client
6 |
7 |
8 | @pytest.fixture(scope="session", autouse=True, name="client")
9 | def client_factory():
10 | return Client(
11 | {
12 | "region": "cn-bj2",
13 | "project_id": os.getenv("UCLOUD_PROJECT_ID"),
14 | "public_key": os.getenv("UCLOUD_PUBLIC_KEY"),
15 | "private_key": os.getenv("UCLOUD_PRIVATE_KEY"),
16 | "max_retries": 10,
17 | "timeout": 60,
18 | }
19 | )
20 |
21 |
22 | @pytest.fixture(scope="module", autouse=True, name="variables")
23 | def variables_factory():
24 | return {
25 | "Region": "cn-bj2",
26 | "Zone": "cn-bj2-05",
27 | "ProjectId": os.getenv("UCLOUD_PROJECT_ID"),
28 | }
29 |
--------------------------------------------------------------------------------
/ucloud/testing/env.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | import os
4 |
5 | ACC_ENV_KEY = "USDKACC"
6 | ACC_SKIP_REASON = "skip test for non-acc environment"
7 |
8 |
9 | def get_skip_reason():
10 | return ACC_SKIP_REASON
11 |
12 |
13 | def is_acc():
14 | """ check test env is acceptance testing or not """
15 | return os.getenv(ACC_ENV_KEY)
16 |
17 |
18 | def is_ut():
19 | """ check test env is unit testing or not """
20 | return not is_acc()
21 |
22 |
23 | def pre_check_env():
24 | """ pre check environment for testing
25 |
26 | NOTE: system environment variables credential is required for test environment
27 | """
28 | assert os.getenv("UCLOUD_PUBLIC_KEY"), "invalid public key"
29 | assert os.getenv("UCLOUD_PRIVATE_KEY"), "invalid private key"
30 | assert os.getenv("UCLOUD_PROJECT_ID"), "invalid region"
31 |
--------------------------------------------------------------------------------
/tests/test_core/test_encoder.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | import pytest
4 | from ucloud.core.typesystem import encoder
5 |
6 |
7 | @pytest.mark.parametrize(
8 | "input_vector,expected",
9 | [
10 | ({"foo": "bar"}, {"foo": "bar"}),
11 | ({"foo": 42}, {"foo": "42"}),
12 | ({"foo": 42.42}, {"foo": "42.42"}),
13 | ({"foo": 42.0}, {"foo": "42"}),
14 | ({"foo": True}, {"foo": "true"}),
15 | ({"foo": False}, {"foo": "false"}),
16 | ({"IP": ["127.0.0.1"]}, {"IP.0": "127.0.0.1"}),
17 | ({"TemplateParams": [u"中文"]}, {"TemplateParams.0": u"中文"}),
18 | ({"IP": ["foo", "bar"]}, {"IP.0": "foo", "IP.1": "bar"}),
19 | ({"IP": [{"foo": "bar"}]}, {"IP.0.foo": "bar"}),
20 | ],
21 | )
22 | def test_params_encode(input_vector, expected):
23 | result = encoder.encode(input_vector)
24 | assert result == expected
25 |
--------------------------------------------------------------------------------
/tests/test_unit/test_core/test_auth.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | from ucloud.core import auth
4 |
5 |
6 | def test_verify_ac():
7 | d = {
8 | "Action": "CreateUHostInstance",
9 | "CPU": 2,
10 | "ChargeType": "Month",
11 | "DiskSpace": 10,
12 | "ImageId": "f43736e1-65a5-4bea-ad2e-8a46e18883c2",
13 | "LoginMode": "Password",
14 | "Memory": 2048,
15 | "Name": "Host01",
16 | "Password": "VUNsb3VkLmNu",
17 | "PublicKey": "ucloudsomeone@example.com1296235120854146120",
18 | "Quantity": 1,
19 | "Region": "cn-bj2",
20 | "Zone": "cn-bj2-04",
21 | }
22 | cred = auth.Credential(
23 | "ucloudsomeone@example.com1296235120854146120",
24 | "46f09bb9fab4f12dfc160dae12273d5332b5debe",
25 | )
26 | assert cred.verify_ac(d) == "4f9ef5df2abab2c6fccd1e9515cb7e2df8c6bb65"
27 |
--------------------------------------------------------------------------------
/ucloud/testing/mock.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | import json
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, **options):
14 | resp = Response(req.url, req.method)
15 | for handler in self.transport_handlers:
16 | resp = handler(req)
17 | for handler in self.client_handler:
18 | payload = handler(req.payload())
19 | resp.content = json.dumps(payload).encode("utf-8")
20 | return resp
21 |
22 | def mock(self, handler):
23 | self.transport_handlers.append(handler)
24 |
25 | def mock_data(self, handler):
26 | self.client_handler.append(handler)
27 |
--------------------------------------------------------------------------------
/tests/test_core/test_auth.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | from ucloud.core import auth
4 |
5 |
6 | def test_verify_ac():
7 | d = {
8 | "Action": "CreateUHostInstance",
9 | "CPU": 2,
10 | "ChargeType": "Month",
11 | "DiskSpace": 10,
12 | "ImageId": "f43736e1-65a5-4bea-ad2e-8a46e18883c2",
13 | "LoginMode": "Password",
14 | "Memory": 2048,
15 | "Name": "Host01",
16 | "Password": "VUNsb3VkLmNu",
17 | "PublicKey": "ucloudsomeone@example.com1296235120854146120",
18 | "Quantity": 1,
19 | "Region": "cn-bj2",
20 | "Zone": "cn-bj2-04",
21 | }
22 | cred = auth.Credential(
23 | "ucloudsomeone@example.com1296235120854146120",
24 | "46f09bb9fab4f12dfc160dae12273d5332b5debe",
25 | )
26 | assert cred.verify_ac(d) == "4f9ef5df2abab2c6fccd1e9515cb7e2df8c6bb65"
27 |
--------------------------------------------------------------------------------
/ucloud/core/utils/deco.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | import functools
4 | import logging
5 |
6 | logger = logging.getLogger("ucloud")
7 |
8 |
9 | def deprecated(instead_of="", message=""):
10 | """ deprecated is a decorator to mark a function is deprecated.
11 | it will logging warning when this function called
12 |
13 | >>> @deprecated(instead_of="new_function")
14 | ... def an_old_function():
15 | ... pass
16 | """
17 |
18 | def deco(fn):
19 | @functools.wraps(fn)
20 | def wrapper(*args, **kwargs):
21 | msg = [
22 | "this function/method `{}` is deprecated".format(fn.__name__)
23 | ]
24 | instead_of and msg.append(
25 | "please use `{}` instead".format(instead_of)
26 | )
27 | message and msg.append(message)
28 | logger.warning(", ".join(msg))
29 | return fn(*args, **kwargs)
30 |
31 | return wrapper
32 |
33 | return deco
34 |
--------------------------------------------------------------------------------
/ucloud/core/typesystem/encoder.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | from ucloud.core.utils.compat import str
4 |
5 |
6 | def encode(d):
7 | result = {}
8 | for k, v in d.items():
9 | if isinstance(v, dict):
10 | for ek, ev in encode(v).items():
11 | result["{}.{}".format(k, ek)] = encode_value(ev)
12 | elif isinstance(v, list):
13 | for i, item in enumerate(v):
14 | if isinstance(item, dict):
15 | for ek, ev in encode(item).items():
16 | result["{}.{}.{}".format(k, i, ek)] = encode_value(ev)
17 | else:
18 | result["{}.{}".format(k, i)] = encode_value(item)
19 | else:
20 | result[k] = encode_value(v)
21 | return result
22 |
23 |
24 | def encode_value(v):
25 | if isinstance(v, bool):
26 | return "true" if v else "false"
27 | if isinstance(v, float):
28 | return str(int(v)) if v % 1 == 0 else str(v)
29 | return str(v)
30 |
--------------------------------------------------------------------------------
/tests/test_unit/test_testing/test_utest.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | import pytest
4 | from ucloud.testing import utest, env
5 |
6 |
7 | @pytest.mark.skipif(env.is_ut(), reason=env.get_skip_reason())
8 | def test_acc_pre_check(self, client):
9 | assert str(client)
10 | assert client.config.to_dict()
11 | assert client.credential.to_dict()
12 | env.pre_check_env()
13 |
14 |
15 | def test_value_at_path():
16 | d = {
17 | "Action": "DescribeEIPResponse",
18 | "EIPSet": [
19 | {
20 | "Resource": {
21 | "ResourceID": "uhost-war3png3",
22 | "ResourceName": "eip-s1-bgp",
23 | "ResourceType": "uhost",
24 | "Zone": "cn-bj2-05",
25 | }
26 | }
27 | ],
28 | "RetCode": 0,
29 | "TotalBandwidth": 6,
30 | "TotalCount": 3,
31 | }
32 | assert (
33 | utest.value_at_path(d, "EIPSet.0.Resource.ResourceID")
34 | == "uhost-war3png3"
35 | )
36 |
--------------------------------------------------------------------------------
/tests/test_testing/test_utest.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | import pytest
4 | from ucloud.testing import utest, env
5 |
6 |
7 | @pytest.mark.skipif(env.is_ut(), reason=env.get_skip_reason())
8 | def test_acc_pre_check(self, client):
9 | assert str(client)
10 | assert client.config.to_dict()
11 | assert client.credential.to_dict()
12 | env.pre_check_env()
13 |
14 |
15 | def test_value_at_path():
16 | d = {
17 | "Action": "DescribeEIPResponse",
18 | "EIPSet": [
19 | {
20 | "Resource": {
21 | "ResourceID": "uhost-war3png3",
22 | "ResourceName": "eip-s1-bgp",
23 | "ResourceType": "uhost",
24 | "Zone": "cn-bj2-05",
25 | }
26 | }
27 | ],
28 | "RetCode": 0,
29 | "TotalBandwidth": 6,
30 | "TotalCount": 3,
31 | }
32 | assert (
33 | utest.value_at_path(d, "EIPSet.0.Resource.ResourceID")
34 | == "uhost-war3png3"
35 | )
36 |
--------------------------------------------------------------------------------
/ucloud/core/transport/utils.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | import codecs
4 |
5 | _null = "\x00".encode("ascii")
6 | _null2 = _null * 2
7 | _null3 = _null * 3
8 |
9 |
10 | def guess_json_utf(data):
11 | """ guess_json_utf will detect the encoding of bytes,
12 | see `requests.utils.guess_json_utf`
13 |
14 | :rtype: str
15 | """
16 | sample = data[:4]
17 | if sample in (codecs.BOM_UTF32_LE, codecs.BOM_UTF32_BE):
18 | return "utf-32"
19 | if sample[:3] == codecs.BOM_UTF8:
20 | return "utf-8-sig"
21 | if sample[:2] in (codecs.BOM_UTF16_LE, codecs.BOM_UTF16_BE):
22 | return "utf-16"
23 | nullcount = sample.count(_null)
24 | if nullcount == 0:
25 | return "utf-8"
26 | if nullcount == 2:
27 | if sample[::2] == _null2:
28 | return "utf-16-be"
29 | if sample[1::2] == _null2:
30 | return "utf-16-le"
31 | if nullcount == 3:
32 | if sample[:3] == _null3:
33 | return "utf-32-be"
34 | if sample[1:] == _null3:
35 | return "utf-32-le"
36 | return None
37 |
--------------------------------------------------------------------------------
/scripts/migrate/__main__.py:
--------------------------------------------------------------------------------
1 | import os
2 | import json
3 |
4 | from scripts.migrate._migrate import Migrate, Config, PluginConfig
5 |
6 |
7 | DEFAULT_CONFIG_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'config.json')
8 |
9 | if __name__ == '__main__':
10 | import argparse
11 |
12 | parser = argparse.ArgumentParser(description='argument parser')
13 | parser.add_argument('--source', required=True,
14 | help='source code file writen by python3')
15 | parser.add_argument('--output', required=True,
16 | help='output source code file writen by python2')
17 | parser.add_argument('--config', required=False,
18 | help='the configuration file for migration processing')
19 |
20 | with open(DEFAULT_CONFIG_PATH) as f:
21 | d = json.load(f)
22 |
23 | config = Config()
24 | config.plugins = [PluginConfig(**plugin) for plugin in d['plugins']]
25 | print(config.__dict__)
26 |
27 | args = parser.parse_args()
28 | migrate = Migrate(config)
29 | migrate.run(args.source, args.output)
30 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | UCloud SDK Python 2
6 |
7 |
8 |
9 |
10 |
11 |
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://ucloud.github.io/ucloud-sdk-python2/)
21 |
--------------------------------------------------------------------------------
/ucloud/services/udpn/schemas/models.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | """ Code is generated by ucloud-model, DO NOT EDIT IT. """
4 | from ucloud.core.typesystem import schema, fields
5 |
6 |
7 | class UDPNDataSchema(schema.ResponseSchema):
8 | """ UDPNData - UDPN 详细信息
9 | """
10 |
11 | fields = {
12 | "Bandwidth": fields.Int(required=True, load_from="Bandwidth"),
13 | "ChargeType": fields.Str(required=True, load_from="ChargeType"),
14 | "CreateTime": fields.Int(required=True, load_from="CreateTime"),
15 | "ExpireTime": fields.Int(required=True, load_from="ExpireTime"),
16 | "Peer1": fields.Str(required=True, load_from="Peer1"),
17 | "Peer2": fields.Str(required=True, load_from="Peer2"),
18 | "UDPNId": fields.Str(required=True, load_from="UDPNId"),
19 | }
20 |
21 |
22 | class UDPNLineSetSchema(schema.ResponseSchema):
23 | """ UDPNLineSet - GetUDPNLineList
24 | """
25 |
26 | fields = {
27 | "BandwidthUpperLimit": fields.Int(
28 | required=True, load_from="BandwidthUpperLimit"
29 | ),
30 | "LocalRegion": fields.Str(required=True, load_from="LocalRegion"),
31 | "RemoteRegion": fields.Str(required=True, load_from="RemoteRegion"),
32 | }
33 |
--------------------------------------------------------------------------------
/ucloud/services/ufs/schemas/models.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | """ Code is generated by ucloud-model, DO NOT EDIT IT. """
4 | from ucloud.core.typesystem import schema, fields
5 |
6 |
7 | class UFSVolumeInfo2Schema(schema.ResponseSchema):
8 | """ UFSVolumeInfo2 - 文件系统信息
9 | """
10 |
11 | fields = {
12 | "CreateTime": fields.Int(required=False, load_from="CreateTime"),
13 | "ExpiredTime": fields.Int(required=False, load_from="ExpiredTime"),
14 | "IsExpired": fields.Str(required=False, load_from="IsExpired"),
15 | "MaxMountPointNum": fields.Int(
16 | required=True, load_from="MaxMountPointNum"
17 | ),
18 | "ProtocolType": fields.Str(required=True, load_from="ProtocolType"),
19 | "Remark": fields.Str(required=False, load_from="Remark"),
20 | "Size": fields.Int(required=False, load_from="Size"),
21 | "StorageType": fields.Str(required=True, load_from="StorageType"),
22 | "Tag": fields.Str(required=False, load_from="Tag"),
23 | "TotalMountPointNum": fields.Int(
24 | required=True, load_from="TotalMountPointNum"
25 | ),
26 | "UsedSize": fields.Int(required=False, load_from="UsedSize"),
27 | "VolumeId": fields.Str(required=True, load_from="VolumeId"),
28 | "VolumeName": fields.Str(required=True, load_from="VolumeName"),
29 | }
30 |
--------------------------------------------------------------------------------
/scripts/migrate/test_migrate.py:
--------------------------------------------------------------------------------
1 | import ast
2 | import astor
3 | import pytest
4 |
5 | from scripts.migrate._plugin_py3to2 import SDK3to2Transformer
6 |
7 |
8 | @pytest.mark.parametrize(
9 | "input_vector,expected",
10 | [
11 | ("foo: int = 42", "foo = 42"),
12 | ("def fn(foo: str) -> int: pass", "def fn(foo):\n pass"),
13 | ("class Foo: pass", "class Foo(object):\n pass"),
14 | ("import typing", ""),
15 | ("str(value)", "unicode(value)"),
16 | ("def deco(fn: typing.Callable[[Client, dict], dict]): pass", "def deco(fn):\n pass"),
17 | ("""
18 | def step(self, **kwargs):
19 | def deco(fn: typing.Callable[[Client, dict], dict]):
20 | return fn
21 | return deco
22 | """, """
23 | def step(self, **kwargs):
24 | def deco(fn):
25 | return fn
26 | return deco
27 | """),
28 | ],
29 | )
30 | def test_transformer(input_vector, expected):
31 | transformer = SDK3to2Transformer()
32 | result = transformer.convert(input_vector)
33 | assert result == astor.to_source(ast.parse(expected))
34 |
35 |
36 | def test_parse_ast():
37 | input_vector = """
38 | def step(self, **kwargs):
39 | def deco(fn: typing.Callable[[Client, dict], dict]):
40 | return fn
41 | return deco
42 | """
43 | node = ast.parse(input_vector)
44 | print(astor.dump_tree(node))
45 |
--------------------------------------------------------------------------------
/ucloud/services/pathx/schemas/models.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | """ Code is generated by ucloud-model, DO NOT EDIT IT. """
4 | from ucloud.core.typesystem import schema, fields
5 |
6 |
7 | class GlobalSSHAreaSchema(schema.ResponseSchema):
8 | """ GlobalSSHArea - GlobalSSH覆盖地区,包括关联的UCloud机房信息
9 | """
10 |
11 | fields = {
12 | "Area": fields.Str(required=True, load_from="Area"),
13 | "AreaCode": fields.Str(required=True, load_from="AreaCode"),
14 | "RegionSet": fields.List(fields.Str()),
15 | }
16 |
17 |
18 | class GlobalSSHInfoSchema(schema.ResponseSchema):
19 | """ GlobalSSHInfo - GlobalSSH实例信息
20 | """
21 |
22 | fields = {
23 | "AcceleratingDomain": fields.Str(
24 | required=True, load_from="AcceleratingDomain"
25 | ),
26 | "Area": fields.Str(required=True, load_from="Area"),
27 | "ChargeType": fields.Str(required=True, load_from="ChargeType"),
28 | "CreateTime": fields.Int(required=True, load_from="CreateTime"),
29 | "ExpireTime": fields.Int(required=True, load_from="ExpireTime"),
30 | "InstanceId": fields.Str(required=True, load_from="InstanceId"),
31 | "Port": fields.Int(required=True, load_from="Port"),
32 | "Remark": fields.Str(required=True, load_from="Remark"),
33 | "TargetIP": fields.Str(required=True, load_from="TargetIP"),
34 | }
35 |
--------------------------------------------------------------------------------
/ucloud/services/stepflow/schemas/models.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | """ Code is generated by ucloud-model, DO NOT EDIT IT. """
4 | from ucloud.core.typesystem import schema, fields
5 |
6 |
7 | class ParamSchema(schema.ResponseSchema):
8 | """ Param - 工作流参数
9 | """
10 |
11 | fields = {
12 | "Name": fields.Str(required=False, load_from="Name"),
13 | "Type": fields.Str(required=False, load_from="Type"),
14 | "Value": fields.Str(required=False, load_from="Value"),
15 | }
16 |
17 |
18 | class ActivityTemplateSchema(schema.ResponseSchema):
19 | """ ActivityTemplate - 工作流的Activity定义
20 | """
21 |
22 | fields = {
23 | "Input": fields.Str(),
24 | "Name": fields.Str(required=False, load_from="Name"),
25 | "Next": fields.Str(required=False, load_from="Next"),
26 | "Output": fields.List(fields.Str()),
27 | "RetryTimes": fields.Str(required=False, load_from="RetryTimes"),
28 | "Timeout": fields.Str(required=False, load_from="Timeout"),
29 | "Type": fields.Str(required=False, load_from="Type"),
30 | }
31 |
32 |
33 | class WorkflowTemplateSchema(schema.ResponseSchema):
34 | """ WorkflowTemplate - Workflow对象定义
35 | """
36 |
37 | fields = {
38 | "Activites": fields.List(ActivityTemplateSchema()),
39 | "Input": fields.List(ParamSchema()),
40 | "Output": fields.List(ParamSchema()),
41 | }
42 |
--------------------------------------------------------------------------------
/ucloud/core/exc/_exc.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | import collections
4 | from ucloud.core.utils import compat
5 |
6 |
7 | class UCloudException(Exception):
8 | @property
9 | def retryable(self):
10 | return False
11 |
12 |
13 | MAX_COMMON_RET_CODE = 2000
14 |
15 |
16 | class RetCodeException(UCloudException):
17 | def __init__(self, action, code, message):
18 | self.action = action
19 | self.code = code
20 | self.message = message
21 |
22 | @property
23 | def retryable(self):
24 | return self.code > MAX_COMMON_RET_CODE
25 |
26 | def __str__(self):
27 | return "{self.action} - {self.code}: {self.message}".format(self=self)
28 |
29 | def json(self):
30 | return {
31 | "RetCode": self.code,
32 | "Message": self.message or "",
33 | "Action": self.action or "",
34 | }
35 |
36 |
37 | class RetryTimeoutException(UCloudException):
38 | pass
39 |
40 |
41 | class ValidationException(UCloudException):
42 | def __init__(self, e=None):
43 | if isinstance(e, compat.string_types):
44 | self.errors = [e]
45 | elif isinstance(e, collections.Iterable):
46 | self.errors = e or []
47 | else:
48 | self.errors = [e]
49 |
50 | @property
51 | def retryable(self):
52 | return False
53 |
54 | def __str__(self):
55 | return str([str(e) for e in self.errors])
56 |
--------------------------------------------------------------------------------
/tests/test_acceptance/conftest.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | import json
4 | import os
5 | import pytest
6 | from ucloud.testing.driver import spec
7 | from ucloud.client import Client
8 |
9 |
10 | @pytest.fixture(scope="session", autouse=True)
11 | def ustack_client():
12 | return Client(
13 | {
14 | "base_url": "http://console.pre.ucloudstack.com/api",
15 | "region": "cn",
16 | "public_key": os.getenv("UCLOUDSTACK_PUBLIC_KEY"),
17 | "private_key": os.getenv("UCLOUDSTACK_PRIVATE_KEY"),
18 | "max_retries": 10,
19 | "timeout": 60,
20 | }
21 | )
22 |
23 |
24 | @pytest.fixture(scope="session", autouse=True)
25 | def client():
26 | return Client(
27 | {
28 | "region": "cn-bj2",
29 | "project_id": os.getenv("UCLOUD_PROJECT_ID"),
30 | "public_key": os.getenv("UCLOUD_PUBLIC_KEY"),
31 | "private_key": os.getenv("UCLOUD_PRIVATE_KEY"),
32 | "max_retries": 10,
33 | "timeout": 60,
34 | }
35 | )
36 |
37 |
38 | @pytest.fixture(scope="module", autouse=True, name="variables")
39 | def variables_factory():
40 | return {
41 | "Region": "cn-bj2",
42 | "Zone": "cn-bj2-05",
43 | "ProjectId": os.getenv("UCLOUD_PROJECT_ID"),
44 | }
45 |
46 |
47 | @pytest.fixture(scope="session", autouse=True)
48 | def save_report(request):
49 | def save_report_handler():
50 | with open("./report.json", "w") as f:
51 | json.dump(spec.json(), f)
52 |
53 | request.addfinalizer(save_report_handler)
54 |
--------------------------------------------------------------------------------
/ucloud/services/uhub/schemas/models.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | """ Code is generated by ucloud-model, DO NOT EDIT IT. """
4 | from ucloud.core.typesystem import schema, fields
5 |
6 |
7 | class TagSetSchema(schema.ResponseSchema):
8 | """ TagSet - Tag详细信息
9 | """
10 |
11 | fields = {
12 | "TagName": fields.Str(required=True, load_from="TagName"),
13 | "UpdateTime": fields.Str(required=True, load_from="UpdateTime"),
14 | }
15 |
16 |
17 | class RepoSetSchema(schema.ResponseSchema):
18 | """ RepoSet - 镜像仓库
19 | """
20 |
21 | fields = {
22 | "CreateTime": fields.Str(required=True, load_from="CreateTime"),
23 | "Description": fields.Str(required=True, load_from="Description"),
24 | "IsOutSide": fields.Str(required=True, load_from="IsOutSide"),
25 | "IsShared": fields.Str(required=True, load_from="IsShared"),
26 | "RepoName": fields.Str(required=True, load_from="RepoName"),
27 | "UpdateTime": fields.Str(required=True, load_from="UpdateTime"),
28 | }
29 |
30 |
31 | class ImageSetSchema(schema.ResponseSchema):
32 | """ ImageSet - 镜像信息
33 | """
34 |
35 | fields = {
36 | "CreateTime": fields.Str(required=True, load_from="CreateTime"),
37 | "ImageName": fields.Str(required=True, load_from="ImageName"),
38 | "LatestTag": fields.Str(required=True, load_from="LatestTag"),
39 | "PullCount": fields.Int(required=True, load_from="PullCount"),
40 | "RepoName": fields.Str(required=True, load_from="RepoName"),
41 | "UpdateTime": fields.Str(required=True, load_from="UpdateTime"),
42 | }
43 |
--------------------------------------------------------------------------------
/ucloud/core/typesystem/abstract.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | from ucloud.core import exc
4 |
5 |
6 | class Field(object):
7 | def __init__(
8 | self,
9 | required=False,
10 | default=None,
11 | dump_to=None,
12 | load_from=None,
13 | strict=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)
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=False,
41 | default=dict,
42 | dump_to=None,
43 | load_from=None,
44 | strict=False,
45 | case_sensitive=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):
57 | raise NotImplementedError
58 |
59 | def loads(self, d):
60 | raise NotImplementedError
61 |
--------------------------------------------------------------------------------
/docs/index.rst:
--------------------------------------------------------------------------------
1 | UCloud SDK Python 2
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-python2.svg
13 | :target: https://pypi.python.org/pypi/ucloud-sdk-python2/
14 | :alt: Latest Version
15 | .. image:: https://travis-ci.org/ucloud/ucloud-sdk-python2.svg?branch=master
16 | :target: https://travis-ci.org/ucloud/ucloud-sdk-python2
17 | :alt: Travis CI Status
18 | .. image:: https://codecov.io/github/ucloud/ucloud-sdk-python2/coverage.svg?branch=master
19 | :target: https://codecov.io/github/ucloud/ucloud-sdk-python2?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-python2/
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 |
--------------------------------------------------------------------------------
/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-python2
12 |
13 | Install with source code:
14 |
15 | .. code:: shell
16 |
17 | clone https://github.com/ucloud/ucloud-sdk-python2.git
18 | cd ucloud-sdk-python2
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 |
--------------------------------------------------------------------------------
/.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 |
50 | # Translations
51 | *.mo
52 | *.pot
53 |
54 | # Django stuff:
55 | *.log
56 | local_settings.py
57 | db.sqlite3
58 |
59 | # Flask stuff:
60 | instance/
61 | .webassets-cache
62 |
63 | # Scrapy stuff:
64 | .scrapy
65 |
66 | # Sphinx documentation
67 | docs/build/
68 |
69 | # PyBuilder
70 | target/
71 |
72 | # Jupyter Notebook
73 | .ipynb_checkpoints
74 |
75 | # pyenv
76 | .python-version
77 |
78 | # celery beat schedule file
79 | celerybeat-schedule
80 |
81 | # SageMath parsed files
82 | *.sage.py
83 |
84 | # Environments
85 | .env
86 | .venv
87 | env/
88 | venv/
89 | ENV/
90 | env.bak/
91 | venv.bak/
92 |
93 | # Spyder project settings
94 | .spyderproject
95 | .spyproject
96 |
97 | # Rope project settings
98 | .ropeproject
99 |
100 | # mkdocs documentation
101 | /site
102 |
103 | # mypy
104 | .mypy_cache/
105 |
106 | # IDE / Editor
107 | .idea/
108 | .vscode/
109 | ~*
110 |
111 | # UCloud
112 | .migrate/
113 |
--------------------------------------------------------------------------------
/tests/test_core/test_fields.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | import logging
4 | import pytest
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 | with pytest.raises(exc.ValidationException):
15 | fields.Str(strict=True).loads(42)
16 |
17 |
18 | def test_field_int():
19 | i = fields.Int()
20 | assert i.dumps(i.loads("42")) == 42
21 | with pytest.raises(exc.ValidationException):
22 | fields.Int().dumps("foo")
23 | with pytest.raises(exc.ValidationException):
24 | fields.Int(strict=True).loads("42")
25 |
26 |
27 | def test_field_float():
28 | f = fields.Float()
29 | assert f.dumps(f.loads("42.0")) == 42.0
30 | with pytest.raises(exc.ValidationException):
31 | fields.Float().dumps("foo")
32 | with pytest.raises(exc.ValidationException):
33 | fields.Float(strict=True).loads("42.0")
34 |
35 |
36 | def test_field_bool():
37 | b = fields.Bool()
38 | assert b.dumps(b.loads("true"))
39 | assert not b.dumps(b.loads("false"))
40 | with pytest.raises(exc.ValidationException):
41 | fields.Bool().dumps("foo")
42 | with pytest.raises(exc.ValidationException):
43 | fields.Bool(strict=True).loads("true")
44 |
45 |
46 | def test_field_list():
47 | l = fields.List(fields.Int())
48 | assert l.dumps(l.loads(["42"])) == [42]
49 | with pytest.raises(exc.ValidationException):
50 | fields.List(fields.Int(), strict=True).dumps(42)
51 | with pytest.raises(exc.ValidationException):
52 | fields.List(fields.Int()).dumps(["foo"])
53 | with pytest.raises(exc.ValidationException):
54 | fields.List(fields.Int(strict=True)).loads(["42"])
55 |
56 |
57 | def test_field_base64():
58 | b64 = fields.Base64()
59 | assert b64.loads("Zm9v") == "foo"
60 | assert b64.dumps("foo") == "Zm9v"
61 |
--------------------------------------------------------------------------------
/scripts/migrate/_plugin_py3to2.py:
--------------------------------------------------------------------------------
1 | import ast
2 |
3 | import astor
4 |
5 |
6 | class SDK3to2Transformer(ast.NodeTransformer):
7 | UTF8_HEADER = '# -*- coding: utf-8 -*-\n\n'
8 |
9 | def visit_Import(self, node):
10 | is_typing = [alias for alias in node.names if alias.name == 'typing']
11 | return None if is_typing else node
12 |
13 | def visit_AnnAssign(self, node):
14 | if node.value is None:
15 | return node
16 | return ast.Assign(targets=[node.target], value=node.value)
17 |
18 | def visit_FunctionDef(self, node):
19 | body = []
20 |
21 | # remove type hints
22 | for arg in node.args.args:
23 | arg.annotation = None
24 |
25 | if node.args.kwarg:
26 | node.args.kwarg.annotation = None
27 |
28 | # visit children
29 | for child in node.body:
30 | if isinstance(child, ast.FunctionDef):
31 | body.append(self.visit_FunctionDef(child))
32 | elif isinstance(child, ast.AnnAssign):
33 | body.append(self.visit_AnnAssign(child))
34 | else:
35 | body.append(child)
36 |
37 | node.body = body
38 | node.returns = None
39 | return node
40 |
41 | def visit_ClassDef(self, node):
42 | body = []
43 |
44 | # old-style class convert to new-style class
45 | if not node.bases:
46 | node.bases = [ast.Name(id='object', ctx=ast.Load())]
47 |
48 | # visit children
49 | for child in node.body:
50 | if isinstance(child, ast.FunctionDef):
51 | body.append(self.visit_FunctionDef(child))
52 | else:
53 | body.append(child)
54 |
55 | node.body = body
56 | return node
57 |
58 | def convert(self, source: str) -> str:
59 | ast_node = ast.parse(source)
60 | ast_node = self.visit(ast_node)
61 | return self.UTF8_HEADER + astor.to_source(ast_node)
62 |
--------------------------------------------------------------------------------
/tests/test_unit/test_core/test_fields.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | import logging
4 | import pytest
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 | with pytest.raises(exc.ValidationException):
15 | fields.Str(strict=True).loads(42)
16 |
17 |
18 | def test_field_int():
19 | i = fields.Int()
20 | assert i.dumps(i.loads("42")) == 42
21 | with pytest.raises(exc.ValidationException):
22 | fields.Int().dumps("foo")
23 | with pytest.raises(exc.ValidationException):
24 | fields.Int(strict=True).loads("42")
25 |
26 |
27 | def test_field_float():
28 | f = fields.Float()
29 | assert f.dumps(f.loads("42.0")) == 42.0
30 | with pytest.raises(exc.ValidationException):
31 | fields.Float().dumps("foo")
32 | with pytest.raises(exc.ValidationException):
33 | fields.Float(strict=True).loads("42.0")
34 |
35 |
36 | def test_field_bool():
37 | b = fields.Bool()
38 | assert b.dumps(b.loads("true"))
39 | assert not b.dumps(b.loads("false"))
40 | with pytest.raises(exc.ValidationException):
41 | fields.Bool().dumps("foo")
42 | with pytest.raises(exc.ValidationException):
43 | fields.Bool(strict=True).loads("true")
44 |
45 |
46 | def test_field_list():
47 | l = fields.List(fields.Int())
48 | assert l.dumps(l.loads(["42"])) == [42]
49 | with pytest.raises(exc.ValidationException):
50 | fields.List(fields.Int(), strict=True).dumps(42)
51 | with pytest.raises(exc.ValidationException):
52 | fields.List(fields.Int()).dumps(["foo"])
53 | with pytest.raises(exc.ValidationException):
54 | fields.List(fields.Int(strict=True)).loads(["42"])
55 |
56 |
57 | def test_field_base64():
58 | b64 = fields.Base64()
59 | assert b64.loads("Zm9v") == "foo"
60 | assert b64.dumps("foo") == "Zm9v"
61 |
--------------------------------------------------------------------------------
/ucloud/testing/driver/_specification.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | from ucloud.testing.driver import _scenario
4 |
5 |
6 | class Specification(object):
7 | def __init__(self):
8 | self.scenarios = []
9 |
10 | def scenario(self, id_, title="", owners=None):
11 | scenario = _scenario.Scenario(self, id_, title, owners)
12 | self.scenarios.append(scenario)
13 | return scenario
14 |
15 | @property
16 | def status(self):
17 | if all([(item.status == "skipped") for item in self.scenarios]):
18 | status = "skipped"
19 | elif any([(item.status == "failed") for item in self.scenarios]):
20 | status = "failed"
21 | else:
22 | status = "passed"
23 | return status
24 |
25 | @property
26 | def start_time(self):
27 | times = [
28 | item.start_time
29 | for item in self.scenarios
30 | if item.status != "skipped"
31 | ]
32 | return min(times) if times else 0
33 |
34 | @property
35 | def end_time(self):
36 | times = [
37 | item.end_time for item in self.scenarios if item.status != "skipped"
38 | ]
39 | return max(times) if times else 0
40 |
41 | def json(self):
42 | return {
43 | "status": self.status,
44 | "execution": {
45 | "duration": self.end_time - self.start_time,
46 | "start_time": self.start_time,
47 | "end_time": self.end_time,
48 | },
49 | "scenarios": [item.json() for item in self.scenarios],
50 | "passed_count": len(
51 | [(1) for item in self.scenarios if item.status == "passed"]
52 | ),
53 | "failed_count": len(
54 | [(1) for item in self.scenarios if item.status == "failed"]
55 | ),
56 | "skipped_count": len(
57 | [(1) for item in self.scenarios if item.status == "skipped"]
58 | ),
59 | }
60 |
--------------------------------------------------------------------------------
/ucloud/testing/funcs.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | import datetime
4 | import time
5 |
6 |
7 | def concat(*args):
8 | """ cancat strings
9 |
10 | >>> concat(42, 'foo', 'bar')
11 | '42foobar'
12 | """
13 | return "".join([str(s) for s in args])
14 |
15 |
16 | def concat_without_dot(args):
17 | """ replace blank
18 |
19 | >>> concat_without_dot('42foo bar')
20 | '42foobar'
21 | """
22 | return "".join([str(s) for s in args.split()])
23 |
24 |
25 | def search_value(array, origin_key, origin_value, dest_key):
26 | """ given origin key and value,search dest_value form array by dest_key
27 |
28 | >>> d = [{"UHostId": "foo", "Name": "testing"}]
29 | >>> search_value(d, "Name", "testing", "UHostId")
30 | 'foo'
31 | """
32 | arr = [i.get(dest_key, "") for i in array if i[origin_key] == origin_value]
33 | if arr:
34 | return arr[0]
35 | return ""
36 |
37 |
38 | def timedelta(timestamp, value, typ="days"):
39 | """ given timestamp(10bit) and calculate relative delta time
40 |
41 | >>> timedelta(0, 1, "days")
42 | 86400.0
43 |
44 | :param timestamp: timestamp (round to second)
45 | :param value: float, can as positive or negative
46 | :param typ: days/hours
47 | :return: timestamp
48 | """
49 | value = int(value)
50 | dt = datetime.datetime.fromtimestamp(float(timestamp))
51 | if typ == "days":
52 | dt += datetime.timedelta(days=value)
53 | elif typ == "hours":
54 | dt += datetime.timedelta(hours=value)
55 | return time.mktime(dt.timetuple())
56 |
57 |
58 | def get_timestamp(length=13):
59 | """ get current timestamp string
60 |
61 | >>> len(str(int(get_timestamp(10))))
62 | 10
63 |
64 | :param length: length of timestamp, can only between 0 and 16
65 | :return:
66 | """
67 | if isinstance(length, int) and 0 < length < 17:
68 | return int("{:.6f}".format(time.time()).replace(".", "")[:length])
69 | raise ValueError("timestamp length can only between 0 and 16.")
70 |
--------------------------------------------------------------------------------
/docs/services.rst:
--------------------------------------------------------------------------------
1 | UCloud SDK Services
2 | ===================
3 |
4 | PathX
5 | -----
6 |
7 | .. autoclass:: ucloud.services.pathx.client.PathXClient
8 | :members:
9 |
10 | StepFlow
11 | --------
12 |
13 | .. autoclass:: ucloud.services.stepflow.client.StepFlowClient
14 | :members:
15 |
16 | UAccount
17 | --------
18 |
19 | .. autoclass:: ucloud.services.uaccount.client.UAccountClient
20 | :members:
21 |
22 | UCDN
23 | ----
24 |
25 | .. autoclass:: ucloud.services.ucdn.client.UCDNClient
26 | :members:
27 |
28 | UDB
29 | ---
30 |
31 | .. autoclass:: ucloud.services.udb.client.UDBClient
32 | :members:
33 |
34 | UDPN
35 | ----
36 |
37 | .. autoclass:: ucloud.services.udpn.client.UDPNClient
38 | :members:
39 |
40 | UDisk
41 | -----
42 |
43 | .. autoclass:: ucloud.services.udisk.client.UDiskClient
44 | :members:
45 |
46 | UHost
47 | -----
48 |
49 | .. autoclass:: ucloud.services.uhost.client.UHostClient
50 | :members:
51 |
52 | ULB
53 | ---
54 |
55 | .. autoclass:: ucloud.services.ulb.client.ULBClient
56 | :members:
57 |
58 | UMem
59 | ----
60 |
61 | .. autoclass:: ucloud.services.umem.client.UMemClient
62 | :members:
63 |
64 | UNet
65 | ----
66 |
67 | .. autoclass:: ucloud.services.unet.client.UNetClient
68 | :members:
69 |
70 | UPHost
71 | ------
72 |
73 | .. autoclass:: ucloud.services.uphost.client.UPHostClient
74 | :members:
75 |
76 | USMS
77 | ----
78 |
79 | .. autoclass:: ucloud.services.usms.client.USMSClient
80 | :members:
81 |
82 | VPC
83 | ---
84 |
85 | .. autoclass:: ucloud.services.vpc.client.VPCClient
86 | :members:
87 |
88 |
89 |
90 | IPSecVPN
91 | --------
92 |
93 | .. autoclass:: ucloud.services.ipsecvpn.client.IPSecVPNClient
94 | :members:
95 |
96 |
97 | UCloudStack
98 | -----------
99 |
100 | .. autoclass:: ucloud.services.ucloudstack.client.UCloudStackClient
101 | :members:
102 |
103 |
104 | UFS
105 | ---
106 |
107 | .. autoclass:: ucloud.services.ufs.client.UFSClient
108 | :members:
109 |
110 |
111 | UHub
112 | ----
113 |
114 | .. autoclass:: ucloud.services.uhub.client.UHubClient
115 | :members:
116 |
117 |
--------------------------------------------------------------------------------
/tests/test_core/test_transport.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | import pytest
4 | import logging
5 | from ucloud.core.transport import RequestsTransport, Request, Response, utils
6 |
7 | logger = logging.getLogger(__name__)
8 |
9 |
10 | @pytest.fixture(scope="function", autouse=True)
11 | def transport():
12 | return RequestsTransport()
13 |
14 |
15 | class TestTransport(object):
16 | def test_transport_send(self, transport):
17 | req = Request(
18 | url="http://httpbin.org/anything",
19 | method="post",
20 | json={"foo": "bar"},
21 | )
22 | resp = transport.send(req)
23 | assert resp.text
24 | assert resp.json()["json"] == {"foo": "bar"}
25 |
26 | def test_transport_handler(self, transport):
27 | global_env = {}
28 |
29 | def request_handler(r):
30 | global_env["req"] = r
31 | return r
32 |
33 | def response_handler(r):
34 | global_env["resp"] = r
35 | return r
36 |
37 | transport.middleware.request(handler=request_handler)
38 | transport.middleware.response(handler=response_handler)
39 | req = Request(
40 | url="http://httpbin.org/anything",
41 | method="post",
42 | json={"foo": "bar"},
43 | )
44 | resp = transport.send(req)
45 | assert resp.text
46 | assert resp.json()["json"] == {"foo": "bar"}
47 | assert "req" in global_env
48 | assert "resp" in global_env
49 |
50 |
51 | class TestResponse(object):
52 | def test_guess_json_utf(self):
53 | import json
54 |
55 | encodings = [
56 | "utf-32",
57 | "utf-8-sig",
58 | "utf-16",
59 | "utf-8",
60 | "utf-16-be",
61 | "utf-16-le",
62 | "utf-32-be",
63 | "utf-32-le",
64 | ]
65 | for e in encodings:
66 | s = json.dumps("表意字符").encode(e)
67 | assert utils.guess_json_utf(s) == e
68 |
69 | def test_response_empty_content(self):
70 | r = Response("http://foo.bar", "post")
71 | assert not r.text
72 | assert r.json() is None
73 |
--------------------------------------------------------------------------------
/tests/test_unit/test_core/test_transport.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | import pytest
4 | import logging
5 | from ucloud.core.transport import RequestsTransport, Request, Response, utils
6 |
7 | logger = logging.getLogger(__name__)
8 |
9 |
10 | @pytest.fixture(scope="function", autouse=True)
11 | def transport():
12 | return RequestsTransport()
13 |
14 |
15 | class TestTransport(object):
16 | def test_transport_send(self, transport):
17 | req = Request(
18 | url="http://httpbin.org/anything",
19 | method="post",
20 | json={"foo": "bar"},
21 | )
22 | resp = transport.send(req)
23 | assert resp.text
24 | assert resp.json()["json"] == {"foo": "bar"}
25 |
26 | def test_transport_handler(self, transport):
27 | global_env = {}
28 |
29 | def request_handler(r):
30 | global_env["req"] = r
31 | return r
32 |
33 | def response_handler(r):
34 | global_env["resp"] = r
35 | return r
36 |
37 | transport.middleware.request(handler=request_handler)
38 | transport.middleware.response(handler=response_handler)
39 | req = Request(
40 | url="http://httpbin.org/anything",
41 | method="post",
42 | json={"foo": "bar"},
43 | )
44 | resp = transport.send(req)
45 | assert resp.text
46 | assert resp.json()["json"] == {"foo": "bar"}
47 | assert "req" in global_env
48 | assert "resp" in global_env
49 |
50 |
51 | class TestResponse(object):
52 | def test_guess_json_utf(self):
53 | import json
54 |
55 | encodings = [
56 | "utf-32",
57 | "utf-8-sig",
58 | "utf-16",
59 | "utf-8",
60 | "utf-16-be",
61 | "utf-16-le",
62 | "utf-32-be",
63 | "utf-32-le",
64 | ]
65 | for e in encodings:
66 | s = json.dumps("表意字符").encode(e)
67 | assert utils.guess_json_utf(s) == e
68 |
69 | def test_response_empty_content(self):
70 | r = Response("http://foo.bar", "post")
71 | assert not r.text
72 | assert r.json() is None
73 |
--------------------------------------------------------------------------------
/ucloud/services/stepflow/schemas/apis.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | """ Code is generated by ucloud-model, DO NOT EDIT IT. """
4 | from ucloud.core.typesystem import schema, fields
5 | from ucloud.services.stepflow.schemas import models
6 |
7 | """ StepFlow API Schema
8 | """
9 | """
10 | API: CreateSFWorkflowFromTemplate
11 |
12 | 导入工作流定义
13 | """
14 |
15 |
16 | class CreateSFWorkflowFromTemplateRequestSchema(schema.RequestSchema):
17 | """ CreateSFWorkflowFromTemplate - 导入工作流定义
18 | """
19 |
20 | fields = {
21 | "Namespace": fields.Str(required=True, dump_to="Namespace"),
22 | "ProjectId": fields.Str(required=False, dump_to="ProjectId"),
23 | "Region": fields.Str(required=True, dump_to="Region"),
24 | "Workflow": fields.Base64(required=True, dump_to="Workflow"),
25 | "WorkflowName": fields.Str(required=True, dump_to="WorkflowName"),
26 | }
27 |
28 |
29 | class CreateSFWorkflowFromTemplateResponseSchema(schema.ResponseSchema):
30 | """ CreateSFWorkflowFromTemplate - 导入工作流定义
31 | """
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 |
50 | fields = {
51 | "ProjectId": fields.Str(required=False, dump_to="ProjectId"),
52 | "Region": fields.Str(required=True, dump_to="Region"),
53 | "WorkflowId": fields.Str(required=True, dump_to="WorkflowId"),
54 | "WorkflowVersion": fields.Int(
55 | required=False, dump_to="WorkflowVersion"
56 | ),
57 | }
58 |
59 |
60 | class GetSFWorkflowTemplateResponseSchema(schema.ResponseSchema):
61 | """ GetSFWorkflowTemplate - 导出工作流定义
62 | """
63 |
64 | fields = {
65 | "Message": fields.Str(required=False, load_from="Message"),
66 | "Version": fields.Int(required=True, load_from="Version"),
67 | "Workflow": models.WorkflowTemplateSchema(),
68 | "WorkflowId": fields.Str(required=True, load_from="WorkflowId"),
69 | }
70 |
--------------------------------------------------------------------------------
/ucloud/services/usms/schemas/models.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | """ Code is generated by ucloud-model, DO NOT EDIT IT. """
4 | from ucloud.core.typesystem import schema, fields
5 |
6 |
7 | class ReceiptPerPhoneSchema(schema.ResponseSchema):
8 | """ ReceiptPerPhone - 每个目的手机号的发送回执信息
9 | """
10 |
11 | fields = {
12 | "CostCount": fields.Int(required=True, load_from="CostCount"),
13 | "Phone": fields.Str(required=True, load_from="Phone"),
14 | "ReceiptDesc": fields.Str(required=True, load_from="ReceiptDesc"),
15 | "ReceiptResult": fields.Str(required=True, load_from="ReceiptResult"),
16 | "ReceiptTime": fields.Int(required=True, load_from="ReceiptTime"),
17 | }
18 |
19 |
20 | class ReceiptPerSessionSchema(schema.ResponseSchema):
21 | """ ReceiptPerSession - 每个提交的回执结果集合
22 | """
23 |
24 | fields = {
25 | "ReceiptSet": fields.List(ReceiptPerPhoneSchema()),
26 | "SessionNo": fields.Str(required=True, load_from="SessionNo"),
27 | }
28 |
29 |
30 | class OutSignatureSchema(schema.ResponseSchema):
31 | """ OutSignature - 短信签名
32 | """
33 |
34 | fields = {
35 | "ErrDesc": fields.Str(required=True, load_from="ErrDesc"),
36 | "SigContent": fields.Str(required=True, load_from="SigContent"),
37 | "SigId": fields.Str(required=True, load_from="SigId"),
38 | "Status": fields.Int(required=True, load_from="Status"),
39 | }
40 |
41 |
42 | class OutTemplateSchema(schema.ResponseSchema):
43 | """ OutTemplate - 短信模板
44 | """
45 |
46 | fields = {
47 | "CreateTime": fields.Int(required=True, load_from="CreateTime"),
48 | "ErrDesc": fields.Str(required=True, load_from="ErrDesc"),
49 | "Purpose": fields.Int(required=True, load_from="Purpose"),
50 | "Remark": fields.Str(required=True, load_from="Remark"),
51 | "Status": fields.Int(required=True, load_from="Status"),
52 | "Template": fields.Str(required=True, load_from="Template"),
53 | "TemplateId": fields.Str(required=True, load_from="TemplateId"),
54 | "TemplateName": fields.Str(required=True, load_from="TemplateName"),
55 | "UnsubscribeInfo": fields.Str(
56 | required=True, load_from="UnsubscribeInfo"
57 | ),
58 | }
59 |
--------------------------------------------------------------------------------
/ucloud/services/ipsecvpn/schemas/apis.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | """ Code is generated by ucloud-model, DO NOT EDIT IT. """
4 | from ucloud.core.typesystem import schema, fields
5 | from ucloud.services.ipsecvpn.schemas import models
6 |
7 | """ IPSecVPN API Schema
8 | """
9 | """
10 | API: DescribeRemoteVPNGateway
11 |
12 | 获取客户VPN网关信息
13 | """
14 |
15 |
16 | class DescribeRemoteVPNGatewayRequestSchema(schema.RequestSchema):
17 | """ DescribeRemoteVPNGateway - 获取客户VPN网关信息
18 | """
19 |
20 | fields = {
21 | "Limit": fields.Int(required=False, dump_to="Limit"),
22 | "Offset": fields.Int(required=False, dump_to="Offset"),
23 | "ProjectId": fields.Str(required=True, dump_to="ProjectId"),
24 | "Region": fields.Str(required=True, dump_to="Region"),
25 | "RemoteVPNGatewayIds": fields.List(fields.Str()),
26 | "Tag": fields.Str(required=False, dump_to="Tag"),
27 | }
28 |
29 |
30 | class DescribeRemoteVPNGatewayResponseSchema(schema.ResponseSchema):
31 | """ DescribeRemoteVPNGateway - 获取客户VPN网关信息
32 | """
33 |
34 | fields = {
35 | "DataSet": fields.List(
36 | models.RemoteVPNGatewayDataSetSchema(),
37 | required=False,
38 | load_from="DataSet",
39 | ),
40 | "TotalCount": fields.Int(required=False, load_from="TotalCount"),
41 | }
42 |
43 |
44 | """
45 | API: DescribeVPNTunnel
46 |
47 | 获取VPN隧道信息
48 | """
49 |
50 |
51 | class DescribeVPNTunnelRequestSchema(schema.RequestSchema):
52 | """ DescribeVPNTunnel - 获取VPN隧道信息
53 | """
54 |
55 | fields = {
56 | "Limit": fields.Int(required=False, dump_to="Limit"),
57 | "Offset": fields.Int(required=False, dump_to="Offset"),
58 | "ProjectId": fields.Str(required=True, dump_to="ProjectId"),
59 | "Region": fields.Str(required=True, dump_to="Region"),
60 | "Tag": fields.Str(required=False, dump_to="Tag"),
61 | "VPNTunnelIds": fields.List(fields.Str()),
62 | }
63 |
64 |
65 | class DescribeVPNTunnelResponseSchema(schema.ResponseSchema):
66 | """ DescribeVPNTunnel - 获取VPN隧道信息
67 | """
68 |
69 | fields = {
70 | "DataSet": fields.List(
71 | models.VPNTunnelDataSetSchema(), required=False, load_from="DataSet"
72 | ),
73 | "TotalCount": fields.Int(required=False, load_from="TotalCount"),
74 | }
75 |
--------------------------------------------------------------------------------
/ucloud/core/auth/_cfg.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | import hashlib
4 | from collections import OrderedDict
5 | from ucloud.core.typesystem import schema, fields, encoder
6 |
7 |
8 | class CredentialSchema(schema.Schema):
9 | fields = {
10 | "public_key": fields.Str(required=True),
11 | "private_key": fields.Str(required=True),
12 | }
13 |
14 |
15 | def verify_ac(private_key, params):
16 | """ calculate signature by private_key/public_key
17 |
18 | the keys can be found on `APIKey documentation `__
19 |
20 | >>> verify_ac("my_private_key", {"foo": "bar"})
21 | '634edc1bb957c0d65e5ab5494cf3b7784fbc87af'
22 |
23 | >>> verify_ac("my_private_key", {"foo": "bar"})
24 | '634edc1bb957c0d65e5ab5494cf3b7784fbc87af'
25 |
26 | :param private_key: private key
27 | :param params:
28 | :return:
29 | """
30 | params = OrderedDict(sorted(params.items(), key=lambda item: item[0]))
31 | simplified = ""
32 | for key, value in params.items():
33 | simplified += str(key) + encoder.encode_value(value)
34 | simplified += private_key
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(object):
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, private_key, **kwargs):
59 | self.public_key = public_key
60 | self.private_key = private_key
61 |
62 | def verify_ac(self, args):
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):
68 | parsed = CredentialSchema().dumps(d)
69 | return cls(**parsed)
70 |
71 | def to_dict(self):
72 | return {"public_key": self.public_key, "private_key": self.private_key}
73 |
--------------------------------------------------------------------------------
/ucloud/core/utils/middleware.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 |
4 | class Middleware(object):
5 | """ middleware is the object to store request/response handlers
6 |
7 | >>> middleware = Middleware()
8 |
9 | Add a request handler to prepare the request
10 |
11 | >>> @middleware.request
12 | ... def prepare(req):
13 | ... req['Region'] = 'cn-bj2'
14 | ... return req
15 |
16 | Add a response handler to log the response detail
17 |
18 | >>> @middleware.response
19 | ... def logged(resp):
20 | ... print(resp)
21 | ... return resp
22 |
23 | >>> len(middleware.request_handlers), len(middleware.response_handlers)
24 | (1, 1)
25 | """
26 |
27 | def __init__(self):
28 | self.request_handlers = []
29 | self.response_handlers = []
30 | self.exception_handlers = []
31 |
32 | def request(self, handler, index=-1):
33 | """ request is the request handler register to add request handler.
34 |
35 | :param handler: request handler function, receive request object
36 | and return a new request
37 | :param int index: the position of request in the handler list,
38 | default is append it to end
39 | :return:
40 | """
41 | self.request_handlers.insert(index, handler)
42 | return handler
43 |
44 | def response(self, handler, index=-1):
45 | """ response is the response handler register to add response handler.
46 |
47 | :param handler: response handler function, receive response object
48 | and return a new response
49 | :param int index: the position of response in the handler list,
50 | default is append it to end
51 | :return:
52 | """
53 | self.response_handlers.insert(index, handler)
54 | return handler
55 |
56 | def exception(self, handler, index=-1):
57 | """ exception is the exception handler register to add exception handler.
58 |
59 | :param handler: exception handler function, receive exception object
60 | and raise a new exception or ignore it
61 | :param int index: the position of handler in the handler list,
62 | default is append it to end
63 | :return:
64 | """
65 | self.exception_handlers.insert(index, handler)
66 | return handler
67 |
--------------------------------------------------------------------------------
/ucloud/helpers/utils.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | import random
4 | import base64
5 |
6 | _lowercase = "abcdefghijklmnopqrstuvwxyz"
7 | _uppercase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
8 | _numbers = "0123456789"
9 | _specials = "_"
10 |
11 |
12 | def gen_password(
13 | n,
14 | lower_letters=_lowercase,
15 | upper_letters=_uppercase,
16 | number_letters=_numbers,
17 | special_letters=_specials,
18 | min_lower=1,
19 | min_upper=1,
20 | min_number=1,
21 | min_specials=1,
22 | ):
23 | """ generate password for any resource
24 |
25 | >>> len(gen_password(20))
26 | 20
27 |
28 | :param int n: password total length
29 | :param str lower_letters: all lowercase letters
30 | :param str upper_letters: all uppercase letters
31 | :param str number_letters: all number letters
32 | :param str special_letters: all special letters
33 | :param int min_lower: minimal number of lowercase letters
34 | :param int min_upper: minimal number of uppercase letters
35 | :param int min_number: minimal number of number letters
36 | :param int min_specials: minimal number of special letters
37 | :return:
38 | """
39 | all_letters = "".join(
40 | [lower_letters, upper_letters, number_letters, special_letters]
41 | )
42 | minimal_total = min_lower + min_upper + min_number + min_specials
43 | if n < minimal_total:
44 | raise ValueError(
45 | "the length of password must be larger than total minimal letters number"
46 | )
47 | minimal_letters = "".join(
48 | [
49 | gen_string(lower_letters, min_lower),
50 | gen_string(upper_letters, min_upper),
51 | gen_string(number_letters, min_number),
52 | gen_string(special_letters, min_specials),
53 | ]
54 | )
55 | additional_letters = random.sample(all_letters, n - minimal_total)
56 | results = list(minimal_letters) + additional_letters
57 | random.shuffle(results)
58 | return "".join(results)
59 |
60 |
61 | def gen_string(letters, length):
62 | return "".join([random.choice(letters) for i in range(length)])
63 |
64 |
65 | def first(arr):
66 | if len(arr) == 0:
67 | return None
68 | return arr[0]
69 |
70 |
71 | def b64encode(s):
72 | """ base64 encode
73 |
74 | :param str s: input string
75 | :return: base64 string
76 | """
77 | return base64.b64encode(s.encode()).decode()
78 |
79 |
80 | def b64decode(s):
81 | """ base64 decode
82 |
83 | :param str s: base64 string
84 | :return: output string
85 | """
86 | return base64.b64decode(s.encode()).decode()
87 |
--------------------------------------------------------------------------------
/tests/test_unit/test_core/test_client.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | import os
4 | import pytest
5 | import logging
6 | from ucloud.client import Client
7 | from ucloud.core import exc
8 | from ucloud.testing.mock import MockedTransport
9 |
10 | logger = logging.getLogger(__name__)
11 |
12 |
13 | @pytest.fixture(scope="session", autouse=True)
14 | def client():
15 | return Client(
16 | {
17 | "region": "cn-bj2",
18 | "public_key": "foo",
19 | "private_key": "foo",
20 | "timeout": 10,
21 | "max_retries": 3,
22 | "ssl_verify": False,
23 | }
24 | )
25 |
26 |
27 | @pytest.fixture(scope="function", autouse=True)
28 | def transport():
29 | return MockedTransport()
30 |
31 |
32 | class TestClient(object):
33 | def test_client_invoke(self, client, transport):
34 | transport.mock_data(lambda _: {"RetCode": 0, "Action": "Foo"})
35 | client.transport = transport
36 | assert client.invoke("Foo") == {"RetCode": 0, "Action": "Foo"}
37 |
38 | def test_client_invoke_code_error(self, client, transport):
39 | transport.mock_data(lambda _: {"RetCode": 171, "Action": "Foo"})
40 | client.transport = transport
41 | with pytest.raises(exc.RetCodeException):
42 | try:
43 | client.invoke("Foo")
44 | except exc.RetCodeException as e:
45 | assert str(e)
46 | expected = {"RetCode": 171, "Action": "Foo", "Message": ""}
47 | assert e.json() == expected
48 | raise e
49 |
50 | def test_client_invoke_with_retryable_error(self, client, transport):
51 | transport.mock_data(lambda _: {"RetCode": 10000, "Action": "Foo"})
52 | client.transport = transport
53 | with pytest.raises(exc.RetCodeException):
54 | client.invoke("Foo")
55 |
56 | def test_client_invoke_with_unexpected_error(self, client, transport):
57 | def raise_error(_):
58 | raise ValueError("temporary error")
59 |
60 | transport.mock_data(raise_error)
61 | client.transport = transport
62 | with pytest.raises(ValueError):
63 | client.invoke("Foo")
64 |
65 | def test_client_try_import(self, client):
66 | assert client.pathx()
67 | assert client.stepflow()
68 | assert client.uaccount()
69 | assert client.udb()
70 | assert client.udpn()
71 | assert client.udisk()
72 | assert client.uhost()
73 | assert client.ulb()
74 | assert client.umem()
75 | assert client.unet()
76 | assert client.uphost()
77 | assert client.vpc()
78 |
--------------------------------------------------------------------------------
/tests/test_core/test_client.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | import os
4 | import pytest
5 | import logging
6 | from ucloud.client import Client
7 | from ucloud.core import exc
8 | from ucloud.testing.mock import MockedTransport
9 |
10 | logger = logging.getLogger(__name__)
11 |
12 |
13 | @pytest.fixture(scope="session", autouse=True)
14 | def client():
15 | return Client(
16 | {
17 | "region": "cn-bj2",
18 | "public_key": "foo",
19 | "private_key": "foo",
20 | "timeout": 10,
21 | "max_retries": 3,
22 | }
23 | )
24 |
25 |
26 | @pytest.fixture(scope="function", autouse=True)
27 | def transport():
28 | return MockedTransport()
29 |
30 |
31 | class TestClient(object):
32 | def test_client_invoke(self, client, transport):
33 | transport.mock_data(lambda _: {"RetCode": 0, "Action": "Foo"})
34 | client.transport = transport
35 | assert client.invoke("Foo") == {"RetCode": 0, "Action": "Foo"}
36 |
37 | def test_client_invoke_code_error(self, client, transport):
38 | transport.mock_data(lambda _: {"RetCode": 171, "Action": "Foo"})
39 | client.transport = transport
40 | with pytest.raises(exc.RetCodeException):
41 | try:
42 | client.invoke("Foo")
43 | except exc.RetCodeException as e:
44 | assert str(e)
45 | expected = {"RetCode": 171, "Action": "Foo", "Message": ""}
46 | assert e.json() == expected
47 | raise e
48 |
49 | def test_client_invoke_with_retryable_error(self, client, transport):
50 | transport.mock_data(lambda _: {"RetCode": 10000, "Action": "Foo"})
51 | client.transport = transport
52 | with pytest.raises(exc.RetCodeException):
53 | client.invoke("Foo")
54 |
55 | def test_client_invoke_with_unexpected_error(self, client, transport):
56 | def raise_error(_):
57 | raise ValueError("temporary error")
58 |
59 | transport.mock_data(raise_error)
60 | client.transport = transport
61 | with pytest.raises(ValueError):
62 | client.invoke("Foo")
63 |
64 | def test_client_try_import(self, client):
65 | assert client.pathx()
66 | assert client.stepflow()
67 | assert client.uaccount()
68 | assert client.udb()
69 | assert client.udpn()
70 | assert client.udisk()
71 | assert client.uhost()
72 | assert client.ulb()
73 | assert client.umem()
74 | assert client.unet()
75 | assert client.uphost()
76 | assert client.vpc()
77 |
--------------------------------------------------------------------------------
/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/services/uaccount/schemas/models.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | """ Code is generated by ucloud-model, DO NOT EDIT IT. """
4 | from ucloud.core.typesystem import schema, fields
5 |
6 |
7 | class ProjectListInfoSchema(schema.ResponseSchema):
8 | """ ProjectListInfo - 项目信息
9 | """
10 |
11 | fields = {
12 | "CreateTime": fields.Int(required=True, load_from="CreateTime"),
13 | "IsDefault": fields.Bool(required=True, load_from="IsDefault"),
14 | "MemberCount": fields.Int(required=True, load_from="MemberCount"),
15 | "ParentId": fields.Str(required=True, load_from="ParentId"),
16 | "ParentName": fields.Str(required=True, load_from="ParentName"),
17 | "ProjectId": fields.Str(required=True, load_from="ProjectId"),
18 | "ProjectName": fields.Str(required=True, load_from="ProjectName"),
19 | "ResourceCount": fields.Int(required=True, load_from="ResourceCount"),
20 | }
21 |
22 |
23 | class RegionInfoSchema(schema.ResponseSchema):
24 | """ RegionInfo - 数据中心信息
25 | """
26 |
27 | fields = {
28 | "BitMaps": fields.Str(required=True, load_from="BitMaps"),
29 | "IsDefault": fields.Bool(required=True, load_from="IsDefault"),
30 | "Region": fields.Str(required=True, load_from="Region"),
31 | "RegionId": fields.Int(required=True, load_from="RegionId"),
32 | "RegionName": fields.Str(required=True, load_from="RegionName"),
33 | "Zone": fields.Str(required=True, load_from="Zone"),
34 | }
35 |
36 |
37 | class UserInfoSchema(schema.ResponseSchema):
38 | """ UserInfo - 用户信息
39 | """
40 |
41 | fields = {
42 | "Admin": fields.Int(required=True, load_from="Admin"),
43 | "Administrator": fields.Str(required=True, load_from="Administrator"),
44 | "AuthState": fields.Str(required=True, load_from="AuthState"),
45 | "City": fields.Str(required=True, load_from="City"),
46 | "CompanyName": fields.Str(required=True, load_from="CompanyName"),
47 | "Finance": fields.Int(required=True, load_from="Finance"),
48 | "IndustryType": fields.Int(required=True, load_from="IndustryType"),
49 | "PhonePrefix": fields.Str(required=True, load_from="PhonePrefix"),
50 | "Province": fields.Str(required=True, load_from="Province"),
51 | "UserAddress": fields.Str(required=True, load_from="UserAddress"),
52 | "UserEmail": fields.Str(required=True, load_from="UserEmail"),
53 | "UserId": fields.Int(required=True, load_from="UserId"),
54 | "UserName": fields.Str(required=True, load_from="UserName"),
55 | "UserPhone": fields.Str(required=True, load_from="UserPhone"),
56 | "UserType": fields.Int(required=True, load_from="UserType"),
57 | "UserVersion": fields.Int(required=True, load_from="UserVersion"),
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/test_core
39 |
40 | test-acc: clean
41 | USDKACC=1 pytest --cov=ucloud
42 |
43 | test-all: clean
44 | tox
45 |
46 | lint:
47 | @flake8 --exclude=ucloud/services ucloud --ignore=E501,F401
48 |
49 | fmt:
50 | @black -l 80 ucloud tests examples
51 |
52 | dev:
53 | @pip install -e .[dev]
54 |
55 | docs:
56 | #sphinx-apidoc -o docs/services ucloud/services
57 | $(MAKE) -C docs clean
58 | $(MAKE) -C docs html
59 |
60 | docs-preview:
61 | $(BROWSER) docs/_build/html/index.html
62 |
63 | clean: clean-build clean-pyc clean-test
64 |
65 | clean-build:
66 | rm -fr build/
67 | rm -fr dist/
68 | rm -fr .eggs/
69 |
70 | clean-pyc:
71 | find . -name '*.pyc' -exec rm -f {} +
72 | find . -name '*.pyo' -exec rm -f {} +
73 | find . -name '*~' -exec rm -f {} +
74 | find . -name '__pycache__' -exec rm -fr {} +
75 |
76 | clean-test:
77 | rm -fr .tox/
78 | rm -f .coverage
79 | rm -fr htmlcov/
80 |
81 | migrate:
82 | git clone https://github.com/ucloud/ucloud-sdk-python3.git .migrate
83 | PYTHONPATH=. python3 scripts/migrate --source .migrate/ucloud --output ucloud
84 | PYTHONPATH=. python3 scripts/migrate --source .migrate/tests --output tests
85 | PYTHONPATH=. python3 scripts/migrate --source .migrate/docs --output docs
86 | PYTHONPATH=. python3 scripts/migrate --source .migrate/examples --output examples
87 | PYTHONPATH=. python3 scripts/migrate --source .migrate/README.md --output README.md
88 | sed -i 's/unicode/unicode # noqa: F821/g' ucloud/core/utils/compat.py
89 | rm -rf .migrate
90 |
--------------------------------------------------------------------------------
/ucloud/core/typesystem/schema.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | import logging
4 | from ucloud.core.typesystem import abstract
5 | from ucloud.core.exc import ValidationException
6 | from ucloud.core.utils import compat
7 |
8 | logger = logging.getLogger(__name__)
9 |
10 |
11 | class Schema(abstract.Schema):
12 | fields = {}
13 |
14 | def dumps(self, d, name=None, **kwargs):
15 | result = {}
16 | errors = []
17 | for k, field in self.fields.items():
18 | v = d.get(k)
19 | if v is None:
20 | if field.required:
21 | errors.append(
22 | ValidationException(
23 | "the field {k} is required".format(k=k)
24 | )
25 | )
26 | continue
27 | if field.default is None:
28 | continue
29 | if isinstance(field.default, compat.Callable):
30 | v = field.default()
31 | else:
32 | v = field.default
33 | try:
34 | serialized = field.dumps(v, name=k)
35 | except ValidationException as e:
36 | errors.extend(e.errors)
37 | continue
38 | result[field.dump_to or k] = serialized
39 | if len(errors) > 0:
40 | raise ValidationException(errors)
41 | return result
42 |
43 | def loads(self, d, name=None, **kwargs):
44 | result = {}
45 | errors = []
46 | if not self.case_sensitive:
47 | d = {k.lower(): v for k, v in d.items()}
48 | for k, field in self.fields.items():
49 | load_key = field.load_from or k
50 | v = d.get(load_key if self.case_sensitive else load_key.lower())
51 | if v is None:
52 | if field.default is None:
53 | continue
54 | if isinstance(field.default, compat.Callable):
55 | v = field.default()
56 | else:
57 | v = field.default
58 | try:
59 | serialized = field.loads(v, name=k)
60 | except ValidationException as e:
61 | errors.extend(e.errors)
62 | continue
63 | result[k] = serialized
64 | if len(errors) > 0:
65 | raise ValidationException(errors)
66 | return result
67 |
68 |
69 | class RequestSchema(Schema):
70 | fields = {}
71 |
72 | def dumps(self, d, name=None, **kwargs):
73 | if not isinstance(d, dict):
74 | raise ValidationException(
75 | "invalid field {}, expect dict, got {}".format(name, type(d))
76 | )
77 | result = super(RequestSchema, self).dumps(d, name=name, **kwargs)
78 | return result
79 |
80 |
81 | class ResponseSchema(Schema):
82 | pass
83 |
--------------------------------------------------------------------------------
/scripts/migrate/_migrate.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | import itertools
3 | import os
4 | import typing
5 | import logging
6 | import dataclasses
7 |
8 | from scripts.migrate._plugin_py3to2 import SDK3to2Transformer
9 | from scripts.migrate._plugin_doc import DocTransformer
10 |
11 | logging.basicConfig()
12 | logger = logging.getLogger(__name__)
13 |
14 |
15 | @dataclasses.dataclass
16 | class PluginConfig:
17 | name: str
18 | ext: typing.List[str] = None
19 | options: dict = None
20 |
21 |
22 | class Config:
23 | paths: typing.List[str] = []
24 | plugins: typing.List[PluginConfig] = []
25 |
26 |
27 | class Migrate(object):
28 | default_plugins_classes = {
29 | "py3to2": SDK3to2Transformer,
30 | "doc": DocTransformer,
31 | }
32 |
33 | def __init__(self, config: Config = None):
34 | self.plugins = {}
35 | self.ext = {}
36 | for plugin in config.plugins:
37 | plugin_cls = self.default_plugins_classes.get(plugin.name)
38 | if plugin_cls is None:
39 | continue
40 |
41 | plugin_inst = plugin_cls(**(plugin.options or {}))
42 | self.plugins[plugin.name] = plugin_inst
43 |
44 | for ext in plugin.ext:
45 | self.ext.setdefault(ext, list())
46 | self.ext[ext].append(plugin_inst)
47 |
48 | self.paths = config.paths
49 |
50 | def find_python_files(self, dir_or_file):
51 | if os.path.isdir(dir_or_file):
52 | for folder, _, files in list(os.walk(dir_or_file)):
53 | for file in files:
54 | yield folder + os.path.sep + file
55 | else:
56 | yield dir_or_file
57 |
58 | def run(self, source_path: str, output_path: str):
59 | for path in self.find_python_files(source_path):
60 | # find plugins by file extension
61 | plugins = [plugins for ext, plugins in self.ext.items() if path.endswith(ext)]
62 | plugins = plugins and plugins[0]
63 |
64 | # skip unexpected file by file extension
65 | if not plugins:
66 | continue
67 |
68 | # resolve path
69 | relative_path = os.path.relpath(path, source_path)
70 | result_path = os.path.abspath(os.path.join(output_path, relative_path))
71 | print('migrate {} to {}'.format(path, result_path))
72 |
73 | # read source code
74 | with open(path, encoding='utf-8') as f:
75 | source_code = f.read()
76 |
77 | # convert destination code
78 | output_code = source_code
79 | for plugin in plugins:
80 | output_code = plugin.convert(source_code)
81 |
82 | # output to file
83 | os.makedirs(os.path.dirname(result_path), exist_ok=True)
84 |
85 | with open(result_path, 'w', encoding='utf-8') as f:
86 | f.write(output_code)
87 |
--------------------------------------------------------------------------------
/examples/uhost/main.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | import os
4 | import logging
5 | import random
6 | from ucloud.client import Client
7 | from ucloud.helpers import wait, utils
8 |
9 | logger = logging.getLogger("ucloud")
10 | logger.setLevel(logging.DEBUG)
11 |
12 |
13 | def main():
14 | client = Client(
15 | {
16 | "region": "cn-bj2",
17 | "project_id": os.getenv("UCLOUD_PROJECT_ID"),
18 | "public_key": os.getenv("UCLOUD_PUBLIC_KEY"),
19 | "private_key": os.getenv("UCLOUD_PRIVATE_KEY"),
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 | assert len(images) > 0
29 | logger.info("creating uhost instance ...")
30 | image = random.choice(images)
31 | resp = client.uhost().create_uhost_instance(
32 | {
33 | "Name": "sdk-python-example",
34 | "Zone": image["Zone"],
35 | "ImageId": image["ImageId"],
36 | "LoginMode": "Password",
37 | "Password": utils.gen_password(20),
38 | "CPU": 1,
39 | "Memory": 1024,
40 | "Disks": [
41 | {
42 | "Size": image["ImageSize"],
43 | "Type": "LOCAL_NORMAL",
44 | "IsBoot": "True",
45 | }
46 | ],
47 | }
48 | )
49 | uhost_id = utils.first(resp["UHostIds"])
50 | logger.info("uhost instance is created")
51 |
52 | def refresh_state():
53 | uhost = utils.first(
54 | client.uhost()
55 | .describe_uhost_instance({"UHostIds": [uhost_id]})
56 | .get("UHostSet", [])
57 | )
58 | if uhost.get("State") in ["Running", "Stopped"]:
59 | return uhost["State"].lower()
60 | return "pending"
61 |
62 | logger.info("wait uhost state is running ...")
63 | try:
64 | wait.wait_for_state(
65 | pending=["pending"],
66 | target=["running"],
67 | timeout=300,
68 | refresh=refresh_state,
69 | )
70 | except wait.WaitTimeoutException as e:
71 | logger.error(e)
72 | logger.info("uhost instance is running")
73 | logger.info("stopping uhost for clean up resources ...")
74 | client.uhost().stop_uhost_instance({"UHostId": uhost_id})
75 | try:
76 | wait.wait_for_state(
77 | pending=["pending"],
78 | target=["stopped"],
79 | timeout=180,
80 | refresh=refresh_state,
81 | )
82 | except wait.WaitTimeoutException as e:
83 | logger.error(e)
84 | else:
85 | logger.info("uhost instance is stopped")
86 | logger.info("remove uhost instance from cloud")
87 | client.uhost().terminate_uhost_instance({"UHostId": uhost_id})
88 |
89 |
90 | if __name__ == "__main__":
91 | main()
92 |
--------------------------------------------------------------------------------
/ucloud/testing/driver/_scenario.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | import functools
4 | from ucloud.testing.driver import _step
5 |
6 |
7 | class Scenario(object):
8 | def __init__(self, spec, id_, title=None, owners=None):
9 | self.id = id_
10 | self.title = title
11 | self.store = {}
12 | self.errors = []
13 | self.steps = []
14 | self.spec = spec
15 | self.owners = owners
16 |
17 | def step(self, invoker, *args, **kwargs):
18 | step = _step.Step(self, invoker, *args, **kwargs)
19 | self.steps.append(step)
20 | return step
21 |
22 | def api(self, **step_kwargs):
23 | def deco(fn):
24 | step = self.step(fn, **step_kwargs)
25 |
26 | @functools.wraps(fn)
27 | def wrapped(*args, **kwargs):
28 | return step.run_api(*args, **kwargs)
29 |
30 | return wrapped
31 |
32 | return deco
33 |
34 | def func(self, **step_kwargs):
35 | def deco(fn):
36 | step = self.step(fn, **step_kwargs)
37 |
38 | @functools.wraps(fn)
39 | def wrapped(*args, **kwargs):
40 | return step.run_func(*args, **kwargs)
41 |
42 | return wrapped
43 |
44 | return deco
45 |
46 | @property
47 | def status(self):
48 | if all([(item.status == "skipped") for item in self.steps]):
49 | status = "skipped"
50 | elif any([(item.status == "failed") for item in self.steps]):
51 | status = "failed"
52 | else:
53 | status = "passed"
54 | return status
55 |
56 | @property
57 | def start_time(self):
58 | times = [
59 | item.start_time for item in self.steps if item.status != "skipped"
60 | ]
61 | return min(times) if times else 0
62 |
63 | @property
64 | def end_time(self):
65 | times = [
66 | item.end_time for item in self.steps if item.status != "skipped"
67 | ]
68 | return max(times) if times else 0
69 |
70 | def json(self):
71 | return {
72 | "title": self.title,
73 | "status": self.status,
74 | "steps": [item.json() for item in self.steps],
75 | "owners": self.owners,
76 | "execution": {
77 | "duration": self.end_time - self.start_time,
78 | "start_time": self.start_time,
79 | "end_time": self.end_time,
80 | },
81 | "passed_count": len(
82 | [(1) for item in self.steps if item.status == "passed"]
83 | ),
84 | "failed_count": len(
85 | [(1) for item in self.steps if item.status == "failed"]
86 | ),
87 | "skipped_count": len(
88 | [(1) for item in self.steps if item.status == "skipped"]
89 | ),
90 | }
91 |
92 | def __call__(self, *args, **kwargs):
93 | for step in self.steps:
94 | step(step, *args, **kwargs)
95 |
--------------------------------------------------------------------------------
/ucloud/core/transport/http.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | import logging
4 | import json as json_mod
5 | from ucloud.core.transport import utils
6 | from ucloud.core.utils.compat import str
7 |
8 | logger = logging.getLogger(__name__)
9 |
10 |
11 | class Request(object):
12 | def __init__(
13 | self,
14 | url,
15 | method="GET",
16 | params=None,
17 | data=None,
18 | json=None,
19 | headers=None,
20 | **kwargs
21 | ):
22 | self.url = url
23 | self.method = method
24 | self.params = params
25 | self.data = data
26 | self.json = json
27 | self.headers = headers
28 | self.request_time = 0
29 |
30 | def payload(self):
31 | payload = (self.params or {}).copy()
32 | payload.update(self.data or {})
33 | payload.update(self.json or {})
34 | return payload
35 |
36 |
37 | class Response(object):
38 | def __init__(
39 | self,
40 | url,
41 | method,
42 | request=None,
43 | status_code=None,
44 | reason=None,
45 | headers=None,
46 | content=None,
47 | encoding=None,
48 | **kwargs
49 | ):
50 | self.url = url
51 | self.method = method
52 | self.request = request
53 | self.status_code = status_code
54 | self.reason = reason
55 | self.headers = headers
56 | self.content = content
57 | self.encoding = encoding
58 | self.response_time = 0
59 |
60 | def json(self, **kwargs):
61 | """ json will return the bytes of content
62 | """
63 | if not self.content:
64 | return None
65 | encoding = utils.guess_json_utf(self.content)
66 | if encoding is not None:
67 | try:
68 | return json_mod.loads(self.content.decode(encoding), **kwargs)
69 | except UnicodeDecodeError:
70 | pass
71 | return json_mod.loads(self.text, **kwargs)
72 |
73 | @property
74 | def text(self):
75 | """ text will return the unicode string of content,
76 | see `requests.Response.text`
77 | """
78 | if not self.content:
79 | return str("")
80 | try:
81 | content = str(self.content, self.encoding, errors="replace")
82 | except (LookupError, TypeError):
83 | content = str(self.content, errors="replace")
84 | return content
85 |
86 |
87 | class SSLOption(object):
88 | def __init__(
89 | self, ssl_verify=True, ssl_cacert=None, ssl_cert=None, ssl_key=None
90 | ):
91 | self.ssl_verify = ssl_verify
92 | self.ssl_cacert = ssl_cacert
93 | self.ssl_cert = ssl_cert
94 | self.ssl_key = ssl_key
95 |
96 |
97 | class Transport(object):
98 | """ the abstract class of transport implementation """
99 |
100 | def send(self, req, **options):
101 | raise NotImplementedError
102 |
--------------------------------------------------------------------------------
/ucloud/services/uaccount/schemas/apis.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | """ Code is generated by ucloud-model, DO NOT EDIT IT. """
4 | from ucloud.core.typesystem import schema, fields
5 | from ucloud.services.uaccount.schemas import models
6 |
7 | """ UAccount API Schema
8 | """
9 | """
10 | API: CreateProject
11 |
12 | 创建项目
13 | """
14 |
15 |
16 | class CreateProjectRequestSchema(schema.RequestSchema):
17 | """ CreateProject - 创建项目
18 | """
19 |
20 | fields = {"ProjectName": fields.Str(required=True, dump_to="ProjectName")}
21 |
22 |
23 | class CreateProjectResponseSchema(schema.ResponseSchema):
24 | """ CreateProject - 创建项目
25 | """
26 |
27 | fields = {"ProjectId": fields.Str(required=True, load_from="ProjectId")}
28 |
29 |
30 | """
31 | API: GetProjectList
32 |
33 | 获取项目列表
34 | """
35 |
36 |
37 | class GetProjectListRequestSchema(schema.RequestSchema):
38 | """ GetProjectList - 获取项目列表
39 | """
40 |
41 | fields = {"IsFinance": fields.Str(required=False, dump_to="IsFinance")}
42 |
43 |
44 | class GetProjectListResponseSchema(schema.ResponseSchema):
45 | """ GetProjectList - 获取项目列表
46 | """
47 |
48 | fields = {
49 | "ProjectCount": fields.Int(required=True, load_from="ProjectCount"),
50 | "ProjectSet": fields.List(
51 | models.ProjectListInfoSchema(),
52 | required=True,
53 | load_from="ProjectSet",
54 | ),
55 | }
56 |
57 |
58 | """
59 | API: GetRegion
60 |
61 | 获取用户在各数据中心的权限等信息
62 | """
63 |
64 |
65 | class GetRegionRequestSchema(schema.RequestSchema):
66 | """ GetRegion - 获取用户在各数据中心的权限等信息
67 | """
68 |
69 | fields = {}
70 |
71 |
72 | class GetRegionResponseSchema(schema.ResponseSchema):
73 | """ GetRegion - 获取用户在各数据中心的权限等信息
74 | """
75 |
76 | fields = {
77 | "Regions": fields.List(
78 | models.RegionInfoSchema(), required=False, load_from="Regions"
79 | )
80 | }
81 |
82 |
83 | """
84 | API: GetUserInfo
85 |
86 | 获取用户信息
87 | """
88 |
89 |
90 | class GetUserInfoRequestSchema(schema.RequestSchema):
91 | """ GetUserInfo - 获取用户信息
92 | """
93 |
94 | fields = {}
95 |
96 |
97 | class GetUserInfoResponseSchema(schema.ResponseSchema):
98 | """ GetUserInfo - 获取用户信息
99 | """
100 |
101 | fields = {
102 | "DataSet": fields.List(
103 | models.UserInfoSchema(), required=True, load_from="DataSet"
104 | )
105 | }
106 |
107 |
108 | """
109 | API: ModifyProject
110 |
111 | 修改项目
112 | """
113 |
114 |
115 | class ModifyProjectRequestSchema(schema.RequestSchema):
116 | """ ModifyProject - 修改项目
117 | """
118 |
119 | fields = {
120 | "ProjectId": fields.Str(required=True, dump_to="ProjectId"),
121 | "ProjectName": fields.Str(required=True, dump_to="ProjectName"),
122 | }
123 |
124 |
125 | class ModifyProjectResponseSchema(schema.ResponseSchema):
126 | """ ModifyProject - 修改项目
127 | """
128 |
129 | fields = {}
130 |
131 |
132 | """
133 | API: TerminateProject
134 |
135 | 删除项目
136 | """
137 |
138 |
139 | class TerminateProjectRequestSchema(schema.RequestSchema):
140 | """ TerminateProject - 删除项目
141 | """
142 |
143 | fields = {"ProjectId": fields.Str(required=False, dump_to="ProjectId")}
144 |
145 |
146 | class TerminateProjectResponseSchema(schema.ResponseSchema):
147 | """ TerminateProject - 删除项目
148 | """
149 |
150 | fields = {}
151 |
--------------------------------------------------------------------------------
/ucloud/services/stepflow/client.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | """ Code is generated by ucloud-model, DO NOT EDIT IT. """
4 | from ucloud.core.client import Client
5 | from ucloud.services.stepflow.schemas import apis
6 |
7 |
8 | class StepFlowClient(Client):
9 | def __init__(self, config, transport=None, middleware=None, logger=None):
10 | super(StepFlowClient, self).__init__(
11 | config, transport, middleware, logger
12 | )
13 |
14 | def create_sf_workflow_from_template(self, req=None, **kwargs):
15 | """ CreateSFWorkflowFromTemplate - 导入工作流定义
16 |
17 | **Request**
18 |
19 | - **ProjectId** (str) - (Config) 项目ID。不填写为默认项目,子帐号必须填写。 请参考 `GetProjectList接口 `_
20 | - **Region** (str) - (Config) 地域。 参见 `地域和可用区列表 `_
21 | - **Namespace** (str) - (Required) 需要创建的工作流namespace
22 | - **Workflow** (str) - (Required) 描述工作流定义的base64字符串
23 | - **WorkflowName** (str) - (Required) 需要创建的工作流名称
24 |
25 | **Response**
26 |
27 | - **Message** (str) - 返回消息
28 | - **Version** (int) - 创建的工作流版本号
29 |
30 | """
31 | d = {"ProjectId": self.config.project_id, "Region": self.config.region}
32 | req and d.update(req)
33 | d = apis.CreateSFWorkflowFromTemplateRequestSchema().dumps(d)
34 | kwargs["max_retries"] = 0
35 | resp = self.invoke("CreateSFWorkflowFromTemplate", d, **kwargs)
36 | return apis.CreateSFWorkflowFromTemplateResponseSchema().loads(resp)
37 |
38 | def get_sf_workflow_template(self, req=None, **kwargs):
39 | """ GetSFWorkflowTemplate - 导出工作流定义
40 |
41 | **Request**
42 |
43 | - **ProjectId** (str) - (Config) 项目ID。不填写为默认项目,子帐号必须填写。 请参考 `GetProjectList接口 `_
44 | - **Region** (str) - (Config) 地域。 参见 `地域和可用区列表 `_
45 | - **WorkflowId** (str) - (Required) 被导出工作流的Id
46 | - **WorkflowVersion** (int) - 被导出工作流的版本号。取值范围:WorkflowVersion >= 1;默认会获取发布版本对应的workflow;超过最大版本会返回错误
47 |
48 | **Response**
49 |
50 | - **Message** (str) - 返回消息
51 | - **Version** (int) - 导出工作流的版本号
52 | - **Workflow** (dict) - 见 **WorkflowTemplate** 模型定义
53 | - **WorkflowId** (str) - 导出工作流的Id
54 |
55 | **Response Model**
56 |
57 | **Param**
58 |
59 | - **Name** (str) - 参数名称
60 | - **Type** (str) - 参数类型
61 | - **Value** (str) - 参数值
62 |
63 | **ActivityTemplate**
64 |
65 | - **Input** (dict) - Activity的输入
66 | - **Name** (str) - Activity的名字
67 | - **Next** (str) - 下一个Activity的名字
68 | - **Output** (list) - Activity的输出,详见Param
69 | - **RetryTimes** (str) - Activity的重试次数
70 | - **Timeout** (str) - Activity的超时时间
71 | - **Type** (str) - Activity的类型
72 |
73 | **WorkflowTemplate**
74 |
75 | - **Activites** (list) - 见 **ActivityTemplate** 模型定义
76 | - **Input** (list) - 见 **Param** 模型定义
77 | - **Output** (list) - 见 **Param** 模型定义
78 |
79 | """
80 | d = {"ProjectId": self.config.project_id, "Region": self.config.region}
81 | req and d.update(req)
82 | d = apis.GetSFWorkflowTemplateRequestSchema().dumps(d)
83 | resp = self.invoke("GetSFWorkflowTemplate", d, **kwargs)
84 | return apis.GetSFWorkflowTemplateResponseSchema().loads(resp)
85 |
--------------------------------------------------------------------------------
/ucloud/helpers/wait.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | import time
4 | import logging
5 | from ucloud.core import exc
6 |
7 | MAX_BACKOFF_INTERVAL = 10
8 | logger = logging.getLogger(__name__)
9 |
10 |
11 | class WaitTimeoutException(exc.UCloudException):
12 | pass
13 |
14 |
15 | class StateConf(object):
16 | """ StateConf is the utilities class to wait the state return by refresh function achieve the specific state,
17 | the generally usage is wait the cloud resource, such as uhost, udb ... is
18 | ready after created.
19 | """
20 |
21 | def __init__(
22 | self,
23 | pending,
24 | target,
25 | refresh,
26 | timeout,
27 | startup_delay=0,
28 | min_backoff_interval=0.1,
29 | max_backoff_interval=MAX_BACKOFF_INTERVAL,
30 | ):
31 | self.pending = pending
32 | self.target = target
33 | self.refresh = refresh
34 | self.timeout = timeout
35 | self.startup_delay = startup_delay
36 | self.min_backoff_interval = min_backoff_interval
37 | self.max_backoff_interval = max_backoff_interval
38 |
39 | def wait(self):
40 | start_time = time.time()
41 | interval = self.min_backoff_interval
42 | time.sleep(self.startup_delay)
43 | while time.time() - start_time < self.timeout:
44 | state = self.refresh()
45 | if state in self.pending:
46 | time.sleep(interval)
47 | interval *= 2
48 | if interval > self.max_backoff_interval:
49 | interval = self.max_backoff_interval
50 | logger.info(
51 | "waiting state for {self.refresh}, got state {state}".format(
52 | self=self, state=state
53 | )
54 | )
55 | continue
56 | if state in self.target:
57 | return
58 | raise WaitTimeoutException(
59 | "wait timeout {self.timeout}s for {self.refresh}".format(self=self)
60 | )
61 |
62 |
63 | def wait_for_state(
64 | pending,
65 | target,
66 | refresh,
67 | timeout,
68 | startup_delay=0,
69 | min_backoff_interval=0.1,
70 | max_backoff_interval=MAX_BACKOFF_INTERVAL,
71 | ):
72 | """ wait_for_state is a utilities function to wait the state return by refresh function achieve the specific state,
73 | the generally usage is wait the cloud resource, such as uhost, udb ... is
74 | ready after created.
75 |
76 | >>> wait_for_state(
77 | ... pending=["pending"],
78 | ... target=["running"],
79 | ... refresh=lambda: "running",
80 | ... timeout=0.5,
81 | ... )
82 |
83 | :param pending: pending is the list of pending state, the state is returned by refresh function
84 | :param target: target is the list of target state, it is usually the terminate state, eg. running and fail
85 | :param refresh: the customized refresh function, expect no arguments and return a state
86 | :param timeout: timeout is the total time to wait state is achieved
87 | :param startup_delay: the time to wait before first refresh function is called
88 | :param min_backoff_interval: the backoff time for first refresh interval
89 | :param max_backoff_interval: the max backoff time for refresh interval
90 | """
91 | conf = StateConf(
92 | pending=pending,
93 | target=target,
94 | refresh=refresh,
95 | timeout=timeout,
96 | startup_delay=startup_delay,
97 | min_backoff_interval=min_backoff_interval,
98 | max_backoff_interval=max_backoff_interval,
99 | )
100 | return conf.wait()
101 |
--------------------------------------------------------------------------------
/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 | PY2 = sys.version_info[0] == 2 and sys.version_info[1] >= 7
31 |
32 | if not PY2:
33 | raise NotImplementedError((
34 | "ucloud-sdk-python2 should be used in 2.7"
35 | "and above of python interpreter"
36 | ))
37 |
38 |
39 | def load_version():
40 | return importlib.import_module(
41 | "ucloud.version", os.path.join("ucloud", "version.py")
42 | ).version
43 |
44 |
45 | def load_long_description():
46 | try:
47 | with io.open("README.md", encoding="utf-8") as f:
48 | return f.read()
49 | except IOError:
50 | return ""
51 |
52 |
53 | def load_requirements(requirements_file):
54 | try:
55 | with io.open(requirements_file, encoding="utf-8") as f:
56 | return list(f.readlines())
57 | except IOError:
58 | return []
59 |
60 |
61 | dependencies = load_requirements("requirements.txt")
62 |
63 | dependencies_test = dependencies + [
64 | 'flake8>=3.6.0',
65 | 'pytest',
66 | 'pytest-cov',
67 | ]
68 |
69 | dependencies_doc = dependencies + ['sphinx']
70 |
71 | dependencies_ci = list(set(dependencies_test + dependencies_doc))
72 |
73 | dependencies_dev = list(set(dependencies_ci + ['black']))
74 |
75 |
76 | def do_setup():
77 | setup(
78 | name="ucloud-sdk-python2",
79 | description="UCloud Service Development Kit - Python",
80 | long_description=load_long_description(),
81 | long_description_content_type='text/markdown',
82 | license="Apache License 2.0",
83 | version=load_version(),
84 | packages=find_packages(exclude=["tests*"]),
85 | package_data={"": []},
86 | include_package_data=True,
87 | zip_safe=False,
88 | install_requires=dependencies,
89 | extras_require={
90 | "test": dependencies_test,
91 | "doc": dependencies_doc,
92 | "dev": dependencies_dev,
93 | "ci": dependencies_ci,
94 | },
95 | classifiers=[
96 | "Development Status :: 3 - Alpha",
97 | "Environment :: Console",
98 | "Environment :: Web Environment",
99 | "Intended Audience :: Developers",
100 | "Intended Audience :: System Administrators",
101 | "License :: OSI Approved :: Apache Software License",
102 | "Programming Language :: Python :: 2.7",
103 | "Programming Language :: Python :: 2 :: Only",
104 | "Topic :: Software Development",
105 | ],
106 | author="ucloud",
107 | author_email="esl_ipdd@ucloud.cn",
108 | url="https://github.com/ucloud/ucloud-sdk-python2",
109 | python_requires=">=2.7",
110 | )
111 |
112 |
113 | if __name__ == "__main__":
114 | do_setup()
115 |
--------------------------------------------------------------------------------
/ucloud/services/ufs/schemas/apis.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | """ Code is generated by ucloud-model, DO NOT EDIT IT. """
4 | from ucloud.core.typesystem import schema, fields
5 | from ucloud.services.ufs.schemas import models
6 |
7 | """ UFS API Schema
8 | """
9 | """
10 | API: CreateUFSVolume
11 |
12 | 创建文件系统
13 | """
14 |
15 |
16 | class CreateUFSVolumeRequestSchema(schema.RequestSchema):
17 | """ CreateUFSVolume - 创建文件系统
18 | """
19 |
20 | fields = {
21 | "ChargeType": fields.Str(required=False, dump_to="ChargeType"),
22 | "CouponId": fields.Str(required=False, dump_to="CouponId"),
23 | "ProjectId": fields.Str(required=False, dump_to="ProjectId"),
24 | "ProtocolType": fields.Str(required=True, dump_to="ProtocolType"),
25 | "Quantity": fields.Int(required=False, dump_to="Quantity"),
26 | "Region": fields.Str(required=True, dump_to="Region"),
27 | "Remark": fields.Str(required=False, dump_to="Remark"),
28 | "Size": fields.Int(required=True, dump_to="Size"),
29 | "StorageType": fields.Str(required=True, dump_to="StorageType"),
30 | "Tag": fields.Str(required=False, dump_to="Tag"),
31 | "VolumeName": fields.Str(required=False, dump_to="VolumeName"),
32 | }
33 |
34 |
35 | class CreateUFSVolumeResponseSchema(schema.ResponseSchema):
36 | """ CreateUFSVolume - 创建文件系统
37 | """
38 |
39 | fields = {
40 | "VolumeId": fields.Str(required=True, load_from="VolumeId"),
41 | "VolumeName": fields.Str(required=True, load_from="VolumeName"),
42 | "VolumeStatus": fields.Str(required=True, load_from="VolumeStatus"),
43 | }
44 |
45 |
46 | """
47 | API: DescribeUFSVolume2
48 |
49 | 获取文件系统列表
50 | """
51 |
52 |
53 | class DescribeUFSVolume2RequestSchema(schema.RequestSchema):
54 | """ DescribeUFSVolume2 - 获取文件系统列表
55 | """
56 |
57 | fields = {
58 | "Limit": fields.Int(required=False, dump_to="Limit"),
59 | "Offset": fields.Int(required=False, dump_to="Offset"),
60 | "ProjectId": fields.Str(required=False, dump_to="ProjectId"),
61 | "Region": fields.Str(required=True, dump_to="Region"),
62 | "VolumeId": fields.Str(required=False, dump_to="VolumeId"),
63 | }
64 |
65 |
66 | class DescribeUFSVolume2ResponseSchema(schema.ResponseSchema):
67 | """ DescribeUFSVolume2 - 获取文件系统列表
68 | """
69 |
70 | fields = {
71 | "DataSet": fields.List(
72 | models.UFSVolumeInfo2Schema(), required=True, load_from="DataSet"
73 | ),
74 | "TotalCount": fields.Int(required=True, load_from="TotalCount"),
75 | }
76 |
77 |
78 | """
79 | API: ExtendUFSVolume
80 |
81 | 文件系统扩容
82 | """
83 |
84 |
85 | class ExtendUFSVolumeRequestSchema(schema.RequestSchema):
86 | """ ExtendUFSVolume - 文件系统扩容
87 | """
88 |
89 | fields = {
90 | "ProjectId": fields.Str(required=False, dump_to="ProjectId"),
91 | "Region": fields.Str(required=True, dump_to="Region"),
92 | "Size": fields.Int(required=True, dump_to="Size"),
93 | "VolumeId": fields.Str(required=True, dump_to="VolumeId"),
94 | }
95 |
96 |
97 | class ExtendUFSVolumeResponseSchema(schema.ResponseSchema):
98 | """ ExtendUFSVolume - 文件系统扩容
99 | """
100 |
101 | fields = {}
102 |
103 |
104 | """
105 | API: RemoveUFSVolume
106 |
107 | 删除UFS文件系统
108 | """
109 |
110 |
111 | class RemoveUFSVolumeRequestSchema(schema.RequestSchema):
112 | """ RemoveUFSVolume - 删除UFS文件系统
113 | """
114 |
115 | fields = {
116 | "ProjectId": fields.Str(required=False, dump_to="ProjectId"),
117 | "Region": fields.Str(required=True, dump_to="Region"),
118 | "VolumeId": fields.Str(required=True, dump_to="VolumeId"),
119 | }
120 |
121 |
122 | class RemoveUFSVolumeResponseSchema(schema.ResponseSchema):
123 | """ RemoveUFSVolume - 删除UFS文件系统
124 | """
125 |
126 | fields = {}
127 |
--------------------------------------------------------------------------------
/ucloud/core/client/_cfg.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | import logging
4 | from ucloud.core.typesystem import schema, fields
5 |
6 |
7 | class ConfigSchema(schema.Schema):
8 | fields = {
9 | "region": fields.Str(),
10 | "project_id": fields.Str(),
11 | "base_url": fields.Str(default="https://api.ucloud.cn"),
12 | "user_agent": fields.Str(),
13 | "timeout": fields.Int(default=30),
14 | "max_retries": fields.Int(default=3),
15 | "log_level": fields.Int(default=logging.INFO),
16 | "validate_request": fields.Bool(default=True),
17 | "ssl_verify": fields.Bool(default=True),
18 | "ssl_cacert": fields.Str(),
19 | "ssl_cert": fields.Str(),
20 | "ssl_key": fields.Str(),
21 | }
22 |
23 |
24 | class Config(object):
25 | """
26 | Config is the config of ucloud sdk, use for setting up
27 |
28 | :type region: str
29 | :param region: Region is the region of backend service,
30 | See also `Region list Documentation `_
31 | :type project_id: str
32 | :param project_id: ProjectId is the unique identify of project, used for organize resources,
33 | Most of resources should belong to a project. Sub-Account must have an project id.
34 | See also `Project list Documentation `_
35 | :type base_url: str
36 | :param base_url: BaseUrl is the url of backend api
37 | :param user_agent: UserAgent is an attribute for sdk client, used for distinguish who is using sdk.
38 | See also `User Agent `_
39 | It will be appended to the end of sdk user-agent.
40 | eg. "MyAPP/0.10.1" -> "Python/3.7.0 Python-SDK/0.1.0 MyAPP/0.10.1"
41 | :type timeout: int
42 | :param timeout: Timeout is timeout for every request.
43 | :type max_retries: int
44 | :param max_retries: MaxRetries is the number of max retry times.
45 | Set MaxRetries more than 0 to enable auto-retry for network and service availability problem
46 | if auto-retry is enabled, it will enable default retry policy using exponential backoff.
47 | :type log_level: int
48 | :param log_level: LogLevel is equal to builtin logging level,
49 | if logLevel not be set, use INFO level as default.
50 | """
51 |
52 | def __init__(
53 | self,
54 | region=None,
55 | project_id=None,
56 | base_url="https://api.ucloud.cn",
57 | user_agent=None,
58 | timeout=30,
59 | max_retries=3,
60 | log_level=logging.INFO,
61 | ssl_verify=True,
62 | ssl_cacert=None,
63 | ssl_cert=None,
64 | ssl_key=None,
65 | **kwargs
66 | ):
67 | self.region = region
68 | self.project_id = project_id
69 | self.base_url = base_url
70 | self.user_agent = user_agent
71 | self.timeout = timeout
72 | self.max_retries = max_retries
73 | self.log_level = log_level
74 | self.ssl_verify = ssl_verify
75 | self.ssl_cacert = ssl_cacert
76 | self.ssl_cert = ssl_cert
77 | self.ssl_key = ssl_key
78 |
79 | @classmethod
80 | def from_dict(cls, d):
81 | parsed = ConfigSchema().dumps(d)
82 | return cls(**parsed)
83 |
84 | def to_dict(self):
85 | return {
86 | "region": self.region,
87 | "project_id": self.project_id,
88 | "base_url": self.base_url,
89 | "user_agent": self.user_agent,
90 | "timeout": self.timeout,
91 | "max_retries": self.max_retries,
92 | "log_level": self.log_level,
93 | "ssl_verify": self.ssl_verify,
94 | "ssl_cacert": self.ssl_cacert,
95 | "ssl_cert": self.ssl_cert,
96 | "ssl_key": self.ssl_key,
97 | }
98 |
--------------------------------------------------------------------------------
/examples/two-tier/main.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | import os
4 | import logging
5 | import random
6 | from ucloud.client import Client
7 | from ucloud.helpers import wait, utils
8 |
9 | logger = logging.getLogger("ucloud")
10 | logger.setLevel(logging.DEBUG)
11 | client = Client(
12 | {
13 | "region": "cn-bj2",
14 | "project_id": os.getenv("UCLOUD_PROJECT_ID"),
15 | "public_key": os.getenv("UCLOUD_PUBLIC_KEY"),
16 | "private_key": os.getenv("UCLOUD_PRIVATE_KEY"),
17 | }
18 | )
19 |
20 |
21 | def main():
22 | image_id = describe_image()
23 | uhost_ids = create_uhost_batch(image_id, 2)
24 | ulb_id = create_ulb()
25 | vserver_id = create_vserver(ulb_id)
26 | backend_ids = allocate_backend_batch(ulb_id, vserver_id, uhost_ids)
27 | backend_ids and release_backend_batch(ulb_id, vserver_id, backend_ids)
28 | vserver_id and delete_vserver(ulb_id, vserver_id)
29 | ulb_id and delete_ulb(ulb_id)
30 | uhost_ids and delete_uhost_batch(uhost_ids)
31 |
32 |
33 | def describe_image():
34 | images = (
35 | client.uhost().describe_image({"ImageType": "Base"}).get("ImageSet", [])
36 | )
37 | if not images:
38 | return
39 | image = random.choice(images)
40 | return image.get("ImageId")
41 |
42 |
43 | def mget_uhost_states(uhost_ids):
44 | resp = client.uhost().describe_uhost_instance({"UHostIds": uhost_ids})
45 | return [inst.get("State") for inst in resp.get("UHostSet")]
46 |
47 |
48 | def create_uhost_batch(image_id, count):
49 | resp = client.uhost().create_uhost_instance(
50 | {
51 | "Name": "sdk-python3-example-two-tier",
52 | "Zone": "cn-bj2-05",
53 | "ImageId": image_id,
54 | "LoginMode": "Password",
55 | "Password": utils.gen_password(20),
56 | "CPU": 1,
57 | "Memory": 1024,
58 | "MaxCount": count,
59 | }
60 | )
61 | uhost_ids = resp.get("UHostIds", [])
62 | wait.wait_for_state(
63 | target=["running"],
64 | pending=["pending"],
65 | timeout=300,
66 | refresh=lambda: "running"
67 | if all([(state == "Running") for state in mget_uhost_states(uhost_ids)])
68 | else "pending",
69 | )
70 | return uhost_ids
71 |
72 |
73 | def create_ulb():
74 | resp = client.ulb().create_ulb({"Name": "sdk-python3-example-two-tier"})
75 | return resp.get("ULBId")
76 |
77 |
78 | def create_vserver(ulb_id):
79 | resp = client.ulb().create_vserver(
80 | {"Name": "sdk-python3-example-two-tier", "ULBId": ulb_id}
81 | )
82 | return resp.get("VServerId")
83 |
84 |
85 | def allocate_backend_batch(ulb_id, vserver_id, uhost_ids):
86 | backend_ids = []
87 | for uhost_id in uhost_ids:
88 | resp = client.ulb().allocate_backend(
89 | {
90 | "ULBId": ulb_id,
91 | "VServerId": vserver_id,
92 | "ResourceId": uhost_id,
93 | "ResourceType": "UHost",
94 | }
95 | )
96 | backend_ids.append(resp.get("BackendId"))
97 | return backend_ids
98 |
99 |
100 | def release_backend_batch(ulb_id, vserver_id, backend_ids):
101 | for backend_id in backend_ids:
102 | client.ulb().release_backend(
103 | {"ULBId": ulb_id, "VServerId": vserver_id, "BackendId": backend_id}
104 | )
105 |
106 |
107 | def delete_vserver(ulb_id, vserver_id):
108 | client.ulb().delete_vserver({"ULBId": ulb_id, "VServerId": vserver_id})
109 |
110 |
111 | def delete_ulb(ulb_id):
112 | client.ulb().delete_ulb({"ULBId": ulb_id})
113 |
114 |
115 | def delete_uhost_batch(uhost_ids):
116 | for uhost_id in uhost_ids:
117 | client.uhost().stop_uhost_instance({"UHostId": uhost_id})
118 | wait.wait_for_state(
119 | target=["stopped"],
120 | pending=["pending"],
121 | timeout=300,
122 | refresh=lambda: "stopped"
123 | if all([(state == "Stopped") for state in mget_uhost_states(uhost_ids)])
124 | else "pending",
125 | )
126 | for uhost_id in uhost_ids:
127 | client.uhost().terminate_uhost_instance({"UHostId": uhost_id})
128 |
129 |
130 | if __name__ == "__main__":
131 | main()
132 |
--------------------------------------------------------------------------------
/ucloud/services/udisk/schemas/models.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | """ Code is generated by ucloud-model, DO NOT EDIT IT. """
4 | from ucloud.core.typesystem import schema, fields
5 |
6 |
7 | class UDiskDataSetSchema(schema.ResponseSchema):
8 | """ UDiskDataSet - DescribeUDisk
9 | """
10 |
11 | fields = {
12 | "ArkSwitchEnable": fields.Int(
13 | required=False, load_from="ArkSwitchEnable"
14 | ),
15 | "ChargeType": fields.Str(required=False, load_from="ChargeType"),
16 | "CloneEnable": fields.Int(required=False, load_from="CloneEnable"),
17 | "CmkId": fields.Str(required=False, load_from="CmkId"),
18 | "CmkIdAlias": fields.Str(required=False, load_from="CmkIdAlias"),
19 | "CmkIdStatus": fields.Str(required=False, load_from="CmkIdStatus"),
20 | "CreateTime": fields.Int(required=False, load_from="CreateTime"),
21 | "DataKey": fields.Str(required=False, load_from="DataKey"),
22 | "DeviceName": fields.Str(required=False, load_from="DeviceName"),
23 | "DiskType": fields.Str(required=False, load_from="DiskType"),
24 | "ExpiredTime": fields.Int(required=False, load_from="ExpiredTime"),
25 | "IsBoot": fields.Str(required=False, load_from="IsBoot"),
26 | "IsExpire": fields.Str(required=False, load_from="IsExpire"),
27 | "Name": fields.Str(required=False, load_from="Name"),
28 | "Size": fields.Int(required=False, load_from="Size"),
29 | "SnapEnable": fields.Int(required=False, load_from="SnapEnable"),
30 | "SnapshotCount": fields.Int(required=False, load_from="SnapshotCount"),
31 | "SnapshotLimit": fields.Int(required=False, load_from="SnapshotLimit"),
32 | "Status": fields.Str(required=False, load_from="Status"),
33 | "Tag": fields.Str(required=False, load_from="Tag"),
34 | "UDataArkMode": fields.Str(required=False, load_from="UDataArkMode"),
35 | "UDiskId": fields.Str(required=False, load_from="UDiskId"),
36 | "UHostIP": fields.Str(required=False, load_from="UHostIP"),
37 | "UHostId": fields.Str(required=False, load_from="UHostId"),
38 | "UHostName": fields.Str(required=False, load_from="UHostName"),
39 | "UKmsMode": fields.Str(required=False, load_from="UKmsMode"),
40 | "Version": fields.Str(required=False, load_from="Version"),
41 | "Zone": fields.Str(required=False, load_from="Zone"),
42 | }
43 |
44 |
45 | class UDiskPriceDataSetSchema(schema.ResponseSchema):
46 | """ UDiskPriceDataSet - DescribeUDiskPrice
47 | """
48 |
49 | fields = {
50 | "ChargeName": fields.Str(required=False, load_from="ChargeName"),
51 | "ChargeType": fields.Str(required=False, load_from="ChargeType"),
52 | "OriginalPrice": fields.Int(required=False, load_from="OriginalPrice"),
53 | "Price": fields.Int(required=False, load_from="Price"),
54 | }
55 |
56 |
57 | class UDiskSnapshotSetSchema(schema.ResponseSchema):
58 | """ UDiskSnapshotSet - DescribeUDiskSnapshot
59 | """
60 |
61 | fields = {
62 | "CmkId": fields.Str(required=False, load_from="CmkId"),
63 | "CmkIdAlias": fields.Str(required=False, load_from="CmkIdAlias"),
64 | "CmkIdStatus": fields.Str(required=False, load_from="CmkIdStatus"),
65 | "Comment": fields.Str(required=False, load_from="Comment"),
66 | "CreateTime": fields.Int(required=True, load_from="CreateTime"),
67 | "DataKey": fields.Str(required=False, load_from="DataKey"),
68 | "DiskType": fields.Int(required=True, load_from="DiskType"),
69 | "ExpiredTime": fields.Int(required=False, load_from="ExpiredTime"),
70 | "IsUDiskAvailable": fields.Bool(
71 | required=False, load_from="IsUDiskAvailable"
72 | ),
73 | "Name": fields.Str(required=True, load_from="Name"),
74 | "Size": fields.Int(required=True, load_from="Size"),
75 | "SnapshotId": fields.Str(required=True, load_from="SnapshotId"),
76 | "Status": fields.Str(required=True, load_from="Status"),
77 | "UDiskId": fields.Str(required=True, load_from="UDiskId"),
78 | "UDiskName": fields.Str(required=True, load_from="UDiskName"),
79 | "UHostId": fields.Str(required=False, load_from="UHostId"),
80 | "UKmsMode": fields.Str(required=False, load_from="UKmsMode"),
81 | "Version": fields.Str(required=False, load_from="Version"),
82 | }
83 |
--------------------------------------------------------------------------------
/ucloud/services/ipsecvpn/schemas/models.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | """ Code is generated by ucloud-model, DO NOT EDIT IT. """
4 | from ucloud.core.typesystem import schema, fields
5 |
6 |
7 | class RemoteVPNGatewayDataSetSchema(schema.ResponseSchema):
8 | """ RemoteVPNGatewayDataSet - DescribeRemoteVPNGateway返回参数
9 | """
10 |
11 | fields = {
12 | "ActiveTunnels": fields.Str(required=False, load_from="ActiveTunnels"),
13 | "CreateTime": fields.Int(required=False, load_from="CreateTime"),
14 | "Remark": fields.Str(required=False, load_from="Remark"),
15 | "RemoteVPNGatewayAddr": fields.Str(
16 | required=False, load_from="RemoteVPNGatewayAddr"
17 | ),
18 | "RemoteVPNGatewayId": fields.Str(
19 | required=False, load_from="RemoteVPNGatewayId"
20 | ),
21 | "RemoteVPNGatewayName": fields.Str(
22 | required=False, load_from="RemoteVPNGatewayName"
23 | ),
24 | "Tag": fields.Str(required=False, load_from="Tag"),
25 | "TunnelCount": fields.Int(required=False, load_from="TunnelCount"),
26 | }
27 |
28 |
29 | class IPSecDataSchema(schema.ResponseSchema):
30 | """ IPSecData - IPSec参数
31 | """
32 |
33 | fields = {
34 | "IPSecAuthenticationAlgorithm": fields.Str(
35 | required=False, load_from="IPSecAuthenticationAlgorithm"
36 | ),
37 | "IPSecEncryptionAlgorithm": fields.Str(
38 | required=False, load_from="IPSecEncryptionAlgorithm"
39 | ),
40 | "IPSecLocalSubnetIds": fields.List(fields.Str()),
41 | "IPSecPFSDhGroup": fields.Str(
42 | required=False, load_from="IPSecPFSDhGroup"
43 | ),
44 | "IPSecProtocol": fields.Str(required=False, load_from="IPSecProtocol"),
45 | "IPSecRemoteSubnets": fields.List(fields.Str()),
46 | "IPSecSALifetime": fields.Str(
47 | required=False, load_from="IPSecSALifetime"
48 | ),
49 | "IPSecSALifetimeBytes": fields.Str(
50 | required=False, load_from="IPSecSALifetimeBytes"
51 | ),
52 | }
53 |
54 |
55 | class IKEDataSchema(schema.ResponseSchema):
56 | """ IKEData - IKE信息
57 | """
58 |
59 | fields = {
60 | "IKEAuthenticationAlgorithm": fields.Str(
61 | required=False, load_from="IKEAuthenticationAlgorithm"
62 | ),
63 | "IKEDhGroup": fields.Str(required=False, load_from="IKEDhGroup"),
64 | "IKEEncryptionAlgorithm": fields.Str(
65 | required=False, load_from="IKEEncryptionAlgorithm"
66 | ),
67 | "IKEExchangeMode": fields.Str(
68 | required=False, load_from="IKEExchangeMode"
69 | ),
70 | "IKELocalId": fields.Str(required=False, load_from="IKELocalId"),
71 | "IKEPreSharedKey": fields.Str(
72 | required=False, load_from="IKEPreSharedKey"
73 | ),
74 | "IKERemoteId": fields.Str(required=False, load_from="IKERemoteId"),
75 | "IKESALifetime": fields.Str(required=False, load_from="IKESALifetime"),
76 | "IKEVersion": fields.Str(required=False, load_from="IKEVersion"),
77 | }
78 |
79 |
80 | class VPNTunnelDataSetSchema(schema.ResponseSchema):
81 | """ VPNTunnelDataSet - DescribeVPNTunnel信息
82 | """
83 |
84 | fields = {
85 | "CreateTime": fields.Int(required=False, load_from="CreateTime"),
86 | "IKEData": IKEDataSchema(),
87 | "IPSecData": IPSecDataSchema(),
88 | "Remark": fields.Str(required=False, load_from="Remark"),
89 | "RemoteVPNGatewayId": fields.Str(
90 | required=False, load_from="RemoteVPNGatewayId"
91 | ),
92 | "RemoteVPNGatewayName": fields.Str(
93 | required=False, load_from="RemoteVPNGatewayName"
94 | ),
95 | "Tag": fields.Str(required=False, load_from="Tag"),
96 | "VPCId": fields.Str(required=False, load_from="VPCId"),
97 | "VPCName": fields.Str(required=False, load_from="VPCName"),
98 | "VPNGatewayId": fields.Str(required=False, load_from="VPNGatewayId"),
99 | "VPNGatewayName": fields.Str(
100 | required=False, load_from="VPNGatewayName"
101 | ),
102 | "VPNTunnelId": fields.Str(required=False, load_from="VPNTunnelId"),
103 | "VPNTunnelName": fields.Str(required=False, load_from="VPNTunnelName"),
104 | }
105 |
--------------------------------------------------------------------------------
/ucloud/client.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | """ Code is generated by ucloud-model, DO NOT EDIT IT. """
4 | from ucloud._compat import CompactClient
5 |
6 |
7 | class Client(CompactClient):
8 | def __init__(self, config, transport=None, middleware=None):
9 | self._config = config
10 | super(Client, self).__init__(config, transport, middleware)
11 |
12 | def pathx(self):
13 | from ucloud.services.pathx.client import PathXClient
14 |
15 | return PathXClient(
16 | self._config, self.transport, self.middleware, self.logger
17 | )
18 |
19 | def stepflow(self):
20 | from ucloud.services.stepflow.client import StepFlowClient
21 |
22 | return StepFlowClient(
23 | self._config, self.transport, self.middleware, self.logger
24 | )
25 |
26 | def uaccount(self):
27 | from ucloud.services.uaccount.client import UAccountClient
28 |
29 | return UAccountClient(
30 | self._config, self.transport, self.middleware, self.logger
31 | )
32 |
33 | def ucdn(self):
34 | from ucloud.services.ucdn.client import UCDNClient
35 |
36 | return UCDNClient(
37 | self._config, self.transport, self.middleware, self.logger
38 | )
39 |
40 | def udb(self):
41 | from ucloud.services.udb.client import UDBClient
42 |
43 | return UDBClient(
44 | self._config, self.transport, self.middleware, self.logger
45 | )
46 |
47 | def udpn(self):
48 | from ucloud.services.udpn.client import UDPNClient
49 |
50 | return UDPNClient(
51 | self._config, self.transport, self.middleware, self.logger
52 | )
53 |
54 | def udisk(self):
55 | from ucloud.services.udisk.client import UDiskClient
56 |
57 | return UDiskClient(
58 | self._config, self.transport, self.middleware, self.logger
59 | )
60 |
61 | def uhost(self):
62 | from ucloud.services.uhost.client import UHostClient
63 |
64 | return UHostClient(
65 | self._config, self.transport, self.middleware, self.logger
66 | )
67 |
68 | def ulb(self):
69 | from ucloud.services.ulb.client import ULBClient
70 |
71 | return ULBClient(
72 | self._config, self.transport, self.middleware, self.logger
73 | )
74 |
75 | def umem(self):
76 | from ucloud.services.umem.client import UMemClient
77 |
78 | return UMemClient(
79 | self._config, self.transport, self.middleware, self.logger
80 | )
81 |
82 | def unet(self):
83 | from ucloud.services.unet.client import UNetClient
84 |
85 | return UNetClient(
86 | self._config, self.transport, self.middleware, self.logger
87 | )
88 |
89 | def uphost(self):
90 | from ucloud.services.uphost.client import UPHostClient
91 |
92 | return UPHostClient(
93 | self._config, self.transport, self.middleware, self.logger
94 | )
95 |
96 | def usms(self):
97 | from ucloud.services.usms.client import USMSClient
98 |
99 | return USMSClient(
100 | self._config, self.transport, self.middleware, self.logger
101 | )
102 |
103 | def ipsecvpn(self):
104 | from ucloud.services.ipsecvpn.client import IPSecVPNClient
105 |
106 | return IPSecVPNClient(
107 | self._config, self.transport, self.middleware, self.logger
108 | )
109 |
110 | def ucloudstack(self):
111 | from ucloud.services.ucloudstack.client import UCloudStackClient
112 |
113 | return UCloudStackClient(
114 | self._config, self.transport, self.middleware, self.logger
115 | )
116 |
117 | def ufs(self):
118 | from ucloud.services.ufs.client import UFSClient
119 |
120 | return UFSClient(
121 | self._config, self.transport, self.middleware, self.logger
122 | )
123 |
124 | def uhub(self):
125 | from ucloud.services.uhub.client import UHubClient
126 |
127 | return UHubClient(
128 | self._config, self.transport, self.middleware, self.logger
129 | )
130 |
131 | def vpc(self):
132 | from ucloud.services.vpc.client import VPCClient
133 |
134 | return VPCClient(
135 | self._config, self.transport, self.middleware, self.logger
136 | )
137 |
--------------------------------------------------------------------------------
/tests/test_services/test_set_2935.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | """ Code is generated by ucloud-model, DO NOT EDIT IT. """
4 | import pytest
5 | import logging
6 | from ucloud.core import exc
7 | from ucloud.testing import env, funcs, op, utest
8 |
9 | logger = logging.getLogger(__name__)
10 | scenario = utest.Scenario(2935)
11 |
12 |
13 | @pytest.mark.skipif(env.is_ut(), reason=env.get_skip_reason())
14 | def test_set_2935(client, variables):
15 | scenario.initial(variables)
16 | scenario.variables[
17 | "Image_Id_ucloud"
18 | ] = "#{u_get_image_resource($Region,$Zone)}"
19 | scenario.variables["saopaulo_image"] = "uimage-1bkjka"
20 | scenario.run(client)
21 |
22 |
23 | @scenario.step(
24 | max_retries=3,
25 | retry_interval=1,
26 | startup_delay=0,
27 | fast_fail=False,
28 | validators=lambda variables: [
29 | ("str_eq", "RetCode", 0),
30 | ("str_eq", "Action", "DescribeImageResponse"),
31 | ],
32 | action="DescribeImage",
33 | )
34 | def describe_image_00(client, variables):
35 | d = {
36 | "Zone": variables.get("Zone"),
37 | "Region": variables.get("Region"),
38 | "OsType": "Linux",
39 | "ImageType": "Base",
40 | }
41 | try:
42 | resp = client.uhost().describe_image(d)
43 | except exc.RetCodeException as e:
44 | resp = e.json()
45 | variables["Image_Id_ucloud"] = utest.value_at_path(
46 | resp, "ImageSet.0.ImageId"
47 | )
48 | return resp
49 |
50 |
51 | @scenario.step(
52 | max_retries=10,
53 | retry_interval=10,
54 | startup_delay=0,
55 | fast_fail=False,
56 | validators=lambda variables: [("str_eq", "RetCode", 0)],
57 | action="CreateULB",
58 | )
59 | def create_ulb_01(client, variables):
60 | d = {
61 | "ULBName": "测试",
62 | "Tag": "Default",
63 | "Region": variables.get("Region"),
64 | "InnerMode": "No",
65 | }
66 | try:
67 | resp = client.ulb().create_ulb(d)
68 | except exc.RetCodeException as e:
69 | resp = e.json()
70 | variables["ULBId"] = utest.value_at_path(resp, "ULBId")
71 | return resp
72 |
73 |
74 | @scenario.step(
75 | max_retries=10,
76 | retry_interval=10,
77 | startup_delay=5,
78 | fast_fail=False,
79 | validators=lambda variables: [
80 | ("str_eq", "RetCode", 0),
81 | ("len_ge", "DataSet", 1),
82 | ],
83 | action="DescribeULBSimple",
84 | )
85 | def describe_ulb_simple_02(client, variables):
86 | d = {"Region": variables.get("Region")}
87 | try:
88 | resp = client.invoke("DescribeULBSimple", d)
89 | except exc.RetCodeException as e:
90 | resp = e.json()
91 | return resp
92 |
93 |
94 | @scenario.step(
95 | max_retries=10,
96 | retry_interval=1,
97 | startup_delay=0,
98 | fast_fail=False,
99 | validators=lambda variables: [
100 | ("str_eq", "RetCode", 0),
101 | ("len_eq", "DataSet", 1),
102 | ],
103 | action="DescribeULBSimple",
104 | )
105 | def describe_ulb_simple_03(client, variables):
106 | d = {"ULBId": variables.get("ULBId"), "Region": variables.get("Region")}
107 | try:
108 | resp = client.invoke("DescribeULBSimple", d)
109 | except exc.RetCodeException as e:
110 | resp = e.json()
111 | return resp
112 |
113 |
114 | @scenario.step(
115 | max_retries=10,
116 | retry_interval=10,
117 | startup_delay=3,
118 | fast_fail=False,
119 | validators=lambda variables: [
120 | ("str_eq", "RetCode", 0),
121 | ("str_eq", "DataSet.0.ULBId", variables.get("ULBId")),
122 | ],
123 | action="DescribeULB",
124 | )
125 | def describe_ulb_04(client, variables):
126 | d = {
127 | "ULBId": variables.get("ULBId"),
128 | "Region": variables.get("Region"),
129 | "Offset": 0,
130 | "Limit": 60,
131 | }
132 | try:
133 | resp = client.ulb().describe_ulb(d)
134 | except exc.RetCodeException as e:
135 | resp = e.json()
136 | return resp
137 |
138 |
139 | @scenario.step(
140 | max_retries=10,
141 | retry_interval=10,
142 | startup_delay=0,
143 | fast_fail=False,
144 | validators=lambda variables: [("str_eq", "RetCode", 0)],
145 | action="DeleteULB",
146 | )
147 | def delete_ulb_05(client, variables):
148 | d = {"ULBId": variables.get("ULBId"), "Region": variables.get("Region")}
149 | try:
150 | resp = client.ulb().delete_ulb(d)
151 | except exc.RetCodeException as e:
152 | resp = e.json()
153 | return resp
154 |
--------------------------------------------------------------------------------
/ucloud/core/typesystem/fields.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | import base64
4 | import collections
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__(self, item, default=list, **kwargs):
19 | super(List, self).__init__(default=default, **kwargs)
20 | self.item = item
21 |
22 | def dumps(self, value, name=None, **kwargs):
23 | if not isinstance(value, collections.Iterable):
24 | raise ValidationException(
25 | "invalid field {}, expect list, got {}".format(
26 | name, type(value)
27 | )
28 | )
29 | errors = []
30 | values = []
31 | for each in value:
32 | try:
33 | v = self.item.dumps(each)
34 | except ValidationException as e:
35 | errors.extend(e.errors)
36 | else:
37 | values.append(v)
38 | if len(errors) > 0:
39 | raise ValidationException(errors)
40 | return values
41 |
42 | def loads(self, value, name=None, **kwargs):
43 | if not isinstance(value, collections.Iterable):
44 | raise ValidationException(
45 | "invalid field {}, expect list, got {}".format(
46 | name, type(value)
47 | )
48 | )
49 | errors = []
50 | values = []
51 | for each in value:
52 | try:
53 | v = self.item.loads(each)
54 | except ValidationException as e:
55 | errors.extend(e.errors)
56 | else:
57 | values.append(v)
58 | if len(errors) > 0:
59 | raise ValidationException(errors)
60 | return values
61 |
62 |
63 | class Str(abstract.Field):
64 | def dumps(self, value, name=None, **kwargs):
65 | return self._convert(value, name)
66 |
67 | def loads(self, value, name=None, **kwargs):
68 | return self._convert(value, name)
69 |
70 | def _convert(self, value, name=None):
71 | if self.strict and not isinstance(value, str):
72 | self.fail(name, "str", type(value))
73 | return str(value)
74 |
75 |
76 | class Base64(Str):
77 | def dumps(self, value, name=None, **kwargs):
78 | s = super(Base64, self).dumps(value, name)
79 | return base64.b64encode(s.encode()).decode()
80 |
81 | def loads(self, value, name=None, **kwargs):
82 | s = super(Base64, self).loads(value, name)
83 | return base64.b64decode(s.encode()).decode()
84 |
85 |
86 | class Int(abstract.Field):
87 | def dumps(self, value, name=None, **kwargs):
88 | return self._convert(value, name)
89 |
90 | def loads(self, value, name=None, **kwargs):
91 | return self._convert(value, name)
92 |
93 | def _convert(self, value, name=None):
94 | if self.strict and not isinstance(value, int):
95 | self.fail(name, "int", type(value))
96 | try:
97 | return int(value)
98 | except ValueError:
99 | self.fail(name, "int", type(value))
100 |
101 |
102 | class Float(abstract.Field):
103 | def dumps(self, value, name=None, **kwargs):
104 | return self._convert(value, name)
105 |
106 | def loads(self, value, name=None, **kwargs):
107 | return self._convert(value, name)
108 |
109 | def _convert(self, value, name=None):
110 | if self.strict and not isinstance(value, float):
111 | self.fail(name, "float", type(value))
112 | try:
113 | return float(value)
114 | except ValueError:
115 | self.fail(name, "float", type(value))
116 |
117 |
118 | class Bool(abstract.Field):
119 | def dumps(self, value, name=None, **kwargs):
120 | return self._convert(value, name)
121 |
122 | def loads(self, value, name=None, **kwargs):
123 | return self._convert(value, name)
124 |
125 | def _convert(self, value, name=None):
126 | if self.strict and not isinstance(value, bool):
127 | self.fail(name, "bool", type(value))
128 | if value == "true" or value is True:
129 | return True
130 | if value == "false" or value is False:
131 | return False
132 | self.fail(name, "bool", type(value))
133 |
--------------------------------------------------------------------------------
/ucloud/core/transport/_requests.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | import time
4 | import requests
5 | from urllib3.util.retry import Retry
6 | from requests.adapters import HTTPAdapter
7 | from ucloud.core.transport import http
8 | from ucloud.core.transport.http import Request, Response, SSLOption
9 | from ucloud.core.utils.middleware import Middleware
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=3,
27 | backoff_factor=0.3,
28 | status_forcelist=(500, 502, 504),
29 | ):
30 | self.max_retries = max_retries
31 | self.backoff_factor = backoff_factor
32 | self.status_forcelist = status_forcelist
33 | self._adapter = self._load_adapter(max_retries)
34 | self._middleware = Middleware()
35 |
36 | def send(self, req, **options):
37 | """ send request and return the response
38 |
39 | :param req: the full http request descriptor
40 | :return: the response of http request
41 | """
42 | for handler in self.middleware.request_handlers:
43 | req = handler(req)
44 | try:
45 | resp = self._send(req, **options)
46 | except Exception as e:
47 | for handler in self.middleware.exception_handlers:
48 | handler(e)
49 | raise e
50 | for handler in self.middleware.response_handlers:
51 | resp = handler(resp)
52 | return resp
53 |
54 | @property
55 | def middleware(self):
56 | """ the middleware object, see :mod:
57 |
58 | :return: the transport middleware
59 | """
60 | return self._middleware
61 |
62 | def _send(self, req, **options):
63 | with requests.Session() as session:
64 | adapter = self._load_adapter(options.get("max_retries"))
65 | session.mount("http://", adapter=adapter)
66 | session.mount("https://", adapter=adapter)
67 | ssl_option = options.get("ssl_option")
68 | kwargs = self._build_ssl_option(ssl_option) if ssl_option else {}
69 | req.request_time = time.time()
70 | session_resp = session.request(
71 | method=req.method.upper(),
72 | url=req.url,
73 | json=req.json,
74 | data=req.data,
75 | params=req.params,
76 | headers=req.headers,
77 | **kwargs
78 | )
79 | resp = self.convert_response(session_resp)
80 | resp.request = req
81 | resp.response_time = time.time()
82 | return resp
83 |
84 | @staticmethod
85 | def _build_ssl_option(ssl_option):
86 | kwargs = {"verify": ssl_option.ssl_verify and ssl_option.ssl_cacert}
87 | if not ssl_option.ssl_cert:
88 | return kwargs
89 | if ssl_option.ssl_key:
90 | kwargs["cert"] = ssl_option.ssl_cert, ssl_option.ssl_key
91 | else:
92 | kwargs["cert"] = ssl_option.ssl_cert
93 | return kwargs
94 |
95 | def _load_adapter(self, max_retries=None):
96 | if max_retries is None and self._adapter is not None:
97 | return self._adapter
98 | max_retries = max_retries or 0
99 | adapter = HTTPAdapter()
100 | adapter.max_retries = Retry(
101 | total=max_retries,
102 | read=max_retries,
103 | connect=max_retries,
104 | backoff_factor=self.backoff_factor,
105 | status_forcelist=self.status_forcelist,
106 | )
107 | return adapter
108 |
109 | @staticmethod
110 | def convert_response(r):
111 | return Response(
112 | url=r.url,
113 | method=r.request.method,
114 | status_code=r.status_code,
115 | reason=r.reason,
116 | headers=r.headers,
117 | content=r.content,
118 | encoding=r.encoding or r.apparent_encoding,
119 | )
120 |
--------------------------------------------------------------------------------
/ucloud/services/uphost/schemas/models.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | """ Code is generated by ucloud-model, DO NOT EDIT IT. """
4 | from ucloud.core.typesystem import schema, fields
5 |
6 |
7 | class PHostIPSetSchema(schema.ResponseSchema):
8 | """ PHostIPSet - DescribePHost
9 | """
10 |
11 | fields = {
12 | "Bandwidth": fields.Int(required=False, load_from="Bandwidth"),
13 | "IPAddr": fields.Str(required=False, load_from="IPAddr"),
14 | "IPId": fields.Str(required=False, load_from="IPId"),
15 | "MACAddr": fields.Str(required=False, load_from="MACAddr"),
16 | "OperatorName": fields.Str(required=False, load_from="OperatorName"),
17 | "SubnetId": fields.Str(required=False, load_from="SubnetId"),
18 | "VPCId": fields.Str(required=False, load_from="VPCId"),
19 | }
20 |
21 |
22 | class PHostDiskSetSchema(schema.ResponseSchema):
23 | """ PHostDiskSet - GetPHostTypeInfo
24 | """
25 |
26 | fields = {
27 | "Count": fields.Int(required=False, load_from="Count"),
28 | "IOCap": fields.Int(required=False, load_from="IOCap"),
29 | "Name": fields.Str(required=False, load_from="Name"),
30 | "Space": fields.Int(required=False, load_from="Space"),
31 | "Type": fields.Str(required=False, load_from="Type"),
32 | }
33 |
34 |
35 | class PHostCPUSetSchema(schema.ResponseSchema):
36 | """ PHostCPUSet - DescribePHost
37 | """
38 |
39 | fields = {
40 | "CoreCount": fields.Int(required=False, load_from="CoreCount"),
41 | "Count": fields.Int(required=False, load_from="Count"),
42 | "Frequence": fields.Float(required=False, load_from="Frequence"),
43 | "Model": fields.Str(required=False, load_from="Model"),
44 | }
45 |
46 |
47 | class PHostSetSchema(schema.ResponseSchema):
48 | """ PHostSet - DescribePHost
49 | """
50 |
51 | fields = {
52 | "AutoRenew": fields.Str(required=False, load_from="AutoRenew"),
53 | "CPUSet": PHostCPUSetSchema(),
54 | "ChargeType": fields.Str(required=False, load_from="ChargeType"),
55 | "Cluster": fields.Str(required=False, load_from="Cluster"),
56 | "Components": fields.Str(required=False, load_from="Components"),
57 | "CreateTime": fields.Int(required=False, load_from="CreateTime"),
58 | "DiskSet": fields.List(PHostDiskSetSchema()),
59 | "ExpireTime": fields.Int(required=False, load_from="ExpireTime"),
60 | "IPSet": fields.List(PHostIPSetSchema()),
61 | "ImageName": fields.Str(required=False, load_from="ImageName"),
62 | "IsSupportKVM": fields.Str(required=False, load_from="IsSupportKVM"),
63 | "Memory": fields.Int(required=False, load_from="Memory"),
64 | "Name": fields.Str(required=False, load_from="Name"),
65 | "OSType": fields.Str(required=False, load_from="OSType"),
66 | "OSname": fields.Str(required=False, load_from="OSname"),
67 | "PHostId": fields.Str(required=False, load_from="PHostId"),
68 | "PHostType": fields.Str(required=False, load_from="PHostType"),
69 | "PMStatus": fields.Str(required=False, load_from="PMStatus"),
70 | "PowerState": fields.Str(required=False, load_from="PowerState"),
71 | "RaidSupported": fields.Str(required=False, load_from="RaidSupported"),
72 | "Remark": fields.Str(required=False, load_from="Remark"),
73 | "SN": fields.Str(required=False, load_from="SN"),
74 | "Tag": fields.Str(required=False, load_from="Tag"),
75 | "Zone": fields.Str(required=False, load_from="Zone"),
76 | }
77 |
78 |
79 | class PHostImageSetSchema(schema.ResponseSchema):
80 | """ PHostImageSet - DescribePHostImage
81 | """
82 |
83 | fields = {
84 | "ImageId": fields.Str(required=False, load_from="ImageId"),
85 | "ImageName": fields.Str(required=False, load_from="ImageName"),
86 | "OsName": fields.Str(required=False, load_from="OsName"),
87 | "OsType": fields.Str(required=False, load_from="OsType"),
88 | }
89 |
90 |
91 | class PHostTagSetSchema(schema.ResponseSchema):
92 | """ PHostTagSet - DescribePHostTags
93 | """
94 |
95 | fields = {
96 | "Tag": fields.Str(required=False, load_from="Tag"),
97 | "TotalCount": fields.Int(required=False, load_from="TotalCount"),
98 | }
99 |
100 |
101 | class PHostPriceSetSchema(schema.ResponseSchema):
102 | """ PHostPriceSet - GetPHostPrice
103 | """
104 |
105 | fields = {
106 | "ChargeType": fields.Str(required=False, load_from="ChargeType"),
107 | "Price": fields.Float(required=False, load_from="Price"),
108 | }
109 |
--------------------------------------------------------------------------------
/ucloud/services/ipsecvpn/client.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | """ Code is generated by ucloud-model, DO NOT EDIT IT. """
4 | from ucloud.core.client import Client
5 | from ucloud.services.ipsecvpn.schemas import apis
6 |
7 |
8 | class IPSecVPNClient(Client):
9 | def __init__(self, config, transport=None, middleware=None, logger=None):
10 | super(IPSecVPNClient, self).__init__(
11 | config, transport, middleware, logger
12 | )
13 |
14 | def describe_remote_vpn_gateway(self, req=None, **kwargs):
15 | """ DescribeRemoteVPNGateway - 获取客户VPN网关信息
16 |
17 | **Request**
18 |
19 | - **ProjectId** (str) - (Config) 项目ID。不填写为默认项目,子帐号必须填写。 请参考 `GetProjectList接口 `_
20 | - **Region** (str) - (Config) 地域。 参见 `地域和可用区列表 `_
21 | - **Limit** (int) - 数据分页值, 默认为20
22 | - **Offset** (int) - 数据偏移量, 默认为0
23 | - **RemoteVPNGatewayIds** (list) - 客户VPN网关的资源ID,例如RemoteVPNGatewayIds.0代表希望获取客户VPN网关1的信息,RemoteVPNGatewayIds.1代表客户VPN网关2,如果为空,则返回当前Region中所有客户VPN网关实例的信息
24 | - **Tag** (str) - 业务组名称,若指定则返回业务组下所有客户VPN网关信息
25 |
26 | **Response**
27 |
28 | - **DataSet** (list) - 见 **RemoteVPNGatewayDataSet** 模型定义
29 | - **TotalCount** (int) - 符合条件的客户VPN网关总数
30 |
31 | **Response Model**
32 |
33 | **RemoteVPNGatewayDataSet**
34 |
35 | - **ActiveTunnels** (str) - 活跃的隧道id
36 | - **CreateTime** (int) - 创建时间
37 | - **Remark** (str) - 备注
38 | - **RemoteVPNGatewayAddr** (str) - 客户网关IP地址
39 | - **RemoteVPNGatewayId** (str) - 客户网关ID
40 | - **RemoteVPNGatewayName** (str) - 客户网关名称
41 | - **Tag** (str) - 用户组
42 | - **TunnelCount** (int) - 活跃的隧道数量
43 |
44 | """
45 | d = {"ProjectId": self.config.project_id, "Region": self.config.region}
46 | req and d.update(req)
47 | d = apis.DescribeRemoteVPNGatewayRequestSchema().dumps(d)
48 | resp = self.invoke("DescribeRemoteVPNGateway", d, **kwargs)
49 | return apis.DescribeRemoteVPNGatewayResponseSchema().loads(resp)
50 |
51 | def describe_vpn_tunnel(self, req=None, **kwargs):
52 | """ DescribeVPNTunnel - 获取VPN隧道信息
53 |
54 | **Request**
55 |
56 | - **ProjectId** (str) - (Config) 项目ID。不填写为默认项目,子帐号必须填写。 请参考 `GetProjectList接口 `_
57 | - **Region** (str) - (Config) 地域。 参见 `地域和可用区列表 `_
58 | - **Limit** (int) - 数据分页值, 默认为20
59 | - **Offset** (int) - 数据偏移量, 默认为0
60 | - **Tag** (str) - 业务组名称,若指定则返回指定的业务组下的所有VPN网关的信息
61 | - **VPNTunnelIds** (list) - VPN隧道的资源ID,例如VPNTunnelIds.0代表希望获取信息的VPN隧道1,VPNTunneIds.1代表VPN隧道2,如果为空,则返回当前Region中所有的VPN隧道实例
62 |
63 | **Response**
64 |
65 | - **DataSet** (list) - 见 **VPNTunnelDataSet** 模型定义
66 | - **TotalCount** (int) - VPN隧道总数
67 |
68 | **Response Model**
69 |
70 | **IPSecData**
71 |
72 | - **IPSecAuthenticationAlgorithm** (str) - IPSec通道中使用的认证算法
73 | - **IPSecEncryptionAlgorithm** (str) - IPSec通道中使用的加密算法
74 | - **IPSecLocalSubnetIds** (list) - 指定VPN连接的本地子网,用逗号分隔
75 | - **IPSecPFSDhGroup** (str) - 是否开启PFS功能,Disable表示关闭,数字表示DH组
76 | - **IPSecProtocol** (str) - 使用的安全协议,ESP或AH
77 | - **IPSecRemoteSubnets** (list) - 指定VPN连接的客户网段,用逗号分隔
78 | - **IPSecSALifetime** (str) - IPSec中SA的生存时间
79 | - **IPSecSALifetimeBytes** (str) - IPSec中SA的生存时间(以字节计)
80 |
81 | **IKEData**
82 |
83 | - **IKEAuthenticationAlgorithm** (str) - IKE认证算法
84 | - **IKEDhGroup** (str) - IKEDH组
85 | - **IKEEncryptionAlgorithm** (str) - IKE加密算法
86 | - **IKEExchangeMode** (str) - IKEv1协商模式
87 | - **IKELocalId** (str) - IKE本地ID标识
88 | - **IKEPreSharedKey** (str) - IKE预共享秘钥
89 | - **IKERemoteId** (str) - IKE对端ID标识
90 | - **IKESALifetime** (str) - IKE秘钥生存时间
91 | - **IKEVersion** (str) - IKE版本
92 |
93 | **VPNTunnelDataSet**
94 |
95 | - **CreateTime** (int) - 创建时间
96 | - **IKEData** (dict) - 见 **IKEData** 模型定义
97 | - **IPSecData** (dict) - 见 **IPSecData** 模型定义
98 | - **Remark** (str) - 备注
99 | - **RemoteVPNGatewayId** (str) - 对端网关Id
100 | - **RemoteVPNGatewayName** (str) - 对端网关名字
101 | - **Tag** (str) - 用户组
102 | - **VPCId** (str) - 所属VPCId
103 | - **VPCName** (str) - 所属VOC名字
104 | - **VPNGatewayId** (str) - 所属VPN网关id
105 | - **VPNGatewayName** (str) - VPN网关名字
106 | - **VPNTunnelId** (str) - 隧道id
107 | - **VPNTunnelName** (str) - 隧道名称
108 |
109 | """
110 | d = {"ProjectId": self.config.project_id, "Region": self.config.region}
111 | req and d.update(req)
112 | d = apis.DescribeVPNTunnelRequestSchema().dumps(d)
113 | resp = self.invoke("DescribeVPNTunnel", d, **kwargs)
114 | return apis.DescribeVPNTunnelResponseSchema().loads(resp)
115 |
--------------------------------------------------------------------------------
/tests/test_services/test_set_1202.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | """ Code is generated by ucloud-model, DO NOT EDIT IT. """
4 | import pytest
5 | import logging
6 | from ucloud.core import exc
7 | from ucloud.testing import env, funcs, op, utest
8 |
9 | logger = logging.getLogger(__name__)
10 | scenario = utest.Scenario(1202)
11 |
12 |
13 | @pytest.mark.skipif(env.is_ut(), reason=env.get_skip_reason())
14 | def test_set_1202(client, variables):
15 | scenario.initial(variables)
16 | scenario.variables["Protocol"] = "memcache"
17 | scenario.variables["ResourceType"] = "distributed"
18 | scenario.variables["Name"] = "distributed_memcache"
19 | scenario.run(client)
20 |
21 |
22 | @scenario.step(
23 | max_retries=0,
24 | retry_interval=0,
25 | startup_delay=0,
26 | fast_fail=False,
27 | validators=lambda variables: [("str_eq", "RetCode", 0)],
28 | action="CreateUMemSpace",
29 | )
30 | def create_umem_space_00(client, variables):
31 | d = {
32 | "Zone": variables.get("Zone"),
33 | "Size": 8,
34 | "Region": variables.get("Region"),
35 | "Quantity": 1,
36 | "Protocol": variables.get("Protocol"),
37 | "Name": variables.get("Name"),
38 | "ChargeType": "Month",
39 | }
40 | try:
41 | resp = client.umem().create_umem_space(d)
42 | except exc.RetCodeException as e:
43 | resp = e.json()
44 | variables["Space_Id"] = utest.value_at_path(resp, "SpaceId")
45 | return resp
46 |
47 |
48 | @scenario.step(
49 | max_retries=30,
50 | retry_interval=10,
51 | startup_delay=3,
52 | fast_fail=False,
53 | validators=lambda variables: [
54 | ("str_eq", "RetCode", 0),
55 | ("str_eq", "DataSet.0.State", "Running"),
56 | ],
57 | action="DescribeUMem",
58 | )
59 | def describe_umem_01(client, variables):
60 | d = {
61 | "ResourceId": variables.get("Space_Id"),
62 | "Region": variables.get("Region"),
63 | "Protocol": variables.get("Protocol"),
64 | "Offset": 0,
65 | "Limit": 1000,
66 | }
67 | try:
68 | resp = client.invoke("DescribeUMem", d)
69 | except exc.RetCodeException as e:
70 | resp = e.json()
71 | return resp
72 |
73 |
74 | @scenario.step(
75 | max_retries=0,
76 | retry_interval=0,
77 | startup_delay=0,
78 | fast_fail=False,
79 | validators=lambda variables: [("str_eq", "RetCode", 0)],
80 | action="ResizeUMemSpace",
81 | )
82 | def resize_umem_space_02(client, variables):
83 | d = {
84 | "Zone": variables.get("Zone"),
85 | "SpaceId": variables.get("Space_Id"),
86 | "Size": 14,
87 | "Region": variables.get("Region"),
88 | }
89 | try:
90 | resp = client.umem().resize_umem_space(d)
91 | except exc.RetCodeException as e:
92 | resp = e.json()
93 | return resp
94 |
95 |
96 | @scenario.step(
97 | max_retries=30,
98 | retry_interval=10,
99 | startup_delay=3,
100 | fast_fail=False,
101 | validators=lambda variables: [
102 | ("str_eq", "RetCode", 0),
103 | ("str_eq", "DataSet.0.State", "Running"),
104 | ],
105 | action="DescribeUMem",
106 | )
107 | def describe_umem_03(client, variables):
108 | d = {
109 | "ResourceId": variables.get("Space_Id"),
110 | "Region": variables.get("Region"),
111 | "Protocol": variables.get("Protocol"),
112 | "Offset": 0,
113 | "Limit": 1000,
114 | }
115 | try:
116 | resp = client.invoke("DescribeUMem", d)
117 | except exc.RetCodeException as e:
118 | resp = e.json()
119 | return resp
120 |
121 |
122 | @scenario.step(
123 | max_retries=0,
124 | retry_interval=0,
125 | startup_delay=0,
126 | fast_fail=False,
127 | validators=lambda variables: [("str_eq", "RetCode", 0)],
128 | action="DeleteUMem",
129 | )
130 | def delete_umem_04(client, variables):
131 | d = {
132 | "Zone": variables.get("Zone"),
133 | "ResourceType": variables.get("ResourceType"),
134 | "ResourceId": variables.get("Space_Id"),
135 | "Region": variables.get("Region"),
136 | }
137 | try:
138 | resp = client.invoke("DeleteUMem", d)
139 | except exc.RetCodeException as e:
140 | resp = e.json()
141 | return resp
142 |
143 |
144 | @scenario.step(
145 | max_retries=3,
146 | retry_interval=1,
147 | startup_delay=0,
148 | fast_fail=False,
149 | validators=lambda variables: [
150 | ("str_eq", "RetCode", 0),
151 | ("str_eq", "Action", "DescribeUMemSpaceResponse"),
152 | ("object_not_contains", "DataSet", variables.get("Space_Id")),
153 | ],
154 | action="DescribeUMemSpace",
155 | )
156 | def describe_umem_space_05(client, variables):
157 | d = {
158 | "Zone": variables.get("Zone"),
159 | "SpaceId": variables.get("Space_Id"),
160 | "Region": variables.get("Region"),
161 | "Offset": 0,
162 | "Limit": 100,
163 | }
164 | try:
165 | resp = client.umem().describe_umem_space(d)
166 | except exc.RetCodeException as e:
167 | resp = e.json()
168 | return resp
169 |
--------------------------------------------------------------------------------
/ucloud/testing/op.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | import re
4 | from ucloud.testing.exc import CompareError
5 |
6 |
7 | def eq(value, expected):
8 | """ value is equal to expected
9 | """
10 | assert value == expected
11 |
12 |
13 | def ne(value, expected):
14 | """ value is equal to expected
15 | """
16 | assert value != expected
17 |
18 |
19 | def gt(value, expected):
20 | """ value is greater than expected
21 | """
22 | assert float(value) > float(expected)
23 |
24 |
25 | def ge(value, expected):
26 | """ value is greater than or equal to expected
27 | """
28 | assert float(value) >= float(expected)
29 |
30 |
31 | def abs_eq(value, expected):
32 | """ value is approx equal to expected
33 | """
34 | assert round(float(value), 2) == round(float(expected), 2)
35 |
36 |
37 | def lt(value, expected):
38 | """ value is less than excepted
39 | """
40 | assert float(value) < float(expected)
41 |
42 |
43 | def le(value, expected):
44 | """ value is less than or equal to excepted
45 | """
46 | assert float(value) <= float(expected)
47 |
48 |
49 | def str_eq(value, expected):
50 | """ value is equal to excepted as string
51 | """
52 | assert str(value) == str(expected)
53 |
54 |
55 | def float_eq(value, expected):
56 | """ value is equal to excepted as float
57 | """
58 | assert round(float(value), 2) == round(float(expected), 2)
59 |
60 |
61 | def len_eq(value, expected):
62 | """ length of value is equal to excepted
63 | """
64 | assert isinstance(expected, int)
65 | assert len(value) == expected
66 |
67 |
68 | def len_gt(value, expected):
69 | """ length of value is greater than excepted
70 | """
71 | assert isinstance(expected, int)
72 | assert len(value) > expected
73 |
74 |
75 | def len_ge(value, expected):
76 | """ length of value is greater than or equal to excepted
77 | """
78 | assert isinstance(expected, int)
79 | assert len(value) >= expected
80 |
81 |
82 | def len_lt(value, expected):
83 | """ length of value is less than excepted
84 | """
85 | assert isinstance(expected, int)
86 | assert len(value) < expected
87 |
88 |
89 | def len_le(value, expected):
90 | """ length of value is less than or equal to excepted
91 | """
92 | assert isinstance(expected, int)
93 | assert len(value) <= expected
94 |
95 |
96 | def contains(value, expected):
97 | """ value is contains expected
98 | """
99 | assert expected in value
100 |
101 |
102 | def contained_by(value, expected):
103 | """ value is contained by expected
104 | """
105 | assert value in expected
106 |
107 |
108 | def type_eq(value, expected):
109 | assert isinstance(value, expected)
110 |
111 |
112 | def regex(value, expected):
113 | assert isinstance(expected, str)
114 | assert isinstance(value, str)
115 | assert re.match(expected, value)
116 |
117 |
118 | def startswith(value, expected):
119 | assert str(value).startswith(expected)
120 |
121 |
122 | def endswith(value, expected):
123 | assert str(value).endswith(expected)
124 |
125 |
126 | def object_contains(value, expected):
127 | assert str(expected) in str(value)
128 |
129 |
130 | def object_not_contains(value, expected):
131 | assert str(expected) not in str(value)
132 |
133 |
134 | mapper = {
135 | "eq": eq,
136 | "equals": eq,
137 | "==": eq,
138 | "abs_eq": abs_eq,
139 | "abs_equals": abs_eq,
140 | "lt": lt,
141 | "less_than": lt,
142 | "le": le,
143 | "less_than_or_equals": le,
144 | "gt": gt,
145 | "greater_than": gt,
146 | "ge": ge,
147 | "greater_than_or_equals": ge,
148 | "ne": ne,
149 | "not_equals": ne,
150 | "str_eq": str_eq,
151 | "string_equals": str_eq,
152 | "float_eq": float_eq,
153 | "float_equals": float_eq,
154 | "len_eq": len_eq,
155 | "length_equals": len_eq,
156 | "count_eq": len_eq,
157 | "len_gt": len_gt,
158 | "count_gt": len_gt,
159 | "length_greater_than": len_gt,
160 | "count_greater_than": len_gt,
161 | "len_ge": len_ge,
162 | "count_ge": len_ge,
163 | "length_greater_than_or_equals": len_ge,
164 | "count_greater_than_or_equals": len_ge,
165 | "len_lt": len_lt,
166 | "count_lt": len_lt,
167 | "length_less_than": len_lt,
168 | "count_less_than": len_lt,
169 | "len_le": len_le,
170 | "count_le": len_le,
171 | "length_less_than_or_equals": len_le,
172 | "count_less_than_or_equals": len_le,
173 | "contains": contains,
174 | "contained_by": contained_by,
175 | "type": type_eq,
176 | "regex": regex,
177 | "startswith": startswith,
178 | "endswith": endswith,
179 | "object_contains": object_contains,
180 | "object_not_contains": object_not_contains,
181 | }
182 |
183 |
184 | def check(name, value, expected):
185 | if name not in mapper:
186 | raise CompareError("comparator {} is not found".format(name))
187 | try:
188 | return mapper.get(name)(value, expected)
189 | except AssertionError as e:
190 | msg = "assert error, expect {} {} {}, got error {}".format(
191 | value, name, expected, e
192 | )
193 | raise CompareError(msg)
194 |
--------------------------------------------------------------------------------
/ucloud/services/pathx/schemas/apis.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | """ Code is generated by ucloud-model, DO NOT EDIT IT. """
4 | from ucloud.core.typesystem import schema, fields
5 | from ucloud.services.pathx.schemas import models
6 |
7 | """ PathX API Schema
8 | """
9 | """
10 | API: CreateGlobalSSHInstance
11 |
12 | 创建GlobalSSH实例
13 | """
14 |
15 |
16 | class CreateGlobalSSHInstanceRequestSchema(schema.RequestSchema):
17 | """ CreateGlobalSSHInstance - 创建GlobalSSH实例
18 | """
19 |
20 | fields = {
21 | "Area": fields.Str(required=True, dump_to="Area"),
22 | "AreaCode": fields.Str(required=True, dump_to="AreaCode"),
23 | "ChargeType": fields.Str(required=False, dump_to="ChargeType"),
24 | "CouponId": fields.Str(required=False, dump_to="CouponId"),
25 | "Port": fields.Int(required=True, dump_to="Port"),
26 | "ProjectId": fields.Str(required=True, dump_to="ProjectId"),
27 | "Quantity": fields.Int(required=False, dump_to="Quantity"),
28 | "Remark": fields.Str(required=False, dump_to="Remark"),
29 | "TargetIP": fields.Str(required=True, dump_to="TargetIP"),
30 | }
31 |
32 |
33 | class CreateGlobalSSHInstanceResponseSchema(schema.ResponseSchema):
34 | """ CreateGlobalSSHInstance - 创建GlobalSSH实例
35 | """
36 |
37 | fields = {
38 | "AcceleratingDomain": fields.Str(
39 | required=False, load_from="AcceleratingDomain"
40 | ),
41 | "InstanceId": fields.Str(required=True, load_from="InstanceId"),
42 | "Message": fields.Str(required=False, load_from="Message"),
43 | }
44 |
45 |
46 | """
47 | API: DeleteGlobalSSHInstance
48 |
49 | 删除GlobalSSH实例
50 | """
51 |
52 |
53 | class DeleteGlobalSSHInstanceRequestSchema(schema.RequestSchema):
54 | """ DeleteGlobalSSHInstance - 删除GlobalSSH实例
55 | """
56 |
57 | fields = {
58 | "InstanceId": fields.Str(required=True, dump_to="InstanceId"),
59 | "ProjectId": fields.Str(required=True, dump_to="ProjectId"),
60 | }
61 |
62 |
63 | class DeleteGlobalSSHInstanceResponseSchema(schema.ResponseSchema):
64 | """ DeleteGlobalSSHInstance - 删除GlobalSSH实例
65 | """
66 |
67 | fields = {"Message": fields.Str(required=False, load_from="Message")}
68 |
69 |
70 | """
71 | API: DescribeGlobalSSHArea
72 |
73 | 获取GlobalSSH覆盖的地区列表 用于控制显示哪些机房地域可以使用SSH特性
74 | """
75 |
76 |
77 | class DescribeGlobalSSHAreaRequestSchema(schema.RequestSchema):
78 | """ DescribeGlobalSSHArea - 获取GlobalSSH覆盖的地区列表 用于控制显示哪些机房地域可以使用SSH特性
79 | """
80 |
81 | fields = {
82 | "ProjectId": fields.Str(required=False, dump_to="ProjectId"),
83 | "Region": fields.Str(required=False, dump_to="Region"),
84 | }
85 |
86 |
87 | class DescribeGlobalSSHAreaResponseSchema(schema.ResponseSchema):
88 | """ DescribeGlobalSSHArea - 获取GlobalSSH覆盖的地区列表 用于控制显示哪些机房地域可以使用SSH特性
89 | """
90 |
91 | fields = {
92 | "AreaSet": fields.List(
93 | models.GlobalSSHAreaSchema(), required=False, load_from="AreaSet"
94 | ),
95 | "Message": fields.Str(required=False, load_from="Message"),
96 | }
97 |
98 |
99 | """
100 | API: DescribeGlobalSSHInstance
101 |
102 | 获取GlobalSSH实例列表(传实例ID获取单个实例信息,不传获取项目下全部实例)
103 | """
104 |
105 |
106 | class DescribeGlobalSSHInstanceRequestSchema(schema.RequestSchema):
107 | """ DescribeGlobalSSHInstance - 获取GlobalSSH实例列表(传实例ID获取单个实例信息,不传获取项目下全部实例)
108 | """
109 |
110 | fields = {
111 | "InstanceId": fields.Str(required=False, dump_to="InstanceId"),
112 | "ProjectId": fields.Str(required=True, dump_to="ProjectId"),
113 | }
114 |
115 |
116 | class DescribeGlobalSSHInstanceResponseSchema(schema.ResponseSchema):
117 | """ DescribeGlobalSSHInstance - 获取GlobalSSH实例列表(传实例ID获取单个实例信息,不传获取项目下全部实例)
118 | """
119 |
120 | fields = {
121 | "InstanceSet": fields.List(
122 | models.GlobalSSHInfoSchema(),
123 | required=False,
124 | load_from="InstanceSet",
125 | )
126 | }
127 |
128 |
129 | """
130 | API: ModifyGlobalSSHPort
131 |
132 | 修改GlobalSSH端口
133 | """
134 |
135 |
136 | class ModifyGlobalSSHPortRequestSchema(schema.RequestSchema):
137 | """ ModifyGlobalSSHPort - 修改GlobalSSH端口
138 | """
139 |
140 | fields = {
141 | "InstanceId": fields.Str(required=True, dump_to="InstanceId"),
142 | "Port": fields.Int(required=True, dump_to="Port"),
143 | "ProjectId": fields.Str(required=True, dump_to="ProjectId"),
144 | }
145 |
146 |
147 | class ModifyGlobalSSHPortResponseSchema(schema.ResponseSchema):
148 | """ ModifyGlobalSSHPort - 修改GlobalSSH端口
149 | """
150 |
151 | fields = {"Message": fields.Str(required=False, load_from="Message")}
152 |
153 |
154 | """
155 | API: ModifyGlobalSSHRemark
156 |
157 | 修改GlobalSSH备注
158 | """
159 |
160 |
161 | class ModifyGlobalSSHRemarkRequestSchema(schema.RequestSchema):
162 | """ ModifyGlobalSSHRemark - 修改GlobalSSH备注
163 | """
164 |
165 | fields = {
166 | "InstanceId": fields.Str(required=True, dump_to="InstanceId"),
167 | "ProjectId": fields.Str(required=True, dump_to="ProjectId"),
168 | "Remark": fields.Str(required=False, dump_to="Remark"),
169 | }
170 |
171 |
172 | class ModifyGlobalSSHRemarkResponseSchema(schema.ResponseSchema):
173 | """ ModifyGlobalSSHRemark - 修改GlobalSSH备注
174 | """
175 |
176 | fields = {"Message": fields.Str(required=False, load_from="Message")}
177 |
--------------------------------------------------------------------------------
/ucloud/services/vpc/schemas/models.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | """ Code is generated by ucloud-model, DO NOT EDIT IT. """
4 | from ucloud.core.typesystem import schema, fields
5 |
6 |
7 | class RouteRuleInfoSchema(schema.ResponseSchema):
8 | """ RouteRuleInfo - 路由规则信息
9 | """
10 |
11 | fields = {
12 | "DstAddr": fields.Str(required=False, load_from="DstAddr"),
13 | "NexthopId": fields.Str(required=False, load_from="NexthopId"),
14 | "NexthopType": fields.Str(required=False, load_from="NexthopType"),
15 | "Remark": fields.Str(required=False, load_from="Remark"),
16 | "RouteRuleId": fields.Str(required=False, load_from="RouteRuleId"),
17 | "RuleType": fields.Int(required=False, load_from="RuleType"),
18 | }
19 |
20 |
21 | class RouteTableInfoSchema(schema.ResponseSchema):
22 | """ RouteTableInfo - 路由表信息
23 | """
24 |
25 | fields = {
26 | "CreateTime": fields.Int(required=False, load_from="CreateTime"),
27 | "Remark": fields.Str(required=False, load_from="Remark"),
28 | "RouteRules": fields.List(RouteRuleInfoSchema()),
29 | "RouteTableId": fields.Str(required=False, load_from="RouteTableId"),
30 | "RouteTableType": fields.Int(
31 | required=False, load_from="RouteTableType"
32 | ),
33 | "SubnetCount": fields.Str(required=False, load_from="SubnetCount"),
34 | "Tag": fields.Str(required=False, load_from="Tag"),
35 | "VPCId": fields.Str(required=False, load_from="VPCId"),
36 | "VPCName": fields.Str(required=False, load_from="VPCName"),
37 | }
38 |
39 |
40 | class SubnetInfoSchema(schema.ResponseSchema):
41 | """ SubnetInfo - 子网信息
42 | """
43 |
44 | fields = {
45 | "AvailableIPs": fields.Int(required=False, load_from="AvailableIPs"),
46 | "CreateTime": fields.Int(required=False, load_from="CreateTime"),
47 | "Gateway": fields.Str(required=False, load_from="Gateway"),
48 | "HasNATGW": fields.Bool(required=False, load_from="HasNATGW"),
49 | "IPv6Network": fields.Str(required=False, load_from="IPv6Network"),
50 | "Netmask": fields.Str(required=False, load_from="Netmask"),
51 | "Remark": fields.Str(required=False, load_from="Remark"),
52 | "RouteTableId": fields.Str(required=False, load_from="RouteTableId"),
53 | "Subnet": fields.Str(required=False, load_from="Subnet"),
54 | "SubnetId": fields.Str(required=False, load_from="SubnetId"),
55 | "SubnetName": fields.Str(required=False, load_from="SubnetName"),
56 | "SubnetType": fields.Int(required=False, load_from="SubnetType"),
57 | "Tag": fields.Str(required=False, load_from="Tag"),
58 | "VPCId": fields.Str(required=False, load_from="VPCId"),
59 | "VPCName": fields.Str(required=False, load_from="VPCName"),
60 | "Zone": fields.Str(required=False, load_from="Zone"),
61 | }
62 |
63 |
64 | class SubnetResourceSchema(schema.ResponseSchema):
65 | """ SubnetResource - 子网下资源
66 | """
67 |
68 | fields = {
69 | "IP": fields.Str(required=False, load_from="IP"),
70 | "IPv6Address": fields.Str(required=False, load_from="IPv6Address"),
71 | "Name": fields.Str(required=False, load_from="Name"),
72 | "ResourceId": fields.Str(required=False, load_from="ResourceId"),
73 | "ResourceType": fields.Str(required=False, load_from="ResourceType"),
74 | "SubResourceId": fields.Str(required=False, load_from="SubResourceId"),
75 | "SubResourceName": fields.Str(
76 | required=False, load_from="SubResourceName"
77 | ),
78 | "SubResourceType": fields.Str(
79 | required=False, load_from="SubResourceType"
80 | ),
81 | }
82 |
83 |
84 | class VPCNetworkInfoSchema(schema.ResponseSchema):
85 | """ VPCNetworkInfo - vpc地址空间信息
86 | """
87 |
88 | fields = {
89 | "Network": fields.Str(required=False, load_from="Network"),
90 | "SubnetCount": fields.Int(required=False, load_from="SubnetCount"),
91 | }
92 |
93 |
94 | class VPCInfoSchema(schema.ResponseSchema):
95 | """ VPCInfo - VPC信息
96 | """
97 |
98 | fields = {
99 | "CreateTime": fields.Int(required=True, load_from="CreateTime"),
100 | "IPv6Network": fields.Str(required=False, load_from="IPv6Network"),
101 | "Name": fields.Str(required=True, load_from="Name"),
102 | "Network": fields.List(fields.Str()),
103 | "NetworkInfo": fields.List(VPCNetworkInfoSchema()),
104 | "OperatorName": fields.Str(required=False, load_from="OperatorName"),
105 | "SubnetCount": fields.Int(required=True, load_from="SubnetCount"),
106 | "Tag": fields.Str(required=True, load_from="Tag"),
107 | "UpdateTime": fields.Int(required=True, load_from="UpdateTime"),
108 | "VPCId": fields.Str(required=False, load_from="VPCId"),
109 | }
110 |
111 |
112 | class VPCIntercomInfoSchema(schema.ResponseSchema):
113 | """ VPCIntercomInfo -
114 | """
115 |
116 | fields = {
117 | "DstRegion": fields.Str(required=False, load_from="DstRegion"),
118 | "Name": fields.Str(required=False, load_from="Name"),
119 | "Network": fields.List(fields.Str()),
120 | "ProjectId": fields.Str(required=False, load_from="ProjectId"),
121 | "Tag": fields.Str(required=False, load_from="Tag"),
122 | "VPCId": fields.Str(required=False, load_from="VPCId"),
123 | }
124 |
--------------------------------------------------------------------------------
/ucloud/core/client/_client.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | import logging
4 | import sys
5 | from ucloud import version
6 | from ucloud.core.client._cfg import Config
7 | from ucloud.core.transport import (
8 | Transport,
9 | RequestsTransport,
10 | Request,
11 | SSLOption,
12 | )
13 | from ucloud.core.typesystem import encoder
14 | from ucloud.core.utils import log
15 | from ucloud.core.utils.middleware import Middleware
16 | from ucloud.core import auth, exc
17 |
18 | default_transport = RequestsTransport()
19 |
20 |
21 | class Client(object):
22 | def __init__(self, config, transport=None, middleware=None, logger=None):
23 | cfg, cred = self._parse_dict_config(config)
24 | self.config = cfg
25 | self.credential = cred
26 | self.transport = transport or default_transport
27 | self.logger = logger or log.default_logger
28 | if middleware is None:
29 | middleware = Middleware()
30 | middleware.response(self.logged_response_handler)
31 | middleware.request(self.logged_request_handler)
32 | self._middleware = middleware
33 |
34 | def invoke(self, action, args=None, **options):
35 | """ invoke will invoke the action with arguments data and options
36 |
37 | :param str action: the api action, like `CreateUHostInstance`
38 | :param dict args: arguments of api(action), see doc: `UCloud API Documentation `__
39 | :return:
40 | """
41 | retries = 0
42 | max_retries = options.get("max_retries") or self.config.max_retries
43 | while retries <= max_retries:
44 | try:
45 | return self._send(action, args or {}, **options)
46 | except exc.UCloudException as e:
47 | for handler in self.middleware.exception_handlers:
48 | handler(e)
49 | if e.retryable and retries != max_retries:
50 | logging.info(
51 | "Retrying {action}: {args}".format(
52 | action=action, args=args
53 | )
54 | )
55 | retries += 1
56 | continue
57 | raise e
58 | except Exception as e:
59 | for handler in self.middleware.exception_handlers:
60 | handler(e)
61 | raise e
62 |
63 | @property
64 | def middleware(self):
65 | return self._middleware
66 |
67 | def logged_request_handler(self, req):
68 | self.logger.info("[request] {} {}".format(req.get("Action", ""), req))
69 | return req
70 |
71 | def logged_response_handler(self, resp):
72 | self.logger.info(
73 | "[response] {} {}".format(resp.get("Action", ""), resp)
74 | )
75 | return resp
76 |
77 | @staticmethod
78 | def _parse_dict_config(config):
79 | return Config.from_dict(config), auth.Credential.from_dict(config)
80 |
81 | def _send(self, action, args, **options):
82 | args["Action"] = action
83 | for handler in self.middleware.request_handlers:
84 | args = handler(args)
85 | req = self._build_http_request(args)
86 | max_retries = options.get("max_retries") or self.config.max_retries
87 | timeout = options.get("timeout") or self.config.timeout
88 | resp = self.transport.send(
89 | req,
90 | ssl_option=SSLOption(
91 | self.config.ssl_verify,
92 | self.config.ssl_cacert,
93 | self.config.ssl_cert,
94 | self.config.ssl_key,
95 | ),
96 | timeout=timeout,
97 | max_retries=max_retries,
98 | ).json()
99 | for handler in self.middleware.response_handlers:
100 | resp = handler(resp)
101 | if int(resp.get("RetCode", -1)) != 0:
102 | raise exc.RetCodeException(
103 | action=req.data.get("Action"),
104 | code=int(resp.get("RetCode")),
105 | message=resp.get("Message"),
106 | )
107 | return resp
108 |
109 | def _build_http_request(self, args):
110 | config = {
111 | "Region": self.config.region,
112 | "ProjectId": self.config.project_id,
113 | }
114 | payload = {k: v for k, v in config.items() if v is not None}
115 | payload.update({k: v for k, v in args.items() if v is not None})
116 | payload = encoder.encode(payload)
117 | payload["Signature"] = self.credential.verify_ac(payload)
118 | return Request(
119 | url=self.config.base_url,
120 | method="post",
121 | data=payload,
122 | headers={
123 | "User-Agent": self._build_user_agent(),
124 | "Content-Type": "application/x-www-form-urlencoded",
125 | },
126 | )
127 |
128 | def _build_user_agent(self):
129 | python_version = "{v[0]}.{v[1]}.{v[2]}".format(v=sys.version_info)
130 | user_agent = "Python/{python_version} Python-SDK/{sdk_version}".format(
131 | python_version=python_version, sdk_version=version.version
132 | ) + (self.config.user_agent or "")
133 | return user_agent
134 |
135 | def __repr__(self):
136 | return '<{}(region="{}")>'.format(
137 | self.__class__.__name__, self.config.region
138 | )
139 |
--------------------------------------------------------------------------------
/ucloud/services/uaccount/client.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | """ Code is generated by ucloud-model, DO NOT EDIT IT. """
4 | from ucloud.core.client import Client
5 | from ucloud.services.uaccount.schemas import apis
6 |
7 |
8 | class UAccountClient(Client):
9 | def __init__(self, config, transport=None, middleware=None, logger=None):
10 | super(UAccountClient, self).__init__(
11 | config, transport, middleware, logger
12 | )
13 |
14 | def create_project(self, req=None, **kwargs):
15 | """ CreateProject - 创建项目
16 |
17 | **Request**
18 |
19 | - **ProjectName** (str) - (Required) 项目名称
20 |
21 | **Response**
22 |
23 | - **ProjectId** (str) - 所创建项目的Id
24 |
25 | """
26 | d = {}
27 | req and d.update(req)
28 | d = apis.CreateProjectRequestSchema().dumps(d)
29 | kwargs["max_retries"] = 0
30 | resp = self.invoke("CreateProject", d, **kwargs)
31 | return apis.CreateProjectResponseSchema().loads(resp)
32 |
33 | def get_project_list(self, req=None, **kwargs):
34 | """ GetProjectList - 获取项目列表
35 |
36 | **Request**
37 |
38 | - **IsFinance** (str) - 是否是财务账号
39 |
40 | **Response**
41 |
42 | - **ProjectCount** (int) - 项目总数
43 | - **ProjectSet** (list) - 见 **ProjectListInfo** 模型定义
44 |
45 | **Response Model**
46 |
47 | **ProjectListInfo**
48 |
49 | - **CreateTime** (int) - 创建时间(Unix时间戳)
50 | - **IsDefault** (bool) - 是否为默认项目
51 | - **MemberCount** (int) - 项目下成员数量
52 | - **ParentId** (str) - 父项目ID
53 | - **ParentName** (str) - 父项目名称
54 | - **ProjectId** (str) - 项目ID
55 | - **ProjectName** (str) - 项目名称
56 | - **ResourceCount** (int) - 项目下资源数量
57 |
58 | """
59 | d = {}
60 | req and d.update(req)
61 | d = apis.GetProjectListRequestSchema().dumps(d)
62 | resp = self.invoke("GetProjectList", d, **kwargs)
63 | return apis.GetProjectListResponseSchema().loads(resp)
64 |
65 | def get_region(self, req=None, **kwargs):
66 | """ GetRegion - 获取用户在各数据中心的权限等信息
67 |
68 | **Request**
69 |
70 |
71 | **Response**
72 |
73 | - **Regions** (list) - 见 **RegionInfo** 模型定义
74 |
75 | **Response Model**
76 |
77 | **RegionInfo**
78 |
79 | - **BitMaps** (str) - 用户在此数据中心的权限位
80 | - **IsDefault** (bool) - 是否用户当前默认数据中心
81 | - **Region** (str) - 地域名字,如cn-bj
82 | - **RegionId** (int) - 数据中心ID
83 | - **RegionName** (str) - 数据中心名称
84 | - **Zone** (str) - 可用区名字,如cn-bj-01
85 |
86 | """
87 | d = {}
88 | req and d.update(req)
89 | d = apis.GetRegionRequestSchema().dumps(d)
90 | resp = self.invoke("GetRegion", d, **kwargs)
91 | return apis.GetRegionResponseSchema().loads(resp)
92 |
93 | def get_user_info(self, req=None, **kwargs):
94 | """ GetUserInfo - 获取用户信息
95 |
96 | **Request**
97 |
98 |
99 | **Response**
100 |
101 | - **DataSet** (list) - 见 **UserInfo** 模型定义
102 |
103 | **Response Model**
104 |
105 | **UserInfo**
106 |
107 | - **Admin** (int) - 是否超级管理员 0:否 1:是
108 | - **Administrator** (str) - 管理员
109 | - **AuthState** (str) - 实名认证状态
110 | - **City** (str) - 城市
111 | - **CompanyName** (str) - 公司名称
112 | - **Finance** (int) - 是否有财务权限 0:否 1:是
113 | - **IndustryType** (int) - 所属行业
114 | - **PhonePrefix** (str) - 国际号码前缀
115 | - **Province** (str) - 省份
116 | - **UserAddress** (str) - 公司地址
117 | - **UserEmail** (str) - 用户邮箱
118 | - **UserId** (int) - 用户Id
119 | - **UserName** (str) - 称呼
120 | - **UserPhone** (str) - 用户手机
121 | - **UserType** (int) - 会员类型
122 | - **UserVersion** (int) - 是否子帐户(大于100为子帐户)
123 |
124 | """
125 | d = {}
126 | req and d.update(req)
127 | d = apis.GetUserInfoRequestSchema().dumps(d)
128 | resp = self.invoke("GetUserInfo", d, **kwargs)
129 | return apis.GetUserInfoResponseSchema().loads(resp)
130 |
131 | def modify_project(self, req=None, **kwargs):
132 | """ ModifyProject - 修改项目
133 |
134 | **Request**
135 |
136 | - **ProjectId** (str) - (Config) 项目ID。不填写为默认项目,子帐号必须填写。 请参考 `GetProjectList接口 `_
137 | - **ProjectName** (str) - (Required) 新的项目名称
138 |
139 | **Response**
140 |
141 |
142 | """
143 | d = {"ProjectId": self.config.project_id}
144 | req and d.update(req)
145 | d = apis.ModifyProjectRequestSchema().dumps(d)
146 | resp = self.invoke("ModifyProject", d, **kwargs)
147 | return apis.ModifyProjectResponseSchema().loads(resp)
148 |
149 | def terminate_project(self, req=None, **kwargs):
150 | """ TerminateProject - 删除项目
151 |
152 | **Request**
153 |
154 | - **ProjectId** (str) - (Config) 项目ID,不填写为默认项目,子帐号必须填写。
155 |
156 | **Response**
157 |
158 |
159 | """
160 | d = {"ProjectId": self.config.project_id}
161 | req and d.update(req)
162 | d = apis.TerminateProjectRequestSchema().dumps(d)
163 | resp = self.invoke("TerminateProject", d, **kwargs)
164 | return apis.TerminateProjectResponseSchema().loads(resp)
165 |
--------------------------------------------------------------------------------
/ucloud/services/uhub/schemas/apis.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | """ Code is generated by ucloud-model, DO NOT EDIT IT. """
4 | from ucloud.core.typesystem import schema, fields
5 | from ucloud.services.uhub.schemas import models
6 |
7 | """ UHub API Schema
8 | """
9 | """
10 | API: CreateRepo
11 |
12 | 创建镜像仓库
13 | """
14 |
15 |
16 | class CreateRepoRequestSchema(schema.RequestSchema):
17 | """ CreateRepo - 创建镜像仓库
18 | """
19 |
20 | fields = {
21 | "Description": fields.Str(required=False, dump_to="Description"),
22 | "IsShared": fields.Bool(required=False, dump_to="IsShared"),
23 | "ProjectId": fields.Str(required=False, dump_to="ProjectId"),
24 | "RepoName": fields.Str(required=True, dump_to="RepoName"),
25 | }
26 |
27 |
28 | class CreateRepoResponseSchema(schema.ResponseSchema):
29 | """ CreateRepo - 创建镜像仓库
30 | """
31 |
32 | fields = {"Message": fields.Str(required=False, load_from="Message")}
33 |
34 |
35 | """
36 | API: DeleteRepo
37 |
38 | 删除镜像仓库
39 | """
40 |
41 |
42 | class DeleteRepoRequestSchema(schema.RequestSchema):
43 | """ DeleteRepo - 删除镜像仓库
44 | """
45 |
46 | fields = {
47 | "ProjectId": fields.Str(required=False, dump_to="ProjectId"),
48 | "RepoName": fields.Str(required=True, dump_to="RepoName"),
49 | }
50 |
51 |
52 | class DeleteRepoResponseSchema(schema.ResponseSchema):
53 | """ DeleteRepo - 删除镜像仓库
54 | """
55 |
56 | fields = {}
57 |
58 |
59 | """
60 | API: DeleteRepoImage
61 |
62 | 删除镜像
63 | """
64 |
65 |
66 | class DeleteRepoImageRequestSchema(schema.RequestSchema):
67 | """ DeleteRepoImage - 删除镜像
68 | """
69 |
70 | fields = {
71 | "ImageName": fields.Str(required=True, dump_to="ImageName"),
72 | "ProjectId": fields.Str(required=False, dump_to="ProjectId"),
73 | "RepoName": fields.Str(required=True, dump_to="RepoName"),
74 | "TagName": fields.Str(required=False, dump_to="TagName"),
75 | }
76 |
77 |
78 | class DeleteRepoImageResponseSchema(schema.ResponseSchema):
79 | """ DeleteRepoImage - 删除镜像
80 | """
81 |
82 | fields = {}
83 |
84 |
85 | """
86 | API: GetImageTag
87 |
88 | 获取镜像tag
89 | """
90 |
91 |
92 | class GetImageTagRequestSchema(schema.RequestSchema):
93 | """ GetImageTag - 获取镜像tag
94 | """
95 |
96 | fields = {
97 | "ImageName": fields.Str(required=True, dump_to="ImageName"),
98 | "Limit": fields.Int(required=False, dump_to="Limit"),
99 | "Offset": fields.Int(required=False, dump_to="Offset"),
100 | "ProjectId": fields.Str(required=False, dump_to="ProjectId"),
101 | "RepoName": fields.Str(required=True, dump_to="RepoName"),
102 | "TagName": fields.Str(required=False, dump_to="TagName"),
103 | }
104 |
105 |
106 | class GetImageTagResponseSchema(schema.ResponseSchema):
107 | """ GetImageTag - 获取镜像tag
108 | """
109 |
110 | fields = {
111 | "TagSet": fields.List(
112 | models.TagSetSchema(), required=True, load_from="TagSet"
113 | ),
114 | "TotalCount": fields.Int(required=True, load_from="TotalCount"),
115 | }
116 |
117 |
118 | """
119 | API: GetRepo
120 |
121 | 获取镜像仓库
122 | """
123 |
124 |
125 | class GetRepoRequestSchema(schema.RequestSchema):
126 | """ GetRepo - 获取镜像仓库
127 | """
128 |
129 | fields = {
130 | "Limit": fields.Int(required=False, dump_to="Limit"),
131 | "Offset": fields.Int(required=False, dump_to="Offset"),
132 | "ProjectId": fields.Str(required=False, dump_to="ProjectId"),
133 | "Type": fields.Str(required=False, dump_to="Type"),
134 | }
135 |
136 |
137 | class GetRepoResponseSchema(schema.ResponseSchema):
138 | """ GetRepo - 获取镜像仓库
139 | """
140 |
141 | fields = {
142 | "RepoSet": fields.List(
143 | models.RepoSetSchema(), required=True, load_from="RepoSet"
144 | ),
145 | "TotalCount": fields.Int(required=True, load_from="TotalCount"),
146 | }
147 |
148 |
149 | """
150 | API: GetRepoImage
151 |
152 | 获取镜像仓库下的镜像
153 | """
154 |
155 |
156 | class GetRepoImageRequestSchema(schema.RequestSchema):
157 | """ GetRepoImage - 获取镜像仓库下的镜像
158 | """
159 |
160 | fields = {
161 | "Limit": fields.Int(required=False, dump_to="Limit"),
162 | "Offset": fields.Int(required=False, dump_to="Offset"),
163 | "ProjectId": fields.Str(required=False, dump_to="ProjectId"),
164 | "RepoName": fields.Str(required=True, dump_to="RepoName"),
165 | }
166 |
167 |
168 | class GetRepoImageResponseSchema(schema.ResponseSchema):
169 | """ GetRepoImage - 获取镜像仓库下的镜像
170 | """
171 |
172 | fields = {
173 | "ImageSet": fields.List(
174 | models.ImageSetSchema(), required=True, load_from="ImageSet"
175 | ),
176 | "TotalCount": fields.Int(required=True, load_from="TotalCount"),
177 | }
178 |
179 |
180 | """
181 | API: UpdateRepo
182 |
183 | 更新镜像仓库
184 | """
185 |
186 |
187 | class UpdateRepoRequestSchema(schema.RequestSchema):
188 | """ UpdateRepo - 更新镜像仓库
189 | """
190 |
191 | fields = {
192 | "Description": fields.Str(required=False, dump_to="Description"),
193 | "IsShared": fields.Str(required=False, dump_to="IsShared"),
194 | "ProjectId": fields.Str(required=False, dump_to="ProjectId"),
195 | "RepoName": fields.Str(required=True, dump_to="RepoName"),
196 | }
197 |
198 |
199 | class UpdateRepoResponseSchema(schema.ResponseSchema):
200 | """ UpdateRepo - 更新镜像仓库
201 | """
202 |
203 | fields = {"Message": fields.Str(required=False, load_from="Message")}
204 |
--------------------------------------------------------------------------------