Просмотр исходного кода

Add implementation for Subnet objects for AWS and OpenStack providers.

Enis Afgan 10 лет назад
Родитель
Сommit
de7a156e3d

+ 18 - 1
cloudbridge/cloud/base/resources.py

@@ -28,6 +28,7 @@ from cloudbridge.cloud.interfaces.resources import SecurityGroup
 from cloudbridge.cloud.interfaces.resources import SecurityGroupRule
 from cloudbridge.cloud.interfaces.resources import Snapshot
 from cloudbridge.cloud.interfaces.resources import SnapshotState
+from cloudbridge.cloud.interfaces.resources import Subnet
 from cloudbridge.cloud.interfaces.resources import Volume
 from cloudbridge.cloud.interfaces.resources import VolumeState
 from cloudbridge.cloud.interfaces.resources import WaitStateException
@@ -596,10 +597,26 @@ class BaseNetwork(Network, BaseCloudResource):
 
     def __repr__(self):
         return "<CB-{0}: {1} ({2})>".format(self.__class__.__name__,
-                                           self.id, self.name)
+                                            self.id, self.name)
 
     def __eq__(self, other):
         return (isinstance(other, Network) and
                 # pylint:disable=protected-access
                 self._provider == other._provider and
                 self.id == other.id)
+
+
+class BaseSubnet(Subnet, BaseCloudResource):
+
+    def __init__(self, provider):
+        super(BaseSubnet, self).__init__(provider)
+
+    def __repr__(self):
+        return "<CB-{0}: {1} ({2})>".format(self.__class__.__name__,
+                                            self.id, self.name)
+
+    def __eq__(self, other):
+        return (isinstance(other, Subnet) and
+                # pylint:disable=protected-access
+                self._provider == other._provider and
+                self.id == other.id)

+ 78 - 2
cloudbridge/cloud/interfaces/resources.py

@@ -855,7 +855,7 @@ class Network(CloudResource):
         Delete this network.
 
         :rtype: ``bool``
-        :return: ``True`` is successful.
+        :return: ``True`` if successful.
         """
         pass
 
@@ -869,6 +869,82 @@ class Network(CloudResource):
         """
         pass
 
+    @abstractmethod
+    def create_subnet(self, cidr_block, name=None):
+        """
+        Create a new network subnet and associate it with this Network.
+
+        :type cidr_block: ``str``
+        :param cidr_block: CIDR block within this Network to assign to the
+                           subnet.
+
+        :type name: ``str``
+        :param name: An optional subnet name. The name will be set if the
+                     provider supports it.
+
+        :rtype: ``object`` of :class:`.Subnet`
+        :return:  A Subnet object
+        """
+        pass
+
+
+class Subnet(CloudResource):
+    """
+    Represents a subnet, as part of a Network.
+    """
+    __metaclass__ = ABCMeta
+
+    @abstractproperty
+    def id(self):
+        """
+        Get the subnet identifier.
+
+        :rtype: ``str``
+        :return: ID for this network. Will generally correspond to the cloud
+                 middleware's ID, but should be treated as an opaque value.
+        """
+        pass
+
+    @abstractproperty
+    def name(self):
+        """
+        Get the subnet name.
+
+        :rtype: ``str``
+        :return: Name for this subnet as returned by the cloud middleware.
+        """
+        pass
+
+    @abstractproperty
+    def cidr_block(self):
+        """
+        A CIDR block for this subnet.
+
+        :rtype: ``str``
+        :return: A CIDR block string.
+        """
+        pass
+
+    @abstractproperty
+    def network_id(self):
+        """
+        ID of the network associated with this this subnet.
+
+        :rtype: ``str``
+        :return: Network ID.
+        """
+        pass
+
+    @abstractmethod
+    def delete(self):
+        """
+        Delete this subnet.
+
+        :rtype: ``bool``
+        :return: ``True`` if successful.
+        """
+        pass
+
 
 class VolumeState(object):
 
@@ -1148,7 +1224,7 @@ class KeyPair(CloudResource):
         Delete this key pair.
 
         :rtype: bool
-        :return: ``True`` is successful.
+        :return: ``True`` if successful.
         """
         pass
 

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

@@ -532,6 +532,52 @@ class NetworkService(PageableObjectMixin, CloudService):
         """
         pass
 
+    @abstractmethod
+    def list_subnets(self):
+        """
+        List all subnets.
+
+        :rtype: list of :class:`.Subnet`
+        :return: A list of existing Subnet objects.
+        """
+        pass
+
+    @abstractmethod
+    def create_subnet(self, network, cidr_block, name=None):
+        """
+        Create a new network subnet.
+
+        :type network: :class:`.Network` object or ``str``
+        :param network: Network object or ID under which to create the subnet.
+
+        :type cidr_block: ``str``
+        :param cidr_block: CIDR block within the Network to assign to the
+                           subnet.
+
+        :type name: ``str``
+        :param name: An optional subnet name. The name will be set if the
+                     provider supports it.
+
+        :rtype: ``object`` of :class:`.Subnet`
+        :return:  A Subnet object
+        """
+        pass
+
+    @abstractmethod
+    def delete_subnet(self, subnet):
+        """
+        Delete a subnet.
+
+        :type network: :class:`.Subnet` object or ``str``
+        :param network: Subnet object or ID of the subnet to delete.
+
+        :rtype: ``bool``
+        :return:  ``True`` if the subnet does not exist, ``False`` otherwise.
+                  Note that this implies that the subnet may not have been
+                  deleted by this method but instead has not existed at all.
+        """
+        pass
+
 
 class ObjectStoreService(PageableObjectMixin, CloudService):
 

+ 50 - 2
cloudbridge/cloud/providers/aws/resources.py

@@ -19,6 +19,7 @@ from cloudbridge.cloud.base.resources import BaseRegion
 from cloudbridge.cloud.base.resources import BaseSecurityGroup
 from cloudbridge.cloud.base.resources import BaseSecurityGroupRule
 from cloudbridge.cloud.base.resources import BaseSnapshot
+from cloudbridge.cloud.base.resources import BaseSubnet
 from cloudbridge.cloud.base.resources import BaseVolume
 from cloudbridge.cloud.base.resources import ClientPagedResultList
 from cloudbridge.cloud.interfaces.resources import InstanceState
@@ -754,5 +755,52 @@ class AWSNetwork(BaseNetwork):
         return self._vpc.delete()
 
     def subnets(self):
-        raise NotImplementedError(
-            'subnets not implemented by this provider.')
+        flter = {'vpcId': self.id}
+        subnets = self._provider.vpc_conn.get_all_subnets(filters=flter)
+        return [AWSSubnet(self._provider, subnet) for subnet in subnets]
+
+    def create_subnet(self, cidr_block, name=None):
+        subnet = self._provider.vpc_conn.create_subnet(self.id, cidr_block)
+        cb_subnet = AWSSubnet(self._provider, subnet)
+        if name:
+            cb_subnet.name = name
+        return cb_subnet
+
+
+class AWSSubnet(BaseSubnet):
+
+    def __init__(self, provider, subnet):
+        super(AWSSubnet, self).__init__(provider)
+        self._subnet = subnet
+
+    @property
+    def id(self):
+        return self._subnet.id
+
+    @property
+    def name(self):
+        """
+        Get the subnet name.
+
+        .. note:: the subnet must have a (case sensitive) tag ``Name``
+        """
+        return self._subnet.tags.get('Name')
+
+    @name.setter
+    # pylint:disable=arguments-differ
+    def name(self, value):
+        """
+        Set the subnet name.
+        """
+        self._subnet.add_tag('Name', value)
+
+    @property
+    def cidr_block(self):
+        return self._subnet.cidr_block
+
+    @property
+    def network_id(self):
+        return self._subnet.vpc_id
+
+    def delete(self):
+        return self._provider.vpc_conn.delete_subnet(subnet_id=self.id)

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

@@ -44,6 +44,7 @@ from .resources import AWSNetwork
 from .resources import AWSRegion
 from .resources import AWSSecurityGroup
 from .resources import AWSSnapshot
+from .resources import AWSSubnet
 from .resources import AWSVolume
 
 
@@ -658,3 +659,19 @@ class AWSNetworkService(BaseNetworkService):
         if name:
             cb_network.name = name
         return cb_network
+
+    def list_subnets(self):
+        subnets = self.provider.vpc_conn.get_all_subnets()
+        return [AWSSubnet(self.provider, subnet) for subnet in subnets]
+
+    def create_subnet(self, network, cidr_block, name=None):
+        network_id = network.id if isinstance(network, AWSNetwork) else network
+        subnet = self.provider.vpc_conn.create_subnet(network_id, cidr_block)
+        cb_subnet = AWSSubnet(self.provider, subnet)
+        if name:
+            cb_subnet.name = name
+        return cb_subnet
+
+    def delete_subnet(self, subnet):
+        subnet_id = subnet.id if isinstance(subnet, AWSSubnet) else subnet
+        return self.provider.vpc_conn.delete_subnet(subnet_id=subnet_id)

+ 41 - 2
cloudbridge/cloud/providers/openstack/resources.py

@@ -18,6 +18,7 @@ from cloudbridge.cloud.base.resources import BaseRegion
 from cloudbridge.cloud.base.resources import BaseSecurityGroup
 from cloudbridge.cloud.base.resources import BaseSecurityGroupRule
 from cloudbridge.cloud.base.resources import BaseSnapshot
+from cloudbridge.cloud.base.resources import BaseSubnet
 from cloudbridge.cloud.base.resources import BaseVolume
 from cloudbridge.cloud.interfaces.resources import InstanceState
 from cloudbridge.cloud.interfaces.resources import MachineImageState
@@ -580,8 +581,46 @@ class OpenStackNetwork(BaseNetwork):
         return False
 
     def subnets(self):
-        raise NotImplementedError(
-            'subnets not implemented by this provider.')
+        subnets = (self._provider.neutron.list_subnets(network_id=self.id)
+                   .get('subnets', []))
+        return [OpenStackSubnet(self._provider, subnet) for subnet in subnets]
+
+    def create_subnet(self, cidr_block, name=''):
+        subnet_info = {'name': name, 'network_id': self.id,
+                       'cidr': cidr_block, 'ip_version': 4}
+        subnet = (self._provider.neutron.create_subnet({'subnet': subnet_info})
+                  .get('subnet'))
+        return OpenStackSubnet(self._provider, subnet)
+
+
+class OpenStackSubnet(BaseSubnet):
+
+    def __init__(self, provider, subnet):
+        super(OpenStackSubnet, self).__init__(provider)
+        self._subnet = subnet
+
+    @property
+    def id(self):
+        return self._subnet.get('id', None)
+
+    @property
+    def name(self):
+        return self._subnet.get('name', None)
+
+    @property
+    def cidr_block(self):
+        return self._subnet.get('cidr', None)
+
+    @property
+    def network_id(self):
+        return self._subnet.get('network_id', None)
+
+    def delete(self):
+        self._provider.neutron.delete_subnet(self.id)
+        # Adhear to the interface docs
+        if self.id not in self._provider.neutron.list_subnets():
+            return True
+        return False
 
 
 class OpenStackKeyPair(BaseKeyPair):

+ 23 - 0
cloudbridge/cloud/providers/openstack/services.py

@@ -40,6 +40,7 @@ from .resources import OpenStackNetwork
 from .resources import OpenStackRegion
 from .resources import OpenStackSecurityGroup
 from .resources import OpenStackSnapshot
+from .resources import OpenStackSubnet
 from .resources import OpenStackVolume
 
 
@@ -657,3 +658,25 @@ class OpenStackNetworkService(BaseNetworkService):
         net_info = {'name': name}
         network = self.provider.neutron.create_network({'network': net_info})
         return OpenStackNetwork(self.provider, network.get('network'))
+
+    def list_subnets(self):
+        subnets = self.provider.neutron.list_subnets().get('subnets', [])
+        return [OpenStackSubnet(self.provider, subnet) for subnet in subnets]
+
+    def create_subnet(self, network, cidr_block, name=''):
+        network_id = (network.id if isinstance(network, OpenStackNetwork)
+                      else network)
+        subnet_info = {'name': name, 'network_id': network_id,
+                       'cidr': cidr_block, 'ip_version': 4}
+        subnet = (self.provider.neutron.create_subnet({'subnet': subnet_info})
+                  .get('subnet'))
+        return OpenStackSubnet(self.provider, subnet)
+
+    def delete_subnet(self, subnet):
+        subnet_id = (subnet.id if isinstance(subnet, OpenStackSubnet)
+                     else subnet)
+        self.provider.neutron.delete_subnet(subnet_id)
+        # Adhear to the interface docs
+        if subnet_id not in self.list():
+            return True
+        return False