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

来源:互联网 发布:如何评价太祖知乎 编辑:程序博客网 时间:2024/05/21 17:52

在上一篇中,讲解了一下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