diff --git a/pkgs/applications/virtualization/nova/default.nix b/pkgs/applications/virtualization/nova/default.nix index a4813b55e663..e28f9012fc69 100644 --- a/pkgs/applications/virtualization/nova/default.nix +++ b/pkgs/applications/virtualization/nova/default.nix @@ -12,6 +12,9 @@ stdenv.mkDerivation rec { sha256 = "0xd7cxn60vzhkvjwnj0i6jfcxaggwwyw2pnhl4qnb759q9hvk1b9"; }; + patches = + [ ./fix-dhcpbridge-output.patch ]; + pythonPath = with pythonPackages; [ setuptools eventlet greenlet gflags netaddr sqlalchemy carrot routes paste_deploy m2crypto ipy boto_1_9 twisted sqlalchemy_migrate diff --git a/pkgs/applications/virtualization/nova/fix-dhcpbridge-output.patch b/pkgs/applications/virtualization/nova/fix-dhcpbridge-output.patch new file mode 100644 index 000000000000..cef1473e5743 --- /dev/null +++ b/pkgs/applications/virtualization/nova/fix-dhcpbridge-output.patch @@ -0,0 +1,124 @@ +Prevent dnsmasq from segfaulting. + +https://code.launchpad.net/~soren/nova/dnsmasq-leasesfile-init/+merge/52421 + +diff -ru nova-2011.1.1-orig//bin/nova-dhcpbridge nova-2011.1.1//bin/nova-dhcpbridge +--- nova-2011.1.1-orig//bin/nova-dhcpbridge 2011-02-24 19:51:54.000000000 +0100 ++++ nova-2011.1.1//bin/nova-dhcpbridge 2011-04-01 17:49:53.848659259 +0200 +@@ -94,7 +94,7 @@ + """Get the list of hosts for an interface.""" + ctxt = context.get_admin_context() + network_ref = db.network_get_by_bridge(ctxt, interface) +- return linux_net.get_dhcp_hosts(ctxt, network_ref['id']) ++ return linux_net.get_dhcp_leases(ctxt, network_ref['id']) + + + def main(): +diff -ru nova-2011.1.1-orig//nova/network/linux_net.py nova-2011.1.1//nova/network/linux_net.py +--- nova-2011.1.1-orig//nova/network/linux_net.py 2011-02-24 19:51:54.000000000 +0100 ++++ nova-2011.1.1//nova/network/linux_net.py 2011-04-01 17:50:37.315585644 +0200 +@@ -18,6 +18,7 @@ + """ + + import os ++import calendar + + from nova import db + from nova import flags +@@ -48,6 +49,8 @@ + 'location of nova-dhcpbridge') + flags.DEFINE_string('routing_source_ip', '$my_ip', + 'Public IP of network host') ++flags.DEFINE_integer('dhcp_lease_time', 120, ++ 'Lifetime of a DHCP lease') + flags.DEFINE_bool('use_nova_chains', False, + 'use the nova_ routing chains instead of default') + +@@ -218,8 +221,17 @@ + _confirm_rule("FORWARD", "-j nova-local") + + ++def get_dhcp_leases(context, network_id): ++ """Return a network's hosts config in dnsmasq leasefile format""" ++ hosts = [] ++ for fixed_ip_ref in db.network_get_associated_fixed_ips(context, ++ network_id): ++ hosts.append(_host_lease(fixed_ip_ref)) ++ return '\n'.join(hosts) ++ ++ + def get_dhcp_hosts(context, network_id): +- """Get a string containing a network's hosts config in dnsmasq format""" ++ """Get a string containing a network's hosts config in dhcp-host format""" + hosts = [] + for fixed_ip_ref in db.network_get_associated_fixed_ips(context, + network_id): +@@ -310,8 +322,24 @@ + utils.get_my_linklocal(network_ref['bridge'])}) + + ++def _host_lease(fixed_ip_ref): ++ """Return a host string for an address in leasefile format""" ++ instance_ref = fixed_ip_ref['instance'] ++ if instance_ref['updated_at']: ++ timestamp = instance_ref['updated_at'] ++ else: ++ timestamp = instance_ref['created_at'] ++ ++ seconds_since_epoch = calendar.timegm(timestamp.utctimetuple()) ++ ++ return "%d %s %s %s *" % (seconds_since_epoch + FLAGS.dhcp_lease_time, ++ instance_ref['mac_address'], ++ fixed_ip_ref['address'], ++ instance_ref['hostname'] or '*') ++ ++ + def _host_dhcp(fixed_ip_ref): +- """Return a host string for an address""" ++ """Return a host string for an address in dhcp-host format""" + instance_ref = fixed_ip_ref['instance'] + return "%s,%s.novalocal,%s" % (instance_ref['mac_address'], + instance_ref['hostname'], +diff -ru nova-2011.1.1-orig//nova/tests/test_network.py nova-2011.1.1//nova/tests/test_network.py +--- nova-2011.1.1-orig//nova/tests/test_network.py 2011-02-24 19:51:54.000000000 +0100 ++++ nova-2011.1.1//nova/tests/test_network.py 2011-04-01 17:49:53.849659365 +0200 +@@ -20,6 +20,7 @@ + """ + import IPy + import os ++import time + + from nova import context + from nova import db +@@ -320,6 +321,31 @@ + network['id']) + self.assertEqual(ip_count, num_available_ips) + ++ def test_dhcp_lease_output(self): ++ admin_ctxt = context.get_admin_context() ++ address = self._create_address(0, self.instance_id) ++ lease_ip(address) ++ network_ref = db.network_get_by_instance(admin_ctxt, self.instance_id) ++ leases = linux_net.get_dhcp_leases(context.get_admin_context(), ++ network_ref['id']) ++ for line in leases.split('\n'): ++ seconds, mac, ip, hostname, client_id = line.split(' ') ++ self.assertTrue(int(seconds) > time.time(), 'Lease expires in ' ++ 'the past') ++ octets = mac.split(':') ++ self.assertEqual(len(octets), 6, "Wrong number of octets " ++ "in %s" % (max,)) ++ for octet in octets: ++ self.assertEqual(len(octet), 2, "Oddly sized octet: %s" ++ % (octet,)) ++ # This will throw an exception if the octet is invalid ++ int(octet, 16) ++ ++ # And this will raise an exception in case of an invalid IP ++ IPy.IP(ip) ++ ++ release_ip(address) ++ + + def is_allocated_in_project(address, project_id): + """Returns true if address is in specified project"""