From 9abb16931489eea480a2d228122af013fb01978d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Canet?= Date: Tue, 15 Apr 2014 15:50:54 +0200 Subject: [PATCH] [LIBCLOUD-536] Add support for the Outscale SAS cloud. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit introduce the Outscale SAS cloud an european cloud provider featuring an EC2 compatible API. Special care have been taken to leave room for Outscale INC an US based cloud using the same infrastructure but governed by US laws. Signed-off-by: Benoît Canet --- .../images/provider_logos/outscale.png | Bin 0 -> 8437 bytes .../_supported_methods_block_storage.rst | 2 + ..._supported_methods_key_pair_management.rst | 2 + docs/compute/_supported_methods_main.rst | 2 + docs/compute/_supported_providers.rst | 2 + docs/compute/drivers/outscale.rst | 31 + libcloud/compute/drivers/ec2.py | 596 +++++++++++++++++- libcloud/compute/providers.py | 2 + libcloud/compute/types.py | 2 + libcloud/data/pricing.json | 69 ++ libcloud/test/compute/test_ec2.py | 93 +++ 11 files changed, 800 insertions(+), 1 deletion(-) create mode 100644 docs/_static/images/provider_logos/outscale.png create mode 100644 docs/compute/drivers/outscale.rst diff --git a/docs/_static/images/provider_logos/outscale.png b/docs/_static/images/provider_logos/outscale.png new file mode 100644 index 0000000000000000000000000000000000000000..c11c92a8f1c9ded5d593a04721f0da7ca875c0b5 GIT binary patch literal 8437 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 L)a7erEyDf}`k%+0 literal 0 HcmV?d00001 diff --git a/docs/compute/_supported_methods_block_storage.rst b/docs/compute/_supported_methods_block_storage.rst index 23860dba34..ffbd0bc48f 100644 --- a/docs/compute/_supported_methods_block_storage.rst +++ b/docs/compute/_supported_methods_block_storage.rst @@ -47,6 +47,7 @@ Provider list volumes create volume destroy volume `OpenNebula (v3.8)`_ yes yes yes yes yes no no `OpenStack`_ yes yes yes yes yes no no `Opsource`_ no no no no no no no +`Outscale SAS`_ yes yes yes yes yes yes yes `Rackspace Cloud (Next Gen)`_ yes yes yes yes yes no no `Rackspace Cloud (First Gen)`_ yes yes yes yes yes no no `RimuHosting`_ no no no no no no no @@ -106,6 +107,7 @@ Provider list volumes create volume destroy volume .. _`OpenNebula (v3.8)`: http://opennebula.org/ .. _`OpenStack`: http://openstack.org/ .. _`Opsource`: http://www.opsource.net/ +.. _`Outscale SAS`: http://www.outscale.com .. _`Rackspace Cloud (Next Gen)`: http://www.rackspace.com .. _`Rackspace Cloud (First Gen)`: http://www.rackspace.com .. _`RimuHosting`: http://rimuhosting.com/ diff --git a/docs/compute/_supported_methods_key_pair_management.rst b/docs/compute/_supported_methods_key_pair_management.rst index 2bc8fedd08..d37d9875d8 100644 --- a/docs/compute/_supported_methods_key_pair_management.rst +++ b/docs/compute/_supported_methods_key_pair_management.rst @@ -47,6 +47,7 @@ Provider list key pairs get key pair create key pai `OpenNebula (v3.8)`_ no no no no no no `OpenStack`_ no no no no no no `Opsource`_ no no no no no no +`Outscale SAS`_ yes yes yes yes no yes `Rackspace Cloud (Next Gen)`_ yes yes yes yes no yes `Rackspace Cloud (First Gen)`_ no no no no no no `RimuHosting`_ no no no no no no @@ -106,6 +107,7 @@ Provider list key pairs get key pair create key pai .. _`OpenNebula (v3.8)`: http://opennebula.org/ .. _`OpenStack`: http://openstack.org/ .. _`Opsource`: http://www.opsource.net/ +.. _`Outscale SAS`: http://www.outscale.com .. _`Rackspace Cloud (Next Gen)`: http://www.rackspace.com .. _`Rackspace Cloud (First Gen)`: http://www.rackspace.com .. _`RimuHosting`: http://rimuhosting.com/ diff --git a/docs/compute/_supported_methods_main.rst b/docs/compute/_supported_methods_main.rst index 84ffffdce2..c2f728eec1 100644 --- a/docs/compute/_supported_methods_main.rst +++ b/docs/compute/_supported_methods_main.rst @@ -47,6 +47,7 @@ Provider list nodes create node reboot node destroy `OpenNebula (v3.8)`_ yes yes yes yes yes yes no `OpenStack`_ yes no yes yes yes yes no `Opsource`_ yes yes yes yes yes yes yes +`Outscale SAS`_ yes yes yes yes yes yes yes `Rackspace Cloud (Next Gen)`_ yes yes yes yes yes yes yes `Rackspace Cloud (First Gen)`_ yes yes yes yes yes yes yes `RimuHosting`_ yes yes yes yes yes yes yes @@ -106,6 +107,7 @@ Provider list nodes create node reboot node destroy .. _`OpenNebula (v3.8)`: http://opennebula.org/ .. _`OpenStack`: http://openstack.org/ .. _`Opsource`: http://www.opsource.net/ +.. _`Outscale SAS`: http://www.outscale.com .. _`Rackspace Cloud (Next Gen)`: http://www.rackspace.com .. _`Rackspace Cloud (First Gen)`: http://www.rackspace.com .. _`RimuHosting`: http://rimuhosting.com/ diff --git a/docs/compute/_supported_providers.rst b/docs/compute/_supported_providers.rst index 0a2c888018..bbd956f973 100644 --- a/docs/compute/_supported_providers.rst +++ b/docs/compute/_supported_providers.rst @@ -47,6 +47,7 @@ Provider Documentation `OpenNebula (v3.8)`_ OPENNEBULA :mod:`libcloud.compute.drivers.opennebula` :class:`OpenNebulaNodeDriver` `OpenStack`_ :doc:`Click ` OPENSTACK :mod:`libcloud.compute.drivers.openstack` :class:`OpenStackNodeDriver` `Opsource`_ OPSOURCE :mod:`libcloud.compute.drivers.opsource` :class:`OpsourceNodeDriver` +`Outscale SAS`_ OUTSCALE_SAS :mod:`libcloud.compute.drivers.ec2` :class:`OutscaleSASNodeDriver` `Rackspace Cloud (Next Gen)`_ :doc:`Click ` RACKSPACE :mod:`libcloud.compute.drivers.rackspace` :class:`RackspaceNodeDriver` `Rackspace Cloud (First Gen)`_ RACKSPACE_FIRST_GEN :mod:`libcloud.compute.drivers.rackspace` :class:`RackspaceFirstGenNodeDriver` `RimuHosting`_ RIMUHOSTING :mod:`libcloud.compute.drivers.rimuhosting` :class:`RimuHostingNodeDriver` @@ -106,6 +107,7 @@ Provider Documentation .. _`OpenNebula (v3.8)`: http://opennebula.org/ .. _`OpenStack`: http://openstack.org/ .. _`Opsource`: http://www.opsource.net/ +.. _`Outscale SAS`: http://www.outscale.com .. _`Rackspace Cloud (Next Gen)`: http://www.rackspace.com .. _`Rackspace Cloud (First Gen)`: http://www.rackspace.com .. _`RimuHosting`: http://rimuhosting.com/ diff --git a/docs/compute/drivers/outscale.rst b/docs/compute/drivers/outscale.rst new file mode 100644 index 0000000000..03e7d4e3c2 --- /dev/null +++ b/docs/compute/drivers/outscale.rst @@ -0,0 +1,31 @@ +Outscale Driver Documentation +============================= + +`Outscale SAS`_ provides an IaaS platform allowing +developers to benefit from all the flexibility of the Cloud. +This IaaS platform relies on TINA OS, its Cloud manager which purpose is to +provide great performances on the Cloud. +TINA OS is an own developed software with APIs compatible with AWS EC2 (TM). + +.. figure:: /_static/images/provider_logos/outscale.png + :align: center + :width: 300 + :target: https://www.outscale.com/ + +Outscale users can start virtual machines in the following regions: + +* EU West (Paris France) Region +* US East (Boston US) Region +* (Soon) US East (New Jersey) Region +* (Soon) Asia (Hong Kong) Region + +Outscale SAS is an european company: prices are in €. + +API Docs +-------- + +.. autoclass:: libcloud.compute.drivers.ec2.OutscaleNodeDriver + :members: + :inherited-members: + +.. _`Outscale SAS`: https://www.outscale.com/ diff --git a/libcloud/compute/drivers/ec2.py b/libcloud/compute/drivers/ec2.py index 6c5e10d556..ac51abc669 100644 --- a/libcloud/compute/drivers/ec2.py +++ b/libcloud/compute/drivers/ec2.py @@ -14,7 +14,7 @@ # limitations under the License. """ -Amazon EC2, Eucalyptus and Nimbus drivers. +Amazon EC2, Eucalyptus, Nimbus and Outscale drivers. """ import re @@ -47,6 +47,8 @@ 'API_VERSION', 'NAMESPACE', 'INSTANCE_TYPES', + 'OUTSCALE_INSTANCE_TYPES', + 'OUTSCALE_SAS_REGION_DETAILS', 'DEFAULT_EUCA_API_VERSION', 'EUCA_NAMESPACE', @@ -56,6 +58,8 @@ 'NimbusNodeDriver', 'EucNodeDriver', + 'OutscaleSASNodeDriver', + 'EC2NodeLocation', 'EC2ReservedNode', 'EC2Network', @@ -622,6 +626,340 @@ } } + +""" +Sizes must be hardcoded because Outscale doesn't provide an API to fetch them. +Outscale cloud instances share some names with EC2 but have differents +specifications so declare them in another constant. +""" +OUTSCALE_INSTANCE_TYPES = { + 't1.micro': { + 'id': 't1.micro', + 'name': 'Micro Instance', + 'ram': 615, + 'disk': 0, + 'bandwidth': None + }, + 'm1.small': { + 'id': 'm1.small', + 'name': 'Standard Small Instance', + 'ram': 1740, + 'disk': 150, + 'bandwidth': None + }, + 'm1.medium': { + 'id': 'm1.medium', + 'name': 'Standard Medium Instance', + 'ram': 3840, + 'disk': 420, + 'bandwidth': None + }, + 'm1.large': { + 'id': 'm1.large', + 'name': 'Standard Large Instance', + 'ram': 7680, + 'disk': 840, + 'bandwidth': None + }, + 'm1.xlarge': { + 'id': 'm1.xlarge', + 'name': 'Standard Extra Large Instance', + 'ram': 15360, + 'disk': 1680, + 'bandwidth': None + }, + 'c1.medium': { + 'id': 'c1.medium', + 'name': 'Compute Optimized Medium Instance', + 'ram': 1740, + 'disk': 340, + 'bandwidth': None + }, + 'c1.xlarge': { + 'id': 'c1.xlarge', + 'name': 'Compute Optimized Extra Large Instance', + 'ram': 7168, + 'disk': 1680, + 'bandwidth': None + }, + 'c3.large': { + 'id': 'c3.large', + 'name': 'Compute Optimized Large Instance', + 'ram': 3840, + 'disk': 32, + 'bandwidth': None + }, + 'c3.xlarge': { + 'id': 'c3.xlarge', + 'name': 'Compute Optimized Extra Large Instance', + 'ram': 7168, + 'disk': 80, + 'bandwidth': None + }, + 'c3.2xlarge': { + 'id': 'c3.2xlarge', + 'name': 'Compute Optimized Double Extra Large Instance', + 'ram': 15359, + 'disk': 160, + 'bandwidth': None + }, + 'c3.4xlarge': { + 'id': 'c3.4xlarge', + 'name': 'Compute Optimized Quadruple Extra Large Instance', + 'ram': 30720, + 'disk': 320, + 'bandwidth': None + }, + 'c3.8xlarge': { + 'id': 'c3.8xlarge', + 'name': 'Compute Optimized Eight Extra Large Instance', + 'ram': 61440, + 'disk': 640, + 'bandwidth': None + }, + 'm2.xlarge': { + 'id': 'm2.xlarge', + 'name': 'High Memory Extra Large Instance', + 'ram': 17510, + 'disk': 420, + 'bandwidth': None + }, + 'm2.2xlarge': { + 'id': 'm2.2xlarge', + 'name': 'High Memory Double Extra Large Instance', + 'ram': 35020, + 'disk': 840, + 'bandwidth': None + }, + 'm2.4xlarge': { + 'id': 'm2.4xlarge', + 'name': 'High Memory Quadruple Extra Large Instance', + 'ram': 70042, + 'disk': 1680, + 'bandwidth': None + }, + 'nv1.small': { + 'id': 'nv1.small', + 'name': 'GPU Small Instance', + 'ram': 1739, + 'disk': 150, + 'bandwidth': None + }, + 'nv1.medium': { + 'id': 'nv1.medium', + 'name': 'GPU Medium Instance', + 'ram': 3839, + 'disk': 420, + 'bandwidth': None + }, + 'nv1.large': { + 'id': 'nv1.large', + 'name': 'GPU Large Instance', + 'ram': 7679, + 'disk': 840, + 'bandwidth': None + }, + 'nv1.xlarge': { + 'id': 'nv1.xlarge', + 'name': 'GPU Extra Large Instance', + 'ram': 15358, + 'disk': 1680, + 'bandwidth': None + }, + 'g2.2xlarge': { + 'id': 'g2.2xlarge', + 'name': 'GPU Double Extra Large Instance', + 'ram': 15360, + 'disk': 60, + 'bandwidth': None + }, + 'cc1.4xlarge': { + 'id': 'cc1.4xlarge', + 'name': 'Cluster Compute Quadruple Extra Large Instance', + 'ram': 24576, + 'disk': 1680, + 'bandwidth': None + }, + 'cc2.8xlarge': { + 'id': 'cc2.8xlarge', + 'name': 'Cluster Compute Eight Extra Large Instance', + 'ram': 65536, + 'disk': 3360, + 'bandwidth': None + }, + 'hi1.xlarge': { + 'id': 'hi1.xlarge', + 'name': 'High Storage Extra Large Instance', + 'ram': 15361, + 'disk': 1680, + 'bandwidth': None + }, + 'm3.xlarge': { + 'id': 'm3.xlarge', + 'name': 'High Storage Optimized Extra Large Instance', + 'ram': 15357, + 'disk': 0, + 'bandwidth': None + }, + 'm3.2xlarge': { + 'id': 'm3.2xlarge', + 'name': 'High Storage Optimized Double Extra Large Instance', + 'ram': 30720, + 'disk': 0, + 'bandwidth': None + }, + 'm3s.xlarge': { + 'id': 'm3s.xlarge', + 'name': 'High Storage Optimized Extra Large Instance', + 'ram': 15359, + 'disk': 0, + 'bandwidth': None + }, + 'm3s.2xlarge': { + 'id': 'm3s.2xlarge', + 'name': 'High Storage Optimized Double Extra Large Instance', + 'ram': 30719, + 'disk': 0, + 'bandwidth': None + }, + 'cr1.8xlarge': { + 'id': 'cr1.8xlarge', + 'name': 'Memory Optimized Eight Extra Large Instance', + 'ram': 249855, + 'disk': 240, + 'bandwidth': None + }, + 'os1.2xlarge': { + 'id': 'os1.2xlarge', + 'name': 'Memory Optimized, High Storage, Passthrough NIC Double Extra ' + 'Large Instance', + 'ram': 65536, + 'disk': 60, + 'bandwidth': None + }, + 'os1.4xlarge': { + 'id': 'os1.4xlarge', + 'name': 'Memory Optimized, High Storage, Passthrough NIC Quadruple Ext' + 'ra Large Instance', + 'ram': 131072, + 'disk': 120, + 'bandwidth': None + }, + 'os1.8xlarge': { + 'id': 'os1.8xlarge', + 'name': 'Memory Optimized, High Storage, Passthrough NIC Eight Extra L' + 'arge Instance', + 'ram': 249856, + 'disk': 500, + 'bandwidth': None + }, + 'oc1.4xlarge': { + 'id': 'oc1.4xlarge', + 'name': 'Outscale Quadruple Extra Large Instance', + 'ram': 24575, + 'disk': 1680, + 'bandwidth': None + }, + 'oc2.8xlarge': { + 'id': 'oc2.8xlarge', + 'name': 'Outscale Eight Extra Large Instance', + 'ram': 65535, + 'disk': 3360, + 'bandwidth': None + } +} + + +""" +The function manipulating Outscale cloud regions will be overriden because +Outscale instances types are in a separate dict so also declare Outscale cloud +regions in another constant. +""" +OUTSCALE_SAS_REGION_DETAILS = { + 'eu-west-3': { + 'endpoint': 'api-ppd.outscale.com', + 'api_name': 'osc_sas_eu_west_3', + 'country': 'FRANCE', + 'instance_types': [ + 't1.micro', + 'm1.small', + 'm1.medium', + 'm1.large', + 'm1.xlarge', + 'c1.medium', + 'c1.xlarge', + 'm2.xlarge', + 'm2.2xlarge', + 'm2.4xlarge', + 'nv1.small', + 'nv1.medium', + 'nv1.large', + 'nv1.xlarge', + 'cc1.4xlarge', + 'cc2.8xlarge', + 'm3.xlarge', + 'm3.2xlarge', + 'cr1.8xlarge', + 'os1.8xlarge' + ] + }, + 'eu-west-1': { + 'endpoint': 'api.eu-west-1.outscale.com', + 'api_name': 'osc_sas_eu_west_1', + 'country': 'FRANCE', + 'instance_types': [ + 't1.micro', + 'm1.small', + 'm1.medium', + 'm1.large', + 'm1.xlarge', + 'c1.medium', + 'c1.xlarge', + 'm2.xlarge', + 'm2.2xlarge', + 'm2.4xlarge', + 'nv1.small', + 'nv1.medium', + 'nv1.large', + 'nv1.xlarge', + 'cc1.4xlarge', + 'cc2.8xlarge', + 'm3.xlarge', + 'm3.2xlarge', + 'cr1.8xlarge', + 'os1.8xlarge' + ] + }, + 'us-east-1': { + 'endpoint': 'api.us-east-1.outscale.com', + 'api_name': 'osc_sas_us_east_1', + 'country': 'USA', + 'instance_types': [ + 't1.micro', + 'm1.small', + 'm1.medium', + 'm1.large', + 'm1.xlarge', + 'c1.medium', + 'c1.xlarge', + 'm2.xlarge', + 'm2.2xlarge', + 'm2.4xlarge', + 'nv1.small', + 'nv1.medium', + 'nv1.large', + 'nv1.xlarge', + 'cc1.4xlarge', + 'cc2.8xlarge', + 'm3.xlarge', + 'm3.2xlarge', + 'cr1.8xlarge', + 'os1.8xlarge' + ] + } +} + + """ Define the extra dictionary for specific resources """ @@ -4229,3 +4567,259 @@ def ex_create_tags(self, resource, tags): @inherits: :class:`EC2NodeDriver.ex_create_tags` """ pass + + +class OutscaleConnection(EC2Connection): + """ + Connection class for Outscale + """ + + host = None + + +class OutscaleNodeDriver(BaseEC2NodeDriver): + """ + Base Outscale FCU node driver. + + Outscale per provider driver classes inherit from it. + """ + + connectionCls = OutscaleConnection + name = 'Outscale' + website = 'http://www.outscale.com' + path = '/' + + NODE_STATE_MAP = { + 'pending': NodeState.PENDING, + 'running': NodeState.RUNNING, + 'shutting-down': NodeState.UNKNOWN, + 'terminated': NodeState.TERMINATED, + 'stopped': NodeState.STOPPED + } + + def create_node(self, **kwargs): + """ + Create a new Outscale node. The ex_iamprofile keyword is not supported. + + @inherits: :class:`BaseEC2NodeDriver.create_node` + + :keyword ex_keyname: The name of the key pair + :type ex_keyname: ``str`` + + :keyword ex_userdata: User data + :type ex_userdata: ``str`` + + :keyword ex_security_groups: A list of names of security groups to + assign to the node. + :type ex_security_groups: ``list`` + + :keyword ex_metadata: Key/Value metadata to associate with a node + :type ex_metadata: ``dict`` + + :keyword ex_mincount: Minimum number of instances to launch + :type ex_mincount: ``int`` + + :keyword ex_maxcount: Maximum number of instances to launch + :type ex_maxcount: ``int`` + + :keyword ex_clienttoken: Unique identifier to ensure idempotency + :type ex_clienttoken: ``str`` + + :keyword ex_blockdevicemappings: ``list`` of ``dict`` block device + mappings. + :type ex_blockdevicemappings: ``list`` of ``dict`` + + :keyword ex_ebs_optimized: EBS-Optimized if True + :type ex_ebs_optimized: ``bool`` + """ + if 'ex_iamprofile' in kwargs: + raise NotImplementedError("ex_iamprofile not implemented") + return super(OutscaleNodeDriver, self).create_node(**kwargs) + + def ex_create_network(self, cidr_block, name=None): + """ + Create a network/VPC. Outscale does not support instance_tenancy. + + :param cidr_block: The CIDR block assigned to the network + :type cidr_block: ``str`` + + :param name: An optional name for the network + :type name: ``str`` + + :return: Dictionary of network properties + :rtype: ``dict`` + """ + return super(OutscaleNodeDriver, self).ex_create_network(cidr_block, + name=name) + + def ex_modify_instance_attribute(self, node, disable_api_termination=None, + ebs_optimized=None, group_id=None, + source_dest_check=None, user_data=None, + instance_type=None): + """ + Modify node attributes. + Ouscale support the following attributes: + 'DisableApiTermination.Value', 'EbsOptimized', 'GroupId.n', + 'SourceDestCheck.Value', 'UserData.Value', + 'InstanceType.Value' + + :param node: Node instance + :type node: :class:`Node` + + :param attributes: Dictionary with node attributes + :type attributes: ``dict`` + + :return: True on success, False otherwise. + :rtype: ``bool`` + """ + attributes = {} + + if disable_api_termination is not None: + attributes['DisableApiTermination.Value'] = disable_api_termination + if ebs_optimized is not None: + attributes['EbsOptimized'] = ebs_optimized + if group_id is not None: + attributes['GroupId.n'] = group_id + if source_dest_check is not None: + attributes['SourceDestCheck.Value'] = source_dest_check + if user_data is not None: + attributes['UserData.Value'] = user_data + if instance_type is not None: + attributes['InstanceType.Value'] = instance_type + + return super(OutscaleNodeDriver, self).ex_modify_instance_attribute( + node, attributes) + + def ex_register_image(self, name, description=None, architecture=None, + root_device_name=None, block_device_mapping=None): + """ + Registers a Machine Image based off of an EBS-backed instance. + Can also be used to create images from snapshots. + + Outscale does not support image_location, kernel_id and ramdisk_id. + + :param name: The name for the AMI being registered + :type name: ``str`` + + :param description: The description of the AMI (optional) + :type description: ``str`` + + :param architecture: The architecture of the AMI (i386/x86_64) + (optional) + :type architecture: ``str`` + + :param root_device_name: The device name for the root device + Required if registering a EBS-backed AMI + :type root_device_name: ``str`` + + :param block_device_mapping: A dictionary of the disk layout + (optional) + :type block_device_mapping: ``dict`` + + :rtype: :class:`NodeImage` + """ + return super(OutscaleNodeDriver, self).ex_register_image( + name, description=description, architecture=architecture, + root_device_name=root_device_name, + block_device_mapping=block_device_mapping) + + def ex_copy_image(self, source_region, image, name=None, description=None): + """ + Outscale does not support copying images. + + @inherits: :class:`EC2NodeDriver.ex_copy_image` + """ + raise NotImplementedError(self._not_implemented_msg) + + def ex_get_limits(self): + """ + Outscale does not support getting limits. + + @inherits: :class:`EC2NodeDriver.ex_get_limits` + """ + raise NotImplementedError(self._not_implemented_msg) + + def ex_create_network_interface(self, subnet, name=None, + description=None, + private_ip_address=None): + """ + Outscale does not support creating a network interface within a VPC. + + @inherits: :class:`EC2NodeDriver.ex_create_network_interface` + """ + raise NotImplementedError(self._not_implemented_msg) + + def ex_delete_network_interface(self, network_interface): + """ + Outscale does not support deleting a network interface within a VPC. + + @inherits: :class:`EC2NodeDriver.ex_delete_network_interface` + """ + raise NotImplementedError(self._not_implemented_msg) + + def ex_attach_network_interface_to_node(self, network_interface, + node, device_index): + """ + Outscale does not support attaching a network interface. + + @inherits: :class:`EC2NodeDriver.ex_attach_network_interface_to_node` + """ + raise NotImplementedError(self._not_implemented_msg) + + def ex_detach_network_interface(self, attachment_id, force=False): + """ + Outscale does not support detaching a network interface + + @inherits: :class:`EC2NodeDriver.ex_detach_network_interface` + """ + raise NotImplementedError(self._not_implemented_msg) + + +class OutscaleSASNodeDriver(OutscaleNodeDriver): + """ + Outscale SAS node driver + """ + name = 'Outscale SAS' + type = Provider.OUTSCALE_SAS + + def __init__(self, key, secret=None, secure=True, host=None, port=None, + region='us-east-1', **kwargs): + if hasattr(self, '_region'): + region = self._region + + if region not in OUTSCALE_SAS_REGION_DETAILS.keys(): + raise ValueError('Invalid region: %s' % (region)) + + details = OUTSCALE_SAS_REGION_DETAILS[region] + self.region_name = region + self.api_name = details['api_name'] + self.country = details['country'] + + self.connectionCls.host = details['endpoint'] + + self._not_implemented_msg =\ + 'This method is not supported in the Outscale driver' + + super(OutscaleNodeDriver, self).__init__(key=key, secret=secret, + secure=secure, host=host, + port=port, **kwargs) + + def list_sizes(self, location=None): + """ + List available instance flavors/sizes + + This override the EC2 default method in order to use Outscale infos. + + :rtype: ``list`` of :class:`NodeSize` + """ + available_types =\ + OUTSCALE_SAS_REGION_DETAILS[self.region_name]['instance_types'] + sizes = [] + + for instance_type in available_types: + attributes = OUTSCALE_INSTANCE_TYPES[instance_type] + attributes = copy.deepcopy(attributes) + price = self._get_size_price(size_id=instance_type) + attributes.update({'price': price}) + sizes.append(NodeSize(driver=self, **attributes)) + return sizes diff --git a/libcloud/compute/providers.py b/libcloud/compute/providers.py index 8cc5a3c1c5..87a46b7214 100644 --- a/libcloud/compute/providers.py +++ b/libcloud/compute/providers.py @@ -139,6 +139,8 @@ ('libcloud.compute.drivers.exoscale', 'ExoscaleNodeDriver'), Provider.IKOULA: ('libcloud.compute.drivers.ikoula', 'IkoulaNodeDriver'), + Provider.OUTSCALE_SAS: + ('libcloud.compute.drivers.ec2', 'OutscaleSASNodeDriver'), # Deprecated Provider.CLOUDSIGMA_US: diff --git a/libcloud/compute/types.py b/libcloud/compute/types.py index b736b2f7cf..561474e0bc 100644 --- a/libcloud/compute/types.py +++ b/libcloud/compute/types.py @@ -74,6 +74,7 @@ class Provider(object): :cvar NEPHOSCALE: NephoScale driver :cvar EXOSCALE: Exoscale driver. :cvar IKOULA: Ikoula driver. + :cvar OUTSCALE_SAS: Outscale SAS driver. """ DUMMY = 'dummy' EC2 = 'ec2_us_east' @@ -117,6 +118,7 @@ class Provider(object): CLOUDFRAMES = 'cloudframes' EXOSCALE = 'exoscale' IKOULA = 'ikoula' + OUTSCALE_SAS = 'outscale_sas' # Deprecated constants which are still supported EC2_US_EAST = 'ec2_us_east' diff --git a/libcloud/data/pricing.json b/libcloud/data/pricing.json index 9e08d3027f..6034ec49e4 100644 --- a/libcloud/data/pricing.json +++ b/libcloud/data/pricing.json @@ -421,6 +421,75 @@ "minimum": 15, "maximum": 200, "low": 50 + }, + "osc_sas_eu_west_3": { + "t1.micro": "0.040", + "m1.small": "0.090", + "m1.medium": "0.130", + "m1.large": "0.360", + "m1.xlarge": "0.730", + "c1.medium": "0.230", + "c1.xlarge": "0.900", + "m2.xlarge": "0.460", + "m2.2xlarge": "0.920", + "m2.4xlarge": "1.840", + "nv1.small": "5.220", + "nv1.medium": "5.310", + "nv1.large": "5.490", + "nv1.xlarge": "5.860", + "cc1.4xlarge": "1.460", + "cc2.8xlarge": "2.700", + "m3.xlarge": "0.780", + "m3.2xlarge": "1.560", + "cr1.8xlarge": "3.750", + "os1.8xlarge": "6.400", + "os1.8xlarge": "6.400" + }, + "osc_sas_eu_west_1": { + "t1.micro": "0.040", + "m1.small": "0.090", + "m1.medium": "0.130", + "m1.large": "0.360", + "m1.xlarge": "0.730", + "c1.medium": "0.230", + "c1.xlarge": "0.900", + "m2.xlarge": "0.460", + "m2.2xlarge": "0.920", + "m2.4xlarge": "1.840", + "nv1.small": "5.220", + "nv1.medium": "5.310", + "nv1.large": "5.490", + "nv1.xlarge": "5.860", + "cc1.4xlarge": "1.460", + "cc2.8xlarge": "2.700", + "m3.xlarge": "0.780", + "m3.2xlarge": "1.560", + "cr1.8xlarge": "3.750", + "os1.8xlarge": "6.400", + "os1.8xlarge": "6.400" + }, + "osc_sas_us_east_1": { + "t1.micro": "0.020", + "m1.small": "0.070", + "m1.medium": "0.180", + "m1.large": "0.260", + "m1.xlarge": "0.730", + "c1.medium": "0.170", + "c1.xlarge": "0.660", + "m2.xlarge": "0.460", + "m2.2xlarge": "1.020", + "m2.4xlarge": "2.040", + "nv1.small": "5.220", + "nv1.medium": "5.310", + "nv1.large": "5.490", + "nv1.xlarge": "5.860", + "cc1.4xlarge": "1.610", + "cc2.8xlarge": "2.700", + "m3.xlarge": "0.550", + "m3.2xlarge": "1.560", + "cr1.8xlarge": "3.750", + "os1.8xlarge": "6.400", + "os1.8xlarge": "6.400" } }, "storage": {}, diff --git a/libcloud/test/compute/test_ec2.py b/libcloud/test/compute/test_ec2.py index 6d665457b5..244958bed2 100644 --- a/libcloud/test/compute/test_ec2.py +++ b/libcloud/test/compute/test_ec2.py @@ -30,6 +30,7 @@ from libcloud.compute.drivers.ec2 import EC2APSESydneyNodeDriver from libcloud.compute.drivers.ec2 import EC2SAEastNodeDriver from libcloud.compute.drivers.ec2 import NimbusNodeDriver, EucNodeDriver +from libcloud.compute.drivers.ec2 import OutscaleSASNodeDriver from libcloud.compute.drivers.ec2 import IdempotentParamError from libcloud.compute.drivers.ec2 import REGION_DETAILS from libcloud.compute.drivers.ec2 import ExEC2AvailabilityZone @@ -1522,5 +1523,97 @@ def test_list_sizes(self): self.assertTrue('m3.xlarge' in ids) +class OutscaleTests(EC2Tests): + + def setUp(self): + OutscaleSASNodeDriver.connectionCls.conn_classes = (None, EC2MockHttp) + EC2MockHttp.use_param = 'Action' + EC2MockHttp.type = None + self.driver = OutscaleSASNodeDriver(key=EC2_PARAMS[0], + secret=EC2_PARAMS[1], + host='some.outscalecloud.com') + + def test_ex_create_network(self): + # overridden from EC2Tests -- Outscale don't support instance_tenancy + vpc = self.driver.ex_create_network('192.168.55.0/24', + name='Test VPC') + + self.assertEqual('vpc-ad3527cf', vpc.id) + self.assertEqual('192.168.55.0/24', vpc.cidr_block) + self.assertEqual('pending', vpc.extra['state']) + + def test_ex_copy_image(self): + # overridden from EC2Tests -- Outscale does not support copying images + image = self.driver.list_images()[0] + try: + self.driver.ex_copy_image('us-east-1', image, + name='Faux Image', + description='Test Image Copy') + except NotImplementedError: + pass + else: + self.fail('Exception was not thrown') + + def test_ex_get_limits(self): + # overridden from EC2Tests -- Outscale does not support getting limits + try: + self.driver.ex_get_limits() + except NotImplementedError: + pass + else: + self.fail('Exception was not thrown') + + def test_ex_create_network_interface(self): + # overridden from EC2Tests -- Outscale don't allow creating interfaces + subnet = self.driver.ex_list_subnets()[0] + try: + self.driver.ex_create_network_interface( + subnet, + name='Test Interface', + description='My Test') + except NotImplementedError: + pass + else: + self.fail('Exception was not thrown') + + def test_ex_delete_network_interface(self): + # overridden from EC2Tests -- Outscale don't allow deleting interfaces + interface = self.driver.ex_list_network_interfaces()[0] + try: + self.driver.ex_delete_network_interface(interface) + except NotImplementedError: + pass + else: + self.fail('Exception was not thrown') + + def test_ex_attach_network_interface_to_node(self): + # overridden from EC2Tests -- Outscale don't allow attaching interfaces + node = self.driver.list_nodes()[0] + interface = self.driver.ex_list_network_interfaces()[0] + try: + self.driver.ex_attach_network_interface_to_node(interface, node, 1) + except NotImplementedError: + pass + else: + self.fail('Exception was not thrown') + + def test_ex_detach_network_interface(self): + # overridden from EC2Tests -- Outscale don't allow detaching interfaces + try: + self.driver.ex_detach_network_interface('eni-attach-2b588b47') + except NotImplementedError: + pass + else: + self.fail('Exception was not thrown') + + def test_list_sizes(self): + sizes = self.driver.list_sizes() + + ids = [s.id for s in sizes] + self.assertTrue('m1.small' in ids) + self.assertTrue('m1.large' in ids) + self.assertTrue('m1.xlarge' in ids) + + if __name__ == '__main__': sys.exit(unittest.main())