Skip to content

Commit abcc5f9

Browse files
authored
Merge pull request #72 from TechConsult/storage_methods
Update ReadMe and refactor storage methods
2 parents 9cfbaa0 + 8986902 commit abcc5f9

File tree

6 files changed

+150
-23
lines changed

6 files changed

+150
-23
lines changed

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -233,21 +233,21 @@ Set up environment and install dependencies:
233233
# run at project root, python3 and virtualenv must be installed
234234
virtualenv ENV
235235
source ENV/bin/activate
236-
pip install -r requirements.txt
236+
pip install -r requirements.txt or pip install -r requirements-dev.txt if changes to the api need to be made
237237
```
238238

239239
Install the package in editable mode, as mentioned in
240-
[https://pytest.org/latest/goodpractises.html](https://pytest.org/latest/goodpractises.html)
240+
[https://docs.pytest.org/en/stable/goodpractices.html](https://docs.pytest.org/en/stable/goodpractices.html)
241241

242242
```python
243243
# run at project root
244244
pip install -e .
245245
```
246246

247-
Tests located in `project_root/tests/` directory. Run with:
247+
Tests located in `project_root/test/` directory. Run with:
248248

249249
```python
250-
py.test tests/
250+
py.test test/
251251
```
252252

253253
To test against all supported python versions, run:

docs/Storage.md

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,3 +81,64 @@ Warning: data loss is permanent.
8181
storage.destroy()
8282

8383
```
84+
85+
86+
## Clone
87+
88+
Clone the storage using StorageManager.
89+
Returns an object based on the API's response.
90+
Method requires title and zone to be passed while tier is optional.
91+
92+
```python
93+
94+
storage_clone = storage.clone(title='title of storage clone', zone=ZONE.Helsinki, tier=None)
95+
96+
```
97+
98+
99+
## Cancel clone operation
100+
101+
Cancels a running cloning operation and deletes the incomplete copy using StorageManager.
102+
Needs to be called from the cloned storage (object returned by clone operation) and not the storage that is being cloned.
103+
104+
```python
105+
106+
storage_clone.cancel_cloning()
107+
108+
```
109+
110+
111+
## Create backup
112+
113+
Creates a point-in-time backup of a storage resource using StorageManager.
114+
Method requires title to be passed.
115+
116+
```python
117+
118+
storage_backup = storage.create_backup('Backup title')
119+
120+
```
121+
122+
123+
## Restore backup
124+
125+
Restores the origin storage with data from the specified backup storage using StorageManager.
126+
Must be called from a storage object created by create_backup and not the original one.
127+
128+
```python
129+
130+
storage_backup.restore_backup()
131+
132+
```
133+
134+
135+
## Templatize storage
136+
137+
Creates an exact copy of an existing storage resource which can be used as a template for creating new servers using StorageManager.
138+
Method requires title to be passed.
139+
140+
```python
141+
142+
storage.templatize('Template title')
143+
144+
```

docs/server-mixin.md

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ manager.method()
2020
```python
2121
def get_servers(self, populate=False):
2222
"""
23-
Returns a list of (populated or unpopulated) Server instances.
23+
Returns a list of (populated or unpopulated) Server instances.
2424
Populate = False (default) => 1 API request, returns unpopulated Server instances.
2525
Populate = True => Does 1 + n API requests (n = # of servers), returns populated Server instances.
2626
"""
@@ -36,14 +36,14 @@ def get_server(self, UUID):
3636
```python
3737
def create_server(self, server):
3838
"""
39-
Creates a server and its storages based on a (locally created) Server object.
39+
Creates a server and its storages based on a (locally created) Server object.
4040
Populates the given Server instance with the API response.
4141
4242
Example:
4343
server1 = Server( core_number = 1,
44-
memory_amount = 1024,
45-
hostname = "my.example.1",
46-
zone = ZONE.London,
44+
memory_amount = 1024,
45+
hostname = "my.example.1",
46+
zone = ZONE.London,
4747
storage_devices = [
4848
Storage(os = "Ubuntu 14.04", size=10, tier=maxiops, title='The OS drive'),
4949
Storage(size=10),
@@ -56,7 +56,7 @@ def create_server(self, server):
5656
- size defaults to 10,
5757
- title defaults to hostname + " OS disk" and hostname + " storage disk id" (id is a running starting from 1)
5858
- tier defaults to maxiops
59-
- valid operating systems are:
59+
- valid operating systems are:
6060
"CentOS 6.5", "CentOS 7.0"
6161
"Debian 7.8"
6262
"Ubuntu 12.04", "Ubuntu 14.04"
@@ -76,17 +76,25 @@ def modify_server(self, UUID, **kwargs):
7676
```python
7777
def delete_server(self, UUID):
7878
"""
79-
DELETE '/server/UUID'. Permanently destroys the virtual machine.
79+
DELETE '/server/UUID'. Permanently destroys the virtual machine.
8080
DOES NOT remove the storage disks.
8181
8282
Returns an empty object.
8383
"""
8484
```
8585

86+
```python
87+
def get_server_by_ip(self, ip_address):
88+
"""
89+
Return a (populated) Server instance by its IP.
90+
Uses GET '/ip_address/x.x.x.x' to retrieve machine UUID using IP-address.
91+
"""
92+
```
93+
8694
```python
8795
def get_server_data(self, UUID):
8896
"""
89-
Returns '/server/uuid' data in Python dict.
97+
Returns '/server/uuid' data in Python dict.
9098
Creates object representations of any IP-address and Storage.
9199
"""
92-
```
100+
```
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{"storage":
2+
{
3+
"access": "private",
4+
"created": "2020-09-21T17:36:50Z",
5+
"license": 0,
6+
"origin": "01ec5c26-a25d-4752-94e4-27bd88b62816",
7+
"progress": "0",
8+
"servers": {"server": []},
9+
"size": 666,
10+
"state": "maintenance",
11+
"title": "test-backup",
12+
"type": "backup",
13+
"uuid": "01350eec-6ebf-4418-abe4-e8bb1d5c9643",
14+
"zone": "fi-hel1"
15+
}
16+
}

test/test_storage.py

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ def test_clone_storage(self, manager):
4040
storage = manager.get_storage("01d4fcd4-e446-433b-8a9c-551a1284952e")
4141

4242
Mock.mock_post("storage/01d4fcd4-e446-433b-8a9c-551a1284952e/clone")
43-
cloned_storage = manager.clone_storage(storage, 'cloned-storage-test', 'fi-hel1')
43+
cloned_storage = storage.clone('cloned-storage-test', 'fi-hel1')
4444
assert type(cloned_storage).__name__ == "Storage"
4545
assert cloned_storage.size == 666
4646
assert cloned_storage.tier == "maxiops"
@@ -56,7 +56,7 @@ def test_cancel_clone_storage(self, manager):
5656
cloned_storage = manager.clone_storage(storage, 'cloned-storage-test', 'fi-hel1')
5757

5858
Mock.mock_post("storage/01d3e9ad-8ff5-4a52-9fa2-48938e488e78/cancel", empty_content=True)
59-
res = manager.cancel_clone_storage(cloned_storage)
59+
res = cloned_storage.cancel_cloning()
6060
assert res == {}
6161

6262
@responses.activate
@@ -73,24 +73,33 @@ def test_eject_cd_rom(self, manager):
7373

7474
@responses.activate
7575
def test_create_storage_backup(self, manager):
76+
data = Mock.mock_get("storage/01d4fcd4-e446-433b-8a9c-551a1284952e")
77+
storage = manager.get_storage("01d4fcd4-e446-433b-8a9c-551a1284952e")
78+
7679
data = Mock.mock_post("storage/01d4fcd4-e446-433b-8a9c-551a1284952e/backup")
77-
storage = manager.create_storage_backup("01d4fcd4-e446-433b-8a9c-551a1284952e", "test-backup")
78-
assert storage.title == "test-backup"
79-
assert storage.size == 666
80-
assert storage.zone == "fi-hel1"
80+
storage_backup = storage.create_backup("test-backup")
81+
assert storage_backup.title == "test-backup"
82+
assert storage_backup.size == 666
83+
assert storage_backup.zone == "fi-hel1"
8184

8285
@responses.activate
8386
def test_restore_storage_backup(self, manager):
87+
data = Mock.mock_get("storage/01350eec-6ebf-4418-abe4-e8bb1d5c9643")
88+
storage_backup = manager.get_storage("01350eec-6ebf-4418-abe4-e8bb1d5c9643")
89+
8490
data = Mock.mock_post("storage/01350eec-6ebf-4418-abe4-e8bb1d5c9643/restore", empty_content=True)
85-
res = manager.restore_storage_backup("01350eec-6ebf-4418-abe4-e8bb1d5c9643")
91+
res = storage_backup.restore_backup()
8692
assert res == {}
8793

8894
@responses.activate
8995
def test_templatize_storage(self, manager):
96+
data = Mock.mock_get("storage/01d4fcd4-e446-433b-8a9c-551a1284952e")
97+
storage = manager.get_storage("01d4fcd4-e446-433b-8a9c-551a1284952e")
98+
9099
data = Mock.mock_post("storage/01d4fcd4-e446-433b-8a9c-551a1284952e/templatize")
91-
storage = manager.templatize_storage("01d4fcd4-e446-433b-8a9c-551a1284952e", "my server template")
92-
assert storage.title == "my server template"
93-
assert storage.type == "template"
100+
storage_template = storage.templatize("my server template")
101+
assert storage_template.title == "my server template"
102+
assert storage_template.type == "template"
94103

95104
@responses.activate
96105
def test_create_storage_import(self, manager):

upcloud_api/storage.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,39 @@ def update(self, size, title):
8080
self.title = title
8181
self.save()
8282

83+
def clone(self, title, zone, tier=None):
84+
"""
85+
Clone the storage using StorageManager.
86+
Returns an object based on the API's response.
87+
"""
88+
return self.cloud_manager.clone_storage(self.uuid, title, zone, tier)
89+
90+
def cancel_cloning(self):
91+
"""
92+
Cancels a running cloning operation and deletes the incomplete copy using StorageManager.
93+
Needs to be called from the cloned storage and not the storage that is being cloned.
94+
"""
95+
return self.cloud_manager.cancel_clone_storage(self.uuid)
96+
97+
def create_backup(self, title):
98+
"""
99+
Creates a point-in-time backup of a storage resource using StorageManager.
100+
"""
101+
return self.cloud_manager.create_storage_backup(self.uuid, title)
102+
103+
def restore_backup(self):
104+
"""
105+
Restores the origin storage with data from the specified backup storage using StorageManager.
106+
Must be called from a storage object created by create_backup and not the original one.
107+
"""
108+
return self.cloud_manager.restore_storage_backup(self.uuid)
109+
110+
def templatize(self, title):
111+
"""
112+
Creates an exact copy of an existing storage resource which can be used as a template for creating new servers using StorageManager.
113+
"""
114+
return self.cloud_manager.templatize_storage(self.uuid, title)
115+
83116
def __str__(self):
84117
"""
85118
String representation of Storage.

0 commit comments

Comments
 (0)