Move sec groups to neutron api LIBCLOUD-874
Project: http://git-wip-us.apache.org/repos/asf/libcloud/repo Commit: http://git-wip-us.apache.org/repos/asf/libcloud/commit/2b2e1f1a Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/2b2e1f1a Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/2b2e1f1a Branch: refs/heads/trunk Commit: 2b2e1f1a4570b2e36f621062389f1cc521dd4ea3 Parents: f05ff35 Author: micafer <[email protected]> Authored: Tue Sep 25 08:57:05 2018 +0200 Committer: Rick van de Loo <[email protected]> Committed: Tue Dec 4 09:45:48 2018 +0100 ---------------------------------------------------------------------- libcloud/compute/drivers/openstack.py | 114 +++++++++++++++++-- .../openstack_v1.1/_v2_0__security_group.json | 18 +-- .../_v2_0__security_group_rule.json | 13 +++ .../openstack_v1.1/_v2_0__security_groups.json | 2 +- libcloud/test/compute/test_openstack.py | 24 +++- 5 files changed, 146 insertions(+), 25 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/libcloud/blob/2b2e1f1a/libcloud/compute/drivers/openstack.py ---------------------------------------------------------------------- diff --git a/libcloud/compute/drivers/openstack.py b/libcloud/compute/drivers/openstack.py index 20826dc..de6d445 100644 --- a/libcloud/compute/drivers/openstack.py +++ b/libcloud/compute/drivers/openstack.py @@ -1112,7 +1112,7 @@ class OpenStackSecurityGroupRule(object): def __init__(self, id, parent_group_id, ip_protocol, from_port, to_port, driver, ip_range=None, group=None, tenant_id=None, - extra=None): + direction=None, extra=None): """ Constructor. @@ -1140,6 +1140,9 @@ class OpenStackSecurityGroupRule(object): :keyword tenant_id: Owner of the security group. :type tenant_id: ``str`` + :keyword direction: Security group Direction (ingress or egress). + :type direction: ``str`` + :keyword extra: Extra attributes associated with this rule. :type extra: ``dict`` """ @@ -1151,12 +1154,21 @@ class OpenStackSecurityGroupRule(object): self.driver = driver self.ip_range = '' self.group = {} + self.direction = 'ingress' if group is None: self.ip_range = ip_range else: self.group = {'name': group, 'tenant_id': tenant_id} + # by default in old versions only ingress was used + if direction is not None: + if direction in ['ingress', 'egress']: + self.direction = direction + else: + raise OpenStackException("Security group direction incorrect " + "value: ingress or egress.") + self.tenant_id = tenant_id self.extra = extra or {} @@ -1678,7 +1690,7 @@ class OpenStack_1_1_NodeDriver(OpenStackNodeDriver): resp = self.connection.request('%s/%s' % (self._networks_url_prefix, network.id), method='DELETE') - return resp.status == httplib.ACCEPTED + return resp.status in (httplib.NO_CONTENT, httplib.ACCEPTED) def ex_get_console_output(self, node, length=None): """ @@ -1840,6 +1852,8 @@ class OpenStack_1_1_NodeDriver(OpenStackNodeDriver): :rtype: ``list`` of :class:`OpenStackSecurityGroup` """ + print(vars(self.connection.request( + '/servers/%s/os-security-groups' % (node.id)))) return self._to_security_groups( self.connection.request('/servers/%s/os-security-groups' % (node.id)).object) @@ -3116,8 +3130,7 @@ class OpenStack_2_NodeDriver(OpenStack_1_1_NodeDriver): def destroy_volume_snapshot(self, snapshot): resp = self.volumev2_connection.request('/snapshots/%s' % snapshot.id, method='DELETE') - return resp.status == httplib.ACCEPTED - + return resp.status in (httplib.NO_CONTENT, httplib.ACCEPTED) def ex_list_security_groups(self): """ @@ -3155,9 +3168,96 @@ class OpenStack_2_NodeDriver(OpenStack_1_1_NodeDriver): :rtype: ``bool`` """ resp = self.network_connection.request('/v2.0/security-groups/%s' % - (security_group.id), - method='DELETE') - return resp.status==httplib.NO_CONTENT + (security_group.id), + method='DELETE') + return resp.status == httplib.NO_CONTENT + + def _to_security_group_rule(self, obj): + ip_range = group = tenant_id = parent_id = None + protocol = from_port = to_port = direction = None + + if 'parent_group_id' in obj: + if obj['group'] == {}: + ip_range = obj['ip_range'].get('cidr', None) + else: + group = obj['group'].get('name', None) + tenant_id = obj['group'].get('tenant_id', None) + + parent_id = obj['parent_group_id'] + from_port = obj['from_port'] + to_port = obj['to_port'] + protocol = obj['ip_protocol'] + else: + ip_range = obj.get('remote_ip_prefix', None) + group = obj.get('remote_group_id', None) + tenant_id = obj.get('tenant_id', None) + + parent_id = obj['security_group_id'] + from_port = obj['port_range_min'] + to_port = obj['port_range_max'] + protocol = obj['protocol'] + + return OpenStackSecurityGroupRule( + id=obj['id'], parent_group_id=parent_id, + ip_protocol=protocol, from_port=from_port, + to_port=to_port, driver=self, ip_range=ip_range, + group=group, tenant_id=tenant_id, direction=direction) + + def ex_create_security_group_rule(self, security_group, ip_protocol, + from_port, to_port, cidr=None, + source_security_group=None): + """ + Create a new Rule in a Security Group + + :param security_group: Security Group in which to add the rule + :type security_group: :class:`OpenStackSecurityGroup` + + :param ip_protocol: Protocol to which this rule applies + Examples: tcp, udp, ... + :type ip_protocol: ``str`` + + :param from_port: First port of the port range + :type from_port: ``int`` + + :param to_port: Last port of the port range + :type to_port: ``int`` + + :param cidr: CIDR notation of the source IP range for this rule + :type cidr: ``str`` + + :param source_security_group: Existing Security Group to use as the + source (instead of CIDR) + :type source_security_group: L{OpenStackSecurityGroup + + :rtype: :class:`OpenStackSecurityGroupRule` + """ + source_security_group_id = None + if type(source_security_group) == OpenStackSecurityGroup: + source_security_group_id = source_security_group.id + + return self._to_security_group_rule(self.network_connection.request( + '/v2.0/security-group-rules', method='POST', + data={'security_group_rule': { + 'protocol': ip_protocol, + 'port_range_min': from_port, + 'port_range_max': to_port, + 'remote_ip_prefix': cidr, + 'remote_group_id': source_security_group_id, + 'security_group_id': security_group.id}} + ).object['security_group_rule']) + + def ex_delete_security_group_rule(self, rule): + """ + Delete a Rule from a Security Group. + + :param rule: Rule should be deleted + :type rule: :class:`OpenStackSecurityGroupRule` + + :rtype: ``bool`` + """ + resp = self.connection.request('/v2.0/security-group-rules/%s' % + (rule.id), method='DELETE') + return resp.status == httplib.NO_CONTENT class OpenStack_1_1_FloatingIpPool(object): http://git-wip-us.apache.org/repos/asf/libcloud/blob/2b2e1f1a/libcloud/test/compute/fixtures/openstack_v1.1/_v2_0__security_group.json ---------------------------------------------------------------------- diff --git a/libcloud/test/compute/fixtures/openstack_v1.1/_v2_0__security_group.json b/libcloud/test/compute/fixtures/openstack_v1.1/_v2_0__security_group.json index df20ef4..d01f206 100644 --- a/libcloud/test/compute/fixtures/openstack_v1.1/_v2_0__security_group.json +++ b/libcloud/test/compute/fixtures/openstack_v1.1/_v2_0__security_group.json @@ -1,20 +1,10 @@ { "security_group": { - "description": "FTP Client-Server - Open 20-21 ports", - "id": 4, - "name": "ftp", - "security_group_rules": [ - { - "security_group_id": "4", - "direction": "ingress", - "port_range_max": 21, - "port_range_min": 20, - "remote_ip_prefix": "0.0.0.0/0", - "id": 1, - "protocol": "tcp" - } - ], + "description": "Test Security Group", + "id": 6, + "name": "test", + "security_group_rules": [], "tenant_id": "68" } } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/libcloud/blob/2b2e1f1a/libcloud/test/compute/fixtures/openstack_v1.1/_v2_0__security_group_rule.json ---------------------------------------------------------------------- diff --git a/libcloud/test/compute/fixtures/openstack_v1.1/_v2_0__security_group_rule.json b/libcloud/test/compute/fixtures/openstack_v1.1/_v2_0__security_group_rule.json new file mode 100644 index 0000000..2004b5d --- /dev/null +++ b/libcloud/test/compute/fixtures/openstack_v1.1/_v2_0__security_group_rule.json @@ -0,0 +1,13 @@ +{ + "security_group_rule": + { + "security_group_id": 6, + "direction": "ingress", + "port_range_max": 16, + "port_range_min": 14, + "remote_ip_prefix": "0.0.0.0/0", + "id": 2, + "protocol": "tcp" + } +} + http://git-wip-us.apache.org/repos/asf/libcloud/blob/2b2e1f1a/libcloud/test/compute/fixtures/openstack_v1.1/_v2_0__security_groups.json ---------------------------------------------------------------------- diff --git a/libcloud/test/compute/fixtures/openstack_v1.1/_v2_0__security_groups.json b/libcloud/test/compute/fixtures/openstack_v1.1/_v2_0__security_groups.json index 5fd84f4..5720901 100644 --- a/libcloud/test/compute/fixtures/openstack_v1.1/_v2_0__security_groups.json +++ b/libcloud/test/compute/fixtures/openstack_v1.1/_v2_0__security_groups.json @@ -13,7 +13,7 @@ "name": "ftp", "security_group_rules": [ { - "security_group_id": "4", + "security_group_id": 4, "direction": "ingress", "port_range_max": 21, "port_range_min": 20, http://git-wip-us.apache.org/repos/asf/libcloud/blob/2b2e1f1a/libcloud/test/compute/test_openstack.py ---------------------------------------------------------------------- diff --git a/libcloud/test/compute/test_openstack.py b/libcloud/test/compute/test_openstack.py index 618b7f5..3faea2b 100644 --- a/libcloud/test/compute/test_openstack.py +++ b/libcloud/test/compute/test_openstack.py @@ -2387,7 +2387,7 @@ class OpenStack_1_1_MockHttp(MockHttp, unittest.TestCase): return (httplib.OK, body, self.json_content_headers, httplib.responses[httplib.OK]) if method == 'DELETE': body = '' - return (httplib.ACCEPTED, body, self.json_content_headers, httplib.responses[httplib.OK]) + return (httplib.NO_CONTENT, body, self.json_content_headers, httplib.responses[httplib.OK]) def _v2_1337_v2_0_subnets(self, method, url, body, headers): body = self.fixtures.load('_v2_0__subnets.json') @@ -2408,7 +2408,7 @@ class OpenStack_1_1_MockHttp(MockHttp, unittest.TestCase): return (httplib.OK, body, self.json_content_headers, httplib.responses[httplib.OK]) if method == 'DELETE': body = '' - return (httplib.ACCEPTED, body, self.json_content_headers, httplib.responses[httplib.OK]) + return (httplib.NO_CONTENT, body, self.json_content_headers, httplib.responses[httplib.OK]) def _v2_1337_snapshots_detail(self, method, url, body, headers): body = self.fixtures.load('_v2_0__snapshots.json') @@ -2425,15 +2425,33 @@ class OpenStack_1_1_MockHttp(MockHttp, unittest.TestCase): return (httplib.OK, body, self.json_content_headers, httplib.responses[httplib.OK]) if method == 'DELETE': body = '' - return (httplib.ACCEPTED, body, self.json_content_headers, httplib.responses[httplib.OK]) + return (httplib.NO_CONTENT, body, self.json_content_headers, httplib.responses[httplib.OK]) def _v2_1337_v2_0_security_groups(self, method, url, body, headers): if method == 'POST': body = self.fixtures.load('_v2_0__security_group.json') return (httplib.CREATED, body, self.json_content_headers, httplib.responses[httplib.OK]) if method == 'GET': + body = self.fixtures.load('_v2_0__security_groups.json') + return (httplib.OK, body, self.json_content_headers, httplib.responses[httplib.OK]) + + def _v2_1337_v2_0_security_groups_6(self, method, url, body, headers): + if method == 'GET': body = self.fixtures.load('_v2_0__security_group.json') return (httplib.OK, body, self.json_content_headers, httplib.responses[httplib.OK]) + if method == 'DELETE': + body = '' + return (httplib.NO_CONTENT, body, self.json_content_headers, httplib.responses[httplib.OK]) + + def _v2_1337_v2_0_security_group_rules(self, method, url, body, headers): + if method == 'POST': + body = self.fixtures.load('_v2_0__security_group_rule.json') + return (httplib.CREATED, body, self.json_content_headers, httplib.responses[httplib.OK]) + + def _v2_1337_v2_0_security_group_rules_2(self, method, url, body, headers): + if method == 'DELETE': + body = '' + return (httplib.NO_CONTENT, body, self.json_content_headers, httplib.responses[httplib.OK]) # This exists because the nova compute url in devstack has v2 in there but the v1.1 fixtures # work fine.
