diff --git a/neutron/ipam/drivers/neutrondb_ipam/db_api.py b/neutron/ipam/drivers/neutrondb_ipam/db_api.py index 10263062ee3..e898e1c6548 100644 --- a/neutron/ipam/drivers/neutrondb_ipam/db_api.py +++ b/neutron/ipam/drivers/neutrondb_ipam/db_api.py @@ -23,8 +23,8 @@ from neutron.ipam.drivers.neutrondb_ipam import db_models class IpamSubnetManager(object): @classmethod - def load_by_neutron_subnet_id(cls, session, neutron_subnet_id): - return session.query(db_models.IpamSubnet).filter_by( + def load_by_neutron_subnet_id(cls, context, neutron_subnet_id): + return context.session.query(db_models.IpamSubnet).filter_by( neutron_subnet_id=neutron_subnet_id).first() def __init__(self, ipam_subnet_id, neutron_subnet_id): @@ -35,13 +35,13 @@ class IpamSubnetManager(object): def neutron_id(self): return self._neutron_subnet_id - def create(self, session): + def create(self, context): """Create database models for an IPAM subnet. This method creates a subnet resource for the IPAM driver and associates it with its neutron identifier, if specified. - :param session: database sesssion. + :param context: neutron api request context :returns: the idenfier of created IPAM subnet """ if not self._ipam_subnet_id: @@ -49,23 +49,23 @@ class IpamSubnetManager(object): ipam_subnet = db_models.IpamSubnet( id=self._ipam_subnet_id, neutron_subnet_id=self._neutron_subnet_id) - session.add(ipam_subnet) + context.session.add(ipam_subnet) return self._ipam_subnet_id @classmethod - def delete(cls, session, neutron_subnet_id): + def delete(cls, context, neutron_subnet_id): """Delete IPAM subnet. IPAM subnet no longer has foreign key to neutron subnet, so need to perform delete manually - :param session: database sesssion + :param context: neutron api request context :param neutron_subnet_id: neutron subnet id associated with ipam subnet """ - return session.query(db_models.IpamSubnet).filter_by( + return context.session.query(db_models.IpamSubnet).filter_by( neutron_subnet_id=neutron_subnet_id).delete() - def create_pool(self, session, pool_start, pool_end): + def create_pool(self, context, pool_start, pool_end): """Create an allocation pool for the subnet. This method does not perform any validation on parameters; it simply @@ -79,50 +79,50 @@ class IpamSubnetManager(object): ipam_subnet_id=self._ipam_subnet_id, first_ip=pool_start, last_ip=pool_end) - session.add(ip_pool) + context.session.add(ip_pool) return ip_pool - def delete_allocation_pools(self, session): + def delete_allocation_pools(self, context): """Remove all allocation pools for the current subnet. - :param session: database session + :param context: neutron api request context """ - session.query(db_models.IpamAllocationPool).filter_by( + context.session.query(db_models.IpamAllocationPool).filter_by( ipam_subnet_id=self._ipam_subnet_id).delete() - def list_pools(self, session): + def list_pools(self, context): """Return pools for the current subnet.""" - return session.query( + return context.session.query( db_models.IpamAllocationPool).filter_by( ipam_subnet_id=self._ipam_subnet_id) - def check_unique_allocation(self, session, ip_address): + def check_unique_allocation(self, context, ip_address): """Validate that the IP address on the subnet is not in use.""" - iprequest = session.query(db_models.IpamAllocation).filter_by( + iprequest = context.session.query(db_models.IpamAllocation).filter_by( ipam_subnet_id=self._ipam_subnet_id, status='ALLOCATED', ip_address=ip_address).first() if iprequest: return False return True - def list_allocations(self, session, status='ALLOCATED'): + def list_allocations(self, context, status='ALLOCATED'): """Return current allocations for the subnet. - :param session: database session + :param context: neutron api request context :param status: IP allocation status :returns: a list of IP allocation as instance of neutron.ipam.drivers.neutrondb_ipam.db_models.IpamAllocation """ - return session.query( + return context.session.query( db_models.IpamAllocation).filter_by( ipam_subnet_id=self._ipam_subnet_id, status=status) - def create_allocation(self, session, ip_address, + def create_allocation(self, context, ip_address, status='ALLOCATED'): """Create an IP allocation entry. - :param session: database session + :param context: neutron api request context :param ip_address: the IP address to allocate :param status: IP allocation status """ @@ -130,16 +130,16 @@ class IpamSubnetManager(object): ip_address=ip_address, status=status, ipam_subnet_id=self._ipam_subnet_id) - session.add(ip_request) + context.session.add(ip_request) - def delete_allocation(self, session, ip_address): + def delete_allocation(self, context, ip_address): """Remove an IP allocation for this subnet. - :param session: database session + :param context: neutron api request context :param ip_address: IP address for which the allocation entry should be removed. """ - return session.query(db_models.IpamAllocation).filter_by( + return context.session.query(db_models.IpamAllocation).filter_by( ip_address=ip_address, ipam_subnet_id=self._ipam_subnet_id).delete( synchronize_session=False) diff --git a/neutron/ipam/drivers/neutrondb_ipam/driver.py b/neutron/ipam/drivers/neutrondb_ipam/driver.py index 7f5e7088d5e..1858d5daac4 100644 --- a/neutron/ipam/drivers/neutrondb_ipam/driver.py +++ b/neutron/ipam/drivers/neutrondb_ipam/driver.py @@ -43,14 +43,14 @@ class NeutronDbSubnet(ipam_base.Subnet): """ @classmethod - def create_allocation_pools(cls, subnet_manager, session, pools, cidr): + def create_allocation_pools(cls, subnet_manager, context, pools, cidr): for pool in pools: # IPv6 addresses that start '::1', '::2', etc cause IP version # ambiguity when converted to integers by pool.first and pool.last. # Infer the IP version from the subnet cidr. ip_version = cidr.version subnet_manager.create_pool( - session, + context, netaddr.IPAddress(pool.first, ip_version).format(), netaddr.IPAddress(pool.last, ip_version).format()) @@ -61,8 +61,7 @@ class NeutronDbSubnet(ipam_base.Subnet): ipam_subnet_id, subnet_request.subnet_id) # Create subnet resource - session = ctx.session - subnet_manager.create(session) + subnet_manager.create(ctx) # If allocation pools are not specified, define them around # the subnet's gateway IP if not subnet_request.allocation_pools: @@ -71,7 +70,7 @@ class NeutronDbSubnet(ipam_base.Subnet): else: pools = subnet_request.allocation_pools # Create IPAM allocation pools - cls.create_allocation_pools(subnet_manager, session, pools, + cls.create_allocation_pools(subnet_manager, ctx, pools, subnet_request.subnet_cidr) return cls(ipam_subnet_id, @@ -89,7 +88,7 @@ class NeutronDbSubnet(ipam_base.Subnet): :param neutron_subnet_id: neutron subnet identifier. """ ipam_subnet = ipam_db_api.IpamSubnetManager.load_by_neutron_subnet_id( - ctx.session, neutron_subnet_id) + ctx, neutron_subnet_id) if not ipam_subnet: LOG.error(_LE("IPAM subnet referenced to " "Neutron subnet %s does not exist"), @@ -132,15 +131,15 @@ class NeutronDbSubnet(ipam_base.Subnet): self._subnet_id) self._context = ctx - def _verify_ip(self, session, ip_address): + def _verify_ip(self, context, ip_address): """Verify whether IP address can be allocated on subnet. - :param session: database session + :param context: neutron api request context :param ip_address: String representing the IP address to verify :raises: InvalidInput, IpAddressAlreadyAllocated """ # Ensure that the IP's are unique - if not self.subnet_manager.check_unique_allocation(session, + if not self.subnet_manager.check_unique_allocation(context, ip_address): raise ipam_exc.IpAddressAlreadyAllocated( subnet_id=self.subnet_manager.neutron_id, @@ -152,13 +151,13 @@ class NeutronDbSubnet(ipam_base.Subnet): subnet_id=self.subnet_manager.neutron_id, ip=ip_address) - def _generate_ip(self, session, prefer_next=False): + def _generate_ip(self, context, prefer_next=False): """Generate an IP address from the set of available addresses.""" ip_allocations = netaddr.IPSet() - for ipallocation in self.subnet_manager.list_allocations(session): + for ipallocation in self.subnet_manager.list_allocations(context): ip_allocations.add(netaddr.IPAddress(ipallocation.ip_address)) - for ip_pool in self.subnet_manager.list_pools(session): + for ip_pool in self.subnet_manager.list_pools(context): ip_set = netaddr.IPSet() ip_set.add(netaddr.IPRange(ip_pool.first_ip, ip_pool.last_ip)) av_set = ip_set.difference(ip_allocations) @@ -183,7 +182,6 @@ class NeutronDbSubnet(ipam_base.Subnet): # running transaction, which is started on create_port or upper level. # To be able to do rollback/retry actions correctly ipam driver # should not create new nested transaction blocks. - session = self._context.session all_pool_id = None # NOTE(salv-orlando): It would probably better to have a simpler # model for address requests and just check whether there is a @@ -192,22 +190,24 @@ class NeutronDbSubnet(ipam_base.Subnet): # This handles both specific and automatic address requests # Check availability of requested IP ip_address = str(address_request.address) - self._verify_ip(session, ip_address) + self._verify_ip(self._context, ip_address) else: prefer_next = isinstance(address_request, ipam_req.PreferNextAddressRequest) - ip_address, all_pool_id = self._generate_ip(session, prefer_next) + ip_address, all_pool_id = self._generate_ip(self._context, + prefer_next) # Create IP allocation request object # The only defined status at this stage is 'ALLOCATED'. # More states will be available in the future - e.g.: RECYCLABLE try: - with session.begin(subtransactions=True): + with self._context.session.begin(subtransactions=True): # NOTE(kevinbenton): we use a subtransaction to force # a flush here so we can capture DBReferenceErrors due # to concurrent subnet deletions. (galera would deadlock # later on final commit) - self.subnet_manager.create_allocation(session, ip_address) + self.subnet_manager.create_allocation(self._context, + ip_address) except db_exc.DBReferenceError: raise n_exc.SubnetNotFound( subnet_id=self.subnet_manager.neutron_id) @@ -215,21 +215,19 @@ class NeutronDbSubnet(ipam_base.Subnet): def deallocate(self, address): # This is almost a no-op because the Neutron DB IPAM driver does not - # delete IPAllocation objects at every deallocation. The only operation - # it performs is to delete an IPRequest entry. - session = self._context.session - + # delete IPAllocation objects at every deallocation. The only + # operation it performs is to delete an IPRequest entry. count = self.subnet_manager.delete_allocation( - session, address) + self._context, address) # count can hardly be greater than 1, but it can be 0... if not count: raise ipam_exc.IpAddressAllocationNotFound( subnet_id=self.subnet_manager.neutron_id, ip_address=address) - def _no_pool_changes(self, session, pools): + def _no_pool_changes(self, context, pools): """Check if pool updates in db are required.""" - db_pools = self.subnet_manager.list_pools(session) + db_pools = self.subnet_manager.list_pools(context) iprange_pools = [netaddr.IPRange(pool.first_ip, pool.last_ip) for pool in db_pools] return pools == iprange_pools @@ -238,11 +236,11 @@ class NeutronDbSubnet(ipam_base.Subnet): # Pools have already been validated in the subnet request object which # was sent to the subnet pool driver. Further validation should not be # required. - session = self._context.session - if self._no_pool_changes(session, pools): + if self._no_pool_changes(self._context, pools): return - self.subnet_manager.delete_allocation_pools(session) - self.create_allocation_pools(self.subnet_manager, session, pools, cidr) + self.subnet_manager.delete_allocation_pools(self._context) + self.create_allocation_pools(self.subnet_manager, self._context, pools, + cidr) self._pools = pools def get_details(self): @@ -313,7 +311,7 @@ class NeutronDbPool(subnet_alloc.SubnetAllocator): IPAM-related data has no foreign key relationships to neutron subnet, so removing ipam subnet manually """ - count = ipam_db_api.IpamSubnetManager.delete(self._context.session, + count = ipam_db_api.IpamSubnetManager.delete(self._context, subnet_id) if count < 1: LOG.error(_LE("IPAM subnet referenced to " diff --git a/neutron/tests/unit/ipam/drivers/neutrondb_ipam/test_db_api.py b/neutron/tests/unit/ipam/drivers/neutrondb_ipam/test_db_api.py index 6e9b824536f..bd9f67146d0 100644 --- a/neutron/tests/unit/ipam/drivers/neutrondb_ipam/test_db_api.py +++ b/neutron/tests/unit/ipam/drivers/neutrondb_ipam/test_db_api.py @@ -34,7 +34,7 @@ class TestIpamSubnetManager(testlib_api.SqlTestCase): self.multi_pool = (('1.2.3.2', '1.2.3.12'), ('1.2.3.15', '1.2.3.24')) self.subnet_manager = db_api.IpamSubnetManager(self.ipam_subnet_id, self.neutron_subnet_id) - self.subnet_manager_id = self.subnet_manager.create(self.ctx.session) + self.subnet_manager_id = self.subnet_manager.create(self.ctx) self.ctx.session.flush() def test_create(self): @@ -44,7 +44,7 @@ class TestIpamSubnetManager(testlib_api.SqlTestCase): self.assertEqual(1, len(subnets)) def test_remove(self): - count = db_api.IpamSubnetManager.delete(self.ctx.session, + count = db_api.IpamSubnetManager.delete(self.ctx, self.neutron_subnet_id) self.assertEqual(1, count) subnets = self.ctx.session.query(db_models.IpamSubnet).filter_by( @@ -52,7 +52,7 @@ class TestIpamSubnetManager(testlib_api.SqlTestCase): self.assertEqual(0, len(subnets)) def test_remove_non_existent_subnet(self): - count = db_api.IpamSubnetManager.delete(self.ctx.session, + count = db_api.IpamSubnetManager.delete(self.ctx, 'non-existent') self.assertEqual(0, count) @@ -61,7 +61,7 @@ class TestIpamSubnetManager(testlib_api.SqlTestCase): any(pool == (db_pool.first_ip, db_pool.last_ip) for pool in pools)) def test_create_pool(self): - self.subnet_manager.create_pool(self.ctx.session, + self.subnet_manager.create_pool(self.ctx, self.single_pool[0], self.single_pool[1]) @@ -71,25 +71,25 @@ class TestIpamSubnetManager(testlib_api.SqlTestCase): def test_check_unique_allocation(self): self.assertTrue(self.subnet_manager.check_unique_allocation( - self.ctx.session, self.subnet_ip)) + self.ctx, self.subnet_ip)) def test_check_unique_allocation_negative(self): - self.subnet_manager.create_allocation(self.ctx.session, + self.subnet_manager.create_allocation(self.ctx, self.subnet_ip) self.assertFalse(self.subnet_manager.check_unique_allocation( - self.ctx.session, self.subnet_ip)) + self.ctx, self.subnet_ip)) def test_list_allocations(self): ips = ['1.2.3.4', '1.2.3.6', '1.2.3.7'] for ip in ips: - self.subnet_manager.create_allocation(self.ctx.session, ip) - allocs = self.subnet_manager.list_allocations(self.ctx.session).all() + self.subnet_manager.create_allocation(self.ctx, ip) + allocs = self.subnet_manager.list_allocations(self.ctx).all() self.assertEqual(len(ips), len(allocs)) for allocation in allocs: self.assertIn(allocation.ip_address, ips) def _test_create_allocation(self): - self.subnet_manager.create_allocation(self.ctx.session, + self.subnet_manager.create_allocation(self.ctx, self.subnet_ip) alloc = self.ctx.session.query(db_models.IpamAllocation).filter_by( ipam_subnet_id=self.ipam_subnet_id).all() @@ -102,7 +102,7 @@ class TestIpamSubnetManager(testlib_api.SqlTestCase): def test_delete_allocation(self): allocs = self._test_create_allocation() - self.subnet_manager.delete_allocation(self.ctx.session, + self.subnet_manager.delete_allocation(self.ctx, allocs[0].ip_address) allocs = self.ctx.session.query(db_models.IpamAllocation).filter_by( diff --git a/neutron/tests/unit/ipam/drivers/neutrondb_ipam/test_driver.py b/neutron/tests/unit/ipam/drivers/neutrondb_ipam/test_driver.py index 1b90ae74e97..4183f990dff 100644 --- a/neutron/tests/unit/ipam/drivers/neutrondb_ipam/test_driver.py +++ b/neutron/tests/unit/ipam/drivers/neutrondb_ipam/test_driver.py @@ -275,14 +275,14 @@ class TestNeutronDbIpamSubnet(testlib_api.SqlTestCase, def test__verify_ip_succeeds(self): cidr = '10.0.0.0/24' ipam_subnet = self._create_and_allocate_ipam_subnet(cidr)[0] - ipam_subnet._verify_ip(self.ctx.session, '10.0.0.2') + ipam_subnet._verify_ip(self.ctx, '10.0.0.2') def test__verify_ip_not_in_subnet_fails(self): cidr = '10.0.0.0/24' ipam_subnet = self._create_and_allocate_ipam_subnet(cidr)[0] self.assertRaises(ipam_exc.InvalidIpForSubnet, ipam_subnet._verify_ip, - self.ctx.session, + self.ctx, '192.168.0.2') def test__verify_ip_bcast_and_network_fail(self): @@ -290,11 +290,11 @@ class TestNeutronDbIpamSubnet(testlib_api.SqlTestCase, ipam_subnet = self._create_and_allocate_ipam_subnet(cidr)[0] self.assertRaises(ipam_exc.InvalidIpForSubnet, ipam_subnet._verify_ip, - self.ctx.session, + self.ctx, '10.0.0.255') self.assertRaises(ipam_exc.InvalidIpForSubnet, ipam_subnet._verify_ip, - self.ctx.session, + self.ctx, '10.0.0.0') def _allocate_address(self, cidr, ip_version, address_request): @@ -415,7 +415,7 @@ class TestNeutronDbIpamSubnet(testlib_api.SqlTestCase, last_ip='192.168.10.60')] ipam_subnet.subnet_manager.list_pools = mock.Mock(return_value=pools) - return ipam_subnet._no_pool_changes(self.ctx.session, new_pools) + return ipam_subnet._no_pool_changes(self.ctx, new_pools) def test__no_pool_changes_negative(self): pool_list = [[netaddr.IPRange('192.168.10.2', '192.168.10.254')],