Revision a2ef112e kamaki/clients/compute.py
b/kamaki/clients/compute.py | ||
---|---|---|
41 | 41 |
"""OpenStack Compute API 1.1 client""" |
42 | 42 |
|
43 | 43 |
def list_servers(self, detail=False): |
44 |
"""List servers, returned detailed output if detailed is True""" |
|
44 |
""" |
|
45 |
:param detail: if true, append full server details to each item |
|
46 |
|
|
47 |
:returns: list of server ids and names |
|
48 |
""" |
|
45 | 49 |
detail = 'detail' if detail else '' |
46 | 50 |
r = self.servers_get(command=detail) |
47 | 51 |
return r.json['servers']['values'] |
48 | 52 |
|
49 | 53 |
def get_server_details(self, server_id, **kwargs): |
50 |
"""Return detailed output on a server specified by its id""" |
|
54 |
"""Return detailed info for a server |
|
55 |
|
|
56 |
:param server_id: integer (int or str) |
|
57 |
|
|
58 |
:returns: dict with server details |
|
59 |
""" |
|
51 | 60 |
r = self.servers_get(server_id, **kwargs) |
52 | 61 |
return r.json['server'] |
53 | 62 |
|
54 | 63 |
def create_server(self, name, flavor_id, image_id, personality=None): |
55 | 64 |
"""Submit request to create a new server |
56 | 65 |
|
57 |
The flavor_id specifies the hardware configuration to use, |
|
58 |
the image_id specifies the OS Image to be deployed inside the new |
|
59 |
server. |
|
66 |
:param name: (str) |
|
67 |
|
|
68 |
:param flavor_id: integer id denoting a preset hardware configuration |
|
69 |
|
|
70 |
:param image_id: (str) id denoting the OS image to run on the VM |
|
60 | 71 |
|
61 |
The personality argument is a list of (file path, file contents)
|
|
62 |
tuples, describing files to be injected into the server upon creation.
|
|
72 |
:param personality: a list of (file path, file contents) tuples,
|
|
73 |
describing files to be injected into VM upon creation.
|
|
63 | 74 |
|
64 |
The call returns a dictionary describing the newly created server. |
|
75 |
:returns: a dict with the new VMs details |
|
76 |
|
|
77 |
:raises ClientError: wraps request errors |
|
65 | 78 |
""" |
66 | 79 |
req = {'server': {'name': name, |
67 | 80 |
'flavorRef': flavor_id, |
... | ... | |
94 | 107 |
return r.json['server'] |
95 | 108 |
|
96 | 109 |
def update_server_name(self, server_id, new_name): |
97 |
"""Update the name of the server as reported by the API. |
|
110 |
"""Update the name of the server as reported by the API (does not |
|
111 |
modify the hostname used inside the VM) |
|
112 |
|
|
113 |
:param server_id: integer (str or int) |
|
98 | 114 |
|
99 |
This call does not modify the hostname actually used by the server |
|
100 |
internally. |
|
115 |
:param new_name: (str) |
|
101 | 116 |
""" |
102 | 117 |
req = {'server': {'name': new_name}} |
103 | 118 |
r = self.servers_put(server_id, json_data=req) |
104 | 119 |
r.release() |
105 | 120 |
|
106 | 121 |
def delete_server(self, server_id): |
107 |
"""Submit a deletion request for a server specified by id""" |
|
122 |
"""Submit a deletion request for a server specified by id |
|
123 |
|
|
124 |
:param server_id: integer (str or int) |
|
125 |
""" |
|
108 | 126 |
r = self.servers_delete(server_id) |
109 | 127 |
r.release() |
110 | 128 |
|
111 | 129 |
def reboot_server(self, server_id, hard=False): |
112 |
"""Submit a reboot request for a server specified by id""" |
|
130 |
""" |
|
131 |
:param server_id: integer (str or int) |
|
132 |
|
|
133 |
:param hard: perform a hard reboot if true, soft reboot otherwise |
|
134 |
""" |
|
113 | 135 |
type = 'HARD' if hard else 'SOFT' |
114 | 136 |
req = {'reboot': {'type': type}} |
115 | 137 |
r = self.servers_post(server_id, 'action', json_data=req) |
116 | 138 |
r.release() |
117 | 139 |
|
118 | 140 |
def get_server_metadata(self, server_id, key=''): |
141 |
""" |
|
142 |
:param server_id: integer (str or int) |
|
143 |
|
|
144 |
:param key: (str) the metadatum key (all metadata if not given) |
|
145 |
|
|
146 |
:returns: a key:val dict of requests metadata |
|
147 |
""" |
|
119 | 148 |
command = path4url('meta', key) |
120 | 149 |
r = self.servers_get(server_id, command) |
121 | 150 |
return r.json['meta'] if key != '' else r.json['metadata']['values'] |
122 | 151 |
|
123 | 152 |
def create_server_metadata(self, server_id, key, val): |
153 |
""" |
|
154 |
:param server_id: integer (str or int) |
|
155 |
|
|
156 |
:param key: (str) |
|
157 |
|
|
158 |
:param val: (str) |
|
159 |
|
|
160 |
:returns: dict of updated key:val metadata |
|
161 |
""" |
|
124 | 162 |
req = {'meta': {key: val}} |
125 | 163 |
r = self.servers_put(server_id, |
126 | 164 |
'meta/' + key, |
... | ... | |
129 | 167 |
return r.json['meta'] |
130 | 168 |
|
131 | 169 |
def update_server_metadata(self, server_id, **metadata): |
170 |
""" |
|
171 |
:param server_id: integer (str or int) |
|
172 |
|
|
173 |
:param metadata: dict of key:val metadata |
|
174 |
|
|
175 |
:returns: dict of updated key:val metadata |
|
176 |
""" |
|
132 | 177 |
req = {'metadata': metadata} |
133 | 178 |
r = self.servers_post(server_id, 'meta', json_data=req, success=201) |
134 | 179 |
return r.json['metadata'] |
135 | 180 |
|
136 | 181 |
def delete_server_metadata(self, server_id, key): |
182 |
""" |
|
183 |
:param server_id: integer (str or int) |
|
184 |
|
|
185 |
:param key: (str) the meta key |
|
186 |
""" |
|
137 | 187 |
r = self.servers_delete(server_id, 'meta/' + key) |
138 | 188 |
r.release() |
139 | 189 |
|
140 |
def flavors_get(self, flavor_id='', command='', **kwargs): |
|
141 |
"""GET base_url[/flavor_id][/command] |
|
142 |
@param flavor_id |
|
143 |
@param command |
|
190 |
def list_flavors(self, detail=False): |
|
144 | 191 |
""" |
145 |
path = path4url('flavors', flavor_id, command) |
|
146 |
success = kwargs.pop('success', 200) |
|
147 |
return self.get(path, success=success, **kwargs) |
|
192 |
:param detail: (bool) detailed flavor info if set, short if not |
|
148 | 193 |
|
149 |
def list_flavors(self, detail=False): |
|
194 |
:returns: (dict) flavor info |
|
195 |
""" |
|
150 | 196 |
detail = 'detail' if detail else '' |
151 | 197 |
r = self.flavors_get(command='detail') |
152 | 198 |
return r.json['flavors']['values'] |
153 | 199 |
|
154 | 200 |
def get_flavor_details(self, flavor_id): |
201 |
""" |
|
202 |
:param flavor_id: integer (str or int) |
|
203 |
|
|
204 |
:returns: dict |
|
205 |
""" |
|
155 | 206 |
r = self.flavors_get(flavor_id) |
156 | 207 |
return r.json['flavor'] |
157 | 208 |
|
158 |
def images_get(self, image_id='', command='', **kwargs): |
|
159 |
"""GET base_url[/image_id][/command] |
|
160 |
@param image_id |
|
161 |
@param command |
|
162 |
""" |
|
163 |
path = path4url('images', image_id, command) |
|
164 |
success = kwargs.pop('success', 200) |
|
165 |
return self.get(path, success=success, **kwargs) |
|
166 |
|
|
167 |
def images_delete(self, image_id='', command='', **kwargs): |
|
168 |
"""DEL ETE base_url[/image_id][/command] |
|
169 |
@param image_id |
|
170 |
@param command |
|
171 |
""" |
|
172 |
path = path4url('images', image_id, command) |
|
173 |
success = kwargs.pop('success', 204) |
|
174 |
return self.delete(path, success=success, **kwargs) |
|
175 |
|
|
176 |
def images_post(self, image_id='', command='', json_data=None, **kwargs): |
|
177 |
"""POST base_url/images[/image_id]/[command] request |
|
178 |
@param image_id or '' |
|
179 |
@param command: can be 'action' or '' |
|
180 |
@param json_data: a json valid dict that will be send as data |
|
181 |
""" |
|
182 |
data = json_data |
|
183 |
if json_data is not None: |
|
184 |
data = json.dumps(json_data) |
|
185 |
self.set_header('Content-Type', 'application/json') |
|
186 |
self.set_header('Content-Length', len(data)) |
|
187 |
|
|
188 |
path = path4url('images', image_id, command) |
|
189 |
success = kwargs.pop('success', 201) |
|
190 |
return self.post(path, data=data, success=success, **kwargs) |
|
191 |
|
|
192 |
def images_put(self, image_id='', command='', json_data=None, **kwargs): |
|
193 |
"""PUT base_url/images[/image_id]/[command] request |
|
194 |
@param image_id or '' |
|
195 |
@param command: can be 'action' or '' |
|
196 |
@param json_data: a json valid dict that will be send as data |
|
197 |
""" |
|
198 |
data = json_data |
|
199 |
if json_data is not None: |
|
200 |
data = json.dumps(json_data) |
|
201 |
self.set_header('Content-Type', 'application/json') |
|
202 |
self.set_header('Content-Length', len(data)) |
|
203 |
|
|
204 |
path = path4url('images', image_id, command) |
|
205 |
success = kwargs.pop('success', 201) |
|
206 |
return self.put(path, data=data, success=success, **kwargs) |
|
207 |
|
|
208 | 209 |
def list_images(self, detail=False): |
210 |
""" |
|
211 |
:param detail: (bool) detailed info if set, short if not |
|
212 |
|
|
213 |
:returns: dict id,name + full info if detail |
|
214 |
""" |
|
209 | 215 |
detail = 'detail' if detail else '' |
210 | 216 |
r = self.images_get(command=detail) |
211 | 217 |
return r.json['images']['values'] |
212 | 218 |
|
213 | 219 |
def get_image_details(self, image_id, **kwargs): |
220 |
""" |
|
221 |
:param image_id: integer (str or int) |
|
222 |
|
|
223 |
:returns: dict |
|
224 |
|
|
225 |
:raises ClientError: 404 if image not available |
|
226 |
""" |
|
214 | 227 |
r = self.images_get(image_id, **kwargs) |
215 | 228 |
try: |
216 | 229 |
return r.json['image'] |
... | ... | |
219 | 232 |
details='Image %d not found or not accessible') |
220 | 233 |
|
221 | 234 |
def delete_image(self, image_id): |
235 |
""" |
|
236 |
:param image_id: (str) |
|
237 |
""" |
|
222 | 238 |
r = self.images_delete(image_id) |
223 | 239 |
r.release() |
224 | 240 |
|
225 | 241 |
def get_image_metadata(self, image_id, key=''): |
242 |
""" |
|
243 |
:param image_id: (str) |
|
244 |
|
|
245 |
:param key: (str) the metadatum key |
|
246 |
|
|
247 |
:returns (dict) metadata if key not set, specific metadatum otherwise |
|
248 |
""" |
|
226 | 249 |
command = path4url('meta', key) |
227 | 250 |
r = self.images_get(image_id, command) |
228 |
return r.json['meta'] if key != '' else r.json['metadata']['values']
|
|
251 |
return r.json['meta'] if key else r.json['metadata']['values'] |
|
229 | 252 |
|
230 | 253 |
def create_image_metadata(self, image_id, key, val): |
254 |
""" |
|
255 |
:param image_id: integer (str or int) |
|
256 |
|
|
257 |
:param key: (str) metadatum key |
|
258 |
|
|
259 |
:param val: (str) metadatum value |
|
260 |
|
|
261 |
:returns: (dict) updated metadata |
|
262 |
""" |
|
231 | 263 |
req = {'meta': {key: val}} |
232 | 264 |
r = self.images_put(image_id, 'meta/' + key, json_data=req) |
233 | 265 |
return r.json['meta'] |
234 | 266 |
|
235 | 267 |
def update_image_metadata(self, image_id, **metadata): |
268 |
""" |
|
269 |
:param image_id: (str) |
|
270 |
|
|
271 |
:param metadata: dict |
|
272 |
|
|
273 |
:returns: updated metadata |
|
274 |
""" |
|
236 | 275 |
req = {'metadata': metadata} |
237 | 276 |
r = self.images_post(image_id, 'meta', json_data=req) |
238 | 277 |
return r.json['metadata'] |
239 | 278 |
|
240 | 279 |
def delete_image_metadata(self, image_id, key): |
280 |
""" |
|
281 |
:param image_id: (str) |
|
282 |
|
|
283 |
:param key: (str) metadatum key |
|
284 |
""" |
|
241 | 285 |
command = path4url('meta', key) |
242 | 286 |
r = self.images_delete(image_id, command) |
243 | 287 |
r.release() |
Also available in: Unified diff