From 18ff3541a543980f4a31e226479850adccc0f231 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20V=C3=A4lim=C3=A4ki?= Date: Fri, 17 May 2024 11:06:55 +0300 Subject: [PATCH 1/7] feat(storage): support for encryption at rest --- CHANGELOG.md | 4 +++- docs/Storage.md | 3 ++- ..._01d4fcd4-e446-433b-8a9c-551a1284952e.json | 1 + test/json_data/storage_post.json | 1 + test/test_storage.py | 4 +++- upcloud_api/cloud_manager/storage_mixin.py | 8 ++++++++ upcloud_api/storage.py | 20 ++++++++++++++++++- 7 files changed, 37 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e89ac0..297e795 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ----- +### Added + +- Storage encryption at rest support via `encrypted` ## [2.5.1] - 2023-09-19 diff --git a/docs/Storage.md b/docs/Storage.md index 6074e76..969335e 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=True ) storage2 = manager.create_storage(zone='de-fra1', size=100) 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/upcloud_api/cloud_manager/storage_mixin.py b/upcloud_api/cloud_manager/storage_mixin.py index 1e30c70..27b28e8 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,12 @@ def create_storage( """ if backup_rule is None: backup_rule = {} + + if encrypted: + encrypted_str = 'yes' + else: + encrypted_str = 'no' + body = { 'storage': { 'size': size, @@ -60,6 +67,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..266f011 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 'encrypted' in kwargs and kwargs['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, 'enrypted') and isinstance(self.enrypted, bool): + body['server']['enrypted'] = "yes" if self.enrypted else "no" + return body @staticmethod From 7dc4c08ef3aeee8aad0d25359e72b44108d0df87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20V=C3=A4lim=C3=A4ki?= Date: Mon, 20 May 2024 12:44:17 +0300 Subject: [PATCH 2/7] fix(storage): typo --- upcloud_api/storage.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/upcloud_api/storage.py b/upcloud_api/storage.py index 266f011..8190a07 100644 --- a/upcloud_api/storage.py +++ b/upcloud_api/storage.py @@ -168,8 +168,8 @@ def to_dict(self): dict_labels.append(label.to_dict()) body['labels'] = dict_labels - if hasattr(self, 'enrypted') and isinstance(self.enrypted, bool): - body['server']['enrypted'] = "yes" if self.enrypted else "no" + if hasattr(self, 'encrypted') and isinstance(self.encrypted, bool): + body['server']['encrypted'] = "yes" if self.encrypted else "no" return body From 82e4d51fda767c4f1a1cd71717799141b4131c9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20V=C3=A4lim=C3=A4ki?= Date: Mon, 20 May 2024 12:44:50 +0300 Subject: [PATCH 3/7] fix(storage): use .get() to access `encrypted` field --- upcloud_api/storage.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/upcloud_api/storage.py b/upcloud_api/storage.py index 8190a07..534f39e 100644 --- a/upcloud_api/storage.py +++ b/upcloud_api/storage.py @@ -56,7 +56,7 @@ def _reset(self, **kwargs) -> None: elif 'storage_size' in kwargs: self.size = kwargs['storage_size'] - if 'encrypted' in kwargs and kwargs['encrypted'] == 'yes': + if kwargs.get('encrypted') == 'yes': self.encrypted = True else: self.encrypted = False From f1b055d003d1e15c356e333e3c47557d2fcbaaed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20V=C3=A4lim=C3=A4ki?= Date: Mon, 20 May 2024 12:48:28 +0300 Subject: [PATCH 4/7] fix(storage): remove server dict --- upcloud_api/storage.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/upcloud_api/storage.py b/upcloud_api/storage.py index 534f39e..51e9ebb 100644 --- a/upcloud_api/storage.py +++ b/upcloud_api/storage.py @@ -169,7 +169,7 @@ def to_dict(self): body['labels'] = dict_labels if hasattr(self, 'encrypted') and isinstance(self.encrypted, bool): - body['server']['encrypted'] = "yes" if self.encrypted else "no" + body['encrypted'] = "yes" if self.encrypted else "no" return body From f98c3dbfc0679b7abe62df1e25953c1a1a7acb0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20V=C3=A4lim=C3=A4ki?= <110451292+villevsv-upcloud@users.noreply.github.com> Date: Mon, 27 May 2024 09:05:46 +0300 Subject: [PATCH 5/7] docs(changelog): wording Co-authored-by: AJ Kovalainen --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 297e795..581a77c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added -- Storage encryption at rest support via `encrypted` +- Added `encrypted` boolean flag to Storage for encryption at rest support ## [2.5.1] - 2023-09-19 From 90ab20befef8e842408b0720c887a826ac94c8a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20V=C3=A4lim=C3=A4ki?= <110451292+villevsv-upcloud@users.noreply.github.com> Date: Mon, 27 May 2024 09:06:34 +0300 Subject: [PATCH 6/7] docs(example): encrypted to False Co-authored-by: AJ Kovalainen --- docs/Storage.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Storage.md b/docs/Storage.md index 969335e..3aa635e 100644 --- a/docs/Storage.md +++ b/docs/Storage.md @@ -52,7 +52,7 @@ storage1 = manager.create_storage( size=10, tier="maxiops", title="my storage disk", - encrypted=True + encrypted=False ) storage2 = manager.create_storage(zone='de-fra1', size=100) From 5bb05be4d3c170f32a135ff5324fe2129004af74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20V=C3=A4lim=C3=A4ki?= <110451292+villevsv-upcloud@users.noreply.github.com> Date: Mon, 27 May 2024 09:08:03 +0300 Subject: [PATCH 7/7] chore(storage): inline if Co-authored-by: AJ Kovalainen --- upcloud_api/cloud_manager/storage_mixin.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/upcloud_api/cloud_manager/storage_mixin.py b/upcloud_api/cloud_manager/storage_mixin.py index 27b28e8..a049a08 100644 --- a/upcloud_api/cloud_manager/storage_mixin.py +++ b/upcloud_api/cloud_manager/storage_mixin.py @@ -55,10 +55,7 @@ def create_storage( if backup_rule is None: backup_rule = {} - if encrypted: - encrypted_str = 'yes' - else: - encrypted_str = 'no' + encrypted_str = 'yes' if encrypted else 'no' body = { 'storage': {