summaryrefslogtreecommitdiff
path: root/openstackclient/compute
diff options
context:
space:
mode:
authorSean Mooney <work@seanmooney.info>2019-03-15 13:03:10 +0000
committerStephen Finucane <sfinucan@redhat.com>2020-11-02 17:08:17 +0000
commit01eb4e839394fe433a92a06daf1499fb00f2fe69 (patch)
treedd77dc8337d8b714a567241c977072c636031188 /openstackclient/compute
parent7fdbc6b8af681fc48bd3a78822ffab52c29329ac (diff)
downloadpython-openstackclient-01eb4e839394fe433a92a06daf1499fb00f2fe69.tar.gz
Add 'openstack server evacuate' command
This change adds a new 'openstack server evacuate' command to provide parity with the 'nova evacuate' command. The term "evacuate" is notoriously poor, in that it implies the instance is moved rather than recreated, but it is retained since people are familiar with it now. Change-Id: I1e32ca51036c501862d8e89b3144a9695d98a06f
Diffstat (limited to 'openstackclient/compute')
-rw-r--r--openstackclient/compute/v2/server.py112
1 files changed, 112 insertions, 0 deletions
diff --git a/openstackclient/compute/v2/server.py b/openstackclient/compute/v2/server.py
index 294b4683..7f1bc088 100644
--- a/openstackclient/compute/v2/server.py
+++ b/openstackclient/compute/v2/server.py
@@ -2502,6 +2502,118 @@ class RebuildServer(command.ShowOne):
return zip(*sorted(details.items()))
+class EvacuateServer(command.ShowOne):
+ _description = _("""Evacuate a server to a different host.
+
+This command is used to recreate a server after the host it was on has failed.
+It can only be used if the compute service that manages the server is down.
+This command should only be used by an admin after they have confirmed that the
+instance is not running on the failed host.
+
+If the server instance was created with an ephemeral root disk on non-shared
+storage the server will be rebuilt using the original glance image preserving
+the ports and any attached data volumes.
+
+If the server uses boot for volume or has its root disk on shared storage the
+root disk will be preserved and reused for the evacuated instance on the new
+host.""")
+
+ def get_parser(self, prog_name):
+ parser = super(EvacuateServer, self).get_parser(prog_name)
+ parser.add_argument(
+ 'server',
+ metavar='<server>',
+ help=_('Server (name or ID)'),
+ )
+
+ parser.add_argument(
+ '--wait', action='store_true',
+ help=_('Wait for evacuation to complete'),
+ )
+ parser.add_argument(
+ '--host', metavar='<host>', default=None,
+ help=_(
+ 'Set the preferred host on which to rebuild the evacuated '
+ 'server. The host will be validated by the scheduler. '
+ '(supported by --os-compute-api-version 2.29 or above)'
+ ),
+ )
+ shared_storage_group = parser.add_mutually_exclusive_group()
+ shared_storage_group.add_argument(
+ '--password', metavar='<password>', default=None,
+ help=_(
+ 'Set the password on the evacuated instance. This option is '
+ 'mutually exclusive with the --shared-storage option'
+ ),
+ )
+ shared_storage_group.add_argument(
+ '--shared-storage', action='store_true', dest='shared_storage',
+ help=_(
+ 'Indicate that the instance is on shared storage. '
+ 'This will be auto-calculated with '
+ '--os-compute-api-version 2.14 and greater and should not '
+ 'be used with later microversions. This option is mutually '
+ 'exclusive with the --password option'
+ ),
+ )
+ return parser
+
+ def take_action(self, parsed_args):
+
+ def _show_progress(progress):
+ if progress:
+ self.app.stdout.write('\rProgress: %s' % progress)
+ self.app.stdout.flush()
+
+ compute_client = self.app.client_manager.compute
+ image_client = self.app.client_manager.image
+
+ if parsed_args.host:
+ if compute_client.api_version < api_versions.APIVersion('2.29'):
+ msg = _(
+ '--os-compute-api-version 2.29 or later is required '
+ 'to specify a preferred host.'
+ )
+ raise exceptions.CommandError(msg)
+
+ if parsed_args.shared_storage:
+ if compute_client.api_version > api_versions.APIVersion('2.13'):
+ msg = _(
+ '--os-compute-api-version 2.13 or earlier is required '
+ 'to specify shared-storage.'
+ )
+ raise exceptions.CommandError(msg)
+
+ kwargs = {
+ 'host': parsed_args.host,
+ 'password': parsed_args.password,
+ }
+
+ if compute_client.api_version <= api_versions.APIVersion('2.13'):
+ kwargs['on_shared_storage'] = parsed_args.shared_storage
+
+ server = utils.find_resource(
+ compute_client.servers, parsed_args.server)
+
+ server = server.evacuate(**kwargs)
+
+ if parsed_args.wait:
+ if utils.wait_for_status(
+ compute_client.servers.get,
+ server.id,
+ callback=_show_progress,
+ ):
+ self.app.stdout.write(_('Complete\n'))
+ else:
+ LOG.error(_('Error evacuating server: %s'), server.id)
+ self.app.stdout.write(_('Error evacuating server\n'))
+ raise SystemExit
+
+ details = _prep_server_detail(
+ compute_client, image_client, server, refresh=False)
+ return zip(*sorted(details.items()))
+
+
class RemoveFixedIP(command.Command):
_description = _("Remove fixed IP address from server")