Procházet zdrojové kódy

VMFirewallRule Service and SubService refactored

almahmoud před 7 roky
rodič
revize
27375fe630

+ 3 - 0
cloudbridge/cloud/base/resources.py

@@ -641,6 +641,9 @@ class BaseVMFirewallRule(BaseCloudResource, VMFirewallRule):
         js['firewall'] = self.firewall.id
         return js
 
+    def delete(self):
+        self._provider.sercurity._vm_firewall_rules.delete(self.firewall, self)
+
 
 class BasePlacementZone(BaseCloudResource, PlacementZone):
 

+ 26 - 0
cloudbridge/cloud/base/services.py

@@ -21,6 +21,7 @@ from cloudbridge.cloud.interfaces.services import SecurityService
 from cloudbridge.cloud.interfaces.services import SnapshotService
 from cloudbridge.cloud.interfaces.services import StorageService
 from cloudbridge.cloud.interfaces.services import SubnetService
+from cloudbridge.cloud.interfaces.services import VMFirewallRuleService
 from cloudbridge.cloud.interfaces.services import VMFirewallService
 from cloudbridge.cloud.interfaces.services import VMTypeService
 from cloudbridge.cloud.interfaces.services import VolumeService
@@ -93,6 +94,31 @@ class BaseVMFirewallService(
                                      matches if matches else [])
 
 
+class BaseVMFirewallRuleService(BasePageableObjectMixin,
+                                VMFirewallRuleService):
+
+    def __init__(self, provider):
+        self.__provider = provider
+
+    @property
+    def _provider(self):
+        return self.__provider
+
+    def get(self, firewall, rule_id):
+        matches = [rule for rule in firewall.rules if rule.id == rule_id]
+        if matches:
+            return matches[0]
+        else:
+            return None
+
+    def find(self, firewall, **kwargs):
+        obj_list = firewall.rules
+        filters = ['name', 'direction', 'protocol', 'from_port', 'to_port',
+                   'cidr', 'src_dest_fw', 'src_dest_fw_id']
+        matches = cb_helpers.generic_find(filters, kwargs, obj_list)
+        return ClientPagedResultList(self._provider, list(matches))
+
+
 class BaseStorageService(StorageService, BaseCloudService):
 
     def __init__(self, provider):

+ 20 - 14
cloudbridge/cloud/base/subservices.py

@@ -69,30 +69,36 @@ class BaseVMFirewallRuleSubService(BasePageableObjectMixin,
 
     def __init__(self, provider, firewall):
         self.__provider = provider
-        self.firewall = firewall
+        self._firewall = firewall
 
     @property
     def _provider(self):
         return self.__provider
 
     def get(self, rule_id):
-        matches = [rule for rule in self if rule.id == rule_id]
-        if matches:
-            return matches[0]
-        else:
-            return None
+        return self._provider.security._vm_firewall_rules.get(self._firewall)
+
+    def list(self, limit=None, marker=None):
+        return self._provider.security._vm_firewall_rules.list(self._firewall,
+                                                        limit, marker)
+
+    def create(self, direction, protocol=None, from_port=None,
+               to_port=None, cidr=None, src_dest_fw=None):
+        return (self._provider
+                    .security
+                    ._vm_firewall_rules
+                    .create(self._firewall, direction, protocol, from_port,
+                            to_port, cidr, src_dest_fw))
 
     def find(self, **kwargs):
-        obj_list = self
-        filters = ['name', 'direction', 'protocol', 'from_port', 'to_port',
-                   'cidr', 'src_dest_fw', 'src_dest_fw_id']
-        matches = cb_helpers.generic_find(filters, kwargs, obj_list)
-        return ClientPagedResultList(self._provider, list(matches))
+        return self._provider.security._vm_firewall_rules.find(self._firewall,
+                                                        **kwargs)
 
     def delete(self, rule_id):
-        rule = self.get(rule_id)
-        if rule:
-            rule.delete()
+        return (self._provider
+                    .security
+                    ._vm_firewall_rules
+                    .delete(self._firewall, rule_id))
 
 
 class BaseFloatingIPSubService(FloatingIPSubService, BasePageableObjectMixin):

+ 153 - 0
cloudbridge/cloud/interfaces/services.py

@@ -1284,6 +1284,159 @@ class VMFirewallService(PageableObjectMixin, CloudService):
         pass
 
 
+class VMFirewallRuleService(CloudService):
+    """
+    Base interface for Firewall rules.
+    """
+    __metaclass__ = ABCMeta
+
+    @abstractmethod
+    def get(self, firewall, rule_id):
+        """
+        Return a firewall rule given its ID.
+
+        Returns ``None`` if the rule does not exist.
+
+        Example:
+
+        .. code-block:: python
+
+            fw = provider.security.vm_firewalls.get('my_fw_id')
+            rule = fw.rules.get('rule_id')
+            print(rule.id, rule.label)
+
+        :type firewall: ``VMFirewall``
+        :param firewall: The firewall to which the rule is attached
+
+        :type rule_id: str
+        :param rule_id: The ID of the desired firewall rule
+
+        :rtype: :class:`.FirewallRule`
+        :return:  a FirewallRule instance
+        """
+        pass
+
+    @abstractmethod
+    def list(self, firewall, limit=None, marker=None):
+        """
+        List all firewall rules associated with this firewall.
+
+        :type firewall: ``VMFirewall``
+        :param firewall: The firewall to which the rules are attached
+
+        :rtype: ``list`` of :class:`.FirewallRule`
+        :return:  list of Firewall rule objects
+        """
+        pass
+
+    @abstractmethod
+    def create(self, firewall,  direction, protocol=None, from_port=None,
+               to_port=None, cidr=None, src_dest_fw=None):
+        """
+        Create a VM firewall rule.
+
+        If a matching rule already exists, return it.
+
+        Example:
+
+        .. code-block:: python
+            from cloudbridge.cloud.interfaces.resources import TrafficDirection
+            from cloudbridge.cloud.interfaces.resources import BaseNetwork
+
+            fw = provider.security.vm_firewalls.get('my_fw_id')
+            fw.rules.create(TrafficDirection.INBOUND, protocol='tcp',
+                            from_port=80, to_port=80,
+                            cidr=BaseNetwork.CB_DEFAULT_IPV4RANGE)
+            fw.rules.create(TrafficDirection.INBOUND, src_dest_fw=fw)
+            fw.rules.create(TrafficDirection.OUTBOUND, src_dest_fw=fw)
+
+        You need to pass in either ``src_dest_fw`` OR ``protocol`` AND
+        ``from_port``, ``to_port``, ``cidr``. In other words, either
+        you are authorizing another group or you are authorizing some
+        IP-based rule.
+
+        :type firewall: ``VMFirewall``
+        :param firewall: The firewall to which the rule should be attached
+
+        :type direction: :class:``.TrafficDirection``
+        :param direction: Either ``TrafficDirection.INBOUND`` |
+                          ``TrafficDirection.OUTBOUND``
+
+        :type protocol: ``str``
+        :param protocol: Either ``tcp`` | ``udp`` | ``icmp``.
+
+        :type from_port: ``int``
+        :param from_port: The beginning port number you are enabling.
+
+        :type to_port: ``int``
+        :param to_port: The ending port number you are enabling.
+
+        :type cidr: ``str`` or list of ``str``
+        :param cidr: The CIDR block you are providing access to.
+
+        :type src_dest_fw: :class:`.VMFirewall`
+        :param src_dest_fw: The VM firewall object which is the
+                            source/destination of the traffic, depending on
+                            whether it's ingress/egress traffic.
+
+        :rtype: :class:`.VMFirewallRule`
+        :return: Rule object if successful or ``None``.
+        """
+        pass
+
+    @abstractmethod
+    def find(self, firewall, **kwargs):
+        """
+        Find a firewall rule filtered by the given parameters.
+
+        :type firewall: ``VMFirewall``
+        :param firewall: The firewall in which to look for rules
+
+        :type label: str
+        :param label: The label of the VM firewall to retrieve.
+
+        :type protocol: ``str``
+        :param protocol: Either ``tcp`` | ``udp`` | ``icmp``.
+
+        :type from_port: ``int``
+        :param from_port: The beginning port number you are enabling.
+
+        :type to_port: ``int``
+        :param to_port: The ending port number you are enabling.
+
+        :type cidr: ``str`` or list of ``str``
+        :param cidr: The CIDR block you are providing access to.
+
+        :type src_dest_fw: :class:`.VMFirewall`
+        :param src_dest_fw: The VM firewall object which is the
+                            source/destination of the traffic, depending on
+                            whether it's ingress/egress traffic.
+
+        :type src_dest_fw_id: :class:`.str`
+        :param src_dest_fw_id: The VM firewall id which is the
+                               source/destination of the traffic, depending on
+                               whether it's ingress/egress traffic.
+
+        :rtype: list of :class:`VMFirewallRule`
+        :return: A list of VMFirewall objects or an empty list if none
+                 found.
+        """
+        pass
+
+    @abstractmethod
+    def delete(self, firewall, rule_id):
+        """
+        Delete an existing VMFirewall rule.
+
+        :type firewall: ``VMFirewall``
+        :param firewall: The firewall to which the rule is attached
+
+        :type rule_id: str
+        :param rule_id: The VM firewall rule to be deleted.
+        """
+        pass
+
+
 class VMTypeService(PageableObjectMixin, CloudService):
     __metaclass__ = ABCMeta
 

+ 3 - 0
cloudbridge/cloud/interfaces/subservices.py

@@ -203,6 +203,9 @@ class VMFirewallRuleSubService(PageableObjectMixin):
             rule = fw.rules.get('rule_id')
             print(rule.id, rule.label)
 
+        :type rule_id: str
+        :param rule_id: The ID of the desired firewall rule
+
         :rtype: :class:`.FirewallRule`
         :return:  a FirewallRule instance
         """

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

@@ -33,7 +33,6 @@ from cloudbridge.cloud.interfaces.resources import NetworkState
 from cloudbridge.cloud.interfaces.resources import RouterState
 from cloudbridge.cloud.interfaces.resources import SnapshotState
 from cloudbridge.cloud.interfaces.resources import SubnetState
-from cloudbridge.cloud.interfaces.resources import TrafficDirection
 from cloudbridge.cloud.interfaces.resources import VolumeState
 
 from .helpers import find_tag_value
@@ -722,23 +721,6 @@ class AWSVMFirewallRule(BaseVMFirewallRule):
             ] if src_dest_fw_id else None
         }
 
-    def delete(self):
-        ip_perm_entry = self._construct_ip_perms(
-            self.protocol, self.from_port, self.to_port,
-            self.cidr, self.src_dest_fw_id)
-
-        # Filter out empty values to please Boto
-        ip_perms = [trim_empty_params(ip_perm_entry)]
-
-        # pylint:disable=protected-access
-        if self.direction == TrafficDirection.INBOUND:
-            self.firewall._vm_firewall.revoke_ingress(
-                IpPermissions=ip_perms)
-        else:
-            self.firewall._vm_firewall.revoke_egress(
-                IpPermissions=ip_perms)
-        self.firewall.refresh()
-
 
 class AWSBucketObject(BaseBucketObject):
 

+ 72 - 0
cloudbridge/cloud/providers/aws/services.py

@@ -27,6 +27,7 @@ from cloudbridge.cloud.base.services import BaseSecurityService
 from cloudbridge.cloud.base.services import BaseSnapshotService
 from cloudbridge.cloud.base.services import BaseStorageService
 from cloudbridge.cloud.base.services import BaseSubnetService
+from cloudbridge.cloud.base.services import BaseVMFirewallRuleService
 from cloudbridge.cloud.base.services import BaseVMFirewallService
 from cloudbridge.cloud.base.services import BaseVMTypeService
 from cloudbridge.cloud.base.services import BaseVolumeService
@@ -34,17 +35,20 @@ from cloudbridge.cloud.interfaces.exceptions import DuplicateResourceException
 from cloudbridge.cloud.interfaces.exceptions import \
     InvalidConfigurationException
 from cloudbridge.cloud.interfaces.exceptions import InvalidParamException
+from cloudbridge.cloud.interfaces.exceptions import InvalidValueException
 from cloudbridge.cloud.interfaces.resources import KeyPair
 from cloudbridge.cloud.interfaces.resources import MachineImage
 from cloudbridge.cloud.interfaces.resources import Network
 from cloudbridge.cloud.interfaces.resources import PlacementZone
 from cloudbridge.cloud.interfaces.resources import Snapshot
+from cloudbridge.cloud.interfaces.resources import TrafficDirection
 from cloudbridge.cloud.interfaces.resources import VMFirewall
 from cloudbridge.cloud.interfaces.resources import VMType
 from cloudbridge.cloud.interfaces.resources import Volume
 
 from .helpers import BotoEC2Service
 from .helpers import BotoS3Service
+from .helpers import trim_empty_params
 from .resources import AWSBucket
 from .resources import AWSBucketObject
 from .resources import AWSInstance
@@ -59,6 +63,7 @@ from .resources import AWSRouter
 from .resources import AWSSnapshot
 from .resources import AWSSubnet
 from .resources import AWSVMFirewall
+from .resources import AWSVMFirewallRule
 from .resources import AWSVMType
 from .resources import AWSVolume
 
@@ -198,6 +203,73 @@ class AWSVMFirewallService(BaseVMFirewallService):
             firewall._vm_firewall.delete()
 
 
+class AWSVMFirewallRuleService(BaseVMFirewallRuleService):
+
+    def __init__(self, provider):
+        super(AWSVMFirewallRuleService, self).__init__(provider)
+
+    def list(self, firewall, limit=None, marker=None):
+        # pylint:disable=protected-access
+        rules = [AWSVMFirewallRule(firewall,
+                                   TrafficDirection.INBOUND, r)
+                 for r in firewall._vm_firewall.ip_permissions]
+        rules = rules + [
+            AWSVMFirewallRule(
+                firewall, TrafficDirection.OUTBOUND, r)
+            for r in firewall._vm_firewall.ip_permissions_egress]
+        return ClientPagedResultList(self.provider, rules,
+                                     limit=limit, marker=marker)
+
+    def create(self, firewall,  direction, protocol=None, from_port=None,
+               to_port=None, cidr=None, src_dest_fw=None):
+        src_dest_fw_id = (
+            src_dest_fw.id if isinstance(src_dest_fw, AWSVMFirewall)
+            else src_dest_fw)
+
+        # pylint:disable=protected-access
+        ip_perm_entry = AWSVMFirewallRule._construct_ip_perms(
+            protocol, from_port, to_port, cidr, src_dest_fw_id)
+        # Filter out empty values to please Boto
+        ip_perms = [trim_empty_params(ip_perm_entry)]
+
+        try:
+            if direction == TrafficDirection.INBOUND:
+                # pylint:disable=protected-access
+                firewall._vm_firewall.authorize_ingress(
+                    IpPermissions=ip_perms)
+            elif direction == TrafficDirection.OUTBOUND:
+                # pylint:disable=protected-access
+                firewall._vm_firewall.authorize_egress(
+                    IpPermissions=ip_perms)
+            else:
+                raise InvalidValueException("direction", direction)
+            firewall.refresh()
+            return AWSVMFirewallRule(firewall, direction, ip_perm_entry)
+        except ClientError as ec2e:
+            if ec2e.response['Error']['Code'] == "InvalidPermission.Duplicate":
+                return AWSVMFirewallRule(
+                    firewall, direction, ip_perm_entry)
+            else:
+                raise ec2e
+
+    def delete(self, firewall, rule):
+        ip_perm_entry = rule._construct_ip_perms(
+            rule.protocol, rule.from_port, rule.to_port,
+            rule.cidr, rule.src_dest_fw_id)
+
+        # Filter out empty values to please Boto
+        ip_perms = [trim_empty_params(ip_perm_entry)]
+
+        # pylint:disable=protected-access
+        if rule.direction == TrafficDirection.INBOUND:
+            firewall._vm_firewall.revoke_ingress(
+                IpPermissions=ip_perms)
+        else:
+            firewall._vm_firewall.revoke_egress(
+                IpPermissions=ip_perms)
+        firewall.refresh()
+
+
 class AWSStorageService(BaseStorageService):
 
     def __init__(self, provider):

+ 0 - 52
cloudbridge/cloud/providers/aws/subservices.py

@@ -1,21 +1,13 @@
 import logging
 
-from botocore.exceptions import ClientError
-
-from cloudbridge.cloud.base.resources import ClientPagedResultList
 from cloudbridge.cloud.base.subservices import BaseBucketObjectSubService
 from cloudbridge.cloud.base.subservices import BaseFloatingIPSubService
 from cloudbridge.cloud.base.subservices import \
     BaseGatewaySubService
 from cloudbridge.cloud.base.subservices import BaseVMFirewallRuleSubService
-from cloudbridge.cloud.interfaces.exceptions import InvalidValueException
-from cloudbridge.cloud.interfaces.resources import TrafficDirection
 
 from .helpers import BotoEC2Service
-from .helpers import trim_empty_params
 from .resources import AWSFloatingIP
-from .resources import AWSVMFirewall
-from .resources import AWSVMFirewallRule
 
 log = logging.getLogger(__name__)
 
@@ -37,50 +29,6 @@ class AWSVMFirewallRuleSubService(BaseVMFirewallRuleSubService):
     def __init__(self, provider, firewall):
         super(AWSVMFirewallRuleSubService, self).__init__(provider, firewall)
 
-    def list(self, limit=None, marker=None):
-        # pylint:disable=protected-access
-        rules = [AWSVMFirewallRule(self.firewall,
-                                   TrafficDirection.INBOUND, r)
-                 for r in self.firewall._vm_firewall.ip_permissions]
-        rules = rules + [
-            AWSVMFirewallRule(
-                self.firewall, TrafficDirection.OUTBOUND, r)
-            for r in self.firewall._vm_firewall.ip_permissions_egress]
-        return ClientPagedResultList(self._provider, rules,
-                                     limit=limit, marker=marker)
-
-    def create(self,  direction, protocol=None, from_port=None,
-               to_port=None, cidr=None, src_dest_fw=None):
-        src_dest_fw_id = (
-            src_dest_fw.id if isinstance(src_dest_fw, AWSVMFirewall)
-            else src_dest_fw)
-
-        # pylint:disable=protected-access
-        ip_perm_entry = AWSVMFirewallRule._construct_ip_perms(
-            protocol, from_port, to_port, cidr, src_dest_fw_id)
-        # Filter out empty values to please Boto
-        ip_perms = [trim_empty_params(ip_perm_entry)]
-
-        try:
-            if direction == TrafficDirection.INBOUND:
-                # pylint:disable=protected-access
-                self.firewall._vm_firewall.authorize_ingress(
-                    IpPermissions=ip_perms)
-            elif direction == TrafficDirection.OUTBOUND:
-                # pylint:disable=protected-access
-                self.firewall._vm_firewall.authorize_egress(
-                    IpPermissions=ip_perms)
-            else:
-                raise InvalidValueException("direction", direction)
-            self.firewall.refresh()
-            return AWSVMFirewallRule(self.firewall, direction, ip_perm_entry)
-        except ClientError as ec2e:
-            if ec2e.response['Error']['Code'] == "InvalidPermission.Duplicate":
-                return AWSVMFirewallRule(
-                    self.firewall, direction, ip_perm_entry)
-            else:
-                raise ec2e
-
 
 class AWSFloatingIPSubService(BaseFloatingIPSubService):
 

+ 0 - 9
cloudbridge/cloud/providers/azure/resources.py

@@ -174,15 +174,6 @@ class AzureVMFirewallRule(BaseVMFirewallRule):
     def src_dest_fw(self):
         return self.firewall
 
-    def delete(self):
-        vm_firewall = self.firewall.name
-        self._provider.azure_client. \
-            delete_vm_firewall_rule(self.id, vm_firewall)
-        for i, o in enumerate(self.firewall._vm_firewall.security_rules):
-            if o.id == self.id:
-                del self.firewall._vm_firewall.security_rules[i]
-                break
-
 
 class AzureBucketObject(BaseBucketObject):
     def __init__(self, provider, container, key):

+ 77 - 0
cloudbridge/cloud/providers/azure/services.py

@@ -26,6 +26,7 @@ from cloudbridge.cloud.base.services import BaseSecurityService
 from cloudbridge.cloud.base.services import BaseSnapshotService
 from cloudbridge.cloud.base.services import BaseStorageService
 from cloudbridge.cloud.base.services import BaseSubnetService
+from cloudbridge.cloud.base.services import BaseVMFirewallRuleService
 from cloudbridge.cloud.base.services import BaseVMFirewallService
 from cloudbridge.cloud.base.services import BaseVMTypeService
 from cloudbridge.cloud.base.services import BaseVolumeService
@@ -36,6 +37,7 @@ from cloudbridge.cloud.interfaces.resources import MachineImage
 from cloudbridge.cloud.interfaces.resources import Network
 from cloudbridge.cloud.interfaces.resources import PlacementZone
 from cloudbridge.cloud.interfaces.resources import Snapshot
+from cloudbridge.cloud.interfaces.resources import TrafficDirection
 from cloudbridge.cloud.interfaces.resources import VMFirewall
 from cloudbridge.cloud.interfaces.resources import VMType
 from cloudbridge.cloud.interfaces.resources import Volume
@@ -53,6 +55,7 @@ from .resources import AzureRouter
 from .resources import AzureSnapshot
 from .resources import AzureSubnet
 from .resources import AzureVMFirewall
+from .resources import AzureVMFirewallRule
 from .resources import AzureVMType
 from .resources import AzureVolume
 
@@ -150,6 +153,80 @@ class AzureVMFirewallService(BaseVMFirewallService):
         self.provider.azure_client.delete_vm_firewall(fw_id)
 
 
+class AzureVMFirewallRuleService(BaseVMFirewallRuleService):
+
+    def __init__(self, provider):
+        super(AzureVMFirewallRuleService, self).__init__(provider)
+
+    def list(self, firewall, limit=None, marker=None):
+        # Filter out firewall rules with priority < 3500 because values
+        # between 3500 and 4096 are assumed to be owned by cloudbridge
+        # default rules.
+        # pylint:disable=protected-access
+        rules = [AzureVMFirewallRule(firewall, rule) for rule
+                 in firewall._vm_firewall.security_rules
+                 if rule.priority < 3500]
+        return ClientPagedResultList(self._provider, rules,
+                                     limit=limit, marker=marker)
+
+    def create(self, firewall, direction, protocol=None, from_port=None,
+               to_port=None, cidr=None, src_dest_fw=None):
+        if protocol and from_port and to_port:
+            return self._create_rule(direction, protocol, from_port,
+                                     to_port, cidr)
+        elif src_dest_fw:
+            result = None
+            fw = (self._provider.security.vm_firewalls.get(src_dest_fw)
+                  if isinstance(src_dest_fw, str) else src_dest_fw)
+            for rule in fw.rules:
+                result = self._create_rule(
+                    rule.direction, rule.protocol, rule.from_port,
+                    rule.to_port, rule.cidr)
+            return result
+        else:
+            return None
+
+    def _create_rule(self, firewall, direction, protocol,
+                     from_port, to_port, cidr):
+
+        # If cidr is None, default values is set as 0.0.0.0/0
+        if not cidr:
+            cidr = '0.0.0.0/0'
+
+        count = len(firewall._vm_firewall.security_rules) + 1
+        rule_name = "cb-rule-" + str(count)
+        priority = 1000 + count
+        destination_port_range = str(from_port) + "-" + str(to_port)
+        source_port_range = '*'
+        destination_address_prefix = "*"
+        access = "Allow"
+        direction = ("Inbound" if direction == TrafficDirection.INBOUND
+                     else "Outbound")
+        parameters = {"priority": priority,
+                      "protocol": protocol,
+                      "source_port_range": source_port_range,
+                      "source_address_prefix": cidr,
+                      "destination_port_range": destination_port_range,
+                      "destination_address_prefix": destination_address_prefix,
+                      "access": access,
+                      "direction": direction}
+        result = self._provider.azure_client. \
+            create_vm_firewall_rule(firewall.id,
+                                    rule_name, parameters)
+        # pylint:disable=protected-access
+        firewall._vm_firewall.security_rules.append(result)
+        return AzureVMFirewallRule(firewall, result)
+
+    def delete(self, firewall, rule):
+        vm_firewall = firewall.name
+        self.provider.azure_client. \
+            delete_vm_firewall_rule(rule.id, vm_firewall)
+        for i, o in enumerate(firewall._vm_firewall.security_rules):
+            if o.id == rule.id:
+                del firewall._vm_firewall.security_rules[i]
+                break
+
+
 class AzureKeyPairService(BaseKeyPairService):
     PARTITION_KEY = '00000000-0000-0000-0000-000000000000'
 

+ 0 - 60
cloudbridge/cloud/providers/azure/subservices.py

@@ -7,10 +7,8 @@ from cloudbridge.cloud.base.subservices import \
     BaseFloatingIPSubService
 from cloudbridge.cloud.base.subservices import BaseGatewaySubService
 from cloudbridge.cloud.base.subservices import BaseVMFirewallRuleSubService
-from cloudbridge.cloud.interfaces.resources import TrafficDirection
 
 from .resources import AzureFloatingIP
-from .resources import AzureVMFirewallRule
 
 log = logging.getLogger(__name__)
 
@@ -31,64 +29,6 @@ class AzureVMFirewallRuleSubService(BaseVMFirewallRuleSubService):
     def __init__(self, provider, firewall):
         super(AzureVMFirewallRuleSubService, self).__init__(provider, firewall)
 
-    def list(self, limit=None, marker=None):
-        # Filter out firewall rules with priority < 3500 because values
-        # between 3500 and 4096 are assumed to be owned by cloudbridge
-        # default rules.
-        # pylint:disable=protected-access
-        rules = [AzureVMFirewallRule(self.firewall, rule) for rule
-                 in self.firewall._vm_firewall.security_rules
-                 if rule.priority < 3500]
-        return ClientPagedResultList(self._provider, rules,
-                                     limit=limit, marker=marker)
-
-    def create(self, direction, protocol=None, from_port=None, to_port=None,
-               cidr=None, src_dest_fw=None):
-        if protocol and from_port and to_port:
-            return self._create_rule(direction, protocol, from_port,
-                                     to_port, cidr)
-        elif src_dest_fw:
-            result = None
-            fw = (self._provider.security.vm_firewalls.get(src_dest_fw)
-                  if isinstance(src_dest_fw, str) else src_dest_fw)
-            for rule in fw.rules:
-                result = self._create_rule(
-                    rule.direction, rule.protocol, rule.from_port,
-                    rule.to_port, rule.cidr)
-            return result
-        else:
-            return None
-
-    def _create_rule(self, direction, protocol, from_port, to_port, cidr):
-
-        # If cidr is None, default values is set as 0.0.0.0/0
-        if not cidr:
-            cidr = '0.0.0.0/0'
-
-        count = len(self.firewall._vm_firewall.security_rules) + 1
-        rule_name = "cb-rule-" + str(count)
-        priority = 1000 + count
-        destination_port_range = str(from_port) + "-" + str(to_port)
-        source_port_range = '*'
-        destination_address_prefix = "*"
-        access = "Allow"
-        direction = ("Inbound" if direction == TrafficDirection.INBOUND
-                     else "Outbound")
-        parameters = {"priority": priority,
-                      "protocol": protocol,
-                      "source_port_range": source_port_range,
-                      "source_address_prefix": cidr,
-                      "destination_port_range": destination_port_range,
-                      "destination_address_prefix": destination_address_prefix,
-                      "access": access,
-                      "direction": direction}
-        result = self._provider.azure_client. \
-            create_vm_firewall_rule(self.firewall.id,
-                                    rule_name, parameters)
-        # pylint:disable=protected-access
-        self.firewall._vm_firewall.security_rules.append(result)
-        return AzureVMFirewallRule(self.firewall, result)
-
 
 class AzureFloatingIPSubService(BaseFloatingIPSubService):
 

+ 0 - 8
cloudbridge/cloud/providers/gce/resources.py

@@ -640,14 +640,6 @@ class GCEVMFirewallRule(BaseVMFirewallRule):
             return False
         return True
 
-    def delete(self):
-        if (self.is_dummy_rule()):
-            return
-        self.force_delete()
-
-    def force_delete(self):
-        self.firewall.delegate.delete_firewall_id(self._rule)
-
 
 class GCEMachineImage(BaseMachineImage):
 

+ 67 - 0
cloudbridge/cloud/providers/gce/services.py

@@ -26,6 +26,7 @@ from cloudbridge.cloud.base.services import BaseSecurityService
 from cloudbridge.cloud.base.services import BaseSnapshotService
 from cloudbridge.cloud.base.services import BaseStorageService
 from cloudbridge.cloud.base.services import BaseSubnetService
+from cloudbridge.cloud.base.services import BaseVMFirewallRuleService
 from cloudbridge.cloud.base.services import BaseVMFirewallService
 from cloudbridge.cloud.base.services import BaseVMTypeService
 from cloudbridge.cloud.base.services import BaseVolumeService
@@ -48,6 +49,7 @@ from .resources import GCERouter
 from .resources import GCESnapshot
 from .resources import GCESubnet
 from .resources import GCEVMFirewall
+from .resources import GCEVMFirewallRule
 from .resources import GCEVMType
 from .resources import GCEVolume
 from .resources import GCSBucket
@@ -223,6 +225,71 @@ class GCEVMFirewallService(BaseVMFirewallService):
         return vm_firewalls
 
 
+class GCEVMFirewallRuleService(BaseVMFirewallRuleService):
+
+    def __init__(self, provider):
+        super(GCEVMFirewallRuleService, self).__init__(provider)
+        self._dummy_rule = None
+
+    def list(self, firewall, limit=None, marker=None):
+        rules = []
+        for firewall in firewall.delegate.iter_firewalls(
+                firewall.name, firewall.network.name):
+            rule = GCEVMFirewallRule(firewall, firewall['id'])
+            if rule.is_dummy_rule():
+                self._dummy_rule = rule
+            else:
+                rules.append(rule)
+        return ClientPagedResultList(self.provider, rules,
+                                     limit=limit, marker=marker)
+
+    @property
+    def dummy_rule(self):
+        if not self._dummy_rule:
+            self.list()
+        return self._dummy_rule
+
+    @staticmethod
+    def to_port_range(from_port, to_port):
+        if from_port is not None and to_port is not None:
+            return '%d-%d' % (from_port, to_port)
+        elif from_port is not None:
+            return from_port
+        else:
+            return to_port
+
+    def create_with_priority(self, firewall, direction, protocol, priority,
+                             from_port=None, to_port=None, cidr=None,
+                             src_dest_fw=None):
+        port = GCEVMFirewallRuleService.to_port_range(from_port, to_port)
+        src_dest_tag = None
+        src_dest_fw_id = None
+        if src_dest_fw:
+            src_dest_tag = src_dest_fw.name
+            src_dest_fw_id = src_dest_fw.id
+        if not firewall.delegate.add_firewall(
+                firewall.name, direction, protocol, priority, port, cidr,
+                src_dest_tag, firewall.description,
+                firewall.network.name):
+            return None
+        rules = self.find(direction=direction, protocol=protocol,
+                          from_port=from_port, to_port=to_port, cidr=cidr,
+                          src_dest_fw_id=src_dest_fw_id)
+        if len(rules) < 1:
+            return None
+        return rules[0]
+
+    def create(self, firewall, direction, protocol, from_port=None,
+               to_port=None, cidr=None, src_dest_fw=None):
+        return self.create_with_priority(direction, protocol, 1000, from_port,
+                                         to_port, cidr, src_dest_fw)
+
+    def delete(self, firewall, rule):
+        if rule.is_dummy_rule():
+            return True
+        firewall.delegate.delete_firewall_id(rule._rule)
+
+
 class GCEVMTypeService(BaseVMTypeService):
 
     def __init__(self, provider):

+ 2 - 59
cloudbridge/cloud/providers/gce/subservices.py

@@ -1,7 +1,6 @@
 import logging
 import uuid
 
-from cloudbridge.cloud.base.resources import ClientPagedResultList
 from cloudbridge.cloud.base.resources import ServerPagedResultList
 from cloudbridge.cloud.base.subservices import BaseBucketObjectSubService
 from cloudbridge.cloud.base.subservices import BaseFloatingIPSubService
@@ -10,7 +9,6 @@ from cloudbridge.cloud.base.subservices import \
 from cloudbridge.cloud.base.subservices import BaseVMFirewallRuleSubService
 
 from .resources import GCEFloatingIP
-from .resources import GCEVMFirewallRule
 
 log = logging.getLogger(__name__)
 
@@ -28,63 +26,8 @@ class GCEGatewaySubService(BaseGatewaySubService):
 
 class GCEVMFirewallRuleSubService(BaseVMFirewallRuleSubService):
 
-    def __init__(self, firewall):
-        super(GCEVMFirewallRuleSubService, self).__init__(
-                firewall.delegate.provider, firewall)
-        self._dummy_rule = None
-
-    def list(self, limit=None, marker=None):
-        rules = []
-        for firewall in self.firewall.delegate.iter_firewalls(
-                self.firewall.name, self.firewall.network.name):
-            rule = GCEVMFirewallRule(self.firewall, firewall['id'])
-            if rule.is_dummy_rule():
-                self._dummy_rule = rule
-            else:
-                rules.append(rule)
-        return ClientPagedResultList(self._provider, rules,
-                                     limit=limit, marker=marker)
-
-    @property
-    def dummy_rule(self):
-        if not self._dummy_rule:
-            self.list()
-        return self._dummy_rule
-
-    @staticmethod
-    def to_port_range(from_port, to_port):
-        if from_port is not None and to_port is not None:
-            return '%d-%d' % (from_port, to_port)
-        elif from_port is not None:
-            return from_port
-        else:
-            return to_port
-
-    def create_with_priority(self, direction, protocol, priority,
-                             from_port=None, to_port=None, cidr=None,
-                             src_dest_fw=None):
-        port = GCEVMFirewallRuleSubService.to_port_range(from_port, to_port)
-        src_dest_tag = None
-        src_dest_fw_id = None
-        if src_dest_fw:
-            src_dest_tag = src_dest_fw.name
-            src_dest_fw_id = src_dest_fw.id
-        if not self.firewall.delegate.add_firewall(
-                self.firewall.name, direction, protocol, priority, port, cidr,
-                src_dest_tag, self.firewall.description,
-                self.firewall.network.name):
-            return None
-        rules = self.find(direction=direction, protocol=protocol,
-                          from_port=from_port, to_port=to_port, cidr=cidr,
-                          src_dest_fw_id=src_dest_fw_id)
-        if len(rules) < 1:
-            return None
-        return rules[0]
-
-    def create(self, direction, protocol, from_port=None, to_port=None,
-               cidr=None, src_dest_fw=None):
-        return self.create_with_priority(direction, protocol, 1000, from_port,
-                                         to_port, cidr, src_dest_fw)
+    def __init__(self, provider, firewall):
+        super(GCEVMFirewallRuleSubService, self).__init__(provider)
 
 
 class GCEFloatingIPSubService(BaseFloatingIPSubService):

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

@@ -1204,10 +1204,6 @@ class OpenStackVMFirewallRule(BaseVMFirewallRule):
             return self._provider.security.vm_firewalls.get(fw_id)
         return None
 
-    def delete(self):
-        self._provider.os_conn.network.delete_security_group_rule(self.id)
-        self.firewall.refresh()
-
 
 class OpenStackBucketObject(BaseBucketObject):
 

+ 58 - 1
cloudbridge/cloud/providers/openstack/services.py

@@ -10,6 +10,7 @@ from neutronclient.common.exceptions import PortNotFoundClient
 
 from novaclient.exceptions import NotFound as NovaNotFound
 
+from openstack.exceptions import HttpException
 from openstack.exceptions import NotFoundException
 from openstack.exceptions import ResourceNotFound
 
@@ -34,23 +35,26 @@ from cloudbridge.cloud.base.services import BaseSecurityService
 from cloudbridge.cloud.base.services import BaseSnapshotService
 from cloudbridge.cloud.base.services import BaseStorageService
 from cloudbridge.cloud.base.services import BaseSubnetService
+from cloudbridge.cloud.base.services import BaseVMFirewallRuleService
 from cloudbridge.cloud.base.services import BaseVMFirewallService
 from cloudbridge.cloud.base.services import BaseVMTypeService
 from cloudbridge.cloud.base.services import BaseVolumeService
 from cloudbridge.cloud.interfaces.exceptions \
     import DuplicateResourceException
 from cloudbridge.cloud.interfaces.exceptions import InvalidParamException
+from cloudbridge.cloud.interfaces.exceptions import InvalidValueException
 from cloudbridge.cloud.interfaces.resources import KeyPair
 from cloudbridge.cloud.interfaces.resources import MachineImage
 from cloudbridge.cloud.interfaces.resources import Network
 from cloudbridge.cloud.interfaces.resources import PlacementZone
 from cloudbridge.cloud.interfaces.resources import Snapshot
 from cloudbridge.cloud.interfaces.resources import Subnet
+from cloudbridge.cloud.interfaces.resources import TrafficDirection
 from cloudbridge.cloud.interfaces.resources import VMFirewall
 from cloudbridge.cloud.interfaces.resources import VMType
 from cloudbridge.cloud.interfaces.resources import Volume
-from cloudbridge.cloud.providers.openstack import helpers as oshelpers
 
+from . import helpers as oshelpers
 from .resources import OpenStackBucket
 from .resources import OpenStackBucketObject
 from .resources import OpenStackInstance
@@ -63,6 +67,7 @@ from .resources import OpenStackRouter
 from .resources import OpenStackSnapshot
 from .resources import OpenStackSubnet
 from .resources import OpenStackVMFirewall
+from .resources import OpenStackVMFirewallRule
 from .resources import OpenStackVMType
 from .resources import OpenStackVolume
 
@@ -268,6 +273,58 @@ class OpenStackVMFirewallService(BaseVMFirewallService):
             fw._vm_firewall.delete(self.provider.os_conn.session)
 
 
+class OpenStackVMFirewallRuleService(BaseVMFirewallRuleService):
+
+    def __init__(self, provider, firewall):
+        super(OpenStackVMFirewallRuleService, self).__init__(provider)
+
+    def list(self, firewall, limit=None, marker=None):
+        # pylint:disable=protected-access
+        rules = [OpenStackVMFirewallRule(firewall, r)
+                 for r in firewall._vm_firewall.security_group_rules]
+        return ClientPagedResultList(self.provider, rules,
+                                     limit=limit, marker=marker)
+
+    def create(self, firewall, direction, protocol=None, from_port=None,
+               to_port=None, cidr=None, src_dest_fw=None):
+        src_dest_fw_id = (src_dest_fw.id if isinstance(src_dest_fw,
+                                                       OpenStackVMFirewall)
+                          else src_dest_fw)
+
+        try:
+            if direction == TrafficDirection.INBOUND:
+                os_direction = 'ingress'
+            elif direction == TrafficDirection.OUTBOUND:
+                os_direction = 'egress'
+            else:
+                raise InvalidValueException("direction", direction)
+            # pylint:disable=protected-access
+            rule = self.provider.os_conn.network.create_security_group_rule(
+                security_group_id=firewall.id,
+                direction=os_direction,
+                port_range_max=to_port,
+                port_range_min=from_port,
+                protocol=protocol,
+                remote_ip_prefix=cidr,
+                remote_group_id=src_dest_fw_id)
+            firewall.refresh()
+            return OpenStackVMFirewallRule(firewall, rule.to_dict())
+        except HttpException as e:
+            firewall.refresh()
+            # 409=Conflict, raised for duplicate rule
+            if e.status_code == 409:
+                existing = self.find(direction=direction, protocol=protocol,
+                                     from_port=from_port, to_port=to_port,
+                                     cidr=cidr, src_dest_fw_id=src_dest_fw_id)
+                return existing[0]
+            else:
+                raise e
+
+    def delete(self, firewall, rule):
+        self.provider.os_conn.network.delete_security_group_rule(rule.id)
+        firewall.refresh()
+
+
 class OpenStackStorageService(BaseStorageService):
 
     def __init__(self, provider):

+ 0 - 47
cloudbridge/cloud/providers/openstack/subservices.py

@@ -1,6 +1,5 @@
 import logging
 
-from openstack.exceptions import HttpException
 from openstack.exceptions import NotFoundException
 from openstack.exceptions import ResourceNotFound
 
@@ -10,12 +9,8 @@ from cloudbridge.cloud.base.subservices import BaseFloatingIPSubService
 from cloudbridge.cloud.base.subservices import BaseGatewaySubService
 from cloudbridge.cloud.base.subservices import \
     BaseVMFirewallRuleSubService
-from cloudbridge.cloud.interfaces.exceptions import InvalidValueException
-from cloudbridge.cloud.interfaces.resources import TrafficDirection
 
 from .resources import OpenStackFloatingIP
-from .resources import OpenStackVMFirewall
-from .resources import OpenStackVMFirewallRule
 
 log = logging.getLogger(__name__)
 
@@ -64,45 +59,3 @@ class OpenStackVMFirewallRuleSubService(BaseVMFirewallRuleSubService):
     def __init__(self, provider, firewall):
         super(OpenStackVMFirewallRuleSubService, self).__init__(
             provider, firewall)
-
-    def list(self, limit=None, marker=None):
-        # pylint:disable=protected-access
-        rules = [OpenStackVMFirewallRule(self.firewall, r)
-                 for r in self.firewall._vm_firewall.security_group_rules]
-        return ClientPagedResultList(self._provider, rules,
-                                     limit=limit, marker=marker)
-
-    def create(self,  direction, protocol=None, from_port=None,
-               to_port=None, cidr=None, src_dest_fw=None):
-        src_dest_fw_id = (src_dest_fw.id if isinstance(src_dest_fw,
-                                                       OpenStackVMFirewall)
-                          else src_dest_fw)
-
-        try:
-            if direction == TrafficDirection.INBOUND:
-                os_direction = 'ingress'
-            elif direction == TrafficDirection.OUTBOUND:
-                os_direction = 'egress'
-            else:
-                raise InvalidValueException("direction", direction)
-            # pylint:disable=protected-access
-            rule = self._provider.os_conn.network.create_security_group_rule(
-                security_group_id=self.firewall.id,
-                direction=os_direction,
-                port_range_max=to_port,
-                port_range_min=from_port,
-                protocol=protocol,
-                remote_ip_prefix=cidr,
-                remote_group_id=src_dest_fw_id)
-            self.firewall.refresh()
-            return OpenStackVMFirewallRule(self.firewall, rule.to_dict())
-        except HttpException as e:
-            self.firewall.refresh()
-            # 409=Conflict, raised for duplicate rule
-            if e.status_code == 409:
-                existing = self.find(direction=direction, protocol=protocol,
-                                     from_port=from_port, to_port=to_port,
-                                     cidr=cidr, src_dest_fw_id=src_dest_fw_id)
-                return existing[0]
-            else:
-                raise e