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> <joshua.mckenty@nasa.gov>
|
||||
<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>
|
||||
<paul@openstack.org> <pvoccio@castor.local>
|
||||
<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>
|
||||
Joshua McKenty <jmckenty@gmail.com>
|
||||
Justin Santa Barbara <justin@fathomdb.com>
|
||||
Kei Masumoto <masumotok@nttdata.co.jp>
|
||||
Ken Pepple <ken.pepple@gmail.com>
|
||||
Koji Iida <iida.koji@lab.ntt.co.jp>
|
||||
Lorin Hochstein <lorin@isi.edu>
|
||||
@@ -35,7 +34,6 @@ Michael Gundlach <michael.gundlach@rackspace.com>
|
||||
Monsyne Dragon <mdragon@rackspace.com>
|
||||
Monty Taylor <mordred@inaugust.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>
|
||||
Paul Voccio <paul@openstack.org>
|
||||
Rick Clark <rick@openstack.org>
|
||||
|
||||
@@ -62,7 +62,6 @@ import time
|
||||
|
||||
import IPy
|
||||
|
||||
|
||||
# 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...
|
||||
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 utils
|
||||
from nova.auth import manager
|
||||
from nova import rpc
|
||||
from nova.cloudpipe import pipelib
|
||||
from nova.api.ec2 import cloud
|
||||
|
||||
|
||||
logging.basicConfig()
|
||||
FLAGS = flags.FLAGS
|
||||
@@ -467,82 +465,6 @@ class NetworkCommands(object):
|
||||
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):
|
||||
"""Enable and disable running services"""
|
||||
|
||||
@@ -605,8 +527,6 @@ CATEGORIES = [
|
||||
('vpn', VpnCommands),
|
||||
('floating', FloatingIpCommands),
|
||||
('network', NetworkCommands),
|
||||
('instance', InstanceCommands),
|
||||
('host', HostCommands),
|
||||
('service', ServiceCommands),
|
||||
('log', LogCommands)]
|
||||
|
||||
|
||||
@@ -26,9 +26,6 @@ import datetime
|
||||
from nova import db
|
||||
from nova import exception
|
||||
from nova import flags
|
||||
from nova import log as logging
|
||||
from nova import rpc
|
||||
from nova.compute import power_state
|
||||
|
||||
FLAGS = flags.FLAGS
|
||||
flags.DEFINE_integer('service_down_time', 60,
|
||||
@@ -67,183 +64,3 @@ class Scheduler(object):
|
||||
def schedule(self, context, topic, *_args, **_kwargs):
|
||||
"""Must override at least this method for scheduler to work."""
|
||||
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 rpc
|
||||
from nova import utils
|
||||
from nova import exception
|
||||
|
||||
LOG = logging.getLogger('nova.scheduler.manager')
|
||||
FLAGS = flags.FLAGS
|
||||
@@ -68,50 +67,3 @@ class SchedulerManager(manager.Manager):
|
||||
{"method": method,
|
||||
"args": kwargs})
|
||||
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.model_disconnected = False
|
||||
ctxt = context.get_admin_context()
|
||||
|
||||
try:
|
||||
service_ref = db.service_get_by_args(ctxt,
|
||||
self.host,
|
||||
@@ -89,9 +88,6 @@ class Service(object):
|
||||
except exception.NotFound:
|
||||
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)
|
||||
conn2 = rpc.Connection.instance(new=True)
|
||||
if self.report_interval:
|
||||
|
||||
Reference in New Issue
Block a user