diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 882b24e..25f47ee 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -8,29 +8,30 @@ jobs: lint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Setup Python - uses: actions/setup-python@v4 + uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5.1.0 with: - python-version: 3.11 - - uses: pre-commit/action@v3.0.0 + python-version: 3.12 + - uses: pre-commit/action@2c7b3805fd2a0fd8c1884dcaebf91fc102a13ecd # v3.0.1 build: runs-on: ubuntu-latest strategy: matrix: tox_env: - - py37 - py38 - py39 - py310 + - py311 + - py312 - pypy3 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Fedora Tox with ${{ matrix.tox_env }} - uses: fedora-python/tox-github-action@v37.0 + uses: fedora-python/tox-github-action@6f0add50b32e4bedfd98976984ffa499af4c218b # v39.0 with: tox_env: ${{ matrix.tox_env }} - - uses: actions/setup-python@v4 + - uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5.1.0 with: cache: pip cache-dependency-path: | @@ -40,9 +41,9 @@ jobs: name: Build deploy runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - uses: actions/setup-python@v4 - - uses: casperdcl/deploy-pypi@v2.3.2 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5.1.0 + - uses: casperdcl/deploy-pypi@10cf4cd83fc885003a8d4f37f93a5a0f0fc2d2f4 # v2.4.1 with: password: ${{ secrets.PYPI_TOKEN }} build: true diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e89ac0..df5c659 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ----- +### Added + +- Added `encrypted` boolean flag to Storage for encryption at rest support + +### Changed + +- Python versions supported: 3.8, 3.9, 3.10, 3.11, 3.12, PyPy3. Dropped support for 3.7. ## [2.5.1] - 2023-09-19 diff --git a/README.md b/README.md index 68c2480..30c2313 100644 --- a/README.md +++ b/README.md @@ -24,9 +24,11 @@ python setup.py install ### Supported Python versions in API v2.5.1 -- Python 3.7 - Python 3.8 - Python 3.9 +- Python 3.10 +- Python 3.11 +- Python 3.12 - PyPy3 **Python 2 has been deprecated** diff --git a/docs/Storage.md b/docs/Storage.md index 6074e76..3aa635e 100644 --- a/docs/Storage.md +++ b/docs/Storage.md @@ -51,7 +51,8 @@ storage1 = manager.create_storage( zone='fi-hel1', size=10, tier="maxiops", - title="my storage disk" + title="my storage disk", + encrypted=False ) storage2 = manager.create_storage(zone='de-fra1', size=100) diff --git a/pyproject.toml b/pyproject.toml index 6fb2a87..a13ebdf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,10 +1,10 @@ [tool.black] line-length = 99 -target-version = ['py37'] +target-version = ['py38'] skip-string-normalization = true [tool.ruff] -target-version = "py37" +target-version = "py38" exclude = [ ".git", "ENV", diff --git a/requirements-dev.txt b/requirements-dev.txt index ef70952..6eda5a5 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -14,7 +14,7 @@ click==8.1.6 # via pip-tools coverage[toml]==7.2.7 # via pytest-cov -idna==3.4 +idna==3.7 # via requests iniconfig==2.0.0 # via pytest diff --git a/setup.cfg b/setup.cfg index 2c4d217..46b7c15 100644 --- a/setup.cfg +++ b/setup.cfg @@ -11,7 +11,7 @@ packages=['upcloud_api', 'upcloud_api.cloud_manager'] license = MIT [options] -python_requires = >=3.7, <4 +python_requires = >=3.8, <4 setup_requires = setuptools install_requires = diff --git a/test/json_data/storage_01d4fcd4-e446-433b-8a9c-551a1284952e.json b/test/json_data/storage_01d4fcd4-e446-433b-8a9c-551a1284952e.json index cc62d8d..e6e5f4f 100644 --- a/test/json_data/storage_01d4fcd4-e446-433b-8a9c-551a1284952e.json +++ b/test/json_data/storage_01d4fcd4-e446-433b-8a9c-551a1284952e.json @@ -5,6 +5,7 @@ "backups" : { "backup" : [] }, + "encrypted": "yes", "labels": [ { "key": "role", diff --git a/test/json_data/storage_post.json b/test/json_data/storage_post.json index 33cec53..856bc65 100644 --- a/test/json_data/storage_post.json +++ b/test/json_data/storage_post.json @@ -5,6 +5,7 @@ "backups": { "backup": [] }, + "encrypted": "yes", "labels": [ { "key": "role", diff --git a/test/test_storage.py b/test/test_storage.py index 76f1973..42c7640 100644 --- a/test/test_storage.py +++ b/test/test_storage.py @@ -31,9 +31,10 @@ def test_get_templates(self, manager): def test_storage_create(self, manager): Mock.mock_post("storage") storage = manager.create_storage( - zone="fi-hel1", size=666, tier="maxiops", title="My data collection" + zone="fi-hel1", encrypted=True, size=666, tier="maxiops", title="My data collection" ) assert type(storage).__name__ == "Storage" + assert storage.encrypted assert storage.size == 666 assert storage.tier == "maxiops" assert storage.title == "My data collection" @@ -47,6 +48,7 @@ def test_clone_storage(self, manager): Mock.mock_post("storage/01d4fcd4-e446-433b-8a9c-551a1284952e/clone") cloned_storage = storage.clone('cloned-storage-test', 'fi-hel1') assert type(cloned_storage).__name__ == "Storage" + assert not cloned_storage.encrypted assert cloned_storage.size == 666 assert cloned_storage.tier == "maxiops" assert cloned_storage.title == "cloned-storage-test" diff --git a/tox.ini b/tox.ini index 3c70186..31ea22a 100644 --- a/tox.ini +++ b/tox.ini @@ -4,7 +4,7 @@ # and then run "tox" from this directory. [tox] -envlist = py37, py38, py39, py310, pypy3 +envlist = py38, py39, py310, py311, py312, pypy3 skip_missing_interpreters = True [testenv] diff --git a/upcloud_api/cloud_manager/storage_mixin.py b/upcloud_api/cloud_manager/storage_mixin.py index 1e30c70..a049a08 100644 --- a/upcloud_api/cloud_manager/storage_mixin.py +++ b/upcloud_api/cloud_manager/storage_mixin.py @@ -45,6 +45,7 @@ def create_storage( size: int = 10, tier: str = 'maxiops', title: str = 'Storage disk', + encrypted: bool = False, *, backup_rule: Optional[dict] = None, ) -> Storage: @@ -53,6 +54,9 @@ def create_storage( """ if backup_rule is None: backup_rule = {} + + encrypted_str = 'yes' if encrypted else 'no' + body = { 'storage': { 'size': size, @@ -60,6 +64,7 @@ def create_storage( 'title': title, 'zone': zone, 'backup_rule': backup_rule, + 'encrypted': encrypted_str, } } res = self.api.post_request('/storage', body) diff --git a/upcloud_api/storage.py b/upcloud_api/storage.py index 9771ef2..51e9ebb 100644 --- a/upcloud_api/storage.py +++ b/upcloud_api/storage.py @@ -21,6 +21,7 @@ class Storage(UpCloudResource): ATTRIBUTES = { 'access': None, 'address': None, + 'encrypted': None, 'labels': None, 'license': None, 'state': None, @@ -55,12 +56,26 @@ def _reset(self, **kwargs) -> None: elif 'storage_size' in kwargs: self.size = kwargs['storage_size'] + if kwargs.get('encrypted') == 'yes': + self.encrypted = True + else: + self.encrypted = False + # send the rest to super._reset filtered_kwargs = { key: val for key, val in kwargs.items() - if key not in ['uuid', 'storage', 'title', 'storage_title', 'size', 'storage_size'] + if key + not in [ + 'uuid', + 'storage', + 'title', + 'storage_title', + 'size', + 'storage_size', + 'encrypted', + ] } super()._reset(**filtered_kwargs) @@ -153,6 +168,9 @@ def to_dict(self): dict_labels.append(label.to_dict()) body['labels'] = dict_labels + if hasattr(self, 'encrypted') and isinstance(self.encrypted, bool): + body['encrypted'] = "yes" if self.encrypted else "no" + return body @staticmethod