nova-compute启动分析-1

来源:互联网 发布:华为淘宝无法联网 编辑:程序博客网 时间:2024/05/17 01:58

python启动脚本 bin/nova-compute

    utils.default_flagfile()  #设置flag文件路径.    flags.FLAGS(sys.argv)   #把flag文件中的参数放到args中。    logging.setup()           #设置日志    utils.monkey_patch()    server = service.Service.create(binary='nova-compute') #创建服务    service.serve(server)  #启动服务    service.wait()             #等待请求

下面我讲按6大步进行讲述:

第一步:utils.default_flagfile()

   if args is None:        args = sys.argv    for arg in args:        if arg.find('flagfile') != -1:            break    else:        if not os.path.isabs(filename):            # turn relative filename into an absolute path            script_dir = os.path.dirname(inspect.stack()[-1][1])            filename = os.path.abspath(os.path.join(script_dir, filename))        if not os.path.exists(filename):            filename = "./nova.conf"            if not os.path.exists(filename):                filename = '/etc/nova/nova.conf'        flagfile = '--flagfile=%s' % filename        args.insert(1, flagfile)     其实所完成的功能也就是把--flagfile=/etc/nova/nova.conf加到入参数列表中。



第二步:flags.FLAGS(sys.argv)

  flags.py中有一句
  FLAGS = FlagValues(),那么直接查看FlagValues()这个类,这个类是继承于gflags.FlagValues.



第三步:logging.setup()

这个是对这个服务开启日志功能。




第四步:server = service.Service.create(binary='nova-compute')

这个函数位于/nova/service.py: 类Service中

class Service(object):    """Service object for binaries running on hosts.    A service takes a manager and enables rpc by listening to queues based    on topic. It also periodically runs tasks on the manager and reports    it state to the database services table.""" 函数定义如下:   @classmethod     def create(cls, host=None, binary=None, topic=None, manager=None,               report_interval=None, periodic_interval=None):        """Instantiates class and passes back application object.        :param host: defaults to FLAGS.host        :param binary: defaults to basename of executable        :param topic: defaults to bin_name - 'nova-' part        :param manager: defaults to FLAGS.<topic>_manager        :param report_interval: defaults to FLAGS.report_interval        :param periodic_interval: defaults to FLAGS.periodic_interval        """        if not host:            host = FLAGS.host #host name  ‘nova’        if not binary:            binary = os.path.basename(inspect.stack()[-1][1]) # 这是因为python可以查看动栈的内容。                                                              # 所以可以得到压入栈中的脚本的名字  这时,binary="nova-compute"        if not topic:            topic = binary.rpartition('nova-')[2]             #设置topic的名字:也就是把 binary的nova-去掉。        if not manager:            manager = FLAGS.get('%s_manager' % topic, None)   #很明显这里得到的是compute_manager.        if not report_interval:            report_interval = FLAGS.report_interval        if not periodic_interval:            periodic_interval = FLAGS.periodic_interval        service_obj = cls(host, binary, topic, manager,                          report_interval, periodic_interval)   #利用 Service.__init__()构造函数生成一个对象        return service_obj


接下来我们看看Service.__init__()

def __init__(self, host, binary, topic, manager, report_interval=None,                 periodic_interval=None, *args, **kwargs):        self.host = host        self.binary = binary        self.topic = topic        self.manager_class_name = manager        manager_class = utils.import_class(self.manager_class_name)        self.manager = manager_class(host=self.host, *args, **kwargs)        self.report_interval = report_interval        self.periodic_interval = periodic_interval        super(Service, self).__init__(*args, **kwargs)        self.saved_args, self.saved_kwargs = args, kwargs        self.timers = []

1、指定host、binary、topic。这个相对简单。

        self.host = host
        self.binary = binary
        self.topic = topic


2、动态指定manager类,并动态生成实例 。

        self.manager_class_name = manager    #在create函数中指定。
        manager_class = utils.import_class(self.manager_class_name)  #动态地import此类。
        self.manager = manager_class(host=self.host, *args, **kwargs) #动态地生成这个类的实例 。

       那么这时会调用ComputeManager::__init__()函数


      我们进入ComputeManager::__init__()函数

     

 def __init__(self, compute_driver=None, *args, **kwargs):        """Load configuration options and connect to the hypervisor."""        # TODO(vish): sync driver creation logic with the rest of the system        #             and re-document the module docstring        if not compute_driver:            compute_driver = FLAGS.compute_driver   #这部分在后面会仔细分析                                    #cfg.StrOpt('compute_driver',default='nova.virt.connection.get_connection',                                    #help='Driver to use for controlling virtualization')        try:            self.driver = utils.check_isinstance(                                        utils.import_object(compute_driver),                                        driver.ComputeDriver)       #动态的加载 虚拟机的控制驱动对象        except ImportError as e:            LOG.error(_("Unable to load the virtualization driver: %s") % (e))            sys.exit(1)        self.network_api = network.API()        self.volume_api = volume.API()        self.network_manager = utils.import_object(FLAGS.network_manager)        self._last_host_check = 0        self._last_bw_usage_poll = 0        self._last_info_cache_heal = 0        super(ComputeManager, self).__init__(service_name="compute",                                             *args, **kwargs)

 这里顺便看一下ComputeManager的类视图。


  3、设置参数:应该是服务间隔时间之类的。

       self.report_interval = report_interval
        self.periodic_interval = periodic_interval


  4、 设置多出来的一些参数。      

        super(Service, self).__init__(*args, **kwargs)
        self.saved_args, self.saved_kwargs = args, kwargs
        self.timers = []



 第五步:service.serve(server)开启服务

def serve(*servers):    global _launcher  # class Launcher 一个全局对象    if not _launcher:        _launcher = Launcher()    for server in servers:        _launcher.launch_server(server)

  类Launcher 主要作用是为每个服务开启一个线程

 

  def launch_server(self, server):        """Load and start the given server.        :param server: The server you would like to start.        :returns: None        """        gt = eventlet.spawn(self.run_server, server)   #启动线程运行 run_server        self._services.append(gt)   #保存到 _services里面     @staticmethod    def run_server(server):        """Start and wait for a server to finish.        :param service: Server to run and wait for.        :returns: None        """        server.start()        server.wait()

其中server.start() #启动服务
我们来查看下 service.py中 Service类中start方法
 
 def start(self):        vcs_string = version.version_string_with_vcs()  #获取版本号        LOG.audit(_('Starting %(topic)s node (version %(vcs_string)s)'),                  {'topic': self.topic, 'vcs_string': vcs_string})        utils.cleanup_file_locks()  #清除锁文件        self.manager.init_host()          self.model_disconnected = False        ctxt = context.get_admin_context()        try:            service_ref = db.service_get_by_args(ctxt,                                                 self.host,                                                 self.binary)            self.service_id = service_ref['id']        except exception.NotFound:            self._create_service_ref(ctxt)        if 'nova-compute' == self.binary:            self.manager.update_available_resource(ctxt)        self.conn = rpc.create_connection(new=True)        LOG.debug(_("Creating Consumer connection for Service %s") %                  self.topic)        # Share this same connection for these Consumers        self.conn.create_consumer(self.topic, self, fanout=False)        node_topic = '%s.%s' % (self.topic, self.host)        self.conn.create_consumer(node_topic, self, fanout=False)        self.conn.create_consumer(self.topic, self, fanout=True)        # Consume from all consumers in a thread        self.conn.consume_in_thread()        if self.report_interval:            pulse = utils.LoopingCall(self.report_state)            pulse.start(interval=self.report_interval, now=False)            self.timers.append(pulse)        if self.periodic_interval:            periodic = utils.LoopingCall(self.periodic_tasks)            periodic.start(interval=self.periodic_interval, now=False)            self.timers.append(periodic)

下面我们对start方法进行分析:

 1、设置版本

        vcs_string = version.version_string_with_vcs()
        logging.audit(_('Starting %(topic)s node (version %(vcs_string)s)'),
                      {'topic': self.topic, 'vcs_string': vcs_string})


 2、初始化init_host(self): nova.compute.ComputeManager


    其中 self.driver.init_host(host=self.host)

    这里需要查看一下在__init__函数中driver的设置。

        if not compute_driver:
                   compute_driver = FLAGS.compute_driver
     FLAGS.compute_driver的值也是在/nova/compute/manager.py中设置:

    

    flags.DEFINE_string('compute_driver', 'nova.virt.connection.get_connection',
                    'Driver to use for controlling virtualization')


    关于get_connection下篇blog继续分析



3 . 接着从service.start()接着init_host()之后,

    得到context.然后再更新当前机器上可用的资源。 

        self.model_disconnected = False        ctxt = context.get_admin_context()        try:            service_ref = db.service_get_by_args(ctxt,                                                 self.host,                                                 self.binary)            self.service_id = service_ref['id']        except exception.NotFound:            self._create_service_ref(ctxt)        if 'nova-compute' == self.binary:            self.manager.update_available_resource(ctxt)


4. 更新RPC链接

 self.conn = rpc.create_connection(new=True)        LOG.debug(_("Creating Consumer connection for Service %s") %                  self.topic)           # Share this same connection for these Consumers        self.conn.create_consumer(self.topic, self, fanout=False)        node_topic = '%s.%s' % (self.topic, self.host)        self.conn.create_consumer(node_topic, self, fanout=False)        self.conn.create_consumer(self.topic, self, fanout=True)        # Consume from all consumers in a thread        self.conn.consume_in_thread()                  if self.report_interval:            pulse = utils.LoopingCall(self.report_state)        #循环调用report_state            pulse.start(interval=self.report_interval, now=False)            self.timers.append(pulse)        if self.periodic_interval:            periodic = utils.LoopingCall(self.periodic_tasks) #循环调用 periodic_tasks 下面详细说明            periodic.start(interval=self.periodic_interval, now=False)            self.timers.append(periodic)

 Nova-Compute启动的主要工作是把环境配置好。让RqbbitMQ的消息队列建立起来。最后服务的启动则主要是让rabbitmq的consumer运行。并且进入wait状态。消息的响应则主要是找到相应的函数地址,并执行之。



六. Wait() 等待

一般服务启动之后,都会有wait()。那么这里也需要看一下服务的wait()。从而可以知道是什么东西在后台真正地运行。

/usr/bin/nova-computeservice.wait()/nova/service.py:Class:Service::wait()    def wait(self):        for x in self.timers:            try:                x.wait()            except Exception:                pass




原创粉丝点击