From f21d8510bb3f55b2b76aab251b0427dbfa69c5d9 Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Tue, 7 Sep 2010 14:34:27 +0200 Subject: Add a clean-traffic filterref to the libvirt templates to prevent spoofing and snooping attacks from the guests. --- nova/virt/libvirt.qemu.xml.template | 3 +++ nova/virt/libvirt.uml.xml.template | 3 +++ 2 files changed, 6 insertions(+) (limited to 'nova/virt') diff --git a/nova/virt/libvirt.qemu.xml.template b/nova/virt/libvirt.qemu.xml.template index 307f9d03a..3de1e5009 100644 --- a/nova/virt/libvirt.qemu.xml.template +++ b/nova/virt/libvirt.qemu.xml.template @@ -20,6 +20,9 @@ + + + diff --git a/nova/virt/libvirt.uml.xml.template b/nova/virt/libvirt.uml.xml.template index 6f4290f98..e64b172d8 100644 --- a/nova/virt/libvirt.uml.xml.template +++ b/nova/virt/libvirt.uml.xml.template @@ -14,6 +14,9 @@ + + + -- cgit From c3dd0aa79d982d8f34172e6023d4b632ea23f2b9 Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Fri, 10 Sep 2010 14:56:36 +0200 Subject: First pass of nwfilter based security group implementation. It is not where it is supposed to be and it does not actually do anything yet. --- nova/virt/libvirt_conn.py | 63 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) (limited to 'nova/virt') diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index e26030158..7bf2a68b1 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -426,3 +426,66 @@ class LibvirtConnection(object): """ domain = self._conn.lookupByName(instance_name) return domain.interfaceStats(interface) + + +class NWFilterFirewall(object): + """ + This class implements a network filtering mechanism versatile + enough for EC2 style Security Group filtering by leveraging + libvirt's nwfilter. + + First, all instances get a filter ("nova-base-filter") applied. + This filter drops all incoming ipv4 and ipv6 connections. + Outgoing connections are never blocked. + + Second, every security group maps to a nwfilter filter(*). + NWFilters can be updated at runtime and changes are applied + immediately, so changes to security groups can be applied at + runtime (as mandated by the spec). + + Security group rules are named "nova-secgroup-" where + is the internal id of the security group. They're applied only on + hosts that have instances in the security group in question. + + Updates to security groups are done by updating the data model + (in response to API calls) followed by a request sent to all + the nodes with instances in the security group to refresh the + security group. + + Outstanding questions: + + The name is unique, so would there be any good reason to sync + the uuid across the nodes (by assigning it from the datamodel)? + + + (*) This sentence brought to you by the redundancy department of + redundancy. + """ + + def __init__(self): + pass + + def nova_base_filter(self): + return ''' + 26717364-50cf-42d1-8185-29bf893ab110 + + + + + + +''' + + def security_group_to_nwfilter_xml(self, security_group_id): + security_group = db.security_group_get_by_id({}, security_group_id) + rule_xml = "" + for rule in security_group.rules: + rule_xml += "" + if rule.cidr: + rule_xml += ("") % \ + (rule.cidr, rule.protocol, + rule.from_port, rule.to_port) + rule_xml += "" + xml = '''%s''' % (security_group_id, rule_xml,) + return xml -- cgit From e53676bb32b70ff01ca27c310e558b651590be3d Mon Sep 17 00:00:00 2001 From: Devin Carlen Date: Fri, 10 Sep 2010 15:26:13 -0700 Subject: Refactored to security group api to support projects --- nova/virt/libvirt_conn.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova/virt') diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index 6f708bb80..09c94577c 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -492,7 +492,7 @@ class NWFilterFirewall(object): ''' def security_group_to_nwfilter_xml(self, security_group_id): - security_group = db.security_group_get_by_id({}, security_group_id) + security_group = db.security_group_get({}, security_group_id) rule_xml = "" for rule in security_group.rules: rule_xml += "" -- cgit From 2a782110bc51f147bdb35264445badac3b3e8e65 Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Mon, 13 Sep 2010 11:45:28 +0200 Subject: Filters all get defined when running an instance. --- nova/virt/libvirt.qemu.xml.template | 2 +- nova/virt/libvirt.uml.xml.template | 2 +- nova/virt/libvirt_conn.py | 74 +++++++++++++++++++++++++++++++++++-- 3 files changed, 72 insertions(+), 6 deletions(-) (limited to 'nova/virt') diff --git a/nova/virt/libvirt.qemu.xml.template b/nova/virt/libvirt.qemu.xml.template index 5d3755b65..cbf501f9c 100644 --- a/nova/virt/libvirt.qemu.xml.template +++ b/nova/virt/libvirt.qemu.xml.template @@ -20,7 +20,7 @@ - + diff --git a/nova/virt/libvirt.uml.xml.template b/nova/virt/libvirt.uml.xml.template index 1000da5ab..2030b87d2 100644 --- a/nova/virt/libvirt.uml.xml.template +++ b/nova/virt/libvirt.uml.xml.template @@ -14,7 +14,7 @@ - + diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index 09c94577c..89ede1d1a 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -27,6 +27,7 @@ import shutil from twisted.internet import defer from twisted.internet import task +from twisted.internet import threads from nova import db from nova import exception @@ -216,6 +217,7 @@ class LibvirtConnection(object): instance['id'], power_state.NOSTATE, 'launching') + yield NWFilterFirewall(self._conn).setup_nwfilters_for_instance(instance) yield self._create_image(instance, xml) yield self._conn.createXML(xml, 0) # TODO(termie): this should actually register @@ -442,7 +444,6 @@ class LibvirtConnection(object): domain = self._conn.lookupByName(instance_name) return domain.interfaceStats(interface) - class NWFilterFirewall(object): """ This class implements a network filtering mechanism versatile @@ -467,6 +468,14 @@ class NWFilterFirewall(object): the nodes with instances in the security group to refresh the security group. + Each instance has its own NWFilter, which references the above + mentioned security group NWFilters. This was done because + interfaces can only reference one filter while filters can + reference multiple other filters. This has the added benefit of + actually being able to add and remove security groups from an + instance at run time. This functionality is not exposed anywhere, + though. + Outstanding questions: The name is unique, so would there be any good reason to sync @@ -477,12 +486,14 @@ class NWFilterFirewall(object): redundancy. """ - def __init__(self): - pass + def __init__(self, get_connection): + self._conn = get_connection + def nova_base_filter(self): return ''' 26717364-50cf-42d1-8185-29bf893ab110 + @@ -491,6 +502,60 @@ class NWFilterFirewall(object): ''' + + def setup_nwfilters_for_instance(self, instance): + """ + Creates an NWFilter for the given instance. In the process, + it makes sure the filters for the security groups as well as + the base filter are all in place. + """ + + d = self.ensure_base_filter() + + nwfilter_xml = ("\n" + + " \n" + ) % instance['name'] + + for security_group in instance.security_groups: + d.addCallback(lambda _:self.ensure_security_group_filter(security_group.id)) + + nwfilter_xml += (" \n" + ) % security_group.id + nwfilter_xml += "" + + d.addCallback(lambda _: threads.deferToThread( + self._conn.nwfilterDefineXML, + nwfilter_xml)) + return d + + + def _nwfilter_name_for_security_group(self, security_group_id): + return 'nova-secgroup-%d' % (security_group_id,) + + + def ensure_filter(self, name, xml_generator): + def _already_exists_check(filterlist, filter): + return filter in filterlist + def _define_if_not_exists(exists, xml_generator): + if not exists: + xml = xml_generator() + return threads.deferToThread(self._conn.nwfilterDefineXML, xml) + d = threads.deferToThread(self._conn.listNWFilter) + d.addCallback(_already_exists_check, name) + d.addCallback(_define_if_not_exists, xml_generator) + return d + + + def ensure_base_filter(self): + return self.ensure_filter('nova-base-filter', self.nova_base_filter) + + + def ensure_security_group_filter(self, security_group_id): + return self.ensure_filter( + self._nwfilter_name_for_security_group(security_group_id), + lambda:self.security_group_to_nwfilter_xml(security_group_id)) + + def security_group_to_nwfilter_xml(self, security_group_id): security_group = db.security_group_get({}, security_group_id) rule_xml = "" @@ -498,7 +563,8 @@ class NWFilterFirewall(object): rule_xml += "" if rule.cidr: rule_xml += ("") % \ + "dstportstart='%s' dstportend='%s' />" + + "priority='900'\n") % \ (rule.cidr, rule.protocol, rule.from_port, rule.to_port) rule_xml += "" -- cgit From 077fc783c4f94de427da98818d262aeb09a31044 Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Mon, 13 Sep 2010 12:04:06 +0200 Subject: (Untested) Make changes to security group rules propagate to the relevant compute nodes. --- nova/virt/libvirt_conn.py | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) (limited to 'nova/virt') diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index 89ede1d1a..a343267dc 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -444,6 +444,12 @@ class LibvirtConnection(object): domain = self._conn.lookupByName(instance_name) return domain.interfaceStats(interface) + + def refresh_security_group(self, security_group_id): + fw = self.NWFilterFirewall(self._conn) + fw.ensure_security_group_filter(security_group_id, override=True) + + class NWFilterFirewall(object): """ This class implements a network filtering mechanism versatile @@ -533,27 +539,32 @@ class NWFilterFirewall(object): return 'nova-secgroup-%d' % (security_group_id,) - def ensure_filter(self, name, xml_generator): - def _already_exists_check(filterlist, filter): - return filter in filterlist - def _define_if_not_exists(exists, xml_generator): - if not exists: - xml = xml_generator() - return threads.deferToThread(self._conn.nwfilterDefineXML, xml) - d = threads.deferToThread(self._conn.listNWFilter) - d.addCallback(_already_exists_check, name) + def define_filter(self, name, xml_generator, override=False): + if not override: + def _already_exists_check(filterlist, filter): + return filter in filterlist + def _define_if_not_exists(exists, xml_generator): + if not exists: + xml = xml_generator() + return threads.deferToThread(self._conn.nwfilterDefineXML, xml) + d = threads.deferToThread(self._conn.listNWFilter) + d.addCallback(_already_exists_check, name) + else: + # Pretend we looked it up and it wasn't defined + d = defer.succeed(False) d.addCallback(_define_if_not_exists, xml_generator) return d def ensure_base_filter(self): - return self.ensure_filter('nova-base-filter', self.nova_base_filter) + return self.define_filter('nova-base-filter', self.nova_base_filter) - def ensure_security_group_filter(self, security_group_id): - return self.ensure_filter( + def ensure_security_group_filter(self, security_group_id, override=False): + return self.define_filter( self._nwfilter_name_for_security_group(security_group_id), - lambda:self.security_group_to_nwfilter_xml(security_group_id)) + lambda:self.security_group_to_nwfilter_xml(security_group_id), + override=override) def security_group_to_nwfilter_xml(self, security_group_id): -- cgit From b15bde79b71e474d96674c8eae4108ac9c063731 Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Mon, 13 Sep 2010 14:18:08 +0200 Subject: Fix call to listNWFilters --- nova/virt/libvirt_conn.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova/virt') diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index a343267dc..2e1dfcefc 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -547,7 +547,7 @@ class NWFilterFirewall(object): if not exists: xml = xml_generator() return threads.deferToThread(self._conn.nwfilterDefineXML, xml) - d = threads.deferToThread(self._conn.listNWFilter) + d = threads.deferToThread(self._conn.listNWFilters) d.addCallback(_already_exists_check, name) else: # Pretend we looked it up and it wasn't defined -- cgit From 9c4b6612e65d548542b1bf37373200e4e6abc98d Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Mon, 13 Sep 2010 14:20:32 +0200 Subject: Correctly pass ip_address to templates. --- nova/virt/libvirt.qemu.xml.template | 4 ++-- nova/virt/libvirt.uml.xml.template | 4 ++-- nova/virt/libvirt_conn.py | 4 +++- 3 files changed, 7 insertions(+), 5 deletions(-) (limited to 'nova/virt') diff --git a/nova/virt/libvirt.qemu.xml.template b/nova/virt/libvirt.qemu.xml.template index cbf501f9c..d02aa9114 100644 --- a/nova/virt/libvirt.qemu.xml.template +++ b/nova/virt/libvirt.qemu.xml.template @@ -20,8 +20,8 @@ - - + + diff --git a/nova/virt/libvirt.uml.xml.template b/nova/virt/libvirt.uml.xml.template index 2030b87d2..bf3f2f86a 100644 --- a/nova/virt/libvirt.uml.xml.template +++ b/nova/virt/libvirt.uml.xml.template @@ -14,8 +14,8 @@ - - + + diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index 2e1dfcefc..00a80989f 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -322,6 +322,7 @@ class LibvirtConnection(object): network = db.project_get_network(None, instance['project_id']) # FIXME(vish): stick this in db instance_type = instance_types.INSTANCE_TYPES[instance['instance_type']] + ip_address = db.instance_get_fixed_address({}, instance['id']) xml_info = {'type': FLAGS.libvirt_type, 'name': instance['name'], 'basepath': os.path.join(FLAGS.instances_path, @@ -329,7 +330,8 @@ class LibvirtConnection(object): 'memory_kb': instance_type['memory_mb'] * 1024, 'vcpus': instance_type['vcpus'], 'bridge_name': network['bridge'], - 'mac_address': instance['mac_address']} + 'mac_address': instance['mac_address'], + 'ip_address': ip_address } libvirt_xml = self.libvirt_xml % xml_info logging.debug('instance %s: finished toXML method', instance['name']) -- cgit From 01a041dd732ae9c56533f6eac25f08c34917d733 Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Tue, 14 Sep 2010 15:17:52 +0200 Subject: Fix up rule generation. It turns out nwfilter gets very, very wonky indeed if you mix rules and rules. Setting a TCP rule adds an early rule to ebtables that ends up overriding the rules which are last in that table. --- nova/virt/libvirt_conn.py | 41 +++++++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 14 deletions(-) (limited to 'nova/virt') diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index 00a80989f..aaa2c69b6 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -290,7 +290,6 @@ class LibvirtConnection(object): address = db.instance_get_fixed_address(None, inst['id']) with open(FLAGS.injected_network_template) as f: net = f.read() % {'address': address, - 'network': network_ref['network'], 'netmask': network_ref['netmask'], 'gateway': network_ref['gateway'], 'broadcast': network_ref['broadcast'], @@ -448,7 +447,7 @@ class LibvirtConnection(object): def refresh_security_group(self, security_group_id): - fw = self.NWFilterFirewall(self._conn) + fw = NWFilterFirewall(self._conn) fw.ensure_security_group_filter(security_group_id, override=True) @@ -541,19 +540,26 @@ class NWFilterFirewall(object): return 'nova-secgroup-%d' % (security_group_id,) + # TODO(soren): Should override be the default (and should it even + # be optional? We save a bit of processing time in + # libvirt by only defining this conditionally, but + # we still have to go and ask libvirt if the group + # is already defined, and there's the off chance of + # of inconsitencies having snuck in which would get + # fixed by just redefining the filter. def define_filter(self, name, xml_generator, override=False): if not override: def _already_exists_check(filterlist, filter): return filter in filterlist - def _define_if_not_exists(exists, xml_generator): - if not exists: - xml = xml_generator() - return threads.deferToThread(self._conn.nwfilterDefineXML, xml) d = threads.deferToThread(self._conn.listNWFilters) d.addCallback(_already_exists_check, name) else: # Pretend we looked it up and it wasn't defined d = defer.succeed(False) + def _define_if_not_exists(exists, xml_generator): + if not exists: + xml = xml_generator() + return threads.deferToThread(self._conn.nwfilterDefineXML, xml) d.addCallback(_define_if_not_exists, xml_generator) return d @@ -573,13 +579,20 @@ class NWFilterFirewall(object): security_group = db.security_group_get({}, security_group_id) rule_xml = "" for rule in security_group.rules: - rule_xml += "" + rule_xml += "" if rule.cidr: - rule_xml += ("" + - "priority='900'\n") % \ - (rule.cidr, rule.protocol, - rule.from_port, rule.to_port) - rule_xml += "" - xml = '''%s''' % (security_group_id, rule_xml,) + rule_xml += "<%s srcipaddr='%s' " % (rule.protocol, rule.cidr) + if rule.protocol in ['tcp', 'udp']: + rule_xml += "dstportstart='%s' dstportend='%s' " % \ + (rule.from_port, rule.to_port) + elif rule.protocol == 'icmp': + logging.info('rule.protocol: %r, rule.from_port: %r, rule.to_port: %r' % (rule.protocol, rule.from_port, rule.to_port)) + if rule.from_port != -1: + rule_xml += "type='%s' " % rule.from_port + if rule.to_port != -1: + rule_xml += "code='%s' " % rule.to_port + + rule_xml += '/>\n' + rule_xml += "\n" + xml = '''%s''' % (security_group_id, rule_xml,) return xml -- cgit From 587b21cc00919cc29e2f815fc9de3e3ad6e6fa30 Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Tue, 14 Sep 2010 15:23:58 +0200 Subject: Leave out the network setting from the interfaces template. It does not get passed anymore. --- nova/virt/interfaces.template | 1 - 1 file changed, 1 deletion(-) (limited to 'nova/virt') diff --git a/nova/virt/interfaces.template b/nova/virt/interfaces.template index 11df301f6..87b92b84a 100644 --- a/nova/virt/interfaces.template +++ b/nova/virt/interfaces.template @@ -10,7 +10,6 @@ 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 -- cgit From 9dbdca83a8233110e94356415629ab9589b580d5 Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Mon, 27 Sep 2010 13:13:29 +0200 Subject: Allow DHCP requests through, pass the IP of the gateway as the dhcp server. --- nova/virt/libvirt.qemu.xml.template | 1 + nova/virt/libvirt.uml.xml.template | 1 + nova/virt/libvirt_conn.py | 6 +++++- 3 files changed, 7 insertions(+), 1 deletion(-) (limited to 'nova/virt') diff --git a/nova/virt/libvirt.qemu.xml.template b/nova/virt/libvirt.qemu.xml.template index d02aa9114..2538b1ade 100644 --- a/nova/virt/libvirt.qemu.xml.template +++ b/nova/virt/libvirt.qemu.xml.template @@ -22,6 +22,7 @@ + diff --git a/nova/virt/libvirt.uml.xml.template b/nova/virt/libvirt.uml.xml.template index bf3f2f86a..bb8b47911 100644 --- a/nova/virt/libvirt.uml.xml.template +++ b/nova/virt/libvirt.uml.xml.template @@ -16,6 +16,7 @@ + diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index 4c4c7980b..93f6977d4 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -319,6 +319,8 @@ class LibvirtConnection(object): # FIXME(vish): stick this in db instance_type = instance_types.INSTANCE_TYPES[instance['instance_type']] ip_address = db.instance_get_fixed_address({}, instance['id']) + # Assume that the gateway also acts as the dhcp server. + dhcp_server = network['gateway'] xml_info = {'type': FLAGS.libvirt_type, 'name': instance['name'], 'basepath': os.path.join(FLAGS.instances_path, @@ -327,7 +329,8 @@ class LibvirtConnection(object): 'vcpus': instance_type['vcpus'], 'bridge_name': network['bridge'], 'mac_address': instance['mac_address'], - 'ip_address': ip_address } + 'ip_address': ip_address, + 'dhcp_server': dhcp_server } libvirt_xml = self.libvirt_xml % xml_info logging.debug('instance %s: finished toXML method', instance['name']) @@ -498,6 +501,7 @@ class NWFilterFirewall(object): return ''' 26717364-50cf-42d1-8185-29bf893ab110 + -- cgit From ab31fa628f4d9148aae8d42bbb41d721716c18e3 Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Mon, 27 Sep 2010 21:49:53 +0200 Subject: Clean up nwfilter code. Move our filters into the ipv4 chain. --- nova/virt/libvirt_conn.py | 99 ++++++++++++++++++----------------------------- 1 file changed, 38 insertions(+), 61 deletions(-) (limited to 'nova/virt') diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index 93f6977d4..558854c38 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -497,20 +497,36 @@ class NWFilterFirewall(object): self._conn = get_connection - def nova_base_filter(self): - return ''' - 26717364-50cf-42d1-8185-29bf893ab110 - - - - - - - - -''' + nova_base_filter = ''' + 26717364-50cf-42d1-8185-29bf893ab110 + + + + + + + ''' + + nova_base_ipv4_filter = ''' + + ''' + + + nova_base_ipv6_filter = ''' + + ''' + + + def _define_filter(self, xml): + if callable(xml): + xml = xml() + d = threads.deferToThread(self._conn.nwfilterDefineXML, xml) + return d + @defer.inlineCallbacks def setup_nwfilters_for_instance(self, instance): """ Creates an NWFilter for the given instance. In the process, @@ -518,63 +534,24 @@ class NWFilterFirewall(object): the base filter are all in place. """ - d = self.ensure_base_filter() + yield self._define_filter(self.nova_base_ipv4_filter) + yield self._define_filter(self.nova_base_ipv6_filter) + yield self._define_filter(self.nova_base_filter) nwfilter_xml = ("\n" + - " \n" + " \n" ) % instance['name'] for security_group in instance.security_groups: - d.addCallback(lambda _:self.ensure_security_group_filter(security_group.id)) + yield self._define_filter( + self.security_group_to_nwfilter_xml(security_group['id'])) nwfilter_xml += (" \n" ) % security_group.id nwfilter_xml += "" - d.addCallback(lambda _: threads.deferToThread( - self._conn.nwfilterDefineXML, - nwfilter_xml)) - return d - - - def _nwfilter_name_for_security_group(self, security_group_id): - return 'nova-secgroup-%d' % (security_group_id,) - - - # TODO(soren): Should override be the default (and should it even - # be optional? We save a bit of processing time in - # libvirt by only defining this conditionally, but - # we still have to go and ask libvirt if the group - # is already defined, and there's the off chance of - # of inconsitencies having snuck in which would get - # fixed by just redefining the filter. - def define_filter(self, name, xml_generator, override=False): - if not override: - def _already_exists_check(filterlist, filter): - return filter in filterlist - d = threads.deferToThread(self._conn.listNWFilters) - d.addCallback(_already_exists_check, name) - else: - # Pretend we looked it up and it wasn't defined - d = defer.succeed(False) - def _define_if_not_exists(exists, xml_generator): - if not exists: - xml = xml_generator() - return threads.deferToThread(self._conn.nwfilterDefineXML, xml) - d.addCallback(_define_if_not_exists, xml_generator) - return d - - - def ensure_base_filter(self): - return self.define_filter('nova-base-filter', self.nova_base_filter) - - - def ensure_security_group_filter(self, security_group_id, override=False): - return self.define_filter( - self._nwfilter_name_for_security_group(security_group_id), - lambda:self.security_group_to_nwfilter_xml(security_group_id), - override=override) - + yield self._define_filter(nwfilter_xml) + return def security_group_to_nwfilter_xml(self, security_group_id): security_group = db.security_group_get({}, security_group_id) @@ -593,7 +570,7 @@ class NWFilterFirewall(object): if rule.to_port != -1: rule_xml += "code='%s' " % rule.to_port - rule_xml += '/>\n' + rule_xml += '/>\n' rule_xml += "\n" - xml = '''%s''' % (security_group_id, rule_xml,) + xml = '''%s''' % (security_group_id, rule_xml,) return xml -- cgit From e705b666679ecccfc3e91c8029f2c646849509ee Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Mon, 27 Sep 2010 21:57:13 +0200 Subject: Recreate ensure_security_group_filter. Needed for refresh. --- nova/virt/libvirt_conn.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'nova/virt') diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index 558854c38..a7370e036 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -448,7 +448,7 @@ class LibvirtConnection(object): def refresh_security_group(self, security_group_id): fw = NWFilterFirewall(self._conn) - fw.ensure_security_group_filter(security_group_id, override=True) + fw.ensure_security_group_filter(security_group_id) class NWFilterFirewall(object): @@ -543,16 +543,20 @@ class NWFilterFirewall(object): ) % instance['name'] for security_group in instance.security_groups: - yield self._define_filter( - self.security_group_to_nwfilter_xml(security_group['id'])) + yield self.ensure_security_group_filter(security_group['id']) nwfilter_xml += (" \n" - ) % security_group.id + ) % security_group['id'] nwfilter_xml += "" yield self._define_filter(nwfilter_xml) return + def ensure_security_group_filter(self, security_group_id): + return self._define_filter( + self.security_group_to_nwfilter_xml(security_group_id)) + + def security_group_to_nwfilter_xml(self, security_group_id): security_group = db.security_group_get({}, security_group_id) rule_xml = "" -- cgit From 9140cd991e5507f65ff1d6a608bd8fd4c9956dbf Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Mon, 27 Sep 2010 22:00:17 +0200 Subject: Set priority of security group rules to 300 to make sure they override the defaults. --- nova/virt/libvirt_conn.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova/virt') diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index a7370e036..d90853084 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -561,7 +561,7 @@ class NWFilterFirewall(object): security_group = db.security_group_get({}, security_group_id) rule_xml = "" for rule in security_group.rules: - rule_xml += "" + rule_xml += "" if rule.cidr: rule_xml += "<%s srcipaddr='%s' " % (rule.protocol, rule.cidr) if rule.protocol in ['tcp', 'udp']: -- cgit From 574aa4bb03c6e79c204d73a8f2a146460cbdb848 Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Tue, 28 Sep 2010 00:21:36 +0200 Subject: This is getting ridiculous. --- nova/virt/libvirt_conn.py | 50 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 40 insertions(+), 10 deletions(-) (limited to 'nova/virt') diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index d90853084..854fa6761 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -503,20 +503,49 @@ class NWFilterFirewall(object): + ''' - nova_base_ipv4_filter = ''' - - ''' - - - nova_base_ipv6_filter = ''' - - ''' + nova_dhcp_filter = ''' + 891e4787-e5c0-d59b-cbd6-41bc3c6b36fc + + + + + + + ''' + + def nova_base_ipv4_filter(self): + retval = "" + for protocol in ['tcp', 'udp', 'icmp']: + for direction,action in [('out','accept'), + ('in','drop')]: + retval += """ + <%s /> + """ % (action, direction, protocol) + retval += '' + return retval + + + def nova_base_ipv6_filter(self): + retval = "" + for protocol in ['tcp', 'udp', 'icmp']: + for direction,action in [('out','accept'), + ('in','drop')]: + retval += """ + <%s-ipv6 /> + """ % (action, direction, protocol) + retval += '' + return retval def _define_filter(self, xml): @@ -536,6 +565,7 @@ class NWFilterFirewall(object): yield self._define_filter(self.nova_base_ipv4_filter) yield self._define_filter(self.nova_base_ipv6_filter) + yield self._define_filter(self.nova_dhcp_filter) yield self._define_filter(self.nova_base_filter) nwfilter_xml = ("\n" + -- cgit From 886534ba4d0281afc0d169546a8d55d3a5c8ece9 Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Tue, 28 Sep 2010 09:07:48 +0200 Subject: Make the incoming blocking rules take precedence over the output accept rules. --- nova/virt/libvirt_conn.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'nova/virt') diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index 854fa6761..40a921743 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -527,11 +527,11 @@ class NWFilterFirewall(object): def nova_base_ipv4_filter(self): retval = "" for protocol in ['tcp', 'udp', 'icmp']: - for direction,action in [('out','accept'), - ('in','drop')]: - retval += """ + for direction,action,priority in [('out','accept', 400), + ('in','drop', 399)]: + retval += """ <%s /> - """ % (action, direction, protocol) + """ % (action, direction, protocol, priority) retval += '' return retval @@ -539,11 +539,12 @@ class NWFilterFirewall(object): def nova_base_ipv6_filter(self): retval = "" for protocol in ['tcp', 'udp', 'icmp']: - for direction,action in [('out','accept'), - ('in','drop')]: - retval += """ + for direction,action,priority in [('out','accept',400), + ('in','drop',399)]: + retval += """ <%s-ipv6 /> - """ % (action, direction, protocol) + """ % (action, direction, + protocol, priority) retval += '' return retval -- cgit From 0dcf2e7e593cce4be1654fb4923ec4bb4524198f Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Tue, 28 Sep 2010 09:47:25 +0200 Subject: Make sure arguments to string format are in the correct order. --- nova/virt/libvirt_conn.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'nova/virt') diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index 40a921743..c86f3ffb7 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -531,7 +531,8 @@ class NWFilterFirewall(object): ('in','drop', 399)]: retval += """ <%s /> - """ % (action, direction, protocol, priority) + """ % (action, direction, + priority, protocol) retval += '' return retval @@ -544,7 +545,7 @@ class NWFilterFirewall(object): retval += """ <%s-ipv6 /> """ % (action, direction, - protocol, priority) + priority, protocol) retval += '' return retval -- cgit From a86507b3224eb051fea97f65bd5653758fa91668 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Wed, 29 Sep 2010 06:17:39 -0700 Subject: fix ordering of rules to actually allow out and drop in --- nova/virt/libvirt_conn.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'nova/virt') diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index c86f3ffb7..9d889cf29 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -527,8 +527,8 @@ class NWFilterFirewall(object): def nova_base_ipv4_filter(self): retval = "" for protocol in ['tcp', 'udp', 'icmp']: - for direction,action,priority in [('out','accept', 400), - ('in','drop', 399)]: + for direction,action,priority in [('out','accept', 399), + ('inout','drop', 400)]: retval += """ <%s /> """ % (action, direction, @@ -540,8 +540,8 @@ class NWFilterFirewall(object): def nova_base_ipv6_filter(self): retval = "" for protocol in ['tcp', 'udp', 'icmp']: - for direction,action,priority in [('out','accept',400), - ('in','drop',399)]: + for direction,action,priority in [('out','accept',399), + ('inout','drop',400)]: retval += """ <%s-ipv6 /> """ % (action, direction, -- cgit From 12e43d9deb3984d2b7ccc91490ffa4c13eedbe2b Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Sat, 2 Oct 2010 16:55:57 +0100 Subject: Bug #653651: XenAPI support completely broken by orm-refactor merge Matches changes in the database / model layer with corresponding fixes to nova.virt.xenapi. --- nova/virt/xenapi.py | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-) (limited to 'nova/virt') diff --git a/nova/virt/xenapi.py b/nova/virt/xenapi.py index 0d06b1fce..118e0b687 100644 --- a/nova/virt/xenapi.py +++ b/nova/virt/xenapi.py @@ -42,10 +42,12 @@ from twisted.internet import defer from twisted.internet import reactor from twisted.internet import task +from nova import db from nova import flags from nova import process from nova import utils from nova.auth.manager import AuthManager +from nova.compute import instance_types from nova.compute import power_state from nova.virt import images @@ -113,32 +115,24 @@ class XenAPIConnection(object): raise Exception('Attempted to create non-unique name %s' % instance.name) - if 'bridge_name' in instance.datamodel: - network_ref = \ - yield self._find_network_with_bridge( - instance.datamodel['bridge_name']) - else: - network_ref = None - - if 'mac_address' in instance.datamodel: - mac_address = instance.datamodel['mac_address'] - else: - mac_address = '' + network = db.project_get_network(None, instance.project_id) + network_ref = \ + yield self._find_network_with_bridge(network.bridge) - user = AuthManager().get_user(instance.datamodel['user_id']) - project = AuthManager().get_project(instance.datamodel['project_id']) + user = AuthManager().get_user(instance.user_id) + project = AuthManager().get_project(instance.project_id) vdi_uuid = yield self._fetch_image( - instance.datamodel['image_id'], user, project, True) + instance.image_id, user, project, True) kernel = yield self._fetch_image( - instance.datamodel['kernel_id'], user, project, False) + instance.kernel_id, user, project, False) ramdisk = yield self._fetch_image( - instance.datamodel['ramdisk_id'], user, project, False) + instance.ramdisk_id, user, project, False) vdi_ref = yield self._call_xenapi('VDI.get_by_uuid', vdi_uuid) vm_ref = yield self._create_vm(instance, kernel, ramdisk) yield self._create_vbd(vm_ref, vdi_ref, 0, True) if network_ref: - yield self._create_vif(vm_ref, network_ref, mac_address) + yield self._create_vif(vm_ref, network_ref, instance.mac_address) logging.debug('Starting VM %s...', vm_ref) yield self._call_xenapi('VM.start', vm_ref, False, False) logging.info('Spawning VM %s created %s.', instance.name, vm_ref) @@ -148,8 +142,9 @@ class XenAPIConnection(object): """Create a VM record. Returns a Deferred that gives the new VM reference.""" - mem = str(long(instance.datamodel['memory_kb']) * 1024) - vcpus = str(instance.datamodel['vcpus']) + instance_type = instance_types.INSTANCE_TYPES[instance.instance_type] + mem = str(long(instance_type['memory_mb']) * 1024 * 1024) + vcpus = str(instance_type['vcpus']) rec = { 'name_label': instance.name, 'name_description': '', -- cgit From a4720c03a8260fb920035d072799d3ecc478db99 Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Mon, 4 Oct 2010 21:58:22 +0200 Subject: Merge security group related changes from lp:~anso/nova/deploy --- nova/virt/libvirt_conn.py | 39 +++++++++++++++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 4 deletions(-) (limited to 'nova/virt') diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index 9d889cf29..319f7d2af 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -25,6 +25,7 @@ import logging import os import shutil +import IPy from twisted.internet import defer from twisted.internet import task from twisted.internet import threads @@ -34,6 +35,7 @@ from nova import exception from nova import flags from nova import process from nova import utils +#from nova.api import context from nova.auth import manager from nova.compute import disk from nova.compute import instance_types @@ -61,6 +63,9 @@ flags.DEFINE_string('libvirt_uri', '', 'Override the default libvirt URI (which is dependent' ' on libvirt_type)') +flags.DEFINE_bool('allow_project_net_traffic', + True, + 'Whether to allow in project network traffic') def get_connection(read_only): @@ -135,7 +140,7 @@ class LibvirtConnection(object): d.addCallback(lambda _: self._cleanup(instance)) # FIXME: What does this comment mean? # TODO(termie): short-circuit me for tests - # WE'LL save this for when we do shutdown, + # WE'LL save this for when we do shutdown, # instead of destroy - but destroy returns immediately timer = task.LoopingCall(f=None) def _wait_for_shutdown(): @@ -550,6 +555,16 @@ class NWFilterFirewall(object): return retval + def nova_project_filter(self, project, net, mask): + retval = "" % project + for protocol in ['tcp', 'udp', 'icmp']: + retval += """ + <%s srcipaddr='%s' srcipmask='%s' /> + """ % (protocol, net, mask) + retval += '' + return retval + + def _define_filter(self, xml): if callable(xml): xml = xml() @@ -557,6 +572,11 @@ class NWFilterFirewall(object): return d + @staticmethod + def _get_net_and_mask(cidr): + net = IPy.IP(cidr) + return str(net.net()), str(net.netmask()) + @defer.inlineCallbacks def setup_nwfilters_for_instance(self, instance): """ @@ -570,9 +590,19 @@ class NWFilterFirewall(object): yield self._define_filter(self.nova_dhcp_filter) yield self._define_filter(self.nova_base_filter) - nwfilter_xml = ("\n" + + nwfilter_xml = ("\n" + " \n" - ) % instance['name'] + ) % instance['name'] + + if FLAGS.allow_project_net_traffic: + network_ref = db.project_get_network({}, instance['project_id']) + net, mask = self._get_net_and_mask(network_ref['cidr']) + project_filter = self.nova_project_filter(instance['project_id'], + net, mask) + yield self._define_filter(project_filter) + + nwfilter_xml += (" \n" + ) % instance['project_id'] for security_group in instance.security_groups: yield self.ensure_security_group_filter(security_group['id']) @@ -595,7 +625,8 @@ class NWFilterFirewall(object): for rule in security_group.rules: rule_xml += "" if rule.cidr: - rule_xml += "<%s srcipaddr='%s' " % (rule.protocol, rule.cidr) + net, mask = self._get_net_and_mask(rule.cidr) + rule_xml += "<%s srcipaddr='%s' srcipmask='%s' " % (rule.protocol, net, mask) if rule.protocol in ['tcp', 'udp']: rule_xml += "dstportstart='%s' dstportend='%s' " % \ (rule.from_port, rule.to_port) -- cgit From 8f524607856dbf4cecf7c7503e53e14c42888307 Mon Sep 17 00:00:00 2001 From: Hisaki Ohara Date: Wed, 6 Oct 2010 18:04:18 +0900 Subject: Defined images_path for nova-compute. Without its setting, it fails to launch instances by exception at _fetch_local_image. --- nova/virt/images.py | 3 +++ 1 file changed, 3 insertions(+) (limited to 'nova/virt') diff --git a/nova/virt/images.py b/nova/virt/images.py index a60bcc4c1..9ba5b7890 100644 --- a/nova/virt/images.py +++ b/nova/virt/images.py @@ -26,6 +26,7 @@ import time import urlparse from nova import flags +from nova import utils from nova import process from nova.auth import manager from nova.auth import signer @@ -34,6 +35,8 @@ from nova.auth import signer FLAGS = flags.FLAGS flags.DEFINE_bool('use_s3', True, 'whether to get images from s3 or use local copy') +flags.DEFINE_string('images_path', utils.abspath('../images'), + 'path to decrypted images') def fetch(image, path, user, project): -- cgit From b7028c0d0262d3d4395077a8bd2d95664c6bf16e Mon Sep 17 00:00:00 2001 From: Hisaki Ohara Date: Thu, 7 Oct 2010 23:03:43 +0900 Subject: Imported images_path from nova.objectstore for nova-compute. Without its setting, it fails to launch instances by exception at _fetch_local_image. --- nova/virt/images.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'nova/virt') diff --git a/nova/virt/images.py b/nova/virt/images.py index 9ba5b7890..dc50764d9 100644 --- a/nova/virt/images.py +++ b/nova/virt/images.py @@ -26,17 +26,15 @@ import time import urlparse from nova import flags -from nova import utils from nova import process from nova.auth import manager from nova.auth import signer +from nova.objectstore import image FLAGS = flags.FLAGS flags.DEFINE_bool('use_s3', True, 'whether to get images from s3 or use local copy') -flags.DEFINE_string('images_path', utils.abspath('../images'), - 'path to decrypted images') def fetch(image, path, user, project): -- cgit