Issue: LIBCLOUD-466 Add ingress/egress VPC support to security group rules.
Signed-off-by: Tomaz Muraus <[email protected]> Project: http://git-wip-us.apache.org/repos/asf/libcloud/repo Commit: http://git-wip-us.apache.org/repos/asf/libcloud/commit/57393395 Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/57393395 Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/57393395 Branch: refs/heads/trunk Commit: 573933951172b0b23673dcb2689d1adc089dd144 Parents: 5e4233c Author: Chris DeRamus <[email protected]> Authored: Fri Dec 20 11:26:23 2013 -0500 Committer: Tomaz Muraus <[email protected]> Committed: Sat Dec 21 15:02:56 2013 +0100 ---------------------------------------------------------------------- libcloud/compute/drivers/ec2.py | 256 +++++++++++++++++++ .../ec2/authorize_security_group_egress.xml | 4 + .../ec2/revoke_security_group_egress.xml | 4 + .../ec2/revoke_security_group_ingress.xml | 4 + libcloud/test/compute/test_ec2.py | 32 +++ 5 files changed, 300 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/libcloud/blob/57393395/libcloud/compute/drivers/ec2.py ---------------------------------------------------------------------- diff --git a/libcloud/compute/drivers/ec2.py b/libcloud/compute/drivers/ec2.py index 2f8dcfe..805f025 100644 --- a/libcloud/compute/drivers/ec2.py +++ b/libcloud/compute/drivers/ec2.py @@ -776,6 +776,42 @@ class BaseEC2NodeDriver(NodeDriver): 'description': description, 'state': state}) + def _get_common_security_group_params(self, group_id, protocol, + from_port, to_port, cidr_ips, + group_pairs): + + params = {'GroupId': id, + 'IpPermissions.1.IpProtocol': protocol, + 'IpPermissions.1.FromPort': from_port, + 'IpPermissions.1.ToPort': to_port} + + if cidr_ips is not None: + ip_ranges = {} + for index, cidr_ip in enumerate(cidr_ips, 1): + ip_ranges['IpPermissions.1.IpRanges.%s.CidrIp' + % (index)] = cidr_ip + + params.update(ip_ranges) + + if group_pairs is not None: + user_groups = {} + for index, group_pair in enumerate(group_pairs, 1): + if 'group_id' in group_pair.keys(): + user_groups['IpPermissions.1.Groups.%s.GroupId' + % (index)] = group_pair['group_id'] + + if 'group_name' in group_pair.keys(): + user_groups['IpPermissions.1.Groups.%s.GroupName' + % (index)] = group_pair['group_name'] + + if 'user_id' in group_pair.keys(): + user_groups['IpPermissions.1.Groups.%s.UserId' + % (index)] = group_pair['user_id'] + + params.update(user_groups) + + return params + def list_nodes(self, ex_node_ids=None): """ List all nodes @@ -1384,6 +1420,226 @@ class BaseEC2NodeDriver(NodeDriver): if e.args[0].find('InvalidPermission.Duplicate') == -1: raise e + def ex_authorize_security_group_ingress(self, id, from_port, to_port, + cidr_ips=None, group_pairs=None, + protocol='tcp'): + """ + Edit a Security Group to allow specific ingress traffic using + CIDR blocks or either a group ID, group name or user ID (account). + + :param id: The id of the security group to edit + :type id: ``str`` + + :param from_port: The beginning of the port range to open + :type from_port: ``int`` + + :param to_port: The end of the port range to open + :type to_port: ``int`` + + :param cidr_ips: The list of ip ranges to allow traffic for. + :type cidr_ips: ``list`` + + :param group_pairs: Source user/group pairs to allow traffic for. + More info can be found at http://goo.gl/stBHJF + + EC2 Classic Example: To allow access from any system + associated with the default group on account 1234567890 + + [{'group_name': 'default', 'user_id': '1234567890'}] + + VPC Example: Allow access from any system associated with + security group sg-47ad482e on your own account + + [{'group_id': ' sg-47ad482e'}] + :type group_pairs: ``list`` of ``dict`` + + :param protocol: tcp/udp/icmp + :type protocol: ``str`` + + :rtype: ``bool`` + """ + + params = self._get_common_security_group_params(id, + protocol, + from_port, + to_port, + cidr_ips, + group_pairs) + + params["Action"] = 'AuthorizeSecurityGroupIngress' + + result = self.connection.request(self.path, params=params).object + element = findtext(element=result, xpath='return', + namespace=NAMESPACE) + + return element == 'true' + + def ex_authorize_security_group_egress(self, id, from_port, to_port, + cidr_ips=None, group_pairs=None, + protocol='tcp'): + """ + Edit a Security Group to allow specific egress traffic using + CIDR blocks or either a group ID, group name or user ID (account). + This call is not supported for EC2 classic and only works for VPC + groups. + + :param id: The id of the security group to edit + :type id: ``str`` + + :param from_port: The beginning of the port range to open + :type from_port: ``int`` + + :param to_port: The end of the port range to open + :type to_port: ``int`` + + :param cidr_ips: The list of ip ranges to allow traffic for. + :type cidr_ips: ``list`` + + :param group_pairs: Source user/group pairs to allow traffic for. + More info can be found at http://goo.gl/stBHJF + + EC2 Classic Example: To allow access from any system + associated with the default group on account 1234567890 + + [{'group_name': 'default', 'user_id': '1234567890'}] + + VPC Example: Allow access from any system associated with + security group sg-47ad482e on your own account + + [{'group_id': ' sg-47ad482e'}] + :type group_pairs: ``list`` of ``dict`` + + :param protocol: tcp/udp/icmp + :type protocol: ``str`` + + :rtype: ``bool`` + """ + + params = self._get_common_security_group_params(id, + protocol, + from_port, + to_port, + cidr_ips, + group_pairs) + + params["Action"] = 'AuthorizeSecurityGroupEgress' + + result = self.connection.request(self.path, params=params).object + element = findtext(element=result, xpath='return', + namespace=NAMESPACE) + + return element == 'true' + + def ex_revoke_security_group_ingress(self, id, from_port, to_port, + cidr_ips=None, group_pairs=None, + protocol='tcp'): + """ + Edit a Security Group to revoke specific ingress traffic using + CIDR blocks or either a group ID, group name or user ID (account). + + :param id: The id of the security group to edit + :type id: ``str`` + + :param from_port: The beginning of the port range to open + :type from_port: ``int`` + + :param to_port: The end of the port range to open + :type to_port: ``int`` + + :param cidr_ips: The list of ip ranges to allow traffic for. + :type cidr_ips: ``list`` + + :param group_pairs: Source user/group pairs to allow traffic for. + More info can be found at http://goo.gl/stBHJF + + EC2 Classic Example: To allow access from any system + associated with the default group on account 1234567890 + + [{'group_name': 'default', 'user_id': '1234567890'}] + + VPC Example: Allow access from any system associated with + security group sg-47ad482e on your own account + + [{'group_id': ' sg-47ad482e'}] + :type group_pairs: ``list`` of ``dict`` + + :param protocol: tcp/udp/icmp + :type protocol: ``str`` + + :rtype: ``bool`` + """ + + params = self._get_common_security_group_params(id, + protocol, + from_port, + to_port, + cidr_ips, + group_pairs) + + params["Action"] = 'RevokeSecurityGroupIngress' + + result = self.connection.request(self.path, params=params).object + element = findtext(element=result, xpath='return', + namespace=NAMESPACE) + + return element == 'true' + + def ex_revoke_security_group_egress(self, id, from_port, to_port, + cidr_ips=None, group_pairs=None, + protocol='tcp'): + """ + Edit a Security Group to revoke specific egress traffic using + CIDR blocks or either a group ID, group name or user ID (account). + This call is not supported for EC2 classic and only works for + VPC groups. + + :param id: The id of the security group to edit + :type id: ``str`` + + :param from_port: The beginning of the port range to open + :type from_port: ``int`` + + :param to_port: The end of the port range to open + :type to_port: ``int`` + + :param cidr_ips: The list of ip ranges to allow traffic for. + :type cidr_ips: ``list`` + + :param group_pairs: Source user/group pairs to allow traffic for. + More info can be found at http://goo.gl/stBHJF + + EC2 Classic Example: To allow access from any system + associated with the default group on account 1234567890 + + [{'group_name': 'default', 'user_id': '1234567890'}] + + VPC Example: Allow access from any system associated with + security group sg-47ad482e on your own account + + [{'group_id': ' sg-47ad482e'}] + :type group_pairs: ``list`` of ``dict`` + + :param protocol: tcp/udp/icmp + :type protocol: ``str`` + + :rtype: ``bool`` + """ + + params = self._get_common_security_group_params(id, + protocol, + from_port, + to_port, + cidr_ips, + group_pairs) + + params['Action'] = 'RevokeSecurityGroupEgress' + + result = self.connection.request(self.path, params=params).object + element = findtext(element=result, xpath='return', + namespace=NAMESPACE) + + return element == 'true' + def ex_authorize_security_group_permissive(self, name): """ Edit a Security Group to allow all traffic. http://git-wip-us.apache.org/repos/asf/libcloud/blob/57393395/libcloud/test/compute/fixtures/ec2/authorize_security_group_egress.xml ---------------------------------------------------------------------- diff --git a/libcloud/test/compute/fixtures/ec2/authorize_security_group_egress.xml b/libcloud/test/compute/fixtures/ec2/authorize_security_group_egress.xml new file mode 100644 index 0000000..41e7e46 --- /dev/null +++ b/libcloud/test/compute/fixtures/ec2/authorize_security_group_egress.xml @@ -0,0 +1,4 @@ +<AuthorizeSecurityGroupEgressResponse xmlns="http://ec2.amazonaws.com/doc/2013-10-15/"> + <requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId> + <return>true</return> +</AuthorizeSecurityGroupEgressResponse> http://git-wip-us.apache.org/repos/asf/libcloud/blob/57393395/libcloud/test/compute/fixtures/ec2/revoke_security_group_egress.xml ---------------------------------------------------------------------- diff --git a/libcloud/test/compute/fixtures/ec2/revoke_security_group_egress.xml b/libcloud/test/compute/fixtures/ec2/revoke_security_group_egress.xml new file mode 100644 index 0000000..248fbb7 --- /dev/null +++ b/libcloud/test/compute/fixtures/ec2/revoke_security_group_egress.xml @@ -0,0 +1,4 @@ +<RevokeSecurityGroupEgressResponse xmlns="http://ec2.amazonaws.com/doc/2013-10-15/"> + <requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId> + <return>true</return> +</RevokeSecurityGroupEgressResponse> http://git-wip-us.apache.org/repos/asf/libcloud/blob/57393395/libcloud/test/compute/fixtures/ec2/revoke_security_group_ingress.xml ---------------------------------------------------------------------- diff --git a/libcloud/test/compute/fixtures/ec2/revoke_security_group_ingress.xml b/libcloud/test/compute/fixtures/ec2/revoke_security_group_ingress.xml new file mode 100644 index 0000000..26708da --- /dev/null +++ b/libcloud/test/compute/fixtures/ec2/revoke_security_group_ingress.xml @@ -0,0 +1,4 @@ +<RevokeSecurityGroupIngressResponse xmlns="http://ec2.amazonaws.com/doc/2013-10-15/"> + <requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId> + <return>true</return> +</RevokeSecurityGroupIngressResponse> http://git-wip-us.apache.org/repos/asf/libcloud/blob/57393395/libcloud/test/compute/test_ec2.py ---------------------------------------------------------------------- diff --git a/libcloud/test/compute/test_ec2.py b/libcloud/test/compute/test_ec2.py index 4364d69..1a843fd 100644 --- a/libcloud/test/compute/test_ec2.py +++ b/libcloud/test/compute/test_ec2.py @@ -220,6 +220,38 @@ class EC2Tests(LibcloudTestCase, TestCaseMixin): '0.0.0.0/0') self.assertTrue(resp) + def test_authorize_security_group_ingress(self): + ranges = ['1.1.1.1/32', '2.2.2.2/32'] + resp = self.driver.ex_authorize_security_group_ingress('sg-42916629', 22, 22, cidr_ips=ranges) + self.assertTrue(resp) + groups = [{'group_id': 'sg-949265ff'}] + resp = self.driver.ex_authorize_security_group_ingress('sg-42916629', 22, 23, group_pairs=groups) + self.assertTrue(resp) + + def test_authorize_security_group_egress(self): + ranges = ['1.1.1.1/32', '2.2.2.2/32'] + resp = self.driver.ex_authorize_security_group_ingress('sg-42916629', 22, 22, cidr_ips=ranges) + self.assertTrue(resp) + groups = [{'group_id': 'sg-949265ff'}] + resp = self.driver.ex_authorize_security_group_ingress('sg-42916629', 22, 22, group_pairs=groups) + self.assertTrue(resp) + + def test_revoke_security_group_ingress(self): + ranges = ['1.1.1.1/32', '2.2.2.2/32'] + resp = self.driver.ex_authorize_security_group_ingress('sg-42916629', 22, 22, cidr_ips=ranges) + self.assertTrue(resp) + groups = [{'group_id': 'sg-949265ff'}] + resp = self.driver.ex_authorize_security_group_ingress('sg-42916629', 22, 22, group_pairs=groups) + self.assertTrue(resp) + + def test_revoke_security_group_egress(self): + ranges = ['1.1.1.1/32', '2.2.2.2/32'] + resp = self.driver.ex_authorize_security_group_ingress('sg-42916629', 22, 22, cidr_ips=ranges) + self.assertTrue(resp) + groups = [{'group_id': 'sg-949265ff'}] + resp = self.driver.ex_authorize_security_group_ingress('sg-42916629', 22, 22, group_pairs=groups) + self.assertTrue(resp) + def test_reboot_node(self): node = Node('i-4382922a', None, None, None, None, self.driver) ret = self.driver.reboot_node(node)
