summaryrefslogtreecommitdiff
path: root/novaclient/v2/servers.py
diff options
context:
space:
mode:
Diffstat (limited to 'novaclient/v2/servers.py')
-rw-r--r--novaclient/v2/servers.py1274
1 files changed, 1274 insertions, 0 deletions
diff --git a/novaclient/v2/servers.py b/novaclient/v2/servers.py
new file mode 100644
index 0000000..36de45b
--- /dev/null
+++ b/novaclient/v2/servers.py
@@ -0,0 +1,1274 @@
1# Copyright 2010 Jacob Kaplan-Moss
2
3# Copyright 2011 OpenStack Foundation
4# All Rights Reserved.
5#
6# Licensed under the Apache License, Version 2.0 (the "License"); you may
7# not use this file except in compliance with the License. You may obtain
8# a copy of the License at
9#
10# http://www.apache.org/licenses/LICENSE-2.0
11#
12# Unless required by applicable law or agreed to in writing, software
13# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15# License for the specific language governing permissions and limitations
16# under the License.
17
18"""
19Server interface.
20"""
21
22import base64
23
24from oslo.utils import encodeutils
25import six
26from six.moves.urllib import parse
27
28from novaclient import base
29from novaclient import crypto
30from novaclient.i18n import _
31from novaclient.v2 import security_groups
32
33
34REBOOT_SOFT, REBOOT_HARD = 'SOFT', 'HARD'
35
36
37class Server(base.Resource):
38 HUMAN_ID = True
39
40 def __repr__(self):
41 return '<Server: %s>' % getattr(self, 'name', 'unknown-name')
42
43 def delete(self):
44 """
45 Delete (i.e. shut down and delete the image) this server.
46 """
47 self.manager.delete(self)
48
49 def update(self, name=None):
50 """
51 Update the name for this server.
52
53 :param name: Update the server's name.
54 """
55 self.manager.update(self, name=name)
56
57 def get_console_output(self, length=None):
58 """
59 Get text console log output from Server.
60
61 :param length: The number of lines you would like to retrieve (as int)
62 """
63 return self.manager.get_console_output(self, length)
64
65 def get_vnc_console(self, console_type):
66 """
67 Get vnc console for a Server.
68
69 :param console_type: Type of console ('novnc' or 'xvpvnc')
70 """
71 return self.manager.get_vnc_console(self, console_type)
72
73 def get_spice_console(self, console_type):
74 """
75 Get spice console for a Server.
76
77 :param console_type: Type of console ('spice-html5')
78 """
79 return self.manager.get_spice_console(self, console_type)
80
81 def get_rdp_console(self, console_type):
82 """
83 Get rdp console for a Server.
84
85 :param console_type: Type of console ('rdp-html5')
86 """
87 return self.manager.get_rdp_console(self, console_type)
88
89 def get_serial_console(self, console_type):
90 """
91 Get serial console for a Server.
92
93 :param console_type: Type of console ('serial')
94 """
95 return self.manager.get_serial_console(self, console_type)
96
97 def get_password(self, private_key=None):
98 """
99 Get password for a Server.
100
101 Returns the clear password of an instance if private_key is
102 provided, returns the ciphered password otherwise.
103
104 :param private_key: Path to private key file for decryption
105 (optional)
106 """
107 return self.manager.get_password(self, private_key)
108
109 def clear_password(self):
110 """
111 Get password for a Server.
112
113 """
114 return self.manager.clear_password(self)
115
116 def add_fixed_ip(self, network_id):
117 """
118 Add an IP address on a network.
119
120 :param network_id: The ID of the network the IP should be on.
121 """
122 self.manager.add_fixed_ip(self, network_id)
123
124 def add_floating_ip(self, address, fixed_address=None):
125 """
126 Add floating IP to an instance
127
128 :param address: The IP address or FloatingIP to add to the instance
129 :param fixed_address: The fixedIP address the FloatingIP is to be
130 associated with (optional)
131 """
132 self.manager.add_floating_ip(self, address, fixed_address)
133
134 def remove_floating_ip(self, address):
135 """
136 Remove floating IP from an instance
137
138 :param address: The IP address or FloatingIP to remove
139 """
140 self.manager.remove_floating_ip(self, address)
141
142 def stop(self):
143 """
144 Stop -- Stop the running server.
145 """
146 self.manager.stop(self)
147
148 def force_delete(self):
149 """
150 Force delete -- Force delete a server.
151 """
152 self.manager.force_delete(self)
153
154 def restore(self):
155 """
156 Restore -- Restore a server in 'soft-deleted' state.
157 """
158 self.manager.restore(self)
159
160 def start(self):
161 """
162 Start -- Start the paused server.
163 """
164 self.manager.start(self)
165
166 def pause(self):
167 """
168 Pause -- Pause the running server.
169 """
170 self.manager.pause(self)
171
172 def unpause(self):
173 """
174 Unpause -- Unpause the paused server.
175 """
176 self.manager.unpause(self)
177
178 def lock(self):
179 """
180 Lock -- Lock the instance from certain operations.
181 """
182 self.manager.lock(self)
183
184 def unlock(self):
185 """
186 Unlock -- Remove instance lock.
187 """
188 self.manager.unlock(self)
189
190 def suspend(self):
191 """
192 Suspend -- Suspend the running server.
193 """
194 self.manager.suspend(self)
195
196 def resume(self):
197 """
198 Resume -- Resume the suspended server.
199 """
200 self.manager.resume(self)
201
202 def rescue(self, password=None, image=None):
203 """
204 Rescue -- Rescue the problematic server.
205
206 :param password: The admin password to be set in the rescue instance.
207 :param image: The :class:`Image` to rescue with.
208 """
209 return self.manager.rescue(self, password, image)
210
211 def unrescue(self):
212 """
213 Unrescue -- Unrescue the rescued server.
214 """
215 self.manager.unrescue(self)
216
217 def shelve(self):
218 """
219 Shelve -- Shelve the server.
220 """
221 self.manager.shelve(self)
222
223 def shelve_offload(self):
224 """
225 Shelve_offload -- Remove a shelved server from the compute node.
226 """
227 self.manager.shelve_offload(self)
228
229 def unshelve(self):
230 """
231 Unshelve -- Unshelve the server.
232 """
233 self.manager.unshelve(self)
234
235 def diagnostics(self):
236 """Diagnostics -- Retrieve server diagnostics."""
237 return self.manager.diagnostics(self)
238
239 def migrate(self):
240 """
241 Migrate a server to a new host.
242 """
243 self.manager.migrate(self)
244
245 def remove_fixed_ip(self, address):
246 """
247 Remove an IP address.
248
249 :param address: The IP address to remove.
250 """
251 self.manager.remove_fixed_ip(self, address)
252
253 def change_password(self, password):
254 """
255 Update the admin password for a server.
256
257 :param password: string to set as the admin password on the server
258 """
259 self.manager.change_password(self, password)
260
261 def reboot(self, reboot_type=REBOOT_SOFT):
262 """
263 Reboot the server.
264
265 :param reboot_type: either :data:`REBOOT_SOFT` for a software-level
266 reboot, or `REBOOT_HARD` for a virtual power cycle hard reboot.
267 """
268 self.manager.reboot(self, reboot_type)
269
270 def rebuild(self, image, password=None, preserve_ephemeral=False,
271 **kwargs):
272 """
273 Rebuild -- shut down and then re-image -- this server.
274
275 :param image: the :class:`Image` (or its ID) to re-image with.
276 :param password: string to set as the admin password on the rebuilt
277 server.
278 :param preserve_ephemeral: If True, request that any ephemeral device
279 be preserved when rebuilding the instance. Defaults to False.
280 """
281 return self.manager.rebuild(self, image, password=password,
282 preserve_ephemeral=preserve_ephemeral,
283 **kwargs)
284
285 def resize(self, flavor, **kwargs):
286 """
287 Resize the server's resources.
288
289 :param flavor: the :class:`Flavor` (or its ID) to resize to.
290
291 Until a resize event is confirmed with :meth:`confirm_resize`, the old
292 server will be kept around and you'll be able to roll back to the old
293 flavor quickly with :meth:`revert_resize`. All resizes are
294 automatically confirmed after 24 hours.
295 """
296 self.manager.resize(self, flavor, **kwargs)
297
298 def create_image(self, image_name, metadata=None):
299 """
300 Create an image based on this server.
301
302 :param image_name: The name to assign the newly create image.
303 :param metadata: Metadata to assign to the image.
304 """
305 return self.manager.create_image(self, image_name, metadata)
306
307 def backup(self, backup_name, backup_type, rotation):
308 """
309 Backup a server instance.
310
311 :param backup_name: Name of the backup image
312 :param backup_type: The backup type, like 'daily' or 'weekly'
313 :param rotation: Int parameter representing how many backups to
314 keep around.
315 """
316 self.manager.backup(self, backup_name, backup_type, rotation)
317
318 def confirm_resize(self):
319 """
320 Confirm that the resize worked, thus removing the original server.
321 """
322 self.manager.confirm_resize(self)
323
324 def revert_resize(self):
325 """
326 Revert a previous resize, switching back to the old server.
327 """
328 self.manager.revert_resize(self)
329
330 @property
331 def networks(self):
332 """
333 Generate a simplified list of addresses
334 """
335 networks = {}
336 try:
337 for network_label, address_list in self.addresses.items():
338 networks[network_label] = [a['addr'] for a in address_list]
339 return networks
340 except Exception:
341 return {}
342
343 def live_migrate(self, host=None,
344 block_migration=False,
345 disk_over_commit=False):
346 """
347 Migrates a running instance to a new machine.
348 """
349 self.manager.live_migrate(self, host,
350 block_migration,
351 disk_over_commit)
352
353 def reset_state(self, state='error'):
354 """
355 Reset the state of an instance to active or error.
356 """
357 self.manager.reset_state(self, state)
358
359 def reset_network(self):
360 """
361 Reset network of an instance.
362 """
363 self.manager.reset_network(self)
364
365 def add_security_group(self, security_group):
366 """
367 Add a security group to an instance.
368 """
369 self.manager.add_security_group(self, security_group)
370
371 def remove_security_group(self, security_group):
372 """
373 Remove a security group from an instance.
374 """
375 self.manager.remove_security_group(self, security_group)
376
377 def list_security_group(self):
378 """
379 List security group(s) of an instance.
380 """
381 return self.manager.list_security_group(self)
382
383 def evacuate(self, host=None, on_shared_storage=True, password=None):
384 """
385 Evacuate an instance from failed host to specified host.
386
387 :param host: Name of the target host
388 :param on_shared_storage: Specifies whether instance files located
389 on shared storage
390 :param password: string to set as admin password on the evacuated
391 server.
392 """
393 return self.manager.evacuate(self, host, on_shared_storage, password)
394
395 def interface_list(self):
396 """
397 List interfaces attached to an instance.
398 """
399 return self.manager.interface_list(self)
400
401 def interface_attach(self, port_id, net_id, fixed_ip):
402 """
403 Attach a network interface to an instance.
404 """
405 return self.manager.interface_attach(self, port_id, net_id, fixed_ip)
406
407 def interface_detach(self, port_id):
408 """
409 Detach a network interface from an instance.
410 """
411 return self.manager.interface_detach(self, port_id)
412
413
414class ServerManager(base.BootingManagerWithFind):
415 resource_class = Server
416
417 def _boot(self, resource_url, response_key, name, image, flavor,
418 meta=None, files=None, userdata=None,
419 reservation_id=None, return_raw=False, min_count=None,
420 max_count=None, security_groups=None, key_name=None,
421 availability_zone=None, block_device_mapping=None,
422 block_device_mapping_v2=None, nics=None, scheduler_hints=None,
423 config_drive=None, admin_pass=None, disk_config=None, **kwargs):
424 """
425 Create (boot) a new server.
426
427 :param name: Something to name the server.
428 :param image: The :class:`Image` to boot with.
429 :param flavor: The :class:`Flavor` to boot onto.
430 :param meta: A dict of arbitrary key/value metadata to store for this
431 server. A maximum of five entries is allowed, and both
432 keys and values must be 255 characters or less.
433 :param files: A dict of files to overwrite on the server upon boot.
434 Keys are file names (i.e. ``/etc/passwd``) and values
435 are the file contents (either as a string or as a
436 file-like object). A maximum of five entries is allowed,
437 and each file must be 10k or less.
438 :param reservation_id: a UUID for the set of servers being requested.
439 :param return_raw: If True, don't try to coerce the result into
440 a Resource object.
441 :param security_groups: list of security group names
442 :param key_name: (optional extension) name of keypair to inject into
443 the instance
444 :param availability_zone: Name of the availability zone for instance
445 placement.
446 :param block_device_mapping: A dict of block device mappings for this
447 server.
448 :param block_device_mapping_v2: A dict of block device mappings V2 for
449 this server.
450 :param nics: (optional extension) an ordered list of nics to be
451 added to this server, with information about
452 connected networks, fixed IPs, etc.
453 :param scheduler_hints: (optional extension) arbitrary key-value pairs
454 specified by the client to help boot an instance.
455 :param config_drive: (optional extension) If True, enable config drive
456 on the server.
457 :param admin_pass: admin password for the server.
458 :param disk_config: (optional extension) control how the disk is
459 partitioned when the server is created.
460 """
461 body = {"server": {
462 "name": name,
463 "imageRef": str(base.getid(image)) if image else '',
464 "flavorRef": str(base.getid(flavor)),
465 }}
466 if userdata:
467 if hasattr(userdata, 'read'):
468 userdata = userdata.read()
469
470 if six.PY3:
471 userdata = userdata.encode("utf-8")
472 else:
473 userdata = encodeutils.safe_encode(userdata)
474
475 userdata_b64 = base64.b64encode(userdata).decode('utf-8')
476 body["server"]["user_data"] = userdata_b64
477 if meta:
478 body["server"]["metadata"] = meta
479 if reservation_id:
480 body["server"]["reservation_id"] = reservation_id
481 if key_name:
482 body["server"]["key_name"] = key_name
483 if scheduler_hints:
484 body['os:scheduler_hints'] = scheduler_hints
485 if config_drive:
486 body["server"]["config_drive"] = config_drive
487 if admin_pass:
488 body["server"]["adminPass"] = admin_pass
489 if not min_count:
490 min_count = 1
491 if not max_count:
492 max_count = min_count
493 body["server"]["min_count"] = min_count
494 body["server"]["max_count"] = max_count
495
496 if security_groups:
497 body["server"]["security_groups"] = [{'name': sg}
498 for sg in security_groups]
499
500 # Files are a slight bit tricky. They're passed in a "personality"
501 # list to the POST. Each item is a dict giving a file name and the
502 # base64-encoded contents of the file. We want to allow passing
503 # either an open file *or* some contents as files here.
504 if files:
505 personality = body['server']['personality'] = []
506 for filepath, file_or_string in sorted(files.items(),
507 key=lambda x: x[0]):
508 if hasattr(file_or_string, 'read'):
509 data = file_or_string.read()
510 else:
511 data = file_or_string
512
513 if six.PY3 and isinstance(data, str):
514 data = data.encode('utf-8')
515 cont = base64.b64encode(data).decode('utf-8')
516 personality.append({
517 'path': filepath,
518 'contents': cont,
519 })
520
521 if availability_zone:
522 body["server"]["availability_zone"] = availability_zone
523
524 # Block device mappings are passed as a list of dictionaries
525 if block_device_mapping:
526 body['server']['block_device_mapping'] = \
527 self._parse_block_device_mapping(block_device_mapping)
528 elif block_device_mapping_v2:
529 # Append the image to the list only if we have new style BDMs
530 if image:
531 bdm_dict = {'uuid': image.id, 'source_type': 'image',
532 'destination_type': 'local', 'boot_index': 0,
533 'delete_on_termination': True}
534 block_device_mapping_v2.insert(0, bdm_dict)
535
536 body['server']['block_device_mapping_v2'] = block_device_mapping_v2
537
538 if nics is not None:
539 # NOTE(tr3buchet): nics can be an empty list
540 all_net_data = []
541 for nic_info in nics:
542 net_data = {}
543 # if value is empty string, do not send value in body
544 if nic_info.get('net-id'):
545 net_data['uuid'] = nic_info['net-id']
546 if (nic_info.get('v4-fixed-ip') and
547 nic_info.get('v6-fixed-ip')):
548 raise base.exceptions.CommandError(_(
549 "Only one of 'v4-fixed-ip' and 'v6-fixed-ip' may be"
550 " provided."))
551 elif nic_info.get('v4-fixed-ip'):
552 net_data['fixed_ip'] = nic_info['v4-fixed-ip']
553 elif nic_info.get('v6-fixed-ip'):
554 net_data['fixed_ip'] = nic_info['v6-fixed-ip']
555 if nic_info.get('port-id'):
556 net_data['port'] = nic_info['port-id']
557 all_net_data.append(net_data)
558 body['server']['networks'] = all_net_data
559
560 if disk_config is not None:
561 body['server']['OS-DCF:diskConfig'] = disk_config
562
563 return self._create(resource_url, body, response_key,
564 return_raw=return_raw, **kwargs)
565
566 def get(self, server):
567 """
568 Get a server.
569
570 :param server: ID of the :class:`Server` to get.
571 :rtype: :class:`Server`
572 """
573 return self._get("/servers/%s" % base.getid(server), "server")
574
575 def list(self, detailed=True, search_opts=None, marker=None, limit=None,
576 sort_keys=None, sort_dirs=None):
577 """
578 Get a list of servers.
579
580 :param detailed: Whether to return detailed server info (optional).
581 :param search_opts: Search options to filter out servers (optional).
582 :param marker: Begin returning servers that appear later in the server
583 list than that represented by this server id (optional).
584 :param limit: Maximum number of servers to return (optional).
585 :param sort_keys: List of sort keys
586 :param sort_dirs: List of sort directions
587
588 :rtype: list of :class:`Server`
589 """
590 if search_opts is None:
591 search_opts = {}
592
593 qparams = {}
594
595 for opt, val in six.iteritems(search_opts):
596 if val:
597 qparams[opt] = val
598
599 if marker:
600 qparams['marker'] = marker
601
602 if limit:
603 qparams['limit'] = limit
604
605 # Transform the dict to a sequence of two-element tuples in fixed
606 # order, then the encoded string will be consistent in Python 2&3.
607 if qparams or sort_keys or sort_dirs:
608 # sort keys and directions are unique since the same parameter
609 # key is repeated for each associated value
610 # (ie, &sort_key=key1&sort_key=key2&sort_key=key3)
611 items = list(qparams.items())
612 if sort_keys:
613 items.extend(('sort_key', sort_key) for sort_key in sort_keys)
614 if sort_dirs:
615 items.extend(('sort_dir', sort_dir) for sort_dir in sort_dirs)
616 new_qparams = sorted(items, key=lambda x: x[0])
617 query_string = "?%s" % parse.urlencode(new_qparams)
618 else:
619 query_string = ""
620
621 detail = ""
622 if detailed:
623 detail = "/detail"
624 return self._list("/servers%s%s" % (detail, query_string), "servers")
625
626 def add_fixed_ip(self, server, network_id):
627 """
628 Add an IP address on a network.
629
630 :param server: The :class:`Server` (or its ID) to add an IP to.
631 :param network_id: The ID of the network the IP should be on.
632 """
633 self._action('addFixedIp', server, {'networkId': network_id})
634
635 def remove_fixed_ip(self, server, address):
636 """
637 Remove an IP address.
638
639 :param server: The :class:`Server` (or its ID) to add an IP to.
640 :param address: The IP address to remove.
641 """
642 self._action('removeFixedIp', server, {'address': address})
643
644 def add_floating_ip(self, server, address, fixed_address=None):
645 """
646 Add a floating IP to an instance
647
648 :param server: The :class:`Server` (or its ID) to add an IP to.
649 :param address: The FloatingIP or string floating address to add.
650 :param fixed_address: The FixedIP the floatingIP should be
651 associated with (optional)
652 """
653
654 address = address.ip if hasattr(address, 'ip') else address
655 if fixed_address:
656 if hasattr(fixed_address, 'ip'):
657 fixed_address = fixed_address.ip
658 self._action('addFloatingIp', server,
659 {'address': address, 'fixed_address': fixed_address})
660 else:
661 self._action('addFloatingIp', server, {'address': address})
662
663 def remove_floating_ip(self, server, address):
664 """
665 Remove a floating IP address.
666
667 :param server: The :class:`Server` (or its ID) to remove an IP from.
668 :param address: The FloatingIP or string floating address to remove.
669 """
670
671 address = address.ip if hasattr(address, 'ip') else address
672 self._action('removeFloatingIp', server, {'address': address})
673
674 def get_vnc_console(self, server, console_type):
675 """
676 Get a vnc console for an instance
677
678 :param server: The :class:`Server` (or its ID) to add an IP to.
679 :param console_type: Type of vnc console to get ('novnc' or 'xvpvnc')
680 """
681
682 return self._action('os-getVNCConsole', server,
683 {'type': console_type})[1]
684
685 def get_spice_console(self, server, console_type):
686 """
687 Get a spice console for an instance
688
689 :param server: The :class:`Server` (or its ID) to add an IP to.
690 :param console_type: Type of spice console to get ('spice-html5')
691 """
692
693 return self._action('os-getSPICEConsole', server,
694 {'type': console_type})[1]
695
696 def get_rdp_console(self, server, console_type):
697 """
698 Get a rdp console for an instance
699
700 :param server: The :class:`Server` (or its ID) to add an IP to.
701 :param console_type: Type of rdp console to get ('rdp-html5')
702 """
703
704 return self._action('os-getRDPConsole', server,
705 {'type': console_type})[1]
706
707 def get_serial_console(self, server, console_type):
708 """
709 Get a serial console for an instance
710
711 :param server: The :class:`Server` (or its ID) to add an IP to.
712 :param console_type: Type of serial console to get ('serial')
713 """
714
715 return self._action('os-getSerialConsole', server,
716 {'type': console_type})[1]
717
718 def get_password(self, server, private_key=None):
719 """
720 Get admin password of an instance
721
722 Returns the admin password of an instance in the clear if private_key
723 is provided, returns the ciphered password otherwise.
724
725 Requires that openssl is installed and in the path
726
727 :param server: The :class:`Server` (or its ID) for which the admin
728 password is to be returned
729 :param private_key: The private key to decrypt password
730 (optional)
731 """
732
733 _resp, body = self.api.client.get("/servers/%s/os-server-password"
734 % base.getid(server))
735 ciphered_pw = body.get('password', '') if body else ''
736 if private_key and ciphered_pw:
737 try:
738 return crypto.decrypt_password(private_key, ciphered_pw)
739 except Exception as exc:
740 return '%sFailed to decrypt:\n%s' % (exc, ciphered_pw)
741 return ciphered_pw
742
743 def clear_password(self, server):
744 """
745 Clear the admin password of an instance
746
747 Remove the admin password for an instance from the metadata server.
748
749 :param server: The :class:`Server` (or its ID) for which the admin
750 password is to be cleared
751 """
752
753 return self._delete("/servers/%s/os-server-password"
754 % base.getid(server))
755
756 def stop(self, server):
757 """
758 Stop the server.
759 """
760 return self._action('os-stop', server, None)
761
762 def force_delete(self, server):
763 """
764 Force delete the server.
765 """
766 return self._action('forceDelete', server, None)
767
768 def restore(self, server):
769 """
770 Restore soft-deleted server.
771 """
772 return self._action('restore', server, None)
773
774 def start(self, server):
775 """
776 Start the server.
777 """
778 self._action('os-start', server, None)
779
780 def pause(self, server):
781 """
782 Pause the server.
783 """
784 self._action('pause', server, None)
785
786 def unpause(self, server):
787 """
788 Unpause the server.
789 """
790 self._action('unpause', server, None)
791
792 def lock(self, server):
793 """
794 Lock the server.
795 """
796 self._action('lock', server, None)
797
798 def unlock(self, server):
799 """
800 Unlock the server.
801 """
802 self._action('unlock', server, None)
803
804 def suspend(self, server):
805 """
806 Suspend the server.
807 """
808 self._action('suspend', server, None)
809
810 def resume(self, server):
811 """
812 Resume the server.
813 """
814 self._action('resume', server, None)
815
816 def rescue(self, server, password=None, image=None):
817 """
818 Rescue the server.
819
820 :param server: The :class:`Server` to rescue.
821 :param password: The admin password to be set in the rescue instance.
822 :param image: The :class:`Image` to rescue with.
823 """
824 info = {}
825 if password:
826 info['adminPass'] = password
827 if image:
828 info['rescue_image_ref'] = base.getid(image)
829 return self._action('rescue', server, info or None)
830
831 def unrescue(self, server):
832 """
833 Unrescue the server.
834 """
835 self._action('unrescue', server, None)
836
837 def shelve(self, server):
838 """
839 Shelve the server.
840 """
841 self._action('shelve', server, None)
842
843 def shelve_offload(self, server):
844 """
845 Remove a shelved instance from the compute node.
846 """
847 self._action('shelveOffload', server, None)
848
849 def unshelve(self, server):
850 """
851 Unshelve the server.
852 """
853 self._action('unshelve', server, None)
854
855 def diagnostics(self, server):
856 """Retrieve server diagnostics."""
857 return self.api.client.get("/servers/%s/diagnostics" %
858 base.getid(server))
859
860 def create(self, name, image, flavor, meta=None, files=None,
861 reservation_id=None, min_count=None,
862 max_count=None, security_groups=None, userdata=None,
863 key_name=None, availability_zone=None,
864 block_device_mapping=None, block_device_mapping_v2=None,
865 nics=None, scheduler_hints=None,
866 config_drive=None, disk_config=None, **kwargs):
867 # TODO(anthony): indicate in doc string if param is an extension
868 # and/or optional
869 """
870 Create (boot) a new server.
871
872 :param name: Something to name the server.
873 :param image: The :class:`Image` to boot with.
874 :param flavor: The :class:`Flavor` to boot onto.
875 :param meta: A dict of arbitrary key/value metadata to store for this
876 server. A maximum of five entries is allowed, and both
877 keys and values must be 255 characters or less.
878 :param files: A dict of files to overrwrite on the server upon boot.
879 Keys are file names (i.e. ``/etc/passwd``) and values
880 are the file contents (either as a string or as a
881 file-like object). A maximum of five entries is allowed,
882 and each file must be 10k or less.
883 :param userdata: user data to pass to be exposed by the metadata
884 server this can be a file type object as well or a
885 string.
886 :param reservation_id: a UUID for the set of servers being requested.
887 :param key_name: (optional extension) name of previously created
888 keypair to inject into the instance.
889 :param availability_zone: Name of the availability zone for instance
890 placement.
891 :param block_device_mapping: (optional extension) A dict of block
892 device mappings for this server.
893 :param block_device_mapping_v2: (optional extension) A dict of block
894 device mappings for this server.
895 :param nics: (optional extension) an ordered list of nics to be
896 added to this server, with information about
897 connected networks, fixed IPs, port etc.
898 :param scheduler_hints: (optional extension) arbitrary key-value pairs
899 specified by the client to help boot an instance
900 :param config_drive: (optional extension) value for config drive
901 either boolean, or volume-id
902 :param disk_config: (optional extension) control how the disk is
903 partitioned when the server is created. possible
904 values are 'AUTO' or 'MANUAL'.
905 """
906 if not min_count:
907 min_count = 1
908 if not max_count:
909 max_count = min_count
910 if min_count > max_count:
911 min_count = max_count
912
913 boot_args = [name, image, flavor]
914
915 boot_kwargs = dict(
916 meta=meta, files=files, userdata=userdata,
917 reservation_id=reservation_id, min_count=min_count,
918 max_count=max_count, security_groups=security_groups,
919 key_name=key_name, availability_zone=availability_zone,
920 scheduler_hints=scheduler_hints, config_drive=config_drive,
921 disk_config=disk_config, **kwargs)
922
923 if block_device_mapping:
924 resource_url = "/os-volumes_boot"
925 boot_kwargs['block_device_mapping'] = block_device_mapping
926 elif block_device_mapping_v2:
927 resource_url = "/os-volumes_boot"
928 boot_kwargs['block_device_mapping_v2'] = block_device_mapping_v2
929 else:
930 resource_url = "/servers"
931 if nics:
932 boot_kwargs['nics'] = nics
933
934 response_key = "server"
935 return self._boot(resource_url, response_key, *boot_args,
936 **boot_kwargs)
937
938 def update(self, server, name=None):
939 """
940 Update the name or the password for a server.
941
942 :param server: The :class:`Server` (or its ID) to update.
943 :param name: Update the server's name.
944 """
945 if name is None:
946 return
947
948 body = {
949 "server": {
950 "name": name,
951 },
952 }
953
954 return self._update("/servers/%s" % base.getid(server), body, "server")
955
956 def change_password(self, server, password):
957 """
958 Update the password for a server.
959 """
960 self._action("changePassword", server, {"adminPass": password})
961
962 def delete(self, server):
963 """
964 Delete (i.e. shut down and delete the image) this server.
965 """
966 self._delete("/servers/%s" % base.getid(server))
967
968 def reboot(self, server, reboot_type=REBOOT_SOFT):
969 """
970 Reboot a server.
971
972 :param server: The :class:`Server` (or its ID) to share onto.
973 :param reboot_type: either :data:`REBOOT_SOFT` for a software-level
974 reboot, or `REBOOT_HARD` for a virtual power cycle hard reboot.
975 """
976 self._action('reboot', server, {'type': reboot_type})
977
978 def rebuild(self, server, image, password=None, disk_config=None,
979 preserve_ephemeral=False, name=None, meta=None, files=None,
980 **kwargs):
981 """
982 Rebuild -- shut down and then re-image -- a server.
983
984 :param server: The :class:`Server` (or its ID) to share onto.
985 :param image: the :class:`Image` (or its ID) to re-image with.
986 :param password: string to set as password on the rebuilt server.
987 :param disk_config: partitioning mode to use on the rebuilt server.
988 Valid values are 'AUTO' or 'MANUAL'
989 :param preserve_ephemeral: If True, request that any ephemeral device
990 be preserved when rebuilding the instance. Defaults to False.
991 :param name: Something to name the server.
992 :param meta: A dict of arbitrary key/value metadata to store for this
993 server. A maximum of five entries is allowed, and both
994 keys and values must be 255 characters or less.
995 :param files: A dict of files to overwrite on the server upon boot.
996 Keys are file names (i.e. ``/etc/passwd``) and values
997 are the file contents (either as a string or as a
998 file-like object). A maximum of five entries is allowed,
999 and each file must be 10k or less.
1000 """
1001 body = {'imageRef': base.getid(image)}
1002 if password is not None:
1003 body['adminPass'] = password
1004 if disk_config is not None:
1005 body['OS-DCF:diskConfig'] = disk_config
1006 if preserve_ephemeral is not False:
1007 body['preserve_ephemeral'] = True
1008 if name is not None:
1009 body['name'] = name
1010 if meta:
1011 body['metadata'] = meta
1012 if files:
1013 personality = body['personality'] = []
1014 for filepath, file_or_string in sorted(files.items(),
1015 key=lambda x: x[0]):
1016 if hasattr(file_or_string, 'read'):
1017 data = file_or_string.read()
1018 else:
1019 data = file_or_string
1020
1021 cont = base64.b64encode(data.encode('utf-8')).decode('utf-8')
1022 personality.append({
1023 'path': filepath,
1024 'contents': cont,
1025 })
1026
1027 _resp, body = self._action('rebuild', server, body, **kwargs)
1028 return Server(self, body['server'])
1029
1030 def migrate(self, server):
1031 """
1032 Migrate a server to a new host.
1033
1034 :param server: The :class:`Server` (or its ID).
1035 """
1036 self._action('migrate', server)
1037
1038 def resize(self, server, flavor, disk_config=None, **kwargs):
1039 """
1040 Resize a server's resources.
1041
1042 :param server: The :class:`Server` (or its ID) to share onto.
1043 :param flavor: the :class:`Flavor` (or its ID) to resize to.
1044 :param disk_config: partitioning mode to use on the rebuilt server.
1045 Valid values are 'AUTO' or 'MANUAL'
1046
1047 Until a resize event is confirmed with :meth:`confirm_resize`, the old
1048 server will be kept around and you'll be able to roll back to the old
1049 flavor quickly with :meth:`revert_resize`. All resizes are
1050 automatically confirmed after 24 hours.
1051 """
1052 info = {'flavorRef': base.getid(flavor)}
1053 if disk_config is not None:
1054 info['OS-DCF:diskConfig'] = disk_config
1055
1056 self._action('resize', server, info=info, **kwargs)
1057
1058 def confirm_resize(self, server):
1059 """
1060 Confirm that the resize worked, thus removing the original server.
1061
1062 :param server: The :class:`Server` (or its ID) to share onto.
1063 """
1064 self._action('confirmResize', server)
1065
1066 def revert_resize(self, server):
1067 """
1068 Revert a previous resize, switching back to the old server.
1069
1070 :param server: The :class:`Server` (or its ID) to share onto.
1071 """
1072 self._action('revertResize', server)
1073
1074 def create_image(self, server, image_name, metadata=None):
1075 """
1076 Snapshot a server.
1077
1078 :param server: The :class:`Server` (or its ID) to share onto.
1079 :param image_name: Name to give the snapshot image
1080 :param metadata: Metadata to give newly-created image entity
1081 """
1082 body = {'name': image_name, 'metadata': metadata or {}}
1083 resp = self._action('createImage', server, body)[0]
1084 location = resp.headers['location']
1085 image_uuid = location.split('/')[-1]
1086 return image_uuid
1087
1088 def backup(self, server, backup_name, backup_type, rotation):
1089 """
1090 Backup a server instance.
1091
1092 :param server: The :class:`Server` (or its ID) to share onto.
1093 :param backup_name: Name of the backup image
1094 :param backup_type: The backup type, like 'daily' or 'weekly'
1095 :param rotation: Int parameter representing how many backups to
1096 keep around.
1097 """
1098 body = {'name': backup_name,
1099 'backup_type': backup_type,
1100 'rotation': rotation}
1101 self._action('createBackup', server, body)
1102
1103 def set_meta(self, server, metadata):
1104 """
1105 Set a servers metadata
1106 :param server: The :class:`Server` to add metadata to
1107 :param metadata: A dict of metadata to add to the server
1108 """
1109 body = {'metadata': metadata}
1110 return self._create("/servers/%s/metadata" % base.getid(server),
1111 body, "metadata")
1112
1113 def set_meta_item(self, server, key, value):
1114 """
1115 Updates an item of server metadata
1116 :param server: The :class:`Server` to add metadata to
1117 :param key: metadata key to update
1118 :param value: string value
1119 """
1120 body = {'meta': {key: value}}
1121 return self._update("/servers/%s/metadata/%s" %
1122 (base.getid(server), key), body)
1123
1124 def get_console_output(self, server, length=None):
1125 """
1126 Get text console log output from Server.
1127
1128 :param server: The :class:`Server` (or its ID) whose console output
1129 you would like to retrieve.
1130 :param length: The number of tail loglines you would like to retrieve.
1131 """
1132 return self._action('os-getConsoleOutput',
1133 server,
1134 {'length': length})[1]['output']
1135
1136 def delete_meta(self, server, keys):
1137 """
1138 Delete metadata from an server
1139 :param server: The :class:`Server` to add metadata to
1140 :param keys: A list of metadata keys to delete from the server
1141 """
1142 for k in keys:
1143 self._delete("/servers/%s/metadata/%s" % (base.getid(server), k))
1144
1145 def live_migrate(self, server, host, block_migration, disk_over_commit):
1146 """
1147 Migrates a running instance to a new machine.
1148
1149 :param server: instance id which comes from nova list.
1150 :param host: destination host name.
1151 :param block_migration: if True, do block_migration.
1152 :param disk_over_commit: if True, Allow overcommit.
1153
1154 """
1155 self._action('os-migrateLive', server,
1156 {'host': host,
1157 'block_migration': block_migration,
1158 'disk_over_commit': disk_over_commit})
1159
1160 def reset_state(self, server, state='error'):
1161 """
1162 Reset the state of an instance to active or error.
1163
1164 :param server: ID of the instance to reset the state of.
1165 :param state: Desired state; either 'active' or 'error'.
1166 Defaults to 'error'.
1167 """
1168 self._action('os-resetState', server, dict(state=state))
1169
1170 def reset_network(self, server):
1171 """
1172 Reset network of an instance.
1173 """
1174 self._action('resetNetwork', server)
1175
1176 def add_security_group(self, server, security_group):
1177 """
1178 Add a Security Group to an instance
1179
1180 :param server: ID of the instance.
1181 :param security_group: The name of security group to add.
1182
1183 """
1184 self._action('addSecurityGroup', server, {'name': security_group})
1185
1186 def remove_security_group(self, server, security_group):
1187 """
1188 Add a Security Group to an instance
1189
1190 :param server: ID of the instance.
1191 :param security_group: The name of security group to remove.
1192
1193 """
1194 self._action('removeSecurityGroup', server, {'name': security_group})
1195
1196 def list_security_group(self, server):
1197 """
1198 List Security Group(s) of an instance
1199
1200 :param server: ID of the instance.
1201
1202 """
1203 return self._list('/servers/%s/os-security-groups' %
1204 base.getid(server), 'security_groups',
1205 security_groups.SecurityGroup)
1206
1207 def evacuate(self, server, host=None, on_shared_storage=True,
1208 password=None):
1209 """
1210 Evacuate a server instance.
1211
1212 :param server: The :class:`Server` (or its ID) to share onto.
1213 :param host: Name of the target host.
1214 :param on_shared_storage: Specifies whether instance files located
1215 on shared storage
1216 :param password: string to set as password on the evacuated server.
1217 """
1218
1219 body = {'onSharedStorage': on_shared_storage}
1220 if host is not None:
1221 body['host'] = host
1222
1223 if password is not None:
1224 body['adminPass'] = password
1225
1226 return self._action('evacuate', server, body)
1227
1228 def interface_list(self, server):
1229 """
1230 List attached network interfaces
1231
1232 :param server: The :class:`Server` (or its ID) to query.
1233 """
1234 return self._list('/servers/%s/os-interface' % base.getid(server),
1235 'interfaceAttachments')
1236
1237 def interface_attach(self, server, port_id, net_id, fixed_ip):
1238 """
1239 Attach a network_interface to an instance.
1240
1241 :param server: The :class:`Server` (or its ID) to attach to.
1242 :param port_id: The port to attach.
1243 """
1244
1245 body = {'interfaceAttachment': {}}
1246 if port_id:
1247 body['interfaceAttachment']['port_id'] = port_id
1248 if net_id:
1249 body['interfaceAttachment']['net_id'] = net_id
1250 if fixed_ip:
1251 body['interfaceAttachment']['fixed_ips'] = [
1252 {'ip_address': fixed_ip}]
1253
1254 return self._create('/servers/%s/os-interface' % base.getid(server),
1255 body, 'interfaceAttachment')
1256
1257 def interface_detach(self, server, port_id):
1258 """
1259 Detach a network_interface from an instance.
1260
1261 :param server: The :class:`Server` (or its ID) to detach from.
1262 :param port_id: The port to detach.
1263 """
1264 self._delete('/servers/%s/os-interface/%s' % (base.getid(server),
1265 port_id))
1266
1267 def _action(self, action, server, info=None, **kwargs):
1268 """
1269 Perform a server "action" -- reboot/rebuild/resize/etc.
1270 """
1271 body = {action: info}
1272 self.run_hooks('modify_body_for_action', body, **kwargs)
1273 url = '/servers/%s/action' % base.getid(server)
1274 return self.api.client.post(url, body=body)