def _stubs(self): with self.context.session.begin(): subnet = db_api.subnet_create(self.context, cidr="192.168.0.0/24") db_api.ip_address_create(self.context, address=self.addr, subnet_id=subnet["id"]) yield
def _create_ip_address(self, ip_address, ip_version, subnet_cidr, net_id): with self.context.session.begin(): subnet = db_api.subnet_find(self.context, None, False, None, None, cidr=subnet_cidr).all() ip = dict(subnet_id=subnet[0].id, network_id=net_id, version=ip_version, address=netaddr.IPAddress(ip_address)) db_api.ip_address_create(self.context, **ip)
def _create_ip_address(self, ip_address, ip_version, subnet_cidr, net_id): with self.context.session.begin(): subnet = db_api.subnet_find(context=self.context, limit=None, page_reverse=False, sorts=['id'], marker_obj=None, cidr=subnet_cidr).all() ip = dict(subnet_id=subnet[0].id, network_id=net_id, version=ip_version, address=netaddr.IPAddress(ip_address)) db_api.ip_address_create(self.context, **ip)
def _allocate_from_subnet(self, context, net_id, subnet, port_id, reuse_after, ip_address=None, **kwargs): ip_policy_cidrs = models.IPPolicy.get_ip_policy_cidrs(subnet) next_ip = ip_address if not next_ip: if subnet["next_auto_assign_ip"] != -1: next_ip = netaddr.IPAddress(subnet["next_auto_assign_ip"] - 1) else: next_ip = netaddr.IPAddress(subnet["last_ip"]) if subnet["ip_version"] == 4: next_ip = next_ip.ipv4() if ip_policy_cidrs and next_ip in ip_policy_cidrs and not ip_address: raise q_exc.IPAddressPolicyRetryableFailure(ip_addr=next_ip, net_id=net_id) try: with context.session.begin(): address = db_api.ip_address_create( context, address=next_ip, subnet_id=subnet["id"], deallocated=0, version=subnet["ip_version"], network_id=net_id) address["deallocated"] = 0 except Exception: # NOTE(mdietz): Our version of sqlalchemy incorrectly raises None # here when there's an IP conflict if ip_address: raise exceptions.IpAddressInUse(ip_address=next_ip, net_id=net_id) raise q_exc.IPAddressRetryableFailure(ip_addr=next_ip, net_id=net_id) return address
def _stubs(self, network, subnet, address, lock=False): self.ipam = quark.ipam.QuarkIpamANY() with self.context.session.begin(): next_ip = subnet.pop("next_auto_assign_ip", 0) net_mod = db_api.network_create(self.context, **network) subnet["network"] = net_mod sub_mod = db_api.subnet_create(self.context, **subnet) address["network_id"] = net_mod["id"] address["subnet_id"] = sub_mod["id"] ip = db_api.ip_address_create(self.context, **address) address.pop("address") ip = db_api.ip_address_update(self.context, ip, **address) # NOTE(asadoughi): update after cidr constructor has been invoked db_api.subnet_update(self.context, sub_mod, next_auto_assign_ip=next_ip) if lock: db_api.lock_holder_create(self.context, ip, name="testlock", type="ip_address") yield net_mod
def _allocate_ips_from_subnets(self, context, net_id, subnets, ip_address=None): new_addresses = [] for subnet in subnets: ip_policy_cidrs = models.IPPolicy.get_ip_policy_cidrs(subnet) # Creating this IP for the first time next_ip = None if ip_address: next_ip = ip_address address = db_api.ip_address_find( context, network_id=net_id, ip_address=next_ip, used_by_tenant_id=context.tenant_id, scope=db_api.ONE) if address: raise exceptions.IpAddressGenerationFailure( net_id=net_id) else: next_ip = self._iterate_until_available_ip( context, subnet, net_id, ip_policy_cidrs) context.session.add(subnet) address = db_api.ip_address_create( context, address=next_ip, subnet_id=subnet["id"], version=subnet["ip_version"], network_id=net_id) address["deallocated"] = 0 new_addresses.append(address) return new_addresses
def allocate_ip_address(self, context, net_id, port_id, reuse_after, version=None, ip_address=None): elevated = context.elevated() if ip_address: ip_address = netaddr.IPAddress(ip_address) address = db_api.ip_address_find( elevated, network_id=net_id, reuse_after=reuse_after, deallocated=True, scope=db_api.ONE, ip_address=ip_address) if address: return db_api.ip_address_update( elevated, address, deallocated=False, deallocated_at=None) subnet = self._choose_available_subnet( elevated, net_id, ip_address=ip_address, version=version) # Creating this IP for the first time next_ip = None if ip_address: next_ip = ip_address else: address = True while address: next_ip_int = int(subnet["next_auto_assign_ip"]) next_ip = netaddr.IPAddress(next_ip_int) if subnet["ip_version"] == 4: next_ip = next_ip.ipv4() subnet["next_auto_assign_ip"] = next_ip_int + 1 address = db_api.ip_address_find( elevated, network_id=net_id, ip_address=next_ip, tenant_id=elevated.tenant_id, scope=db_api.ONE) # TODO(mdietz): this is a hack until we have IP policies ip_int = int(next_ip) first_ip = netaddr.IPAddress(int(subnet["first_ip"])) last_ip = netaddr.IPAddress(int(subnet["last_ip"])) if subnet["ip_version"] == 4: first_ip = first_ip.ipv4() last_ip = last_ip.ipv4() first_ip = int(first_ip) last_ip = int(last_ip) diff = ip_int - first_ip if diff < 2: next_ip = netaddr.IPAddress(ip_int + (2 - diff)) if ip_int == last_ip: raise exceptions.IpAddressGenerationFailure(net_id=net_id) if next_ip not in netaddr.IPNetwork(subnet["cidr"]): raise exceptions.IpAddressGenerationFailure(net_id=net_id) address = db_api.ip_address_create( elevated, address=next_ip, subnet_id=subnet["id"], version=subnet["ip_version"], network_id=net_id) return address
def test_create_lock_holder(self): kwargs = {"address": netaddr.IPAddress("192.168.2.1")} ip_address = db_api.ip_address_create(self.context, **kwargs) kwargs = {"type": "ip_address", "name": "because i said so"} lock_holder = db_api.lock_holder_create( self.context, ip_address, **kwargs) self.context.session.refresh(ip_address) self.assertEqual(ip_address.lock_id, lock_holder.lock_id)
def _allocate_from_subnet(self, context, net_id, subnet, port_id, reuse_after, ip_address=None, **kwargs): LOG.info("Creating a new address in subnet {0} - [{1}]".format( subnet["_cidr"], utils.pretty_kwargs(network_id=net_id, subnet=subnet, port_id=port_id, ip_address=ip_address))) if subnet and subnet["ip_policy"]: ip_policy_cidrs = subnet["ip_policy"].get_cidrs_ip_set() else: ip_policy_cidrs = netaddr.IPSet([]) next_ip = ip_address if not next_ip: if subnet["next_auto_assign_ip"] != -1: next_ip = netaddr.IPAddress(subnet["next_auto_assign_ip"] - 1) else: next_ip = netaddr.IPAddress(subnet["last_ip"]) if subnet["ip_version"] == 4: next_ip = next_ip.ipv4() LOG.info("Next IP is {0}".format(str(next_ip))) if ip_policy_cidrs and next_ip in ip_policy_cidrs and not ip_address: LOG.info("Next IP {0} violates policy".format(str(next_ip))) raise q_exc.IPAddressPolicyRetryableFailure(ip_addr=next_ip, net_id=net_id) try: with context.session.begin(): address = db_api.ip_address_create( context, address=next_ip, subnet_id=subnet["id"], deallocated=0, version=subnet["ip_version"], network_id=net_id, port_id=port_id, address_type=kwargs.get('address_type', ip_types.FIXED)) address["deallocated"] = 0 # alexm: instead of notifying billing from here we notify from # allocate_ip_address() when it's clear that the IP # allocation was successful except db_exception.DBDuplicateEntry: raise n_exc.IpAddressInUse(ip_address=next_ip, net_id=net_id) except db_exception.DBError: raise q_exc.IPAddressRetryableFailure(ip_addr=next_ip, net_id=net_id) return address
def allocate_ip_address(self, context, net_id, port_id, reuse_after, version=None, ip_address=None): elevated = context.elevated() if ip_address: ip_address = netaddr.IPAddress(ip_address) new_addresses = [] realloc_ips = self.attempt_to_reallocate_ip(context, net_id, port_id, reuse_after, version=None, ip_address=None) if self.is_strategy_satisfied(realloc_ips): return realloc_ips new_addresses.extend(realloc_ips) with context.session.begin(subtransactions=True): subnets = self._choose_available_subnet( elevated, net_id, version, ip_address=ip_address, reallocated_ips=realloc_ips) for subnet in subnets: ip_policy_rules = models.IPPolicy.get_ip_policy_rule_set( subnet) # Creating this IP for the first time next_ip = None if ip_address: next_ip = ip_address address = db_api.ip_address_find( elevated, network_id=net_id, ip_address=next_ip, used_by_tenant_id=elevated.tenant_id, scope=db_api.ONE) if address: raise exceptions.IpAddressGenerationFailure( net_id=net_id) else: next_ip = self._iterate_until_available_ip( elevated, subnet, net_id, ip_policy_rules) context.session.add(subnet) address = db_api.ip_address_create( elevated, address=next_ip, subnet_id=subnet["id"], version=subnet["ip_version"], network_id=net_id) address["deallocated"] = 0 new_addresses.append(address) for addr in new_addresses: payload = dict(used_by_tenant_id=addr["used_by_tenant_id"], ip_block_id=addr["subnet_id"], ip_address=addr["address_readable"], device_ids=[p["device_id"] for p in addr["ports"]], created_at=addr["created_at"]) notifier_api.notify(context, notifier_api.publisher_id("network"), "ip_block.address.create", notifier_api.CONF.default_notification_level, payload) return new_addresses
def _allocate_from_v6_subnet(self, context, net_id, subnet, port_id, ip_address=None, **kwargs): """This attempts to allocate v6 addresses as per RFC2462 and RFC3041. To accomodate this, we effectively treat all v6 assignment as a first time allocation utilizing the MAC address of the VIF. Because we recycle MACs, we will eventually attempt to recreate a previously generated v6 address. Instead of failing, we've opted to handle reallocating that address in this method. This should provide a performance boost over attempting to check each and every subnet in the existing reallocate logic, as we'd have to iterate over each and every subnet returned """ if not (ip_address is None and "mac_address" in kwargs and kwargs["mac_address"]): return self._allocate_from_subnet(context, net_id, subnet, ip_address, **kwargs) else: ip_policy_cidrs = models.IPPolicy.get_ip_policy_cidrs(subnet) for tries, ip_address in enumerate( generate_v6(kwargs["mac_address"]["address"], port_id, subnet["cidr"])): if tries > CONF.QUARK.v6_allocation_attempts - 1: raise exceptions.IpAddressGenerationFailure( net_id=net_id) ip_address = netaddr.IPAddress(ip_address) # NOTE(mdietz): treating the IPSet as a boolean caused netaddr # to attempt to enumerate the entire set! if (ip_policy_cidrs is not None and ip_address in ip_policy_cidrs): continue with context.session.begin(): address = db_api.ip_address_find( context, network_id=net_id, ip_address=ip_address, used_by_tenant_id=context.tenant_id, scope=db_api.ONE, lock_mode=True) if address: return db_api.ip_address_update( context, address, deallocated=False, deallocated_at=None, used_by_tenant_id=context.tenant_id, allocated_at=timeutils.utcnow()) with context.session.begin(): return db_api.ip_address_create( context, address=ip_address, subnet_id=subnet["id"], version=subnet["ip_version"], network_id=net_id)
def test_create_locks_address_exists(self): network = db_api.network_create(self.context) address_model = db_api.ip_address_create( self.context, address=netaddr.IPAddress("192.168.10.1"), network=network) self.context.session.flush() addresses = netaddr.IPSet(netaddr.IPNetwork(self.sub_cidr)) null_routes.create_locks(self.context, [network.id], addresses) self.context.session.refresh(address_model) self.assertIsNotNone(address_model.lock_id)
def _allocate_from_subnet(self, context, net_id, subnet, port_id, reuse_after, ip_address=None, **kwargs): LOG.info("Creating a new address in subnet {0} - [{1}]".format( subnet["_cidr"], utils.pretty_kwargs(network_id=net_id, subnet=subnet, port_id=port_id, ip_address=ip_address))) ip_policy_cidrs = models.IPPolicy.get_ip_policy_cidrs(subnet) next_ip = ip_address if not next_ip: if subnet["next_auto_assign_ip"] != -1: next_ip = netaddr.IPAddress(subnet["next_auto_assign_ip"] - 1) else: next_ip = netaddr.IPAddress(subnet["last_ip"]) if subnet["ip_version"] == 4: next_ip = next_ip.ipv4() LOG.info("Next IP is {0}".format(str(next_ip))) if ip_policy_cidrs and next_ip in ip_policy_cidrs and not ip_address: LOG.info("Next IP {0} violates policy".format(str(next_ip))) raise q_exc.IPAddressPolicyRetryableFailure(ip_addr=next_ip, net_id=net_id) try: with context.session.begin(): address = db_api.ip_address_create( context, address=next_ip, subnet_id=subnet["id"], deallocated=0, version=subnet["ip_version"], network_id=net_id, port_id=port_id, address_type=kwargs.get('address_type', ip_types.FIXED)) address["deallocated"] = 0 except Exception: # NOTE(mdietz): Our version of sqlalchemy incorrectly raises None # here when there's an IP conflict if ip_address: raise exceptions.IpAddressInUse(ip_address=next_ip, net_id=net_id) raise q_exc.IPAddressRetryableFailure(ip_addr=next_ip, net_id=net_id) return address
def test_delete_locks_doesnt_have_lock(self): network = db_api.network_create(self.context) address_model = db_api.ip_address_create( self.context, address=netaddr.IPAddress("192.168.10.1"), network=network) db_api.lock_holder_create( self.context, address_model, name="not-null-routes", type="ip_address") self.context.session.flush() null_routes.delete_locks(self.context, [network.id], []) self.context.session.refresh(address_model) self.assertIsNotNone(address_model.lock_id)
def _stubs(self, network, subnet, ip_address1, ip_address2, ip_address3): with self.context.session.begin(): net_mod = db_api.network_create(self.context, **network) subnet["network"] = net_mod sub_mod = db_api.subnet_create(self.context, **subnet) # set tenant id to "123" ip_address1['network_id'] = net_mod.id ip_address1['subnet_id'] = sub_mod.id self.context.tenant_id = 123 ip_address1 = db_api.ip_address_create(self.context, **ip_address1) # set tenant_id=456 ip_address2['network_id'] = net_mod.id ip_address2['subnet_id'] = sub_mod.id self.context.tenant_id = 456 ip_address2 = db_api.ip_address_create(self.context, **ip_address2) # set tenant id = "123" to test the list of IPs ip_address3['network_id'] = net_mod.id ip_address3['subnet_id'] = sub_mod.id self.context.tenant_id = 123 ip_address3 = db_api.ip_address_create(self.context, **ip_address3) yield net_mod with self.context.session.begin(): db_api.subnet_delete(self.context, sub_mod) db_api.network_delete(self.context, net_mod)
def insert_ip_address(self, ip_address, network_db, subnet_db): ip_address_db = db_api.ip_address_create( self.context, address=ip_address, version=ip_address.version, subnet_id=subnet_db["id"] if subnet_db else None, network_id=network_db["id"]) ip_address_db["_deallocated"] = True ip_address_db["deallocated_at"] = ( timeutils.utcnow() - datetime.timedelta(seconds=self.REUSE_AFTER)) self.context.session.add(ip_address_db) self.context.session.flush() return ip_address_db
def allocate_ip_address(self, context, net_id, port_id, reuse_after, version=None, ip_address=None): elevated = context.elevated() if ip_address: ip_address = netaddr.IPAddress(ip_address) address = db_api.ip_address_find( elevated, network_id=net_id, reuse_after=reuse_after, deallocated=True, scope=db_api.ONE, ip_address=ip_address) if address: return db_api.ip_address_update( elevated, address, deallocated=False, deallocated_at=None) subnet = self._choose_available_subnet( elevated, net_id, ip_address=ip_address, version=version) ip_policy_rules = self.get_ip_policy_rule_set(subnet) # Creating this IP for the first time next_ip = None if ip_address: next_ip = ip_address address = db_api.ip_address_find( elevated, network_id=net_id, ip_address=next_ip, tenant_id=elevated.tenant_id, scope=db_api.ONE) if address: raise exceptions.IpAddressGenerationFailure(net_id=net_id) else: address = True while address: next_ip_int = int(subnet["next_auto_assign_ip"]) next_ip = netaddr.IPAddress(next_ip_int) if subnet["ip_version"] == 4: next_ip = next_ip.ipv4() subnet["next_auto_assign_ip"] = next_ip_int + 1 if ip_policy_rules and next_ip in ip_policy_rules: continue address = db_api.ip_address_find( elevated, network_id=net_id, ip_address=next_ip, tenant_id=elevated.tenant_id, scope=db_api.ONE) address = db_api.ip_address_create( elevated, address=next_ip, subnet_id=subnet["id"], version=subnet["ip_version"], network_id=net_id) address["deallocated"] = 0 return address
def test_find_lock_holder(self): kwargs = {"address": netaddr.IPAddress("192.168.2.1")} ip_address = db_api.ip_address_create(self.context, **kwargs) kwargs = {"type": "ip_address", "name": "because i said so"} lock_holder = db_api.lock_holder_create( self.context, ip_address, **kwargs) self.context.session.refresh(ip_address) self.assertEqual(ip_address.lock_id, lock_holder.lock_id) lock_holders = db_api.lock_holder_find( self.context, lock_id=ip_address.lock_id, name=kwargs["name"], scope=db_api.ALL) self.assertEqual(len(lock_holders), 1) self.assertEqual(lock_holders[0]["lock_id"], ip_address.lock_id) self.assertEqual(lock_holders[0]["name"], kwargs["name"])
def _stubs(self, network, subnet, address): self.ipam = quark.ipam.QuarkIpamANY() with self.context.session.begin(): next_ip = subnet.pop("next_auto_assign_ip", 0) net_mod = db_api.network_create(self.context, **network) subnet["network"] = net_mod sub_mod = db_api.subnet_create(self.context, **subnet) address["network_id"] = net_mod["id"] address["subnet_id"] = sub_mod["id"] ip = db_api.ip_address_create(self.context, **address) address.pop("address") db_api.ip_address_update(self.context, ip, **address) # NOTE(asadoughi): update after cidr constructor has been invoked db_api.subnet_update(self.context, sub_mod, next_auto_assign_ip=next_ip) yield net_mod
def _allocate_from_subnet(self, context, net_id, subnet, port_id, reuse_after, ip_address=None, **kwargs): ip_policy_cidrs = models.IPPolicy.get_ip_policy_cidrs(subnet) next_ip = ip_address if not next_ip: if subnet["next_auto_assign_ip"] != -1: next_ip = netaddr.IPAddress(subnet["next_auto_assign_ip"] - 1) else: next_ip = netaddr.IPAddress(subnet["last_ip"]) if subnet["ip_version"] == 4: next_ip = next_ip.ipv4() if (ip_policy_cidrs is not None and next_ip in ip_policy_cidrs): if not ip_address: raise q_exc.IPAddressPolicyRetryableFailure(ip_addr=next_ip, net_id=net_id) try: with context.session.begin(): address = db_api.ip_address_create( context, address=next_ip, subnet_id=subnet["id"], deallocated=0, version=subnet["ip_version"], network_id=net_id) address["deallocated"] = 0 except Exception: # NOTE(mdietz): Our version of sqlalchemy incorrectly raises None # here when there's an IP conflict if ip_address: raise exceptions.IpAddressInUse(ip_address=next_ip, net_id=net_id) raise q_exc.IPAddressRetryableFailure(ip_addr=next_ip, net_id=net_id) return address
def test_create_locks_lock_holder_exists(self): network = db_api.network_create(self.context) address_model = db_api.ip_address_create( self.context, address=netaddr.IPAddress("192.168.10.1"), network=network) db_api.lock_holder_create( self.context, address_model, name=null_routes.LOCK_NAME, type="ip_address") self.context.session.flush() addresses = netaddr.IPSet(netaddr.IPNetwork(self.sub_cidr)) null_routes.create_locks(self.context, [network.id], addresses) lock_holders = db_api.lock_holder_find( self.context, lock_id=address_model.lock_id, name=null_routes.LOCK_NAME, scope=db_api.ALL) self.assertEqual(len(lock_holders), 1)
def _find_or_create_address(context, network_ids, address): address_model = db_api.ip_address_find( context, network_id=network_ids, address=_to_int(address), scope=db_api.ONE) if not address_model: query = context.session.query(models.Subnet) query = query.filter(models.Subnet.network_id.in_(network_ids)) query = query.filter(models.Subnet.ip_version == address.version) query = query.filter(_to_int(address) >= models.Subnet.first_ip) query = query.filter(_to_int(address) <= models.Subnet.last_ip) subnet = query.one() address_model = db_api.ip_address_create( context, address=address, subnet_id=subnet["id"], version=subnet["ip_version"], network_id=subnet["network_id"], address_type=ip_types.FIXED) address_model["deallocated"] = 1 context.session.add(address_model) return address_model
def test_create_lock_holder_already_locked(self): kwargs = {"address": netaddr.IPAddress("192.168.2.1")} ip_address = db_api.ip_address_create(self.context, **kwargs) name = "because i said so" kwargs_1 = {"type": "ip_address", "name": name + "1"} lock_holder_1 = db_api.lock_holder_create( self.context, ip_address, **kwargs_1) self.context.session.flush() kwargs_2 = {"type": "ip_address", "name": name + "2"} self.context.session.refresh(ip_address) lock_holder_2 = db_api.lock_holder_create( self.context, ip_address, **kwargs_2) self.context.session.flush() self.context.session.refresh(ip_address) self.assertNotEqual(lock_holder_1.id, lock_holder_2.id) self.assertEqual(lock_holder_1.name, name + "1") self.assertEqual(lock_holder_2.name, name + "2") self.assertEqual(lock_holder_1.lock_id, lock_holder_2.lock_id) self.assertEqual(ip_address.lock_id, lock_holder_1.lock_id)
def test_ip_address_port_find_service(self): net = db_api.network_create(self.context) port = db_api.port_create(self.context, network_id=net["id"], backend_key="", device_id="") ip_address = db_api.ip_address_create( self.context, address=netaddr.IPAddress("0.0.0.0")) self.context.session.flush() ip_address = db_api.port_associate_ip(self.context, [port], ip_address) ip_address.set_service_for_port(port, "foobar") self.context.session.flush() ports = ip_api.get_ports_for_ip_address( self.context, ip_address["id"], filters={"service": "not-foobar"}) self.assertEqual(len(ports), 0) ports = ip_api.get_ports_for_ip_address( self.context, ip_address["id"], filters={"service": "foobar"}) self.assertEqual(len(ports), 1)
def _find_or_create_address(context, network_ids, address): address_model = db_api.ip_address_find(context, network_id=network_ids, address=_to_int(address), scope=db_api.ONE) if not address_model: query = context.session.query(models.Subnet) query = query.filter(models.Subnet.network_id.in_(network_ids)) query = query.filter(models.Subnet.ip_version == address.version) query = query.filter(_to_int(address) >= models.Subnet.first_ip) query = query.filter(_to_int(address) <= models.Subnet.last_ip) subnet = query.one() address_model = db_api.ip_address_create( context, address=address, subnet_id=subnet["id"], version=subnet["ip_version"], network_id=subnet["network_id"], address_type=ip_types.FIXED) address_model["deallocated"] = 1 context.session.add(address_model) return address_model
def allocate_ip_address(self, context, net_id, port_id, reuse_after, version=None, ip_address=None): elevated = context.elevated() if ip_address: ip_address = netaddr.IPAddress(ip_address) address = db_api.ip_address_find(elevated, network_id=net_id, reuse_after=reuse_after, deallocated=True, scope=db_api.ONE, ip_address=ip_address) if address: return db_api.ip_address_update(elevated, address, deallocated=False, deallocated_at=None) subnet = self._choose_available_subnet(elevated, net_id, ip_address=ip_address, version=version) ip_policy_rules = self.get_ip_policy_rule_set(subnet) # Creating this IP for the first time next_ip = None if ip_address: next_ip = ip_address address = db_api.ip_address_find(elevated, network_id=net_id, ip_address=next_ip, tenant_id=elevated.tenant_id, scope=db_api.ONE) if address: raise exceptions.IpAddressGenerationFailure(net_id=net_id) else: address = True while address: next_ip_int = int(subnet["next_auto_assign_ip"]) next_ip = netaddr.IPAddress(next_ip_int) if subnet["ip_version"] == 4: next_ip = next_ip.ipv4() subnet["next_auto_assign_ip"] = next_ip_int + 1 if ip_policy_rules and next_ip in ip_policy_rules: continue address = db_api.ip_address_find(elevated, network_id=net_id, ip_address=next_ip, tenant_id=elevated.tenant_id, scope=db_api.ONE) address = db_api.ip_address_create(elevated, address=next_ip, subnet_id=subnet["id"], version=subnet["ip_version"], network_id=net_id) address["deallocated"] = 0 return address
def _allocate_from_v6_subnet(self, context, net_id, subnet, port_id, reuse_after, ip_address=None, **kwargs): """This attempts to allocate v6 addresses as per RFC2462 and RFC3041. To accomodate this, we effectively treat all v6 assignment as a first time allocation utilizing the MAC address of the VIF. Because we recycle MACs, we will eventually attempt to recreate a previously generated v6 address. Instead of failing, we've opted to handle reallocating that address in this method. This should provide a performance boost over attempting to check each and every subnet in the existing reallocate logic, as we'd have to iterate over each and every subnet returned """ if not (ip_address is None and "mac_address" in kwargs and kwargs["mac_address"]): return self._allocate_from_subnet(context, net_id, subnet, reuse_after, ip_address, **kwargs) else: ip_policy_cidrs = models.IPPolicy.get_ip_policy_cidrs(subnet) for tries, ip_address in enumerate( generate_v6(kwargs["mac_address"]["address"], port_id, subnet["cidr"])): if tries > CONF.QUARK.v6_allocation_attempts - 1: raise exceptions.IpAddressGenerationFailure(net_id=net_id) ip_address = netaddr.IPAddress(ip_address) # NOTE(mdietz): treating the IPSet as a boolean caused netaddr # to attempt to enumerate the entire set! if (ip_policy_cidrs is not None and ip_address in ip_policy_cidrs): continue # TODO(mdietz): replace this with a compare-and-swap loop with context.session.begin(): address = db_api.ip_address_find(context, network_id=net_id, ip_address=ip_address, scope=db_api.ONE, reuse_after=reuse_after, deallocated=True, subnet_id=subnet["id"], lock_mode=True) if address: return db_api.ip_address_update( context, address, deallocated=False, deallocated_at=None, used_by_tenant_id=context.tenant_id, allocated_at=timeutils.utcnow()) # This triggers when the IP is allocated to another tenant, # either because we missed it due to our filters above, or # in an extremely unlikely race between the find and here. try: with context.session.begin(): return db_api.ip_address_create( context, address=ip_address, subnet_id=subnet["id"], version=subnet["ip_version"], network_id=net_id) except db_exception.DBDuplicateEntry: LOG.debug( "Duplicate entry found when inserting subnet_id" " %s ip_address %s", subnet["id"], ip_address)
def _allocate_from_v6_subnet(self, context, net_id, subnet, port_id, reuse_after, ip_address=None, **kwargs): """This attempts to allocate v6 addresses as per RFC2462 and RFC3041. To accomodate this, we effectively treat all v6 assignment as a first time allocation utilizing the MAC address of the VIF. Because we recycle MACs, we will eventually attempt to recreate a previously generated v6 address. Instead of failing, we've opted to handle reallocating that address in this method. This should provide a performance boost over attempting to check each and every subnet in the existing reallocate logic, as we'd have to iterate over each and every subnet returned """ LOG.info("Attempting to allocate a v6 address - [{0}]".format( utils.pretty_kwargs(network_id=net_id, subnet=subnet, port_id=port_id, ip_address=ip_address))) if ip_address: LOG.info("IP %s explicitly requested, deferring to standard " "allocation" % ip_address) return self._allocate_from_subnet(context, net_id=net_id, subnet=subnet, port_id=port_id, reuse_after=reuse_after, ip_address=ip_address, **kwargs) else: mac = kwargs.get("mac_address") if mac: mac = kwargs["mac_address"].get("address") if subnet and subnet["ip_policy"]: ip_policy_cidrs = subnet["ip_policy"].get_cidrs_ip_set() else: ip_policy_cidrs = netaddr.IPSet([]) for tries, ip_address in enumerate( generate_v6(mac, port_id, subnet["cidr"])): LOG.info("Attempt {0} of {1}".format( tries + 1, CONF.QUARK.v6_allocation_attempts)) if tries > CONF.QUARK.v6_allocation_attempts - 1: LOG.info("Exceeded v6 allocation attempts, bailing") raise ip_address_failure(net_id) ip_address = netaddr.IPAddress(ip_address).ipv6() LOG.info("Generated a new v6 address {0}".format( str(ip_address))) if (ip_policy_cidrs is not None and ip_address in ip_policy_cidrs): LOG.info("Address {0} excluded by policy".format( str(ip_address))) continue try: with context.session.begin(): address = db_api.ip_address_create( context, address=ip_address, subnet_id=subnet["id"], version=subnet["ip_version"], network_id=net_id, address_type=kwargs.get('address_type', ip_types.FIXED)) return address except db_exception.DBDuplicateEntry: # This shouldn't ever happen, since we hold a unique MAC # address from the previous IPAM step. LOG.info("{0} exists but was already " "allocated".format(str(ip_address))) LOG.debug("Duplicate entry found when inserting subnet_id" " %s ip_address %s", subnet["id"], ip_address)
def _allocate_from_v6_subnet(self, context, net_id, subnet, port_id, reuse_after, ip_address=None, **kwargs): """This attempts to allocate v6 addresses as per RFC2462 and RFC3041. To accomodate this, we effectively treat all v6 assignment as a first time allocation utilizing the MAC address of the VIF. Because we recycle MACs, we will eventually attempt to recreate a previously generated v6 address. Instead of failing, we've opted to handle reallocating that address in this method. This should provide a performance boost over attempting to check each and every subnet in the existing reallocate logic, as we'd have to iterate over each and every subnet returned """ LOG.info("Attempting to allocate a v6 address - [{0}]".format( utils.pretty_kwargs(network_id=net_id, subnet=subnet, port_id=port_id, ip_address=ip_address))) if ip_address: LOG.info("IP %s explicitly requested, deferring to standard " "allocation" % ip_address) return self._allocate_from_subnet(context, net_id=net_id, subnet=subnet, port_id=port_id, reuse_after=reuse_after, ip_address=ip_address, **kwargs) else: mac = kwargs.get("mac_address") if mac: mac = kwargs["mac_address"].get("address") ip_policy_cidrs = models.IPPolicy.get_ip_policy_cidrs(subnet) for tries, ip_address in enumerate( generate_v6(mac, port_id, subnet["cidr"])): LOG.info("Attempt {0} of {1}".format( tries + 1, CONF.QUARK.v6_allocation_attempts)) if tries > CONF.QUARK.v6_allocation_attempts - 1: LOG.info("Exceeded v6 allocation attempts, bailing") raise exceptions.IpAddressGenerationFailure( net_id=net_id) ip_address = netaddr.IPAddress(ip_address).ipv6() LOG.info("Generated a new v6 address {0}".format( str(ip_address))) # NOTE(mdietz): treating the IPSet as a boolean caused netaddr # to attempt to enumerate the entire set! if (ip_policy_cidrs is not None and ip_address in ip_policy_cidrs): LOG.info("Address {0} excluded by policy".format( str(ip_address))) continue # TODO(mdietz): replace this with a compare-and-swap loop with context.session.begin(): address = db_api.ip_address_find( context, network_id=net_id, ip_address=ip_address, scope=db_api.ONE, reuse_after=reuse_after, deallocated=True, subnet_id=subnet["id"], lock_mode=True) if address: LOG.info("Address {0} exists, claiming".format( str(ip_address))) return db_api.ip_address_update( context, address, deallocated=False, deallocated_at=None, used_by_tenant_id=context.tenant_id, allocated_at=timeutils.utcnow(), address_type=kwargs.get('address_type', ip_types.FIXED)) # This triggers when the IP is allocated to another tenant, # either because we missed it due to our filters above, or # in an extremely unlikely race between the find and here. try: with context.session.begin(): return db_api.ip_address_create( context, address=ip_address, subnet_id=subnet["id"], version=subnet["ip_version"], network_id=net_id, address_type=kwargs.get('address_type', ip_types.FIXED)) except db_exception.DBDuplicateEntry: LOG.info("{0} exists but was already " "allocated".format(str(ip_address))) LOG.debug("Duplicate entry found when inserting subnet_id" " %s ip_address %s", subnet["id"], ip_address)
def setUp(self): super(QuarkIPAddressFind, self).setUp() self.address = netaddr.IPAddress("0.0.0.1") db_api.ip_address_create(self.context, address=self.address) self.context.session.flush()
def _stubs(self): with self.context.session.begin(): db_api.ip_address_create(self.context, address=self.addr) yield
def _allocate_from_v6_subnet(self, context, net_id, subnet, port_id, reuse_after, ip_address=None, **kwargs): """This attempts to allocate v6 addresses as per RFC2462 and RFC3041. To accomodate this, we effectively treat all v6 assignment as a first time allocation utilizing the MAC address of the VIF. Because we recycle MACs, we will eventually attempt to recreate a previously generated v6 address. Instead of failing, we've opted to handle reallocating that address in this method. This should provide a performance boost over attempting to check each and every subnet in the existing reallocate logic, as we'd have to iterate over each and every subnet returned """ if (ip_address or "mac_address" not in kwargs or not kwargs["mac_address"]): return self._allocate_from_subnet(context, net_id=net_id, subnet=subnet, port_id=port_id, reuse_after=reuse_after, ip_address=ip_address, **kwargs) else: ip_policy_cidrs = models.IPPolicy.get_ip_policy_cidrs(subnet) for tries, ip_address in enumerate( generate_v6(kwargs["mac_address"]["address"], port_id, subnet["cidr"])): if tries > CONF.QUARK.v6_allocation_attempts - 1: raise exceptions.IpAddressGenerationFailure( net_id=net_id) ip_address = netaddr.IPAddress(ip_address) # NOTE(mdietz): treating the IPSet as a boolean caused netaddr # to attempt to enumerate the entire set! if (ip_policy_cidrs is not None and ip_address in ip_policy_cidrs): continue # TODO(mdietz): replace this with a compare-and-swap loop with context.session.begin(): address = db_api.ip_address_find( context, network_id=net_id, ip_address=ip_address, scope=db_api.ONE, reuse_after=reuse_after, deallocated=True, subnet_id=subnet["id"], lock_mode=True) if address: return db_api.ip_address_update( context, address, deallocated=False, deallocated_at=None, used_by_tenant_id=context.tenant_id, allocated_at=timeutils.utcnow()) # This triggers when the IP is allocated to another tenant, # either because we missed it due to our filters above, or # in an extremely unlikely race between the find and here. try: with context.session.begin(): return db_api.ip_address_create( context, address=ip_address, subnet_id=subnet["id"], version=subnet["ip_version"], network_id=net_id) except db_exception.DBDuplicateEntry: LOG.debug("Duplicate entry found when inserting subnet_id" " %s ip_address %s", subnet["id"], ip_address)
def _allocate_from_v6_subnet(self, context, net_id, subnet, port_id, reuse_after, ip_address=None, **kwargs): """This attempts to allocate v6 addresses as per RFC2462 and RFC3041. To accomodate this, we effectively treat all v6 assignment as a first time allocation utilizing the MAC address of the VIF. Because we recycle MACs, we will eventually attempt to recreate a previously generated v6 address. Instead of failing, we've opted to handle reallocating that address in this method. This should provide a performance boost over attempting to check each and every subnet in the existing reallocate logic, as we'd have to iterate over each and every subnet returned """ LOG.info("Attempting to allocate a v6 address - [{0}]".format( utils.pretty_kwargs(network_id=net_id, subnet=subnet, port_id=port_id, ip_address=ip_address))) if ip_address: LOG.info("IP %s explicitly requested, deferring to standard " "allocation" % ip_address) return self._allocate_from_subnet(context, net_id=net_id, subnet=subnet, port_id=port_id, reuse_after=reuse_after, ip_address=ip_address, **kwargs) else: mac = kwargs.get("mac_address") if mac: mac = kwargs["mac_address"].get("address") if subnet and subnet["ip_policy"]: ip_policy_cidrs = subnet["ip_policy"].get_cidrs_ip_set() else: ip_policy_cidrs = netaddr.IPSet([]) for tries, ip_address in enumerate( generate_v6(mac, port_id, subnet["cidr"])): LOG.info("Attempt {0} of {1}".format( tries + 1, CONF.QUARK.v6_allocation_attempts)) if tries > CONF.QUARK.v6_allocation_attempts - 1: LOG.info("Exceeded v6 allocation attempts, bailing") raise ip_address_failure(net_id) ip_address = netaddr.IPAddress(ip_address).ipv6() LOG.info("Generated a new v6 address {0}".format( str(ip_address))) if (ip_policy_cidrs is not None and ip_address in ip_policy_cidrs): LOG.info("Address {0} excluded by policy".format( str(ip_address))) continue try: with context.session.begin(): address = db_api.ip_address_create( context, address=ip_address, subnet_id=subnet["id"], version=subnet["ip_version"], network_id=net_id, address_type=kwargs.get('address_type', ip_types.FIXED)) # alexm: need to notify from here because this code # does not go through the _allocate_from_subnet() path. notify(context, 'ip.add', address) return address except db_exception.DBDuplicateEntry: # This shouldn't ever happen, since we hold a unique MAC # address from the previous IPAM step. LOG.info("{0} exists but was already " "allocated".format(str(ip_address))) LOG.debug( "Duplicate entry found when inserting subnet_id" " %s ip_address %s", subnet["id"], ip_address)