openstack neuturon模块 dhcp_agent向服务器汇报状态更新数据库与更新本地配置文件过程

一、更新服务器数据库

DhcpAgentWithStateReport类继承DhcpAgent类,DhcpAgentWithStateReport类的作用主要是创建一个协程定时向neutron-server启动时开启的rpc-server上报neutron-dhcp-agent的服务或network状态,然后通过neutron-server的core plugin将状态更新到数据库中。

其中self.cache = NetworkCache()主要保存底层的active的dhcp networks信息,这些信息会通过DhcpAgentWithStateReport类的_report_state方法上报到数据库中。

#DhcpAgentWithStateReport继承自DhcpAgent,用于汇报DHCPAgent的状态
class DhcpAgentWithStateReport(DhcpAgent):
    def __init__(self, host=None, conf=None):
        super(DhcpAgentWithStateReport, self).__init__(host=host, conf=conf)
        self.state_rpc = agent_rpc.PluginReportStateAPI(topics.REPORTS)
        self.agent_state = {
            'binary': 'neutron-dhcp-agent',
            'host': host,
            'availability_zone': self.conf.AGENT.availability_zone,
            'topic': topics.DHCP_AGENT,
            'configurations': {
                'dhcp_driver': self.conf.dhcp_driver,
                'dhcp_lease_duration': self.conf.dhcp_lease_duration,
                'log_agent_heartbeats': self.conf.AGENT.log_agent_heartbeats},
            'start_flag': True,
            'agent_type': constants.AGENT_TYPE_DHCP}
        report_interval = self.conf.AGENT.report_interval
        if report_interval:
            self.heartbeat = loopingcall.FixedIntervalLoopingCall(
                self._report_state)
            self.heartbeat.start(interval=report_interval)

    def _report_state(self):
        try:
            self.agent_state.get('configurations').update(
                self.cache.get_state())
            ctx = context.get_admin_context_without_session()
            agent_status = self.state_rpc.report_state(#汇报状态
                ctx, self.agent_state, True)
            if agent_status == n_const.AGENT_REVIVED:
                LOG.info("Agent has just been revived. "
                         "Scheduling full sync")
                self.schedule_resync("Agent has just been revived")
        except AttributeError:
            # This means the server does not support report_state
            LOG.warning("Neutron server does not support state report. "
                        "State report for this agent will be disabled.")
            self.heartbeat.stop()
            self.run()
            return
        except Exception:
            LOG.exception("Failed reporting state!")
            return
        if self.agent_state.pop('start_flag', None):#在neutron-dhcp-agent开始运行时对网络进行dhcp分配
            self.run()

    def agent_updated(self, context, payload):
        """Handle the agent_updated notification event."""
        self.schedule_resync(_("Agent updated: %(payload)s") %
                             {"payload": payload})
        LOG.info("agent_updated by server side %s!", payload)

    def after_start(self):
        LOG.info("DHCP agent started")

DhcpAgent类才是为neutron-dhcp-agent服务做主要工作的。初始化代码如下:

#/neutron/agent/dhcp/agent.py: DhcpAgentWithStateReport

class DhcpAgent(manager.Manager):
  """DHCP agent service manager.
  
    Note that the public methods of this class are exposed as the server side
    of an rpc interface.  The neutron server uses
    neutron.api.rpc.agentnotifiers.dhcp_rpc_agent_api.DhcpAgentNotifyApi as the
    client side to execute the methods here.  For more information about
    changing rpc interfaces, see doc/source/devref/rpc_api.rst.
    """
  target = oslo_messaging.Target(version='1.0')
  
  def __init__(self, host=None, conf=None):
  super(DhcpAgent, self).__init__(host=host)
  self.needs_resync_reasons = collections.defaultdict(list)
  self.conf = conf or cfg.CONF
  self.cache = NetworkCache()
  self.dhcp_driver_cls = importutils.import_class(self.conf.dhcp_driver)
        ctx = context.get_admin_context_without_session()
  self.plugin_rpc = DhcpPluginApi(topics.PLUGIN, ctx, self.conf.host)
  # create dhcp dir to store dhcp info
  dhcp_dir = os.path.dirname("/%s/dhcp/" % self.conf.state_path)
          utils.ensure_dir(dhcp_dir)
  self.dhcp_version = self.dhcp_driver_cls.check_version()
  self._populate_networks_cache()
  # keep track of mappings between networks and routers for
        # metadata processing
  self._metadata_routers = {}  # {network_id: router_id}
  self._process_monitor = external_process.ProcessMonitor(
  config=self.conf,
  resource_type='dhcp')

其中self.cache = NetworkCache()主要保存底层的active的dhcp networks信息,这些信息会通过DhcpAgentWithStateReport类的_report_state方法上报到数据库中。

二、更新配置文件
初始

接着首先看下rpc-service的start代码,代码路径在neutron/service.py

#/neutron/service.py:Service

def start(self):
  self.manager.init_host()
  super(Service, self).start()
  if self.report_interval:
        pulse = loopingcall.FixedIntervalLoopingCall(self.report_state)
        pulse.start(interval=self.report_interval,
  initial_delay=self.report_interval)
  self.timers.append(pulse)
  
  if self.periodic_interval:
  if self.periodic_fuzzy_delay:
            initial_delay = random.randint(0, self.periodic_fuzzy_delay)
  else:
            initial_delay = None
  
  periodic = loopingcall.FixedIntervalLoopingCall(
  self.periodic_tasks)
        periodic.start(interval=self.periodic_interval,
  initial_delay=initial_delay)
  self.timers.append(periodic)
  self.manager.after_start()

rpc-service start的时候会调用agent的init_host函数。下面分析self.manager.init_host()

#/neutron/agent/dhcp/agent.py:DhcpAgent
def init_host(self):
  self.sync_state()
#/neutron/agent/dhcp/agent.py:DhcpAgent
@utils.synchronized('dhcp-agent')
  def sync_state(self, networks=None):
  """Sync the local DHCP state with Neutron. If no networks are passed,
    or 'None' is one of the networks, sync all of the networks.
    """
  only_nets = set([] if (not networks or None in networks) else networks)
    LOG.info(_LI('Synchronizing state'))
    pool = eventlet.GreenPool(self.conf.num_sync_threads)
    known_network_ids = set(self.cache.get_network_ids())
  
  try:
        active_networks = self.plugin_rpc.get_active_networks_info()
        LOG.info(_LI('All active networks have been fetched through RPC.'))
        active_network_ids = set(network.id for network in active_networks)
  for deleted_id in known_network_ids - active_network_ids:
  try:
  self.disable_dhcp_helper(deleted_id)
  except Exception as e:
  self.schedule_resync(e, deleted_id)
                LOG.exception(_LE('Unable to sync network state on '
                                  'deleted network %s'), deleted_id)
  
  for network in active_networks:
  if (not only_nets or  # specifically resync all
  network.id not in known_network_ids or  # missing net
  network.id in only_nets):  # specific network to sync
  pool.spawn(self.safe_configure_dhcp_for_network, network)
        pool.waitall()
        LOG.info(_LI('Synchronizing state complete'))
  
  except Exception as e:
  if only_nets:
  for network_id in only_nets:
  self.schedule_resync(e, network_id)
  else:
  self.schedule_resync(e)
        LOG.exception(_LE('Unable to sync network state.'))
   def get_active_networks_info(self):
        """Make a remote process call to retrieve all network info."""
        cctxt = self.client.prepare(version='1.1')
        networks = cctxt.call(self.context, 'get_active_networks_info',
                              host=self.host)
        return [dhcp.NetModel(n) for n in networks]

sync_state函数主要功能是根据数据库同步底层的networks信息,即将self.cache(底层保存的dhcpnetworks信息)与通过active_networks=self.plugin_rpc.get_active_networks_info()函数获取的数据库中的networks信息作比较,将未在数据库中的底层networks从self.cache中进行移除。其中self.cache中的networks信息在创建DhcpAgent类的__init__函数的self._populate_networks_cache()代码进行实现.
在将未在数据库中的底层的dhcpnetworks从self.cache中进行移除后,将更新active的dhcp networks信息。

更新

DHCP agent会调用dhcp_driver.reload_allocations来更新配置文件。reload_allocations会根据新网络配置重新生成配置文件。DHCP agent会在收到如下4种消息时调用reload_allocations

port_update_end
port_delete_end
subnet_update_end
subnet_delete_end

上面这些通知消息在neturon rest API的前端实现中发出,具体代码在neutron.api.v2.base.py中

#neutron/api/v2/base.py
notifier_method = self._resource + '.create.end'
notifier_method = self._resource + '.delete.end'
notifier_method = self._resource + '.update.end'

可以看到针对每种resource(network, subnet, port),都会有相应的消息发出。dhcp agent根据这些消息来决定何时重新加载dnsmasp配置文件。
在dhcp.py中可见\neutron\agent\linux

 def spawn_process(self):
        """Spawn the process, if it's not spawned already."""
        # we only need to generate the lease file the first time dnsmasq starts
        # rather than on every reload since dnsmasq will keep the file current
        self._output_init_lease_file()
        self._spawn_or_reload_process(reload_with_HUP=False)

    def _spawn_or_reload_process(self, reload_with_HUP):
        """Spawns or reloads a Dnsmasq process for the network.

        When reload_with_HUP is True, dnsmasq receives a HUP signal,
        or it's reloaded if the process is not running.
        """

        self._output_config_files()

        pm = self._get_process_manager(
            cmd_callback=self._build_cmdline_callback)

        pm.enable(reload_cfg=reload_with_HUP)

        self.process_monitor.register(uuid=self.network.id,
                                      service_name=DNSMASQ_SERVICE_NAME,
                                      monitored_process=pm)

 def _output_config_files(self):
        self._output_hosts_file()
        self._output_addn_hosts_file()
        self._output_opts_file()

DHCP agent对外的提供的API接口在neutron/api/agentnotifiers/dhcp_rpc_agent_api.py里面,当网络变化时,比如网络创建和删除,会通过API调用DHCP driver。

#neutron/api/agentnotifiers/dhcp_rpc_agent_api.py
class DhcpAgentNotifyAPI(object):
  """API for plugin to notify DHCP agent.
  VALID_RESOURCES = ['network', 'subnet', 'port']
    VALID_METHOD_NAMES = ['network.create.end',
  'network.update.end',
  'network.delete.end',
  'subnet.create.end',
  'subnet.update.end',
  'subnet.delete.end',
  'port.create.end',
  'port.update.end',
  'port.delete.end']

可以看network/subnet/port的创建、删除和更新都会通知到DHCP agent, DHCPagent里面有对应的回调函数。

#/neutron/agent/dhcp/agent.py:DhcpAgent
@utils.synchronized('dhcp-agent')
  def network_create_end(self, context, payload):
  """Handle the network.create.end notification event."""
  network_id = payload['network']['id']
  self.enable_dhcp_helper(network_id)
#/neutron/agent/dhcp/agent.py:DhcpAgent
@utils.synchronized('dhcp-agent')
  def network_update_end(self, context, payload):
  """Handle the network.update.end notification event."""
  #/neutron/agent/dhcp/agent.py:DhcpAgent
@utils.synchronized('dhcp-agent')
  def network_delete_end(self, context, payload):
  """Handle the network.delete.end notification event."""
  #/neutron/agent/dhcp/agent.py:DhcpAgent
@utils.synchronized('dhcp-agent')
  def subnet_update_end(self, context, payload):
  """Handle the subnet.update.end notification event."""
  #/neutron/agent/dhcp/agent.py:DhcpAgent
@utils.synchronized('dhcp-agent')
  def subnet_delete_end(self, context, payload):
  """Handle the subnet.delete.end notification event."""
  #/neutron/agent/dhcp/agent.py:DhcpAgent
@utils.synchronized('dhcp-agent')
  def port_update_end(self, context, payload):
  """Handle the port.update.end notification event."""
  #/neutron/agent/dhcp/agent.py:DhcpAgent
@utils.synchronized('dhcp-agent')
  def port_delete_end(self, context, payload):
  """Handle the port.delete.end notification event."""

我们以network创建为例,分析HDCP agent如何调用DHCP driver 启动DHCP server服务的

#/neutron/agent/dhcp/agent.py:DhcpAgent
@utils.synchronized('dhcp-agent')
  def network_create_end(self, context, payload):
  """Handle the network.create.end notification event."""
  network_id = payload['network']['id']
  self.enable_dhcp_helper(network_id)
#/neutron/agent/dhcp/agent.py:DhcpAgent
def enable_dhcp_helper(self, network_id):
  """Enable DHCP for a network that meets enabling criteria."""
  network = self.safe_get_network_info(network_id)
  if network:
  self.configure_dhcp_for_network(network)
#/neutron/agent/dhcp/agent.py:DhcpAgent
def configure_dhcp_for_network(self, network):
  if not network.admin_state_up:
  return
  
  enable_metadata = self.dhcp_driver_cls.should_enable_metadata(
  self.conf, network)
    dhcp_network_enabled = False
  
  for subnet in network.subnets:
  if subnet.enable_dhcp:
  if self.call_driver('enable', network):
                dhcp_network_enabled = True
  self.cache.put(network)
  break
  
    if enable_metadata and dhcp_network_enabled:
  for subnet in network.subnets:
  if subnet.ip_version == 4 and subnet.enable_dhcp:
  self.enable_isolated_metadata_proxy(network)
  break
    elif (not self.conf.force_metadata and
          not self.conf.enable_isolated_metadata):
  # In the case that the dhcp agent ran with metadata enabled,
        # and dhcp agent now starts with metadata disabled, check and
        # delete any metadata_proxy.
  self.disable_isolated_metadata_proxy(network)

DhcpAgent通过self.dhcp_driver_cls = importutils.import_class(self.conf.dhcp_driver)注册了Dnsmasq这个Driver,并在需要的时候调用driver的相应接口。

当创建网络的时候,发现子网里面需要开启DHCP server,则调用self.call_driver(‘enable’, network)。会创建一个DHCP服务,这个通过命令可以看到。

当删除网络时候,发现已经开启了DHCP server,那么就要删除掉DHCP server,则调用接口self.call_driver(‘disable’, network)。

当子网和port添加和删除的时候,与网络有所不同,是调用的self.call_driver(‘reload_allocations’, network),进行更新配置操作数据。这块代码最终会调用DHCP driver部分。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

举世无双勇

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值