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 2014/05/24 21:43:56 UTC

git commit: LIBCLOUD-559 Add ex_get_security_groups method to the EC2 driver.

Repository: libcloud
Updated Branches:
  refs/heads/trunk 0283f3c3b -> 074e86ccf


LIBCLOUD-559 Add ex_get_security_groups method to the EC2 driver.

Closes #297

Signed-off-by: Tomaz Muraus <to...@apache.org>


Project: http://git-wip-us.apache.org/repos/asf/libcloud/repo
Commit: http://git-wip-us.apache.org/repos/asf/libcloud/commit/074e86cc
Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/074e86cc
Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/074e86cc

Branch: refs/heads/trunk
Commit: 074e86ccf898b7083d7de0932fca7492af255456
Parents: 0283f3c
Author: Lior Goikhburg <go...@gmail.com>
Authored: Wed May 21 18:54:44 2014 +0400
Committer: Tomaz Muraus <to...@apache.org>
Committed: Sat May 24 21:42:00 2014 +0200

----------------------------------------------------------------------
 libcloud/compute/drivers/ec2.py | 226 ++++++++++++++++++++++++++++++++---
 1 file changed, 211 insertions(+), 15 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/libcloud/blob/074e86cc/libcloud/compute/drivers/ec2.py
----------------------------------------------------------------------
diff --git a/libcloud/compute/drivers/ec2.py b/libcloud/compute/drivers/ec2.py
index 1f94d79..621a6df 100644
--- a/libcloud/compute/drivers/ec2.py
+++ b/libcloud/compute/drivers/ec2.py
@@ -64,6 +64,7 @@ __all__ = [
 
     'EC2NodeLocation',
     'EC2ReservedNode',
+    'EC2SecurityGroup',
     'EC2Network',
     'EC2NetworkSubnet',
     'EC2NetworkInterface',
@@ -1403,6 +1404,20 @@ RESOURCE_EXTRA_ATTRIBUTES_MAP = {
             'transform_func': str
         }
     },
+    'security_group': {
+        'vpc_id': {
+            'xpath': 'vpcId',
+            'transform_func': str
+        },
+        'description': {
+            'xpath': 'groupDescription',
+            'transform_func': str
+        },
+        'owner_id': {
+            'xpath': 'ownerId',
+            'transform_func': str
+        }
+    },
     'snapshot': {
         'volume_id': {
             'xpath': 'volumeId',
@@ -1591,6 +1606,25 @@ class EC2ReservedNode(Node):
         return (('<EC2ReservedNode: id=%s>') % (self.id))
 
 
+class EC2SecurityGroup(object):
+    """
+    Represents information about a Security group
+
+    Note: This class is EC2 specific.
+    """
+
+    def __init__(self, id, name, ingress_rules, egress_rules, extra=None):
+        self.id = id
+        self.name = name
+        self.ingress_rules = ingress_rules
+        self.egress_rules = egress_rules
+        self.extra = extra or {}
+
+    def __repr__(self):
+        return (('<EC2SecurityGroup: id=%s, name=%s')
+                % (self.id, self.name))
+
+
 class EC2Network(object):
     """
     Represents information about a VPC (Virtual Private Cloud) network
@@ -2368,21 +2402,7 @@ class BaseEC2NodeDriver(NodeDriver):
                 params[network_key] = network_id
 
         if filters:
-            for filter_idx, filter_data in enumerate(filters.items()):
-                filter_idx += 1  # We want 1-based indexes
-                filter_name, filter_values = filter_data
-                filter_key = 'Filter.%s.Name' % filter_idx
-                params[filter_key] = filter_name
-
-                if isinstance(filter_values, (list, tuple)):
-                    for value_idx, value in enumerate(filter_values):
-                        value_idx += 1  # We want 1-based indexes
-                        value_key = 'Filter.%s.Value.%s' % (filter_idx,
-                                                            value_idx)
-                        params[value_key] = value
-                else:
-                    value_key = 'Filter.%s.Value.1' % filter_idx
-                    params[value_key] = filter_values
+            params.update(self._build_filters(filters))
 
         return self._to_networks(
             self.connection.request(self.path, params=params).object
@@ -2527,6 +2547,47 @@ class BaseEC2NodeDriver(NodeDriver):
 
         return groups
 
+    def ex_get_security_groups(self, group_ids=None,
+                               group_names=None, filters=None):
+        """
+        Return a list of :class:`EC2SecurityGroup` objects for the
+        current region.
+
+        :param      group_ids: Return only groups matching the provided
+                               group IDs.
+        :type       group_ids: ``list``
+
+        :param      group_names: Return only groups matching the provided
+                                 group names.
+        :type       group_ids: ``list``
+
+        :param      filters: The filters so that the response includes
+                             information for only specific security groups.
+        :type       filters: ``dict``
+
+        :rtype:     ``list`` of :class:`EC2SecurityGroup`
+        """
+
+        params = {'Action': 'DescribeSecurityGroups'}
+
+        if group_ids:
+            for id_idx, group_id in enumerate(group_ids):
+                id_idx += 1  # We want 1-based indexes
+                id_key = 'GroupId.%s' % (id_idx)
+                params[id_key] = group_id
+
+        if group_names:
+            for name_idx, group_name in enumerate(group_names):
+                name_idx += 1  # We want 1-based indexes
+                name_key = 'GroupName.%s' % (name_idx)
+                params[name_key] = group_name
+
+        if filters:
+            params.update(self._build_filters(filters))
+
+        response = self.connection.request(self.path, params=params)
+        return self._to_security_groups(response.object)
+
     def ex_create_security_group(self, name, description, vpc_id=None):
         """
         Creates a new Security Group in EC2-Classic or a targeted VPC.
@@ -4019,6 +4080,110 @@ class BaseEC2NodeDriver(NodeDriver):
                            driver=self)
         return key_pair
 
+    def _to_security_groups(self, response):
+        return [self._to_security_group(el) for el in response.findall(
+            fixxpath(xpath='securityGroupInfo/item', namespace=NAMESPACE))
+        ]
+
+    def _to_security_group(self, element):
+        # security group id
+        sg_id = findtext(element=element,
+                         xpath='groupId',
+                         namespace=NAMESPACE)
+
+        # security group name
+        name = findtext(element=element,
+                        xpath='groupName',
+                        namespace=NAMESPACE)
+
+        # Get our tags
+        tags = self._get_resource_tags(element)
+
+        # Get our extra dictionary
+        extra = self._get_extra_dict(
+            element, RESOURCE_EXTRA_ATTRIBUTES_MAP['security_group'])
+
+        # Add tags to the extra dict
+        extra['tags'] = tags
+
+        # Get ingress rules
+        ingress_rules = self._to_security_group_rules(
+            element, 'ipPermissions/item'
+        )
+
+        # Get egress rules
+        egress_rules = self._to_security_group_rules(
+            element, 'ipPermissionsEgress/item'
+        )
+
+        return EC2SecurityGroup(sg_id, name, ingress_rules,
+                                egress_rules, extra=extra)
+
+    def _to_security_group_rules(self, element, xpath):
+        return [self._to_security_group_rule(el) for el in element.findall(
+            fixxpath(xpath=xpath, namespace=NAMESPACE))
+        ]
+
+    def _to_security_group_rule(self, element):
+        """
+        Parse the XML element and return a SecurityGroup object.
+
+        :rtype:     :class:`EC2SecurityGroup`
+        """
+
+        rule = {}
+        rule['protocol'] = findtext(element=element,
+                                    xpath='ipProtocol',
+                                    namespace=NAMESPACE)
+
+        rule['from_port'] = findtext(element=element,
+                                     xpath='fromPort',
+                                     namespace=NAMESPACE)
+
+        rule['to_port'] = findtext(element=element,
+                                   xpath='toPort',
+                                   namespace=NAMESPACE)
+
+       # get security groups
+        elements = element.findall(fixxpath(
+            xpath='groups/item',
+            namespace=NAMESPACE
+        ))
+
+        rule['group_pairs'] = []
+
+        for element in elements:
+            item = {
+                'user_id': findtext(
+                    element=element,
+                    xpath='userId',
+                    namespace=NAMESPACE),
+                'group_id': findtext(
+                    element=element,
+                    xpath='groupId',
+                    namespace=NAMESPACE),
+                'group_name': findtext(
+                    element=element,
+                    xpath='groupName',
+                    namespace=NAMESPACE)
+            }
+            rule['group_pairs'].append(item)
+
+        # get ip ranges
+        elements = element.findall(fixxpath(
+            xpath='ipRanges/item',
+            namespace=NAMESPACE
+        ))
+
+        rule['cidr_ips'] = [
+            findtext(
+                element=element,
+                xpath='cidrIp',
+                namespace=NAMESPACE
+            ) for element in elements]
+
+        return rule
+
     def _to_networks(self, response):
         return [self._to_network(el) for el in response.findall(
             fixxpath(xpath='vpcSet/item', namespace=NAMESPACE))
@@ -4484,6 +4649,37 @@ class BaseEC2NodeDriver(NodeDriver):
 
         return groups
 
+    def _build_filters(self, filters):
+        """
+        Return a dictionary with filter query parameters which are used when
+        listing networks, security groups, etc.
+
+        :param      filters: Dict of filter names and filter values
+        :type       filters: ``dict``
+
+        :rtype:     ``dict``
+        """
+
+        filter_entries = {}
+
+        for filter_idx, filter_data in enumerate(filters.items()):
+            filter_idx += 1  # We want 1-based indexes
+            filter_name, filter_values = filter_data
+            filter_key = 'Filter.%s.Name' % (filter_idx)
+            filter_entries[filter_key] = filter_name
+
+            if isinstance(filter_values, list):
+                for value_idx, value in enumerate(filter_values):
+                    value_idx += 1  # We want 1-based indexes
+                    value_key = 'Filter.%s.Value.%s' % (filter_idx,
+                                                        value_idx)
+                    filter_entries[value_key] = value
+            else:
+                value_key = 'Filter.%s.Value.1' % (filter_idx)
+                filter_entries[value_key] = filter_values
+
+        return filter_entries
+
 
 class EC2NodeDriver(BaseEC2NodeDriver):
     """