Exemplo n.º 1
0
 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))
Exemplo n.º 2
0
 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
Exemplo n.º 3
0
    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)