nova-compute启动分析-1

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-compute
service.wait()

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




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值