Live migrate each instance from one host to other hosts
Using the existing server live_migrate api, this new feature, adds the ability for admins to live-migrate all running instances from one host to other hosts. The patch implements the feature for Nova API V2 and API V3. Co-Authored-By: Cédric Soulas <cedric.soulas@cloudwatt.com> Change-Id: Ie8dd1b66fb8eaefa6ff38752b1e4f46bab145820 Implements: blueprint host-servers-live-migrate
This commit is contained in:
parent
2a1c07e790
commit
a400b58d03
|
@ -1389,6 +1389,51 @@ class ShellTest(utils.TestCase):
|
|||
'block_migration': True,
|
||||
'disk_over_commit': True}})
|
||||
|
||||
def test_host_evacuate_live_with_no_target_host(self):
|
||||
self.run_command('host-evacuate-live hyper')
|
||||
self.assert_called('GET', '/os-hypervisors/hyper/servers', pos=0)
|
||||
body = {'os-migrateLive': {'host': None,
|
||||
'block_migration': False,
|
||||
'disk_over_commit': False}}
|
||||
self.assert_called('POST', '/servers/uuid1/action', body, pos=1)
|
||||
self.assert_called('POST', '/servers/uuid2/action', body, pos=2)
|
||||
self.assert_called('POST', '/servers/uuid3/action', body, pos=3)
|
||||
self.assert_called('POST', '/servers/uuid4/action', body, pos=4)
|
||||
|
||||
def test_host_evacuate_live_with_target_host(self):
|
||||
self.run_command('host-evacuate-live hyper '
|
||||
'--target-host hostname')
|
||||
self.assert_called('GET', '/os-hypervisors/hyper/servers', pos=0)
|
||||
body = {'os-migrateLive': {'host': 'hostname',
|
||||
'block_migration': False,
|
||||
'disk_over_commit': False}}
|
||||
self.assert_called('POST', '/servers/uuid1/action', body, pos=1)
|
||||
self.assert_called('POST', '/servers/uuid2/action', body, pos=2)
|
||||
self.assert_called('POST', '/servers/uuid3/action', body, pos=3)
|
||||
self.assert_called('POST', '/servers/uuid4/action', body, pos=4)
|
||||
|
||||
def test_host_evacuate_live_with_block_migration(self):
|
||||
self.run_command('host-evacuate-live --block-migrate hyper')
|
||||
self.assert_called('GET', '/os-hypervisors/hyper/servers', pos=0)
|
||||
body = {'os-migrateLive': {'host': None,
|
||||
'block_migration': True,
|
||||
'disk_over_commit': False}}
|
||||
self.assert_called('POST', '/servers/uuid1/action', body, pos=1)
|
||||
self.assert_called('POST', '/servers/uuid2/action', body, pos=2)
|
||||
self.assert_called('POST', '/servers/uuid3/action', body, pos=3)
|
||||
self.assert_called('POST', '/servers/uuid4/action', body, pos=4)
|
||||
|
||||
def test_host_evacuate_live_with_disk_over_commit(self):
|
||||
self.run_command('host-evacuate-live --disk-over-commit hyper')
|
||||
self.assert_called('GET', '/os-hypervisors/hyper/servers', pos=0)
|
||||
body = {'os-migrateLive': {'host': None,
|
||||
'block_migration': False,
|
||||
'disk_over_commit': True}}
|
||||
self.assert_called('POST', '/servers/uuid1/action', body, pos=1)
|
||||
self.assert_called('POST', '/servers/uuid2/action', body, pos=2)
|
||||
self.assert_called('POST', '/servers/uuid3/action', body, pos=3)
|
||||
self.assert_called('POST', '/servers/uuid4/action', body, pos=4)
|
||||
|
||||
def test_reset_state(self):
|
||||
self.run_command('reset-state sample-server')
|
||||
self.assert_called('POST', '/servers/1234/action',
|
||||
|
|
|
@ -335,6 +335,10 @@ class FakeHTTPClient(fakes_v1_1.FakeHTTPClient):
|
|||
# Hypervisors
|
||||
#
|
||||
def get_os_hypervisors_search(self, **kw):
|
||||
if kw['query'] == 'hyper1':
|
||||
return (200, {}, {'hypervisors': [
|
||||
{'id': 1234, 'hypervisor_hostname': 'hyper1'},
|
||||
]})
|
||||
return (200, {}, {'hypervisors': [
|
||||
{'id': 1234, 'hypervisor_hostname': 'hyper1'},
|
||||
{'id': 5678, 'hypervisor_hostname': 'hyper2'}
|
||||
|
|
|
@ -644,6 +644,47 @@ class ShellTest(utils.TestCase):
|
|||
self.assert_called('GET', '/flavors/2', pos=3)
|
||||
self.assert_called('GET', '/flavors/2/flavor-extra-specs', pos=4)
|
||||
|
||||
def test_host_evacuate_live_with_no_target_host(self):
|
||||
self.run_command('host-evacuate-live hyper1')
|
||||
self.assert_called('GET', '/os-hypervisors/search?query=hyper1', pos=0)
|
||||
self.assert_called('GET', '/os-hypervisors/1234/servers', pos=1)
|
||||
body = {'migrate_live': {'host': None,
|
||||
'block_migration': False,
|
||||
'disk_over_commit': False}}
|
||||
self.assert_called('POST', '/servers/uuid1/action', body, pos=2)
|
||||
self.assert_called('POST', '/servers/uuid2/action', body, pos=3)
|
||||
|
||||
def test_host_evacuate_live_with_target_host(self):
|
||||
self.run_command('host-evacuate-live hyper1 '
|
||||
'--target-host hostname')
|
||||
self.assert_called('GET', '/os-hypervisors/search?query=hyper1', pos=0)
|
||||
self.assert_called('GET', '/os-hypervisors/1234/servers', pos=1)
|
||||
body = {'migrate_live': {'host': 'hostname',
|
||||
'block_migration': False,
|
||||
'disk_over_commit': False}}
|
||||
self.assert_called('POST', '/servers/uuid1/action', body, pos=2)
|
||||
self.assert_called('POST', '/servers/uuid2/action', body, pos=3)
|
||||
|
||||
def test_host_evacuate_live_with_block_migration(self):
|
||||
self.run_command('host-evacuate-live --block-migrate hyper1')
|
||||
self.assert_called('GET', '/os-hypervisors/search?query=hyper1', pos=0)
|
||||
self.assert_called('GET', '/os-hypervisors/1234/servers', pos=1)
|
||||
body = {'migrate_live': {'host': None,
|
||||
'block_migration': True,
|
||||
'disk_over_commit': False}}
|
||||
self.assert_called('POST', '/servers/uuid1/action', body, pos=2)
|
||||
self.assert_called('POST', '/servers/uuid2/action', body, pos=3)
|
||||
|
||||
def test_host_evacuate_live_with_disk_over_commit(self):
|
||||
self.run_command('host-evacuate-live --disk-over-commit hyper1')
|
||||
self.assert_called('GET', '/os-hypervisors/search?query=hyper1', pos=0)
|
||||
self.assert_called('GET', '/os-hypervisors/1234/servers', pos=1)
|
||||
body = {'migrate_live': {'host': None,
|
||||
'block_migration': False,
|
||||
'disk_over_commit': True}}
|
||||
self.assert_called('POST', '/servers/uuid1/action', body, pos=2)
|
||||
self.assert_called('POST', '/servers/uuid2/action', body, pos=3)
|
||||
|
||||
def test_delete(self):
|
||||
self.run_command('delete 1234')
|
||||
self.assert_called('DELETE', '/servers/1234')
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
# Copyright 2014 OpenStack Foundation
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from novaclient.openstack.common.gettextutils import _
|
||||
from novaclient import utils
|
||||
|
||||
|
||||
def _server_live_migrate(cs, server, args):
|
||||
class HostEvacuateLiveResponse(object):
|
||||
def __init__(self, server_uuid, live_migration_accepted,
|
||||
error_message):
|
||||
self.server_uuid = server_uuid
|
||||
self.live_migration_accepted = live_migration_accepted
|
||||
self.error_message = error_message
|
||||
success = True
|
||||
error_message = ""
|
||||
try:
|
||||
cs.servers.live_migrate(server['uuid'], args.target_host,
|
||||
args.block_migrate, args.disk_over_commit)
|
||||
except Exception as e:
|
||||
success = False
|
||||
error_message = _("Error while live migrating instance: %s") % e
|
||||
return HostEvacuateLiveResponse(server['uuid'],
|
||||
success,
|
||||
error_message)
|
||||
|
||||
|
||||
@utils.arg('host', metavar='<host>', help='Name of host.')
|
||||
@utils.arg('--target-host',
|
||||
metavar='<target_host>',
|
||||
default=None,
|
||||
help=_('Name of target host.'))
|
||||
@utils.arg('--block-migrate',
|
||||
action='store_true',
|
||||
default=False,
|
||||
help=_('Enable block migration.'))
|
||||
@utils.arg('--disk-over-commit',
|
||||
action='store_true',
|
||||
default=False,
|
||||
help=_('Enable disk overcommit.'))
|
||||
def do_host_evacuate_live(cs, args):
|
||||
"""Live migrate all instances of the specified host
|
||||
to other available hosts.
|
||||
"""
|
||||
hypervisors = cs.hypervisors.search(args.host, servers=True)
|
||||
response = []
|
||||
for hyper in hypervisors:
|
||||
for server in getattr(hyper, 'servers', []):
|
||||
response.append(_server_live_migrate(cs, server, args))
|
||||
|
||||
utils.print_list(response, ["Server UUID", "Live Migration Accepted",
|
||||
"Error Message"])
|
|
@ -2392,6 +2392,53 @@ def do_live_migration(cs, args):
|
|||
args.disk_over_commit)
|
||||
|
||||
|
||||
def _server_live_migrate(cs, server, args):
|
||||
class HostServersLiveMigrateResponse(object):
|
||||
def __init__(self, server_uuid, live_migration_accepted,
|
||||
error_message):
|
||||
self.server_uuid = server_uuid
|
||||
self.live_migration_accepted = live_migration_accepted
|
||||
self.error_message = error_message
|
||||
success = True
|
||||
error_message = ""
|
||||
try:
|
||||
cs.servers.live_migrate(server['id'], args.target_host,
|
||||
args.block_migrate, args.disk_over_commit)
|
||||
except Exception as e:
|
||||
success = False
|
||||
error_message = "Error while live migrating instance: %s" % e
|
||||
return HostServersLiveMigrateResponse(server['id'],
|
||||
success,
|
||||
error_message)
|
||||
|
||||
|
||||
@utils.arg('host', metavar='<host>', help='Name of host.')
|
||||
@utils.arg('--target-host',
|
||||
metavar='<target_host>',
|
||||
default=None,
|
||||
help='Name of target host.')
|
||||
@utils.arg('--block-migrate',
|
||||
action='store_true',
|
||||
default=False,
|
||||
help='Enable block migration.')
|
||||
@utils.arg('--disk-over-commit',
|
||||
action='store_true',
|
||||
default=False,
|
||||
help='Enable disk overcommit.')
|
||||
def do_host_evacuate_live(cs, args):
|
||||
"""Live Migrate all instances of the specified host
|
||||
to other available hosts.
|
||||
"""
|
||||
hypervisors = cs.hypervisors.search(args.host)
|
||||
response = []
|
||||
for hyper in hypervisors:
|
||||
servers = getattr(cs.hypervisors.servers(hyper.id), 'servers', [])
|
||||
for server in servers:
|
||||
response.append(_server_live_migrate(cs, server, args))
|
||||
utils.print_list(response, ["Server UUID", "Live Migration Accepted",
|
||||
"Error Message"])
|
||||
|
||||
|
||||
@utils.arg('server', metavar='<server>', nargs='+',
|
||||
help='Name or ID of server(s).')
|
||||
@utils.arg('--active', action='store_const', dest='state',
|
||||
|
|
Loading…
Reference in New Issue