From 00971feed32d22ae9bc63aea716ecf4e972aee32 Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Wed, 30 Jun 2010 16:46:26 +0200 Subject: Replace spaces in x509 cert subject with underscores. It ends up getting split(' ')'ed and passed to subprocess.Popen, so it needs to not have spaces in it, otherwise openssl gets very upset. --- nova/auth/users.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova') diff --git a/nova/auth/users.py b/nova/auth/users.py index 6997596aa..12c73ca27 100644 --- a/nova/auth/users.py +++ b/nova/auth/users.py @@ -481,7 +481,7 @@ class UserManager(object): def __cert_subject(self, uid): # FIXME(ja) - this should be pulled from a global configuration - return "/C=US/ST=California/L=Mountain View/O=Anso Labs/OU=Nova Dev/CN=%s-%s" % (uid, str(datetime.datetime.utcnow().isoformat())) + return "/C=US/ST=California/L=Mountain_View/O=Anso_Labs/OU=Nova_Dev/CN=%s-%s" % (uid, str(datetime.datetime.utcnow().isoformat())) class LDAPWrapper(object): -- cgit From 7ce77bfffca575e0136807779d98140280c7fa90 Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Wed, 30 Jun 2010 16:46:47 +0200 Subject: Add _s instance attribute to Instance class. It's referenced in a bunch of places, but is never set. This is unlikely to be the right fix (why have two attributes pointing to the same object?), but it seems to make ends meet. --- nova/compute/node.py | 1 + 1 file changed, 1 insertion(+) (limited to 'nova') diff --git a/nova/compute/node.py b/nova/compute/node.py index c217056f5..b39a0fe9c 100644 --- a/nova/compute/node.py +++ b/nova/compute/node.py @@ -269,6 +269,7 @@ class Instance(object): data['project_id'] = data['owner_id'] self.datamodel = data + self._s = data size = data.get('instance_type', FLAGS.default_instance_type) if size not in INSTANCE_TYPES: raise exception.Error('invalid instance type: %s' % size) -- cgit From 3b916f690ce332ac15e1ec50d5e511ec6a9895ab Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Wed, 30 Jun 2010 16:47:12 +0200 Subject: Make sure get_assigned_vlans and BaseNetwork.hosts always return a dict, even if the key is currently empty in the KVS. --- nova/compute/network.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'nova') diff --git a/nova/compute/network.py b/nova/compute/network.py index 911d0344a..94fa6c47a 100644 --- a/nova/compute/network.py +++ b/nova/compute/network.py @@ -133,7 +133,7 @@ class BaseNetwork(datastore.RedisModel): @property def hosts(self): - return datastore.Redis.instance().hgetall(self._hosts_key) + return datastore.Redis.instance().hgetall(self._hosts_key) or {} def _add_host(self, _user_id, _project_id, host, target): datastore.Redis.instance().hset(self._hosts_key, host, target) @@ -392,7 +392,7 @@ def _rem_vlan(project_id): def get_assigned_vlans(): """ Returns a dictionary, with keys of project_id and values of vlan_id """ - return datastore.Redis.instance().hgetall(VLANS_KEY) + return datastore.Redis.instance().hgetall(VLANS_KEY) or {} def get_vlan_for_project(project_id): """ -- cgit From f8a19693b5d4172ce3207c63acf0209ed8b3d636 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Fri, 2 Jul 2010 10:38:15 -0500 Subject: clean a few merge errors from network --- nova/compute/network.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'nova') diff --git a/nova/compute/network.py b/nova/compute/network.py index 911d0344a..2de8bea4d 100644 --- a/nova/compute/network.py +++ b/nova/compute/network.py @@ -98,27 +98,23 @@ class BaseNetwork(datastore.RedisModel): @property def network(self): return IPy.IP(self['network_str']) + @property def netmask(self): return self.network.netmask() + @property def gateway(self): return self.network[1] + @property def broadcast(self): return self.network.broadcast() - @property - def gateway(self): - return self.network[1] + @property def bridge_name(self): return "br%s" % (self["vlan"]) - def range(self): - # the .2 address is always CloudPipe - for idx in range(3, len(self.network)-2): - yield self.network[idx] - @property def user(self): return users.UserManager.instance().get_user(self['user_id']) -- cgit From 95e7571a597abdafc638747e2d28c725df96bb17 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Fri, 2 Jul 2010 10:39:04 -0500 Subject: Simple Network avoids vlans --- nova/compute/network.py | 21 +++++++++++++++++++++ nova/compute/node.py | 9 +++++---- nova/endpoint/cloud.py | 24 ++++++++++++++++++------ 3 files changed, 44 insertions(+), 10 deletions(-) (limited to 'nova') diff --git a/nova/compute/network.py b/nova/compute/network.py index 2de8bea4d..ce156967e 100644 --- a/nova/compute/network.py +++ b/nova/compute/network.py @@ -58,6 +58,13 @@ flags.DEFINE_integer('cnt_vpn_clients', 5, flags.DEFINE_integer('cloudpipe_start_port', 12000, 'Starting port for mapped CloudPipe external ports') +flags.DEFINE_boolean('simple_network', False, + 'Use simple networking instead of vlans') +flags.DEFINE_string('simple_network_bridge', 'br100', + 'Bridge for instances') +flags.DEFINE_list('simple_network_ips', ['192.168.1.1'], + 'Available ips for network') + logging.getLogger().setLevel(logging.DEBUG) # CLEANUP: @@ -418,6 +425,20 @@ def get_network_by_address(address): return net raise exception.AddressNotAllocated() +def allocate_simple_ip(): + redis = datastore.Redis.instance() + if not redis.exists('ips') and not len(redis.keys('instances:*')): + for address in FLAGS.simple_network_ips: + redis.sadd('ips', address) + address = redis.spop('ips') + if not address: + raise exception.NoMoreAddresses() + return address + +def deallocate_simple_ip(address): + datastore.Redis.instance().sadd('ips', address) + + def allocate_vpn_ip(user_id, project_id, mac): return get_project_network(project_id).allocate_vpn_ip(mac) diff --git a/nova/compute/node.py b/nova/compute/node.py index 65eb4bf3e..1b4714d67 100644 --- a/nova/compute/node.py +++ b/nova/compute/node.py @@ -57,7 +57,7 @@ from nova.objectstore import image # for image_path flag FLAGS = flags.FLAGS flags.DEFINE_string('libvirt_xml_template', utils.abspath('compute/libvirt.xml.template'), - 'Network XML Template') + 'Libvirt XML Template') flags.DEFINE_bool('use_s3', True, 'whether to get images from s3 or use local copy') flags.DEFINE_string('instances_path', utils.abspath('../instances'), @@ -151,9 +151,10 @@ class Node(object, service.Service): """ launch a new instance with specified options """ logging.debug("Starting instance %s..." % (instance_id)) inst = self.instdir.get(instance_id) - # TODO: Get the real security group of launch in here - security_group = "default" - net = network.BridgedNetwork.get_network_for_project(inst['user_id'], + if not FLAGS.simple_network: + # TODO: Get the real security group of launch in here + security_group = "default" + net = network.BridgedNetwork.get_network_for_project(inst['user_id'], inst['project_id'], security_group).express() inst['node_name'] = FLAGS.node_name diff --git a/nova/endpoint/cloud.py b/nova/endpoint/cloud.py index 931c6c6e1..50c087f2d 100644 --- a/nova/endpoint/cloud.py +++ b/nova/endpoint/cloud.py @@ -516,7 +516,12 @@ class CloudController(object): key_data = key_pair.public_key # TODO: Get the real security group of launch in here security_group = "default" - bridge_name = network.BridgedNetwork.get_network_for_project(context.user.id, context.project.id, security_group)['bridge_name'] + if FLAGS.simple_network: + bridge_name = FLAGS.simple_network_bridge + else: + net = network.BridgedNetwork.get_network_for_project( + context.user.id, context.project.id, security_group) + bridge_name = net['bridge_name'] for num in range(int(kwargs['max_count'])): inst = self.instdir.new() # TODO(ja): add ari, aki @@ -532,12 +537,19 @@ class CloudController(object): inst['mac_address'] = utils.generate_mac() inst['ami_launch_index'] = num inst['bridge_name'] = bridge_name - if inst['image_id'] == FLAGS.vpn_image_id: - address = network.allocate_vpn_ip( - inst['user_id'], inst['project_id'], mac=inst['mac_address']) + if FLAGS.simple_network: + network.allocate_simple_ip(mac=inst['mac_address']) else: - address = network.allocate_ip( - inst['user_id'], inst['project_id'], mac=inst['mac_address']) + if inst['image_id'] == FLAGS.vpn_image_id: + address = network.allocate_vpn_ip( + inst['user_id'], + inst['project_id'], + mac=inst['mac_address']) + else: + address = network.allocate_ip( + inst['user_id'], + inst['project_id'], + mac=inst['mac_address']) inst['private_dns_name'] = str(address) # TODO: allocate expresses on the router node inst.save() -- cgit From 04b7b42bde70c53e251f795a1d71cd7cd341b5dc Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Fri, 2 Jul 2010 10:39:04 -0500 Subject: Simple network injection --- nova/compute/disk.py | 23 +++++++++++++++++------ nova/compute/network.py | 19 ++++++++++++++++--- nova/compute/node.py | 23 +++++++++++++++++------ 3 files changed, 50 insertions(+), 15 deletions(-) (limited to 'nova') diff --git a/nova/compute/disk.py b/nova/compute/disk.py index bd6a010ee..3f528de61 100644 --- a/nova/compute/disk.py +++ b/nova/compute/disk.py @@ -87,12 +87,14 @@ def partition(infile, outfile, local_bytes=0, local_type='ext2', execute=None): % (infile, outfile, sector_size, primary_first)) @defer.inlineCallbacks -def inject_key(key, image, partition=None, execute=None): - """Injects a ssh key into a disk image. - It adds the specified key to /root/.ssh/authorized_keys +def inject_data(image, key=None, net=None, partition=None, execute=None): + """Injects a ssh key and optionally net data into a disk image. + it will mount the image as a fully partitioned disk and attempt to inject into the specified partition number. + If partition is not specified it mounts the image as a single partition. + """ out, err = yield execute('sudo losetup -f --show %s' % image) if err: @@ -119,8 +121,11 @@ def inject_key(key, image, partition=None, execute=None): raise exception.Error('Failed to mount filesystem: %s' % err) try: - # inject key file - yield _inject_into_fs(key, tmpdir, execute=execute) + if key: + # inject key file + yield _inject_key_into_fs(key, tmpdir, execute=execute) + if net: + yield _inject_net_into_fs(net, tmpdir) finally: # unmount device yield execute('sudo umount %s' % mapped_device) @@ -136,7 +141,7 @@ def inject_key(key, image, partition=None, execute=None): yield execute('sudo losetup -d %s' % device) @defer.inlineCallbacks -def _inject_into_fs(key, fs, execute=None): +def _inject_key_into_fs(key, fs, execute=None): sshdir = os.path.join(os.path.join(fs, 'root'), '.ssh') yield execute('sudo mkdir -p %s' % sshdir) # existing dir doesn't matter yield execute('sudo chown root %s' % sshdir) @@ -144,3 +149,9 @@ def _inject_into_fs(key, fs, execute=None): keyfile = os.path.join(sshdir, 'authorized_keys') yield execute('sudo tee -a %s' % keyfile, '\n' + key.strip() + '\n') +@defer.inlineCallbacks +def _inject_net_into_fs(net, fs, execute=None): + netfile = os.path.join(os.path.join(os.path.join( + fs, 'etc'), 'network'), 'interfaces') + yield execute('sudo tee %s' % netfile, net) + diff --git a/nova/compute/network.py b/nova/compute/network.py index ce156967e..5223e59da 100644 --- a/nova/compute/network.py +++ b/nova/compute/network.py @@ -61,9 +61,22 @@ flags.DEFINE_integer('cloudpipe_start_port', 12000, flags.DEFINE_boolean('simple_network', False, 'Use simple networking instead of vlans') flags.DEFINE_string('simple_network_bridge', 'br100', - 'Bridge for instances') -flags.DEFINE_list('simple_network_ips', ['192.168.1.1'], - 'Available ips for network') + 'Bridge for simple network instances') +flags.DEFINE_list('simple_network_ips', ['192.168.0.2'], + 'Available ips for simple network') +flags.DEFINE_string('simple_network_template', + utils.abspath('compute/interfaces.template'), + 'Template file for simple network') +flags.DEFINE_string('simple_network_netmask', '255.255.255.0', + 'Netmask for simple network') +flags.DEFINE_string('simple_network_network', '192.168.0.0', + 'Network for simple network') +flags.DEFINE_string('simple_network_gateway', '192.168.0.1', + 'Broadcast for simple network') +flags.DEFINE_string('simple_network_broadcast', '192.168.0.255', + 'Broadcast for simple network') +flags.DEFINE_string('simple_network_dns', '8.8.8.8', + 'Dns for simple network') logging.getLogger().setLevel(logging.DEBUG) diff --git a/nova/compute/node.py b/nova/compute/node.py index 1b4714d67..e1503683e 100644 --- a/nova/compute/node.py +++ b/nova/compute/node.py @@ -483,12 +483,23 @@ class Instance(object): if not os.path.exists(basepath('ramdisk')): yield _fetch_file(data['ramdisk_id'], basepath('ramdisk')) - execute = lambda cmd, input=None: self._pool.simpleExecute(cmd=cmd, input=input, error_ok=1) - - if data['key_data']: - logging.info('Injecting key data into image %s', data['image_id']) - yield disk.inject_key( - data['key_data'], basepath('disk-raw'), execute=execute) + execute = lambda cmd, input=None: self._pool.simpleExecute(cmd=cmd, + input=input, + error_ok=1) + + key = data['key_data'] + net = None + if FLAGS.simple_network: + with open(FLAGS.simple_network_template) as f: + net = f.read() % {'address': data['private_dns_name'], + 'network': FLAGS.simple_network_network, + 'netmask': FLAGS.simple_network_netmask, + 'gateway': FLAGS.simple_network_gateway, + 'broadcast': FLAGS.simple_network_broadcast, + 'dns': FLAGS.simple_network_dns} + if key or net: + logging.info('Injecting data into image %s', data['image_id']) + yield disk.inject_data(basepath('disk-raw'), key, net, execute=execute) if os.path.exists(basepath('disk')): yield self._pool.simpleExecute('rm -f %s' % basepath('disk')) -- cgit From 45c192aee681eb684599ac2cacd9c38996ca2bb5 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Fri, 2 Jul 2010 10:39:04 -0500 Subject: Fixes and add interface template --- nova/compute/disk.py | 2 +- nova/compute/interfaces.template | 18 ++++++++++++++++++ nova/compute/network.py | 2 +- nova/endpoint/cloud.py | 13 ++++++++----- 4 files changed, 28 insertions(+), 7 deletions(-) create mode 100644 nova/compute/interfaces.template (limited to 'nova') diff --git a/nova/compute/disk.py b/nova/compute/disk.py index 3f528de61..3cf06e0eb 100644 --- a/nova/compute/disk.py +++ b/nova/compute/disk.py @@ -125,7 +125,7 @@ def inject_data(image, key=None, net=None, partition=None, execute=None): # inject key file yield _inject_key_into_fs(key, tmpdir, execute=execute) if net: - yield _inject_net_into_fs(net, tmpdir) + yield _inject_net_into_fs(net, tmpdir, execute=execute) finally: # unmount device yield execute('sudo umount %s' % mapped_device) diff --git a/nova/compute/interfaces.template b/nova/compute/interfaces.template new file mode 100644 index 000000000..11df301f6 --- /dev/null +++ b/nova/compute/interfaces.template @@ -0,0 +1,18 @@ +# This file describes the network interfaces available on your system +# and how to activate them. For more information, see interfaces(5). + +# The loopback network interface +auto lo +iface lo inet loopback + +# The primary network interface +auto eth0 +iface eth0 inet static + address %(address)s + netmask %(netmask)s + network %(network)s + broadcast %(broadcast)s + gateway %(gateway)s + dns-nameservers %(dns)s + + diff --git a/nova/compute/network.py b/nova/compute/network.py index 5223e59da..1cb202ea9 100644 --- a/nova/compute/network.py +++ b/nova/compute/network.py @@ -75,7 +75,7 @@ flags.DEFINE_string('simple_network_gateway', '192.168.0.1', 'Broadcast for simple network') flags.DEFINE_string('simple_network_broadcast', '192.168.0.255', 'Broadcast for simple network') -flags.DEFINE_string('simple_network_dns', '8.8.8.8', +flags.DEFINE_string('simple_network_dns', '8.8.4.4', 'Dns for simple network') logging.getLogger().setLevel(logging.DEBUG) diff --git a/nova/endpoint/cloud.py b/nova/endpoint/cloud.py index 50c087f2d..960c1e9af 100644 --- a/nova/endpoint/cloud.py +++ b/nova/endpoint/cloud.py @@ -538,7 +538,7 @@ class CloudController(object): inst['ami_launch_index'] = num inst['bridge_name'] = bridge_name if FLAGS.simple_network: - network.allocate_simple_ip(mac=inst['mac_address']) + address = network.allocate_simple_ip() else: if inst['image_id'] == FLAGS.vpn_image_id: address = network.allocate_vpn_ip( @@ -579,10 +579,13 @@ class CloudController(object): pass if instance.get('private_dns_name', None): logging.debug("Deallocating address %s" % instance.get('private_dns_name', None)) - try: - self.network.deallocate_ip(instance.get('private_dns_name', None)) - except Exception, _err: - pass + if FLAGS.simple_network: + network.deallocate_simple_ip(instance.get('private_dns_name', None)) + else: + try: + self.network.deallocate_ip(instance.get('private_dns_name', None)) + except Exception, _err: + pass if instance.get('node_name', 'unassigned') != 'unassigned': #It's also internal default rpc.cast('%s.%s' % (FLAGS.compute_topic, instance['node_name']), {"method": "terminate_instance", -- cgit From baea119aefe8e939eb5796b17fab29f5ae283449 Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Mon, 5 Jul 2010 12:46:26 +0200 Subject: Use rmdir instead of rm -rf to remove a tempdir. --- nova/compute/disk.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'nova') diff --git a/nova/compute/disk.py b/nova/compute/disk.py index e7090dad3..f4d75a781 100644 --- a/nova/compute/disk.py +++ b/nova/compute/disk.py @@ -126,8 +126,7 @@ def inject_key(key, image, partition=None, execute=None): yield execute('sudo umount %s' % mapped_device) finally: # remove temporary directory - # TODO(termie): scary, is there any thing we can check here? - yield execute('rm -rf %s' % tmpdir) + yield execute('rmdir %s' % tmpdir) if not partition is None: # remove partitions yield execute('sudo kpartx -d %s' % device) -- cgit From 6e77201cbab22d0c4b383b245d5957946a229e4c Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Tue, 6 Jul 2010 17:35:33 +0200 Subject: If set, pass KernelId and RamdiskId from RunInstances call to the target compute node. --- nova/endpoint/cloud.py | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'nova') diff --git a/nova/endpoint/cloud.py b/nova/endpoint/cloud.py index 39b3fd628..7b2d23e37 100644 --- a/nova/endpoint/cloud.py +++ b/nova/endpoint/cloud.py @@ -498,6 +498,10 @@ class CloudController(object): inst = self.instdir.new() # TODO(ja): add ari, aki inst['image_id'] = kwargs['image_id'] + if 'kernel_id' in kwargs: + inst['kernel_id'] = kwargs['kernel_id'] + if 'ramdisk_id' in kwargs: + inst['ramdisk_id'] = kwargs['ramdisk_id'] inst['user_data'] = kwargs.get('user_data', '') inst['instance_type'] = kwargs.get('instance_type', 'm1.small') inst['reservation_id'] = reservation_id -- cgit From b7ea2f70581f6acd927ea7b65adaffeeb4b8d2ba Mon Sep 17 00:00:00 2001 From: Joshua McKenty Date: Wed, 7 Jul 2010 12:06:34 -0700 Subject: Capture signals from dnsmasq and use them to update network state. --- nova/compute/linux_net.py | 9 ++++++++- nova/compute/network.py | 14 +++++++++++--- nova/tests/fake_flags.py | 2 +- nova/tests/network_unittest.py | 34 ++++++++++++++++++++++++++++++++++ nova/utils.py | 10 +++++++--- 5 files changed, 61 insertions(+), 8 deletions(-) (limited to 'nova') diff --git a/nova/compute/linux_net.py b/nova/compute/linux_net.py index 0bd5ce007..b44cf9437 100644 --- a/nova/compute/linux_net.py +++ b/nova/compute/linux_net.py @@ -62,6 +62,9 @@ def remove_rule(cmd): def bind_public_ip(ip, interface): runthis("Binding IP to interface: %s", "sudo ip addr add %s dev %s" % (ip, interface)) + +def unbind_public_ip(ip, interface): + runthis("Binding IP to interface: %s", "sudo ip addr del %s dev %s" % (ip, interface)) def vlan_create(net): """ create a vlan on on a bridge device unless vlan already exists """ @@ -98,7 +101,8 @@ def dnsmasq_cmd(net): ' --dhcp-range=%s,static,120s' % (net.dhcp_range_start), ' --dhcp-lease-max=61', ' --dhcp-hostsfile=%s' % dhcp_file(net['vlan'], 'conf'), - ' --dhcp-leasefile=%s' % dhcp_file(net['vlan'], 'leases')] + ' --dhcp-leasefile=%s' % dhcp_file(net['vlan'], 'leases'), + ' ---dhcp-script=%s' % bin_file('dhcpleasor.py')] return ''.join(cmd) def hostDHCP(network, host, mac): @@ -154,6 +158,9 @@ def dhcp_file(vlan, kind): return os.path.abspath("%s/nova-%s.%s" % (FLAGS.networks_path, vlan, kind)) +def bin_file(script): + return os.path.abspath(os.path.join(__file__, "../../../bin", script)) + def dnsmasq_pid_for(network): """ the pid for prior dnsmasq instance for a vlan, returns None if no pid file exists diff --git a/nova/compute/network.py b/nova/compute/network.py index 911d0344a..7a347aa11 100644 --- a/nova/compute/network.py +++ b/nova/compute/network.py @@ -162,12 +162,16 @@ class BaseNetwork(datastore.RedisModel): return address raise exception.NoMoreAddresses() - def deallocate_ip(self, ip_str): + def release_ip(self, ip_str): if not ip_str in self.assigned: raise exception.AddressNotAllocated() self.deexpress(address=ip_str) self._rem_host(ip_str) + def deallocate_ip(self, ip_str): + # Do nothing for now, cleanup on ip release + pass + def list_addresses(self): for address in self.hosts: yield address @@ -197,7 +201,7 @@ class BridgedNetwork(BaseNetwork): def get_network_for_project(cls, user_id, project_id, security_group): vlan = get_vlan_for_project(project_id) network_str = get_subnet_from_vlan(vlan) - logging.debug("creating network on vlan %s with network string %s" % (vlan, network_str)) + # logging.debug("creating network on vlan %s with network string %s" % (vlan, network_str)) return cls.create(user_id, project_id, security_group, vlan, network_str) def __init__(self, *args, **kwargs): @@ -221,7 +225,7 @@ class DHCPNetwork(BridgedNetwork): def __init__(self, *args, **kwargs): super(DHCPNetwork, self).__init__(*args, **kwargs) - logging.debug("Initing DHCPNetwork object...") + # logging.debug("Initing DHCPNetwork object...") self.dhcp_listen_address = self.network[1] self.dhcp_range_start = self.network[3] self.dhcp_range_end = self.network[-(1 + FLAGS.cnt_vpn_clients)] @@ -372,6 +376,7 @@ class PublicNetworkController(BaseNetwork): def deexpress(self, address=None): addr = self.get_host(address) private_ip = addr['private_ip'] + linux_net.unbind_public_ip(address, FLAGS.public_interface) linux_net.remove_rule("PREROUTING -t nat -d %s -j DNAT --to %s" % (address, private_ip)) linux_net.remove_rule("POSTROUTING -t nat -s %s -j SNAT --to %s" @@ -416,8 +421,11 @@ def get_vlan_for_project(project_id): def get_network_by_address(address): + logging.debug("Get Network By Address:") for project in users.UserManager.instance().get_projects(): + logging.debug(" looking at project %s", project.id) net = get_project_network(project.id) + logging.debug(" is %s in %s ?" % (address, str(net.assigned))) if address in net.assigned: return net raise exception.AddressNotAllocated() diff --git a/nova/tests/fake_flags.py b/nova/tests/fake_flags.py index d40172cfc..3f5d9ff54 100644 --- a/nova/tests/fake_flags.py +++ b/nova/tests/fake_flags.py @@ -28,5 +28,5 @@ FLAGS.fake_rabbit = True FLAGS.fake_network = True FLAGS.fake_users = True #FLAGS.keeper_backend = 'sqlite' -FLAGS.datastore_path = ':memory:' +# FLAGS.datastore_path = ':memory:' FLAGS.verbose = True diff --git a/nova/tests/network_unittest.py b/nova/tests/network_unittest.py index f215c0b3f..4c9f340c1 100644 --- a/nova/tests/network_unittest.py +++ b/nova/tests/network_unittest.py @@ -18,6 +18,7 @@ # License for the specific language governing permissions and limitations # under the License. +import os import logging import unittest @@ -26,6 +27,7 @@ import IPy from nova import flags from nova import test +from nova import exception from nova.compute import network from nova.auth import users from nova import utils @@ -40,6 +42,7 @@ class NetworkTestCase(test.TrialTestCase): network_size=32) logging.getLogger().setLevel(logging.DEBUG) self.manager = users.UserManager.instance() + self.dnsmasq = FakeDNSMasq() try: self.manager.create_user('netuser', 'netuser', 'netuser') except: pass @@ -63,11 +66,23 @@ class NetworkTestCase(test.TrialTestCase): self.assertTrue(IPy.IP(address) in self.network.network) def test_allocate_deallocate_ip(self): + # Address should be allocated + # Then, simulate acquisition of the address + # Deallocate it, and wait for simulated ip release + # then confirm it's gone. address = network.allocate_ip( "netuser", "project0", utils.generate_mac()) logging.debug("Was allocated %s" % (address)) + net = network.get_project_network("project0", "default") self.assertEqual(True, address in self._get_project_addresses("project0")) + mac = utils.generate_mac() + hostname = "test-host" + self.dnsmasq.issue_ip(mac, address, hostname, net.bridge_name) rv = network.deallocate_ip(address) + # Doesn't go away until it's dhcp released + self.assertEqual(True, address in self._get_project_addresses("project0")) + + self.dnsmasq.release_ip(mac, address, hostname, net.bridge_name) self.assertEqual(False, address in self._get_project_addresses("project0")) def test_range_allocation(self): @@ -122,3 +137,22 @@ class NetworkTestCase(test.TrialTestCase): for addr in network.get_project_network(project_id).list_addresses(): project_addresses.append(addr) return project_addresses + +def binpath(script): + return os.path.abspath(os.path.join(__file__, "../../../bin", script)) + +class FakeDNSMasq(object): + def issue_ip(self, mac, ip, hostname, interface): + cmd = "%s add %s %s %s" % (binpath('dhcpleasor.py'), mac, ip, hostname) + env = {'DNSMASQ_INTERFACE': interface, 'REDIS_DB' : '8'} + (out, err) = utils.execute(cmd, addl_env=env) + logging.debug(out) + logging.debug(err) + + def release_ip(self, mac, ip, hostname, interface): + cmd = "%s del %s %s %s" % (binpath('dhcpleasor.py'), mac, ip, hostname) + env = {'DNSMASQ_INTERFACE': interface, 'REDIS_DB' : '8'} + (out, err) = utils.execute(cmd, addl_env=env) + logging.debug(out) + logging.debug(err) + \ No newline at end of file diff --git a/nova/utils.py b/nova/utils.py index 325b062ee..cbfdd835d 100644 --- a/nova/utils.py +++ b/nova/utils.py @@ -26,6 +26,7 @@ import logging import socket import sys import os.path +from os import environ import inspect import subprocess import random @@ -46,11 +47,14 @@ def fetchfile(url, target): # fp.close() execute("curl %s -o %s" % (url, target)) - -def execute(cmd, input=None): +def execute(cmd, input=None, addl_env=None): #logging.debug("Running %s" % (cmd)) + env = os.environ.copy() + if addl_env: + env.update(addl_env) + logging.debug(env) obj = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE, - stdout=subprocess.PIPE, stderr=subprocess.PIPE) + stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env) result = None if input != None: result = obj.communicate(input) -- cgit From dbe324f7254dd3e01de44bb908150fb8397fe118 Mon Sep 17 00:00:00 2001 From: Joshua McKenty Date: Wed, 7 Jul 2010 12:15:11 -0700 Subject: Got dhcpleasor working, with test ENV for testing, and rpc.cast for real world. --- nova/compute/linux_net.py | 7 +++---- nova/compute/network.py | 25 +++++++++++++++++++++---- nova/endpoint/cloud.py | 8 ++++++++ nova/tests/network_unittest.py | 40 +++++++++++++++++++++++++++++++--------- nova/utils.py | 2 -- 5 files changed, 63 insertions(+), 19 deletions(-) (limited to 'nova') diff --git a/nova/compute/linux_net.py b/nova/compute/linux_net.py index b44cf9437..c9e5bb1a7 100644 --- a/nova/compute/linux_net.py +++ b/nova/compute/linux_net.py @@ -98,11 +98,10 @@ def dnsmasq_cmd(net): ' --pid-file=%s' % dhcp_file(net['vlan'], 'pid'), ' --listen-address=%s' % net.dhcp_listen_address, ' --except-interface=lo', - ' --dhcp-range=%s,static,120s' % (net.dhcp_range_start), - ' --dhcp-lease-max=61', + ' --dhcp-range=%s,static,600s' % (net.dhcp_range_start), ' --dhcp-hostsfile=%s' % dhcp_file(net['vlan'], 'conf'), - ' --dhcp-leasefile=%s' % dhcp_file(net['vlan'], 'leases'), - ' ---dhcp-script=%s' % bin_file('dhcpleasor.py')] + ' --dhcp-script=%s' % bin_file('dhcpleasor.py'), + ' --leasefile-ro'] return ''.join(cmd) def hostDHCP(network, host, mac): diff --git a/nova/compute/network.py b/nova/compute/network.py index 7a347aa11..96b8e9627 100644 --- a/nova/compute/network.py +++ b/nova/compute/network.py @@ -160,7 +160,10 @@ class BaseNetwork(datastore.RedisModel): self._add_host(user_id, project_id, address, mac) self.express(address=address) return address - raise exception.NoMoreAddresses() + raise exception.NoMoreAddresses("Project %s with network %s" % (project_id, str(self.network))) + + def lease_ip(self, ip_str): + logging.debug("Leasing allocated IP %s" % (ip_str)) def release_ip(self, ip_str): if not ip_str in self.assigned: @@ -419,14 +422,22 @@ def get_vlan_for_project(project_id): return vlan raise exception.AddressNotAllocated("Out of VLANs") +def get_project_id_for_vlan(vlan): + assigned_vlans = get_assigned_vlans() + for project_id, project_vlan in assigned_vlans.iteritems(): + if vlan == project_vlan: + return project_id + +def get_network_by_interface(iface, security_group='default'): + vlan = iface.rpartition("br")[2] + return get_project_network(get_project_id_for_vlan(vlan), security_group) def get_network_by_address(address): - logging.debug("Get Network By Address:") + logging.debug("Get Network By Address: %s" % address) for project in users.UserManager.instance().get_projects(): - logging.debug(" looking at project %s", project.id) net = get_project_network(project.id) - logging.debug(" is %s in %s ?" % (address, str(net.assigned))) if address in net.assigned: + logging.debug("Found %s in %s" % (address, project.id)) return net raise exception.AddressNotAllocated() @@ -438,6 +449,12 @@ def allocate_ip(user_id, project_id, mac): def deallocate_ip(address): return get_network_by_address(address).deallocate_ip(address) + +def release_ip(address): + return get_network_by_address(address).release_ip(address) + +def lease_ip(address): + return get_network_by_address(address).lease_ip(address) def get_project_network(project_id, security_group='default'): """ get a project's private network, allocating one if needed """ diff --git a/nova/endpoint/cloud.py b/nova/endpoint/cloud.py index 931c6c6e1..269fb3950 100644 --- a/nova/endpoint/cloud.py +++ b/nova/endpoint/cloud.py @@ -498,6 +498,14 @@ class CloudController(object): # TODO - Strip the IP from the instance return defer.succeed({'disassociateResponse': ["Address disassociated."]}) + def release_ip(self, context, private_ip, **kwargs): + self.network.release_ip(private_ip) + return defer.succeed({'releaseResponse': ["Address released."]}) + + def lease_ip(self, context, private_ip, **kwargs): + self.network.lease_ip(private_ip) + return defer.succeed({'leaseResponse': ["Address lease."]}) + @rbac.allow('projectmanager', 'sysadmin') def run_instances(self, context, **kwargs): # make sure user can access the image diff --git a/nova/tests/network_unittest.py b/nova/tests/network_unittest.py index 4c9f340c1..8cbc2b7cd 100644 --- a/nova/tests/network_unittest.py +++ b/nova/tests/network_unittest.py @@ -21,6 +21,7 @@ import os import logging import unittest +import time from nova import vendor import IPy @@ -86,18 +87,36 @@ class NetworkTestCase(test.TrialTestCase): self.assertEqual(False, address in self._get_project_addresses("project0")) def test_range_allocation(self): + mac = utils.generate_mac() + secondmac = utils.generate_mac() + hostname = "test-host" address = network.allocate_ip( - "netuser", "project0", utils.generate_mac()) + "netuser", "project0", mac) secondaddress = network.allocate_ip( - "netuser", "project1", utils.generate_mac()) + "netuser", "project1", secondmac) + net = network.get_project_network("project0", "default") + secondnet = network.get_project_network("project1", "default") + self.assertEqual(True, address in self._get_project_addresses("project0")) self.assertEqual(True, secondaddress in self._get_project_addresses("project1")) self.assertEqual(False, address in self._get_project_addresses("project1")) + # Addresses are allocated before they're issued + self.dnsmasq.issue_ip(mac, address, hostname, net.bridge_name) + self.dnsmasq.issue_ip(secondmac, secondaddress, + hostname, secondnet.bridge_name) + rv = network.deallocate_ip(address) + self.dnsmasq.release_ip(mac, address, hostname, net.bridge_name) self.assertEqual(False, address in self._get_project_addresses("project0")) + # First address release shouldn't affect the second + self.assertEqual(True, + secondaddress in self._get_project_addresses("project1")) + rv = network.deallocate_ip(secondaddress) + self.dnsmasq.release_ip(secondmac, secondaddress, + hostname, secondnet.bridge_name) self.assertEqual(False, secondaddress in self._get_project_addresses("project1")) @@ -127,9 +146,14 @@ class NetworkTestCase(test.TrialTestCase): for i in range(0, 30): name = 'toomany-project%s' % i self.manager.create_project(name, 'netuser', name) + net = network.get_project_network(name, "default") + mac = utils.generate_mac() + hostname = "toomany-hosts" address = network.allocate_ip( - "netuser", name, utils.generate_mac()) + "netuser", name, mac) + self.dnsmasq.issue_ip(mac, address, hostname, net.bridge_name) rv = network.deallocate_ip(address) + self.dnsmasq.release_ip(mac, address, hostname, net.bridge_name) self.manager.delete_project(name) def _get_project_addresses(self, project_id): @@ -144,15 +168,13 @@ def binpath(script): class FakeDNSMasq(object): def issue_ip(self, mac, ip, hostname, interface): cmd = "%s add %s %s %s" % (binpath('dhcpleasor.py'), mac, ip, hostname) - env = {'DNSMASQ_INTERFACE': interface, 'REDIS_DB' : '8'} + env = {'DNSMASQ_INTERFACE': interface, 'TESTING' : '1'} (out, err) = utils.execute(cmd, addl_env=env) - logging.debug(out) - logging.debug(err) + logging.debug("ISSUE_IP: %s, %s " % (out, err)) def release_ip(self, mac, ip, hostname, interface): cmd = "%s del %s %s %s" % (binpath('dhcpleasor.py'), mac, ip, hostname) - env = {'DNSMASQ_INTERFACE': interface, 'REDIS_DB' : '8'} + env = {'DNSMASQ_INTERFACE': interface, 'TESTING' : '1'} (out, err) = utils.execute(cmd, addl_env=env) - logging.debug(out) - logging.debug(err) + logging.debug("RELEASE_IP: %s, %s " % (out, err)) \ No newline at end of file diff --git a/nova/utils.py b/nova/utils.py index cbfdd835d..62ad00aec 100644 --- a/nova/utils.py +++ b/nova/utils.py @@ -48,11 +48,9 @@ def fetchfile(url, target): execute("curl %s -o %s" % (url, target)) def execute(cmd, input=None, addl_env=None): - #logging.debug("Running %s" % (cmd)) env = os.environ.copy() if addl_env: env.update(addl_env) - logging.debug(env) obj = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env) result = None -- cgit From d831ef39e2d84aa3e39bc3861085d563575efa43 Mon Sep 17 00:00:00 2001 From: Joshua McKenty Date: Wed, 7 Jul 2010 12:15:11 -0700 Subject: Adding more tests, refactoring for dhcp logic. --- nova/tests/network_unittest.py | 106 ++++++++++++++++++++++++----------------- 1 file changed, 62 insertions(+), 44 deletions(-) (limited to 'nova') diff --git a/nova/tests/network_unittest.py b/nova/tests/network_unittest.py index 8cbc2b7cd..67ae7ad2d 100644 --- a/nova/tests/network_unittest.py +++ b/nova/tests/network_unittest.py @@ -29,6 +29,7 @@ import IPy from nova import flags from nova import test from nova import exception +from nova.compute.exception import NoMoreAddresses from nova.compute import network from nova.auth import users from nova import utils @@ -67,24 +68,21 @@ class NetworkTestCase(test.TrialTestCase): self.assertTrue(IPy.IP(address) in self.network.network) def test_allocate_deallocate_ip(self): - # Address should be allocated - # Then, simulate acquisition of the address - # Deallocate it, and wait for simulated ip release - # then confirm it's gone. address = network.allocate_ip( "netuser", "project0", utils.generate_mac()) logging.debug("Was allocated %s" % (address)) net = network.get_project_network("project0", "default") - self.assertEqual(True, address in self._get_project_addresses("project0")) + self.assertEqual(True, is_in_project(address, "project0")) mac = utils.generate_mac() hostname = "test-host" self.dnsmasq.issue_ip(mac, address, hostname, net.bridge_name) rv = network.deallocate_ip(address) + # Doesn't go away until it's dhcp released - self.assertEqual(True, address in self._get_project_addresses("project0")) + self.assertEqual(True, is_in_project(address, "project0")) self.dnsmasq.release_ip(mac, address, hostname, net.bridge_name) - self.assertEqual(False, address in self._get_project_addresses("project0")) + self.assertEqual(False, is_in_project(address, "project0")) def test_range_allocation(self): mac = utils.generate_mac() @@ -97,11 +95,10 @@ class NetworkTestCase(test.TrialTestCase): net = network.get_project_network("project0", "default") secondnet = network.get_project_network("project1", "default") - self.assertEqual(True, - address in self._get_project_addresses("project0")) - self.assertEqual(True, - secondaddress in self._get_project_addresses("project1")) - self.assertEqual(False, address in self._get_project_addresses("project1")) + self.assertEqual(True, is_in_project(address, "project0")) + self.assertEqual(True, is_in_project(secondaddress, "project1")) + self.assertEqual(False, is_in_project(address, "project1")) + # Addresses are allocated before they're issued self.dnsmasq.issue_ip(mac, address, hostname, net.bridge_name) self.dnsmasq.issue_ip(secondmac, secondaddress, @@ -109,58 +106,79 @@ class NetworkTestCase(test.TrialTestCase): rv = network.deallocate_ip(address) self.dnsmasq.release_ip(mac, address, hostname, net.bridge_name) - self.assertEqual(False, address in self._get_project_addresses("project0")) + self.assertEqual(False, is_in_project(address, "project0")) + # First address release shouldn't affect the second - self.assertEqual(True, - secondaddress in self._get_project_addresses("project1")) + self.assertEqual(True, is_in_project(secondaddress, "project1")) rv = network.deallocate_ip(secondaddress) self.dnsmasq.release_ip(secondmac, secondaddress, hostname, secondnet.bridge_name) - self.assertEqual(False, - secondaddress in self._get_project_addresses("project1")) + self.assertEqual(False, is_in_project(secondaddress, "project1")) def test_subnet_edge(self): secondaddress = network.allocate_ip("netuser", "project0", utils.generate_mac()) + hostname = "toomany-hosts" for project in range(1,5): project_id = "project%s" % (project) + mac = utils.generate_mac() + mac2 = utils.generate_mac() + mac3 = utils.generate_mac() address = network.allocate_ip( - "netuser", project_id, utils.generate_mac()) + "netuser", project_id, mac) address2 = network.allocate_ip( - "netuser", project_id, utils.generate_mac()) + "netuser", project_id, mac2) address3 = network.allocate_ip( - "netuser", project_id, utils.generate_mac()) - self.assertEqual(False, - address in self._get_project_addresses("project0")) - self.assertEqual(False, - address2 in self._get_project_addresses("project0")) - self.assertEqual(False, - address3 in self._get_project_addresses("project0")) + "netuser", project_id, mac3) + self.assertEqual(False, is_in_project(address, "project0")) + self.assertEqual(False, is_in_project(address2, "project0")) + self.assertEqual(False, is_in_project(address3, "project0")) rv = network.deallocate_ip(address) rv = network.deallocate_ip(address2) rv = network.deallocate_ip(address3) + net = network.get_project_network(project_id, "default") + self.dnsmasq.release_ip(mac, address, hostname, net.bridge_name) + self.dnsmasq.release_ip(mac2, address2, hostname, net.bridge_name) + self.dnsmasq.release_ip(mac3, address3, hostname, net.bridge_name) + net = network.get_project_network("project0", "default") rv = network.deallocate_ip(secondaddress) + self.dnsmasq.release_ip(mac, address, hostname, net.bridge_name) - def test_too_many_projects(self): - for i in range(0, 30): - name = 'toomany-project%s' % i - self.manager.create_project(name, 'netuser', name) - net = network.get_project_network(name, "default") - mac = utils.generate_mac() - hostname = "toomany-hosts" - address = network.allocate_ip( - "netuser", name, mac) - self.dnsmasq.issue_ip(mac, address, hostname, net.bridge_name) - rv = network.deallocate_ip(address) - self.dnsmasq.release_ip(mac, address, hostname, net.bridge_name) - self.manager.delete_project(name) + def test_release_before_deallocate(self): + pass + + def test_deallocate_before_issued(self): + pass + + def test_too_many_addresses(self): + """ + Network size is 32, there are 5 addresses reserved for VPN. + So we should get 24 usable addresses + """ + net = network.get_project_network("project0", "default") + hostname = "toomany-hosts" + macs = {} + addresses = {} + for i in range(0, 23): + macs[i] = utils.generate_mac() + addresses[i] = network.allocate_ip("netuser", "project0", macs[i]) + self.dnsmasq.issue_ip(macs[i], addresses[i], hostname, net.bridge_name) + + self.assertRaises(NoMoreAddresses, network.allocate_ip, "netuser", "project0", utils.generate_mac()) + + for i in range(0, 23): + rv = network.deallocate_ip(addresses[i]) + self.dnsmasq.release_ip(macs[i], addresses[i], hostname, net.bridge_name) + +def is_in_project(address, project_id): + return address in network.get_project_network(project_id).list_addresses() - def _get_project_addresses(self, project_id): - project_addresses = [] - for addr in network.get_project_network(project_id).list_addresses(): - project_addresses.append(addr) - return project_addresses +def _get_project_addresses(project_id): + project_addresses = [] + for addr in network.get_project_network(project_id).list_addresses(): + project_addresses.append(addr) + return project_addresses def binpath(script): return os.path.abspath(os.path.join(__file__, "../../../bin", script)) -- cgit From 84c69c32297a1f79e8630102497e1e7e0041a324 Mon Sep 17 00:00:00 2001 From: Joshua McKenty Date: Wed, 7 Jul 2010 12:24:17 -0700 Subject: Off by one error in the allocation test (can someone check my subnet math?) --- nova/tests/network_unittest.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'nova') diff --git a/nova/tests/network_unittest.py b/nova/tests/network_unittest.py index 67ae7ad2d..4d79758fb 100644 --- a/nova/tests/network_unittest.py +++ b/nova/tests/network_unittest.py @@ -21,7 +21,6 @@ import os import logging import unittest -import time from nova import vendor import IPy @@ -154,20 +153,20 @@ class NetworkTestCase(test.TrialTestCase): def test_too_many_addresses(self): """ Network size is 32, there are 5 addresses reserved for VPN. - So we should get 24 usable addresses + So we should get 23 usable addresses """ net = network.get_project_network("project0", "default") hostname = "toomany-hosts" macs = {} addresses = {} - for i in range(0, 23): + for i in range(0, 22): macs[i] = utils.generate_mac() addresses[i] = network.allocate_ip("netuser", "project0", macs[i]) self.dnsmasq.issue_ip(macs[i], addresses[i], hostname, net.bridge_name) self.assertRaises(NoMoreAddresses, network.allocate_ip, "netuser", "project0", utils.generate_mac()) - for i in range(0, 23): + for i in range(0, 22): rv = network.deallocate_ip(addresses[i]) self.dnsmasq.release_ip(macs[i], addresses[i], hostname, net.bridge_name) -- cgit From b9a8bd2d55f016fba305a00c985c7f6769afddd2 Mon Sep 17 00:00:00 2001 From: Joshua McKenty Date: Wed, 7 Jul 2010 12:24:22 -0700 Subject: Fixes as per Vish review (whitespace, import statements) --- nova/endpoint/cloud.py | 2 +- nova/utils.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'nova') diff --git a/nova/endpoint/cloud.py b/nova/endpoint/cloud.py index 269fb3950..a2f60b47f 100644 --- a/nova/endpoint/cloud.py +++ b/nova/endpoint/cloud.py @@ -504,7 +504,7 @@ class CloudController(object): def lease_ip(self, context, private_ip, **kwargs): self.network.lease_ip(private_ip) - return defer.succeed({'leaseResponse': ["Address lease."]}) + return defer.succeed({'leaseResponse': ["Address leased."]}) @rbac.allow('projectmanager', 'sysadmin') def run_instances(self, context, **kwargs): diff --git a/nova/utils.py b/nova/utils.py index 62ad00aec..1041733f1 100644 --- a/nova/utils.py +++ b/nova/utils.py @@ -26,7 +26,7 @@ import logging import socket import sys import os.path -from os import environ +import os.environ import inspect import subprocess import random -- cgit From 6d695e8410ad40b886cf6aff3a1e41598dcdfc66 Mon Sep 17 00:00:00 2001 From: Joshua McKenty Date: Wed, 7 Jul 2010 12:24:24 -0700 Subject: Fixed the os.environ patch (bogus) --- nova/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova') diff --git a/nova/utils.py b/nova/utils.py index 1041733f1..2f0ce33cd 100644 --- a/nova/utils.py +++ b/nova/utils.py @@ -26,7 +26,7 @@ import logging import socket import sys import os.path -import os.environ +import os import inspect import subprocess import random -- cgit From faada0612d8e8580a2a932626c8972b7c2a4ef59 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Wed, 7 Jul 2010 12:25:22 -0700 Subject: whitespace fixes and header changes --- nova/tests/network_unittest.py | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) (limited to 'nova') diff --git a/nova/tests/network_unittest.py b/nova/tests/network_unittest.py index 4d79758fb..bccaacfa7 100644 --- a/nova/tests/network_unittest.py +++ b/nova/tests/network_unittest.py @@ -76,10 +76,10 @@ class NetworkTestCase(test.TrialTestCase): hostname = "test-host" self.dnsmasq.issue_ip(mac, address, hostname, net.bridge_name) rv = network.deallocate_ip(address) - + # Doesn't go away until it's dhcp released self.assertEqual(True, is_in_project(address, "project0")) - + self.dnsmasq.release_ip(mac, address, hostname, net.bridge_name) self.assertEqual(False, is_in_project(address, "project0")) @@ -93,25 +93,25 @@ class NetworkTestCase(test.TrialTestCase): "netuser", "project1", secondmac) net = network.get_project_network("project0", "default") secondnet = network.get_project_network("project1", "default") - + self.assertEqual(True, is_in_project(address, "project0")) self.assertEqual(True, is_in_project(secondaddress, "project1")) self.assertEqual(False, is_in_project(address, "project1")) - + # Addresses are allocated before they're issued self.dnsmasq.issue_ip(mac, address, hostname, net.bridge_name) - self.dnsmasq.issue_ip(secondmac, secondaddress, + self.dnsmasq.issue_ip(secondmac, secondaddress, hostname, secondnet.bridge_name) - + rv = network.deallocate_ip(address) self.dnsmasq.release_ip(mac, address, hostname, net.bridge_name) self.assertEqual(False, is_in_project(address, "project0")) - + # First address release shouldn't affect the second self.assertEqual(True, is_in_project(secondaddress, "project1")) - + rv = network.deallocate_ip(secondaddress) - self.dnsmasq.release_ip(secondmac, secondaddress, + self.dnsmasq.release_ip(secondmac, secondaddress, hostname, secondnet.bridge_name) self.assertEqual(False, is_in_project(secondaddress, "project1")) @@ -146,15 +146,15 @@ class NetworkTestCase(test.TrialTestCase): def test_release_before_deallocate(self): pass - + def test_deallocate_before_issued(self): pass - - def test_too_many_addresses(self): + + def test_too_many_addresses(self): """ Network size is 32, there are 5 addresses reserved for VPN. So we should get 23 usable addresses - """ + """ net = network.get_project_network("project0", "default") hostname = "toomany-hosts" macs = {} @@ -163,10 +163,10 @@ class NetworkTestCase(test.TrialTestCase): macs[i] = utils.generate_mac() addresses[i] = network.allocate_ip("netuser", "project0", macs[i]) self.dnsmasq.issue_ip(macs[i], addresses[i], hostname, net.bridge_name) - + self.assertRaises(NoMoreAddresses, network.allocate_ip, "netuser", "project0", utils.generate_mac()) - - for i in range(0, 22): + + for i in range(0, 22): rv = network.deallocate_ip(addresses[i]) self.dnsmasq.release_ip(macs[i], addresses[i], hostname, net.bridge_name) @@ -188,10 +188,10 @@ class FakeDNSMasq(object): env = {'DNSMASQ_INTERFACE': interface, 'TESTING' : '1'} (out, err) = utils.execute(cmd, addl_env=env) logging.debug("ISSUE_IP: %s, %s " % (out, err)) - + def release_ip(self, mac, ip, hostname, interface): cmd = "%s del %s %s %s" % (binpath('dhcpleasor.py'), mac, ip, hostname) env = {'DNSMASQ_INTERFACE': interface, 'TESTING' : '1'} (out, err) = utils.execute(cmd, addl_env=env) logging.debug("RELEASE_IP: %s, %s " % (out, err)) - \ No newline at end of file + -- cgit From 082c228f98e1d7545a9d5d7abe10bd35691d85c9 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Wed, 7 Jul 2010 18:29:19 -0700 Subject: use a flag for cert subject --- nova/auth/users.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'nova') diff --git a/nova/auth/users.py b/nova/auth/users.py index 1fc97345f..1a270733e 100644 --- a/nova/auth/users.py +++ b/nova/auth/users.py @@ -100,6 +100,10 @@ flags.DEFINE_string('credential_cert_file', 'cert.pem', 'Filename of certificate in credentials zip') flags.DEFINE_string('credential_rc_file', 'novarc', 'Filename of rc in credentials zip') +flags.DEFINE_string('credential_cert_subject', + '/C=US/ST=California/L=MountainView/O=AnsoLabs/' + 'OU=NovaDev/CN=%s-%s' + 'Subject for certificate for users') flags.DEFINE_string('vpn_ip', '127.0.0.1', 'Public IP for the cloudpipe VPN servers') @@ -516,7 +520,7 @@ class UserManager(object): def __cert_subject(self, uid): # FIXME(ja) - this should be pulled from a global configuration - return "/C=US/ST=California/L=MountainView/O=AnsoLabs/OU=NovaDev/CN=%s-%s" % (uid, str(datetime.datetime.utcnow().isoformat())) + return FLAGS.credential_cert_subject % (uid, utils.isotime()) class LDAPWrapper(object): -- cgit From f5ce5b5750120012287d78ea0a40598ec0eefd47 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Thu, 8 Jul 2010 09:42:11 -0700 Subject: missed a comma --- nova/auth/users.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova') diff --git a/nova/auth/users.py b/nova/auth/users.py index 1a270733e..671fdbdbf 100644 --- a/nova/auth/users.py +++ b/nova/auth/users.py @@ -102,7 +102,7 @@ flags.DEFINE_string('credential_rc_file', 'novarc', 'Filename of rc in credentials zip') flags.DEFINE_string('credential_cert_subject', '/C=US/ST=California/L=MountainView/O=AnsoLabs/' - 'OU=NovaDev/CN=%s-%s' + 'OU=NovaDev/CN=%s-%s', 'Subject for certificate for users') flags.DEFINE_string('vpn_ip', '127.0.0.1', 'Public IP for the cloudpipe VPN servers') -- cgit From 6993e9fb1aca0c238a78c3948eb19d4fbb7963eb Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Thu, 8 Jul 2010 10:53:27 -0700 Subject: added missing isotime method from utils --- nova/utils.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'nova') diff --git a/nova/utils.py b/nova/utils.py index 325b062ee..46b5b7c51 100644 --- a/nova/utils.py +++ b/nova/utils.py @@ -22,13 +22,14 @@ System-level utilities and helper functions. """ +import datetime +import inspect import logging -import socket -import sys import os.path -import inspect -import subprocess import random +import socket +import subprocess +import sys from nova import flags @@ -114,3 +115,8 @@ def get_my_ip(): (addr, port) = csock.getsockname() csock.close() return addr + +def isotime(at=None): + if not at: + at = datetime.utcnow() + return at.strftime("%Y-%m-%dT%H:%M:%SZ") -- cgit From a6e5d2139cbe46992370b0f2b107532a2b55b62e Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Thu, 8 Jul 2010 11:00:53 -0700 Subject: datetime import typo --- nova/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova') diff --git a/nova/utils.py b/nova/utils.py index 46b5b7c51..d6d958b3c 100644 --- a/nova/utils.py +++ b/nova/utils.py @@ -22,7 +22,6 @@ System-level utilities and helper functions. """ -import datetime import inspect import logging import os.path @@ -30,6 +29,7 @@ import random import socket import subprocess import sys +from datetime import datetime from nova import flags -- cgit From 0f375589c2c6c32de9530a9075eba224a041c697 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Thu, 8 Jul 2010 11:03:43 -0700 Subject: typo in exception in crypto --- nova/crypto.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova') diff --git a/nova/crypto.py b/nova/crypto.py index 413796ccc..92a1ab76f 100644 --- a/nova/crypto.py +++ b/nova/crypto.py @@ -92,7 +92,7 @@ def ssl_pub_to_ssh_pub(ssl_public_key, name='root', suffix='nova'): + " transport | lsh-export-key --openssh" (out, err) = utils.execute(convert, ssl_public_key) if err: - raise exception.Error("Failed to generate key: %s", err) + raise exception.Error("Failed to generate key: %s" % err) return '%s %s@%s\n' %(out.strip(), name, suffix) -- cgit From ddc4a0970d9e98a45b820ed740f3ed8e696a4972 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Fri, 9 Jul 2010 16:17:45 -0700 Subject: move check for none before get mpi data --- nova/endpoint/cloud.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova') diff --git a/nova/endpoint/cloud.py b/nova/endpoint/cloud.py index 931c6c6e1..f11faeb56 100644 --- a/nova/endpoint/cloud.py +++ b/nova/endpoint/cloud.py @@ -115,9 +115,9 @@ class CloudController(object): def get_metadata(self, ip): i = self.get_instance_by_ip(ip) - mpi = self._get_mpi_data(i['project_id']) if i is None: return None + mpi = self._get_mpi_data(i['project_id']) if i['key_name']: keys = { '0': { -- cgit From 732707903f65fc126c147fc0a0839a3639b8d976 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Mon, 12 Jul 2010 15:11:41 -0500 Subject: fixed bug in auth group_exists it was using the name instead of the dn --- nova/auth/users.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova') diff --git a/nova/auth/users.py b/nova/auth/users.py index 671fdbdbf..769983e83 100644 --- a/nova/auth/users.py +++ b/nova/auth/users.py @@ -710,7 +710,7 @@ class LDAPWrapper(object): def __create_group(self, group_dn, name, uid, description, member_uids = None): - if self.group_exists(name): + if self.group_exists(group_dn): raise exception.Duplicate("Group can't be created because " "group %s already exists" % name) members = [] -- cgit From dfdb094956acce5f0d459203a9f95067f989d68d Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Mon, 12 Jul 2010 16:28:19 -0500 Subject: Avoid using s-expr, pkcs1-conv, and lsh-export-key. Instead we now use M2Crypto and struct.pack to construct it on our own. This removes a dependency on nettle-bin and lsh-utils (which were never specified in debian/control). --- nova/crypto.py | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) (limited to 'nova') diff --git a/nova/crypto.py b/nova/crypto.py index 80b4ef9de..4f97bb824 100644 --- a/nova/crypto.py +++ b/nova/crypto.py @@ -23,10 +23,12 @@ Wrappers around standard crypto, including root and intermediate CAs, SSH keypairs and x509 certificates. """ +import base64 import hashlib import logging import os import shutil +import struct import tempfile import time import utils @@ -86,14 +88,17 @@ def generate_key_pair(bits=1024): def ssl_pub_to_ssh_pub(ssl_public_key, name='root', suffix='nova'): - """requires lsh-utils""" - convert="sed -e'1d' -e'$d' | pkcs1-conv --public-key-info --base-64 |" \ - + " sexp-conv | sed -e'1s/(rsa-pkcs1/(rsa-pkcs1-sha1/' | sexp-conv -s" \ - + " transport | lsh-export-key --openssh" - (out, err) = utils.execute(convert, ssl_public_key) - if err: - raise exception.Error("Failed to generate key: %s", err) - return '%s %s@%s\n' %(out.strip(), name, suffix) + rsa_key = M2Crypto.RSA.load_pub_key_bio(M2Crypto.BIO.MemoryBuffer(ssl_public_key)) + e, n = rsa_key.pub() + + key_type = 'ssh-rsa' + + key_data = struct.pack('>I', len(key_type)) + key_data += key_type + key_data += '%s%s' % (e,n) + + b64_blob = base64.b64encode(key_data) + return '%s %s %s@%s\n' %(key_type, b64_blob, name, suffix) def generate_x509_cert(subject="/C=US/ST=California/L=The Mission/O=CloudFed/OU=NOVA/CN=foo", bits=1024): -- cgit From c17dcd9db1afeef79263f5d8d1bd2a52de8f87a5 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Tue, 13 Jul 2010 20:52:13 -0500 Subject: fix for extra space in vblade-persist --- nova/volume/storage.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova') diff --git a/nova/volume/storage.py b/nova/volume/storage.py index a0c4b0d55..ed7857b3d 100644 --- a/nova/volume/storage.py +++ b/nova/volume/storage.py @@ -243,7 +243,7 @@ class Volume(datastore.RedisModel): def _exec_export(self): utils.runthis("Creating AOE export: %s", - "sudo vblade- persist setup %s %s %s /dev/%s/%s" % + "sudo vblade-persist setup %s %s %s /dev/%s/%s" % (self['shelf_id'], self['blade_id'], FLAGS.aoe_eth_dev, -- cgit From 69104d57f95b8d6609490af8ed981add3fc0a98b Mon Sep 17 00:00:00 2001 From: Jesse Andrews Date: Wed, 14 Jul 2010 18:03:19 -0500 Subject: optimization to not load all instances when describe instances is called --- nova/endpoint/cloud.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'nova') diff --git a/nova/endpoint/cloud.py b/nova/endpoint/cloud.py index f11faeb56..19b6db91f 100644 --- a/nova/endpoint/cloud.py +++ b/nova/endpoint/cloud.py @@ -403,15 +403,17 @@ class CloudController(object): def _format_instances(self, context, reservation_id = None): reservations = {} - for instance in self.instdir.all: + if context.user.is_admin(): + instgenerator = self.instdir.all + else: + instgenerator = self.instdir.by_project(context.project.id) + for instance in instgenerator: res_id = instance.get('reservation_id', 'Unknown') if reservation_id != None and reservation_id != res_id: continue if not context.user.is_admin(): if instance['image_id'] == FLAGS.vpn_image_id: continue - if context.project.id != instance['project_id']: - continue i = {} i['instance_id'] = instance.get('instance_id', None) i['image_id'] = instance.get('image_id', None) -- cgit