Add support for instance evacuate.
This adds support for server evacuation from failed host. Adds CLI command: nova evacuate <server> <host> [--password pwd] [--on-shared-storage] Depends on the approval of change: https://review.openstack.org/#change,17991 Change-Id: Icd91c0484b2db532861e23163d043737ad04117a
This commit is contained in:
parent
4410339a45
commit
9e319ece37
@ -108,6 +108,7 @@ You'll find complete documentation on the shell by running
|
||||
and name.
|
||||
endpoints Discover endpoints that get returned from the
|
||||
authenticate services
|
||||
evacuate Evacuate a server from failed host
|
||||
flavor-create Create a new flavor
|
||||
flavor-delete Delete a specific flavor
|
||||
flavor-list Print a list of available 'flavors' (sizes of
|
||||
|
@ -281,6 +281,17 @@ class Server(base.Resource):
|
||||
"""
|
||||
self.manager.remove_security_group(self, security_group)
|
||||
|
||||
def evacuate(self, host, on_shared_storage, password=None):
|
||||
"""
|
||||
Evacuate an instance from failed host to specified host.
|
||||
|
||||
:param host: Name of the target host
|
||||
:param on_shared_storage: Specifies whether instance files located
|
||||
on shared storage
|
||||
:param password: string to set as password on the evacuated server.
|
||||
"""
|
||||
return self.manager.evacuate(self, host, on_shared_storage, password)
|
||||
|
||||
|
||||
class ServerManager(local_base.BootingManagerWithFind):
|
||||
resource_class = Server
|
||||
@ -707,6 +718,26 @@ class ServerManager(local_base.BootingManagerWithFind):
|
||||
"""
|
||||
self._action('removeSecurityGroup', server, {'name': security_group})
|
||||
|
||||
def evacuate(self, server, host, on_shared_storage, password=None):
|
||||
"""
|
||||
Evacuate a server instance.
|
||||
|
||||
:param server: The :class:`Server` (or its ID) to share onto.
|
||||
:param host: Name of the target host.
|
||||
:param on_shared_storage: Specifies whether instance files located
|
||||
on shared storage
|
||||
:param password: string to set as password on the evacuated server.
|
||||
"""
|
||||
body = {
|
||||
'host': host,
|
||||
'onSharedStorage': on_shared_storage,
|
||||
}
|
||||
|
||||
if password is not None:
|
||||
body['adminPass'] = password
|
||||
|
||||
return self._action('evacuate', server, body)
|
||||
|
||||
def _action(self, action, server, info=None, **kwargs):
|
||||
"""
|
||||
Perform a server "action" -- reboot/rebuild/resize/etc.
|
||||
|
@ -2701,3 +2701,25 @@ def do_quota_class_update(cs, args):
|
||||
"""Update the quotas for a quota class."""
|
||||
|
||||
_quota_update(cs.quota_classes, args.class_name, args)
|
||||
|
||||
|
||||
@utils.arg('server', metavar='<server>', help='Name or ID of server.')
|
||||
@utils.arg('host', metavar='<host>', help='Name or ID of target host.')
|
||||
@utils.arg('--password',
|
||||
dest='password',
|
||||
metavar='<password>',
|
||||
default=None,
|
||||
help="Set the provided password on the evacuated instance. Not applicable "
|
||||
"with on-shared-storage flag")
|
||||
@utils.arg('--on-shared-storage',
|
||||
dest='on_shared_storage',
|
||||
action="store_true",
|
||||
default=False,
|
||||
help='Specifies whether instance files located on shared storage')
|
||||
def do_evacuate(cs, args):
|
||||
"""Evacuate server from failed host to specified one."""
|
||||
server = _find_server(cs, args.server)
|
||||
|
||||
res = server.evacuate(args.host, args.on_shared_storage, args.password)[0]
|
||||
if type(res) is dict:
|
||||
utils.print_dict(res)
|
||||
|
@ -489,6 +489,11 @@ class FakeHTTPClient(base_client.HTTPClient):
|
||||
assert set(body[action].keys()) == set(['name',
|
||||
'backup_type',
|
||||
'rotation'])
|
||||
elif action == 'evacuate':
|
||||
keys = body[action].keys()
|
||||
if 'adminPass' in keys:
|
||||
keys.remove('adminPass')
|
||||
assert set(keys) == set(['host', 'onSharedStorage'])
|
||||
else:
|
||||
raise AssertionError("Unexpected server action: %s" % action)
|
||||
return (resp, _headers, _body)
|
||||
|
@ -399,3 +399,10 @@ class ServersTest(utils.TestCase):
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
cs.servers.remove_security_group(s, 'oldsg')
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
|
||||
def test_evacuate(self):
|
||||
s = cs.servers.get(1234)
|
||||
s.evacuate('fake_target_host', 'True')
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
cs.servers.evacuate(s, 'fake_target_host', 'False', 'NewAdminPassword')
|
||||
cs.assert_called('POST', '/servers/1234/action')
|
||||
|
@ -790,3 +790,24 @@ class ShellTest(utils.TestCase):
|
||||
|
||||
self.run_command('absolute-limits --reserved')
|
||||
self.assert_called('GET', '/limits?reserved=1')
|
||||
|
||||
def test_evacuate(self):
|
||||
self.run_command('evacuate sample-server new_host')
|
||||
self.assert_called('POST', '/servers/1234/action',
|
||||
{'evacuate': {'host': 'new_host',
|
||||
'onSharedStorage': False}})
|
||||
self.run_command('evacuate sample-server new_host '
|
||||
'--password NewAdminPass')
|
||||
self.assert_called('POST', '/servers/1234/action',
|
||||
{'evacuate': {'host': 'new_host',
|
||||
'onSharedStorage': False,
|
||||
'adminPass': 'NewAdminPass'}})
|
||||
self.run_command('evacuate sample-server new_host')
|
||||
self.assert_called('POST', '/servers/1234/action',
|
||||
{'evacuate': {'host': 'new_host',
|
||||
'onSharedStorage': False}})
|
||||
self.run_command('evacuate sample-server new_host '
|
||||
'--on-shared-storage')
|
||||
self.assert_called('POST', '/servers/1234/action',
|
||||
{'evacuate': {'host': 'new_host',
|
||||
'onSharedStorage': True}})
|
||||
|
Loading…
x
Reference in New Issue
Block a user