You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@libcloud.apache.org by to...@apache.org on 2012/12/26 23:21:12 UTC
svn commit: r1426060 - in /libcloud/trunk: ./ libcloud/compute/drivers/
libcloud/test/compute/ libcloud/test/compute/fixtures/openstack_v1.1/
Author: tomaz
Date: Wed Dec 26 22:21:11 2012
New Revision: 1426060
URL: http://svn.apache.org/viewvc?rev=1426060&view=rev
Log:
Add support and extension methods for managing security groups to the OpenStack
driver.
Contributed by L. Schaub, part of LIBCLOUD-253.
Added:
libcloud/trunk/libcloud/test/compute/fixtures/openstack_v1.1/_os_security_group_rules_create.json
libcloud/trunk/libcloud/test/compute/fixtures/openstack_v1.1/_os_security_groups.json
libcloud/trunk/libcloud/test/compute/fixtures/openstack_v1.1/_os_security_groups_create.json
libcloud/trunk/libcloud/test/compute/fixtures/openstack_v1.1/_servers_1c01300f-ef97-4937-8f03-ac676d6234be_os-security-groups.json
Modified:
libcloud/trunk/CHANGES
libcloud/trunk/libcloud/compute/drivers/openstack.py
libcloud/trunk/libcloud/test/compute/test_openstack.py
Modified: libcloud/trunk/CHANGES
URL: http://svn.apache.org/viewvc/libcloud/trunk/CHANGES?rev=1426060&r1=1426059&r2=1426060&view=diff
==============================================================================
--- libcloud/trunk/CHANGES (original)
+++ libcloud/trunk/CHANGES Wed Dec 26 22:21:11 2012
@@ -57,7 +57,7 @@ Changes with Apache Libcloud in developm
the code to make it easier to maintain.
[Tomaz Muraus]
- - Add a new driver for HostVirtual (http://www.vr.org) provider.
+ - Add a new driver for HostVirtual (http://www.vr.org) provider.
(LIBCLOUD-249)
[Dinesh Bhoopathy]
@@ -68,6 +68,14 @@ Changes with Apache Libcloud in developm
- Add a new driver for new Asia Pacific (Sydney) EC2 region.
[Tomaz Muraus]
+ - Add support for managing security groups to the OpenStack driver. This
+ patch adds the following extension methods:
+ - ex_list_security_groups, ex_get_node_security_groups methods
+ - ex_create_security_group, ex_delete_security_group
+ - ex_create_security_group_rule, ex_delete_security_group_rule
+ (LIBCLOUD-253)
+ [L. Schaub]
+
*) Storage
- Add a new local storage driver.
Modified: libcloud/trunk/libcloud/compute/drivers/openstack.py
URL: http://svn.apache.org/viewvc/libcloud/trunk/libcloud/compute/drivers/openstack.py?rev=1426060&r1=1426059&r2=1426060&view=diff
==============================================================================
--- libcloud/trunk/libcloud/compute/drivers/openstack.py (original)
+++ libcloud/trunk/libcloud/compute/drivers/openstack.py Wed Dec 26 22:21:11 2012
@@ -921,6 +921,112 @@ class OpenStackNetwork(object):
self.name, self.cidr,)
+class OpenStackSecurityGroup(object):
+ """
+ A Security Group.
+ """
+
+ def __init__(self, id, tenant_id, name, description, driver, rules=None,
+ extra=None):
+ """
+ Constructor.
+
+ @keyword id: Group id.
+ @type id: C{str}
+
+ @keyword tenant_id: Owner of the security group.
+ @type tenant_id: C{str}
+
+ @keyword name: Human-readable name for the security group. Might
+ not be unique.
+ @type name: C{str}
+
+ @keyword description: Human-readable description of a security
+ group.
+ @type description: C{str}
+
+ @keyword rules: Rules associated with this group.
+ @type description: C{list} of L{OpenStackSecurityGroupRule}
+
+ @keyword extra: Extra attributes associated with this group.
+ @type extra: C{dict}
+ """
+ self.id = id
+ self.tenant_id = tenant_id
+ self.name = name
+ self.description = description
+ self.driver = driver
+ self.rules = rules or []
+ self.extra = extra or {}
+
+ def __repr__(self):
+ return ('<OpenStackSecurityGroup id=%s tenant_id=%s name=%s \
+ description=%s>' % (self.id, self.tenant_id, self.name,
+ self.description))
+
+
+class OpenStackSecurityGroupRule(object):
+ """
+ A Rule of a Security Group.
+ """
+
+ def __init__(self, id, parent_group_id, ip_protocol, from_port, to_port,
+ driver, ip_range=None, group=None, tenant_id=None,
+ extra=None):
+ """
+ Constructor.
+
+ @keyword id: Rule id.
+ @type id: C{str}
+
+ @keyword parent_group_id: ID of the parent security group.
+ @type parent_group_id: C{str}
+
+ @keyword ip_protocol: IP Protocol (icmp, tcp, udp, etc).
+ @type ip_protocol: C{str}
+
+ @keyword from_port: Port at start of range.
+ @type from_port: C{int}
+
+ @keyword to_port: Port at end of range.
+ @type to_port: C{int}
+
+ @keyword ip_range: CIDR for address range.
+ @type ip_range: C{str}
+
+ @keyword group: Name of a source security group to apply to rule.
+ @type group: C{str}
+
+ @keyword tenant_id: Owner of the security group.
+ @type tenant_id: C{str}
+
+ @keyword extra: Extra attributes associated with this rule.
+ @type extra: C{dict}
+ """
+ self.id = id
+ self.parent_group_id = parent_group_id
+ self.ip_protocol = ip_protocol
+ self.from_port = from_port
+ self.to_port = to_port
+ self.driver = driver
+ self.ip_range = ''
+ self.group = {}
+
+ if group is None:
+ self.ip_range = ip_range
+ else:
+ self.group = {'name': group, 'tenant_id': tenant_id}
+
+ self.tenant_id = tenant_id
+ self.extra = extra or {}
+
+ def __repr__(self):
+ return ('<OpenStackSecurityGroupRule id=%s parent_group_id=%s \
+ ip_protocol=%s from_port=%s to_port=%s>' % (self.id,
+ self.parent_group_id, self.ip_protocol, self.from_port,
+ self.to_port))
+
+
class OpenStack_1_1_Connection(OpenStackComputeConnection):
responseCls = OpenStack_1_1_Response
accept_format = 'application/json'
@@ -967,6 +1073,10 @@ class OpenStack_1_1_NodeDriver(OpenStack
@keyword networks: The server is launched into a set of Networks.
@type networks: L{OpenStackNetwork}
+
+ @keyword ex_security_groups: List of security groups to assign to
+ the node
+ @type ex_security_groups: C{list} of L{OpenStackSecurityGroup}
"""
server_params = self._create_args_to_params(None, **kwargs)
@@ -1038,6 +1148,12 @@ class OpenStack_1_1_NodeDriver(OpenStack
networks = [{'uuid': network.id} for network in networks]
server_params['networks'] = networks
+ if 'ex_security_groups' in kwargs:
+ server_params['security_groups'] = []
+ for security_group in kwargs['ex_security_groups']:
+ name = security_group.name
+ server_params['security_groups'].append({'name': name})
+
if 'name' in kwargs:
server_params['name'] = kwargs.get('name')
else:
@@ -1275,6 +1391,149 @@ class OpenStack_1_1_NodeDriver(OpenStack
method='DELETE')
return resp.status == httplib.ACCEPTED
+ def _to_security_group_rules(self, obj):
+ return [self._to_security_group_rule(security_group_rule) for
+ security_group_rule in obj]
+
+ def _to_security_group_rule(self, obj):
+ ip_range = group = tenant_id = None
+ 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)
+
+ return OpenStackSecurityGroupRule(id=obj['id'],
+ parent_group_id=
+ obj['parent_group_id'],
+ ip_protocol=obj['ip_protocol'],
+ from_port=obj['from_port'],
+ to_port=obj['to_port'],
+ driver=self,
+ ip_range=ip_range,
+ group=group,
+ tenant_id=tenant_id)
+
+ def _to_security_groups(self, obj):
+ security_groups = obj['security_groups']
+ return [self._to_security_group(security_group) for security_group in
+ security_groups]
+
+ def _to_security_group(self, obj):
+ return OpenStackSecurityGroup(id=obj['id'],
+ tenant_id=obj['tenant_id'],
+ name=obj['name'],
+ description=obj.get('description', ''),
+ rules=self._to_security_group_rules(
+ obj.get('rules', [])),
+ driver=self)
+
+ def ex_list_security_groups(self):
+ """
+ Get a list of Security Groups that are available.
+
+ @rtype: C{list} of L{OpenStackSecurityGroup}
+ """
+ return self._to_security_groups(
+ self.connection.request('/os-security-groups').object)
+
+ def ex_get_node_security_groups(self, node):
+ """
+ Get Security Groups of the specified server.
+
+ @rtype: C{list} of L{OpenStackSecurityGroup}
+ """
+ return self._to_security_groups(
+ self.connection.request('/servers/%s/os-security-groups' %
+ (node.id)).object)
+
+ def ex_create_security_group(self, name, description):
+ """
+ Create a new Security Group
+
+ @param name: Name of the new Security Group
+ @type name: C{str}
+
+ @param description: Description of the new Security Group
+ @type description: C{str}
+
+ @rtype: L{OpenStackSecurityGroup}
+ """
+ return self._to_security_group(self.connection.request(
+ '/os-security-groups', method='POST',
+ data={'security_group': {'name': name, 'description': description}}
+ ).object['security_group'])
+
+ def ex_delete_security_group(self, security_group):
+ """
+ Delete a Security Group.
+
+ @param security_group: Security Group should be deleted
+ @type security_group: L{OpenStackSecurityGroup}
+
+ @rtype: C{bool}
+ """
+ resp = self.connection.request('/os-security-groups/%s' %
+ (security_group.id),
+ method='DELETE')
+ return resp.status == httplib.NO_CONTENT
+
+ 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: L{OpenStackSecurityGroup}
+
+ @param ip_protocol: Protocol to which this rule applies
+ Examples: tcp, udp, ...
+ @type ip_protocol: C{str}
+
+ @param from_port: First port of the port range
+ @type from_port: C{int}
+
+ @param to_port: Last port of the port range
+ @type to_port: C{int}
+
+ @param cidr: CIDR notation of the source IP range for this rule
+ @type cidr: C{str}
+
+ @param source_security_group: Existing Security Group to use as the
+ source (instead of CIDR)
+ @type source_security_group: L{OpenStackSecurityGroup
+
+ @rtype: L{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.connection.request(
+ '/os-security-group-rules', method='POST',
+ data={'security_group_rule': {
+ 'ip_protocol': ip_protocol,
+ 'from_port': from_port,
+ 'to_port': to_port,
+ 'cidr': cidr,
+ 'group_id': source_security_group_id,
+ 'parent_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: L{OpenStackSecurityGroupRule}
+
+ @rtype: C{bool}
+ """
+ resp = self.connection.request('/os-security-group-rules/%s' %
+ (rule.id), method='DELETE')
+ return resp.status == httplib.NO_CONTENT
+
def ex_get_size(self, size_id):
"""
Get a NodeSize
@@ -1352,7 +1611,7 @@ class OpenStack_1_1_NodeDriver(OpenStack
imageId=api_node['image']['id'],
flavorId=api_node['flavor']['id'],
uri=next(link['href'] for link in api_node['links'] if
- link['rel'] == 'self'),
+ link['rel'] == 'self'),
metadata=api_node['metadata'],
password=api_node.get('adminPass'),
created=api_node['created'],
Added: libcloud/trunk/libcloud/test/compute/fixtures/openstack_v1.1/_os_security_group_rules_create.json
URL: http://svn.apache.org/viewvc/libcloud/trunk/libcloud/test/compute/fixtures/openstack_v1.1/_os_security_group_rules_create.json?rev=1426060&view=auto
==============================================================================
--- libcloud/trunk/libcloud/test/compute/fixtures/openstack_v1.1/_os_security_group_rules_create.json (added)
+++ libcloud/trunk/libcloud/test/compute/fixtures/openstack_v1.1/_os_security_group_rules_create.json Wed Dec 26 22:21:11 2012
@@ -0,0 +1,14 @@
+{
+ "security_group_rule": {
+ "from_port": 14,
+ "group": {},
+ "id": 2,
+ "ip_protocol": "tcp",
+ "ip_range": {
+ "cidr": "0.0.0.0/0"
+ },
+ "parent_group_id": 6,
+ "to_port": 16
+ }
+}
+
Added: libcloud/trunk/libcloud/test/compute/fixtures/openstack_v1.1/_os_security_groups.json
URL: http://svn.apache.org/viewvc/libcloud/trunk/libcloud/test/compute/fixtures/openstack_v1.1/_os_security_groups.json?rev=1426060&view=auto
==============================================================================
--- libcloud/trunk/libcloud/test/compute/fixtures/openstack_v1.1/_os_security_groups.json (added)
+++ libcloud/trunk/libcloud/test/compute/fixtures/openstack_v1.1/_os_security_groups.json Wed Dec 26 22:21:11 2012
@@ -0,0 +1,31 @@
+{
+ "security_groups": [
+ {
+ "description": "default",
+ "id": 2,
+ "name": "default",
+ "rules": [],
+ "tenant_id": "68"
+ },
+ {
+ "description": "FTP Client-Server - Open 20-21 ports",
+ "id": 4,
+ "name": "ftp",
+ "rules": [
+ {
+ "from_port": 20,
+ "group": {},
+ "id": 1,
+ "ip_protocol": "tcp",
+ "ip_range": {
+ "cidr": "0.0.0.0/0"
+ },
+ "parent_group_id": 4,
+ "to_port": 21
+ }
+ ],
+ "tenant_id": "68"
+ }
+ ]
+}
+
Added: libcloud/trunk/libcloud/test/compute/fixtures/openstack_v1.1/_os_security_groups_create.json
URL: http://svn.apache.org/viewvc/libcloud/trunk/libcloud/test/compute/fixtures/openstack_v1.1/_os_security_groups_create.json?rev=1426060&view=auto
==============================================================================
--- libcloud/trunk/libcloud/test/compute/fixtures/openstack_v1.1/_os_security_groups_create.json (added)
+++ libcloud/trunk/libcloud/test/compute/fixtures/openstack_v1.1/_os_security_groups_create.json Wed Dec 26 22:21:11 2012
@@ -0,0 +1,10 @@
+{
+ "security_group": {
+ "description": "Test Security Group",
+ "id": 6,
+ "name": "test",
+ "rules": [],
+ "tenant_id": "68"
+ }
+}
+
Added: libcloud/trunk/libcloud/test/compute/fixtures/openstack_v1.1/_servers_1c01300f-ef97-4937-8f03-ac676d6234be_os-security-groups.json
URL: http://svn.apache.org/viewvc/libcloud/trunk/libcloud/test/compute/fixtures/openstack_v1.1/_servers_1c01300f-ef97-4937-8f03-ac676d6234be_os-security-groups.json?rev=1426060&view=auto
==============================================================================
--- libcloud/trunk/libcloud/test/compute/fixtures/openstack_v1.1/_servers_1c01300f-ef97-4937-8f03-ac676d6234be_os-security-groups.json (added)
+++ libcloud/trunk/libcloud/test/compute/fixtures/openstack_v1.1/_servers_1c01300f-ef97-4937-8f03-ac676d6234be_os-security-groups.json Wed Dec 26 22:21:11 2012
@@ -0,0 +1,31 @@
+{
+ "security_groups": [
+ {
+ "description": "default",
+ "id": 2,
+ "name": "default",
+ "rules": [],
+ "tenant_id": "68"
+ },
+ {
+ "description": "FTP Client-Server - Open 20-21 ports",
+ "id": 4,
+ "name": "ftp",
+ "rules": [
+ {
+ "from_port": 20,
+ "group": {},
+ "id": 1,
+ "ip_protocol": "tcp",
+ "ip_range": {
+ "cidr": "0.0.0.0/0"
+ },
+ "parent_group_id": 4,
+ "to_port": 21
+ }
+ ],
+ "tenant_id": "68"
+ }
+ ]
+}
+
Modified: libcloud/trunk/libcloud/test/compute/test_openstack.py
URL: http://svn.apache.org/viewvc/libcloud/trunk/libcloud/test/compute/test_openstack.py?rev=1426060&r1=1426059&r2=1426060&view=diff
==============================================================================
--- libcloud/trunk/libcloud/test/compute/test_openstack.py (original)
+++ libcloud/trunk/libcloud/test/compute/test_openstack.py Wed Dec 26 22:21:11 2012
@@ -30,7 +30,7 @@ from libcloud.compute.types import Provi
from libcloud.compute.providers import get_driver
from libcloud.compute.drivers.openstack import (
OpenStack_1_0_NodeDriver, OpenStack_1_0_Response,
- OpenStack_1_1_NodeDriver
+ OpenStack_1_1_NodeDriver, OpenStackSecurityGroup, OpenStackSecurityGroupRule
)
from libcloud.compute.base import Node, NodeImage, NodeSize
from libcloud.pricing import set_pricing, clear_pricing_data
@@ -856,6 +856,73 @@ class OpenStack_1_1_Tests(unittest.TestC
result = self.driver.ex_unrescue(node)
self.assertTrue(result)
+ def test_ex_get_node_security_groups(self):
+ node = Node(id='1c01300f-ef97-4937-8f03-ac676d6234be', name=None,
+ state=None, public_ips=None, private_ips=None, driver=self.driver)
+ security_groups = self.driver.ex_get_node_security_groups(node)
+ self.assertEqual(len(security_groups), 2, 'Wrong security groups count')
+
+ security_group = security_groups[1]
+ self.assertEqual(security_group.id, 4)
+ self.assertEqual(security_group.tenant_id, '68')
+ self.assertEqual(security_group.name, 'ftp')
+ self.assertEqual(security_group.description, 'FTP Client-Server - Open 20-21 ports')
+ self.assertEqual(security_group.rules[0].id, 1)
+ self.assertEqual(security_group.rules[0].parent_group_id, 4)
+ self.assertEqual(security_group.rules[0].ip_protocol, "tcp")
+ self.assertEqual(security_group.rules[0].from_port, 20)
+ self.assertEqual(security_group.rules[0].to_port, 21)
+ self.assertEqual(security_group.rules[0].ip_range, '0.0.0.0/0')
+
+ def test_ex_list_security_groups(self):
+ security_groups = self.driver.ex_list_security_groups()
+ self.assertEqual(len(security_groups), 2, 'Wrong security groups count')
+
+ security_group = security_groups[1]
+ self.assertEqual(security_group.id, 4)
+ self.assertEqual(security_group.tenant_id, '68')
+ self.assertEqual(security_group.name, 'ftp')
+ self.assertEqual(security_group.description, 'FTP Client-Server - Open 20-21 ports')
+ self.assertEqual(security_group.rules[0].id, 1)
+ self.assertEqual(security_group.rules[0].parent_group_id, 4)
+ self.assertEqual(security_group.rules[0].ip_protocol, "tcp")
+ self.assertEqual(security_group.rules[0].from_port, 20)
+ self.assertEqual(security_group.rules[0].to_port, 21)
+ self.assertEqual(security_group.rules[0].ip_range, '0.0.0.0/0')
+
+ def test_ex_create_security_group(self):
+ name = 'test'
+ description = 'Test Security Group'
+ security_group = self.driver.ex_create_security_group(name, description)
+
+ self.assertEqual(security_group.id, 6)
+ self.assertEqual(security_group.tenant_id, '68')
+ self.assertEqual(security_group.name, name)
+ self.assertEqual(security_group.description, description)
+ self.assertEqual(len(security_group.rules), 0)
+
+ def test_ex_delete_security_group(self):
+ security_group = OpenStackSecurityGroup(id=6, tenant_id=None, name=None, description=None, driver=self.driver)
+ result = self.driver.ex_delete_security_group(security_group)
+ self.assertTrue(result)
+
+ def test_ex_create_security_group_rule(self):
+ security_group = OpenStackSecurityGroup(id=6, tenant_id=None, name=None, description=None, driver=self.driver)
+ security_group_rule = self.driver.ex_create_security_group_rule(security_group, 'tcp', 14, 16, '0.0.0.0/0')
+
+ self.assertEqual(security_group_rule.id, 2)
+ self.assertEqual(security_group_rule.parent_group_id, 6)
+ self.assertEqual(security_group_rule.ip_protocol, 'tcp')
+ self.assertEqual(security_group_rule.from_port, 14)
+ self.assertEqual(security_group_rule.to_port, 16)
+ self.assertEqual(security_group_rule.ip_range, '0.0.0.0/0')
+ self.assertEqual(security_group_rule.tenant_id, None)
+
+ def test_ex_delete_security_group_rule(self):
+ security_group_rule = OpenStackSecurityGroupRule(id=2, parent_group_id=None, ip_protocol=None, from_port=None, to_port=None, driver=self.driver)
+ result = self.driver.ex_delete_security_group_rule(security_group_rule)
+ self.assertTrue(result)
+
class OpenStack_1_1_FactoryMethodTests(OpenStack_1_1_Tests):
should_list_locations = False
@@ -1011,6 +1078,44 @@ class OpenStack_1_1_MockHttp(MockHttpTes
else:
raise NotImplementedError()
+ def _v1_1_slug_servers_1c01300f_ef97_4937_8f03_ac676d6234be_os_security_groups(self, method, url, body, headers):
+ if method == "GET":
+ body = self.fixtures.load('_servers_1c01300f-ef97-4937-8f03-ac676d6234be_os-security-groups.json')
+ else:
+ raise NotImplementedError()
+
+ return (httplib.OK, body, self.json_content_headers, httplib.responses[httplib.OK])
+
+ def _v1_1_slug_os_security_groups(self, method, url, body, headers):
+ if method == "GET":
+ body = self.fixtures.load('_os_security_groups.json')
+ elif method == "POST":
+ body = self.fixtures.load('_os_security_groups_create.json')
+ else:
+ raise NotImplementedError()
+
+ return (httplib.OK, body, self.json_content_headers, httplib.responses[httplib.OK])
+
+ def _v1_1_slug_os_security_groups_6(self, method, url, body, headers):
+ if method == "DELETE":
+ return (httplib.NO_CONTENT, "", {}, httplib.responses[httplib.NO_CONTENT])
+ else:
+ raise NotImplementedError()
+
+ def _v1_1_slug_os_security_group_rules(self, method, url, body, headers):
+ if method == "POST":
+ body = self.fixtures.load('_os_security_group_rules_create.json')
+ else:
+ raise NotImplementedError()
+
+ return (httplib.OK, body, self.json_content_headers, httplib.responses[httplib.OK])
+
+ def _v1_1_slug_os_security_group_rules_2(self, method, url, body, headers):
+ if method == "DELETE":
+ return (httplib.NO_CONTENT, "", {}, httplib.responses[httplib.NO_CONTENT])
+ else:
+ raise NotImplementedError()
+
# This exists because the nova compute url in devstack has v2 in there but the v1.1 fixtures
# work fine.