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/compute') 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/compute') 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/compute') 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 +++++---- 2 files changed, 26 insertions(+), 4 deletions(-) (limited to 'nova/compute') 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 -- 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/compute') 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 +- 3 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 nova/compute/interfaces.template (limited to 'nova/compute') 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) -- 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/compute') 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 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 +++++++++++--- 2 files changed, 19 insertions(+), 4 deletions(-) (limited to 'nova/compute') 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() -- 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 +++++++++++++++++++++---- 2 files changed, 24 insertions(+), 8 deletions(-) (limited to 'nova/compute') 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 """ -- cgit