From e12339def3d9182f5ab23869e6bdc946e8e42825 Mon Sep 17 00:00:00 2001 From: Chet Burgess Date: Thu, 24 Jan 2013 03:18:40 +0000 Subject: [PATCH] populate dnsmasq lease db with valid leases At start dnsmasq retrieves its lease db by calling the nova-dhcpbridge script with the init action. Previously we were returning all allocated IPs in the network and calculating the lease exirpation time based upon instances.updated_at or instances.created_at. Now we are only returning entries for IPs that are allocated and leased. Additionally we set the lease expiration time to be i now + CONF.dhcp_lease_time Change-Id: Ie3b4fafd38094dc01ceea592ab5229e581193512 Fixes: bug #1103260 --- nova/db/sqlalchemy/api.py | 6 +++- nova/network/linux_net.py | 14 ++++---- nova/tests/network/test_linux_net.py | 50 ++++++++++++++++++++++++++-- 3 files changed, 60 insertions(+), 10 deletions(-) diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py index dff2e6b814cf..03d5056cb241 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -2245,7 +2245,9 @@ def network_get_associated_fixed_ips(context, network_id, host=None): models.VirtualInterface.address, models.Instance.hostname, models.Instance.updated_at, - models.Instance.created_at).\ + models.Instance.created_at, + models.FixedIp.allocated, + models.FixedIp.leased).\ filter(models.FixedIp.deleted == 0).\ filter(models.FixedIp.network_id == network_id).\ filter(models.FixedIp.allocated == True).\ @@ -2267,6 +2269,8 @@ def network_get_associated_fixed_ips(context, network_id, host=None): cleaned['instance_hostname'] = datum[5] cleaned['instance_updated'] = datum[6] cleaned['instance_created'] = datum[7] + cleaned['allocated'] = datum[8] + cleaned['leased'] = datum[9] data.append(cleaned) return data diff --git a/nova/network/linux_net.py b/nova/network/linux_net.py index a9b44e94a116..c508b8db58d9 100644 --- a/nova/network/linux_net.py +++ b/nova/network/linux_net.py @@ -31,6 +31,7 @@ from nova.openstack.common import fileutils from nova.openstack.common import importutils from nova.openstack.common import lockutils from nova.openstack.common import log as logging +from nova.openstack.common import timeutils from nova import paths from nova import utils @@ -735,7 +736,11 @@ def get_dhcp_leases(context, network_ref): for data in db.network_get_associated_fixed_ips(context, network_ref['id'], host=host): - hosts.append(_host_lease(data)) + # NOTE(cfb): Don't return a lease entry if the IP isn't + # already leased + if data['allocated'] and data['leased']: + hosts.append(_host_lease(data)) + return '\n'.join(hosts) @@ -988,13 +993,8 @@ interface %s def _host_lease(data): """Return a host string for an address in leasefile format.""" - if data['instance_updated']: - timestamp = data['instance_updated'] - else: - timestamp = data['instance_created'] - + timestamp = timeutils.utcnow() seconds_since_epoch = calendar.timegm(timestamp.utctimetuple()) - return '%d %s %s %s *' % (seconds_since_epoch + CONF.dhcp_lease_time, data['vif_address'], data['address'], diff --git a/nova/tests/network/test_linux_net.py b/nova/tests/network/test_linux_net.py index 8a7865b83136..003f5adcb52d 100644 --- a/nova/tests/network/test_linux_net.py +++ b/nova/tests/network/test_linux_net.py @@ -15,6 +15,7 @@ # License for the specific language governing permissions and limitations # under the License. +import calendar import os import mox @@ -25,6 +26,7 @@ from nova.network import driver from nova.network import linux_net from nova.openstack.common import fileutils from nova.openstack.common import log as logging +from nova.openstack.common import timeutils from nova import test from nova import utils @@ -107,6 +109,7 @@ fixed_ips = [{'id': 0, 'address': '192.168.0.100', 'instance_id': 0, 'allocated': True, + 'leased': True, 'virtual_interface_id': 0, 'instance_uuid': '00000000-0000-0000-0000-0000000000000000', 'floating_ips': []}, @@ -115,6 +118,7 @@ fixed_ips = [{'id': 0, 'address': '192.168.1.100', 'instance_id': 0, 'allocated': True, + 'leased': True, 'virtual_interface_id': 1, 'instance_uuid': '00000000-0000-0000-0000-0000000000000000', 'floating_ips': []}, @@ -123,6 +127,7 @@ fixed_ips = [{'id': 0, 'address': '192.168.0.101', 'instance_id': 1, 'allocated': True, + 'leased': True, 'virtual_interface_id': 2, 'instance_uuid': '00000000-0000-0000-0000-0000000000000001', 'floating_ips': []}, @@ -131,6 +136,7 @@ fixed_ips = [{'id': 0, 'address': '192.168.1.101', 'instance_id': 1, 'allocated': True, + 'leased': True, 'virtual_interface_id': 3, 'instance_uuid': '00000000-0000-0000-0000-0000000000000001', 'floating_ips': []}, @@ -139,6 +145,7 @@ fixed_ips = [{'id': 0, 'address': '192.168.0.102', 'instance_id': 0, 'allocated': True, + 'leased': False, 'virtual_interface_id': 4, 'instance_uuid': '00000000-0000-0000-0000-0000000000000000', 'floating_ips': []}, @@ -147,6 +154,7 @@ fixed_ips = [{'id': 0, 'address': '192.168.1.102', 'instance_id': 1, 'allocated': True, + 'leased': False, 'virtual_interface_id': 5, 'instance_uuid': '00000000-0000-0000-0000-0000000000000001', 'floating_ips': []}] @@ -184,7 +192,7 @@ vifs = [{'id': 0, 'instance_uuid': '00000000-0000-0000-0000-0000000000000001'}] -def get_associated(context, network_id, host=None): +def get_associated(context, network_id, host=None, address=None): result = [] for datum in fixed_ips: if (datum['network_id'] == network_id and datum['allocated'] @@ -193,6 +201,8 @@ def get_associated(context, network_id, host=None): instance = instances[datum['instance_uuid']] if host and host != instance['host']: continue + if address and address != datum['address']: + continue cleaned = {} cleaned['address'] = datum['address'] cleaned['instance_uuid'] = datum['instance_uuid'] @@ -203,6 +213,8 @@ def get_associated(context, network_id, host=None): cleaned['instance_hostname'] = instance['hostname'] cleaned['instance_updated'] = instance['updated_at'] cleaned['instance_created'] = instance['created_at'] + cleaned['allocated'] = datum['allocated'] + cleaned['leased'] = datum['leased'] result.append(cleaned) return result @@ -299,7 +311,6 @@ class LinuxNetworkTestCase(test.TestCase): "192.168.1.102,net:NW-5" ) actual_hosts = self.driver.get_dhcp_hosts(self.context, networks[1]) - self.assertEquals(actual_hosts, expected) def test_get_dns_hosts_for_nw00(self): @@ -333,6 +344,41 @@ class LinuxNetworkTestCase(test.TestCase): self.assertEquals(actual_opts, expected_opts) + def test_get_dhcp_leases_for_nw00(self): + timestamp = timeutils.utcnow() + seconds_since_epoch = calendar.timegm(timestamp.utctimetuple()) + + leases = self.driver.get_dhcp_leases(self.context, networks[0]) + leases = leases.split('\n') + for lease in leases: + lease = lease.split(' ') + data = get_associated(self.context, 0, address=lease[2])[0] + self.assertTrue(data['allocated']) + self.assertTrue(data['leased']) + self.assertTrue(lease[0] > seconds_since_epoch) + self.assertTrue(lease[1] == data['vif_address']) + self.assertTrue(lease[2] == data['address']) + self.assertTrue(lease[3] == data['instance_hostname']) + self.assertTrue(lease[4] == '*') + + def test_get_dhcp_leases_for_nw01(self): + self.flags(host='fake_instance01') + timestamp = timeutils.utcnow() + seconds_since_epoch = calendar.timegm(timestamp.utctimetuple()) + + leases = self.driver.get_dhcp_leases(self.context, networks[1]) + leases = leases.split('\n') + for lease in leases: + lease = lease.split(' ') + data = get_associated(self.context, 1, address=lease[2])[0] + self.assertTrue(data['allocated']) + self.assertTrue(data['leased']) + self.assertTrue(lease[0] > seconds_since_epoch) + self.assertTrue(lease[1] == data['vif_address']) + self.assertTrue(lease[2] == data['address']) + self.assertTrue(lease[3] == data['instance_hostname']) + self.assertTrue(lease[4] == '*') + def test_dhcp_opts_not_default_gateway_network(self): expected = "NW-0,3" data = get_associated(self.context, 0)[0]