From 562ad1933593d1d835b1765aa2aca4ea369e7263 Mon Sep 17 00:00:00 2001 From: Kazuki OIKAWA Date: Thu, 27 Aug 2015 17:31:39 +0900 Subject: [PATCH] Adds IPv6 support to auto security group Heat infra-engine uses AWS::EC2::SecurityGroup. But AWS::EC2::SecurityGroup for Neutron doesn't support IPv6. This patch migrate from AWS::EC2::SecurityGroup to OS::Neutron::SecurityGroup, for Neutron. Change-Id: I04e4aacdd843d3efa388f9527efec2e141eabbbb Closes-Bug: #1488452 --- sahara/service/heat/templates.py | 48 +++++++++---- .../tests/unit/service/heat/test_templates.py | 68 +++++++++++++++++++ 2 files changed, 101 insertions(+), 15 deletions(-) diff --git a/sahara/service/heat/templates.py b/sahara/service/heat/templates.py index a0eb1d3471..232e8ba111 100644 --- a/sahara/service/heat/templates.py +++ b/sahara/service/heat/templates.py @@ -201,37 +201,55 @@ class ClusterStack(object): security_group_description = ( "Auto security group created by Sahara for Node Group " "'%s' of cluster '%s'." % (ng.name, ng.cluster.name)) - rules = self._serialize_auto_security_group_rules(ng) + + if CONF.use_neutron: + res_type = "OS::Neutron::SecurityGroup" + desc_key = "description" + rules_key = "rules" + create_rule = lambda ip_version, cidr, proto, from_port, to_port: { + "ethertype": "IPv{}".format(ip_version), + "remote_ip_prefix": cidr, + "protocol": proto, + "port_range_min": six.text_type(from_port), + "port_range_max": six.text_type(to_port)} + else: + res_type = "AWS::EC2::SecurityGroup" + desc_key = "GroupDescription" + rules_key = "SecurityGroupIngress" + create_rule = lambda _, cidr, proto, from_port, to_port: { + "CidrIp": cidr, + "IpProtocol": proto, + "FromPort": six.text_type(from_port), + "ToPort": six.text_type(to_port)} + + rules = self._serialize_auto_security_group_rules(ng, create_rule) return { security_group_name: { - "type": "AWS::EC2::SecurityGroup", + "type": res_type, "properties": { - "GroupDescription": security_group_description, - "SecurityGroupIngress": rules + desc_key: security_group_description, + rules_key: rules } } } - def _serialize_auto_security_group_rules(self, ng): - create_rule = lambda cidr, proto, from_port, to_port: { - "CidrIp": cidr, - "IpProtocol": proto, - "FromPort": six.text_type(from_port), - "ToPort": six.text_type(to_port)} - + def _serialize_auto_security_group_rules(self, ng, create_rule): rules = [] for port in ng.open_ports: - rules.append(create_rule('0.0.0.0/0', 'tcp', port, port)) + rules.append(create_rule(4, '0.0.0.0/0', 'tcp', port, port)) + rules.append(create_rule(6, '::/0', 'tcp', port, port)) - rules.append(create_rule('0.0.0.0/0', 'tcp', SSH_PORT, SSH_PORT)) + rules.append(create_rule(4, '0.0.0.0/0', 'tcp', SSH_PORT, SSH_PORT)) + rules.append(create_rule(6, '::/0', 'tcp', SSH_PORT, SSH_PORT)) # open all traffic for private networks if CONF.use_neutron: for cidr in neutron.get_private_network_cidrs(ng.cluster): + ip_ver = 6 if ':' in cidr else 4 for protocol in ['tcp', 'udp']: - rules.append(create_rule(cidr, protocol, 1, 65535)) - rules.append(create_rule(cidr, 'icmp', -1, -1)) + rules.append(create_rule(ip_ver, cidr, protocol, 1, 65535)) + rules.append(create_rule(ip_ver, cidr, 'icmp', 0, 255)) return rules diff --git a/sahara/tests/unit/service/heat/test_templates.py b/sahara/tests/unit/service/heat/test_templates.py index 01fbdb7ae2..bd5771b567 100644 --- a/sahara/tests/unit/service/heat/test_templates.py +++ b/sahara/tests/unit/service/heat/test_templates.py @@ -13,6 +13,9 @@ # See the License for the specific language governing permissions and # limitations under the License. +import mock + +from sahara.conductor import resource as r from sahara.service.heat import templates as h from sahara.tests.unit import base from sahara.tests.unit import testutils as tu @@ -93,6 +96,71 @@ class TestClusterTemplate(base.SaharaWithDbTestCase): actual = heat_template._get_security_groups(ng2) self.assertEqual(expected, actual) + def _generate_auto_security_group_template(self, use_neutron): + self.override_config('use_neutron', use_neutron) + ng1, ng2 = self._make_node_groups('floating') + cluster = self._make_cluster('private_net', ng1, ng2) + ng1['cluster'] = cluster + ng2['cluster'] = cluster + ng1 = r.NodeGroupResource(ng1) + ng2 = r.NodeGroupResource(ng2) + heat_template = self._make_heat_template(cluster, ng1, ng2) + return heat_template._serialize_auto_security_group(ng1) + + @mock.patch('sahara.utils.openstack.neutron.get_private_network_cidrs') + def test_serialize_auto_security_group_neutron(self, patched): + ipv4_cidr = '192.168.0.0/24' + ipv6_cidr = 'fe80::/64' + patched.side_effect = lambda cluster: [ipv4_cidr, ipv6_cidr] + expected_rules = [ + ('0.0.0.0/0', 'IPv4', 'tcp', '22', '22'), + ('::/0', 'IPv6', 'tcp', '22', '22'), + (ipv4_cidr, 'IPv4', 'tcp', '1', '65535'), + (ipv4_cidr, 'IPv4', 'udp', '1', '65535'), + (ipv4_cidr, 'IPv4', 'icmp', '0', '255'), + (ipv6_cidr, 'IPv6', 'tcp', '1', '65535'), + (ipv6_cidr, 'IPv6', 'udp', '1', '65535'), + (ipv6_cidr, 'IPv6', 'icmp', '0', '255'), + ] + expected = {'cluster-master-1': { + 'type': 'OS::Neutron::SecurityGroup', + 'properties': { + 'description': 'Auto security group created by Sahara ' + 'for Node Group \'master\' of cluster \'cluster\'.', + 'rules': [{ + 'remote_ip_prefix': rule[0], + 'ethertype': rule[1], + 'protocol': rule[2], + 'port_range_min': rule[3], + 'port_range_max': rule[4] + } for rule in expected_rules] + } + }} + actual = self._generate_auto_security_group_template(True) + self.assertEqual(expected, actual) + + def test_serialize_auto_security_group_nova_network(self): + expected = {'cluster-master-1': { + 'type': 'AWS::EC2::SecurityGroup', + 'properties': { + 'GroupDescription': 'Auto security group created by Sahara' + ' for Node Group \'master\' of cluster \'cluster\'.', + 'SecurityGroupIngress': [{ + 'ToPort': '22', + 'CidrIp': '0.0.0.0/0', + 'FromPort': '22', + 'IpProtocol': 'tcp' + }, { + 'ToPort': '22', + 'CidrIp': '::/0', + 'FromPort': '22', + 'IpProtocol': 'tcp' + }] + } + }} + actual = self._generate_auto_security_group_template(False) + self.assertEqual(expected, actual) + def get_ud_generator(s): def generator(*args, **kwargs):