Kaynağa Gözat

Add id property to SecurityGroupRule and a delete method

Enis Afgan 10 yıl önce
ebeveyn
işleme
c06dabaa3c

+ 17 - 0
cloudbridge/cloud/interfaces/resources.py

@@ -1698,6 +1698,16 @@ class SecurityGroupRule(CloudResource):
     """
     __metaclass__ = ABCMeta
 
+    @abstractproperty
+    def id(self):
+        """
+        ID for this rule.
+
+        Note that this may be a Cloudbridge-specific ID if the underlying
+        provider does not support rule IDs.
+        """
+        pass
+
     @abstractproperty
     def ip_protocol(self):
         """
@@ -1736,6 +1746,13 @@ class SecurityGroupRule(CloudResource):
         """
         pass
 
+    @abstractmethod
+    def delete(self):
+        """
+        Delete this rule.
+        """
+        pass
+
 
 class BucketObject(CloudResource):
 

+ 20 - 0
cloudbridge/cloud/providers/aws/resources.py

@@ -7,6 +7,7 @@ import json
 from boto.exception import EC2ResponseError
 from boto.s3.key import Key
 from retrying import retry
+from slugify import slugify
 
 from cloudbridge.cloud.base.resources import BaseAttachmentInfo
 from cloudbridge.cloud.base.resources import BaseBucket
@@ -651,6 +652,15 @@ class AWSSecurityGroupRule(BaseSecurityGroupRule):
     def __init__(self, provider, rule, parent):
         super(AWSSecurityGroupRule, self).__init__(provider, rule, parent)
 
+    @property
+    def id(self):
+        """
+        AWS does not support rule IDs so compose one.
+        """
+        return slugify("sgr-{0}-{1}-{2}-{3}".format(
+            self.ip_protocol, self.from_port, self.to_port, self.cidr_ip),
+            to_lower=True)
+
     @property
     def ip_protocol(self):
         return self._rule.ip_protocol
@@ -685,6 +695,16 @@ class AWSSecurityGroupRule(BaseSecurityGroupRule):
         js['parent'] = self.parent.id if self.parent else ''
         return json.dumps(js, sort_keys=True)
 
+    def delete(self):
+        if self.group:
+            # pylint:disable=protected-access
+            self.parent._security_group.revoke(
+                src_group=self.group._security_group)
+        else:
+            # pylint:disable=protected-access
+            self.parent._security_group.revoke(self.ip_protocol, self.from_port,
+                                               self.to_port, self.cidr_ip)
+
 
 class AWSBucketObject(BaseBucketObject):
 

+ 7 - 0
cloudbridge/cloud/providers/openstack/resources.py

@@ -816,6 +816,10 @@ class OpenStackSecurityGroupRule(BaseSecurityGroupRule):
         super(OpenStackSecurityGroupRule, self).__init__(
             provider, rule, parent)
 
+    @property
+    def id(self):
+        return self._rule.get('id')
+
     @property
     def ip_protocol(self):
         return self._rule.get('ip_protocol')
@@ -849,6 +853,9 @@ class OpenStackSecurityGroupRule(BaseSecurityGroupRule):
         js['parent'] = self.parent.id if self.parent else ''
         return json.dumps(js, sort_keys=True)
 
+    def delete(self):
+        return self._provider.nova.security_group_rules.delete(self.id)
+
 
 class OpenStackBucketObject(BaseBucketObject):
 

+ 2 - 1
setup.py

@@ -13,7 +13,8 @@ with open(os.path.join('cloudbridge', '__init__.py')) as f:
             version = ast.literal_eval(m.group(1))
             break
 
-base_reqs = ['bunch==1.0.1', 'six==1.10.0', 'retrying==1.3.3']
+base_reqs = ['bunch==1.0.1', 'six==1.10.0', 'retrying==1.3.3',
+             'awesome-slugify==1.6.5']
 openstack_reqs = ['python-novaclient==2.33.0',
                   'python-glanceclient',
                   'python-cinderclient==1.4.0',

+ 11 - 4
test/test_security_service.py

@@ -176,9 +176,9 @@ class CloudSecurityServiceTestCase(ProviderTestBase):
                 sg.rules[0].to_port)
             self.assertTrue(
                 all(str(key) in repr(sg.rules[0]) for key in object_keys),
-                "repr(obj) should contain ip_protocol, form_port and to_port"
-                " so that the object can be reconstructed, but does not."
-                " eval(repr(obj)) == obj")
+                "repr(obj) should contain ip_protocol, form_port, and to_port"
+                " so that the object can be reconstructed, but does not:"
+                " {0}; {1}".format(sg.rules[0], object_keys))
             self.assertTrue(
                 sg == sg,
                 "The same security groups should be equal?")
@@ -188,7 +188,8 @@ class CloudSecurityServiceTestCase(ProviderTestBase):
             json_repr = json.dumps(
                 {"description": name, "name": name, "id": sg.id, "rules":
                  [{"from_port": 1111, "group": "", "cidr_ip": "0.0.0.0/0",
-                   "parent": sg.id, "to_port": 1111, "ip_protocol": "tcp"}]},
+                   "parent": sg.id, "to_port": 1111, "ip_protocol": "tcp",
+                   "id": sg.rules[0].id}]},
                 sort_keys=True)
             self.assertTrue(
                 sg.to_json() == json_repr,
@@ -217,6 +218,12 @@ class CloudSecurityServiceTestCase(ProviderTestBase):
                 sg.rules[0].group.name == name,
                 "Expected security group rule name {0}. Got {1}."
                 .format(name, sg.rules[0].group.name))
+            sg.rules[0].delete()
+            sg = self.provider.security.security_groups.get(sg.id)  # update
+            self.assertTrue(
+                len(sg.rules) == 0,
+                "Deleting SecurityGroupRule should delete it: {0}".format(
+                    sg.rules))
         sgl = self.provider.security.security_groups.list()
         found_sg = [g for g in sgl if g.name == name]
         self.assertTrue(