def test_automatic_address_request_eui64(self): subnet_cidr = '2607:f0d0:1002:51::/64' port_mac = 'aa:bb:cc:dd:ee:ff' eui_addr = str(netutils.get_ipv6_addr_by_EUI64(subnet_cidr, port_mac)) request = ipam_req.AutomaticAddressRequest(address_type=self.EUI64, prefix=subnet_cidr, mac=port_mac) self.assertEqual(request.address, netaddr.IPAddress(eui_addr))
def add_auto_addrs_on_network_ports(self, context, subnet, ipam_subnet): """For an auto-address subnet, add addrs for ports on the net.""" with context.session.begin(subtransactions=True): network_id = subnet['network_id'] port_qry = context.session.query(models_v2.Port) ports = port_qry.filter( and_( models_v2.Port.network_id == network_id, ~models_v2.Port.device_owner.in_( constants.ROUTER_INTERFACE_OWNERS_SNAT))) updated_ports = [] for port in ports: ip_request = ipam_req.AutomaticAddressRequest( prefix=subnet['cidr'], mac=port['mac_address']) ip_address = ipam_subnet.allocate(ip_request) allocated = models_v2.IPAllocation(network_id=network_id, port_id=port['id'], ip_address=ip_address, subnet_id=subnet['id']) try: # Do the insertion of each IP allocation entry within # the context of a nested transaction, so that the entry # is rolled back independently of other entries whenever # the corresponding port has been deleted. with context.session.begin_nested(): context.session.add(allocated) updated_ports.append(port['id']) except db_exc.DBReferenceError: LOG.debug( "Port %s was deleted while updating it with an " "IPv6 auto-address. Ignoring.", port['id']) LOG.debug("Reverting IP allocation for %s", ip_address) # Do not fail if reverting allocation was unsuccessful try: ipam_subnet.deallocate(ip_address) except Exception: LOG.debug("Reverting IP allocation failed for %s", ip_address) return updated_ports
def get_request(cls, context, port, ip_dict): """Get a prepared Address Request. :param context: context :param port: port dict :param ip_dict: dict that can contain 'ip_address', 'mac' and 'subnet_cidr' keys. Request to generate is selected depending on this ip_dict keys. :return: returns prepared AddressRequest (specific or any) """ mac = port['mac_address'] owner = port.get('device_owner') LOG.debug( "AAA: \tTenant %s, is admin %s\n\tdevice owner: %s\n\t%s\n\t%s", context.tenant, context.is_admin, owner, port, ip_dict) if owner == constants.DEVICE_OWNER_DHCP: return RomanaDhcpAddressRequest(port.get('binding:host_id')) # Lazily instantiate DB connection info. if cls._db_url is None: cls._db_url = cfg.CONF.database.connection _parsed_db_url = urlparse(cls._db_url) cls._db_conn_dict = { 'host': _parsed_db_url.hostname, 'user': _parsed_db_url.username, 'passwd': _parsed_db_url.password, 'db': _parsed_db_url.path[1:] } LOG.debug("Connecting to %s" % cls._db_url) con = MySQLdb.connect(**cls._db_conn_dict) cur = con.cursor() # FIXIT! TODO(gg) # What a hack! This is being written by Neutron within a transaction, # so we have to do a dirty read. However, there is no other [good] way # of getting the information about the instance ID in Neutron-land # additional this point without patching Nova. The only fix I can # think of is actually a enhancement/blueprint to OpenStack for a more # flexible ways of creating requests. In other words, the decision # that only host ID and tenant ID (but not instance ID, for one) # should go into a request for an IP address lies right now with Nova, # but why can't it be made more pluggable/flexible, sort of akin # to https://review.openstack.org/#/c/192663/ cur.execute("SET LOCAL TRANSACTION ISOLATION LEVEL READ UNCOMMITTED") query = ("SELECT `key`, value FROM neutron.ports p JOIN " "nova.instance_metadata im ON p.device_id = im.instance_uuid " "WHERE mac_address = '%s' AND `key` = 'romanaSegment'" % mac) LOG.debug("DB Query: %s" % query) cur.execute(query) rows = [row for row in cur.fetchall()] cur.close() con.close() LOG.debug("Found segments for instance: %s" % rows) if rows: segment_name = rows[0][1] else: msg = "Cannot find romanaSegment value for mac_address %s." % mac raise exceptions.RomanaException(msg) #raise ipam_exc.IpAddressGenerationFailure() LOG.debug("segment_id: %s" % segment_name) if ip_dict.get('ip_address'): return ipam_req.SpecificAddressRequest(ip_dict['ip_address']) elif ip_dict.get('eui64_address'): return ipam_req.AutomaticAddressRequest( prefix=ip_dict['subnet_cidr'], mac=ip_dict['mac']) else: return RomanaAnyAddressRequest(port.get('binding:host_id'), port.get('tenant_id'), segment_name)