From 2925ca3ac3010b9a65276ad2cfc8118679827da3 Mon Sep 17 00:00:00 2001 From: masumotok Date: Tue, 7 Dec 2010 19:25:43 +0900 Subject: rev439ベースにライブマイグレーションの機能をマージ このバージョンはEBSなし、CPUフラグのチェックなし MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nova/virt/libvirt_conn.py | 101 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) (limited to 'nova/virt') diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index 18085089f..4ed791130 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -44,6 +44,8 @@ Supports KVM, QEMU, UML, and XEN. import logging import os import shutil +# appended by masumotok +#import libvirt import IPy from twisted.internet import defer @@ -101,6 +103,10 @@ flags.DEFINE_string('libvirt_uri', '', 'Override the default libvirt URI (which is dependent' ' on libvirt_type)') +# added by masumotok +flags.DEFINE_string('live_migration_uri', + "qemu+tcp://%s/system", + 'Define protocol used by live_migration feature') flags.DEFINE_bool('allow_project_net_traffic', True, 'Whether to allow in project network traffic') @@ -648,6 +654,101 @@ class LibvirtConnection(object): fw = NWFilterFirewall(self._conn) fw.ensure_security_group_filter(security_group_id) + # created by masumotok + def setup_nwfilters_for_instance(self, instance): + nwfilter = NWFilterFirewall(self._conn) + return nwfilter.setup_nwfilters_for_instance(instance) + + # created by masumotok + def nwfilter_for_instance_exists(self, instance_ref): + try: + filter = 'nova-instance-%s' % instance_ref.name + self._conn.nwfilterLookupByName(filter) + return True + except libvirt.libvirtError: + return False + + # created by masumotok + def live_migration(self, instance_ref, dest): + uri = FLAGS.live_migration_uri % dest + out, err = utils.execute("sudo virsh migrate --live %s %s" + % (instance_ref.name, uri)) + + # wait for completion of live_migration + d = defer.Deferred() + d.addCallback(lambda _: self._post_live_migration(instance_ref, dest)) + timer = task.LoopingCall(f=None) + + def _wait_for_live_migration(): + try: + state = self.get_info(instance_ref.name)['state'] + #except libvirt.libvirtError, e: + except exception.NotFound: + timer.stop() + d.callback(None) + timer.f = _wait_for_live_migration + timer.start(interval=0.5, now=True) + return d + + # created by masumotok + def _post_live_migration(self, instance_ref, dest): + + # 1. detaching volumes + # (not necessary in current version ) + #try : + # ec2_id = instance_ref['ec2_id'] + # volumes = db.volume_get_by_ec2_id(context, ec2_id) + # for volume in volumes : + # self.detach_volume(context, instance_id, volume.id) + #except exception.NotFound: + # logging.debug('%s doesnt mount any volumes.. ' % ec2_id) + + # 2. releasing vlan + # (not necessary in current implementation?) + + # 3. releasing security group ingress rule + # (not necessary in current implementation?) + + # 4. database updating + ec2_id = instance_ref['hostname'] + ctxt = context.get_admin_context() + + instance_id = instance_ref['id'] + fixed_ip = db.instance_get_fixed_address(ctxt, instance_id) + # not return if fixed_ip is not found, otherwise, + # instance never be accessible.. + if None == fixed_ip: + logging.error('fixed_ip is not found for %s ' % ec2_id) + db.fixed_ip_update(ctxt, fixed_ip, {'host': dest}) + network_ref = db.fixed_ip_get_network(ctxt, fixed_ip) + db.network_update(ctxt, network_ref['id'], {'host': dest}) + + try: + floating_ip = db.instance_get_floating_address(ctxt, instance_id) + # not return if floating_ip is not found, otherwise, + # instance never be accessible.. + if None == floating_ip: + logging.error('floating_ip is not found for %s ' % ec2_id) + floating_ip_ref = db.floating_ip_get_by_address(ctxt, floating_ip) + db.floating_ip_update(ctxt, + floating_ip_ref['address'], + {'host': dest}) + except exception.NotFound: + logging.debug('%s doesnt have floating_ip.. ' % ec2_id) + except: + msg = 'Live migration: Unexpected error:' + msg += '%s cannot inherit floating ip.. ' % ec2_id + logging.error(msg) + + db.instance_update(ctxt, + instance_id, + {'state_description': 'running', + 'state': power_state.RUNNING, + 'host': dest}) + + logging.info('Live migrating %s to %s finishes successfully' + % (ec2_id, dest)) + class NWFilterFirewall(object): """ -- cgit From 3313a5170a83feb6e571faa6296ffea7f065ec25 Mon Sep 17 00:00:00 2001 From: masumotok Date: Wed, 8 Dec 2010 17:21:04 +0900 Subject: コメントを除去 README.live_migration.txtのレビュー結果を修正 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nova/virt/libvirt_conn.py | 7 ------- 1 file changed, 7 deletions(-) (limited to 'nova/virt') diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index 4ed791130..783f2409e 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -44,8 +44,6 @@ Supports KVM, QEMU, UML, and XEN. import logging import os import shutil -# appended by masumotok -#import libvirt import IPy from twisted.internet import defer @@ -103,7 +101,6 @@ flags.DEFINE_string('libvirt_uri', '', 'Override the default libvirt URI (which is dependent' ' on libvirt_type)') -# added by masumotok flags.DEFINE_string('live_migration_uri', "qemu+tcp://%s/system", 'Define protocol used by live_migration feature') @@ -654,12 +651,10 @@ class LibvirtConnection(object): fw = NWFilterFirewall(self._conn) fw.ensure_security_group_filter(security_group_id) - # created by masumotok def setup_nwfilters_for_instance(self, instance): nwfilter = NWFilterFirewall(self._conn) return nwfilter.setup_nwfilters_for_instance(instance) - # created by masumotok def nwfilter_for_instance_exists(self, instance_ref): try: filter = 'nova-instance-%s' % instance_ref.name @@ -668,7 +663,6 @@ class LibvirtConnection(object): except libvirt.libvirtError: return False - # created by masumotok def live_migration(self, instance_ref, dest): uri = FLAGS.live_migration_uri % dest out, err = utils.execute("sudo virsh migrate --live %s %s" @@ -690,7 +684,6 @@ class LibvirtConnection(object): timer.start(interval=0.5, now=True) return d - # created by masumotok def _post_live_migration(self, instance_ref, dest): # 1. detaching volumes -- cgit From 4809c1bf82130f969614a8f0458636a462b81a88 Mon Sep 17 00:00:00 2001 From: masumotok Date: Thu, 16 Dec 2010 18:20:04 +0900 Subject: Hostテーブルのカラム名を修正 FlatManager, FlatDHCPManagerに対応 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nova/virt/libvirt_conn.py | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'nova/virt') diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index 783f2409e..f2b5cf794 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -631,6 +631,10 @@ class LibvirtConnection(object): return interfaces + def get_vcpu_number(self): + """ get vcpu number of physical computer """ + return self._conn.getMaxVcpus(None) + def block_stats(self, instance_name, disk): """ Note that this function takes an instance name, not an Instance, so -- cgit From f983884dd262f46907f80a04121d957347881240 Mon Sep 17 00:00:00 2001 From: root Date: Fri, 24 Dec 2010 15:09:05 +0900 Subject: nova.compute.managerがこれまでの修正でデグレしていたので修正 CPUID, その他のチェックルーチンをnova.scheduler.manager.live_migrationに追加 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nova/virt/libvirt_conn.py | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) (limited to 'nova/virt') diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index f2b5cf794..6450db8bd 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -44,6 +44,7 @@ Supports KVM, QEMU, UML, and XEN. import logging import os import shutil +import re import IPy from twisted.internet import defer @@ -632,9 +633,30 @@ class LibvirtConnection(object): return interfaces def get_vcpu_number(self): - """ get vcpu number of physical computer """ + """ Get vcpu number of physical computer. """ return self._conn.getMaxVcpus(None) + def get_hypervisor_type(self): + """ Get hypervisor type """ + return self._conn.getType() + + def get_hypervisor_version(self): + """ Get hypervisor version """ + return self._conn.getVersion() + + def get_cpu_xml(self): + """ Get cpuinfo information """ + xmlstr = self._conn.getCapabilities() + xml = libxml2.parseDoc(xmlstr) + nodes = xml.xpathEval('//cpu') + if 1 != len(nodes): + msg = 'Unexpected xml format. tag "cpu" must be 1, but %d.' % len(nodes) + msg += '\n'+xml.serialize() + raise exception.Invalid(msg) + cpuxmlstr = re.sub("\n|[ ]+", ' ', nodes[0].serialize()) + return cpuxmlstr + + def block_stats(self, instance_name, disk): """ Note that this function takes an instance name, not an Instance, so @@ -651,14 +673,17 @@ class LibvirtConnection(object): domain = self._conn.lookupByName(instance_name) return domain.interfaceStats(interface) + def refresh_security_group(self, security_group_id): fw = NWFilterFirewall(self._conn) fw.ensure_security_group_filter(security_group_id) + def setup_nwfilters_for_instance(self, instance): nwfilter = NWFilterFirewall(self._conn) return nwfilter.setup_nwfilters_for_instance(instance) + def nwfilter_for_instance_exists(self, instance_ref): try: filter = 'nova-instance-%s' % instance_ref.name @@ -667,6 +692,19 @@ class LibvirtConnection(object): except libvirt.libvirtError: return False + + def compareCPU(self, xml): + """ + Check the host cpu is compatible to a cpu given by xml. + "xml" must be a part of libvirt.openReadonly().getCapabilities(). + return values follows by virCPUCompareResult. + if 0 > return value, do live migration. + + 'http://libvirt.org/html/libvirt-libvirt.html#virCPUCompareResult' + """ + return self._conn.compareCPU(xml,0) + + def live_migration(self, instance_ref, dest): uri = FLAGS.live_migration_uri % dest out, err = utils.execute("sudo virsh migrate --live %s %s" -- cgit From 3bf9bc6f6c0fbf90e3f4eab68a9bd99d85fcc422 Mon Sep 17 00:00:00 2001 From: Rick Harris Date: Thu, 6 Jan 2011 21:37:33 -0600 Subject: Reserving image before uploading --- nova/virt/libvirt_conn.py | 2 +- nova/virt/xenapi/vm_utils.py | 24 +++++++++++++++--------- nova/virt/xenapi/vmops.py | 6 +++--- nova/virt/xenapi_conn.py | 8 ++++++-- 4 files changed, 25 insertions(+), 15 deletions(-) (limited to 'nova/virt') diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index 00edfbdc8..18456be5a 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -260,7 +260,7 @@ class LibvirtConnection(object): virt_dom.detachDevice(xml) @exception.wrap_exception - def snapshot(self, instance, name): + def snapshot(self, instance, image_id): """ Create snapshot from a running VM instance """ raise NotImplementedError( _("Instance snapshotting is not supported for libvirt" diff --git a/nova/virt/xenapi/vm_utils.py b/nova/virt/xenapi/vm_utils.py index 9d1b51848..308cf5834 100644 --- a/nova/virt/xenapi/vm_utils.py +++ b/nova/virt/xenapi/vm_utils.py @@ -237,15 +237,15 @@ class VMHelper(HelperBase): return template_vm_ref, [template_vdi_uuid, parent_uuid] @classmethod - def upload_image(cls, session, instance_id, vdi_uuids, image_name): + def upload_image(cls, session, instance_id, vdi_uuids, image_id): """ Requests that the Glance plugin bundle the specified VDIs and push them into Glance using the specified human-friendly name. """ - logging.debug(_("Asking xapi to upload %s as '%s'"), - vdi_uuids, image_name) + logging.debug(_("Asking xapi to upload %s as ID %s"), + vdi_uuids, image_id) params = {'vdi_uuids': vdi_uuids, - 'image_name': image_name, + 'image_id': image_id, 'glance_host': FLAGS.glance_host, 'glance_port': FLAGS.glance_port} @@ -427,9 +427,16 @@ def wait_for_vhd_coalesce(session, instance_id, sr_ref, vdi_ref, * parent_vhd snapshot """ - #TODO(sirp): we need to timeout this req after a while + max_attempts = FLAGS.xenapi_vhd_coalesce_max_attempts + attempts = {'counter': 0} def _poll_vhds(): + attempts['counter'] += 1 + if attempts['counter'] > max_attempts: + msg = (_("VHD coalesce attempts exceeded (%d > %d), giving up...") + % (attempts['counter'], max_attempts)) + raise exception.Error(msg) + scan_sr(session, instance_id, sr_ref) parent_uuid = get_vhd_parent_uuid(session, vdi_ref) if original_parent_uuid and (parent_uuid != original_parent_uuid): @@ -438,13 +445,12 @@ def wait_for_vhd_coalesce(session, instance_id, sr_ref, vdi_ref, "waiting for coalesce..."), parent_uuid, original_parent_uuid) else: - done.send(parent_uuid) + # Breakout of the loop (normally) and return the parent_uuid + raise utils.LoopingCallDone(parent_uuid) - done = event.Event() loop = utils.LoopingCall(_poll_vhds) loop.start(FLAGS.xenapi_vhd_coalesce_poll_interval, now=True) - parent_uuid = done.wait() - loop.stop() + parent_uuid = loop.wait() return parent_uuid diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py index 76f31635a..8f2fae08a 100644 --- a/nova/virt/xenapi/vmops.py +++ b/nova/virt/xenapi/vmops.py @@ -120,11 +120,11 @@ class VMOps(object): timer.f = _wait_for_boot return timer.start(interval=0.5, now=True) - def snapshot(self, instance, name): + def snapshot(self, instance, image_id): """ Create snapshot from a running VM instance :param instance: instance to be snapshotted - :param name: name/label to be given to the snapshot + :param image_id: id of image to upload to Steps involved in a XenServer snapshot: @@ -160,7 +160,7 @@ class VMOps(object): try: # call plugin to ship snapshot off to glance VMHelper.upload_image( - self._session, instance.id, template_vdi_uuids, name) + self._session, instance.id, template_vdi_uuids, image_id) finally: self._destroy(instance, template_vm_ref, shutdown=False) diff --git a/nova/virt/xenapi_conn.py b/nova/virt/xenapi_conn.py index f17c8f39d..d6be9f4a2 100644 --- a/nova/virt/xenapi_conn.py +++ b/nova/virt/xenapi_conn.py @@ -87,6 +87,10 @@ flags.DEFINE_float('xenapi_vhd_coalesce_poll_interval', 5.0, 'The interval used for polling of coalescing vhds.' ' Used only if connection_type=xenapi.') +flags.DEFINE_integer('xenapi_vhd_coalesce_max_attempts', + 5, + 'Max number of times to poll for VHD to coalesce.' + ' Used only if connection_type=xenapi.') flags.DEFINE_string('target_host', None, 'iSCSI Target Host') @@ -135,9 +139,9 @@ class XenAPIConnection(object): """Create VM instance""" self._vmops.spawn(instance) - def snapshot(self, instance, name): + def snapshot(self, instance, image_id): """ Create snapshot from a running VM instance """ - self._vmops.snapshot(instance, name) + self._vmops.snapshot(instance, image_id) def reboot(self, instance): """Reboot VM instance""" -- cgit From 5afd9848ad09414c00062ceebdad45bca0604888 Mon Sep 17 00:00:00 2001 From: Muneyuki Noguchi Date: Tue, 11 Jan 2011 18:01:23 +0900 Subject: Add support for EBS volumes to the live migration feature. Currently, only AoE is supported. --- nova/virt/libvirt_conn.py | 45 +++++++++++++++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 14 deletions(-) (limited to 'nova/virt') diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index d1a53f275..044e6584c 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -695,8 +695,9 @@ class LibvirtConnection(object): xmlstr = self._conn.getCapabilities() xml = libxml2.parseDoc(xmlstr) nodes = xml.xpathEval('//cpu') - if 1 != len(nodes): - msg = 'Unexpected xml format. tag "cpu" must be 1, but %d.' % len(nodes) + if 1 != len(nodes): + msg = 'Unexpected xml format. tag "cpu" must be 1, but %d.' \ + % len(nodes) msg += '\n' + xml.serialize() raise exception.Invalid(_(msg)) cpuxmlstr = re.sub("\n|[ ]+", ' ', nodes[0].serialize()) @@ -735,8 +736,8 @@ class LibvirtConnection(object): except libvirt.libvirtError: return False - def compareCPU(self, xml): - """ + def compareCPU(self, xml): + """ Check the host cpu is compatible to a cpu given by xml. "xml" must be a part of libvirt.openReadonly().getCapabilities(). return values follows by virCPUCompareResult. @@ -747,9 +748,9 @@ class LibvirtConnection(object): return self._conn.compareCPU(xml, 0) def live_migration(self, context, instance_ref, dest): - """ - Just spawning live_migration operation for - distributing high-load. + """ + Just spawning live_migration operation for + distributing high-load. """ greenthread.spawn(self._live_migration, context, instance_ref, dest) @@ -757,14 +758,21 @@ class LibvirtConnection(object): """ Do live migration.""" # Do live migration. - try: + try: uri = FLAGS.live_migration_uri % dest out, err = utils.execute("sudo virsh migrate --live %s %s" % (instance_ref.name, uri)) - except exception.ProcessExecutionError: + except exception.ProcessExecutionError: id = instance_ref['id'] db.instance_set_state(context, id, power_state.RUNNING, 'running') - raise + try: + for volume in db.volume_get_all_by_instance(context, id): + db.volume_update(context, + volume['id'], + {'status': 'in-use'}) + except exception.NotFound: + pass + raise exception.ProcessExecutionError # Waiting for completion of live_migration. timer = utils.LoopingCall(f=None) @@ -781,7 +789,7 @@ class LibvirtConnection(object): timer.start(interval=0.5, now=True) def _post_live_migration(self, context, instance_ref, dest): - """ + """ Post operations for live migration. Mainly, database updating. """ @@ -808,13 +816,14 @@ class LibvirtConnection(object): db.network_update(context, network_ref['id'], {'host': dest}) try: - floating_ip = db.instance_get_floating_address(context, instance_id) + floating_ip \ + = db.instance_get_floating_address(context, instance_id) # Not return if floating_ip is not found, otherwise, # instance never be accessible.. if None == floating_ip: logging.error('floating_ip is not found for %s ' % ec2_id) - else: - floating_ip_ref = db.floating_ip_get_by_address(context, + else: + floating_ip_ref = db.floating_ip_get_by_address(context, floating_ip) db.floating_ip_update(context, floating_ip_ref['address'], @@ -832,6 +841,14 @@ class LibvirtConnection(object): 'state': power_state.RUNNING, 'host': dest}) + try: + for volume in db.volume_get_all_by_instance(context, instance_id): + db.volume_update(context, + volume['id'], + {'status': 'in-use'}) + except exception.NotFound: + pass + logging.info(_('Live migrating %s to %s finishes successfully') % (ec2_id, dest)) -- cgit From c57ccba743c54786e28317194000bcf22dc5b69e Mon Sep 17 00:00:00 2001 From: Kei Masumoto Date: Fri, 14 Jan 2011 08:26:25 +0900 Subject: checking based on pep8 --- nova/virt/libvirt_conn.py | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) (limited to 'nova/virt') diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index 3024515b8..f3f837153 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -96,7 +96,7 @@ flags.DEFINE_string('live_migration_uri', flags.DEFINE_string('live_migration_flag', "VIR_MIGRATE_UNDEFINE_SOURCE, VIR_MIGRATE_PEER2PEER", 'Define live migration behavior.') -flags.DEFINE_integer('live_migration_bandwidth', 0, +flags.DEFINE_integer('live_migration_bandwidth', 0, 'Define live migration behavior') flags.DEFINE_string('live_migration_timeout_sec', 10, 'Timeout second for pre_live_migration is completed.') @@ -817,7 +817,6 @@ class LibvirtConnection(object): def refresh_security_group_members(self, security_group_id): self.firewall_driver.refresh_security_group_members(security_group_id) - def compare_cpu(self, xml): """ Check the host cpu is compatible to a cpu given by xml. @@ -827,9 +826,8 @@ class LibvirtConnection(object): 'http://libvirt.org/html/libvirt-libvirt.html#virCPUCompareResult' """ - ret = self._conn.compareCPU(xml, 0) - if ret <= 0 : + if ret <= 0: url = 'http://libvirt.org/html/libvirt-libvirt.html' url += '#virCPUCompareResult\n' msg = 'CPU does not have compativility.\n' @@ -837,22 +835,22 @@ class LibvirtConnection(object): msg += 'Refer to %s' msg = _(msg) raise exception.Invalid(msg % (ret, url)) - return + return def ensure_filtering_rules_for_instance(self, instance_ref): - """ Setting up inevitable filtering rules on compute node, - and waiting for its completion. + """ Setting up inevitable filtering rules on compute node, + and waiting for its completion. To migrate an instance, filtering rules to hypervisors and firewalls are inevitable on destination host. - ( Waiting only for filterling rules to hypervisor, + ( Waiting only for filterling rules to hypervisor, since filtering rules to firewall rules can be set faster). Concretely, the below method must be called. - setup_basic_filtering (for nova-basic, etc.) - prepare_instance_filter(for nova-instance-instance-xxx, etc.) - + to_xml may have to be called since it defines PROJNET, PROJMASK. - but libvirt migrates those value through migrateToURI(), + but libvirt migrates those value through migrateToURI(), so , no need to be called. Don't use thread for this method since migration should @@ -879,7 +877,7 @@ class LibvirtConnection(object): msg = _('Timeout migrating for %s(%s)') raise exception.Error(msg % (ec2_id, instance_ref.name)) time.sleep(0.5) - + def live_migration(self, context, instance_ref, dest): """ Just spawning live_migration operation for @@ -895,21 +893,21 @@ class LibvirtConnection(object): duri = FLAGS.live_migration_uri % dest flaglist = FLAGS.live_migration_flag.split(',') - flagvals = [ getattr(libvirt, x.strip()) for x in flaglist ] - logical_sum = reduce(lambda x,y: x|y, flagvals) + flagvals = [getattr(libvirt, x.strip()) for x in flaglist] + logical_sum = reduce(lambda x, y: x | y, flagvals) bandwidth = FLAGS.live_migration_bandwidth - - if self.read_only: + + if self.read_only: tmpconn = self._connect(self.libvirt_uri, False) dom = tmpconn.lookupByName(instance_ref.name) dom.migrateToURI(duri, logical_sum, None, bandwidth) tmpconn.close() - else : + else: dom = self._conn.lookupByName(instance_ref.name) dom.migrateToURI(duri, logical_sum, None, bandwidth) - - except Exception, e: + + except Exception, e: id = instance_ref['id'] db.instance_set_state(context, id, power_state.RUNNING, 'running') try: @@ -950,7 +948,7 @@ class LibvirtConnection(object): # Releasing security group ingress rule. if FLAGS.firewall_driver == \ 'nova.virt.libvirt_conn.IptablesFirewallDriver': - try : + try: self.firewall_driver.remove_instance(instance_ref) except KeyError, e: pass -- cgit From 69c11c27c20c74aced491ecfe78a80872ad6232a Mon Sep 17 00:00:00 2001 From: Andy Smith Date: Fri, 14 Jan 2011 17:54:36 -0800 Subject: pep8 fixes... largely to things from trunk? --- nova/virt/libvirt_conn.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'nova/virt') diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index 073a8e5bb..b06246135 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -995,8 +995,7 @@ class NWFilterFirewall(FirewallDriver): ['no-mac-spoofing', 'no-ip-spoofing', 'no-arp-spoofing', - 'allow-dhcp-server' - ])) + 'allow-dhcp-server'])) self._define_filter(self.nova_base_ipv4_filter) self._define_filter(self.nova_base_ipv6_filter) self._define_filter(self.nova_dhcp_filter) -- cgit From 525544e689334346305ecc11552105fc1b32a5dd Mon Sep 17 00:00:00 2001 From: Kei Masumoto Date: Sun, 16 Jan 2011 14:54:35 +0900 Subject: merged to rev 561 and fixed based on reviewer's comment --- nova/virt/fake.py | 31 +++++++++++++++++ nova/virt/libvirt_conn.py | 86 ++++++++++++++++++++++++++++++++++++----------- nova/virt/xenapi_conn.py | 30 +++++++++++++++++ 3 files changed, 128 insertions(+), 19 deletions(-) (limited to 'nova/virt') diff --git a/nova/virt/fake.py b/nova/virt/fake.py index 9186d885e..3b53f714f 100644 --- a/nova/virt/fake.py +++ b/nova/virt/fake.py @@ -297,6 +297,37 @@ class FakeConnection(object): 'username': 'fakeuser', 'password': 'fakepassword'} + def get_cpu_info(self): + """This method is supported only libvirt. """ + return + + def get_vcpu_number(self): + """This method is supported only libvirt. """ + return -1 + + def get_memory_mb(self): + """This method is supported only libvirt..""" + return -1 + + def get_local_gb(self): + """This method is supported only libvirt..""" + return -1 + + def get_hypervisor_type(self): + """This method is supported only libvirt..""" + return + + def get_hypervisor_version(self): + """This method is supported only libvirt..""" + return -1 + + def compare_cpu(self, xml): + """This method is supported only libvirt..""" + raise NotImplementedError('This method is supported only libvirt.') + + def live_migration(self, context, instance_ref, dest): + """This method is supported only libvirt..""" + raise NotImplementedError('This method is supported only libvirt.') class FakeInstance(object): diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index f3f837153..93e768ae9 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -36,6 +36,7 @@ Supports KVM, QEMU, UML, and XEN. """ +import json import os import shutil import re @@ -82,6 +83,9 @@ flags.DEFINE_string('injected_network_template', flags.DEFINE_string('libvirt_xml_template', utils.abspath('virt/libvirt.xml.template'), 'Libvirt XML Template') +flags.DEFINE_string('cpuinfo_xml_template', + utils.abspath('virt/cpuinfo.xml.template'), + 'CpuInfo XML Template (used only live migration now)') flags.DEFINE_string('libvirt_type', 'kvm', 'Libvirt domain type (valid options are: ' @@ -110,6 +114,11 @@ flags.DEFINE_string('firewall_driver', 'nova.virt.libvirt_conn.IptablesFirewallDriver', 'Firewall driver (defaults to iptables)') +class cpuinfo: + arch = '' + vendor = '' + def __init__(self): pass + def get_connection(read_only): # These are loaded late so that there's no need to install these @@ -145,6 +154,7 @@ class LibvirtConnection(object): self.libvirt_uri = self.get_uri() self.libvirt_xml = open(FLAGS.libvirt_xml_template).read() + self.cpuinfo_xml = open(FLAGS.cpuinfo_xml_template).read() self._wrapped_conn = None self.read_only = read_only @@ -774,7 +784,7 @@ class LibvirtConnection(object): """ Get hypervisor version """ return self._conn.getVersion() - def get_cpu_xml(self): + def get_cpu_info(self): """ Get cpuinfo information """ xmlstr = self._conn.getCapabilities() xml = libxml2.parseDoc(xmlstr) @@ -784,8 +794,40 @@ class LibvirtConnection(object): % len(nodes) msg += '\n' + xml.serialize() raise exception.Invalid(_(msg)) - cpuxmlstr = re.sub("\n|[ ]+", ' ', nodes[0].serialize()) - return cpuxmlstr + + arch = xml.xpathEval('//cpu/arch')[0].getContent() + model = xml.xpathEval('//cpu/model')[0].getContent() + vendor = xml.xpathEval('//cpu/vendor')[0].getContent() + + topology_node = xml.xpathEval('//cpu/topology')[0].get_properties() + topology = dict() + while topology_node != None: + name = topology_node.get_name() + topology[name] = topology_node.getContent() + topology_node = topology_node.get_next() + + keys = ['cores', 'sockets', 'threads'] + tkeys = topology.keys() + if list(set(tkeys)) != list(set(keys)): + msg = _('Invalid xml: topology(%s) must have %s') + raise exception.Invalid(msg % (str(topology), ', '.join(keys))) + + feature_nodes = xml.xpathEval('//cpu/feature') + features = list() + for nodes in feature_nodes: + feature_name = nodes.get_properties().getContent() + features.append(feature_name) + + template = ("""{"arch":"%s", "model":"%s", "vendor":"%s", """ + """"topology":{"cores":"%s", "threads":"%s", "sockets":"%s"}, """ + """"features":[%s]}""") + c = topology['cores'] + s = topology['sockets'] + t = topology['threads'] + f = [ '"%s"' % x for x in features] + cpu_info = template % (arch, model, vendor, c, s, t, ', '.join(f)) + return cpu_info + def block_stats(self, instance_name, disk): """ @@ -817,7 +859,7 @@ class LibvirtConnection(object): def refresh_security_group_members(self, security_group_id): self.firewall_driver.refresh_security_group_members(security_group_id) - def compare_cpu(self, xml): + def compare_cpu(self, cpu_info): """ Check the host cpu is compatible to a cpu given by xml. "xml" must be a part of libvirt.openReadonly().getCapabilities(). @@ -826,6 +868,11 @@ class LibvirtConnection(object): 'http://libvirt.org/html/libvirt-libvirt.html#virCPUCompareResult' """ + dic = json.loads(cpu_info) + print dic + xml = str(Template(self.cpuinfo_xml, searchList=dic)) + msg = _('Checking cpu_info: instance was launched this cpu.\n: %s ') + LOG.info(msg % xml) ret = self._conn.compareCPU(xml, 0) if ret <= 0: url = 'http://libvirt.org/html/libvirt-libvirt.html' @@ -910,13 +957,10 @@ class LibvirtConnection(object): except Exception, e: id = instance_ref['id'] db.instance_set_state(context, id, power_state.RUNNING, 'running') - try: - for volume in db.volume_get_all_by_instance(context, id): - db.volume_update(context, - volume['id'], - {'status': 'in-use'}) - except exception.NotFound: - pass + for v in instance_ref['volumes']: + db.volume_update(context, + v['id'], + {'status': 'in-use'}) raise e @@ -939,6 +983,7 @@ class LibvirtConnection(object): Post operations for live migration. Mainly, database updating. """ + LOG.info('post livemigration operation is started..') # Detaching volumes. # (not necessary in current version ) @@ -949,7 +994,7 @@ class LibvirtConnection(object): if FLAGS.firewall_driver == \ 'nova.virt.libvirt_conn.IptablesFirewallDriver': try: - self.firewall_driver.remove_instance(instance_ref) + self.firewall_driver.unfilter_instance(instance_ref) except KeyError, e: pass @@ -986,22 +1031,25 @@ class LibvirtConnection(object): msg += '%s cannot inherit floating ip.. ' % ec2_id logging.error(_(msg)) + # Restore instance/volume state db.instance_update(context, instance_id, {'state_description': 'running', 'state': power_state.RUNNING, 'host': dest}) - try: - for volume in db.volume_get_all_by_instance(context, instance_id): - db.volume_update(context, - volume['id'], - {'status': 'in-use'}) - except exception.NotFound: - pass + for v in instance_ref['volumes']: + db.volume_update(context, + v['id'], + {'status': 'in-use'}) logging.info(_('Live migrating %s to %s finishes successfully') % (ec2_id, dest)) + msg = _(("""Known error: the below error is nomally occurs.\n""" + """Just check if iinstance is successfully migrated.\n""" + """libvir: QEMU error : Domain not found: no domain """ + """with matching name..""")) + logging.info(msg) class FirewallDriver(object): diff --git a/nova/virt/xenapi_conn.py b/nova/virt/xenapi_conn.py index 45d0738a5..76862be27 100644 --- a/nova/virt/xenapi_conn.py +++ b/nova/virt/xenapi_conn.py @@ -201,6 +201,36 @@ class XenAPIConnection(object): 'username': FLAGS.xenapi_connection_username, 'password': FLAGS.xenapi_connection_password} + def get_cpu_info(self): + """This method is supported only libvirt. """ + return + + def get_vcpu_number(self): + """This method is supported only libvirt. """ + return -1 + + def get_memory_mb(self): + """This method is supported only libvirt..""" + return -1 + + def get_local_gb(self): + """This method is supported only libvirt..""" + return -1 + + def get_hypervisor_type(self): + """This method is supported only libvirt..""" + return + + def get_hypervisor_version(self): + """This method is supported only libvirt..""" + return -1 + + def compare_cpu(self, xml): + raise NotImplementedError('This method is supported only libvirt.') + + def live_migration(self, context, instance_ref, dest): + raise NotImplementedError('This method is supported only libvirt.') + class XenAPISession(object): """The session to invoke XenAPI SDK calls""" -- cgit From a0779f5df2829f91bdc944e7275f44bd831643cc Mon Sep 17 00:00:00 2001 From: Kei Masumoto Date: Wed, 19 Jan 2011 08:49:17 +0900 Subject: fixed based on reviewer's comment --- nova/virt/libvirt_conn.py | 1 + 1 file changed, 1 insertion(+) (limited to 'nova/virt') diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index 541432ce3..534227339 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -1267,6 +1267,7 @@ class NWFilterFirewall(FirewallDriver): # anyway. return + logging.info('ensuring static filters') self._ensure_static_filters() instance_filter_name = self._instance_filter_name(instance) -- cgit From 1dc38833c75d546b1c64d2bcd1f5d9a5bab8836d Mon Sep 17 00:00:00 2001 From: Kei Masumoto Date: Thu, 20 Jan 2011 01:14:23 +0900 Subject: fixed pep8 error --- nova/virt/fake.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'nova/virt') diff --git a/nova/virt/fake.py b/nova/virt/fake.py index b931e3638..80ae7f34c 100644 --- a/nova/virt/fake.py +++ b/nova/virt/fake.py @@ -312,7 +312,7 @@ class FakeConnection(object): def get_cpu_info(self): """This method is supported only libvirt. """ - return + return def get_vcpu_number(self): """This method is supported only libvirt. """ @@ -328,7 +328,7 @@ class FakeConnection(object): def get_hypervisor_type(self): """This method is supported only libvirt..""" - return + return def get_hypervisor_version(self): """This method is supported only libvirt..""" @@ -342,6 +342,7 @@ class FakeConnection(object): """This method is supported only libvirt..""" raise NotImplementedError('This method is supported only libvirt.') + class FakeInstance(object): def __init__(self): -- cgit