分享

openstack nova 源码分析4-1 -nova/virt/libvirt目录下的connection.py

nettman 发表于 2014-11-18 14:44:22 [显示全部楼层] 回帖奖励 阅读模式 关闭右栏 0 26236
导读:

该文件位于nova/virt/libvirt目录下的connection.py!我只是浅浅的分析了一下类中函数的方法 细节并没有多看,肯定有很多地方是错的 或者不好!希望大家能够帮忙指出错误!
      接下来 看源代码如下:中文部分是我加的注释 !或许大家会问 为什么要看这个connection.py呢 因为我发现该文件外部virt目录下有个connection.py 其中引用了 这个文件 所以觉得这个应该很重要 而且发现 好多方法都是重写的底层的driver的方法




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





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

    接下来 看源代码如下:中文部分是我加的注释 !或许大家会问 为什么要看这个connection.py呢 因为我发现该文件外部virt目录下有个connection.py 其中引用了 这个文件 所以觉得这个应该很重要 而且发现 好多方法都是重写的底层的driver的方法
  1. def rescue(self, context, instance, callback, network_info):  
  2.        #使用恢复镜像 加载一个vM  
  3.        """Loads a VM using rescue images.  
  4.    
  5.        A rescue is normally performed when something goes wrong with the  
  6.        primary images and data needs to be corrected/recovered. Rescuing  
  7.        should not edit or over-ride the original image, only allow for  
  8.        data recovery.  
  9.        """
  10.        virt_dom = self._conn.lookupByName(instance['name'])  
  11.        unrescue_xml = virt_dom.XMLDesc(0)  
  12.        unrescue_xml_path = os.path.join(FLAGS.instances_path,  
  13.                                         instance['name'],  
  14.                                         'unrescue.xml')  
  15.        f = open(unrescue_xml_path, 'w')  
  16.        f.write(unrescue_xml)  
  17.        f.close()  
  18.        xml = self.to_xml(instance, network_info, rescue=True)  
  19.        rescue_images = {  
  20.            'image_id': FLAGS.rescue_image_id or instance['image_ref'],  
  21.            'kernel_id': FLAGS.rescue_kernel_id or instance['kernel_id'],  
  22.            'ramdisk_id': FLAGS.rescue_ramdisk_id or instance['ramdisk_id'],  
  23.        }  
  24.        self._create_image(context, instance, xml, '.rescue', rescue_images,  
  25.                           network_info=network_info)  
  26.        self.reboot(instance, network_info, xml=xml)  
  27.    @exception.wrap_exception()  
  28.    def unrescue(self, instance, callback, network_info):  
  29.        """Reboot the VM which is being rescued back into primary images.  
  30.        Because reboot destroys and re-creates instances, unresue should  
  31.        simply call reboot.  
  32.        """
  33.        unrescue_xml_path = os.path.join(FLAGS.instances_path,  
  34.                                         instance['name'],  
  35.                                         'unrescue.xml')  
  36.        f = open(unrescue_xml_path)  
  37.        unrescue_xml = f.read()  
  38.        f.close()  
  39.        os.remove(unrescue_xml_path)  
  40.        self.reboot(instance, network_info, xml=unrescue_xml)  
  41.    @exception.wrap_exception()  
  42.    def poll_rescued_instances(self, timeout):  
  43.        #轮询已经恢复的实例  
  44.        pass
  45.    # NOTE(ilyaalekseyev): Implementation like in multinics  
  46.    # for xenapi(tr3buchet)  
  47.    @exception.wrap_exception()  
  48.    def spawn(self, context, instance, network_info,  
  49.              block_device_info=None):  
  50.        #感觉像是防火墙的过滤  
  51.        xml = self.to_xml(instance, network_info, False,  
  52.                          block_device_info=block_device_info)  
  53.        self.firewall_driver.setup_basic_filtering(instance, network_info)  
  54.        self.firewall_driver.prepare_instance_filter(instance, network_info)  
  55.        self._create_image(context, instance, xml, network_info=network_info,  
  56.                           block_device_info=block_device_info)  
  57.        domain = self._create_new_domain(xml)  
  58.        LOG.debug(_("instance %s: is running"), instance['name'])  
  59.        self.firewall_driver.apply_instance_filter(instance, network_info)  
  60.        def _wait_for_boot():  
  61.            """Called at an interval until the VM is running."""
  62.            instance_name = instance['name']  
  63.            try:  
  64.                state = self.get_info(instance_name)['state']  
  65.            except exception.NotFound:  
  66.                msg = _("During reboot, %s disappeared.") % instance_name  
  67.                LOG.error(msg)  
  68.                raise utils.LoopingCallDone  
  69.            if state == power_state.RUNNING:  
  70.                msg = _("Instance %s spawned successfully.") % instance_name  
  71.                LOG.info(msg)  
  72.                raise utils.LoopingCallDone  
  73.        timer = utils.LoopingCall(_wait_for_boot)  
  74.        return timer.start(interval=0.5, now=True)  
  75.    def _flush_xen_console(self, virsh_output):  
  76.        #清除??  
  77.        LOG.info(_('virsh said: %r'), virsh_output)  
  78.        virsh_output = virsh_output[0].strip()  
  79.        if virsh_output.startswith('/dev/'):  
  80.            LOG.info(_("cool, it's a device"))  
  81.            out, err = utils.execute('dd',  
  82.                                     "if=%s" % virsh_output,  
  83.                                     'iflag=nonblock',  
  84.                                     run_as_root=True,  
  85.                                     check_exit_code=False)  
  86.            return out  
  87.        else:  
  88.            return ''
  89.    def _append_to_file(self, data, fpath):  
  90.        #写入fp中 返回fpath  
  91.        LOG.info(_('data: %(data)r, fpath: %(fpath)r') % locals())  
  92.        fp = open(fpath, 'a+')  
  93.        fp.write(data)  
  94.        return fpath  
  95.    def _dump_file(self, fpath):  
  96.        #返回读出来的contents  
  97.        fp = open(fpath, 'r+')  
  98.        contents = fp.read()  
  99.        LOG.info(_('Contents of file %(fpath)s: %(contents)r') % locals())  
  100.        return contents  
  101.    @exception.wrap_exception()  
  102.    def get_console_output(self, instance):  
  103.        #得到控制台的outPut 最后返回的是fpath里面的contents  
  104.        console_log = os.path.join(FLAGS.instances_path, instance['name'],  
  105.                                   'console.log')  
  106.        utils.execute('chown', os.getuid(), console_log, run_as_root=True)  
  107.        if FLAGS.libvirt_type == 'xen':  
  108.            # Xen is special  
  109.            virsh_output = utils.execute('virsh', 'ttyconsole',  
  110.                                         instance['name'])  
  111.            data = self._flush_xen_console(virsh_output)  
  112.            fpath = self._append_to_file(data, console_log)  
  113.        elif FLAGS.libvirt_type == 'lxc':  
  114.            # LXC is also special  
  115.            LOG.info(_("Unable to read LXC console"))  
  116.        else:  
  117.            fpath = console_log  
  118.        return self._dump_file(fpath)  
  119.    @exception.wrap_exception()  
  120.    def get_ajax_console(self, instance):  
  121.        def get_open_port():  
  122.            start_port, end_port = FLAGS.ajaxterm_portrange.split("-")  
  123.            for i in xrange(0, 100):  # don't loop forever  
  124.                port = random.randint(int(start_port), int(end_port))  
  125.                # netcat will exit with 0 only if the port is in use,  
  126.                # so a nonzero return value implies it is unused  
  127.                cmd = 'netcat', '0.0.0.0', port, '-w', '1'
  128.                try:  
  129.                    stdout, stderr = utils.execute(*cmd, process_input='')  
  130.                except exception.ProcessExecutionError:  
  131.                    return port  
  132.            raise Exception(_('Unable to find an open port'))  
  133.        def get_pty_for_instance(instance_name):  
  134.            virt_dom = self._lookup_by_name(instance_name)  
  135.            xml = virt_dom.XMLDesc(0)  
  136.            dom = minidom.parseString(xml)  
  137.            for serial in dom.getElementsByTagName('serial'):  
  138.                if serial.getAttribute('type') == 'pty':  
  139.                    source = serial.getElementsByTagName('source')[0]  
  140.                    return source.getAttribute('path')  
  141.        port = get_open_port()  
  142.        token = str(uuid.uuid4())  
  143.        host = instance['host']  
  144.        ajaxterm_cmd = 'sudo socat - %s' \  
  145.                       % get_pty_for_instance(instance['name'])  
  146.        cmd = ['%s/tools/ajaxterm/ajaxterm.py' % utils.novadir(),  
  147.               '--command', ajaxterm_cmd, '-t', token, '-p', port]  
  148.        utils.execute(cmd)  
  149.        return {'token': token, 'host': host, 'port': port}  
  150.    def get_host_ip_addr(self):  
  151.        # Retrieves the IP address of the dom0得到主机ip地址  
  152.        return FLAGS.my_ip  
  153.    @exception.wrap_exception()  
  154.    def get_vnc_console(self, instance):  
  155.        #取得虚拟网络计算机的控制 最后返回 token,host,port  
  156.        def get_vnc_port_for_instance(instance_name):  
  157.            virt_dom = self._lookup_by_name(instance_name)  
  158.            xml = virt_dom.XMLDesc(0)  
  159.            # TODO: use etree instead of minidom  
  160.            dom = minidom.parseString(xml)  
  161.            for graphic in dom.getElementsByTagName('graphics'):  
  162.                if graphic.getAttribute('type') == 'vnc':  
  163.                    return graphic.getAttribute('port')  
  164.        port = get_vnc_port_for_instance(instance['name'])  
  165.        token = str(uuid.uuid4())  
  166.        host = instance['host']  
  167.        return {'token': token, 'host': host, 'port': port}  
  168.    @staticmethod
  169.    def _cache_image(fn, target, fname, cow=False, *args, **kwargs):  
  170.        #封装一个方法是他能够创建一个可以缓存镜像的镜像  
  171.        """Wrapper for a method that creates an image that caches the image.  
  172.        This wrapper will save the image into a common store and create a  
  173.        copy for use by the hypervisor.  
  174.        The underlying method should specify a kwarg of target representing  
  175.        where the image will be saved.  
  176.        fname is used as the filename of the base image.  The filename needs  
  177.        to be unique to a given image.  
  178.        If cow is True, it will make a CoW image instead of a copy.  
  179.        """
  180.        if not os.path.exists(target):  
  181.            base_dir = os.path.join(FLAGS.instances_path, '_base')  
  182.            if not os.path.exists(base_dir):  
  183.                os.mkdir(base_dir)  
  184.            base = os.path.join(base_dir, fname)  
  185.            @utils.synchronized(fname)  
  186.            def call_if_not_exists(base, fn, *args, **kwargs):  
  187.                if not os.path.exists(base):  
  188.                    fn(target=base, *args, **kwargs)  
  189.            call_if_not_exists(base, fn, *args, **kwargs)  
  190.            if cow:  
  191.                utils.execute('qemu-img', 'create', '-f', 'qcow2', '-o',  
  192.                              'cluster_size=2M,backing_file=%s' % base,  
  193.                              target)  
  194.            else:  
  195.                utils.execute('cp', base, target)  
  196.    def _fetch_image(self, context, target, image_id, user_id, project_id,  
  197.                     size=None):  
  198.        """Grab image and optionally attempt to resize it"""
  199.        #GRAB 镜像和可选地试图调整他  
  200.        images.fetch_to_raw(context, image_id, target, user_id, project_id)  
  201.        if size:  
  202.            disk.extend(target, size)  
  203.    def _create_local(self, target, local_size, unit='G', fs_format=None):  
  204.        """Create a blank image of specified size"""
  205.        #创建一个空的指定size的镜像  
  206.        if not fs_format:  
  207.            fs_format = FLAGS.default_local_format  
  208.        utils.execute('truncate', target, '-s', "%d%c" % (local_size, unit))  
  209.        if fs_format:  
  210.            utils.execute('mkfs', '-t', fs_format, target)  
  211.    def _create_ephemeral(self, target, local_size, fs_label, os_type):  
  212.        self._create_local(target, local_size)  
  213.        disk.mkfs(os_type, fs_label, target)  
  214.    def _create_swap(self, target, swap_mb):  
  215.        """Create a swap file of specified size"""
  216.        #创建一个指定size的swap file  
  217.        self._create_local(target, swap_mb, unit='M')  
  218.        utils.execute('mkswap', target)  
  219.    def _create_image(self, context, inst, libvirt_xml, suffix='',  
  220.                      disk_images=None, network_info=None,  
  221.                      block_device_info=None):  
  222.        if not suffix:  
  223.            suffix = ''
  224.        # syntactic nicety  
  225.        def basepath(fname='', suffix=suffix):  
  226.            return os.path.join(FLAGS.instances_path,  
  227.                                inst['name'],  
  228.                                fname + suffix)  
  229.        # ensure directories exist and are writable  
  230.        utils.execute('mkdir', '-p', basepath(suffix=''))  
  231.        LOG.info(_('instance %s: Creating image'), inst['name'])  
  232.        f = open(basepath('libvirt.xml'), 'w')  
  233.        f.write(libvirt_xml)  
  234.        f.close()  
  235.        if FLAGS.libvirt_type == 'lxc':  
  236.            container_dir = '%s/rootfs' % basepath(suffix='')  
  237.            utils.execute('mkdir', '-p', container_dir)  
  238.        # NOTE(vish): No need add the suffix to console.log  
  239.        console_log = basepath('console.log', '')  
  240.        if os.path.exists(console_log):  
  241.            utils.execute('chown', os.getuid(), console_log, run_as_root=True)  
  242.        os.close(os.open(console_log, os.O_CREAT | os.O_WRONLY, 0660))  
  243.        if not disk_images:  
  244.            disk_images = {'image_id': inst['image_ref'],  
  245.                           'kernel_id': inst['kernel_id'],  
  246.                           'ramdisk_id': inst['ramdisk_id']}  
  247.        if disk_images['kernel_id']:  
  248.            fname = '%08x' % int(disk_images['kernel_id'])  
  249.            self._cache_image(fn=self._fetch_image,  
  250.                              context=context,  
  251.                              target=basepath('kernel'),  
  252.                              fname=fname,  
  253.                              image_id=disk_images['kernel_id'],  
  254.                              user_id=inst['user_id'],  
  255.                              project_id=inst['project_id'])  
  256.            if disk_images['ramdisk_id']:  
  257.                fname = '%08x' % int(disk_images['ramdisk_id'])  
  258.                self._cache_image(fn=self._fetch_image,  
  259.                                  context=context,  
  260.                                  target=basepath('ramdisk'),  
  261.                                  fname=fname,  
  262.                                  image_id=disk_images['ramdisk_id'],  
  263.                                  user_id=inst['user_id'],  
  264.                                  project_id=inst['project_id'])  
  265.        root_fname = hashlib.sha1(disk_images['image_id']).hexdigest()  
  266.        size = FLAGS.minimum_root_size  
  267.        inst_type_id = inst['instance_type_id']  
  268.        inst_type = instance_types.get_instance_type(inst_type_id)  
  269.        if inst_type['name'] == 'm1.tiny' or suffix == '.rescue':  
  270.            size = None
  271.            root_fname += "_sm"
  272.        if not self._volume_in_mapping(self.default_root_device,  
  273.                                       block_device_info):  
  274.            self._cache_image(fn=self._fetch_image,  
  275.                              context=context,  
  276.                              target=basepath('disk'),  
  277.                              fname=root_fname,  
  278.                              cow=FLAGS.use_cow_images,  
  279.                              image_id=disk_images['image_id'],  
  280.                              user_id=inst['user_id'],  
  281.                              project_id=inst['project_id'],  
  282.                              size=size)  
  283.        local_gb = inst['local_gb']  
  284.        if local_gb and not self._volume_in_mapping(  
  285.            self.default_local_device, block_device_info):  
  286.            fn = functools.partial(self._create_ephemeral,  
  287.                                   fs_label='ephemeral0',  
  288.                                   os_type=inst.os_type)  
  289.            self._cache_image(fn=fn,  
  290.                              target=basepath('disk.local'),  
  291.                              fname="ephemeral_%s_%s_%s" %  
  292.                              ("0", local_gb, inst.os_type),  
  293.                              cow=FLAGS.use_cow_images,  
  294.                              local_size=local_gb)  
  295.        for eph in driver.block_device_info_get_ephemerals(block_device_info):  
  296.            fn = functools.partial(self._create_ephemeral,  
  297.                                   fs_label='ephemeral%d' % eph['num'],  
  298.                                   os_type=inst.os_type)  
  299.            self._cache_image(fn=fn,  
  300.                              target=basepath(_get_eph_disk(eph)),  
  301.                              fname="ephemeral_%s_%s_%s" %  
  302.                              (eph['num'], eph['size'], inst.os_type),  
  303.                              cow=FLAGS.use_cow_images,  
  304.                              local_size=eph['size'])  
  305.        swap_mb = 0
  306.        swap = driver.block_device_info_get_swap(block_device_info)  
  307.        if driver.swap_is_usable(swap):  
  308.            swap_mb = swap['swap_size']  
  309.        elif (inst_type['swap'] > 0 and
  310.              not self._volume_in_mapping(self.default_swap_device,  
  311.                                          block_device_info)):  
  312.            swap_mb = inst_type['swap']  
  313.        if swap_mb > 0:  
  314.            self._cache_image(fn=self._create_swap,  
  315.                              target=basepath('disk.swap'),  
  316.                              fname="swap_%s" % swap_mb,  
  317.                              cow=FLAGS.use_cow_images,  
  318.                              swap_mb=swap_mb)  
  319.        # For now, we assume that if we're not using a kernel, we're using a  
  320.        # partitioned disk image where the target partition is the first  
  321.        # partition  
  322.        target_partition = None
  323.        if not inst['kernel_id']:  
  324.            target_partition = "1"
  325.        config_drive_id = inst.get('config_drive_id')  
  326.        config_drive = inst.get('config_drive')  
  327.        if any((FLAGS.libvirt_type == 'lxc', config_drive, config_drive_id)):  
  328.            target_partition = None
  329.        if config_drive_id:  
  330.            fname = '%08x' % int(config_drive_id)  
  331.            self._cache_image(fn=self._fetch_image,  
  332.                              target=basepath('disk.config'),  
  333.                              fname=fname,  
  334.                              image_id=config_drive_id,  
  335.                              user_id=inst['user_id'],  
  336.                              project_id=inst['project_id'],)  
  337.        elif config_drive:  
  338.            self._create_local(basepath('disk.config'), 64, unit='M',  
  339.                               fs_format='msdos')  # 64MB  
  340.        if inst['key_data']:  
  341.            key = str(inst['key_data'])  
  342.        else:  
  343.            key = None
  344.        net = None
  345.        nets = []  
  346.        ifc_template = open(FLAGS.injected_network_template).read()  
  347.        ifc_num = -1
  348.        have_injected_networks = False
  349.        admin_context = nova_context.get_admin_context()  
  350.        for (network_ref, mapping) in network_info:  
  351.            ifc_num += 1
  352.            if not network_ref['injected']:  
  353.                continue
  354.            have_injected_networks = True
  355.            address = mapping['ips'][0]['ip']  
  356.            netmask = mapping['ips'][0]['netmask']  
  357.            address_v6 = None
  358.            gateway_v6 = None
  359.            netmask_v6 = None
  360.            if FLAGS.use_ipv6:  
  361.                address_v6 = mapping['ip6s'][0]['ip']  
  362.                netmask_v6 = mapping['ip6s'][0]['netmask']  
  363.                gateway_v6 = mapping['gateway6']  
  364.            net_info = {'name': 'eth%d' % ifc_num,  
  365.                   'address': address,  
  366.                   'netmask': netmask,  
  367.                   'gateway': mapping['gateway'],  
  368.                   'broadcast': mapping['broadcast'],  
  369.                   'dns': ' '.join(mapping['dns']),  
  370.                   'address_v6': address_v6,  
  371.                   'gateway6': gateway_v6,  
  372.                   'netmask_v6': netmask_v6}  
  373.            nets.append(net_info)  
  374.        if have_injected_networks:  
  375.            net = str(Template(ifc_template,  
  376.                               searchList=[{'interfaces': nets,  
  377.                                            'use_ipv6': FLAGS.use_ipv6}]))  
  378.        metadata = inst.get('metadata')  
  379.        if any((key, net, metadata)):  
  380.            inst_name = inst['name']  
  381.            if config_drive:  # Should be True or None by now.  
  382.                injection_path = basepath('disk.config')  
  383.                img_id = 'config-drive'
  384.                tune2fs = False
  385.            else:  
  386.                injection_path = basepath('disk')  
  387.                img_id = inst.image_ref  
  388.                tune2fs = True
  389.            for injection in ('metadata', 'key', 'net'):  
  390.                if locals()[injection]:  
  391.                    LOG.info(_('instance %(inst_name)s: injecting '
  392.                               '%(injection)s into image %(img_id)s'
  393.                               % locals()))  
  394.            try:  
  395.                disk.inject_data(injection_path, key, net, metadata,  
  396.                                 partition=target_partition,  
  397.                                 nbd=FLAGS.use_cow_images,  
  398.                                 tune2fs=tune2fs)  
  399.            except Exception as e:  
  400.                # This could be a windows image, or a vmdk format disk  
  401.                LOG.warn(_('instance %(inst_name)s: ignoring error injecting'
  402.                        ' data into image %(img_id)s (%(e)s)') % locals())  
  403.        if FLAGS.libvirt_type == 'lxc':  
  404.            disk.setup_container(basepath('disk'),  
  405.                                container_dir=container_dir,  
  406.                                nbd=FLAGS.use_cow_images)  
  407.        if FLAGS.libvirt_type == 'uml':  
  408.            utils.execute('chown', 'root', basepath('disk'), run_as_root=True)
复制代码





相关内容:

openstack nova 源码分析1-setup脚本
http://www.aboutyun.com/thread-10090-1-1.html


openstack nova 源码分析2之nova-api,nova-compute
http://www.aboutyun.com/thread-10091-1-1.html


openstack nova 源码分析3-nova目录下的service.py、driver.py
http://www.aboutyun.com/thread-10092-1-1.html



openstack nova 源码分析4-2 -nova/virt/libvirt目录下的connection.py
http://www.aboutyun.com/thread-10095-1-1.html









出处http://brucemars.blog.51cto.com/5288106/968433

没找到任何评论,期待你打破沉寂

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

推荐上一条 /2 下一条