from nova to ironic(3)

来源:互联网 发布:余弦夹角算法 编辑:程序博客网 时间:2024/05/18 15:56

之前写了两篇从nova到ironic是如何调用的文章,只是大概的架子。这两年看openstack的源码也看了不少,看到后来觉得大同小异,之前的积累现在看起来因为没有具体项目带动也比较零散,东一点儿西一点儿,现在从ironic进来反而觉得都很清晰起来,因此想把之前写的完全搬到网上来总觉得不和谐,我决定还是从细节入手按照之前的风格,把这两年

的积累归零,换个思路来(Juno,之前是icehouse,还是很多相似的)。

这个人写的比我好:

http://bingotree.cn/?p=193


我也稍微捋一捋:

一样的,作为一个python项目,nova也有entry_points,和ironic一样,在做egg之前就写在setup.cfg中,通过stevedore在初始化时,将entry_points和类

的对应关系load进来。

在nova.cmd下面是nova启服务的地方,nova作为openstack中最初也是最复杂的一块,一切都源于nova,因此cmd包下面的启动的服务很多,不像ironic只有api,conductor,dbsync,nova有api,compute,cert,cells,console,scheduler等等,很多,但是也就是两种类型,和ironic一样,一种是WSGI的service,对外接收

rest请求,另一种是RPC service,接收RPC call进行处理或者转发,分别来看一看:

WSGI service:

在nova.cmd下以api开头的,比如api.py, api_ec2.py,api_os_comput.py以及api_metadata.py都属于WSGI的service,这里以api.py为例,

 config.parse_args(sys.argv)  #根据传入的参数做一些default的设置,log,debug,rpc等,初始化一个全局的CONF manager, notifier比较有意思,确定不同的message

写到不同的地方,log,test,routing等等

 logging.setup("nova") #log设置,基本不会变动,包装logging
 utils.monkey_patch()#运行时动态修改code,python有很多这样的黑魔法,前面提到的metaclass也是一种,其实,个人觉得不一样非要这样。。。

notify_decorator = 'nova.notifications.notify_decorator'

monkey_patch_opts = [
    cfg.BoolOpt('monkey_patch',
                default=False,
                help='Whether to log monkey patching'),
    cfg.ListOpt('monkey_patch_modules',
                default=[
                  'nova.api.ec2.cloud:%s' % (notify_decorator),
                  'nova.compute.api:%s' % (notify_decorator)
                  ],
                help='List of modules/decorators to monkey patch'),
]

调用utils.monkey_patch时,我们在方法中可以看到,实际上只是给monkey_patch_modules中的方法加上了notify_decorator而已


 objects.register_all()#将objects包中的类load起来

 gmr.TextGuruMeditation.setup_autorun(version)  #通过发送一个USER1的信号量,进程捕获后会返回对应的信息


cfg.ListOpt('enabled_apis',
                default=['ec2', 'osapi_compute', 'metadata'],
                help='A list of APIs to enable by default'),

针对enabled_apis启动WSGI服务,初始化self.manager的时候只有MetadataManager,没有ec2 manager或者 osapi_compute manager

        self.loader = loader or wsgi.Loader()
        self.app = self.loader.load_app(name)

分别解析paste-api.ini并取得接收rest的入口

接着launcher.launch_service(server, workers=server.workers or 1)就涉及到core的内容,包括协程使用等等,最后调用WSGIService的start方法,

可以看出如果前面提到的self.manager存在的话会做一些pre hook和post hook

有一段话引用的文章中说的很好,我mark一下,对于理解Openstack的service很有好处:

openstack中使用协程和普通的多线程模型下的HTTP server有一个很大的不同:普通的HTTP server在启动的时候只有一个线程在那里监听一个端口,来了一个请求才会fork一个线程去做独立的处理(也就是说如果请求很多的话,线程个数也会很多)。但这里由于使用了eventlet的绿化(本质就是协程,可以看这里),因此对于协程来说,一个协程只能运行在一个CPU核上,并且不存在来个请求就fork这种东西,所以这里会根据CPU的核的个数去建立对应的协程(worker)。当一个请求来了过后呢其就会交给某一个协程去处理。不管请求个数多少,协程的个数是固定的。协程在HTTP server方面的效率是很高的。


RPC service或者说内部service,举nova-compute service为例:

http://bingotree.cn/?p=289这一篇也不错,很细,可参考


在nova.cmd.compute.py中,首先

CONF.import_opt('compute_topic', 'nova.compute.rpcapi')
CONF.import_opt('use_local', 'nova.conductor.api', group='conductor')

分别从nova.compute.rpcapi和nova.conductor.api中引入compute_topic='compute', 'use_local'=false


if not CONF.conductor.use_local:
        block_db_access()                          #nova.db.api.IMPL = NoDB(),在NoDB中实现__call__方法,在compute service中调用数据库会报错
        objects_base.NovaObject.indirection_api = conductor_rpcapi.ConductorAPI() #在ironic中也提到indirection_api,不过ironic中并没有真正使用,而在nova中,

Objects的基类NovaObject的元数据类中有此属性,也就是创建nova中的objects时会用到该属性,而我们看到很多object的方法会加@base.remotable或者@base.remotable_classmethod,则会将方法变成rpc call(可以跟踪conductor_rpcapi.ConductorAPI()的调用过程,会发现最后走到nova.conductor.manager.py中的

_object_dispatch方法)


server = service.Service.create(binary='nova-compute',
                                    topic=CONF.compute_topic,
                                    db_allowed=CONF.conductor.use_local)

topic为compute,manager为nova.compute.manager.ComputeManage, db_allowed 为false

cfg.StrOpt('compute_manager',
               default='nova.compute.manager.ComputeManager',
               help='Full class name for the Manager for compute'),

在nova.compute.manager.ComputeManager的__init__方法中:

        self.virtapi = ComputeVirtAPI(self)
        self.network_api = network.API()
        self.volume_api = volume.API()
        self.image_api = image.API()
        self._last_host_check = 0
        self._last_bw_usage_poll = 0
        self._bw_usage_supported = True
        self._last_bw_usage_cell_update = 0
        self.compute_api = compute.API()
        self.compute_rpcapi = compute_rpcapi.ComputeAPI()
        self.conductor_api = conductor.API()
        self.compute_task_api = conductor.ComputeTaskAPI()
        self.is_neutron_security_groups = (
            openstack_driver.is_neutron_security_groups())
        self.consoleauth_rpcapi = consoleauth.rpcapi.ConsoleAuthAPI()
        self.cells_rpcapi = cells_rpcapi.CellsAPI()
        self.scheduler_rpcapi = scheduler_rpcapi.SchedulerAPI()
        self._resource_tracker_dict = {}
        self.instance_events = InstanceEvents()
        self._sync_power_pool = eventlet.GreenPool()
        self._syncs_in_progress = {}

建立调用的入口关系,如virtapi的入口为ComputeVirtAPI,调用其self.virtapi的方法时就知道调用的是谁了

Service.serve(server)调用service的start方法,start方法中重要的几个点为:


 self.manager.init_host()#首先调用driver的init_host,默认的是LibVirt Driver,check运行环境是否为qemu或者kvm,DB和当前实际情况

的比较,比如当前host的虚机是否仍然存在等,涉及到hypervisor的信息暂时不是我的方向或者重点,不再继续追进。

 self.manager.pre_start_hook()#追进去内容很多且比较底层,主要就是主动调用一个周期性的任务,将虚拟机和物理机的相关性能信息写入nova的数据库。

并且如果是新上线的物理机节点,则会注册相关信息到数据库中(内存,cpu,disk等)。

 endpoints = [
            self.manager,
            baserpc.BaseRPCAPI(self.manager.service_name, self.backdoor_port)
        ]
endpoints.extend(self.manager.additional_endpoints)
serializer = objects_base.NovaObjectSerializer()
self.rpcserver = rpc.get_server(target, endpoints, serializer)  #RPC调用会调用endpoints中的方法, ComputeManager中的addtional_endpoints为空,但是

ConductorManager中的不为空


还有conductor,scheduler等服务,如何启动也是上面两种情况,以后温习具体的点时再记录下来。

0 0
原创粉丝点击