From 8eb531becb7e67169fddb8f7d1547589ab733dc7 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Tue, 17 Aug 2010 20:33:37 -0700 Subject: almost there --- bin/nova-dhcpbridge | 17 +++++----- nova/models.py | 9 +++--- nova/network/linux_net.py | 28 ++++++++++------- nova/network/service.py | 3 +- nova/tests/network_unittest.py | 71 ++++++++++++++++++++---------------------- 5 files changed, 65 insertions(+), 63 deletions(-) diff --git a/bin/nova-dhcpbridge b/bin/nova-dhcpbridge index f70a4482c..593811598 100755 --- a/bin/nova-dhcpbridge +++ b/bin/nova-dhcpbridge @@ -34,7 +34,6 @@ from nova import flags from nova import rpc from nova import utils from nova.network import linux_net -from nova.network import model from nova.network import service FLAGS = flags.FLAGS @@ -43,11 +42,12 @@ FLAGS = flags.FLAGS def add_lease(_mac, ip, _hostname, _interface): """Set the IP that was assigned by the DHCP server.""" if FLAGS.fake_rabbit: + logging.debug("leasing_ip") service.VlanNetworkService().lease_ip(ip) else: rpc.cast("%s.%s" % (FLAGS.network_topic, FLAGS.node_name), {"method": "lease_ip", - "args": {"fixed_ip": ip}}) + "args": {"fixed_ip_str": ip}}) def old_lease(_mac, _ip, _hostname, _interface): @@ -58,20 +58,18 @@ def old_lease(_mac, _ip, _hostname, _interface): def del_lease(_mac, ip, _hostname, _interface): """Called when a lease expires.""" if FLAGS.fake_rabbit: + logging.debug("releasing_ip") service.VlanNetworkService().release_ip(ip) else: rpc.cast("%s.%s" % (FLAGS.network_topic, FLAGS.node_name), {"method": "release_ip", - "args": {"fixed_ip": ip}}) + "args": {"fixed_ip_str": ip}}) def init_leases(interface): """Get the list of hosts for an interface.""" - net = model.get_network_by_interface(interface) - res = "" - for address in net.assigned_objs: - res += "%s\n" % linux_net.host_dhcp(address) - return res + network = service.get_network_by_interface(interface) + return linux_net.get_dhcp_hosts(network) def main(): @@ -80,6 +78,9 @@ def main(): utils.default_flagfile(flagfile) argv = FLAGS(sys.argv) interface = os.environ.get('DNSMASQ_INTERFACE', 'br0') + LOG_FILENAME = 'example.log' + logging.basicConfig(filename=LOG_FILENAME,level=logging.DEBUG) + logging.debug("this is a test") if int(os.environ.get('TESTING', '0')): FLAGS.fake_rabbit = True FLAGS.redis_db = 8 diff --git a/nova/models.py b/nova/models.py index 5fc4ba1cf..110a4fc80 100644 --- a/nova/models.py +++ b/nova/models.py @@ -214,7 +214,6 @@ class Volume(Base, NovaBase): attach_time = Column(String) # FIXME datetime status = Column(String) # FIXME enum? attach_status = Column(String) # FIXME enum - delete_on_termination = Column(Boolean) class Network(Base, NovaBase): @@ -222,7 +221,7 @@ class Network(Base, NovaBase): id = Column(Integer, primary_key=True) kind = Column(String) - injected = Column(Boolean) + injected = Column(Boolean, default=False) network_str = Column(String) netmask = Column(String) bridge = Column(String) @@ -259,9 +258,9 @@ class FixedIp(Base, NovaBase): instance_id = Column(Integer, ForeignKey('instances.id'), nullable=True) instance = relationship(Instance, backref=backref('fixed_ip', uselist=False)) - allocated = Column(Boolean) - leased = Column(Boolean) - reserved = Column(Boolean) + allocated = Column(Boolean, default=False) + leased = Column(Boolean, default=False) + reserved = Column(Boolean, default=False) @classmethod def find_by_ip_str(cls, ip_str): diff --git a/nova/network/linux_net.py b/nova/network/linux_net.py index 48d71f11e..6fa3bae73 100644 --- a/nova/network/linux_net.py +++ b/nova/network/linux_net.py @@ -122,11 +122,15 @@ def ensure_bridge(bridge, interface, network=None): _execute("sudo ifconfig %s up" % bridge) -def host_dhcp(fixed_ip): - """Return a host string for a fixed ip""" - return "%s,%s.novalocal,%s" % (fixed_ip.instance.mac_address, - fixed_ip.instance.host_name, - fixed_ip.ip_str) +def get_dhcp_hosts(network): + hosts = [] + # FIXME abstract this + session = models.NovaBase.get_session() + query = session.query(models.FixedIp).filter_by(allocated=True) + fixed_ips = query.filter_by(network_id=network.id) + for fixed_ip in network.fixed_ips: + hosts.append(_host_dhcp(fixed_ip)) + return '\n'.join(hosts) # TODO(ja): if the system has restarted or pid numbers have wrapped @@ -140,13 +144,8 @@ def update_dhcp(network): if a dnsmasq instance is already running then send a HUP signal causing it to reload, otherwise spawn a new instance """ - # FIXME abstract this - session = models.NovaBase.get_session() - query = session.query(models.FixedIp).filter_by(allocated=True) - fixed_ips = query.filter_by(network_id=network.id) with open(_dhcp_file(network['vlan'], 'conf'), 'w') as f: - for fixed_ip in fixed_ips: - f.write("%s\n" % host_dhcp(fixed_ip)) + f.write(get_dhcp_hosts(network)) pid = _dnsmasq_pid_for(network) @@ -166,6 +165,13 @@ def update_dhcp(network): _execute(_dnsmasq_cmd(network), addl_env=env) +def _host_dhcp(fixed_ip): + """Return a host string for a fixed ip""" + return "%s,%s.novalocal,%s" % (fixed_ip.instance.mac_address, + fixed_ip.instance.host_name, + fixed_ip.ip_str) + + def _execute(cmd, addl_env=None): """Wrapper around utils._execute for fake_network""" if FLAGS.fake_network: diff --git a/nova/network/service.py b/nova/network/service.py index 115a7fa98..8d676111a 100644 --- a/nova/network/service.py +++ b/nova/network/service.py @@ -121,11 +121,10 @@ class BaseNetworkService(service.Service): def allocate_fixed_ip(self, project_id, instance_id, *args, **kwargs): """Gets fixed ip from the pool""" - print "allocating", project_id, instance_id network = get_network_for_project(project_id) session = models.NovaBase.get_session() query = session.query(models.FixedIp).filter_by(network_id=network.id) - query = query.filter_by(allocated=False).filter_by(reserved=False) + query = query.filter_by(reserved=False).filter_by(allocated=False) query = query.filter_by(leased=False) while(True): fixed_ip = query.first() diff --git a/nova/tests/network_unittest.py b/nova/tests/network_unittest.py index 8b7730d87..657dd89d2 100644 --- a/nova/tests/network_unittest.py +++ b/nova/tests/network_unittest.py @@ -43,7 +43,8 @@ class NetworkTestCase(test.TrialTestCase): fake_storage=True, fake_network=True, auth_driver='nova.auth.ldapdriver.FakeLdapDriver', - network_size=32) + network_size=32, + num_networks=10) logging.getLogger().setLevel(logging.DEBUG) self.manager = manager.AuthManager() self.user = self.manager.create_user('netuser', 'netuser', 'netuser') @@ -79,22 +80,16 @@ class NetworkTestCase(test.TrialTestCase): """Makes sure that we can allocate and deallocate a fixed ip""" address = self.service.allocate_fixed_ip(self.projects[0].id, self.instance.id) - net = service.get_project_network(self.projects[0].id) - self.assertEqual(True, is_in_project(address, self.projects[0].id)) - issue_ip(self.instance.mac_address, - address, - self.instance.hostname, - net.bridge) + net = service.get_network_for_project(self.projects[0].id) + self.assertEqual(True, is_allocated_in_project(address, self.projects[0].id)) + issue_ip(address, net.bridge) self.service.deallocate_fixed_ip(address) # Doesn't go away until it's dhcp released - self.assertEqual(True, is_in_project(address, self.projects[0].id)) + self.assertEqual(True, is_allocated_in_project(address, self.projects[0].id)) - release_ip(self.instance.mac_address, - address, - self.instance.hostname, - net.bridge) - self.assertEqual(False, is_in_project(address, self.projects[0].id)) + release_ip(address, net.bridge) + self.assertEqual(False, is_allocated_in_project(address, self.projects[0].id)) def test_side_effects(self): """Ensures allocating and releasing has no side effects""" @@ -108,13 +103,13 @@ class NetworkTestCase(test.TrialTestCase): secondmac = result['mac_address'] secondaddress = result['private_dns_name'] - net = service.get_project_network(self.projects[0].id) - secondnet = service.get_project_network(self.projects[1].id) + net = service.get_network_for_project(self.projects[0].id) + secondnet = service.get_network_for_project(self.projects[1].id) - self.assertEqual(True, is_in_project(address, self.projects[0].id)) - self.assertEqual(True, is_in_project(secondaddress, + self.assertEqual(True, is_allocated_in_project(address, self.projects[0].id)) + self.assertEqual(True, is_allocated_in_project(secondaddress, self.projects[1].id)) - self.assertEqual(False, is_in_project(address, self.projects[1].id)) + self.assertEqual(False, is_allocated_in_project(address, self.projects[1].id)) # Addresses are allocated before they're issued issue_ip(mac, address, hostname, net.bridge_name) @@ -122,15 +117,15 @@ class NetworkTestCase(test.TrialTestCase): self.service.deallocate_fixed_ip(address) release_ip(mac, address, hostname, net.bridge_name) - self.assertEqual(False, is_in_project(address, self.projects[0].id)) + self.assertEqual(False, is_allocated_in_project(address, self.projects[0].id)) # First address release shouldn't affect the second - self.assertEqual(True, is_in_project(secondaddress, + self.assertEqual(True, is_allocated_in_project(secondaddress, self.projects[1].id)) self.service.deallocate_fixed_ip(secondaddress) release_ip(secondmac, secondaddress, hostname, secondnet.bridge_name) - self.assertEqual(False, is_in_project(secondaddress, + self.assertEqual(False, is_allocated_in_project(secondaddress, self.projects[1].id)) def test_subnet_edge(self): @@ -153,15 +148,15 @@ class NetworkTestCase(test.TrialTestCase): self.user, project_id) mac3 = result['mac_address'] address3 = result['private_dns_name'] - net = service.get_project_network(project_id) + net = service.get_network_for_project(project_id) issue_ip(mac, address, hostname, net.bridge_name) issue_ip(mac2, address2, hostname, net.bridge_name) issue_ip(mac3, address3, hostname, net.bridge_name) - self.assertEqual(False, is_in_project(address, + self.assertEqual(False, is_allocated_in_project(address, self.projects[0].id)) - self.assertEqual(False, is_in_project(address2, + self.assertEqual(False, is_allocated_in_project(address2, self.projects[0].id)) - self.assertEqual(False, is_in_project(address3, + self.assertEqual(False, is_allocated_in_project(address3, self.projects[0].id)) self.service.deallocate_fixed_ip(address) self.service.deallocate_fixed_ip(address2) @@ -169,7 +164,7 @@ class NetworkTestCase(test.TrialTestCase): release_ip(mac, address, hostname, net.bridge_name) release_ip(mac2, address2, hostname, net.bridge_name) release_ip(mac3, address3, hostname, net.bridge_name) - net = service.get_project_network(self.projects[0].id) + net = service.get_network_for_project(self.projects[0].id) self.service.deallocate_fixed_ip(firstaddress) release_ip(mac, firstaddress, hostname, net.bridge_name) @@ -196,7 +191,7 @@ class NetworkTestCase(test.TrialTestCase): address = result['private_dns_name'] hostname = "reuse-host" - net = service.get_project_network(self.projects[0].id) + net = service.get_network_for_project(self.projects[0].id) issue_ip(mac, address, hostname, net.bridge_name) self.service.deallocate_fixed_ip(address) @@ -222,7 +217,7 @@ class NetworkTestCase(test.TrialTestCase): There are ips reserved at the bottom and top of the range. services (network, gateway, CloudPipe, broadcast) """ - net = service.get_project_network(self.projects[0].id) + net = service.get_network_for_project(self.projects[0].id) num_preallocated_ips = len(net.assigned) net_size = flags.FLAGS.network_size num_available_ips = net_size - (net.num_bottom_reserved_ips + @@ -233,7 +228,7 @@ class NetworkTestCase(test.TrialTestCase): def test_too_many_addresses(self): """Test for a NoMoreAddresses exception when all fixed ips are used. """ - net = service.get_project_network(self.projects[0].id) + net = service.get_network_for_project(self.projects[0].id) hostname = "toomany-hosts" macs = {} @@ -259,9 +254,13 @@ class NetworkTestCase(test.TrialTestCase): self.assertEqual(len(list(net.available)), num_available_ips) -def is_in_project(address, project_id): +def is_allocated_in_project(address, project_id): """Returns true if address is in specified project""" - return models.FixedIp.find_by_ip_str(address) == service.get_project_network(project_id) + fixed_ip = models.FixedIp.find_by_ip_str(address) + project_net = service.get_network_for_project(project_id) + print fixed_ip.instance + # instance exists until release + return fixed_ip.instance and project_net == fixed_ip.network def binpath(script): @@ -269,10 +268,9 @@ def binpath(script): return os.path.abspath(os.path.join(__file__, "../../../bin", script)) -def issue_ip(mac, private_ip, hostname, interface): +def issue_ip(private_ip, interface): """Run add command on dhcpbridge""" - cmd = "%s add %s %s %s" % (binpath('nova-dhcpbridge'), - mac, private_ip, hostname) + cmd = "%s add %s fake fake" % (binpath('nova-dhcpbridge'), private_ip) env = {'DNSMASQ_INTERFACE': interface, 'TESTING': '1', 'FLAGFILE': FLAGS.dhcpbridge_flagfile} @@ -280,10 +278,9 @@ def issue_ip(mac, private_ip, hostname, interface): logging.debug("ISSUE_IP: %s, %s ", out, err) -def release_ip(mac, private_ip, hostname, interface): +def release_ip(private_ip, interface): """Run del command on dhcpbridge""" - cmd = "%s del %s %s %s" % (binpath('nova-dhcpbridge'), - mac, private_ip, hostname) + cmd = "%s del %s fake fake" % (binpath('nova-dhcpbridge'), private_ip) env = {'DNSMASQ_INTERFACE': interface, 'TESTING': '1', 'FLAGFILE': FLAGS.dhcpbridge_flagfile} -- cgit