Enis Afgan 9 лет назад
Родитель
Сommit
c4e4ea8b1e

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

@@ -35,6 +35,7 @@ from cloudbridge.cloud.interfaces.resources import SecurityGroupRule
 from cloudbridge.cloud.interfaces.resources import Snapshot
 from cloudbridge.cloud.interfaces.resources import Snapshot
 from cloudbridge.cloud.interfaces.resources import SnapshotState
 from cloudbridge.cloud.interfaces.resources import SnapshotState
 from cloudbridge.cloud.interfaces.resources import Subnet
 from cloudbridge.cloud.interfaces.resources import Subnet
+from cloudbridge.cloud.interfaces.resources import FloatingIP
 from cloudbridge.cloud.interfaces.resources import Volume
 from cloudbridge.cloud.interfaces.resources import Volume
 from cloudbridge.cloud.interfaces.resources import VolumeState
 from cloudbridge.cloud.interfaces.resources import VolumeState
 from cloudbridge.cloud.interfaces.resources import WaitStateException
 from cloudbridge.cloud.interfaces.resources import WaitStateException
@@ -673,3 +674,19 @@ class BaseSubnet(Subnet, BaseCloudResource):
                 # pylint:disable=protected-access
                 # pylint:disable=protected-access
                 self._provider == other._provider and
                 self._provider == other._provider and
                 self.id == other.id)
                 self.id == other.id)
+
+
+class BaseFloatingIP(FloatingIP, BaseCloudResource):
+
+    def __init__(self, provider):
+        super(BaseFloatingIP, self).__init__(provider)
+
+    def __repr__(self):
+        return "<CB-{0}: {1} ({2})>".format(self.__class__.__name__,
+                                            self.id, self.public_ip)
+
+    def __eq__(self, other):
+        return (isinstance(other, FloatingIP) and
+                # pylint:disable=protected-access
+                self._provider == other._provider and
+                self.id == other.id)

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

@@ -976,6 +976,64 @@ class Subnet(CloudResource):
         pass
         pass
 
 
 
 
+class FloatingIP(CloudResource):
+    """
+    Represents a floating (i.e., static) IP address.
+    """
+    __metaclass__ = ABCMeta
+
+    @abstractproperty
+    def id(self):
+        """
+        Get the address 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 public_ip(self):
+        """
+        Public IP address.
+
+        :rtype: ``str``
+        :return: IP address.
+        """
+        pass
+
+    @abstractproperty
+    def private_ip(self):
+        """
+        Private IP address this address is attached to.
+
+        :rtype: ``str``
+        :return: IP address or ``None``.
+        """
+        pass
+
+    @abstractmethod
+    def in_use(self):
+        """
+        Whether the address is in use or not.
+
+        :rtype: ``bool``
+        :return: ``True`` if the address is attached to an instance.
+        """
+        pass
+
+    @abstractmethod
+    def delete(self):
+        """
+        Delete this address.
+
+        :rtype: ``bool``
+        :return: ``True`` if successful.
+        """
+        pass
+
+
 class AttachmentInfo(object):
 class AttachmentInfo(object):
     """
     """
     Contains attachment information for a volume.
     Contains attachment information for a volume.

+ 19 - 4
cloudbridge/cloud/interfaces/services.py

@@ -2,6 +2,7 @@
 Specifications for services available through a provider
 Specifications for services available through a provider
 """
 """
 from abc import ABCMeta, abstractmethod, abstractproperty
 from abc import ABCMeta, abstractmethod, abstractproperty
+
 from cloudbridge.cloud.interfaces.resources import PageableObjectMixin
 from cloudbridge.cloud.interfaces.resources import PageableObjectMixin
 
 
 
 
@@ -559,11 +560,25 @@ class NetworkService(PageableObjectMixin, CloudService):
         """
         """
         List floating (i.e., static) IP addresses.
         List floating (i.e., static) IP addresses.
 
 
-        :type: ``str``
-        :param: The ID of the network by which to filter the IPs.
+        :type network_id: ``str``
+        :param network_id: The ID of the network by which to filter the IPs.
+
+        :rtype: ``list`` of :class:`FloatingIP`
+        :return: list of floating IP objects
+        """
+        pass
+
+    @abstractmethod
+    def create_floating_ip(self):
+        """
+        Allocate a new floating (i.e., static) IP address.
+
+        :type network_id: ``str``
+        :param network_id: The ID of the network with which to associate the
+                           new IP address.
 
 
-        :rtype: ``list`` of strings
-        :return: list of static IPs
+        :rtype: :class:`FloatingIP`
+        :return: floating IP object
         """
         """
         pass
         pass
 
 

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

@@ -15,6 +15,7 @@ from cloudbridge.cloud.base.resources import BaseSecurityGroup
 from cloudbridge.cloud.base.resources import BaseSecurityGroupRule
 from cloudbridge.cloud.base.resources import BaseSecurityGroupRule
 from cloudbridge.cloud.base.resources import BaseSnapshot
 from cloudbridge.cloud.base.resources import BaseSnapshot
 from cloudbridge.cloud.base.resources import BaseSubnet
 from cloudbridge.cloud.base.resources import BaseSubnet
+from cloudbridge.cloud.base.resources import BaseFloatingIP
 from cloudbridge.cloud.base.resources import BaseVolume
 from cloudbridge.cloud.base.resources import BaseVolume
 from cloudbridge.cloud.base.resources import ClientPagedResultList
 from cloudbridge.cloud.base.resources import ClientPagedResultList
 from cloudbridge.cloud.interfaces.resources import SecurityGroup
 from cloudbridge.cloud.interfaces.resources import SecurityGroup
@@ -985,3 +986,28 @@ class AWSSubnet(BaseSubnet):
 
 
     def delete(self):
     def delete(self):
         return self._provider.vpc_conn.delete_subnet(subnet_id=self.id)
         return self._provider.vpc_conn.delete_subnet(subnet_id=self.id)
+
+
+class AWSFloatingIP(BaseFloatingIP):
+
+    def __init__(self, provider, floating_ip):
+        super(AWSFloatingIP, self).__init__(provider)
+        self._ip = floating_ip
+
+    @property
+    def id(self):
+        return self._ip.allocation_id
+
+    @property
+    def public_ip(self):
+        return self._ip.public_ip
+
+    @property
+    def private_ip(self):
+        return self._ip.private_ip_address
+
+    def in_use(self):
+        return True if self._ip.instance_id else False
+
+    def delete(self):
+        return self._ip.delete()

+ 6 - 1
cloudbridge/cloud/providers/aws/services.py

@@ -37,6 +37,7 @@ from cloudbridge.cloud.interfaces.resources import Snapshot
 from cloudbridge.cloud.interfaces.resources import Volume
 from cloudbridge.cloud.interfaces.resources import Volume
 
 
 from .resources import AWSBucket
 from .resources import AWSBucket
+from .resources import AWSFloatingIP
 from .resources import AWSInstance
 from .resources import AWSInstance
 from .resources import AWSInstanceType
 from .resources import AWSInstanceType
 from .resources import AWSKeyPair
 from .resources import AWSKeyPair
@@ -795,7 +796,11 @@ class AWSNetworkService(BaseNetworkService):
         if network_id:
         if network_id:
             fltrs = {'network-interface-id': network_id}
             fltrs = {'network-interface-id': network_id}
         al = self.provider.vpc_conn.get_all_addresses(filters=fltrs)
         al = self.provider.vpc_conn.get_all_addresses(filters=fltrs)
-        return [a.public_ip for a in al]
+        return [AWSFloatingIP(self.provider, a) for a in al]
+
+    def create_floating_ip(self):
+        ip = self.provider.ec2_conn.allocate_address(domain='vpc')
+        return AWSFloatingIP(self.provider, ip)
 
 
 
 
 class AWSSubnetService(BaseSubnetService):
 class AWSSubnetService(BaseSubnetService):

+ 30 - 1
cloudbridge/cloud/providers/openstack/resources.py

@@ -15,6 +15,7 @@ from cloudbridge.cloud.base.resources import BaseSecurityGroup
 from cloudbridge.cloud.base.resources import BaseSecurityGroupRule
 from cloudbridge.cloud.base.resources import BaseSecurityGroupRule
 from cloudbridge.cloud.base.resources import BaseSnapshot
 from cloudbridge.cloud.base.resources import BaseSnapshot
 from cloudbridge.cloud.base.resources import BaseSubnet
 from cloudbridge.cloud.base.resources import BaseSubnet
+from cloudbridge.cloud.base.resources import BaseFloatingIP
 from cloudbridge.cloud.base.resources import BaseVolume
 from cloudbridge.cloud.base.resources import BaseVolume
 from cloudbridge.cloud.interfaces.resources import InstanceState
 from cloudbridge.cloud.interfaces.resources import InstanceState
 from cloudbridge.cloud.interfaces.resources import MachineImageState
 from cloudbridge.cloud.interfaces.resources import MachineImageState
@@ -724,11 +725,39 @@ class OpenStackSubnet(BaseSubnet):
     def delete(self):
     def delete(self):
         if self.id in str(self._provider.neutron.list_subnets()):
         if self.id in str(self._provider.neutron.list_subnets()):
             self._provider.neutron.delete_subnet(self.id)
             self._provider.neutron.delete_subnet(self.id)
-        # Adhear to the interface docs
+        # Adhere to the interface docs
         if self.id not in str(self._provider.neutron.list_subnets()):
         if self.id not in str(self._provider.neutron.list_subnets()):
             return True
             return True
 
 
 
 
+class OpenStackFloatingIP(BaseFloatingIP):
+
+    def __init__(self, provider, floating_ip):
+        super(OpenStackFloatingIP, self).__init__(provider)
+        self._ip = floating_ip
+
+    @property
+    def id(self):
+        return self._ip.get('id', None)
+
+    @property
+    def public_ip(self):
+        return self._ip.get('floating_ip_address', None)
+
+    @property
+    def private_ip(self):
+        return self._ip.get('fixed_ip_address', None)
+
+    def in_use(self):
+        return True if self._ip.get('status', None) == 'ACTIVE' else False
+
+    def delete(self):
+        self._provider.neutron.delete_floatingip(self.id)
+        # Adhere to the interface docs
+        if self.id not in str(self._provider.neutron.list_floatingips()):
+            return True
+
+
 class OpenStackKeyPair(BaseKeyPair):
 class OpenStackKeyPair(BaseKeyPair):
 
 
     def __init__(self, provider, key_pair):
     def __init__(self, provider, key_pair):

+ 13 - 2
cloudbridge/cloud/providers/openstack/services.py

@@ -5,7 +5,6 @@ import fnmatch
 import re
 import re
 
 
 from cinderclient.exceptions import NotFound as CinderNotFound
 from cinderclient.exceptions import NotFound as CinderNotFound
-from novaclient.exceptions import NotFound as NovaNotFound
 
 
 from cloudbridge.cloud.base.resources import BaseLaunchConfig
 from cloudbridge.cloud.base.resources import BaseLaunchConfig
 from cloudbridge.cloud.base.resources import ClientPagedResultList
 from cloudbridge.cloud.base.resources import ClientPagedResultList
@@ -32,7 +31,10 @@ from cloudbridge.cloud.interfaces.resources import Snapshot
 from cloudbridge.cloud.interfaces.resources import Volume
 from cloudbridge.cloud.interfaces.resources import Volume
 from cloudbridge.cloud.providers.openstack import helpers as oshelpers
 from cloudbridge.cloud.providers.openstack import helpers as oshelpers
 
 
+from novaclient.exceptions import NotFound as NovaNotFound
+
 from .resources import OpenStackBucket
 from .resources import OpenStackBucket
+from .resources import OpenStackFloatingIP
 from .resources import OpenStackInstance
 from .resources import OpenStackInstance
 from .resources import OpenStackInstanceType
 from .resources import OpenStackInstanceType
 from .resources import OpenStackKeyPair
 from .resources import OpenStackKeyPair
@@ -731,7 +733,16 @@ class OpenStackNetworkService(BaseNetworkService):
                 floating_network_id=network_id)['floatingips']
                 floating_network_id=network_id)['floatingips']
         else:
         else:
             al = self.provider.neutron.list_floatingips()['floatingips']
             al = self.provider.neutron.list_floatingips()['floatingips']
-        return [a.get('floating_ip_address') for a in al]
+        return [OpenStackFloatingIP(self.provider, a) for a in al]
+
+    def create_floating_ip(self):
+        # OpenStack requires a floating IP to be associated with a pool,
+        # so just choose the first one available...
+        ip_pool_name = self.provider.nova.floating_ip_pools.list()[0].name
+        ip = self.provider.nova.floating_ips.create(ip_pool_name)
+        # Nova returns a different object than Neutron so fetch the Neutron one
+        ip = self.provider.neutron.list_floatingips(id=ip.id)['floatingips'][0]
+        return OpenStackFloatingIP(self.provider, ip)
 
 
 
 
 class OpenStackSubnetService(BaseSubnetService):
 class OpenStackSubnetService(BaseSubnetService):