由于该文件大于8万字符 所以我分4次挂载(1)

 

     该文件位于nova/virt/libvirt目录下的connection.py!我只是浅浅的分析了一下类中函数的方法 细节并没有多看,肯定有很多地方是错的 或者不好!希望大家能够帮忙指出错误!

      接下来 看源代码如下:中文部分是我加的注释 !或许大家会问 为什么要看这个connection.py呢 因为我发现该文件外部virt目录下有个connection.py 其中引用了 这个文件 所以觉得这个应该很重要 而且发现 好多方法都是重写的底层的driver的方法

 

 
  
  1.  
  2. import hashlib  
  3. import functools  
  4. import multiprocessing  
  5. import netaddr  
  6. import os  
  7. import random  
  8. import re  
  9. import shutil  
  10. import sys  
  11. import tempfile  
  12. import time  
  13. import uuid  
  14. from xml.dom import minidom  
  15. from xml.etree import ElementTree  
  16.  
  17. from eventlet import greenthread  
  18. from eventlet import tpool  
  19.  
  20. from nova import block_device  
  21. from nova import context as nova_context  
  22. from nova import db  
  23. from nova import exception  
  24. from nova import flags  
  25. import nova.p_w_picpath  
  26. from nova import log as logging  
  27. from nova import utils  
  28. from nova import vnc  
  29. from nova.auth import manager  
  30. from nova.compute import instance_types  
  31. from nova.compute import power_state  
  32. from nova.virt import disk  
  33. from nova.virt import driver  
  34. from nova.virt import p_w_picpaths  
  35. from nova.virt.libvirt import netutils  
  36.  
  37.  
  38. libvirt = None 
  39. libxml2 = None 
  40. Template = None 
  41.  
  42.  
  43. LOG = logging.getLogger('nova.virt.libvirt_conn')  
  44.  
  45.  
  46. FLAGS = flags.FLAGS  
  47. flags.DECLARE('live_migration_retry_count''nova.compute.manager')  
  48. # TODO(vish): These flags should probably go into a shared location  
  49. #这些标志应该进入共享位置  
  50. flags.DEFINE_string('rescue_p_w_picpath_id'None'Rescue ami p_w_picpath')  
  51. flags.DEFINE_string('rescue_kernel_id'None'Rescue aki p_w_picpath')  
  52. flags.DEFINE_string('rescue_ramdisk_id'None'Rescue ari p_w_picpath')  
  53. flags.DEFINE_string('libvirt_xml_template',  
  54.                     utils.abspath('virt/libvirt.xml.template'),  
  55.                     'Libvirt XML Template')  
  56. flags.DEFINE_string('libvirt_type',  
  57.                     'kvm',  
  58.                     'Libvirt domain type (valid options are: ' 
  59.                     'kvm, lxc, qemu, uml, xen)')  
  60. flags.DEFINE_string('libvirt_uri',  
  61.                     '',  
  62.                     'Override the default libvirt URI (which is dependent' 
  63.                     ' on libvirt_type)')  
  64. flags.DEFINE_bool('allow_same_net_traffic',  
  65.                   True,  
  66.                   'Whether to allow network traffic from same network')  
  67. flags.DEFINE_bool('use_cow_p_w_picpaths',  
  68.                   True,  
  69.                   'Whether to use cow p_w_picpaths')  
  70. flags.DEFINE_string('ajaxterm_portrange',  
  71.                     '10000-12000',  
  72.                     'Range of ports that ajaxterm should randomly try to bind')  
  73. flags.DEFINE_string('firewall_driver',  
  74.                     'nova.virt.libvirt.firewall.IptablesFirewallDriver',  
  75.                     'Firewall driver (defaults to iptables)')  
  76. flags.DEFINE_string('cpuinfo_xml_template',  
  77.                     utils.abspath('virt/cpuinfo.xml.template'),  
  78.                     'CpuInfo XML Template (Used only live migration now)')  
  79. flags.DEFINE_string('live_migration_uri',  
  80.                     "qemu+tcp://%s/system",  
  81.                     'Define protocol used by live_migration feature')  
  82. flags.DEFINE_string('live_migration_flag',  
  83.                     "VIR_MIGRATE_UNDEFINE_SOURCE, VIR_MIGRATE_PEER2PEER",  
  84.                     'Define live migration behavior.')  
  85. flags.DEFINE_string('block_migration_flag',  
  86.                     "VIR_MIGRATE_UNDEFINE_SOURCE, VIR_MIGRATE_PEER2PEER, " 
  87.                     "VIR_MIGRATE_NON_SHARED_INC",  
  88.                     'Define block migration behavior.')  
  89. flags.DEFINE_integer('live_migration_bandwidth'0,  
  90.                     'Define live migration behavior')  
  91. flags.DEFINE_string('snapshot_p_w_picpath_format'None,  
  92.                     'Snapshot p_w_picpath format (valid options are : ' 
  93.                     'raw, qcow2, vmdk, vdi).' 
  94.                     'Defaults to same as source p_w_picpath')  
  95. flags.DEFINE_string('libvirt_vif_type''bridge',  
  96.                     'Type of VIF to create.')  
  97. flags.DEFINE_string('libvirt_vif_driver',  
  98.                     'nova.virt.libvirt.vif.LibvirtBridgeDriver',  
  99.                     'The libvirt VIF driver to configure the VIFs.')  
  100. flags.DEFINE_string('default_local_format',  
  101.                     None,  
  102.                     'The default format a local_volume will be formatted with ' 
  103.                     'on creation.')  
  104. flags.DEFINE_bool('libvirt_use_virtio_for_bridges',  
  105.                   False,  
  106.                   'Use virtio for bridge interfaces')  
  107.  
  108. #get_connection 获得与hypervisor(管理程序)的连接  
  109. def get_connection(read_only):  
  110.     # These are loaded late so that there's no need to install these  
  111.     # libraries when not using libvirt.  
  112.     # Cheetah is separate because the unit tests want to load Cheetah,  
  113.     # but not libvirt.  
  114.     global libvirt  
  115.     global libxml2  
  116.     if libvirt is None:  
  117.         libvirt = __import__('libvirt')  
  118.     if libxml2 is None:  
  119.         libxml2 = __import__('libxml2')  
  120.     _late_load_cheetah() #实际上是延迟引入模板  
  121.     return LibvirtConnection(read_only)  
  122.  
  123.  
  124. def _late_load_cheetah():  
  125.     global Template  
  126.     if Template is None:  
  127.         t = __import__('Cheetah.Template', globals(), locals(),  
  128.                        ['Template'], -1)  
  129.         Template = t.Template  
  130.  
  131.  
  132. def _get_eph_disk(ephemeral):  
  133.     return 'disk.eph' + str(ephemeral['num'])  
  134.  
  135.  
  136. class LibvirtConnection(driver.ComputeDriver):  
  137.     #这个类 LibvirtConnection是继承的drive.ComputerDriver  
  138.     #为了让大家一目了然 后面会插入一个 LibvirtConnection 的类图  
  139.  
  140.     def __init__(self, read_only):  
  141.         super(LibvirtConnection, self).__init__() #父类的初始化  
  142.         self.libvirt_uri = self.get_uri()  
  143.         #2、获得链接  
  144.         """  
  145.          self.libvirt_uri = self.get_uri()    
  146.  
  147.         get_uri()函数如下定义。  
  148.  
  149.             def get_uri(self):  
  150.             if FLAGS.libvirt_type == 'uml':  
  151.                 uri = FLAGS.libvirt_uri or 'uml:///system'  
  152.             elif FLAGS.libvirt_type == 'xen':  
  153.                 uri = FLAGS.libvirt_uri or 'xen:///'  
  154.             elif FLAGS.libvirt_type == 'lxc':  
  155.                 uri = FLAGS.libvirt_uri or 'lxc:///'  
  156.             else:  
  157.                 uri = FLAGS.libvirt_uri or 'qemu:///system'  
  158.             return uri  
  159.         """ 
  160.  
  161.         #设置模板  
  162.         self.libvirt_xml = open(FLAGS.libvirt_xml_template).read()  
  163.         self.cpuinfo_xml = open(FLAGS.cpuinfo_xml_template).read()  
  164.         self._wrapped_conn = None 
  165.         self.read_only = read_only  
  166.         #设置firewall  
  167.         fw_class = utils.import_class(FLAGS.firewall_driver) #获得类名  
  168.         self.firewall_driver = fw_class(get_connection=self._get_connection)  
  169.         #获得链接调用—get_connection  
  170.         """函数如下  
  171.         def _get_connection(self):  
  172.         if not self._wrapped_conn or not self._test_connection():  
  173.             LOG.debug(_('Connecting to libvirt: %s'), self.libvirt_uri)  
  174.             self._wrapped_conn = self._connect(self.libvirt_uri,  
  175.                                                self.read_only)  
  176.             #此处是_connect函数 这个函数是从底层libvirt库中拿到链接  
  177.             #def _connect(self, uri, read_only): auth = [[libvirt.VIR_CRED_AUTHNAME, libvirt.VIR_CRED_NOECHOPROMPT],'root',None]  
  178.  
  179.             #       if read_only:  
  180.             #           return libvirt.openReadOnly(uri)  
  181.             #       else:  
  182.             #           return libvirt.openAuth(uri, auth, 0)  
  183.  
  184.         return self._wrapped_conn  
  185.         """ 
  186.         self.vif_driver = utils.import_object(FLAGS.libvirt_vif_driver)  
  187.  
  188.     def init_host(self, host):  
  189.         # NOTE(nsokolov): moved instance restarting to ComputeManager  
  190.         pass 
  191.  
  192.     def _get_connection(self):  
  193.         #获得链接  
  194.         if not self._wrapped_conn or not self._test_connection():  
  195.             LOG.debug(_('Connecting to libvirt: %s'), self.libvirt_uri)  
  196.             self._wrapped_conn = self._connect(self.libvirt_uri,  
  197.                                                self.read_only)  
  198.         return self._wrapped_conn  
  199.     _conn = property(_get_connection)  
  200.  
  201.     def _test_connection(self):  
  202.         #测试链接  
  203.         try:  
  204.             self._wrapped_conn.getCapabilities()  
  205.             return True 
  206.         except libvirt.libvirtError as e:  
  207.             if e.get_error_code() == libvirt.VIR_ERR_SYSTEM_ERROR and \  
  208.                e.get_error_domain() == libvirt.VIR_FROM_REMOTE:  
  209.                 LOG.debug(_('Connection to libvirt broke'))  
  210.                 return False 
  211.             raise 
  212.  
  213.     def get_uri(self):  
  214.         #获得url 提供被调用  
  215.         if FLAGS.libvirt_type == 'uml':  
  216.             uri = FLAGS.libvirt_uri or 'uml:///system' 
  217.         elif FLAGS.libvirt_type == 'xen':  
  218.             uri = FLAGS.libvirt_uri or 'xen:///' 
  219.         elif FLAGS.libvirt_type == 'lxc':  
  220.             uri = FLAGS.libvirt_uri or 'lxc:///' 
  221.         else:  
  222.             uri = FLAGS.libvirt_uri or 'qemu:///system' 
  223.         return uri  
  224.  
  225.     def _connect(self, uri, read_only):  
  226.         #链接  
  227.         auth = [[libvirt.VIR_CRED_AUTHNAME, libvirt.VIR_CRED_NOECHOPROMPT],  
  228.                 'root',  
  229.                 None]  
  230.  
  231.         if read_only:  
  232.             return libvirt.openReadOnly(uri)  
  233.         else:  
  234.             return libvirt.openAuth(uri, auth, 0)  
  235.  
  236.     def list_instances(self):  
  237.         return [self._conn.lookupByID(x).name()  
  238.                 for x in self._conn.listDomainsID()]  
  239.  
  240.     def _map_to_instance_info(self, domain):  
  241.         #从一个virsh(虚拟)域对象到一个 InstanceInfO得到信息  
  242.         """Gets info from a virsh domain object into an InstanceInfo""" 
  243.  
  244.         # domain.info() returns a list of:  
  245.         #    state:       one of the state values (virDomainState)  
  246.         #    maxMemory:   the maximum memory used by the domain  
  247.         #    memory:      the current amount of memory used by the domain  
  248.         #    nbVirtCPU:   the number of virtual CPU  
  249.         #    puTime:      the time used by the domain in nanoseconds  
  250.  
  251.         (state, _max_mem, _mem, _num_cpu, _cpu_time) = domain.info()  
  252.         name = domain.name()  
  253.  
  254.         return driver.InstanceInfo(name, state)  
  255.  
  256.     def list_instances_detail(self):  
  257.         #返回一个信息列表   
  258.         infos = []  
  259.         for domain_id in self._conn.listDomainsID():  
  260.             domain = self._conn.lookupByID(domain_id)  
  261.             info = self._map_to_instance_info(domain)  
  262.             infos.append(info)  
  263.         return infos  
  264.  
  265.     def plug_vifs(self, instance, network_info):  
  266.         #接通VIFs(虚拟接口) 的网络  
  267.           
  268.         """Plugin VIFs into networks.""" 
  269.         for (network, mapping) in network_info:  
  270.             self.vif_driver.plug(instance, network, mapping)  
  271.  
  272.     def destroy(self, instance, network_info, cleanup=True):  
  273.         #Destroy (shutdown and delete) the specified instance.  
  274.  
  275.         instance_name = instance['name']  
  276.  
  277.         try:  
  278.             virt_dom = self._lookup_by_name(instance_name)  
  279.         except exception.NotFound:  
  280.             virt_dom = None 
  281.  
  282.         # If the instance is already terminated, we're still happy  
  283.         # Otherwise, destroy it  
  284.         if virt_dom is not None:  
  285.             try:  
  286.                 virt_dom.destroy()  
  287.             except libvirt.libvirtError as e:  
  288.                 is_okay = False 
  289.                 errcode = e.get_error_code()  
  290.                 if errcode == libvirt.VIR_ERR_OPERATION_INVALID:  
  291.                     # If the instance if already shut off, we get this:  
  292.                     # Code=55 Error=Requested operation is not valid:  
  293.                     # domain is not running  
  294.                     (state, _max_mem, _mem, _cpus, _t) = virt_dom.info()  
  295.                     if state == power_state.SHUTOFF:  
  296.                         is_okay = True 
  297.  
  298.                 if not is_okay:  
  299.                     LOG.warning(_("Error from libvirt during destroy of " 
  300.                                   "%(instance_name)s. Code=%(errcode)s " 
  301.                                   "Error=%(e)s") %  
  302.                                 locals())  
  303.                     raise 
  304.  
  305.             try:  
  306.                 # NOTE(justinsb): We remove the domain definition. We probably  
  307.                 # would do better to keep it if cleanup=False (e.g. volumes?)  
  308.                 # (e.g. #2 - not losing machines on failure)  
  309.                 virt_dom.undefine()  
  310.             except libvirt.libvirtError as e:  
  311.                 errcode = e.get_error_code()  
  312.                 LOG.warning(_("Error from libvirt during undefine of " 
  313.                               "%(instance_name)s. Code=%(errcode)s " 
  314.                               "Error=%(e)s") %  
  315.                             locals())  
  316.                 raise 
  317.  
  318.             for (network, mapping) in network_info:  
  319.                 self.vif_driver.unplug(instance, network, mapping)  
  320.  
  321.         def _wait_for_destroy():  
  322.             """Called at an interval until the VM is gone.""" 
  323.             instance_name = instance['name']  
  324.  
  325.             try:  
  326.                 state = self.get_info(instance_name)['state']  
  327.             except exception.NotFound:  
  328.                 msg = _("Instance %s destroyed successfully.") % instance_name  
  329.                 LOG.info(msg)  
  330.                 raise utils.LoopingCallDone  
  331.  
  332.         timer = utils.LoopingCall(_wait_for_destroy)  
  333.         timer.start(interval=0.5, now=True)  
  334.  
  335.         self.firewall_driver.unfilter_instance(instance,  
  336.                                                network_info=network_info)  
  337.  
  338.         if cleanup:  
  339.             self._cleanup(instance)  
  340.  
  341.         return True 
  342.  
  343.     def _cleanup(self, instance):  
  344.         target = os.path.join(FLAGS.instances_path, instance['name'])  
  345.         instance_name = instance['name']  
  346.         LOG.info(_('instance %(instance_name)s: deleting instance files' 
  347.                 ' %(target)s') % locals())  
  348.         if FLAGS.libvirt_type == 'lxc':  
  349.             disk.destroy_container(target, instance, nbd=FLAGS.use_cow_p_w_picpaths)  
  350.         if os.path.exists(target):  
  351.             shutil.rmtree(target)  
  352.  
  353.     @exception.wrap_exception()  
  354.     def attach_volume(self, instance_name, device_path, mountpoint):  
  355.         #在挂载点设置实例磁盘的路径  
  356.         virt_dom = self._lookup_by_name(instance_name)  
  357.         mount_device = mountpoint.rpartition("/")[2]  
  358.         (type, protocol, name) = \  
  359.             self._get_volume_device_info(device_path)  
  360.         if type == 'block':  
  361.             xml = """<disk type='block'>  
  362.                          <driver name='qemu' type='raw'/>  
  363.                          <source dev='%s'/>  
  364.                          <target dev='%s' bus='virtio'/>  
  365.                      </disk>""" % (device_path, mount_device)  
  366.         elif type == 'network':  
  367.             xml = """<disk type='network'>  
  368.                          <driver name='qemu' type='raw'/>  
  369.                          <source protocol='%s' name='%s'/>  
  370.                          <target dev='%s' bus='virtio'/>  
  371.                      </disk>""" % (protocol, name, mount_device)  
  372.         virt_dom.attachDevice(xml)  
  373.  
  374.     def _get_disk_xml(self, xml, device):  
  375.         """Returns the xml for the disk mounted at device""" 
  376.         #返回磁盘在设备上磁盘安装的xml  
  377.         try:  
  378.             doc = libxml2.parseDoc(xml)  
  379.         except Exception:  
  380.             return None 
  381.         ctx = doc.xpathNewContext()  
  382.         try:  
  383.             ret = ctx.xpathEval('/domain/devices/disk')  
  384.             for node in ret:  
  385.                 for child in node.children:  
  386.                     if child.name == 'target':  
  387.                         if child.prop('dev') == device:  
  388.                             return str(node)  
  389.         finally:  
  390.             if ctx is not None:  
  391.                 ctx.xpathFreeContext()  
  392.             if doc is not None:  
  393.                 doc.freeDoc()  
  394.  
  395.     @exception.wrap_exception()  
  396.     def detach_volume(self, instance_name, mountpoint):  
  397.         virt_dom = self._lookup_by_name(instance_name)  
  398.         mount_device = mountpoint.rpartition("/")[2]  
  399.         xml = self._get_disk_xml(virt_dom.XMLDesc(0), mount_device)  
  400.         if not xml:  
  401.             raise exception.DiskNotFound(location=mount_device)  
  402.         virt_dom.detachDevice(xml)  
  403.  
  404.     @exception.wrap_exception()  
  405.     def snapshot(self, context, instance, p_w_picpath_href):  
  406.         """Create snapshot from a running VM instance.  
  407.  
  408.         This command only works with qemu 0.14+  
  409.         """ 
  410.         virt_dom = self._lookup_by_name(instance['name'])  
  411.  
  412.         (p_w_picpath_service, p_w_picpath_id) = nova.p_w_picpath.get_p_w_picpath_service(  
  413.             context, instance['p_w_picpath_ref'])  
  414.         base = p_w_picpath_service.show(context, p_w_picpath_id)  
  415.         (snapshot_p_w_picpath_service, snapshot_p_w_picpath_id) = \  
  416.             nova.p_w_picpath.get_p_w_picpath_service(context, p_w_picpath_href)  
  417.         snapshot = snapshot_p_w_picpath_service.show(context, snapshot_p_w_picpath_id)  
  418.  
  419.         metadata = {'is_public'False,  
  420.                     'status''active',  
  421.                     'name': snapshot['name'],  
  422.                     'properties': {  
  423.                                    'kernel_id': instance['kernel_id'],  
  424.                                    'p_w_picpath_location''snapshot',  
  425.                                    'p_w_picpath_state''available',  
  426.                                    'owner_id': instance['project_id'],  
  427.                                    'ramdisk_id': instance['ramdisk_id'],  
  428.                                    }  
  429.                     }  
  430.         if 'architecture' in base['properties']:  
  431.             arch = base['properties']['architecture']  
  432.             metadata['properties']['architecture'] = arch  
  433.  
  434.         source_format = base.get('disk_format'or 'raw' 
  435.         p_w_picpath_format = FLAGS.snapshot_p_w_picpath_format or source_format  
  436.         if FLAGS.use_cow_p_w_picpaths:  
  437.             source_format = 'qcow2' 
  438.         metadata['disk_format'] = p_w_picpath_format  
  439.  
  440.         if 'container_format' in base:  
  441.             metadata['container_format'] = base['container_format']  
  442.  
  443.         # Make the snapshot  
  444.         snapshot_name = uuid.uuid4().hex  
  445.         snapshot_xml = """  
  446.         <domainsnapshot>  
  447.             <name>%s</name>  
  448.         </domainsnapshot>  
  449.         """ % snapshot_name  
  450.         snapshot_ptr = virt_dom.snapshotCreateXML(snapshot_xml, 0)  
  451.  
  452.         # Find the disk  
  453.         xml_desc = virt_dom.XMLDesc(0)  
  454.         domain = ElementTree.fromstring(xml_desc)  
  455.         source = domain.find('devices/disk/source')  
  456.         disk_path = source.get('file')  
  457.  
  458.         # Export the snapshot to a raw p_w_picpath  
  459.         temp_dir = tempfile.mkdtemp()  
  460.         out_path = os.path.join(temp_dir, snapshot_name)  
  461.         qemu_img_cmd = ('qemu-img',  
  462.                         'convert',  
  463.                         '-f',  
  464.                         source_format,  
  465.                         '-O',  
  466.                         p_w_picpath_format,  
  467.                         '-s',  
  468.                         snapshot_name,  
  469.                         disk_path,  
  470.                         out_path)  
  471.         utils.execute(*qemu_img_cmd)  
  472.  
  473.         # Upload that p_w_picpath to the p_w_picpath service  
  474.         with open(out_path) as p_w_picpath_file:  
  475.             p_w_picpath_service.update(context,  
  476.                                  p_w_picpath_href,  
  477.                                  metadata,  
  478.                                  p_w_picpath_file)  
  479.  
  480.         # Clean up  
  481.         shutil.rmtree(temp_dir)  
  482.         snapshot_ptr.delete(0)  
  483.  
  484.     @exception.wrap_exception()  
  485.     def reboot(self, instance, network_info, xml=None):  
  486.         """Reboot a virtual machine, given an instance reference.  
  487.  
  488.         This method actually destroys and re-creates the domain to ensure the  
  489.         reboot happens, as the guest OS cannot ignore this action.  
  490.  
  491.         """ 
  492.         virt_dom = self._conn.lookupByName(instance['name'])  
  493.         # NOTE(itoumsn): Use XML delived from the running instance  
  494.         # instead of using to_xml(instance, network_info). This is almost  
  495.         # the ultimate stupid workaround.  
  496.         if not xml:  
  497.             xml = virt_dom.XMLDesc(0)  
  498.  
  499.         # NOTE(itoumsn): self.shutdown() and wait instead of self.destroy() is  
  500.         # better because we cannot ensure flushing dirty buffers  
  501.         # in the guest OS. But, in case of KVM, shutdown() does not work...  
  502.         self.destroy(instance, network_info, cleanup=False)  
  503.         self.plug_vifs(instance, network_info)  
  504.         self.firewall_driver.setup_basic_filtering(instance, network_info)  
  505.         self.firewall_driver.prepare_instance_filter(instance, network_info)  
  506.         self._create_new_domain(xml)  
  507.         self.firewall_driver.apply_instance_filter(instance, network_info)  
  508.  
  509.         def _wait_for_reboot():  
  510.             """Called at an interval until the VM is running again.""" 
  511.             instance_name = instance['name']  
  512.  
  513.             try:  
  514.                 state = self.get_info(instance_name)['state']  
  515.             except exception.NotFound:  
  516.                 msg = _("During reboot, %s disappeared.") % instance_name  
  517.                 LOG.error(msg)  
  518.                 raise utils.LoopingCallDone  
  519.  
  520.             if state == power_state.RUNNING:  
  521.                 msg = _("Instance %s rebooted successfully.") % instance_name  
  522.                 LOG.info(msg)  
  523.                 raise utils.LoopingCallDone  
  524.  
  525.         timer = utils.LoopingCall(_wait_for_reboot)  
  526.         return timer.start(interval=0.5, now=True)  
  527.  
  528.     @exception.wrap_exception()  
  529.     def pause(self, instance, callback):  
  530.         """Pause VM instance""" 
  531.         dom = self._lookup_by_name(instance.name)  
  532.         dom.suspend()  
  533.  
  534.     @exception.wrap_exception()  
  535.     def unpause(self, instance, callback):  
  536.         """Unpause paused VM instance""" 
  537.         dom = self._lookup_by_name(instance.name)  
  538.         dom.resume()  
  539.  
  540.     @exception.wrap_exception()  
  541.     def suspend(self, instance, callback):  
  542.         """Suspend the specified instance""" 
  543.         dom = self._lookup_by_name(instance.name)  
  544.         dom.managedSave(0)  
  545.  
  546.     @exception.wrap_exception()  
  547.     def resume(self, instance, callback):  
  548.         """resume the specified instance""" 
  549.         dom = self._lookup_by_name(instance.name)  
  550.         dom.create()  
  551.  
  552.     @exception.wrap_exception()