def _get_gbp_details(self, context, request, host): with context.session.begin(subtransactions=True): device = request.get('device') core_plugin = self._core_plugin port_id = core_plugin._device_to_port_id(context, device) port_context = core_plugin.get_bound_port_context( context, port_id, host) if not port_context: LOG.warning( _LW("Device %(device)s requested by agent " "%(agent_id)s not found in database"), { 'device': port_id, 'agent_id': request.get('agent_id') }) return {'device': request.get('device')} port = port_context.current # NOTE(ivar): removed the PROXY_PORT_PREFIX hack. # This was needed to support network services without hotplug. epg = self._get_port_epg(context, port) details = { 'device': request.get('device'), 'enable_dhcp_optimization': self._is_dhcp_optimized(context, port), 'enable_metadata_optimization': (self._is_metadata_optimized(context, port)), 'port_id': port_id, 'mac_address': port['mac_address'], 'app_profile_name': epg.app_profile_name, 'tenant_id': port['tenant_id'], 'host': host, # TODO(ivar): scope names, possibly through AIM or the # name mapper 'ptg_tenant': epg.tenant_name, 'endpoint_group_name': epg.name, 'promiscuous_mode': self._is_port_promiscuous(context, port), 'extra_ips': [], 'floating_ip': [], 'ip_mapping': [], # Put per mac-address extra info 'extra_details': {} } # Set VM name if needed. if port['device_owner'].startswith( 'compute:') and port['device_id']: vm = nclient.NovaClient().get_server(port['device_id']) details['vm-name'] = vm.name if vm else port['device_id'] mtu = self._get_port_mtu(context, port) if mtu: details['interface_mtu'] = mtu # NOTE(ivar): having these methods cleanly separated actually makes # things less efficient by requiring lots of calls duplication. # we could alleviate this by passing down a cache that stores # commonly requested objects (like EPGs). 'details' itself could # be used for such caching. details['_cache'] = {} vrf = self._get_port_vrf(context, port, details) details['l3_policy_id'] = '%s %s' % (vrf.tenant_name, vrf.name) self._add_subnet_details(context, port, details) self._add_allowed_address_pairs_details(context, port, details) self._add_vrf_details(context, details['l3_policy_id'], details) self._add_nat_details(context, port, host, details) self._add_extra_details(context, port, details) self._add_segmentation_label_details(context, port, details) self._set_dhcp_lease_time(details) details.pop('_cache', None) LOG.debug("Details for port %s : %s", port['id'], details) return details
def bind_port(self, context): """Get port binding per host. This is similar to the one defined in the AgentMechanismDriverBase class, but is modified to support multiple L2 agent types (DVS and OpFlex). """ port = context.current LOG.debug("Attempting to bind port %(port)s on " "network %(network)s", { 'port': port['id'], 'network': context.network.current['id'] }) vnic_type = port.get(portbindings.VNIC_TYPE, portbindings.VNIC_NORMAL) if vnic_type not in [portbindings.VNIC_NORMAL]: LOG.debug("Refusing to bind due to unsupported vnic_type: %s", vnic_type) return if port['device_owner'].startswith('compute:'): # enforce the allowed_vm_names rules if possible if (port['device_id'] and self.apic_allowed_vm_name_driver): ptg, pt = self.apic_gbp._port_id_to_ptg( context._plugin_context, port['id']) if ptg is None: LOG.warning(_LW("PTG for port %s does not exist"), port['id']) return l2p = self.apic_gbp._get_l2_policy(context._plugin_context, ptg['l2_policy_id']) l3p = self.apic_gbp.gbp_plugin.get_l3_policy( context._plugin_context, l2p['l3_policy_id']) ok_to_bind = True if l3p.get('allowed_vm_names'): ok_to_bind = False vm = nclient.NovaClient().get_server(port['device_id']) for allowed_vm_name in l3p['allowed_vm_names']: match = re.search(allowed_vm_name, vm.name) if match: ok_to_bind = True break if not ok_to_bind: LOG.warning( _LW("Failed to bind the port due to " "allowed_vm_names rules %(rules)s " "for VM: %(vm)s"), { 'rules': l3p['allowed_vm_names'], 'vm': vm.name }) return # Attempt to bind ports for DVS agents for nova-compute daemons # first. This allows having network agents (dhcp, metadata) # that typically run on a network node using an OpFlex agent to # co-exist with nova-compute daemons for ESX, which host DVS # agents. agent_list = context.host_agents(AGENT_TYPE_DVS) if self._agent_bind_port(context, agent_list, self._bind_dvs_port): return # It either wasn't a DVS binding, or there wasn't a DVS # agent on the binding host (could be the case in a hybrid # environment supporting KVM and ESX compute). Go try for # OpFlex agents. agent_list = context.host_agents(ofcst.AGENT_TYPE_OPFLEX_OVS) self._agent_bind_port(context, agent_list, self._bind_opflex_port)