【Nova】nova-network网络模型之flatdhcp网络-代码学习2

在上一篇中,讲解了一下flatdhcp网络下nova-network服务在启动之前的准备工作:创建网桥、启动DNSmasq服务、添加iptables和ebtables规则等。

那这一篇,学习下创建虚拟机实例时,nova-network会进行的工作:

创建虚拟机实例时,nova-compute会通过rpc调用相应的(multi_host下通常就是自己所在主机上的)nova-network的allocate_for_instance API来为实例分配网络资源;

流程并不复杂,就是先为实例分配MAC地址然后分配固定IP,并在数据库进行记录;然后修改每个nova-network节点更新本地DNS的解析文件;最后修改DHCP服务的数据库文件,记录刚才分配的固定IP以及关联实例的主机名和MAC地址,并使DHCP优雅地重启;那么当实例启动后通过DHCP获取IP时,DHCP就把绑定其MAC地址的固定IP分配给它

class RPCAllocateFixedIP(object):

    servicegroup_api = None
    
    def _rpc_allocate_fixed_ip(self, context, instance_id, network_id,
                               **kwargs):
        # 提高network_id获取network信息
        network = self._get_network_by_id(context, network_id)
        # 调用NetworkManager中allocate_fixed_ip来分配固定IP, 指定了address就使用address对应的固定IP;
        # 如果没有指定, 就从固定IP池中选取一个未分配的与实例进行绑定
        return self.allocate_fixed_ip(context, instance_id, network, **kwargs)

    def _allocate_fixed_ips(self, context, instance_id, host, networks,
                            **kwargs):
        green_threads = []

        vpn = kwargs.get('vpn')
        requested_networks = kwargs.get('requested_networks')

        for network in networks:
            address = None
            if requested_networks is not None:
                for address in (fixed_ip for (uuid, fixed_ip) in
                                requested_networks if network['uuid'] == uuid):
                    break

            # 如果不是multi_host模式, 说明只有一个nova-network节点;
            # 那么rpc调用的目标就是该节点
            if not network['multi_host']:
                host = network['host']
            # 如果参数host为空并且数据库中的网络信息没有记录host, 那么进行一次rpc调用让存在的nova-network节点返回自己的host信息
            if host is None:
                network_p = obj_base.obj_to_primitive(network)
                host = self.network_rpcapi.set_network_host(context,
                                                            network_p)
            if host != self.host:
                # 如果目标主机不是自己, 那么就意味着需要进行rpc调用;
                # 因为可能需要针对多个网络来进行rpc调用, 为了提高响应速度, 使用协程来进行, 让多个调用能同时进行
                green_threads.append(eventlet.spawn(
                        self.network_rpcapi._rpc_allocate_fixed_ip,
                        context, instance_id, network['id'], address, vpn,
                        host))
            else:
                # 调用NetworkManager中allocate_fixed_ip来分配固定IP
                self.allocate_fixed_ip(context, instance_id, network,
                                       vpn=vpn, address=address)

        # 等待所有的协程处理完毕
        for gt in green_threads:
            gt.wait()
            
class NetworkManager(manager.Manager):

    # 获取requested_networks中的网络信息或者当前租户的所有网络信息
    def _get_networks_for_instance(self, context, instance_id, project_id,
                                   requested_networks=None):
        if requested_networks is not None and len(requested_networks) != 0:
            network_uuids = [uuid for (uuid, fixed_ip) in requested_networks]
            networks = self._get_networks_by_uuids(context, network_uuids)
        else:
            networks = network_obj.NetworkList.get_by_project(context,
                                                              project_id)
        return networks
        
    # 为实例分配一个固定IP, 要进行配额管理, 之前已经讲过, 大部分是数据库操作,
    # 在此不做赘述, 重点关注下分配完后的操作_setup_network_on_host
    def allocate_fixed_ip(self, context, instance_id, network, **kwargs):

        if kwargs.get('vpn', None):
            address = network['vpn_private_address']
            fip = fixed_ip_obj.FixedIP.associate(context, address, instance_id,
                                                 network['id'], reserved=True)
        else:
            address = kwargs.get('address', None)
            if address:
                fip = fixed_ip_obj.FixedIP.associate(context, address,
                                                     instance_id,
                                                     network['id'])
            else:
                fip = fixed_ip_obj.FixedIP.associate_pool(context,
                                                          network['id'],
                                                          instance_id)
        address = fip.address

        vif = vif_obj.VirtualInterface.get_by_instance_and_network(
            context, instance_id, network['id'])
        fip.allocated = True
        fip.virtual_interface_id = vif.id
        fip.save()

        if not kwargs.get('vpn', None):
            self._do_trigger_security_group_members_refresh_for_instance(
                                                                   instance_id)

        instance = instance_obj.Instance.get_by_uuid(context, instance_id)

        name = instance.display_name
        if self._validate_instance_zone_for_dns_domain(context, instance):
            self.instance_dns_manager.create_entry(name, address,
                                                   "A",
                                                   self.instance_dns_domain)
            self.instance_dns_manager.create_entry(instance_id, address,
                                                   "A",
                                                   self.instance_dns_domain)

        # 调用_setup_network_on_host, 需要具体的网络模式自行实现;
        # 分配了固定IP后还需要在主机上进行相应的设置工作
        self._setup_network_on_host(context, network)
        return address
        
    # nova-compute创建实例时, 会通过rpc调用此方法为实例分配网络资源
    def allocate_for_instance(self, context, **kwargs):
        instance_uuid = kwargs['instance_id']
        if not uuidutils.is_uuid_like(instance_uuid):
            instance_uuid = kwargs.get('instance_uuid')
        host = kwargs['host']
        project_id = kwargs['project_id']
        rxtx_factor = kwargs['rxtx_factor']
        requested_networks = kwargs.get('requested_networks')
        vpn = kwargs['vpn']
        macs = kwargs['macs']
        admin_context = context.elevated()
        LOG.debug(_("network allocations"), instance_uuid=instance_uuid,
                  context=context)
        # 获取requested_networks中的网络信息或者当前租户的所有网络信息
        networks = self._get_networks_for_instance(admin_context,
                                        instance_uuid, project_id,
                                        requested_networks=requested_networks)
        # 从networks中抽取出一部分的必需网络信息
        networks_list = [self._get_network_dict(network)
                                 for network in networks]
        LOG.debug(_('networks retrieved for instance: |%s|'),
                  networks_list, context=context, instance_uuid=instance_uuid)

        try:
            # 为实例的分配MAC地址并创建虚拟网卡的数据库记录
            self._allocate_mac_addresses(context, instance_uuid, networks,
                                         macs)
        except Exception as e:
            with excutils.save_and_reraise_exception():
                # 遇到异常时进行回滚并抛出
                vif_obj.VirtualInterface.delete_by_instance_uuid(context,
                        instance_uuid)

        # 为实例分配固定IP
        self._allocate_fixed_ips(admin_context, instance_uuid,
                                 host, networks, vpn=vpn,
                                 requested_networks=requested_networks)

        # 如果需要更新DNS记录
        if CONF.update_dns_entries:
            network_ids = [network['id'] for network in networks]
            # 通知全部的nova-network包括自己更新本地解析文件, 并优雅的重启DHCP服务
            self.network_rpcapi.update_dns(context, network_ids)
        # 返回实例的全部网络信息
        return self.get_instance_nw_info(context, instance_uuid, rxtx_factor,
                                         host)

class FlatDHCPManager(RPCAllocateFixedIP, floating_ips.FloatingIP,
                      NetworkManager):

    # 该方法在准备工作中已经详细讲过了, 在分配固定IP后, 最主要的工作就是更新DHCP数据库记录
    # 然后优雅重启DHCP服务
    def _setup_network_on_host(self, context, network):
        
        network['dhcp_server'] = self._get_dhcp_ip(context, network)

        self.l3driver.initialize_network(network.get('cidr'))
        self.l3driver.initialize_gateway(network)
        
        if not CONF.fake_network:
            dev = self.driver.get_dev(network)
            elevated = context.elevated()
            # !这里才是本次设置的重点所在:
            # 更新DHCP数据库文件, 并优雅重启DHCP服务
            self.driver.update_dhcp(elevated, dev, network)
            if CONF.use_ipv6:
                self.driver.update_ra(context, dev, network)
                gateway = utils.get_my_linklocal(dev)
                network.gateway_v6 = gateway
                network.save()        


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值