【openstack】Nova(Folsom)虚拟化层Driver分析

【转载】Nova(Folsom)虚拟化层Driver分析

本文是我一个同事的一篇分析,征求了同事的意见,获取同意后,在此转载。

本文依据Openstack目前最新folsom版本中,从代码走读的角度,分析了Openstack异构不同hypervisor下virt部分的代码结构。同时,给出了当前不同hypervisor对于Openstack定义的通用接口的支持情况。

1.Folsom版本virt代码重构

两个版本相比,virt部分的逻辑结构更加清晰。下面是两个版本virt代码中libvirt的结构对比:



2.Driver类型

当前支持的虚拟化平台,主要有以下五种:

3. virt继承关系

在Folsom版本中,对应不同的hypervisor实现,所有插件类全部继承于一个基类/nova/virt/driver.py,文件中定义到了所有需要driver支持的接口(当然有少部分接口是选配的),文件中仅有接口定义。

各个driver的继承关系如下:




4. ComputeDriver基类

接下来,我们来看下/nova/virt/driver.py中的全部接口定义,它是整个virt部分的基础。详见文档中第一部分~

5. 基类接口在不同hypervisor下的支持情况

上面那份表格第二部分,罗列出了不同hypervisor对基类中全部接口的支持情况。从对比中可以看出,Openstack对于libvirt的支持最好,XenAPI也基本都覆盖到了;这也和Openstack设计时候的出发点有关。另外,对于VMWareAPI、Hyper-V,一些基本的功能也大致覆盖到了,但接口总体支持情况仅能算一般。

接下来,我们分别看一下不同hypervisor的Driver情况~

6. 创vm中调用virt

之前我在分析《创建vm》文档中写到过,经过调度的消息在compute模块中,会走到/nova/compute/manager.py中ComputeManager的__init__()方法。方法继续走到nova.virt.connection.get_connection处:

Python代码 收藏代码
  1. driver_name=known_drivers.get(FLAGS.connection_type)
  2. ifdriver_nameisNone:
  3. raiseexception.VirtDriverNotFound(name=FLAGS.connection_type)
  4. conn=importutils.import_object_ns('nova.virt',driver_name,
  5. read_only=read_only)
  6. ifconnisNone:
  7. LOG.error(_('Failedtoopenconnectiontounderlyingvirtplatform'))
  8. sys.exit(1)
  9. returnutils.check_isinstance(conn,driver.ComputeDriver)

原有essex版本中的基类connections.py,目前在folsom版本中已被简化,仅用来读取配置文件中的hypervisor类型,如:




并加载一个工具类/nova/openstack/common/importutils.py,来返回一个nova.virt.libvirt类。如下:




7. libvirt Driver

首先看一下libvirt的包结构,结构很简单,核心的方法都放在/nova/virt/libvirt/driver.py中,比起此前essex版本中放到connection.py的做法结构更加清晰了:




7.1 有关libvirt

目前libvirt下,一共支持kvm、lxc、qemu、uml、xen五种具体的libvirt_type,默认选用kvm。

虚拟机的状态映射如下:

VIR内部状态

对外呈现状态

说明

VIR_DOMAIN_NOSTATE

NOSTATE

VIR_DOMAIN_RUNNING

RUNNING

VIR_DOMAIN_BLOCKED

RUNNING

仅在Xen中存在Blocked状态

VIR_DOMAIN_PAUSED

PAUSED

VIR_DOMAIN_SHUTDOWN

SHUTDOWN

libvirt API文档中已指出,此时vm可能仍旧处于Running状态

VIR_DOMAIN_SHUTOFF

SHUTDOWN

VIR_DOMAIN_CRASHED

CRASHED

VIR_DOMAIN_PMSUSPENDED

SUSPENDED

7.2 libvirt连接hypervisor

接下来开始看代码。整个libvrit的driver.py文件非常长(3000+行python)。。。初始化部分,首先调用基类ComputerDriver类中的__init__(),之后主要由配置文件读取了一些基本的配置项。

libvrit接口由_conn = property(_get_connection)来连接底层的hypervisor。而实际的连接工作,由内部的一个静态方法_connect()进行调用,一种是只读方式,另一种是拥有读写权限的,后一种需要用root身份登录。代码如下:

Python代码 收藏代码
  1. @staticmethod
  2. def_connect(uri,read_only):
  3. def_connect_auth_cb(creds,opaque):
  4. iflen(creds)==0:
  5. return0
  6. LOG.warning(
  7. _("Cannothandleauthenticationrequestfor%dcredentials")
  8. %len(creds))
  9. raiseexception.NovaException(
  10. _("Cannothandleauthenticationrequestfor%dcredentials")
  11. %len(creds))
  12. auth=[[libvirt.VIR_CRED_AUTHNAME,
  13. libvirt.VIR_CRED_ECHOPROMPT,
  14. libvirt.VIR_CRED_REALM,
  15. libvirt.VIR_CRED_PASSPHRASE,
  16. libvirt.VIR_CRED_NOECHOPROMPT,
  17. libvirt.VIR_CRED_EXTERNAL],
  18. _connect_auth_cb,
  19. None]
  20. ifread_only:
  21. returnlibvirt.openReadOnly(uri)
  22. else:
  23. returnlibvirt.openAuth(uri,auth,0)

7.3 libvirt创建vm实例

我们接着来看下spawn()方法,这个是libvirt对外的创建vm接口。传入参数,都是由Nova处理过的虚拟机、镜像、网络、安全等方面的参数。

Python代码 收藏代码
  1. @exception.wrap_exception()
  2. defspawn(self,context,instance,image_meta,injected_files,
  3. admin_password,network_info=None,block_device_info=None):
  4. xml=self.to_xml(instance,network_info,image_meta,
  5. block_device_info=block_device_info)
  6. self._create_image(context,instance,xml,network_info=network_info,
  7. block_device_info=block_device_info,
  8. files=injected_files,
  9. admin_pass=admin_password)
  10. self._create_domain_and_network(xml,instance,network_info,
  11. block_device_info)
  12. LOG.debug(_("Instanceisrunning"),instance=instance)
  13. def_wait_for_boot():
  14. """CalledatanintervaluntiltheVMisrunning."""
  15. state=self.get_info(instance)['state']
  16. ifstate==power_state.RUNNING:
  17. LOG.info(_("Instancespawnedsuccessfully."),
  18. instance=instance)
  19. raiseutils.LoopingCallDone()
  20. timer=utils.LoopingCall(_wait_for_boot)
  21. timer.start(interval=0.5).wait()


方法入口处的self.to_xml()方法,把之前传入的虚拟机、网络、镜像等信息,转化为创建vm时使用的xml描述文件。这个方法中,针对不同libvrit_type(xen/kvm/qemu/…)做了大量的分别处理。方法最终走到config.py中,调用基类LibvirtConfigObject的to_xml()方法,生成描述文件,代码如下:

Python代码 收藏代码
  1. defto_xml(self,pretty_print=True):
  2. root=self.format_dom()
  3. xml_str=etree.tostring(root,pretty_print=pretty_print)
  4. LOG.debug("GeneratedXML%s"%(xml_str,))
  5. returnxml_str

回到spawn()中,_create_image()方法略过。接下来看下_create_domain_and_network(),用来设置卷映射、构建网络参数,最后创建vm实例。以下是方法的简明分析:




其中,在底层创建vm的动作,是在_create_domain()中完成的。它根据上一步生成好的xml的内容,定义一个虚拟机,相当于创建了一个virDomain对象,注意这时还没有启动这个虚拟机。

另外,其他需要vm的动作都是通过组装+调用该方法实现的。

Python代码 收藏代码
  1. def_create_domain(self,xml=None,domain=None,launch_flags=0):
  2. """Createadomain.
  3. Eitherdomainorxmlmustbepassedin.Ifbotharepassed,then
  4. thedomaindefinitionisoverwrittenfromthexml.
  5. """
  6. ifxml:
  7. domain=self._conn.defineXML(xml)
  8. domain.createWithFlags(launch_flags)
  9. self._enable_hairpin(domain.XMLDesc(0))
  10. returndomain

其余libvirt API分析,因时间关系暂略。

8. XenAPI Driver

还是先看下XenAPI驱动部分的包结构。和libvirt的结构基本相同。




XenAPI Driver部分,一共分两个类,包括连接XenServer或者Xen Cloud的XenAPIDriver部分,以及一个调用XenAPI的XenAPISession类。

连接的初始化部分如下,其中,所有Xen相关的配置,和其他配置项一起保存在nova.conf中,通过之前《创建vm》文档中提到的flags.py来读取。配置项太长了,这里就不贴了。

Python代码 收藏代码
  1. classXenAPIDriver(driver.ComputeDriver):
  2. """AconnectiontoXenServerorXenCloudPlatform"""
  3. def__init__(self,read_only=False):
  4. super(XenAPIDriver,self).__init__()
  5. url=FLAGS.xenapi_connection_url
  6. username=FLAGS.xenapi_connection_username
  7. password=FLAGS.xenapi_connection_password
  8. ifnoturlorpasswordisNone:
  9. raiseException(_('Mustspecifyxenapi_connection_url,'
  10. 'xenapi_connection_username(optionally),and'
  11. 'xenapi_connection_passwordtouse'
  12. 'compute_driver=xenapi.XenAPIDriver'))
  13. self._session=XenAPISession(url,username,password)
  14. self._volumeops=volumeops.VolumeOps(self._session)
  15. self._host_state=None
  16. self._host=host.Host(self._session)
  17. self._vmops=vmops.VMOps(self._session)
  18. self._initiator=None
  19. self._hypervisor_hostname=None
  20. self._pool=pool.ResourcePool(self._session)

之后对于Xen主机、卷、资源池的操作,都是通过上面初始化了的对象,通过XenAPISession发送消息。不细写了~

9. VMWareApi Driver

目前,Openstack对于VMWare虚拟化的支持,还是主要集中于对于ESX的异构,暂时还无法覆盖到vCenter的层面。

依旧先来看下VMwareAPI驱动的包结构:




还是先看下driver.py,文件开头的配置部分列出了连接ESX所需的一些基础配置项,包括主机地址、用户名、密码等常规内容。这些都可以在nova.conf中进行配置。如下:

Python代码 收藏代码
  1. vmwareapi_opts=[
  2. cfg.StrOpt('vmwareapi_host_ip',
  3. default=None,
  4. help='URLforconnectiontoVMWareESXhost.Requiredif'
  5. 'compute_driverisvmwareapi.VMWareESXDriver.'),
  6. cfg.StrOpt('vmwareapi_host_username',
  7. default=None,
  8. help='UsernameforconnectiontoVMWareESXhost.'
  9. 'Usedonlyifcompute_driveris'
  10. 'vmwareapi.VMWareESXDriver.'),
  11. cfg.StrOpt('vmwareapi_host_password',
  12. default=None,
  13. help='PasswordforconnectiontoVMWareESXhost.'
  14. 'Usedonlyifcompute_driveris'
  15. 'vmwareapi.VMWareESXDriver.'),
  16. cfg.FloatOpt('vmwareapi_task_poll_interval',
  17. default=5.0,
  18. help='Theintervalusedforpollingofremotetasks.'
  19. 'Usedonlyifcompute_driveris'
  20. 'vmwareapi.VMWareESXDriver.'),
  21. cfg.IntOpt('vmwareapi_api_retry_count',
  22. default=10,
  23. help='Thenumberoftimesweretryonfailures,e.g.,'
  24. 'socketerror,etc.'
  25. 'Usedonlyifcompute_driveris'
  26. 'vmwareapi.VMWareESXDriver.'),
  27. cfg.StrOpt('vmwareapi_vlan_interface',
  28. default='vmnic0',
  29. help='Physicalethernetadapternameforvlannetworking'),
  30. ]
  31. FLAGS=flags.FLAGS
  32. FLAGS.register_opts(vmwareapi_opts)

以下是配置文件的sample,因未配置所以这几项目前是None:


继续看driver.py的代码,可以发现VMWare Driver部分的代码结构,与XenAPI的非常相似。都是有两个类,包括一个作为ESX主机连接对象的VMWareESXDriver部分+一个用于与ESX主机建立连接并处理全部请求调用的VMWareAPISession类。代码不细写了~

10. Hyper-V Driver

在essex版本规划中,本来计划要删掉的Hyper-V driver,由于微软积极投入开发人员更新代码,反而把功能补齐了。这里是Hyper-V driver的包结构:




Hyper-V的Driver支持,主要是使用一个基于python的Windows Management Instrumentation (WMI)来实现。这里有微软关于WMI的介绍:http://msdn.microsoft.com/en-us/library/cc723875%28v=VS.85%29.aspx

主要处理类都在HyperVDriver的初始化方法中定义了:

Python代码 收藏代码
  1. classHyperVDriver(driver.ComputeDriver):
  2. def__init__(self):
  3. super(HyperVDriver,self).__init__()
  4. self._volumeops=volumeops.VolumeOps()
  5. self._vmops=vmops.VMOps(self._volumeops)
  6. self._snapshotops=snapshotops.SnapshotOps()
  7. self._livemigrationops=livemigrationops.LiveMigrationOps(
  8. self._volumeops)

其他基本相同,过程略。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值