-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathsdk.py
202 lines (152 loc) · 5.33 KB
/
sdk.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
import time
import openstack
from halo import Halo
class OpenStack(object):
def setup_spinner(self, text='Loading'):
spinner = Halo(
text=text,
spinner='simpleDots',
color='white',
).start()
return spinner
def handle_spinner_error_state(self, spinner, succeed_on_error=False):
if succeed_on_error:
spinner.stop_and_persist(symbol='[x]', text='Finished')
return True
spinner.fail()
return False
def wait_for_state(self, state='available', attempts=10, succeed_on_error=False): # noqa
'''Waits until the volume has a certain state'''
tries = 0
# Start the spinner
spinner = self.setup_spinner()
# Wait 1 second to give the API some space to breathe
time.sleep(1)
# Get the current state and check if it's valid
try:
previous_state = self.state
except openstack.exceptions.ResourceNotFound:
return self.handle_spinner_error_state(
spinner=spinner,
succeed_on_error=succeed_on_error
)
spinner.text = previous_state.title()
while tries < attempts:
time.sleep(1)
try:
current_state = self.state
except openstack.exceptions.ResourceNotFound:
return self.handle_spinner_error_state(
spinner=spinner,
succeed_on_error=succeed_on_error
)
if current_state == state:
spinner.stop_and_persist(
symbol='[x]',
text=current_state.title()
)
return True
spinner.fail()
return False
def delete(self):
'''Dummy method that should delete the object'''
return True
@property
def state(self):
'''Return the current state of the object'''
return 'unknown'
class Image(OpenStack):
def __init__(self, api, image, debug=True):
self.api = api
self.image = image
self.debug = debug
def to_volume(self, name, size, wait=True, attempts=600):
'''Convert the image to a volume'''
volume = self.api.volume.create_volume(
name=name,
image_id=self.image.id,
size=size,
)
volume = Volume(api=self.api, volume=volume)
if wait:
if volume.wait_for_state(state='available', attempts=attempts):
return volume
return False
return volume
def delete(self):
'''Delete the image from OpenStack'''
self.api.delete_image(self.image.id)
@property
def state(self):
'''Get the current state of the image'''
return self.api.get_image(self.image.id).status
class Volume(OpenStack):
def __init__(self, api, volume, debug=True):
self.api = api
self.volume = volume
self.debug = debug
def to_image(self, name, wait=True, attempts=600):
'''Convert an existing volume to an image'''
image = self.api.create_image(
name=name,
volume=self.volume,
)
image = Image(api=self.api, image=image)
if wait:
if image.wait_for_state(state='active', attempts=attempts):
return image
return False
return image
def to_snapshot(self, name, description, wait=True, attempts=600):
'''Create a snapshot of a volume'''
snapshot = self.api.volume.create_snapshot(
name=name,
description=description,
volume_id=self.volume.id,
force=True,
)
snapshot = Snapshot(api=self.api, snapshot=snapshot)
if wait:
if snapshot.wait_for_state(state='available', attempts=attempts):
return snapshot
return False
return snapshot
def snapshots(self):
'''Return all snapshots for this volume'''
return self.api.volume.snapshots(volume_id=self.volume.id)
def delete(self):
'''Delete the volume from OpenStack'''
self.api.volume.delete_volume(self.volume)
@property
def state(self):
'''Get the current state of the volume'''
return self.api.volume.get_volume(self.volume).status
class Snapshot(OpenStack):
def __init__(self, api, snapshot, debug=True):
self.api = api
self.snapshot = snapshot
self.debug = debug
def to_volume(self, name, wait=True, attempts=10):
'''Create a volume from a snapshot'''
volume = self.api.volume.create_volume(
name=name,
snapshot_id=self.snapshot.id,
)
volume = Volume(api=self.api, volume=volume)
if wait:
if volume.wait_for_state(state='available', attempts=attempts):
return volume
return False
return volume
def delete(self):
'''Delete the snapshot from OpenStack'''
self.api.volume.delete_snapshot(self.snapshot)
return self.wait_for_state(
state='error',
attempts=10,
succeed_on_error=True
)
@property
def state(self):
'''Return the current state of the snapshot'''
return self.api.volume.get_snapshot(self.snapshot).status