revert live_migration branch
This commit is contained in:
2
.mailmap
2
.mailmap
@@ -16,8 +16,6 @@
|
|||||||
<jmckenty@gmail.com> <jmckenty@joshua-mckentys-macbook-pro.local>
|
<jmckenty@gmail.com> <jmckenty@joshua-mckentys-macbook-pro.local>
|
||||||
<jmckenty@gmail.com> <joshua.mckenty@nasa.gov>
|
<jmckenty@gmail.com> <joshua.mckenty@nasa.gov>
|
||||||
<justin@fathomdb.com> <justinsb@justinsb-desktop>
|
<justin@fathomdb.com> <justinsb@justinsb-desktop>
|
||||||
<masumotok@nttdata.co.jp> <root@openstack2-api>
|
|
||||||
<masumotok@nttdata.co.jp> Masumoto<masumotok@nttdata.co.jp>
|
|
||||||
<mordred@inaugust.com> <mordred@hudson>
|
<mordred@inaugust.com> <mordred@hudson>
|
||||||
<paul@openstack.org> <pvoccio@castor.local>
|
<paul@openstack.org> <pvoccio@castor.local>
|
||||||
<paul@openstack.org> <paul.voccio@rackspace.com>
|
<paul@openstack.org> <paul.voccio@rackspace.com>
|
||||||
|
|||||||
2
Authors
2
Authors
@@ -26,7 +26,6 @@ Josh Durgin <joshd@hq.newdream.net>
|
|||||||
Josh Kearney <josh.kearney@rackspace.com>
|
Josh Kearney <josh.kearney@rackspace.com>
|
||||||
Joshua McKenty <jmckenty@gmail.com>
|
Joshua McKenty <jmckenty@gmail.com>
|
||||||
Justin Santa Barbara <justin@fathomdb.com>
|
Justin Santa Barbara <justin@fathomdb.com>
|
||||||
Kei Masumoto <masumotok@nttdata.co.jp>
|
|
||||||
Ken Pepple <ken.pepple@gmail.com>
|
Ken Pepple <ken.pepple@gmail.com>
|
||||||
Koji Iida <iida.koji@lab.ntt.co.jp>
|
Koji Iida <iida.koji@lab.ntt.co.jp>
|
||||||
Lorin Hochstein <lorin@isi.edu>
|
Lorin Hochstein <lorin@isi.edu>
|
||||||
@@ -35,7 +34,6 @@ Michael Gundlach <michael.gundlach@rackspace.com>
|
|||||||
Monsyne Dragon <mdragon@rackspace.com>
|
Monsyne Dragon <mdragon@rackspace.com>
|
||||||
Monty Taylor <mordred@inaugust.com>
|
Monty Taylor <mordred@inaugust.com>
|
||||||
MORITA Kazutaka <morita.kazutaka@gmail.com>
|
MORITA Kazutaka <morita.kazutaka@gmail.com>
|
||||||
Muneyuki Noguchi <noguchimn@nttdata.co.jp>
|
|
||||||
Nachi Ueno <ueno.nachi@lab.ntt.co.jp> <openstack@lab.ntt.co.jp> <nati.ueno@gmail.com> <nova@u4>
|
Nachi Ueno <ueno.nachi@lab.ntt.co.jp> <openstack@lab.ntt.co.jp> <nati.ueno@gmail.com> <nova@u4>
|
||||||
Paul Voccio <paul@openstack.org>
|
Paul Voccio <paul@openstack.org>
|
||||||
Rick Clark <rick@openstack.org>
|
Rick Clark <rick@openstack.org>
|
||||||
|
|||||||
@@ -62,7 +62,6 @@ import time
|
|||||||
|
|
||||||
import IPy
|
import IPy
|
||||||
|
|
||||||
|
|
||||||
# If ../nova/__init__.py exists, add ../ to Python search path, so that
|
# If ../nova/__init__.py exists, add ../ to Python search path, so that
|
||||||
# it will override what happens to be installed in /usr/(local/)lib/python...
|
# it will override what happens to be installed in /usr/(local/)lib/python...
|
||||||
possible_topdir = os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]),
|
possible_topdir = os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]),
|
||||||
@@ -82,9 +81,8 @@ from nova import log as logging
|
|||||||
from nova import quota
|
from nova import quota
|
||||||
from nova import utils
|
from nova import utils
|
||||||
from nova.auth import manager
|
from nova.auth import manager
|
||||||
from nova import rpc
|
|
||||||
from nova.cloudpipe import pipelib
|
from nova.cloudpipe import pipelib
|
||||||
from nova.api.ec2 import cloud
|
|
||||||
|
|
||||||
logging.basicConfig()
|
logging.basicConfig()
|
||||||
FLAGS = flags.FLAGS
|
FLAGS = flags.FLAGS
|
||||||
@@ -467,82 +465,6 @@ class NetworkCommands(object):
|
|||||||
int(vpn_start), fixed_range_v6)
|
int(vpn_start), fixed_range_v6)
|
||||||
|
|
||||||
|
|
||||||
class InstanceCommands(object):
|
|
||||||
"""Class for mangaging VM instances."""
|
|
||||||
|
|
||||||
def live_migration(self, ec2_id, dest):
|
|
||||||
"""live_migration"""
|
|
||||||
|
|
||||||
ctxt = context.get_admin_context()
|
|
||||||
instance_id = cloud.ec2_id_to_id(ec2_id)
|
|
||||||
|
|
||||||
if FLAGS.connection_type != 'libvirt':
|
|
||||||
msg = _('Only KVM is supported for now. Sorry!')
|
|
||||||
raise exception.Error(msg)
|
|
||||||
|
|
||||||
if FLAGS.volume_driver != 'nova.volume.driver.AOEDriver':
|
|
||||||
instance_ref = db.instance_get(ctxt, instance_id)
|
|
||||||
if len(instance_ref['volumes']) != 0:
|
|
||||||
msg = _(("""Volumes attached by ISCSIDriver"""
|
|
||||||
""" are not supported. Sorry!"""))
|
|
||||||
raise exception.Error(msg)
|
|
||||||
|
|
||||||
rpc.call(ctxt,
|
|
||||||
FLAGS.scheduler_topic,
|
|
||||||
{"method": "live_migration",
|
|
||||||
"args": {"instance_id": instance_id,
|
|
||||||
"dest": dest,
|
|
||||||
"topic": FLAGS.compute_topic}})
|
|
||||||
|
|
||||||
msg = 'Migration of %s initiated. ' % ec2_id
|
|
||||||
msg += 'Check its progress using euca-describe-instances.'
|
|
||||||
print msg
|
|
||||||
|
|
||||||
|
|
||||||
class HostCommands(object):
|
|
||||||
"""Class for mangaging host(physical nodes)."""
|
|
||||||
|
|
||||||
def list(self):
|
|
||||||
"""describe host list."""
|
|
||||||
|
|
||||||
# To supress msg: No handlers could be found for logger "amqplib"
|
|
||||||
logging.basicConfig()
|
|
||||||
|
|
||||||
service_refs = db.service_get_all(context.get_admin_context())
|
|
||||||
hosts = [h['host'] for h in service_refs]
|
|
||||||
hosts = list(set(hosts))
|
|
||||||
for host in hosts:
|
|
||||||
print host
|
|
||||||
|
|
||||||
def show(self, host):
|
|
||||||
"""describe cpu/memory/hdd info for host."""
|
|
||||||
|
|
||||||
result = rpc.call(context.get_admin_context(),
|
|
||||||
FLAGS.scheduler_topic,
|
|
||||||
{"method": "show_host_resource",
|
|
||||||
"args": {"host": host}})
|
|
||||||
|
|
||||||
# Checking result msg format is necessary, that will have done
|
|
||||||
# when this feture is included in API.
|
|
||||||
if type(result) != dict:
|
|
||||||
print 'Unexpected error occurs'
|
|
||||||
elif not result['ret']:
|
|
||||||
print '%s' % result['msg']
|
|
||||||
else:
|
|
||||||
cpu = result['phy_resource']['vcpus']
|
|
||||||
mem = result['phy_resource']['memory_mb']
|
|
||||||
hdd = result['phy_resource']['local_gb']
|
|
||||||
|
|
||||||
print 'HOST\t\tPROJECT\t\tcpu\tmem(mb)\tdisk(gb)'
|
|
||||||
print '%s\t\t\t%s\t%s\t%s' % (host, cpu, mem, hdd)
|
|
||||||
for p_id, val in result['usage'].items():
|
|
||||||
print '%s\t%s\t\t%s\t%s\t%s' % (host,
|
|
||||||
p_id,
|
|
||||||
val['vcpus'],
|
|
||||||
val['memory_mb'],
|
|
||||||
val['local_gb'])
|
|
||||||
|
|
||||||
|
|
||||||
class ServiceCommands(object):
|
class ServiceCommands(object):
|
||||||
"""Enable and disable running services"""
|
"""Enable and disable running services"""
|
||||||
|
|
||||||
@@ -605,8 +527,6 @@ CATEGORIES = [
|
|||||||
('vpn', VpnCommands),
|
('vpn', VpnCommands),
|
||||||
('floating', FloatingIpCommands),
|
('floating', FloatingIpCommands),
|
||||||
('network', NetworkCommands),
|
('network', NetworkCommands),
|
||||||
('instance', InstanceCommands),
|
|
||||||
('host', HostCommands),
|
|
||||||
('service', ServiceCommands),
|
('service', ServiceCommands),
|
||||||
('log', LogCommands)]
|
('log', LogCommands)]
|
||||||
|
|
||||||
|
|||||||
@@ -26,9 +26,6 @@ import datetime
|
|||||||
from nova import db
|
from nova import db
|
||||||
from nova import exception
|
from nova import exception
|
||||||
from nova import flags
|
from nova import flags
|
||||||
from nova import log as logging
|
|
||||||
from nova import rpc
|
|
||||||
from nova.compute import power_state
|
|
||||||
|
|
||||||
FLAGS = flags.FLAGS
|
FLAGS = flags.FLAGS
|
||||||
flags.DEFINE_integer('service_down_time', 60,
|
flags.DEFINE_integer('service_down_time', 60,
|
||||||
@@ -67,183 +64,3 @@ class Scheduler(object):
|
|||||||
def schedule(self, context, topic, *_args, **_kwargs):
|
def schedule(self, context, topic, *_args, **_kwargs):
|
||||||
"""Must override at least this method for scheduler to work."""
|
"""Must override at least this method for scheduler to work."""
|
||||||
raise NotImplementedError(_("Must implement a fallback schedule"))
|
raise NotImplementedError(_("Must implement a fallback schedule"))
|
||||||
|
|
||||||
def schedule_live_migration(self, context, instance_id, dest):
|
|
||||||
""" live migration method """
|
|
||||||
|
|
||||||
# Whether instance exists and running
|
|
||||||
instance_ref = db.instance_get(context, instance_id)
|
|
||||||
ec2_id = instance_ref['hostname']
|
|
||||||
|
|
||||||
# Checking instance.
|
|
||||||
self._live_migration_src_check(context, instance_ref)
|
|
||||||
|
|
||||||
# Checking destination host.
|
|
||||||
self._live_migration_dest_check(context, instance_ref, dest)
|
|
||||||
|
|
||||||
# Common checking.
|
|
||||||
self._live_migration_common_check(context, instance_ref, dest)
|
|
||||||
|
|
||||||
# Changing instance_state.
|
|
||||||
db.instance_set_state(context,
|
|
||||||
instance_id,
|
|
||||||
power_state.PAUSED,
|
|
||||||
'migrating')
|
|
||||||
|
|
||||||
# Changing volume state
|
|
||||||
for v in instance_ref['volumes']:
|
|
||||||
db.volume_update(context,
|
|
||||||
v['id'],
|
|
||||||
{'status': 'migrating'})
|
|
||||||
|
|
||||||
# Return value is necessary to send request to src
|
|
||||||
# Check _schedule() in detail.
|
|
||||||
src = instance_ref['host']
|
|
||||||
return src
|
|
||||||
|
|
||||||
def _live_migration_src_check(self, context, instance_ref):
|
|
||||||
"""Live migration check routine (for src host)"""
|
|
||||||
|
|
||||||
# Checking instance is running.
|
|
||||||
if power_state.RUNNING != instance_ref['state'] or \
|
|
||||||
'running' != instance_ref['state_description']:
|
|
||||||
msg = _('Instance(%s) is not running')
|
|
||||||
ec2_id = instance_ref['hostname']
|
|
||||||
raise exception.Invalid(msg % ec2_id)
|
|
||||||
|
|
||||||
# Checing volume node is running when any volumes are mounted
|
|
||||||
# to the instance.
|
|
||||||
if len(instance_ref['volumes']) != 0:
|
|
||||||
services = db.service_get_all_by_topic(context, 'volume')
|
|
||||||
if len(services) < 1 or not self.service_is_up(services[0]):
|
|
||||||
msg = _('volume node is not alive(time synchronize problem?)')
|
|
||||||
raise exception.Invalid(msg)
|
|
||||||
|
|
||||||
# Checking src host is alive.
|
|
||||||
src = instance_ref['host']
|
|
||||||
services = db.service_get_all_by_topic(context, 'compute')
|
|
||||||
services = [service for service in services if service.host == src]
|
|
||||||
if len(services) < 1 or not self.service_is_up(services[0]):
|
|
||||||
msg = _('%s is not alive(time synchronize problem?)')
|
|
||||||
raise exception.Invalid(msg % src)
|
|
||||||
|
|
||||||
def _live_migration_dest_check(self, context, instance_ref, dest):
|
|
||||||
"""Live migration check routine (for destination host)"""
|
|
||||||
|
|
||||||
# Checking dest exists and compute node.
|
|
||||||
dservice_refs = db.service_get_all_by_host(context, dest)
|
|
||||||
if len(dservice_refs) <= 0:
|
|
||||||
msg = _('%s does not exists.')
|
|
||||||
raise exception.Invalid(msg % dest)
|
|
||||||
|
|
||||||
dservice_ref = dservice_refs[0]
|
|
||||||
if dservice_ref['topic'] != 'compute':
|
|
||||||
msg = _('%s must be compute node')
|
|
||||||
raise exception.Invalid(msg % dest)
|
|
||||||
|
|
||||||
# Checking dest host is alive.
|
|
||||||
if not self.service_is_up(dservice_ref):
|
|
||||||
msg = _('%s is not alive(time synchronize problem?)')
|
|
||||||
raise exception.Invalid(msg % dest)
|
|
||||||
|
|
||||||
# Checking whether The host where instance is running
|
|
||||||
# and dest is not same.
|
|
||||||
src = instance_ref['host']
|
|
||||||
if dest == src:
|
|
||||||
ec2_id = instance_ref['hostname']
|
|
||||||
msg = _('%s is where %s is running now. choose other host.')
|
|
||||||
raise exception.Invalid(msg % (dest, ec2_id))
|
|
||||||
|
|
||||||
# Checking dst host still has enough capacities.
|
|
||||||
self.has_enough_resource(context, instance_ref, dest)
|
|
||||||
|
|
||||||
def _live_migration_common_check(self, context, instance_ref, dest):
|
|
||||||
"""
|
|
||||||
Live migration check routine.
|
|
||||||
Below pre-checkings are followed by
|
|
||||||
http://wiki.libvirt.org/page/TodoPreMigrationChecks
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
# Checking dest exists.
|
|
||||||
dservice_refs = db.service_get_all_by_host(context, dest)
|
|
||||||
if len(dservice_refs) <= 0:
|
|
||||||
msg = _('%s does not exists.')
|
|
||||||
raise exception.Invalid(msg % dest)
|
|
||||||
dservice_ref = dservice_refs[0]
|
|
||||||
|
|
||||||
# Checking original host( where instance was launched at) exists.
|
|
||||||
orighost = instance_ref['launched_on']
|
|
||||||
oservice_refs = db.service_get_all_by_host(context, orighost)
|
|
||||||
if len(oservice_refs) <= 0:
|
|
||||||
msg = _('%s(where instance was launched at) does not exists.')
|
|
||||||
raise exception.Invalid(msg % orighost)
|
|
||||||
oservice_ref = oservice_refs[0]
|
|
||||||
|
|
||||||
# Checking hypervisor is same.
|
|
||||||
otype = oservice_ref['hypervisor_type']
|
|
||||||
dtype = dservice_ref['hypervisor_type']
|
|
||||||
if otype != dtype:
|
|
||||||
msg = _('Different hypervisor type(%s->%s)')
|
|
||||||
raise exception.Invalid(msg % (otype, dtype))
|
|
||||||
|
|
||||||
# Checkng hypervisor version.
|
|
||||||
oversion = oservice_ref['hypervisor_version']
|
|
||||||
dversion = dservice_ref['hypervisor_version']
|
|
||||||
if oversion > dversion:
|
|
||||||
msg = _('Older hypervisor version(%s->%s)')
|
|
||||||
raise exception.Invalid(msg % (oversion, dversion))
|
|
||||||
|
|
||||||
# Checking cpuinfo.
|
|
||||||
cpu_info = oservice_ref['cpu_info']
|
|
||||||
try:
|
|
||||||
rpc.call(context,
|
|
||||||
db.queue_get_for(context, FLAGS.compute_topic, dest),
|
|
||||||
{"method": 'compare_cpu',
|
|
||||||
"args": {'cpu_info': cpu_info}})
|
|
||||||
|
|
||||||
except rpc.RemoteError, e:
|
|
||||||
msg = _(("""%s doesnt have compatibility to %s"""
|
|
||||||
"""(where %s was launched at)"""))
|
|
||||||
ec2_id = instance_ref['hostname']
|
|
||||||
src = instance_ref['host']
|
|
||||||
logging.error(msg % (dest, src, ec2_id))
|
|
||||||
raise e
|
|
||||||
|
|
||||||
def has_enough_resource(self, context, instance_ref, dest):
|
|
||||||
""" Check if destination host has enough resource for live migration"""
|
|
||||||
|
|
||||||
# Getting instance information
|
|
||||||
ec2_id = instance_ref['hostname']
|
|
||||||
vcpus = instance_ref['vcpus']
|
|
||||||
mem = instance_ref['memory_mb']
|
|
||||||
hdd = instance_ref['local_gb']
|
|
||||||
|
|
||||||
# Gettin host information
|
|
||||||
service_refs = db.service_get_all_by_host(context, dest)
|
|
||||||
if len(service_refs) <= 0:
|
|
||||||
msg = _('%s does not exists.')
|
|
||||||
raise exception.Invalid(msg % dest)
|
|
||||||
service_ref = service_refs[0]
|
|
||||||
|
|
||||||
total_cpu = int(service_ref['vcpus'])
|
|
||||||
total_mem = int(service_ref['memory_mb'])
|
|
||||||
total_hdd = int(service_ref['local_gb'])
|
|
||||||
|
|
||||||
instances_ref = db.instance_get_all_by_host(context, dest)
|
|
||||||
for i_ref in instances_ref:
|
|
||||||
total_cpu -= int(i_ref['vcpus'])
|
|
||||||
total_mem -= int(i_ref['memory_mb'])
|
|
||||||
total_hdd -= int(i_ref['local_gb'])
|
|
||||||
|
|
||||||
# Checking host has enough information
|
|
||||||
logging.debug('host(%s) remains vcpu:%s mem:%s hdd:%s,' %
|
|
||||||
(dest, total_cpu, total_mem, total_hdd))
|
|
||||||
logging.debug('instance(%s) has vcpu:%s mem:%s hdd:%s,' %
|
|
||||||
(ec2_id, vcpus, mem, hdd))
|
|
||||||
|
|
||||||
if total_cpu <= vcpus or total_mem <= mem or total_hdd <= hdd:
|
|
||||||
msg = '%s doesnt have enough resource for %s' % (dest, ec2_id)
|
|
||||||
raise exception.NotEmpty(msg)
|
|
||||||
|
|
||||||
logging.debug(_('%s has_enough_resource() for %s') % (dest, ec2_id))
|
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ from nova import log as logging
|
|||||||
from nova import manager
|
from nova import manager
|
||||||
from nova import rpc
|
from nova import rpc
|
||||||
from nova import utils
|
from nova import utils
|
||||||
from nova import exception
|
|
||||||
|
|
||||||
LOG = logging.getLogger('nova.scheduler.manager')
|
LOG = logging.getLogger('nova.scheduler.manager')
|
||||||
FLAGS = flags.FLAGS
|
FLAGS = flags.FLAGS
|
||||||
@@ -68,50 +67,3 @@ class SchedulerManager(manager.Manager):
|
|||||||
{"method": method,
|
{"method": method,
|
||||||
"args": kwargs})
|
"args": kwargs})
|
||||||
LOG.debug(_("Casting to %s %s for %s"), topic, host, method)
|
LOG.debug(_("Casting to %s %s for %s"), topic, host, method)
|
||||||
|
|
||||||
# NOTE (masumotok) : This method should be moved to nova.api.ec2.admin.
|
|
||||||
# Based on bear design summit discussion,
|
|
||||||
# just put this here for bexar release.
|
|
||||||
def show_host_resource(self, context, host, *args):
|
|
||||||
""" show the physical/usage resource given by hosts."""
|
|
||||||
|
|
||||||
services = db.service_get_all_by_host(context, host)
|
|
||||||
if len(services) == 0:
|
|
||||||
return {'ret': False, 'msg': 'No such Host'}
|
|
||||||
|
|
||||||
compute = [s for s in services if s['topic'] == 'compute']
|
|
||||||
if 0 == len(compute):
|
|
||||||
service_ref = services[0]
|
|
||||||
else:
|
|
||||||
service_ref = compute[0]
|
|
||||||
|
|
||||||
# Getting physical resource information
|
|
||||||
h_resource = {'vcpus': service_ref['vcpus'],
|
|
||||||
'memory_mb': service_ref['memory_mb'],
|
|
||||||
'local_gb': service_ref['local_gb']}
|
|
||||||
|
|
||||||
# Getting usage resource information
|
|
||||||
u_resource = {}
|
|
||||||
instances_ref = db.instance_get_all_by_host(context,
|
|
||||||
service_ref['host'])
|
|
||||||
|
|
||||||
if 0 == len(instances_ref):
|
|
||||||
return {'ret': True, 'phy_resource': h_resource, 'usage': {}}
|
|
||||||
|
|
||||||
project_ids = [i['project_id'] for i in instances_ref]
|
|
||||||
project_ids = list(set(project_ids))
|
|
||||||
for p_id in project_ids:
|
|
||||||
vcpus = db.instance_get_vcpu_sum_by_host_and_project(context,
|
|
||||||
host,
|
|
||||||
p_id)
|
|
||||||
mem = db.instance_get_memory_sum_by_host_and_project(context,
|
|
||||||
host,
|
|
||||||
p_id)
|
|
||||||
hdd = db.instance_get_disk_sum_by_host_and_project(context,
|
|
||||||
host,
|
|
||||||
p_id)
|
|
||||||
u_resource[p_id] = {'vcpus': vcpus,
|
|
||||||
'memory_mb': mem,
|
|
||||||
'local_gb': hdd}
|
|
||||||
|
|
||||||
return {'ret': True, 'phy_resource': h_resource, 'usage': u_resource}
|
|
||||||
|
|||||||
@@ -80,7 +80,6 @@ class Service(object):
|
|||||||
self.manager.init_host()
|
self.manager.init_host()
|
||||||
self.model_disconnected = False
|
self.model_disconnected = False
|
||||||
ctxt = context.get_admin_context()
|
ctxt = context.get_admin_context()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
service_ref = db.service_get_by_args(ctxt,
|
service_ref = db.service_get_by_args(ctxt,
|
||||||
self.host,
|
self.host,
|
||||||
@@ -89,9 +88,6 @@ class Service(object):
|
|||||||
except exception.NotFound:
|
except exception.NotFound:
|
||||||
self._create_service_ref(ctxt)
|
self._create_service_ref(ctxt)
|
||||||
|
|
||||||
if 'nova-compute' == self.binary:
|
|
||||||
self.manager.update_service(ctxt, self.host, self.binary)
|
|
||||||
|
|
||||||
conn1 = rpc.Connection.instance(new=True)
|
conn1 = rpc.Connection.instance(new=True)
|
||||||
conn2 = rpc.Connection.instance(new=True)
|
conn2 = rpc.Connection.instance(new=True)
|
||||||
if self.report_interval:
|
if self.report_interval:
|
||||||
|
|||||||
Reference in New Issue
Block a user