From d8ff17ecb9466b64dbd064710489ea62843e6636 Mon Sep 17 00:00:00 2001 From: Mandar Vaze Date: Fri, 6 Apr 2012 04:35:27 -0700 Subject: [PATCH] Introduced option to delete deallocated ips immediately. Fixes bug 971504 New flag allows deleting IPs soon on deallocation. This removes the need to run external script manually or via cron. Get old beaviour by setting the falg to True. Added test case for this beahviour. Change-Id: Ife04dd85ed311e806b790f6d1487a963dd3a05af --- etc/melange/melange.conf.sample | 5 +++++ melange/ipam/models.py | 21 +++++++++++------ melange/tests/unit/test_ipam_models.py | 31 +++++++++++++++++++++----- 3 files changed, 45 insertions(+), 12 deletions(-) diff --git a/etc/melange/melange.conf.sample b/etc/melange/melange.conf.sample index 095efe4c..3d194301 100644 --- a/etc/melange/melange.conf.sample +++ b/etc/melange/melange.conf.sample @@ -44,6 +44,11 @@ api_extensions_path = melange/extensions dns1 = 8.8.8.8 dns2 = 8.8.4.4 +#Release Deallocated fixed IPs immediately +#If set to True, deallocated IPs would be deleted only when +#bin/melange-delete-deallocated-ips script is executed +keep_deallocated_ips = False + #Number of days before deallocated IPs are deleted keep_deallocated_ips_for_days = 2 diff --git a/melange/ipam/models.py b/melange/ipam/models.py index 735fb66e..2330a21d 100644 --- a/melange/ipam/models.py +++ b/melange/ipam/models.py @@ -233,6 +233,11 @@ class IpAddressIterator(object): raise StopIteration +def deallocated_by_date(): + days = config.Config.get('keep_deallocated_ips_for_days', 2) + return utils.utcnow() - datetime.timedelta(days=int(days)) + + class IpBlock(ModelBase): PUBLIC_TYPE = "public" @@ -256,7 +261,8 @@ class IpBlock(ModelBase): def delete_all_deallocated_ips(cls): LOG.info("Deleting all deallocated IPs") for block in db.db_api.find_all_blocks_with_deallocated_ips(): - block.delete_deallocated_ips() + block.delete_deallocated_ips( + deallocated_by_func=deallocated_by_date) @property def broadcast(self): @@ -414,20 +420,16 @@ class IpBlock(ModelBase): LOG.debug("Deallocating IP: %s" % ip_address) ip_address.deallocate() - def delete_deallocated_ips(self): + def delete_deallocated_ips(self, deallocated_by_func): self.update(is_full=False) for ip in db.db_api.find_deallocated_ips( - deallocated_by=self._deallocated_by_date(), ip_block_id=self.id): + deallocated_by=deallocated_by_func(), ip_block_id=self.id): LOG.debug("Deleting deallocated IP: %s" % ip) generator = ipv4.plugin().get_generator(self) generator.ip_removed(ip.address) ip.delete() - def _deallocated_by_date(self): - days = config.Config.get('keep_deallocated_ips_for_days', 2) - return utils.utcnow() - datetime.timedelta(days=int(days)) - def subnet(self, cidr, network_id=None, tenant_id=None): network_id = network_id or self.network_id tenant_id = tenant_id or self.tenant_id @@ -1058,6 +1060,11 @@ class Network(ModelBase): ips = IpAddress.find_all_by_network(self.id, interface_id=interface_id) for ip in ips: ip.deallocate() + keep_deallocated_ips = config.Config.get('keep_deallocated_ips', 'False') + if not utils.bool_from_string(keep_deallocated_ips): + LOG.debug("Deleting deallocated ips") + for block in db.db_api.find_all_blocks_with_deallocated_ips(): + block.delete_deallocated_ips(deallocated_by_func=utils.utcnow) def find_allocated_ip(self, **conditions): for ip_block in self.ip_blocks: diff --git a/melange/tests/unit/test_ipam_models.py b/melange/tests/unit/test_ipam_models.py index 168d1939..f65bdf4d 100644 --- a/melange/tests/unit/test_ipam_models.py +++ b/melange/tests/unit/test_ipam_models.py @@ -956,13 +956,30 @@ class TestIpBlock(tests.BaseTest): ip2.deallocate() with unit.StubTime(time=current_time): - models.IpBlock.delete_all_deallocated_ips() + models.IpBlock.delete_all_deallocated_ips( + deallocated_by_func=models.deallocated_by_date) self.assertEqual(models.IpAddress.find_all( ip_block_id=ip_block1.id).all(), []) self.assertEqual(models.IpAddress.find_all( ip_block_id=ip_block2.id).all(), []) + def test_delete_deallocated_ips_immediately(self): + ip_block = factory_models.PrivateIpBlockFactory(cidr="10.0.1.1/24") + current_time = datetime.datetime(2050, 1, 1) + ip1 = _allocate_ip(ip_block) + ip2 = _allocate_ip(ip_block) + ip3 = _allocate_ip(ip_block) + with unit.StubTime(time=current_time): + ip1.deallocate() + ip3.deallocate() + + with unit.StubTime(time=current_time): + ip_block.delete_deallocated_ips(deallocated_by_func=utils.utcnow) + + existing_ips = models.IpAddress.find_all(ip_block_id=ip_block.id).all() + self.assertModelsEqual(existing_ips, [ip2]) + def test_delete_deallocated_ips_after_default_of_two_days(self): ip_block = factory_models.PrivateIpBlockFactory(cidr="10.0.1.1/24") current_time = datetime.datetime(2050, 1, 1) @@ -975,7 +992,8 @@ class TestIpBlock(tests.BaseTest): ip3.deallocate() with unit.StubTime(time=current_time): - ip_block.delete_deallocated_ips() + ip_block.delete_deallocated_ips( + deallocated_by_func=models.deallocated_by_date) existing_ips = models.IpAddress.find_all(ip_block_id=ip_block.id).all() self.assertModelsEqual(existing_ips, [ip2]) @@ -999,7 +1017,8 @@ class TestIpBlock(tests.BaseTest): with unit.StubConfig(keep_deallocated_ips_for_days=1): with unit.StubTime(time=current_time): - ip_block.delete_deallocated_ips() + ip_block.delete_deallocated_ips( + deallocated_by_func=models.deallocated_by_date) self.assertEqual(ip_block.addresses(), [ip2]) @@ -1014,7 +1033,8 @@ class TestIpBlock(tests.BaseTest): interface=interface) self.assertTrue(ip_block.is_full) - models.IpBlock.delete_all_deallocated_ips() + models.IpBlock.delete_all_deallocated_ips( + deallocated_by_func=models.deallocated_by_date) self.assertFalse(models.IpBlock.find(ip_block.id).is_full) @@ -2461,7 +2481,8 @@ class TestAllowedIp(tests.BaseTest): with unit.StubTime(time=two_days_before): block.deallocate_ip(ip.address) with unit.StubTime(time=current_time): - block.delete_deallocated_ips() + block.delete_deallocated_ips( + deallocated_by_func=models.deallocated_by_date) reloaded_ip = models.IpAddress.find(ip.id) self.assertFalse(reloaded_ip.marked_for_deallocation)