You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@libcloud.apache.org by GitBox <gi...@apache.org> on 2020/07/21 12:00:58 UTC

[GitHub] [libcloud] tgn-outscale opened a new pull request #1476: New compute driver OUTSCALE

tgn-outscale opened a new pull request #1476:
URL: https://github.com/apache/libcloud/pull/1476


   ## Description
   
   This PR add a new compute driver name OUTSCALE, it is added in file types.py of compute section, a osc.py file for authentification and a new file named outscale.py to perform actions of the OUTSCALE API using requests. See the documentation link: https://docs.outscale.com/api
   
   This PR is a reworked version of https://github.com/apache/libcloud/pull/1345 using python requests lib instead of using outscale python sdk.
   
   ### Status
   - done, ready for review
   
   ### Checklist (tick everything that applies)
   
   - [x] Code linting (required, can be done after the PR checks)
   
   - [x] Documentation (do the documentation refer to the docstring ?)
   
   - [x] Tests
   
   - [ ] ICLA (required for bigger changes)
   
   Legal Team is currently working on the ICLA.
   I have made some tests but a lot are still missing for now.
   Not sure if this is enough.
   
   Happy to receive thoughs.


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [libcloud] tgn-outscale commented on pull request #1476: New compute driver OUTSCALE

Posted by GitBox <gi...@apache.org>.
tgn-outscale commented on pull request #1476:
URL: https://github.com/apache/libcloud/pull/1476#issuecomment-674169318


   Thanks for your review @Kami, I will make these changes and come back to you as soon as possible.


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [libcloud] Kami commented on pull request #1476: New compute driver OUTSCALE

Posted by GitBox <gi...@apache.org>.
Kami commented on pull request #1476:
URL: https://github.com/apache/libcloud/pull/1476#issuecomment-667667335


   @tgn-outscale Thanks for the contribution and sorry for the delay. I will have a more detailed look a bit later.
   
   For now, I'm just trying to understand how this fits along with the existing Outscale driver which is based on the EC2 one? Is the EC2 based one still relevant, or should we remove it?


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [libcloud] Kami commented on pull request #1476: New compute driver OUTSCALE

Posted by GitBox <gi...@apache.org>.
Kami commented on pull request #1476:
URL: https://github.com/apache/libcloud/pull/1476#issuecomment-674096348


   I've added some in-line comments.
   
   Overall, the changes mostly look good, but the code needs a bit more work to reduce duplication and to make sure the methods and method arguments comply with the base Libcloud API - that's one of the main ideas behind Libcloud - all the provider drivers should expose the same API (where possible), so users can easily switch between different providers and non-standard methods and arguments should be prefixed with ``ex_``.


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [libcloud] Kami commented on a change in pull request #1476: New compute driver OUTSCALE

Posted by GitBox <gi...@apache.org>.
Kami commented on a change in pull request #1476:
URL: https://github.com/apache/libcloud/pull/1476#discussion_r470649055



##########
File path: libcloud/compute/drivers/outscale.py
##########
@@ -0,0 +1,1109 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""
+Outscale SDK
+"""
+
+import json
+
+import requests
+
+from libcloud.compute.base import NodeDriver
+from libcloud.compute.types import Provider
+from libcloud.common.osc import OSCRequestSignerAlgorithmV4
+from libcloud.common.base import ConnectionUserAndKey
+
+
+class OutscaleNodeDriver(NodeDriver):
+    """
+    Outscale SDK node driver
+    """
+
+    type = Provider.OUTSCALE
+    name = 'Outscale API'
+    website = 'http://www.outscale.com'
+
+    def __init__(self,
+                 key=None,
+                 secret=None,
+                 region='eu-west-2',
+                 service='api',
+                 version='latest'
+                 ):
+        self.key = key
+        self.secret = secret
+        self.region = region
+        self.connection = ConnectionUserAndKey(self.key, self.secret)
+        self.connection.region_name = region
+        self.connection.service_name = service
+        self.service_name = service
+        self.version = version
+
+    def list_locations(self, dry_run=False):
+        """
+        Lists available regions details.
+
+        :return: regions details
+        :rtype: ``dict``
+        """
+        action = "ReadRegions"
+        data = json.dumps({"DryRun": dry_run})
+        signer = OSCRequestSignerAlgorithmV4(access_key=self.key,
+                                             access_secret=self.secret,
+                                             version=self.version,
+                                             connection=self.connection)
+        headers = signer.get_request_headers(action=action,
+                                             data=data,
+                                             service_name=self.service_name,
+                                             region=self.region)
+        endpoint = self._get_outscale_endpoint(self.region,
+                                               self.version,
+                                               action)
+        return requests.post(endpoint, data=data, headers=headers)
+
+    def create_public_ip(self, dry_run=False):
+        """
+        Create a new public ip.
+
+        :param      dry_run: If true, checks whether you have the required
+        permissions to perform the action.
+        :type       dry_run: ``bool``
+
+        :return: the created public ip
+        :rtype: ``dict``
+            """
+        action = "CreatePublicIp"
+        data = json.dumps({"DryRun": dry_run})
+        signer = OSCRequestSignerAlgorithmV4(access_key=self.key,
+                                             access_secret=self.secret,
+                                             version=self.version,
+                                             connection=self.connection)
+        headers = signer.get_request_headers(action=action,
+                                             data=data,
+                                             service_name=self.service_name,
+                                             region=self.region)
+        endpoint = self._get_outscale_endpoint(self.region,
+                                               self.version,
+                                               action)
+        return requests.post(endpoint, data=data, headers=headers)
+
+    def delete_public_ip(self, dry_run=False,
+                         public_ip=None,
+                         public_ip_id=None):
+        """
+        Delete instances.
+
+        :param      dry_run: If true, checks whether you have the required
+        permissions to perform the action.
+        :type       dry_run: ``bool``
+
+        :param      public_ip: The EIP. In the public Cloud, this parameter is
+        required.
+        :type       public_ip: ``str``
+
+        :param      public_ip_id: The ID representing the association of the
+        EIP with the VM or the NIC. In a Net,
+        this parameter is required.
+        :type       public_ip_id: ``str``
+
+        :return: request
+        :rtype: ``dict``
+        """
+        action = "DeletePublicIp"
+        data = {"DryRun": dry_run}
+        if public_ip is not None:
+            data.update({"PublicIp": public_ip})
+        if public_ip_id is not None:
+            data.update({"PublicIpId": public_ip_id})
+        data = json.dumps(data)
+        signer = OSCRequestSignerAlgorithmV4(access_key=self.key,
+                                             access_secret=self.secret,
+                                             version=self.version,
+                                             connection=self.connection)
+        headers = signer.get_request_headers(action=action,
+                                             data=data,
+                                             service_name=self.service_name,
+                                             region=self.region)
+        endpoint = self._get_outscale_endpoint(self.region,
+                                               self.version,
+                                               action)
+        return requests.post(endpoint, data=data, headers=headers)
+
+    def list_public_ips(self, data="{}"):
+        """
+        List all nodes.
+
+        :param      data: json stringify following the outscale api
+        documentation for filter
+        :type       data: ``string``
+
+        :return: nodes
+        :rtype: ``dict``
+        """
+        action = "ReadPublicIps"
+        signer = OSCRequestSignerAlgorithmV4(access_key=self.key,
+                                             access_secret=self.secret,
+                                             version=self.version,
+                                             connection=self.connection)
+        headers = signer.get_request_headers(action=action,
+                                             data=data,
+                                             service_name=self.service_name,
+                                             region=self.region)
+        endpoint = self._get_outscale_endpoint(self.region,
+                                               self.version,
+                                               action)
+        return requests.post(endpoint, data=data, headers=headers)
+
+    def list_public_ip_ranges(self, dry_run=False):
+        """
+        Lists available regions details.
+
+        :param      dry_run: If true, checks whether you have the
+        required permissions to perform the action.
+        :type       dry_run: ``bool``
+
+        :return: regions details
+        :rtype: ``dict``
+        """
+        action = "ReadPublicIpRanges"
+        data = json.dumps({"DryRun": dry_run})
+        signer = OSCRequestSignerAlgorithmV4(access_key=self.key,
+                                             access_secret=self.secret,
+                                             version=self.version,
+                                             connection=self.connection)
+        headers = signer.get_request_headers(action=action,
+                                             data=data,
+                                             service_name=self.service_name,
+                                             region=self.region)
+        endpoint = self._get_outscale_endpoint(self.region,
+                                               self.version,
+                                               action)
+        return requests.post(endpoint, data=data, headers=headers)
+
+    def attach_public_ip(self,
+                         allow_relink=None,
+                         dry_run=False,
+                         nic_id=None,
+                         vm_id=None,
+                         public_ip=None,
+                         public_ip_id=None,
+                         ):
+        """
+        Attach a volume.
+
+        :param      allow_relink: If true, allows the EIP to be associated
+        with the VM or NIC that you specify even if
+        it is already associated with another VM or NIC.
+        :type       allow_relink: ``bool``
+
+        :param      dry_run: If true, checks whether you have the required
+        permissions to perform the action.
+        :type       dry_run: ``bool``
+
+        :param      nic_id:(Net only) The ID of the NIC. This parameter is
+        required if the VM has more than one NIC attached. Otherwise,
+        you need to specify the VmId parameter instead.
+        You cannot specify both parameters
+        at the same time.
+        :type       nic_id: ``str``
+
+        :param      vm_id: the ID of the VM
+        :type       nic_id: ``str``
+
+        :param      public_ip: The EIP. In the public Cloud, this parameter
+        is required.
+        :type       public_ip: ``str``
+
+        :param      public_ip_id: The allocation ID of the EIP. In a Net,
+        this parameter is required.
+        :type       public_ip_id: ``str``
+
+        :return: the attached volume
+        :rtype: ``dict``
+        """
+        action = "LinkPublicIp"
+        data = {"DryRun": dry_run}
+        if public_ip is not None:
+            data.update({"PublicIp": public_ip})
+        if public_ip_id is not None:
+            data.update({"PublicIpId": public_ip_id})
+        if nic_id is not None:
+            data.update({"NicId": nic_id})
+        if vm_id is not None:
+            data.update({"VmId": vm_id})
+        if allow_relink is not None:
+            data.update({"AllowRelink": allow_relink})
+        data = json.dumps(data)
+        signer = OSCRequestSignerAlgorithmV4(access_key=self.key,
+                                             access_secret=self.secret,
+                                             version=self.version,
+                                             connection=self.connection)
+        headers = signer.get_request_headers(action=action,
+                                             data=data,
+                                             service_name=self.service_name,
+                                             region=self.region)
+        endpoint = self._get_outscale_endpoint(self.region,
+                                               self.version,
+                                               action)
+        return requests.post(endpoint, data=data, headers=headers)
+
+    def detach_public_ip(self, public_ip=None,
+                         link_public_ip_id=None,
+                         dry_run=False):
+        """
+        Detach a volume.
+
+        :param      public_ip: (Required in a Net) The ID representing the
+        association of the EIP with the VM or the NIC
+        :type       public_ip: ``str``
+
+        :param      link_public_ip_id: (Required in a Net) The ID
+        representing the association of the EIP with the
+        VM or the NIC.
+        :type       link_public_ip_id: ``str``
+
+        :param      dry_run: If true, checks whether you have the required
+        permissions to perform the action.
+        :type       dry_run: ``bool``
+
+        :return: the attached volume
+        :rtype: ``dict``
+        """
+        action = "UnlinkPublicIp"
+        data = {"DryRun": dry_run}
+        if public_ip is not None:
+            data.update({"PublicIp": public_ip})
+        if link_public_ip_id is not None:
+            data.update({"LinkPublicIpId": link_public_ip_id})
+        data = json.dumps(data)
+        signer = OSCRequestSignerAlgorithmV4(access_key=self.key,
+                                             access_secret=self.secret,
+                                             version=self.version,
+                                             connection=self.connection)
+        headers = signer.get_request_headers(action=action,
+                                             data=data,
+                                             service_name=self.service_name,
+                                             region=self.region)
+        endpoint = self._get_outscale_endpoint(self.region,
+                                               self.version,
+                                               action)
+        return requests.post(endpoint, data=data, headers=headers)
+
+    def create_node(self,
+                    image_id,
+                    dry_run=False,
+                    block_device_mapping=None,
+                    boot_on_creation=True,
+                    bsu_optimized=True,
+                    client_token=None,
+                    deletion_protection=False,
+                    keypair_name=None,
+                    max_vms_count=None,
+                    min_vms_count=None,
+                    nics=None,
+                    performance=None,
+                    placement=None,
+                    private_ips=None,
+                    security_group_ids=None,
+                    security_groups=None,
+                    subnet_id=None,
+                    ):
+        """
+        Create a new instance.
+
+        :param      image_id: The ID of the OMI used to create the VM.
+        :type       image_id: ``str``
+
+        :param      dry_run: If true, checks whether you have the required
+        permissions to perform the action.
+        :type       dry_run: ``bool``
+
+        :param      block_device_mapping: One or more block device mappings.
+        :type       block_device_mapping: ``dict``
+
+        :param      boot_on_creation: By default or if true, the VM is
+        started on creation. If false, the VM is
+        stopped on creation.
+        :type       boot_on_creation: ``bool``
+
+        :param      bsu_optimized: If true, the VM is created with optimized
+        BSU I/O.
+        :type       bsu_optimized: ``bool``
+
+        :param      client_token: A unique identifier which enables you to
+        manage the idempotency.
+        :type       client_token: ``bool``
+
+        :param      deletion_protection: If true, you cannot terminate the
+        VM using Cockpit, the CLI or the API.
+        If false, you can.
+        :type       deletion_protection: ``bool``
+
+        :param      keypair_name: The name of the keypair.
+        :type       keypair_name: ``str``
+
+        :param      max_vms_count: The maximum number of VMs you want to
+        create. If all the VMs cannot be created, the
+        largest possible number of VMs above MinVmsCount is created.
+        :type       max_vms_count: ``integer``
+
+        :param      min_vms_count: The minimum number of VMs you want to
+        create. If this number of VMs cannot be
+        created, no VMs are created.
+        :type       min_vms_count: ``integer``
+
+        :param      nics: One or more NICs. If you specify this parameter,
+        you must define one NIC as the primary
+        network interface of the VM with 0 as its device number.
+        :type       nics: ``dict``
+
+        :param      performance: The performance of the VM (standard | high
+        | highest).
+        :type       performance: ``str``
+
+        :param      placement: Information about the placement of the VM.
+        :type       placement: ``dict``
+
+        :param      private_ips: One or more private IP addresses of the VM.
+        :type       private_ips: ``list``
+
+        :param      security_group_ids: One or more IDs of security group
+        for the VMs.
+        :type       security_group_ids: ``list``
+
+        :param      security_groups: One or more names of security groups
+        for the VMs.
+        :type       security_groups: ``list``
+
+        :param      subnet_id: The ID of the Subnet in which you want to
+        create the VM.
+        :type       subnet_id: ``str``
+
+        :return: the created instance
+        :rtype: ``dict``
+        """
+        data = {
+            "DryRun": dry_run,
+            "BootOnCreation": boot_on_creation,
+            "BsuOptimized": bsu_optimized,
+            "ImageId": image_id
+        }
+        if block_device_mapping is not None:
+            data.update({"BlockDeviceMappings": block_device_mapping})
+        if client_token is not None:
+            data.update({"ClientToken": client_token})
+        if deletion_protection is not None:
+            data.update({"DeletionProtection": deletion_protection})
+        if keypair_name is not None:
+            data.update({"KeypairName": keypair_name})
+        if max_vms_count is not None:
+            data.update({"MaxVmsCount": max_vms_count})
+        if min_vms_count is not None:
+            data.update({"MinVmsCount": min_vms_count})
+        if nics is not None:
+            data.update({"Nics": nics})
+        if performance is not None:
+            data.update({"Performance": performance})
+        if placement is not None:
+            data.update({"Placement": placement})
+        if private_ips is not None:
+            data.update({"PrivateIps": private_ips})
+        if security_group_ids is not None:
+            data.update({"SecurityGroupIds": security_group_ids})
+        if security_groups is not None:
+            data.update({"SecurityGroups": security_groups})
+        if subnet_id is not None:
+            data.update({"SubnetId": subnet_id})
+        action = "CreateVms"
+        data = json.dumps(data)
+        signer = OSCRequestSignerAlgorithmV4(access_key=self.key,
+                                             access_secret=self.secret,
+                                             version=self.version,
+                                             connection=self.connection)
+        headers = signer.get_request_headers(action=action,
+                                             data=data,
+                                             service_name=self.service_name,
+                                             region=self.region)
+        endpoint = self._get_outscale_endpoint(self.region,
+                                               self.version,
+                                               action)
+        return requests.post(endpoint, data=data, headers=headers)
+
+    def reboot_node(self, node_ids):
+        """
+        Reboot instances.
+
+        :param      node_ids: the ID(s) of the VM(s)
+                    you want to reboot (required)
+        :type       node_ids: ``list``
+
+        :return: the rebooted instances
+        :rtype: ``dict``
+        """
+        action = "RebootVms"
+        data = json.dumps({"VmIds": node_ids})
+        signer = OSCRequestSignerAlgorithmV4(access_key=self.key,
+                                             access_secret=self.secret,
+                                             version=self.version,
+                                             connection=self.connection)
+        headers = signer.get_request_headers(action=action,
+                                             data=data,
+                                             service_name=self.service_name,
+                                             region=self.region)
+        endpoint = self._get_outscale_endpoint(self.region,
+                                               self.version,
+                                               action)
+        return requests.post(endpoint, data=data, headers=headers)
+
+    def list_nodes(self, data="{}"):
+        """
+        List all nodes.
+
+        :return: nodes
+        :rtype: ``dict``
+        """
+        action = "ReadVms"
+        signer = OSCRequestSignerAlgorithmV4(access_key=self.key,
+                                             access_secret=self.secret,
+                                             version=self.version,
+                                             connection=self.connection)
+        headers = signer.get_request_headers(action=action,
+                                             data=data,
+                                             service_name=self.service_name,
+                                             region=self.region)
+        endpoint = self._get_outscale_endpoint(self.region,
+                                               self.version,
+                                               action)
+        return requests.post(endpoint, data=data, headers=headers)
+
+    def delete_node(self, node_ids):
+        """
+        Delete instances.
+
+        :param      node_ids: one or more IDs of VMs (required)
+        :type       node_ids: ``list``
+
+        :return: request
+        :rtype: ``dict``
+        """
+        action = "DeleteVms"
+        data = json.dumps({"VmIds": node_ids})
+        signer = OSCRequestSignerAlgorithmV4(access_key=self.key,
+                                             access_secret=self.secret,
+                                             version=self.version,
+                                             connection=self.connection)
+        headers = signer.get_request_headers(action=action,
+                                             data=data,
+                                             service_name=self.service_name,
+                                             region=self.region)
+        endpoint = self._get_outscale_endpoint(self.region,
+                                               self.version,
+                                               action)
+        return requests.post(endpoint, data=data, headers=headers)
+
+    def create_image(
+        self,
+        architecture=None,
+        vm_id=None,
+        image_name=None,
+        description=None,
+        block_device_mapping=None,
+        no_reboot=False,
+        root_device_name=None,
+        dry_run=False,
+        source_region_name=None,
+        file_location=None
+    ):
+        """
+        Create a new image.
+
+        :param      vm_id: the ID of the VM from which
+                    you want to create the OMI (required)
+        :type       vm_id: ``str``
+
+        :param      architecture: The architecture of the OMI (by default,
+        i386).
+        :type       architecture: ``str``
+
+        :param      description: a description for the new OMI
+        :type       description: ``str``
+
+        :param      image_name: A unique name for the new OMI.
+        :type       image_name: ``str``
+
+        :param      block_device_mapping: One or more block device mappings.
+        :type       block_device_mapping: ``dict``
+
+        :param      no_reboot: If false, the VM shuts down before creating
+        the OMI and then reboots.
+        If true, the VM does not.
+        :type       no_reboot: ``bool``
+
+        :param      root_device_name: The name of the root device.
+        :type       root_device_name: ``str``
+
+        :param      source_region_name: The name of the source Region,
+        which must be the same
+        as the Region of your account.
+        :type       source_region_name: ``str``
+
+        :param      file_location: The pre-signed URL of the OMI manifest
+        file, or the full path to the OMI stored in
+        an OSU bucket. If you specify this parameter, a copy of the OMI is
+        created in your account.
+        :type       file_location: ``str``
+
+        :param      dry_run: If true, checks whether you have the required
+        permissions to perform the action.
+        :type       dry_run: ``bool``
+
+        :return: the created image
+        :rtype: ``dict``
+        """
+        data = {
+            "DryRun": dry_run,
+            "NoReboot": no_reboot,
+        }
+        if block_device_mapping is not None:
+            data.update({"BlockDeviceMappings": block_device_mapping})
+        if image_name is not None:
+            data.update({"ImageName": image_name})
+        if description is not None:
+            data.update({"Description": description})
+        if vm_id is not None:
+            data.update({"VmId": vm_id})
+        if root_device_name is not None:
+            data.update({"RootDeviceName": root_device_name})
+        if source_region_name is not None:
+            data.update({"SourceRegionName": source_region_name})
+        if file_location is not None:
+            data.update({"FileLocation": file_location})
+        data = json.dumps(data)
+        action = "CreateImage"
+        signer = OSCRequestSignerAlgorithmV4(access_key=self.key,
+                                             access_secret=self.secret,
+                                             version=self.version,
+                                             connection=self.connection)
+        headers = signer.get_request_headers(action=action,
+                                             data=data,
+                                             service_name=self.service_name,
+                                             region=self.region)
+        endpoint = self._get_outscale_endpoint(self.region,
+                                               self.version,
+                                               action)
+        return requests.post(endpoint, data=data, headers=headers)
+
+    def list_images(self, data="{}"):

Review comment:
       Needs to return a list of ``NodeImage`` objects. data is a non-standard argument so it needs to be prefixed with ``ex_``.




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [libcloud] Kami commented on a change in pull request #1476: New compute driver OUTSCALE

Posted by GitBox <gi...@apache.org>.
Kami commented on a change in pull request #1476:
URL: https://github.com/apache/libcloud/pull/1476#discussion_r470648144



##########
File path: libcloud/compute/drivers/outscale.py
##########
@@ -0,0 +1,1109 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""
+Outscale SDK
+"""
+
+import json
+
+import requests
+
+from libcloud.compute.base import NodeDriver
+from libcloud.compute.types import Provider
+from libcloud.common.osc import OSCRequestSignerAlgorithmV4
+from libcloud.common.base import ConnectionUserAndKey
+
+
+class OutscaleNodeDriver(NodeDriver):
+    """
+    Outscale SDK node driver
+    """
+
+    type = Provider.OUTSCALE
+    name = 'Outscale API'
+    website = 'http://www.outscale.com'
+
+    def __init__(self,
+                 key=None,
+                 secret=None,
+                 region='eu-west-2',
+                 service='api',
+                 version='latest'
+                 ):
+        self.key = key
+        self.secret = secret
+        self.region = region
+        self.connection = ConnectionUserAndKey(self.key, self.secret)
+        self.connection.region_name = region
+        self.connection.service_name = service
+        self.service_name = service
+        self.version = version
+
+    def list_locations(self, dry_run=False):
+        """
+        Lists available regions details.
+
+        :return: regions details
+        :rtype: ``dict``
+        """
+        action = "ReadRegions"
+        data = json.dumps({"DryRun": dry_run})
+        signer = OSCRequestSignerAlgorithmV4(access_key=self.key,
+                                             access_secret=self.secret,
+                                             version=self.version,
+                                             connection=self.connection)
+        headers = signer.get_request_headers(action=action,
+                                             data=data,
+                                             service_name=self.service_name,
+                                             region=self.region)
+        endpoint = self._get_outscale_endpoint(self.region,
+                                               self.version,
+                                               action)
+        return requests.post(endpoint, data=data, headers=headers)
+
+    def create_public_ip(self, dry_run=False):
+        """
+        Create a new public ip.
+
+        :param      dry_run: If true, checks whether you have the required
+        permissions to perform the action.
+        :type       dry_run: ``bool``
+
+        :return: the created public ip
+        :rtype: ``dict``
+            """
+        action = "CreatePublicIp"
+        data = json.dumps({"DryRun": dry_run})
+        signer = OSCRequestSignerAlgorithmV4(access_key=self.key,
+                                             access_secret=self.secret,
+                                             version=self.version,
+                                             connection=self.connection)
+        headers = signer.get_request_headers(action=action,
+                                             data=data,
+                                             service_name=self.service_name,
+                                             region=self.region)
+        endpoint = self._get_outscale_endpoint(self.region,
+                                               self.version,
+                                               action)
+        return requests.post(endpoint, data=data, headers=headers)
+
+    def delete_public_ip(self, dry_run=False,
+                         public_ip=None,
+                         public_ip_id=None):
+        """
+        Delete instances.
+
+        :param      dry_run: If true, checks whether you have the required
+        permissions to perform the action.
+        :type       dry_run: ``bool``
+
+        :param      public_ip: The EIP. In the public Cloud, this parameter is
+        required.
+        :type       public_ip: ``str``
+
+        :param      public_ip_id: The ID representing the association of the
+        EIP with the VM or the NIC. In a Net,
+        this parameter is required.
+        :type       public_ip_id: ``str``
+
+        :return: request
+        :rtype: ``dict``
+        """
+        action = "DeletePublicIp"
+        data = {"DryRun": dry_run}
+        if public_ip is not None:
+            data.update({"PublicIp": public_ip})
+        if public_ip_id is not None:
+            data.update({"PublicIpId": public_ip_id})
+        data = json.dumps(data)
+        signer = OSCRequestSignerAlgorithmV4(access_key=self.key,
+                                             access_secret=self.secret,
+                                             version=self.version,
+                                             connection=self.connection)
+        headers = signer.get_request_headers(action=action,
+                                             data=data,
+                                             service_name=self.service_name,
+                                             region=self.region)
+        endpoint = self._get_outscale_endpoint(self.region,
+                                               self.version,
+                                               action)
+        return requests.post(endpoint, data=data, headers=headers)
+
+    def list_public_ips(self, data="{}"):
+        """
+        List all nodes.
+
+        :param      data: json stringify following the outscale api
+        documentation for filter
+        :type       data: ``string``
+
+        :return: nodes
+        :rtype: ``dict``
+        """
+        action = "ReadPublicIps"
+        signer = OSCRequestSignerAlgorithmV4(access_key=self.key,
+                                             access_secret=self.secret,
+                                             version=self.version,
+                                             connection=self.connection)
+        headers = signer.get_request_headers(action=action,
+                                             data=data,
+                                             service_name=self.service_name,
+                                             region=self.region)
+        endpoint = self._get_outscale_endpoint(self.region,
+                                               self.version,
+                                               action)
+        return requests.post(endpoint, data=data, headers=headers)
+
+    def list_public_ip_ranges(self, dry_run=False):
+        """
+        Lists available regions details.
+
+        :param      dry_run: If true, checks whether you have the
+        required permissions to perform the action.
+        :type       dry_run: ``bool``
+
+        :return: regions details
+        :rtype: ``dict``
+        """
+        action = "ReadPublicIpRanges"
+        data = json.dumps({"DryRun": dry_run})
+        signer = OSCRequestSignerAlgorithmV4(access_key=self.key,
+                                             access_secret=self.secret,
+                                             version=self.version,
+                                             connection=self.connection)
+        headers = signer.get_request_headers(action=action,
+                                             data=data,
+                                             service_name=self.service_name,
+                                             region=self.region)
+        endpoint = self._get_outscale_endpoint(self.region,
+                                               self.version,
+                                               action)
+        return requests.post(endpoint, data=data, headers=headers)
+
+    def attach_public_ip(self,
+                         allow_relink=None,
+                         dry_run=False,
+                         nic_id=None,
+                         vm_id=None,
+                         public_ip=None,
+                         public_ip_id=None,
+                         ):
+        """
+        Attach a volume.
+
+        :param      allow_relink: If true, allows the EIP to be associated
+        with the VM or NIC that you specify even if
+        it is already associated with another VM or NIC.
+        :type       allow_relink: ``bool``
+
+        :param      dry_run: If true, checks whether you have the required
+        permissions to perform the action.
+        :type       dry_run: ``bool``
+
+        :param      nic_id:(Net only) The ID of the NIC. This parameter is
+        required if the VM has more than one NIC attached. Otherwise,
+        you need to specify the VmId parameter instead.
+        You cannot specify both parameters
+        at the same time.
+        :type       nic_id: ``str``
+
+        :param      vm_id: the ID of the VM
+        :type       nic_id: ``str``
+
+        :param      public_ip: The EIP. In the public Cloud, this parameter
+        is required.
+        :type       public_ip: ``str``
+
+        :param      public_ip_id: The allocation ID of the EIP. In a Net,
+        this parameter is required.
+        :type       public_ip_id: ``str``
+
+        :return: the attached volume
+        :rtype: ``dict``
+        """
+        action = "LinkPublicIp"
+        data = {"DryRun": dry_run}
+        if public_ip is not None:
+            data.update({"PublicIp": public_ip})
+        if public_ip_id is not None:
+            data.update({"PublicIpId": public_ip_id})
+        if nic_id is not None:
+            data.update({"NicId": nic_id})
+        if vm_id is not None:
+            data.update({"VmId": vm_id})
+        if allow_relink is not None:
+            data.update({"AllowRelink": allow_relink})
+        data = json.dumps(data)
+        signer = OSCRequestSignerAlgorithmV4(access_key=self.key,
+                                             access_secret=self.secret,
+                                             version=self.version,
+                                             connection=self.connection)
+        headers = signer.get_request_headers(action=action,
+                                             data=data,
+                                             service_name=self.service_name,
+                                             region=self.region)
+        endpoint = self._get_outscale_endpoint(self.region,
+                                               self.version,
+                                               action)
+        return requests.post(endpoint, data=data, headers=headers)
+
+    def detach_public_ip(self, public_ip=None,
+                         link_public_ip_id=None,
+                         dry_run=False):
+        """
+        Detach a volume.
+
+        :param      public_ip: (Required in a Net) The ID representing the
+        association of the EIP with the VM or the NIC
+        :type       public_ip: ``str``
+
+        :param      link_public_ip_id: (Required in a Net) The ID
+        representing the association of the EIP with the
+        VM or the NIC.
+        :type       link_public_ip_id: ``str``
+
+        :param      dry_run: If true, checks whether you have the required
+        permissions to perform the action.
+        :type       dry_run: ``bool``
+
+        :return: the attached volume
+        :rtype: ``dict``
+        """
+        action = "UnlinkPublicIp"
+        data = {"DryRun": dry_run}
+        if public_ip is not None:
+            data.update({"PublicIp": public_ip})
+        if link_public_ip_id is not None:
+            data.update({"LinkPublicIpId": link_public_ip_id})
+        data = json.dumps(data)
+        signer = OSCRequestSignerAlgorithmV4(access_key=self.key,
+                                             access_secret=self.secret,
+                                             version=self.version,
+                                             connection=self.connection)
+        headers = signer.get_request_headers(action=action,
+                                             data=data,
+                                             service_name=self.service_name,
+                                             region=self.region)
+        endpoint = self._get_outscale_endpoint(self.region,
+                                               self.version,
+                                               action)
+        return requests.post(endpoint, data=data, headers=headers)
+
+    def create_node(self,
+                    image_id,
+                    dry_run=False,
+                    block_device_mapping=None,
+                    boot_on_creation=True,
+                    bsu_optimized=True,
+                    client_token=None,
+                    deletion_protection=False,
+                    keypair_name=None,
+                    max_vms_count=None,
+                    min_vms_count=None,
+                    nics=None,
+                    performance=None,
+                    placement=None,
+                    private_ips=None,
+                    security_group_ids=None,
+                    security_groups=None,
+                    subnet_id=None,
+                    ):
+        """
+        Create a new instance.
+
+        :param      image_id: The ID of the OMI used to create the VM.
+        :type       image_id: ``str``
+
+        :param      dry_run: If true, checks whether you have the required
+        permissions to perform the action.
+        :type       dry_run: ``bool``
+
+        :param      block_device_mapping: One or more block device mappings.
+        :type       block_device_mapping: ``dict``
+
+        :param      boot_on_creation: By default or if true, the VM is
+        started on creation. If false, the VM is
+        stopped on creation.
+        :type       boot_on_creation: ``bool``
+
+        :param      bsu_optimized: If true, the VM is created with optimized
+        BSU I/O.
+        :type       bsu_optimized: ``bool``
+
+        :param      client_token: A unique identifier which enables you to
+        manage the idempotency.
+        :type       client_token: ``bool``
+
+        :param      deletion_protection: If true, you cannot terminate the
+        VM using Cockpit, the CLI or the API.
+        If false, you can.
+        :type       deletion_protection: ``bool``
+
+        :param      keypair_name: The name of the keypair.
+        :type       keypair_name: ``str``
+
+        :param      max_vms_count: The maximum number of VMs you want to
+        create. If all the VMs cannot be created, the
+        largest possible number of VMs above MinVmsCount is created.
+        :type       max_vms_count: ``integer``
+
+        :param      min_vms_count: The minimum number of VMs you want to
+        create. If this number of VMs cannot be
+        created, no VMs are created.
+        :type       min_vms_count: ``integer``
+
+        :param      nics: One or more NICs. If you specify this parameter,
+        you must define one NIC as the primary
+        network interface of the VM with 0 as its device number.
+        :type       nics: ``dict``
+
+        :param      performance: The performance of the VM (standard | high
+        | highest).
+        :type       performance: ``str``
+
+        :param      placement: Information about the placement of the VM.
+        :type       placement: ``dict``
+
+        :param      private_ips: One or more private IP addresses of the VM.
+        :type       private_ips: ``list``
+
+        :param      security_group_ids: One or more IDs of security group
+        for the VMs.
+        :type       security_group_ids: ``list``
+
+        :param      security_groups: One or more names of security groups
+        for the VMs.
+        :type       security_groups: ``list``
+
+        :param      subnet_id: The ID of the Subnet in which you want to
+        create the VM.
+        :type       subnet_id: ``str``
+
+        :return: the created instance
+        :rtype: ``dict``
+        """
+        data = {
+            "DryRun": dry_run,
+            "BootOnCreation": boot_on_creation,
+            "BsuOptimized": bsu_optimized,
+            "ImageId": image_id
+        }
+        if block_device_mapping is not None:
+            data.update({"BlockDeviceMappings": block_device_mapping})
+        if client_token is not None:
+            data.update({"ClientToken": client_token})
+        if deletion_protection is not None:
+            data.update({"DeletionProtection": deletion_protection})
+        if keypair_name is not None:
+            data.update({"KeypairName": keypair_name})
+        if max_vms_count is not None:
+            data.update({"MaxVmsCount": max_vms_count})
+        if min_vms_count is not None:
+            data.update({"MinVmsCount": min_vms_count})
+        if nics is not None:
+            data.update({"Nics": nics})
+        if performance is not None:
+            data.update({"Performance": performance})
+        if placement is not None:
+            data.update({"Placement": placement})
+        if private_ips is not None:
+            data.update({"PrivateIps": private_ips})
+        if security_group_ids is not None:
+            data.update({"SecurityGroupIds": security_group_ids})
+        if security_groups is not None:
+            data.update({"SecurityGroups": security_groups})
+        if subnet_id is not None:
+            data.update({"SubnetId": subnet_id})
+        action = "CreateVms"
+        data = json.dumps(data)
+        signer = OSCRequestSignerAlgorithmV4(access_key=self.key,
+                                             access_secret=self.secret,
+                                             version=self.version,
+                                             connection=self.connection)
+        headers = signer.get_request_headers(action=action,
+                                             data=data,
+                                             service_name=self.service_name,
+                                             region=self.region)
+        endpoint = self._get_outscale_endpoint(self.region,
+                                               self.version,
+                                               action)
+        return requests.post(endpoint, data=data, headers=headers)
+
+    def reboot_node(self, node_ids):

Review comment:
       To comply with the libcloud standard API, this method needs to take a single ``node`` argument which must be ``Node`` class instance.
   
   If you also want to support rebooting multiple notes, you should add a new extension method. For example: ``ex_reboot_nodes(self, node_ids)``.




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [libcloud] asfgit merged pull request #1476: New compute driver OUTSCALE

Posted by GitBox <gi...@apache.org>.
asfgit merged pull request #1476:
URL: https://github.com/apache/libcloud/pull/1476


   


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [libcloud] tgn-outscale commented on pull request #1476: New compute driver OUTSCALE

Posted by GitBox <gi...@apache.org>.
tgn-outscale commented on pull request #1476:
URL: https://github.com/apache/libcloud/pull/1476#issuecomment-667920292


    Hi, @Kami, thanks for your reply
   
   The Outscale EC2 driver is using our old API, and this implementation is using the new one.
   As the old version is still in use and the new version still lacking some features, I think the EC2 version is still relevant for now.


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [libcloud] Kami commented on a change in pull request #1476: New compute driver OUTSCALE

Posted by GitBox <gi...@apache.org>.
Kami commented on a change in pull request #1476:
URL: https://github.com/apache/libcloud/pull/1476#discussion_r479778214



##########
File path: libcloud/compute/drivers/outscale.py
##########
@@ -0,0 +1,1018 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""
+Outscale SDK
+"""
+
+import json
+
+import requests
+
+from libcloud.compute.base import NodeDriver
+from libcloud.compute.types import Provider
+from libcloud.common.osc import OSCRequestSignerAlgorithmV4
+from libcloud.common.base import ConnectionUserAndKey
+from libcloud.compute.base import \
+    Node,\
+    NodeImage, \
+    KeyPair, \
+    StorageVolume, \
+    VolumeSnapshot, \
+    NodeLocation
+from libcloud.compute.types import NodeState
+
+
+class OutscaleNodeDriver(NodeDriver):
+    """
+    Outscale SDK node driver
+    """
+
+    type = Provider.OUTSCALE
+    name = 'Outscale API'
+    website = 'http://www.outscale.com'
+
+    def __init__(self,
+                 key: str = None,
+                 secret: str = None,
+                 region: str = 'eu-west-2',
+                 service: str = 'api',
+                 version: str = 'latest'
+                 ):
+        self.key = key
+        self.secret = secret
+        self.region = region
+        self.connection = ConnectionUserAndKey(self.key, self.secret)
+        self.connection.region_name = region
+        self.connection.service_name = service
+        self.service_name = service
+        self.version = version
+        self.signer = OSCRequestSignerAlgorithmV4(
+            access_key=self.key,
+            access_secret=self.secret,
+            version=self.version,
+            connection=self.connection
+        )
+        self.NODE_STATE = {
+            'pending': NodeState.PENDING,
+            'running': NodeState.RUNNING,
+            'shutting-down': NodeState.UNKNOWN,
+            'terminated': NodeState.TERMINATED,
+            'stopped': NodeState.STOPPED
+        }
+
+    def list_locations(self, ex_dry_run: bool = False):
+        """
+        Lists available regions details.
+        :param      ex_dry_run: If true, checks whether you have the required
+        permissions to perform the action.
+        :type       ex_dry_run: ``bool``
+        :return: regions details
+        :rtype: ``dict``
+        """
+        action = "ReadRegions"
+        data = json.dumps({"DryRun": ex_dry_run})
+        response = self._call_api(action, data)
+        return self._to_locations(response.json()["Regions"])
+
+    def ex_create_public_ip(self, dry_run: bool = False):
+        """
+        Create a new public ip.
+
+        :param      dry_run: If true, checks whether you have the required
+        permissions to perform the action.
+        :type       dry_run: ``bool``
+
+        :return: the created public ip
+        :rtype: ``dict``
+            """
+        action = "CreatePublicIp"
+        data = json.dumps({"DryRun": dry_run})
+        if self._call_api(action, data).status_code == 200:
+            return True
+        return False
+
+    def ex_delete_public_ip(self,
+                            dry_run: bool = False,
+                            public_ip: str = None,
+                            public_ip_id: str = None):
+        """
+        Delete instances.
+
+        :param      dry_run: If true, checks whether you have the required
+        permissions to perform the action.
+        :type       dry_run: ``bool``
+
+        :param      public_ip: The EIP. In the public Cloud, this parameter is
+        required.
+        :type       public_ip: ``str``
+
+        :param      public_ip_id: The ID representing the association of the
+        EIP with the VM or the NIC. In a Net,
+        this parameter is required.
+        :type       public_ip_id: ``str``
+
+        :return: request
+        :rtype: ``dict``
+        """
+        action = "DeletePublicIp"
+        data = {"DryRun": dry_run}
+        if public_ip is not None:
+            data.update({"PublicIp": public_ip})
+        if public_ip_id is not None:
+            data.update({"PublicIpId": public_ip_id})
+        data = json.dumps(data)
+        if self._call_api(action, data).status_code == 200:
+            return True
+        return False
+
+    def ex_list_public_ips(self, data: str = "{}"):
+        """
+        List all nodes.
+
+        :param      data: json stringify following the outscale api
+        documentation for filter
+        :type       data: ``string``
+
+        :return: nodes
+        :rtype: ``dict``
+        """
+        action = "ReadPublicIps"
+        return self._call_api(action, data)
+
+    def ex_list_public_ip_ranges(self, dry_run: bool = False):
+        """
+        Lists available regions details.
+
+        :param      dry_run: If true, checks whether you have the
+        required permissions to perform the action.
+        :type       dry_run: ``bool``
+
+        :return: regions details
+        :rtype: ``dict``
+        """
+        action = "ReadPublicIpRanges"
+        data = json.dumps({"DryRun": dry_run})
+        return self._call_api(action, data)
+
+    def ex_attach_public_ip(self,
+                            allow_relink: bool = None,
+                            dry_run: bool = False,
+                            nic_id: str = None,
+                            vm_id: str = None,
+                            public_ip: str = None,
+                            public_ip_id: str = None,
+                            ):
+        """
+        Attach a volume.
+
+        :param      allow_relink: If true, allows the EIP to be associated
+        with the VM or NIC that you specify even if
+        it is already associated with another VM or NIC.
+        :type       allow_relink: ``bool``
+
+        :param      dry_run: If true, checks whether you have the required
+        permissions to perform the action.
+        :type       dry_run: ``bool``
+
+        :param      nic_id:(Net only) The ID of the NIC. This parameter is
+        required if the VM has more than one NIC attached. Otherwise,
+        you need to specify the VmId parameter instead.
+        You cannot specify both parameters
+        at the same time.
+        :type       nic_id: ``str``
+
+        :param      vm_id: the ID of the VM
+        :type       nic_id: ``str``
+
+        :param      public_ip: The EIP. In the public Cloud, this parameter
+        is required.
+        :type       public_ip: ``str``
+
+        :param      public_ip_id: The allocation ID of the EIP. In a Net,
+        this parameter is required.
+        :type       public_ip_id: ``str``
+
+        :return: the attached volume
+        :rtype: ``dict``
+        """
+        action = "LinkPublicIp"
+        data = {"DryRun": dry_run}
+        if public_ip is not None:
+            data.update({"PublicIp": public_ip})
+        if public_ip_id is not None:
+            data.update({"PublicIpId": public_ip_id})
+        if nic_id is not None:
+            data.update({"NicId": nic_id})
+        if vm_id is not None:
+            data.update({"VmId": vm_id})
+        if allow_relink is not None:
+            data.update({"AllowRelink": allow_relink})
+        data = json.dumps(data)
+        if self._call_api(action, data).status_code == 200:
+            return True
+        return False
+
+    def ex_detach_public_ip(self,
+                            public_ip: str = None,
+                            link_public_ip_id: str = None,
+                            dry_run: bool = False):
+        """
+        Detach a volume.
+
+        :param      public_ip: (Required in a Net) The ID representing the
+        association of the EIP with the VM or the NIC
+        :type       public_ip: ``str``
+
+        :param      link_public_ip_id: (Required in a Net) The ID
+        representing the association of the EIP with the
+        VM or the NIC.
+        :type       link_public_ip_id: ``str``
+
+        :param      dry_run: If true, checks whether you have the required
+        permissions to perform the action.
+        :type       dry_run: ``bool``
+
+        :return: the attached volume
+        :rtype: ``dict``
+        """
+        action = "UnlinkPublicIp"
+        data = {"DryRun": dry_run}
+        if public_ip is not None:
+            data.update({"PublicIp": public_ip})
+        if link_public_ip_id is not None:
+            data.update({"LinkPublicIpId": link_public_ip_id})
+        data = json.dumps(data)
+        if self._call_api(action, data).status_code == 200:
+            return True
+        return False
+
+    def create_node(self,
+                    ex_image_id: str,
+                    ex_dry_run: bool = False,
+                    ex_block_device_mapping: dict = None,
+                    ex_boot_on_creation: bool = True,
+                    ex_bsu_optimized: bool = True,
+                    ex_client_token: str = None,
+                    ex_deletion_protection: bool = False,
+                    ex_keypair_name: str = None,
+                    ex_max_vms_count: int = None,
+                    ex_min_vms_count: int = None,
+                    ex_nics: dict = None,
+                    ex_performance: str = None,
+                    ex_placement: dict = None,
+                    ex_private_ips: [str] = None,
+                    ex_security_group_ids: [str] = None,
+                    ex_security_groups: [str] = None,
+                    ex_subnet_id: str = None,
+                    ex_user_data: str = None,
+                    ex_vm_initiated_shutdown_behavior: str = None,
+                    ex_vm_type: str = None
+                    ):
+        """
+        Create a new instance.
+
+        :param      ex_image_id: The ID of the OMI used to create the VM.

Review comment:
       That's fine for now, but ideally this method would comply with the standard API in the future - this means take name, image and size arguments.
   
   This would make it much easier for users to switch from other providers to this one without needing to change much code.




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [libcloud] Kami commented on a change in pull request #1476: New compute driver OUTSCALE

Posted by GitBox <gi...@apache.org>.
Kami commented on a change in pull request #1476:
URL: https://github.com/apache/libcloud/pull/1476#discussion_r470648641



##########
File path: libcloud/compute/drivers/outscale.py
##########
@@ -0,0 +1,1109 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""
+Outscale SDK
+"""
+
+import json
+
+import requests
+
+from libcloud.compute.base import NodeDriver
+from libcloud.compute.types import Provider
+from libcloud.common.osc import OSCRequestSignerAlgorithmV4
+from libcloud.common.base import ConnectionUserAndKey
+
+
+class OutscaleNodeDriver(NodeDriver):
+    """
+    Outscale SDK node driver
+    """
+
+    type = Provider.OUTSCALE
+    name = 'Outscale API'
+    website = 'http://www.outscale.com'
+
+    def __init__(self,
+                 key=None,
+                 secret=None,
+                 region='eu-west-2',
+                 service='api',
+                 version='latest'
+                 ):
+        self.key = key
+        self.secret = secret
+        self.region = region
+        self.connection = ConnectionUserAndKey(self.key, self.secret)
+        self.connection.region_name = region
+        self.connection.service_name = service
+        self.service_name = service
+        self.version = version
+
+    def list_locations(self, dry_run=False):
+        """
+        Lists available regions details.
+
+        :return: regions details
+        :rtype: ``dict``
+        """
+        action = "ReadRegions"
+        data = json.dumps({"DryRun": dry_run})
+        signer = OSCRequestSignerAlgorithmV4(access_key=self.key,
+                                             access_secret=self.secret,
+                                             version=self.version,
+                                             connection=self.connection)
+        headers = signer.get_request_headers(action=action,
+                                             data=data,
+                                             service_name=self.service_name,
+                                             region=self.region)
+        endpoint = self._get_outscale_endpoint(self.region,
+                                               self.version,
+                                               action)
+        return requests.post(endpoint, data=data, headers=headers)
+
+    def create_public_ip(self, dry_run=False):
+        """
+        Create a new public ip.
+
+        :param      dry_run: If true, checks whether you have the required
+        permissions to perform the action.
+        :type       dry_run: ``bool``
+
+        :return: the created public ip
+        :rtype: ``dict``
+            """
+        action = "CreatePublicIp"
+        data = json.dumps({"DryRun": dry_run})
+        signer = OSCRequestSignerAlgorithmV4(access_key=self.key,
+                                             access_secret=self.secret,
+                                             version=self.version,
+                                             connection=self.connection)
+        headers = signer.get_request_headers(action=action,
+                                             data=data,
+                                             service_name=self.service_name,
+                                             region=self.region)
+        endpoint = self._get_outscale_endpoint(self.region,
+                                               self.version,
+                                               action)
+        return requests.post(endpoint, data=data, headers=headers)
+
+    def delete_public_ip(self, dry_run=False,
+                         public_ip=None,
+                         public_ip_id=None):
+        """
+        Delete instances.
+
+        :param      dry_run: If true, checks whether you have the required
+        permissions to perform the action.
+        :type       dry_run: ``bool``
+
+        :param      public_ip: The EIP. In the public Cloud, this parameter is
+        required.
+        :type       public_ip: ``str``
+
+        :param      public_ip_id: The ID representing the association of the
+        EIP with the VM or the NIC. In a Net,
+        this parameter is required.
+        :type       public_ip_id: ``str``
+
+        :return: request
+        :rtype: ``dict``
+        """
+        action = "DeletePublicIp"
+        data = {"DryRun": dry_run}
+        if public_ip is not None:
+            data.update({"PublicIp": public_ip})
+        if public_ip_id is not None:
+            data.update({"PublicIpId": public_ip_id})
+        data = json.dumps(data)
+        signer = OSCRequestSignerAlgorithmV4(access_key=self.key,
+                                             access_secret=self.secret,
+                                             version=self.version,
+                                             connection=self.connection)
+        headers = signer.get_request_headers(action=action,
+                                             data=data,
+                                             service_name=self.service_name,
+                                             region=self.region)
+        endpoint = self._get_outscale_endpoint(self.region,
+                                               self.version,
+                                               action)
+        return requests.post(endpoint, data=data, headers=headers)
+
+    def list_public_ips(self, data="{}"):
+        """
+        List all nodes.
+
+        :param      data: json stringify following the outscale api
+        documentation for filter
+        :type       data: ``string``
+
+        :return: nodes
+        :rtype: ``dict``
+        """
+        action = "ReadPublicIps"
+        signer = OSCRequestSignerAlgorithmV4(access_key=self.key,
+                                             access_secret=self.secret,
+                                             version=self.version,
+                                             connection=self.connection)
+        headers = signer.get_request_headers(action=action,
+                                             data=data,
+                                             service_name=self.service_name,
+                                             region=self.region)
+        endpoint = self._get_outscale_endpoint(self.region,
+                                               self.version,
+                                               action)
+        return requests.post(endpoint, data=data, headers=headers)
+
+    def list_public_ip_ranges(self, dry_run=False):
+        """
+        Lists available regions details.
+
+        :param      dry_run: If true, checks whether you have the
+        required permissions to perform the action.
+        :type       dry_run: ``bool``
+
+        :return: regions details
+        :rtype: ``dict``
+        """
+        action = "ReadPublicIpRanges"
+        data = json.dumps({"DryRun": dry_run})
+        signer = OSCRequestSignerAlgorithmV4(access_key=self.key,
+                                             access_secret=self.secret,
+                                             version=self.version,
+                                             connection=self.connection)
+        headers = signer.get_request_headers(action=action,
+                                             data=data,
+                                             service_name=self.service_name,
+                                             region=self.region)
+        endpoint = self._get_outscale_endpoint(self.region,
+                                               self.version,
+                                               action)
+        return requests.post(endpoint, data=data, headers=headers)
+
+    def attach_public_ip(self,
+                         allow_relink=None,
+                         dry_run=False,
+                         nic_id=None,
+                         vm_id=None,
+                         public_ip=None,
+                         public_ip_id=None,
+                         ):
+        """
+        Attach a volume.
+
+        :param      allow_relink: If true, allows the EIP to be associated
+        with the VM or NIC that you specify even if
+        it is already associated with another VM or NIC.
+        :type       allow_relink: ``bool``
+
+        :param      dry_run: If true, checks whether you have the required
+        permissions to perform the action.
+        :type       dry_run: ``bool``
+
+        :param      nic_id:(Net only) The ID of the NIC. This parameter is
+        required if the VM has more than one NIC attached. Otherwise,
+        you need to specify the VmId parameter instead.
+        You cannot specify both parameters
+        at the same time.
+        :type       nic_id: ``str``
+
+        :param      vm_id: the ID of the VM
+        :type       nic_id: ``str``
+
+        :param      public_ip: The EIP. In the public Cloud, this parameter
+        is required.
+        :type       public_ip: ``str``
+
+        :param      public_ip_id: The allocation ID of the EIP. In a Net,
+        this parameter is required.
+        :type       public_ip_id: ``str``
+
+        :return: the attached volume
+        :rtype: ``dict``
+        """
+        action = "LinkPublicIp"
+        data = {"DryRun": dry_run}
+        if public_ip is not None:
+            data.update({"PublicIp": public_ip})
+        if public_ip_id is not None:
+            data.update({"PublicIpId": public_ip_id})
+        if nic_id is not None:
+            data.update({"NicId": nic_id})
+        if vm_id is not None:
+            data.update({"VmId": vm_id})
+        if allow_relink is not None:
+            data.update({"AllowRelink": allow_relink})
+        data = json.dumps(data)
+        signer = OSCRequestSignerAlgorithmV4(access_key=self.key,
+                                             access_secret=self.secret,
+                                             version=self.version,
+                                             connection=self.connection)
+        headers = signer.get_request_headers(action=action,
+                                             data=data,
+                                             service_name=self.service_name,
+                                             region=self.region)
+        endpoint = self._get_outscale_endpoint(self.region,
+                                               self.version,
+                                               action)
+        return requests.post(endpoint, data=data, headers=headers)
+
+    def detach_public_ip(self, public_ip=None,
+                         link_public_ip_id=None,
+                         dry_run=False):
+        """
+        Detach a volume.
+
+        :param      public_ip: (Required in a Net) The ID representing the
+        association of the EIP with the VM or the NIC
+        :type       public_ip: ``str``
+
+        :param      link_public_ip_id: (Required in a Net) The ID
+        representing the association of the EIP with the
+        VM or the NIC.
+        :type       link_public_ip_id: ``str``
+
+        :param      dry_run: If true, checks whether you have the required
+        permissions to perform the action.
+        :type       dry_run: ``bool``
+
+        :return: the attached volume
+        :rtype: ``dict``
+        """
+        action = "UnlinkPublicIp"
+        data = {"DryRun": dry_run}
+        if public_ip is not None:
+            data.update({"PublicIp": public_ip})
+        if link_public_ip_id is not None:
+            data.update({"LinkPublicIpId": link_public_ip_id})
+        data = json.dumps(data)
+        signer = OSCRequestSignerAlgorithmV4(access_key=self.key,
+                                             access_secret=self.secret,
+                                             version=self.version,
+                                             connection=self.connection)
+        headers = signer.get_request_headers(action=action,
+                                             data=data,
+                                             service_name=self.service_name,
+                                             region=self.region)
+        endpoint = self._get_outscale_endpoint(self.region,
+                                               self.version,
+                                               action)
+        return requests.post(endpoint, data=data, headers=headers)
+
+    def create_node(self,
+                    image_id,
+                    dry_run=False,
+                    block_device_mapping=None,
+                    boot_on_creation=True,
+                    bsu_optimized=True,
+                    client_token=None,
+                    deletion_protection=False,
+                    keypair_name=None,
+                    max_vms_count=None,
+                    min_vms_count=None,
+                    nics=None,
+                    performance=None,
+                    placement=None,
+                    private_ips=None,
+                    security_group_ids=None,
+                    security_groups=None,
+                    subnet_id=None,
+                    ):
+        """
+        Create a new instance.
+
+        :param      image_id: The ID of the OMI used to create the VM.
+        :type       image_id: ``str``
+
+        :param      dry_run: If true, checks whether you have the required
+        permissions to perform the action.
+        :type       dry_run: ``bool``
+
+        :param      block_device_mapping: One or more block device mappings.
+        :type       block_device_mapping: ``dict``
+
+        :param      boot_on_creation: By default or if true, the VM is
+        started on creation. If false, the VM is
+        stopped on creation.
+        :type       boot_on_creation: ``bool``
+
+        :param      bsu_optimized: If true, the VM is created with optimized
+        BSU I/O.
+        :type       bsu_optimized: ``bool``
+
+        :param      client_token: A unique identifier which enables you to
+        manage the idempotency.
+        :type       client_token: ``bool``
+
+        :param      deletion_protection: If true, you cannot terminate the
+        VM using Cockpit, the CLI or the API.
+        If false, you can.
+        :type       deletion_protection: ``bool``
+
+        :param      keypair_name: The name of the keypair.
+        :type       keypair_name: ``str``
+
+        :param      max_vms_count: The maximum number of VMs you want to
+        create. If all the VMs cannot be created, the
+        largest possible number of VMs above MinVmsCount is created.
+        :type       max_vms_count: ``integer``
+
+        :param      min_vms_count: The minimum number of VMs you want to
+        create. If this number of VMs cannot be
+        created, no VMs are created.
+        :type       min_vms_count: ``integer``
+
+        :param      nics: One or more NICs. If you specify this parameter,
+        you must define one NIC as the primary
+        network interface of the VM with 0 as its device number.
+        :type       nics: ``dict``
+
+        :param      performance: The performance of the VM (standard | high
+        | highest).
+        :type       performance: ``str``
+
+        :param      placement: Information about the placement of the VM.
+        :type       placement: ``dict``
+
+        :param      private_ips: One or more private IP addresses of the VM.
+        :type       private_ips: ``list``
+
+        :param      security_group_ids: One or more IDs of security group
+        for the VMs.
+        :type       security_group_ids: ``list``
+
+        :param      security_groups: One or more names of security groups
+        for the VMs.
+        :type       security_groups: ``list``
+
+        :param      subnet_id: The ID of the Subnet in which you want to
+        create the VM.
+        :type       subnet_id: ``str``
+
+        :return: the created instance
+        :rtype: ``dict``
+        """
+        data = {
+            "DryRun": dry_run,
+            "BootOnCreation": boot_on_creation,
+            "BsuOptimized": bsu_optimized,
+            "ImageId": image_id
+        }
+        if block_device_mapping is not None:
+            data.update({"BlockDeviceMappings": block_device_mapping})
+        if client_token is not None:
+            data.update({"ClientToken": client_token})
+        if deletion_protection is not None:
+            data.update({"DeletionProtection": deletion_protection})
+        if keypair_name is not None:
+            data.update({"KeypairName": keypair_name})
+        if max_vms_count is not None:
+            data.update({"MaxVmsCount": max_vms_count})
+        if min_vms_count is not None:
+            data.update({"MinVmsCount": min_vms_count})
+        if nics is not None:
+            data.update({"Nics": nics})
+        if performance is not None:
+            data.update({"Performance": performance})
+        if placement is not None:
+            data.update({"Placement": placement})
+        if private_ips is not None:
+            data.update({"PrivateIps": private_ips})
+        if security_group_ids is not None:
+            data.update({"SecurityGroupIds": security_group_ids})
+        if security_groups is not None:
+            data.update({"SecurityGroups": security_groups})
+        if subnet_id is not None:
+            data.update({"SubnetId": subnet_id})
+        action = "CreateVms"
+        data = json.dumps(data)
+        signer = OSCRequestSignerAlgorithmV4(access_key=self.key,
+                                             access_secret=self.secret,
+                                             version=self.version,
+                                             connection=self.connection)
+        headers = signer.get_request_headers(action=action,
+                                             data=data,
+                                             service_name=self.service_name,
+                                             region=self.region)
+        endpoint = self._get_outscale_endpoint(self.region,
+                                               self.version,
+                                               action)
+        return requests.post(endpoint, data=data, headers=headers)
+
+    def reboot_node(self, node_ids):
+        """
+        Reboot instances.
+
+        :param      node_ids: the ID(s) of the VM(s)
+                    you want to reboot (required)
+        :type       node_ids: ``list``
+
+        :return: the rebooted instances
+        :rtype: ``dict``
+        """
+        action = "RebootVms"
+        data = json.dumps({"VmIds": node_ids})
+        signer = OSCRequestSignerAlgorithmV4(access_key=self.key,
+                                             access_secret=self.secret,
+                                             version=self.version,
+                                             connection=self.connection)
+        headers = signer.get_request_headers(action=action,
+                                             data=data,
+                                             service_name=self.service_name,
+                                             region=self.region)
+        endpoint = self._get_outscale_endpoint(self.region,
+                                               self.version,
+                                               action)
+        return requests.post(endpoint, data=data, headers=headers)
+
+    def list_nodes(self, data="{}"):
+        """
+        List all nodes.
+
+        :return: nodes
+        :rtype: ``dict``
+        """
+        action = "ReadVms"
+        signer = OSCRequestSignerAlgorithmV4(access_key=self.key,
+                                             access_secret=self.secret,
+                                             version=self.version,
+                                             connection=self.connection)
+        headers = signer.get_request_headers(action=action,
+                                             data=data,
+                                             service_name=self.service_name,
+                                             region=self.region)
+        endpoint = self._get_outscale_endpoint(self.region,
+                                               self.version,
+                                               action)
+        return requests.post(endpoint, data=data, headers=headers)
+
+    def delete_node(self, node_ids):

Review comment:
       Same here - should take a single ``node`` argument which represents ``Node`` class instance.




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [libcloud] Kami commented on a change in pull request #1476: New compute driver OUTSCALE

Posted by GitBox <gi...@apache.org>.
Kami commented on a change in pull request #1476:
URL: https://github.com/apache/libcloud/pull/1476#discussion_r470647555



##########
File path: libcloud/compute/drivers/outscale.py
##########
@@ -0,0 +1,1109 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""
+Outscale SDK
+"""
+
+import json
+
+import requests
+
+from libcloud.compute.base import NodeDriver
+from libcloud.compute.types import Provider
+from libcloud.common.osc import OSCRequestSignerAlgorithmV4
+from libcloud.common.base import ConnectionUserAndKey
+
+
+class OutscaleNodeDriver(NodeDriver):
+    """
+    Outscale SDK node driver
+    """
+
+    type = Provider.OUTSCALE
+    name = 'Outscale API'
+    website = 'http://www.outscale.com'
+
+    def __init__(self,
+                 key=None,
+                 secret=None,
+                 region='eu-west-2',
+                 service='api',
+                 version='latest'
+                 ):
+        self.key = key
+        self.secret = secret
+        self.region = region
+        self.connection = ConnectionUserAndKey(self.key, self.secret)
+        self.connection.region_name = region
+        self.connection.service_name = service
+        self.service_name = service
+        self.version = version
+
+    def list_locations(self, dry_run=False):
+        """
+        Lists available regions details.
+
+        :return: regions details
+        :rtype: ``dict``
+        """
+        action = "ReadRegions"
+        data = json.dumps({"DryRun": dry_run})
+        signer = OSCRequestSignerAlgorithmV4(access_key=self.key,
+                                             access_secret=self.secret,
+                                             version=self.version,
+                                             connection=self.connection)
+        headers = signer.get_request_headers(action=action,
+                                             data=data,
+                                             service_name=self.service_name,
+                                             region=self.region)
+        endpoint = self._get_outscale_endpoint(self.region,
+                                               self.version,
+                                               action)
+        return requests.post(endpoint, data=data, headers=headers)
+
+    def create_public_ip(self, dry_run=False):
+        """
+        Create a new public ip.
+
+        :param      dry_run: If true, checks whether you have the required
+        permissions to perform the action.
+        :type       dry_run: ``bool``
+
+        :return: the created public ip
+        :rtype: ``dict``
+            """
+        action = "CreatePublicIp"
+        data = json.dumps({"DryRun": dry_run})
+        signer = OSCRequestSignerAlgorithmV4(access_key=self.key,
+                                             access_secret=self.secret,
+                                             version=self.version,
+                                             connection=self.connection)
+        headers = signer.get_request_headers(action=action,
+                                             data=data,
+                                             service_name=self.service_name,
+                                             region=self.region)
+        endpoint = self._get_outscale_endpoint(self.region,
+                                               self.version,
+                                               action)
+        return requests.post(endpoint, data=data, headers=headers)
+
+    def delete_public_ip(self, dry_run=False,
+                         public_ip=None,
+                         public_ip_id=None):
+        """
+        Delete instances.
+
+        :param      dry_run: If true, checks whether you have the required
+        permissions to perform the action.
+        :type       dry_run: ``bool``
+
+        :param      public_ip: The EIP. In the public Cloud, this parameter is
+        required.
+        :type       public_ip: ``str``
+
+        :param      public_ip_id: The ID representing the association of the
+        EIP with the VM or the NIC. In a Net,
+        this parameter is required.
+        :type       public_ip_id: ``str``
+
+        :return: request
+        :rtype: ``dict``
+        """
+        action = "DeletePublicIp"
+        data = {"DryRun": dry_run}
+        if public_ip is not None:
+            data.update({"PublicIp": public_ip})
+        if public_ip_id is not None:
+            data.update({"PublicIpId": public_ip_id})
+        data = json.dumps(data)
+        signer = OSCRequestSignerAlgorithmV4(access_key=self.key,
+                                             access_secret=self.secret,
+                                             version=self.version,
+                                             connection=self.connection)
+        headers = signer.get_request_headers(action=action,
+                                             data=data,
+                                             service_name=self.service_name,
+                                             region=self.region)
+        endpoint = self._get_outscale_endpoint(self.region,
+                                               self.version,
+                                               action)
+        return requests.post(endpoint, data=data, headers=headers)
+
+    def list_public_ips(self, data="{}"):
+        """
+        List all nodes.
+
+        :param      data: json stringify following the outscale api
+        documentation for filter
+        :type       data: ``string``
+
+        :return: nodes
+        :rtype: ``dict``
+        """
+        action = "ReadPublicIps"
+        signer = OSCRequestSignerAlgorithmV4(access_key=self.key,
+                                             access_secret=self.secret,
+                                             version=self.version,
+                                             connection=self.connection)
+        headers = signer.get_request_headers(action=action,
+                                             data=data,
+                                             service_name=self.service_name,
+                                             region=self.region)
+        endpoint = self._get_outscale_endpoint(self.region,
+                                               self.version,
+                                               action)
+        return requests.post(endpoint, data=data, headers=headers)
+
+    def list_public_ip_ranges(self, dry_run=False):
+        """
+        Lists available regions details.
+
+        :param      dry_run: If true, checks whether you have the
+        required permissions to perform the action.
+        :type       dry_run: ``bool``
+
+        :return: regions details
+        :rtype: ``dict``
+        """
+        action = "ReadPublicIpRanges"
+        data = json.dumps({"DryRun": dry_run})
+        signer = OSCRequestSignerAlgorithmV4(access_key=self.key,
+                                             access_secret=self.secret,
+                                             version=self.version,
+                                             connection=self.connection)
+        headers = signer.get_request_headers(action=action,
+                                             data=data,
+                                             service_name=self.service_name,
+                                             region=self.region)
+        endpoint = self._get_outscale_endpoint(self.region,
+                                               self.version,
+                                               action)
+        return requests.post(endpoint, data=data, headers=headers)
+
+    def attach_public_ip(self,
+                         allow_relink=None,
+                         dry_run=False,
+                         nic_id=None,
+                         vm_id=None,
+                         public_ip=None,
+                         public_ip_id=None,
+                         ):
+        """
+        Attach a volume.
+
+        :param      allow_relink: If true, allows the EIP to be associated
+        with the VM or NIC that you specify even if
+        it is already associated with another VM or NIC.
+        :type       allow_relink: ``bool``
+
+        :param      dry_run: If true, checks whether you have the required
+        permissions to perform the action.
+        :type       dry_run: ``bool``
+
+        :param      nic_id:(Net only) The ID of the NIC. This parameter is
+        required if the VM has more than one NIC attached. Otherwise,
+        you need to specify the VmId parameter instead.
+        You cannot specify both parameters
+        at the same time.
+        :type       nic_id: ``str``
+
+        :param      vm_id: the ID of the VM
+        :type       nic_id: ``str``
+
+        :param      public_ip: The EIP. In the public Cloud, this parameter
+        is required.
+        :type       public_ip: ``str``
+
+        :param      public_ip_id: The allocation ID of the EIP. In a Net,
+        this parameter is required.
+        :type       public_ip_id: ``str``
+
+        :return: the attached volume
+        :rtype: ``dict``
+        """
+        action = "LinkPublicIp"
+        data = {"DryRun": dry_run}
+        if public_ip is not None:
+            data.update({"PublicIp": public_ip})
+        if public_ip_id is not None:
+            data.update({"PublicIpId": public_ip_id})
+        if nic_id is not None:
+            data.update({"NicId": nic_id})
+        if vm_id is not None:
+            data.update({"VmId": vm_id})
+        if allow_relink is not None:
+            data.update({"AllowRelink": allow_relink})
+        data = json.dumps(data)
+        signer = OSCRequestSignerAlgorithmV4(access_key=self.key,
+                                             access_secret=self.secret,
+                                             version=self.version,
+                                             connection=self.connection)
+        headers = signer.get_request_headers(action=action,
+                                             data=data,
+                                             service_name=self.service_name,
+                                             region=self.region)
+        endpoint = self._get_outscale_endpoint(self.region,
+                                               self.version,
+                                               action)
+        return requests.post(endpoint, data=data, headers=headers)
+
+    def detach_public_ip(self, public_ip=None,
+                         link_public_ip_id=None,
+                         dry_run=False):
+        """
+        Detach a volume.
+
+        :param      public_ip: (Required in a Net) The ID representing the
+        association of the EIP with the VM or the NIC
+        :type       public_ip: ``str``
+
+        :param      link_public_ip_id: (Required in a Net) The ID
+        representing the association of the EIP with the
+        VM or the NIC.
+        :type       link_public_ip_id: ``str``
+
+        :param      dry_run: If true, checks whether you have the required
+        permissions to perform the action.
+        :type       dry_run: ``bool``
+
+        :return: the attached volume
+        :rtype: ``dict``
+        """
+        action = "UnlinkPublicIp"
+        data = {"DryRun": dry_run}
+        if public_ip is not None:
+            data.update({"PublicIp": public_ip})
+        if link_public_ip_id is not None:
+            data.update({"LinkPublicIpId": link_public_ip_id})
+        data = json.dumps(data)
+        signer = OSCRequestSignerAlgorithmV4(access_key=self.key,
+                                             access_secret=self.secret,
+                                             version=self.version,
+                                             connection=self.connection)
+        headers = signer.get_request_headers(action=action,
+                                             data=data,
+                                             service_name=self.service_name,
+                                             region=self.region)
+        endpoint = self._get_outscale_endpoint(self.region,
+                                               self.version,
+                                               action)
+        return requests.post(endpoint, data=data, headers=headers)
+
+    def create_node(self,
+                    image_id,
+                    dry_run=False,
+                    block_device_mapping=None,

Review comment:
       Argument which are not part of the Libcloud standard API (aka are not defined on the base NodeDriver class) need to be prefixed with ``ex_`` - ex_bsu_optimized, ex_nics, etc.




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [libcloud] Kami commented on a change in pull request #1476: New compute driver OUTSCALE

Posted by GitBox <gi...@apache.org>.
Kami commented on a change in pull request #1476:
URL: https://github.com/apache/libcloud/pull/1476#discussion_r470645205



##########
File path: libcloud/common/osc.py
##########
@@ -0,0 +1,151 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from datetime import datetime
+import hashlib
+import hmac
+
+from libcloud.utils.py3 import urlquote
+
+__all__ = [
+    'OSCRequestSignerAlgorithmV4',
+]
+
+
+class OSCRequestSigner(object):
+    """
+    Class which handles signing the outgoing AWS requests.
+    """
+
+    def __init__(self, access_key, access_secret, version, connection):

Review comment:
       It you get a chance, it would also be good to add type annotations for MyPy.




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [libcloud] Kami commented on a change in pull request #1476: New compute driver OUTSCALE

Posted by GitBox <gi...@apache.org>.
Kami commented on a change in pull request #1476:
URL: https://github.com/apache/libcloud/pull/1476#discussion_r470648467



##########
File path: libcloud/compute/drivers/outscale.py
##########
@@ -0,0 +1,1109 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""
+Outscale SDK
+"""
+
+import json
+
+import requests
+
+from libcloud.compute.base import NodeDriver
+from libcloud.compute.types import Provider
+from libcloud.common.osc import OSCRequestSignerAlgorithmV4
+from libcloud.common.base import ConnectionUserAndKey
+
+
+class OutscaleNodeDriver(NodeDriver):
+    """
+    Outscale SDK node driver
+    """
+
+    type = Provider.OUTSCALE
+    name = 'Outscale API'
+    website = 'http://www.outscale.com'
+
+    def __init__(self,
+                 key=None,
+                 secret=None,
+                 region='eu-west-2',
+                 service='api',
+                 version='latest'
+                 ):
+        self.key = key
+        self.secret = secret
+        self.region = region
+        self.connection = ConnectionUserAndKey(self.key, self.secret)
+        self.connection.region_name = region
+        self.connection.service_name = service
+        self.service_name = service
+        self.version = version
+
+    def list_locations(self, dry_run=False):
+        """
+        Lists available regions details.
+
+        :return: regions details
+        :rtype: ``dict``
+        """
+        action = "ReadRegions"
+        data = json.dumps({"DryRun": dry_run})
+        signer = OSCRequestSignerAlgorithmV4(access_key=self.key,
+                                             access_secret=self.secret,
+                                             version=self.version,
+                                             connection=self.connection)
+        headers = signer.get_request_headers(action=action,
+                                             data=data,
+                                             service_name=self.service_name,
+                                             region=self.region)
+        endpoint = self._get_outscale_endpoint(self.region,
+                                               self.version,
+                                               action)
+        return requests.post(endpoint, data=data, headers=headers)
+
+    def create_public_ip(self, dry_run=False):
+        """
+        Create a new public ip.
+
+        :param      dry_run: If true, checks whether you have the required
+        permissions to perform the action.
+        :type       dry_run: ``bool``
+
+        :return: the created public ip
+        :rtype: ``dict``
+            """
+        action = "CreatePublicIp"
+        data = json.dumps({"DryRun": dry_run})
+        signer = OSCRequestSignerAlgorithmV4(access_key=self.key,
+                                             access_secret=self.secret,
+                                             version=self.version,
+                                             connection=self.connection)
+        headers = signer.get_request_headers(action=action,
+                                             data=data,
+                                             service_name=self.service_name,
+                                             region=self.region)
+        endpoint = self._get_outscale_endpoint(self.region,
+                                               self.version,
+                                               action)
+        return requests.post(endpoint, data=data, headers=headers)
+
+    def delete_public_ip(self, dry_run=False,
+                         public_ip=None,
+                         public_ip_id=None):
+        """
+        Delete instances.
+
+        :param      dry_run: If true, checks whether you have the required
+        permissions to perform the action.
+        :type       dry_run: ``bool``
+
+        :param      public_ip: The EIP. In the public Cloud, this parameter is
+        required.
+        :type       public_ip: ``str``
+
+        :param      public_ip_id: The ID representing the association of the
+        EIP with the VM or the NIC. In a Net,
+        this parameter is required.
+        :type       public_ip_id: ``str``
+
+        :return: request
+        :rtype: ``dict``
+        """
+        action = "DeletePublicIp"
+        data = {"DryRun": dry_run}
+        if public_ip is not None:
+            data.update({"PublicIp": public_ip})
+        if public_ip_id is not None:
+            data.update({"PublicIpId": public_ip_id})
+        data = json.dumps(data)
+        signer = OSCRequestSignerAlgorithmV4(access_key=self.key,
+                                             access_secret=self.secret,
+                                             version=self.version,
+                                             connection=self.connection)
+        headers = signer.get_request_headers(action=action,
+                                             data=data,
+                                             service_name=self.service_name,
+                                             region=self.region)
+        endpoint = self._get_outscale_endpoint(self.region,
+                                               self.version,
+                                               action)
+        return requests.post(endpoint, data=data, headers=headers)
+
+    def list_public_ips(self, data="{}"):
+        """
+        List all nodes.
+
+        :param      data: json stringify following the outscale api
+        documentation for filter
+        :type       data: ``string``
+
+        :return: nodes
+        :rtype: ``dict``
+        """
+        action = "ReadPublicIps"
+        signer = OSCRequestSignerAlgorithmV4(access_key=self.key,
+                                             access_secret=self.secret,
+                                             version=self.version,
+                                             connection=self.connection)
+        headers = signer.get_request_headers(action=action,
+                                             data=data,
+                                             service_name=self.service_name,
+                                             region=self.region)
+        endpoint = self._get_outscale_endpoint(self.region,
+                                               self.version,
+                                               action)
+        return requests.post(endpoint, data=data, headers=headers)
+
+    def list_public_ip_ranges(self, dry_run=False):
+        """
+        Lists available regions details.
+
+        :param      dry_run: If true, checks whether you have the
+        required permissions to perform the action.
+        :type       dry_run: ``bool``
+
+        :return: regions details
+        :rtype: ``dict``
+        """
+        action = "ReadPublicIpRanges"
+        data = json.dumps({"DryRun": dry_run})
+        signer = OSCRequestSignerAlgorithmV4(access_key=self.key,
+                                             access_secret=self.secret,
+                                             version=self.version,
+                                             connection=self.connection)
+        headers = signer.get_request_headers(action=action,
+                                             data=data,
+                                             service_name=self.service_name,
+                                             region=self.region)
+        endpoint = self._get_outscale_endpoint(self.region,
+                                               self.version,
+                                               action)
+        return requests.post(endpoint, data=data, headers=headers)
+
+    def attach_public_ip(self,
+                         allow_relink=None,
+                         dry_run=False,
+                         nic_id=None,
+                         vm_id=None,
+                         public_ip=None,
+                         public_ip_id=None,
+                         ):
+        """
+        Attach a volume.
+
+        :param      allow_relink: If true, allows the EIP to be associated
+        with the VM or NIC that you specify even if
+        it is already associated with another VM or NIC.
+        :type       allow_relink: ``bool``
+
+        :param      dry_run: If true, checks whether you have the required
+        permissions to perform the action.
+        :type       dry_run: ``bool``
+
+        :param      nic_id:(Net only) The ID of the NIC. This parameter is
+        required if the VM has more than one NIC attached. Otherwise,
+        you need to specify the VmId parameter instead.
+        You cannot specify both parameters
+        at the same time.
+        :type       nic_id: ``str``
+
+        :param      vm_id: the ID of the VM
+        :type       nic_id: ``str``
+
+        :param      public_ip: The EIP. In the public Cloud, this parameter
+        is required.
+        :type       public_ip: ``str``
+
+        :param      public_ip_id: The allocation ID of the EIP. In a Net,
+        this parameter is required.
+        :type       public_ip_id: ``str``
+
+        :return: the attached volume
+        :rtype: ``dict``
+        """
+        action = "LinkPublicIp"
+        data = {"DryRun": dry_run}
+        if public_ip is not None:
+            data.update({"PublicIp": public_ip})
+        if public_ip_id is not None:
+            data.update({"PublicIpId": public_ip_id})
+        if nic_id is not None:
+            data.update({"NicId": nic_id})
+        if vm_id is not None:
+            data.update({"VmId": vm_id})
+        if allow_relink is not None:
+            data.update({"AllowRelink": allow_relink})
+        data = json.dumps(data)
+        signer = OSCRequestSignerAlgorithmV4(access_key=self.key,
+                                             access_secret=self.secret,
+                                             version=self.version,
+                                             connection=self.connection)
+        headers = signer.get_request_headers(action=action,
+                                             data=data,
+                                             service_name=self.service_name,
+                                             region=self.region)
+        endpoint = self._get_outscale_endpoint(self.region,
+                                               self.version,
+                                               action)
+        return requests.post(endpoint, data=data, headers=headers)
+
+    def detach_public_ip(self, public_ip=None,
+                         link_public_ip_id=None,
+                         dry_run=False):
+        """
+        Detach a volume.
+
+        :param      public_ip: (Required in a Net) The ID representing the
+        association of the EIP with the VM or the NIC
+        :type       public_ip: ``str``
+
+        :param      link_public_ip_id: (Required in a Net) The ID
+        representing the association of the EIP with the
+        VM or the NIC.
+        :type       link_public_ip_id: ``str``
+
+        :param      dry_run: If true, checks whether you have the required
+        permissions to perform the action.
+        :type       dry_run: ``bool``
+
+        :return: the attached volume
+        :rtype: ``dict``
+        """
+        action = "UnlinkPublicIp"
+        data = {"DryRun": dry_run}
+        if public_ip is not None:
+            data.update({"PublicIp": public_ip})
+        if link_public_ip_id is not None:
+            data.update({"LinkPublicIpId": link_public_ip_id})
+        data = json.dumps(data)
+        signer = OSCRequestSignerAlgorithmV4(access_key=self.key,
+                                             access_secret=self.secret,
+                                             version=self.version,
+                                             connection=self.connection)
+        headers = signer.get_request_headers(action=action,
+                                             data=data,
+                                             service_name=self.service_name,
+                                             region=self.region)
+        endpoint = self._get_outscale_endpoint(self.region,
+                                               self.version,
+                                               action)
+        return requests.post(endpoint, data=data, headers=headers)
+
+    def create_node(self,
+                    image_id,
+                    dry_run=False,
+                    block_device_mapping=None,
+                    boot_on_creation=True,
+                    bsu_optimized=True,
+                    client_token=None,
+                    deletion_protection=False,
+                    keypair_name=None,
+                    max_vms_count=None,
+                    min_vms_count=None,
+                    nics=None,
+                    performance=None,
+                    placement=None,
+                    private_ips=None,
+                    security_group_ids=None,
+                    security_groups=None,
+                    subnet_id=None,
+                    ):
+        """
+        Create a new instance.
+
+        :param      image_id: The ID of the OMI used to create the VM.
+        :type       image_id: ``str``
+
+        :param      dry_run: If true, checks whether you have the required
+        permissions to perform the action.
+        :type       dry_run: ``bool``
+
+        :param      block_device_mapping: One or more block device mappings.
+        :type       block_device_mapping: ``dict``
+
+        :param      boot_on_creation: By default or if true, the VM is
+        started on creation. If false, the VM is
+        stopped on creation.
+        :type       boot_on_creation: ``bool``
+
+        :param      bsu_optimized: If true, the VM is created with optimized
+        BSU I/O.
+        :type       bsu_optimized: ``bool``
+
+        :param      client_token: A unique identifier which enables you to
+        manage the idempotency.
+        :type       client_token: ``bool``
+
+        :param      deletion_protection: If true, you cannot terminate the
+        VM using Cockpit, the CLI or the API.
+        If false, you can.
+        :type       deletion_protection: ``bool``
+
+        :param      keypair_name: The name of the keypair.
+        :type       keypair_name: ``str``
+
+        :param      max_vms_count: The maximum number of VMs you want to
+        create. If all the VMs cannot be created, the
+        largest possible number of VMs above MinVmsCount is created.
+        :type       max_vms_count: ``integer``
+
+        :param      min_vms_count: The minimum number of VMs you want to
+        create. If this number of VMs cannot be
+        created, no VMs are created.
+        :type       min_vms_count: ``integer``
+
+        :param      nics: One or more NICs. If you specify this parameter,
+        you must define one NIC as the primary
+        network interface of the VM with 0 as its device number.
+        :type       nics: ``dict``
+
+        :param      performance: The performance of the VM (standard | high
+        | highest).
+        :type       performance: ``str``
+
+        :param      placement: Information about the placement of the VM.
+        :type       placement: ``dict``
+
+        :param      private_ips: One or more private IP addresses of the VM.
+        :type       private_ips: ``list``
+
+        :param      security_group_ids: One or more IDs of security group
+        for the VMs.
+        :type       security_group_ids: ``list``
+
+        :param      security_groups: One or more names of security groups
+        for the VMs.
+        :type       security_groups: ``list``
+
+        :param      subnet_id: The ID of the Subnet in which you want to
+        create the VM.
+        :type       subnet_id: ``str``
+
+        :return: the created instance
+        :rtype: ``dict``
+        """
+        data = {
+            "DryRun": dry_run,
+            "BootOnCreation": boot_on_creation,
+            "BsuOptimized": bsu_optimized,
+            "ImageId": image_id
+        }
+        if block_device_mapping is not None:
+            data.update({"BlockDeviceMappings": block_device_mapping})
+        if client_token is not None:
+            data.update({"ClientToken": client_token})
+        if deletion_protection is not None:
+            data.update({"DeletionProtection": deletion_protection})
+        if keypair_name is not None:
+            data.update({"KeypairName": keypair_name})
+        if max_vms_count is not None:
+            data.update({"MaxVmsCount": max_vms_count})
+        if min_vms_count is not None:
+            data.update({"MinVmsCount": min_vms_count})
+        if nics is not None:
+            data.update({"Nics": nics})
+        if performance is not None:
+            data.update({"Performance": performance})
+        if placement is not None:
+            data.update({"Placement": placement})
+        if private_ips is not None:
+            data.update({"PrivateIps": private_ips})
+        if security_group_ids is not None:
+            data.update({"SecurityGroupIds": security_group_ids})
+        if security_groups is not None:
+            data.update({"SecurityGroups": security_groups})
+        if subnet_id is not None:
+            data.update({"SubnetId": subnet_id})
+        action = "CreateVms"
+        data = json.dumps(data)
+        signer = OSCRequestSignerAlgorithmV4(access_key=self.key,
+                                             access_secret=self.secret,
+                                             version=self.version,
+                                             connection=self.connection)
+        headers = signer.get_request_headers(action=action,
+                                             data=data,
+                                             service_name=self.service_name,
+                                             region=self.region)
+        endpoint = self._get_outscale_endpoint(self.region,
+                                               self.version,
+                                               action)
+        return requests.post(endpoint, data=data, headers=headers)
+
+    def reboot_node(self, node_ids):
+        """
+        Reboot instances.
+
+        :param      node_ids: the ID(s) of the VM(s)
+                    you want to reboot (required)
+        :type       node_ids: ``list``
+
+        :return: the rebooted instances
+        :rtype: ``dict``
+        """
+        action = "RebootVms"
+        data = json.dumps({"VmIds": node_ids})
+        signer = OSCRequestSignerAlgorithmV4(access_key=self.key,
+                                             access_secret=self.secret,
+                                             version=self.version,
+                                             connection=self.connection)
+        headers = signer.get_request_headers(action=action,
+                                             data=data,
+                                             service_name=self.service_name,
+                                             region=self.region)
+        endpoint = self._get_outscale_endpoint(self.region,
+                                               self.version,
+                                               action)
+        return requests.post(endpoint, data=data, headers=headers)
+
+    def list_nodes(self, data="{}"):

Review comment:
       To comply with the base Libcloud API, this method needs to return a list of ``Node`` objects.




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [libcloud] tgn-outscale edited a comment on pull request #1476: New compute driver OUTSCALE

Posted by GitBox <gi...@apache.org>.
tgn-outscale edited a comment on pull request #1476:
URL: https://github.com/apache/libcloud/pull/1476#issuecomment-680064416


   Hello @Kami,
   I have made the changes according to what you said for more compliance with the base driver.
   Let me know if I missed or misunderstood anything.


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [libcloud] Kami commented on a change in pull request #1476: New compute driver OUTSCALE

Posted by GitBox <gi...@apache.org>.
Kami commented on a change in pull request #1476:
URL: https://github.com/apache/libcloud/pull/1476#discussion_r470649269



##########
File path: libcloud/compute/drivers/outscale.py
##########
@@ -0,0 +1,1109 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""
+Outscale SDK
+"""
+
+import json
+
+import requests
+
+from libcloud.compute.base import NodeDriver
+from libcloud.compute.types import Provider
+from libcloud.common.osc import OSCRequestSignerAlgorithmV4
+from libcloud.common.base import ConnectionUserAndKey
+
+
+class OutscaleNodeDriver(NodeDriver):
+    """
+    Outscale SDK node driver
+    """
+
+    type = Provider.OUTSCALE
+    name = 'Outscale API'
+    website = 'http://www.outscale.com'
+
+    def __init__(self,
+                 key=None,
+                 secret=None,
+                 region='eu-west-2',
+                 service='api',
+                 version='latest'
+                 ):
+        self.key = key
+        self.secret = secret
+        self.region = region
+        self.connection = ConnectionUserAndKey(self.key, self.secret)
+        self.connection.region_name = region
+        self.connection.service_name = service
+        self.service_name = service
+        self.version = version
+
+    def list_locations(self, dry_run=False):
+        """
+        Lists available regions details.
+
+        :return: regions details
+        :rtype: ``dict``
+        """
+        action = "ReadRegions"
+        data = json.dumps({"DryRun": dry_run})
+        signer = OSCRequestSignerAlgorithmV4(access_key=self.key,
+                                             access_secret=self.secret,
+                                             version=self.version,
+                                             connection=self.connection)
+        headers = signer.get_request_headers(action=action,
+                                             data=data,
+                                             service_name=self.service_name,
+                                             region=self.region)
+        endpoint = self._get_outscale_endpoint(self.region,
+                                               self.version,
+                                               action)
+        return requests.post(endpoint, data=data, headers=headers)
+
+    def create_public_ip(self, dry_run=False):
+        """
+        Create a new public ip.
+
+        :param      dry_run: If true, checks whether you have the required
+        permissions to perform the action.
+        :type       dry_run: ``bool``
+
+        :return: the created public ip
+        :rtype: ``dict``
+            """
+        action = "CreatePublicIp"
+        data = json.dumps({"DryRun": dry_run})
+        signer = OSCRequestSignerAlgorithmV4(access_key=self.key,
+                                             access_secret=self.secret,
+                                             version=self.version,
+                                             connection=self.connection)
+        headers = signer.get_request_headers(action=action,
+                                             data=data,
+                                             service_name=self.service_name,
+                                             region=self.region)
+        endpoint = self._get_outscale_endpoint(self.region,
+                                               self.version,
+                                               action)
+        return requests.post(endpoint, data=data, headers=headers)
+
+    def delete_public_ip(self, dry_run=False,
+                         public_ip=None,
+                         public_ip_id=None):
+        """
+        Delete instances.
+
+        :param      dry_run: If true, checks whether you have the required
+        permissions to perform the action.
+        :type       dry_run: ``bool``
+
+        :param      public_ip: The EIP. In the public Cloud, this parameter is
+        required.
+        :type       public_ip: ``str``
+
+        :param      public_ip_id: The ID representing the association of the
+        EIP with the VM or the NIC. In a Net,
+        this parameter is required.
+        :type       public_ip_id: ``str``
+
+        :return: request
+        :rtype: ``dict``
+        """
+        action = "DeletePublicIp"
+        data = {"DryRun": dry_run}
+        if public_ip is not None:
+            data.update({"PublicIp": public_ip})
+        if public_ip_id is not None:
+            data.update({"PublicIpId": public_ip_id})
+        data = json.dumps(data)
+        signer = OSCRequestSignerAlgorithmV4(access_key=self.key,
+                                             access_secret=self.secret,
+                                             version=self.version,
+                                             connection=self.connection)
+        headers = signer.get_request_headers(action=action,
+                                             data=data,
+                                             service_name=self.service_name,
+                                             region=self.region)
+        endpoint = self._get_outscale_endpoint(self.region,
+                                               self.version,
+                                               action)
+        return requests.post(endpoint, data=data, headers=headers)
+
+    def list_public_ips(self, data="{}"):
+        """
+        List all nodes.
+
+        :param      data: json stringify following the outscale api
+        documentation for filter
+        :type       data: ``string``
+
+        :return: nodes
+        :rtype: ``dict``
+        """
+        action = "ReadPublicIps"
+        signer = OSCRequestSignerAlgorithmV4(access_key=self.key,
+                                             access_secret=self.secret,
+                                             version=self.version,
+                                             connection=self.connection)
+        headers = signer.get_request_headers(action=action,
+                                             data=data,
+                                             service_name=self.service_name,
+                                             region=self.region)
+        endpoint = self._get_outscale_endpoint(self.region,
+                                               self.version,
+                                               action)
+        return requests.post(endpoint, data=data, headers=headers)
+
+    def list_public_ip_ranges(self, dry_run=False):
+        """
+        Lists available regions details.
+
+        :param      dry_run: If true, checks whether you have the
+        required permissions to perform the action.
+        :type       dry_run: ``bool``
+
+        :return: regions details
+        :rtype: ``dict``
+        """
+        action = "ReadPublicIpRanges"
+        data = json.dumps({"DryRun": dry_run})
+        signer = OSCRequestSignerAlgorithmV4(access_key=self.key,
+                                             access_secret=self.secret,
+                                             version=self.version,
+                                             connection=self.connection)
+        headers = signer.get_request_headers(action=action,
+                                             data=data,
+                                             service_name=self.service_name,
+                                             region=self.region)
+        endpoint = self._get_outscale_endpoint(self.region,
+                                               self.version,
+                                               action)
+        return requests.post(endpoint, data=data, headers=headers)
+
+    def attach_public_ip(self,
+                         allow_relink=None,
+                         dry_run=False,
+                         nic_id=None,
+                         vm_id=None,
+                         public_ip=None,
+                         public_ip_id=None,
+                         ):
+        """
+        Attach a volume.
+
+        :param      allow_relink: If true, allows the EIP to be associated
+        with the VM or NIC that you specify even if
+        it is already associated with another VM or NIC.
+        :type       allow_relink: ``bool``
+
+        :param      dry_run: If true, checks whether you have the required
+        permissions to perform the action.
+        :type       dry_run: ``bool``
+
+        :param      nic_id:(Net only) The ID of the NIC. This parameter is
+        required if the VM has more than one NIC attached. Otherwise,
+        you need to specify the VmId parameter instead.
+        You cannot specify both parameters
+        at the same time.
+        :type       nic_id: ``str``
+
+        :param      vm_id: the ID of the VM
+        :type       nic_id: ``str``
+
+        :param      public_ip: The EIP. In the public Cloud, this parameter
+        is required.
+        :type       public_ip: ``str``
+
+        :param      public_ip_id: The allocation ID of the EIP. In a Net,
+        this parameter is required.
+        :type       public_ip_id: ``str``
+
+        :return: the attached volume
+        :rtype: ``dict``
+        """
+        action = "LinkPublicIp"
+        data = {"DryRun": dry_run}
+        if public_ip is not None:
+            data.update({"PublicIp": public_ip})
+        if public_ip_id is not None:
+            data.update({"PublicIpId": public_ip_id})
+        if nic_id is not None:
+            data.update({"NicId": nic_id})
+        if vm_id is not None:
+            data.update({"VmId": vm_id})
+        if allow_relink is not None:
+            data.update({"AllowRelink": allow_relink})
+        data = json.dumps(data)
+        signer = OSCRequestSignerAlgorithmV4(access_key=self.key,
+                                             access_secret=self.secret,
+                                             version=self.version,
+                                             connection=self.connection)
+        headers = signer.get_request_headers(action=action,
+                                             data=data,
+                                             service_name=self.service_name,
+                                             region=self.region)
+        endpoint = self._get_outscale_endpoint(self.region,
+                                               self.version,
+                                               action)
+        return requests.post(endpoint, data=data, headers=headers)
+
+    def detach_public_ip(self, public_ip=None,
+                         link_public_ip_id=None,
+                         dry_run=False):
+        """
+        Detach a volume.
+
+        :param      public_ip: (Required in a Net) The ID representing the
+        association of the EIP with the VM or the NIC
+        :type       public_ip: ``str``
+
+        :param      link_public_ip_id: (Required in a Net) The ID
+        representing the association of the EIP with the
+        VM or the NIC.
+        :type       link_public_ip_id: ``str``
+
+        :param      dry_run: If true, checks whether you have the required
+        permissions to perform the action.
+        :type       dry_run: ``bool``
+
+        :return: the attached volume
+        :rtype: ``dict``
+        """
+        action = "UnlinkPublicIp"
+        data = {"DryRun": dry_run}
+        if public_ip is not None:
+            data.update({"PublicIp": public_ip})
+        if link_public_ip_id is not None:
+            data.update({"LinkPublicIpId": link_public_ip_id})
+        data = json.dumps(data)
+        signer = OSCRequestSignerAlgorithmV4(access_key=self.key,
+                                             access_secret=self.secret,
+                                             version=self.version,
+                                             connection=self.connection)
+        headers = signer.get_request_headers(action=action,
+                                             data=data,
+                                             service_name=self.service_name,
+                                             region=self.region)
+        endpoint = self._get_outscale_endpoint(self.region,
+                                               self.version,
+                                               action)
+        return requests.post(endpoint, data=data, headers=headers)
+
+    def create_node(self,
+                    image_id,
+                    dry_run=False,
+                    block_device_mapping=None,
+                    boot_on_creation=True,
+                    bsu_optimized=True,
+                    client_token=None,
+                    deletion_protection=False,
+                    keypair_name=None,
+                    max_vms_count=None,
+                    min_vms_count=None,
+                    nics=None,
+                    performance=None,
+                    placement=None,
+                    private_ips=None,
+                    security_group_ids=None,
+                    security_groups=None,
+                    subnet_id=None,
+                    ):
+        """
+        Create a new instance.
+
+        :param      image_id: The ID of the OMI used to create the VM.
+        :type       image_id: ``str``
+
+        :param      dry_run: If true, checks whether you have the required
+        permissions to perform the action.
+        :type       dry_run: ``bool``
+
+        :param      block_device_mapping: One or more block device mappings.
+        :type       block_device_mapping: ``dict``
+
+        :param      boot_on_creation: By default or if true, the VM is
+        started on creation. If false, the VM is
+        stopped on creation.
+        :type       boot_on_creation: ``bool``
+
+        :param      bsu_optimized: If true, the VM is created with optimized
+        BSU I/O.
+        :type       bsu_optimized: ``bool``
+
+        :param      client_token: A unique identifier which enables you to
+        manage the idempotency.
+        :type       client_token: ``bool``
+
+        :param      deletion_protection: If true, you cannot terminate the
+        VM using Cockpit, the CLI or the API.
+        If false, you can.
+        :type       deletion_protection: ``bool``
+
+        :param      keypair_name: The name of the keypair.
+        :type       keypair_name: ``str``
+
+        :param      max_vms_count: The maximum number of VMs you want to
+        create. If all the VMs cannot be created, the
+        largest possible number of VMs above MinVmsCount is created.
+        :type       max_vms_count: ``integer``
+
+        :param      min_vms_count: The minimum number of VMs you want to
+        create. If this number of VMs cannot be
+        created, no VMs are created.
+        :type       min_vms_count: ``integer``
+
+        :param      nics: One or more NICs. If you specify this parameter,
+        you must define one NIC as the primary
+        network interface of the VM with 0 as its device number.
+        :type       nics: ``dict``
+
+        :param      performance: The performance of the VM (standard | high
+        | highest).
+        :type       performance: ``str``
+
+        :param      placement: Information about the placement of the VM.
+        :type       placement: ``dict``
+
+        :param      private_ips: One or more private IP addresses of the VM.
+        :type       private_ips: ``list``
+
+        :param      security_group_ids: One or more IDs of security group
+        for the VMs.
+        :type       security_group_ids: ``list``
+
+        :param      security_groups: One or more names of security groups
+        for the VMs.
+        :type       security_groups: ``list``
+
+        :param      subnet_id: The ID of the Subnet in which you want to
+        create the VM.
+        :type       subnet_id: ``str``
+
+        :return: the created instance
+        :rtype: ``dict``
+        """
+        data = {
+            "DryRun": dry_run,
+            "BootOnCreation": boot_on_creation,
+            "BsuOptimized": bsu_optimized,
+            "ImageId": image_id
+        }
+        if block_device_mapping is not None:
+            data.update({"BlockDeviceMappings": block_device_mapping})
+        if client_token is not None:
+            data.update({"ClientToken": client_token})
+        if deletion_protection is not None:
+            data.update({"DeletionProtection": deletion_protection})
+        if keypair_name is not None:
+            data.update({"KeypairName": keypair_name})
+        if max_vms_count is not None:
+            data.update({"MaxVmsCount": max_vms_count})
+        if min_vms_count is not None:
+            data.update({"MinVmsCount": min_vms_count})
+        if nics is not None:
+            data.update({"Nics": nics})
+        if performance is not None:
+            data.update({"Performance": performance})
+        if placement is not None:
+            data.update({"Placement": placement})
+        if private_ips is not None:
+            data.update({"PrivateIps": private_ips})
+        if security_group_ids is not None:
+            data.update({"SecurityGroupIds": security_group_ids})
+        if security_groups is not None:
+            data.update({"SecurityGroups": security_groups})
+        if subnet_id is not None:
+            data.update({"SubnetId": subnet_id})
+        action = "CreateVms"
+        data = json.dumps(data)
+        signer = OSCRequestSignerAlgorithmV4(access_key=self.key,
+                                             access_secret=self.secret,
+                                             version=self.version,
+                                             connection=self.connection)
+        headers = signer.get_request_headers(action=action,
+                                             data=data,
+                                             service_name=self.service_name,
+                                             region=self.region)
+        endpoint = self._get_outscale_endpoint(self.region,
+                                               self.version,
+                                               action)
+        return requests.post(endpoint, data=data, headers=headers)
+
+    def reboot_node(self, node_ids):
+        """
+        Reboot instances.
+
+        :param      node_ids: the ID(s) of the VM(s)
+                    you want to reboot (required)
+        :type       node_ids: ``list``
+
+        :return: the rebooted instances
+        :rtype: ``dict``
+        """
+        action = "RebootVms"
+        data = json.dumps({"VmIds": node_ids})
+        signer = OSCRequestSignerAlgorithmV4(access_key=self.key,
+                                             access_secret=self.secret,
+                                             version=self.version,
+                                             connection=self.connection)
+        headers = signer.get_request_headers(action=action,
+                                             data=data,
+                                             service_name=self.service_name,
+                                             region=self.region)
+        endpoint = self._get_outscale_endpoint(self.region,
+                                               self.version,
+                                               action)
+        return requests.post(endpoint, data=data, headers=headers)
+
+    def list_nodes(self, data="{}"):
+        """
+        List all nodes.
+
+        :return: nodes
+        :rtype: ``dict``
+        """
+        action = "ReadVms"
+        signer = OSCRequestSignerAlgorithmV4(access_key=self.key,
+                                             access_secret=self.secret,
+                                             version=self.version,
+                                             connection=self.connection)
+        headers = signer.get_request_headers(action=action,
+                                             data=data,
+                                             service_name=self.service_name,
+                                             region=self.region)
+        endpoint = self._get_outscale_endpoint(self.region,
+                                               self.version,
+                                               action)
+        return requests.post(endpoint, data=data, headers=headers)
+
+    def delete_node(self, node_ids):
+        """
+        Delete instances.
+
+        :param      node_ids: one or more IDs of VMs (required)
+        :type       node_ids: ``list``
+
+        :return: request
+        :rtype: ``dict``
+        """
+        action = "DeleteVms"
+        data = json.dumps({"VmIds": node_ids})
+        signer = OSCRequestSignerAlgorithmV4(access_key=self.key,
+                                             access_secret=self.secret,
+                                             version=self.version,
+                                             connection=self.connection)
+        headers = signer.get_request_headers(action=action,
+                                             data=data,
+                                             service_name=self.service_name,
+                                             region=self.region)
+        endpoint = self._get_outscale_endpoint(self.region,
+                                               self.version,
+                                               action)
+        return requests.post(endpoint, data=data, headers=headers)
+
+    def create_image(
+        self,
+        architecture=None,
+        vm_id=None,
+        image_name=None,
+        description=None,
+        block_device_mapping=None,
+        no_reboot=False,
+        root_device_name=None,
+        dry_run=False,
+        source_region_name=None,
+        file_location=None
+    ):
+        """
+        Create a new image.
+
+        :param      vm_id: the ID of the VM from which
+                    you want to create the OMI (required)
+        :type       vm_id: ``str``
+
+        :param      architecture: The architecture of the OMI (by default,
+        i386).
+        :type       architecture: ``str``
+
+        :param      description: a description for the new OMI
+        :type       description: ``str``
+
+        :param      image_name: A unique name for the new OMI.
+        :type       image_name: ``str``
+
+        :param      block_device_mapping: One or more block device mappings.
+        :type       block_device_mapping: ``dict``
+
+        :param      no_reboot: If false, the VM shuts down before creating
+        the OMI and then reboots.
+        If true, the VM does not.
+        :type       no_reboot: ``bool``
+
+        :param      root_device_name: The name of the root device.
+        :type       root_device_name: ``str``
+
+        :param      source_region_name: The name of the source Region,
+        which must be the same
+        as the Region of your account.
+        :type       source_region_name: ``str``
+
+        :param      file_location: The pre-signed URL of the OMI manifest
+        file, or the full path to the OMI stored in
+        an OSU bucket. If you specify this parameter, a copy of the OMI is
+        created in your account.
+        :type       file_location: ``str``
+
+        :param      dry_run: If true, checks whether you have the required
+        permissions to perform the action.
+        :type       dry_run: ``bool``
+
+        :return: the created image
+        :rtype: ``dict``
+        """
+        data = {
+            "DryRun": dry_run,
+            "NoReboot": no_reboot,
+        }
+        if block_device_mapping is not None:
+            data.update({"BlockDeviceMappings": block_device_mapping})
+        if image_name is not None:
+            data.update({"ImageName": image_name})
+        if description is not None:
+            data.update({"Description": description})
+        if vm_id is not None:
+            data.update({"VmId": vm_id})
+        if root_device_name is not None:
+            data.update({"RootDeviceName": root_device_name})
+        if source_region_name is not None:
+            data.update({"SourceRegionName": source_region_name})
+        if file_location is not None:
+            data.update({"FileLocation": file_location})
+        data = json.dumps(data)
+        action = "CreateImage"
+        signer = OSCRequestSignerAlgorithmV4(access_key=self.key,
+                                             access_secret=self.secret,
+                                             version=self.version,
+                                             connection=self.connection)
+        headers = signer.get_request_headers(action=action,
+                                             data=data,
+                                             service_name=self.service_name,
+                                             region=self.region)
+        endpoint = self._get_outscale_endpoint(self.region,
+                                               self.version,
+                                               action)
+        return requests.post(endpoint, data=data, headers=headers)
+
+    def list_images(self, data="{}"):
+        """
+        List all images.
+
+        :return: images
+        :rtype: ``dict``
+        """
+        action = "ReadImages"
+        signer = OSCRequestSignerAlgorithmV4(access_key=self.key,
+                                             access_secret=self.secret,
+                                             version=self.version,
+                                             connection=self.connection)
+        headers = signer.get_request_headers(action=action,
+                                             data=data,
+                                             service_name=self.service_name,
+                                             region=self.region)
+        endpoint = self._get_outscale_endpoint(self.region,
+                                               self.version,
+                                               action)
+        return requests.post(endpoint, data=data, headers=headers)
+
+    def get_image(self, image_id):
+        """
+        Get a specific image.
+
+        :param      image_id: the ID of the image you want to select (required)
+        :type       image_id: ``str``
+
+        :return: the selected image
+        :rtype: ``dict``
+        """
+        action = "ReadImages"
+        data = '{"Filters": {"ImageIds": ["' + image_id + '"]}}'
+        signer = OSCRequestSignerAlgorithmV4(access_key=self.key,
+                                             access_secret=self.secret,
+                                             version=self.version,
+                                             connection=self.connection)
+        headers = signer.get_request_headers(action=action,
+                                             data=data,
+                                             service_name=self.service_name,
+                                             region=self.region)
+        endpoint = self._get_outscale_endpoint(self.region,
+                                               self.version,
+                                               action)
+        return requests.post(endpoint, data=data, headers=headers)
+
+    def delete_image(self, image_id):

Review comment:
       Needs to take ``NodeImage`` object.




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [libcloud] tgn-outscale commented on pull request #1476: New compute driver OUTSCALE

Posted by GitBox <gi...@apache.org>.
tgn-outscale commented on pull request #1476:
URL: https://github.com/apache/libcloud/pull/1476#issuecomment-680064416


   Hello @Kami,
   I have made the change according to what you said for more compliance with the base driver.
   Let me know if I missed or misunderstood anything.


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [libcloud] Kami commented on a change in pull request #1476: New compute driver OUTSCALE

Posted by GitBox <gi...@apache.org>.
Kami commented on a change in pull request #1476:
URL: https://github.com/apache/libcloud/pull/1476#discussion_r479777624



##########
File path: libcloud/compute/drivers/outscale.py
##########
@@ -0,0 +1,1018 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""
+Outscale SDK
+"""
+
+import json
+
+import requests
+
+from libcloud.compute.base import NodeDriver
+from libcloud.compute.types import Provider
+from libcloud.common.osc import OSCRequestSignerAlgorithmV4
+from libcloud.common.base import ConnectionUserAndKey
+from libcloud.compute.base import \
+    Node,\
+    NodeImage, \
+    KeyPair, \
+    StorageVolume, \
+    VolumeSnapshot, \
+    NodeLocation
+from libcloud.compute.types import NodeState
+
+
+class OutscaleNodeDriver(NodeDriver):
+    """
+    Outscale SDK node driver
+    """
+
+    type = Provider.OUTSCALE
+    name = 'Outscale API'
+    website = 'http://www.outscale.com'
+
+    def __init__(self,
+                 key: str = None,

Review comment:
       Thanks for adding type annotations :+1: 




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [libcloud] Kami commented on pull request #1476: New compute driver OUTSCALE

Posted by GitBox <gi...@apache.org>.
Kami commented on pull request #1476:
URL: https://github.com/apache/libcloud/pull/1476#issuecomment-674092009


   @tgn-outscale Thanks for the clarification. It would be a good idea to also point this out in the driver documentation page inside docs/ directory.


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [libcloud] Kami commented on a change in pull request #1476: New compute driver OUTSCALE

Posted by GitBox <gi...@apache.org>.
Kami commented on a change in pull request #1476:
URL: https://github.com/apache/libcloud/pull/1476#discussion_r470646392



##########
File path: libcloud/compute/drivers/outscale.py
##########
@@ -0,0 +1,1109 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""
+Outscale SDK
+"""
+
+import json
+
+import requests
+
+from libcloud.compute.base import NodeDriver
+from libcloud.compute.types import Provider
+from libcloud.common.osc import OSCRequestSignerAlgorithmV4
+from libcloud.common.base import ConnectionUserAndKey
+
+
+class OutscaleNodeDriver(NodeDriver):
+    """
+    Outscale SDK node driver
+    """
+
+    type = Provider.OUTSCALE
+    name = 'Outscale API'
+    website = 'http://www.outscale.com'
+
+    def __init__(self,
+                 key=None,
+                 secret=None,
+                 region='eu-west-2',
+                 service='api',
+                 version='latest'
+                 ):
+        self.key = key
+        self.secret = secret
+        self.region = region
+        self.connection = ConnectionUserAndKey(self.key, self.secret)
+        self.connection.region_name = region
+        self.connection.service_name = service
+        self.service_name = service
+        self.version = version
+
+    def list_locations(self, dry_run=False):
+        """
+        Lists available regions details.
+
+        :return: regions details
+        :rtype: ``dict``
+        """
+        action = "ReadRegions"
+        data = json.dumps({"DryRun": dry_run})
+        signer = OSCRequestSignerAlgorithmV4(access_key=self.key,

Review comment:
       Looks like the next couple of lines are duplicated across all the driver methods.
   
   To avoid duplication it would be good to refactor that in some common method.
   
   In addition to that, it looks like ``OSCRequestSignerAlgorithmV4`` could also be instantiated inside the driver constructor since it doesn't seem to depend on any method specific arguments.




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [libcloud] tgn-outscale commented on pull request #1476: New compute driver OUTSCALE

Posted by GitBox <gi...@apache.org>.
tgn-outscale commented on pull request #1476:
URL: https://github.com/apache/libcloud/pull/1476#issuecomment-683656042


   Thanks for your help @Kami, I will try to implement those changes when I will find time to do so,
   Best regards


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [libcloud] Kami commented on pull request #1476: New compute driver OUTSCALE

Posted by GitBox <gi...@apache.org>.
Kami commented on pull request #1476:
URL: https://github.com/apache/libcloud/pull/1476#issuecomment-674249627


   You are welcome.
   
   If you need any additional clarification on the extension method and argument naming, please let me know.


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [libcloud] Kami commented on pull request #1476: New compute driver OUTSCALE

Posted by GitBox <gi...@apache.org>.
Kami commented on pull request #1476:
URL: https://github.com/apache/libcloud/pull/1476#issuecomment-683429846


   @tgn-outscale Thanks for addressing the review feedback.
   
   I merged the PR into trunk, but there are still some places which would ideally be improved in the near future:
   
   - Try to make more methods comply with the Libcloud standard API (where possible) - this would make it easier for users to switch to this driver (right now it utilizes a lot of non-standard argument names which means Libcloud code which works with other provider drivers won't work with this one). This includes both - the argument the methods take and method return values - e.g. ``create_node()`` should take name, size and image arguments and return ``Node`` instance class (and not a dictionary). Same goes for some other methods. 
   - Need to add some documentation with examples to ``docs/compute/drivers/``


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [libcloud] Kami commented on a change in pull request #1476: New compute driver OUTSCALE

Posted by GitBox <gi...@apache.org>.
Kami commented on a change in pull request #1476:
URL: https://github.com/apache/libcloud/pull/1476#discussion_r470647071



##########
File path: libcloud/compute/drivers/outscale.py
##########
@@ -0,0 +1,1109 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""
+Outscale SDK
+"""
+
+import json
+
+import requests
+
+from libcloud.compute.base import NodeDriver
+from libcloud.compute.types import Provider
+from libcloud.common.osc import OSCRequestSignerAlgorithmV4
+from libcloud.common.base import ConnectionUserAndKey
+
+
+class OutscaleNodeDriver(NodeDriver):
+    """
+    Outscale SDK node driver
+    """
+
+    type = Provider.OUTSCALE
+    name = 'Outscale API'
+    website = 'http://www.outscale.com'
+
+    def __init__(self,
+                 key=None,
+                 secret=None,
+                 region='eu-west-2',
+                 service='api',
+                 version='latest'
+                 ):
+        self.key = key
+        self.secret = secret
+        self.region = region
+        self.connection = ConnectionUserAndKey(self.key, self.secret)
+        self.connection.region_name = region
+        self.connection.service_name = service
+        self.service_name = service
+        self.version = version
+
+    def list_locations(self, dry_run=False):
+        """
+        Lists available regions details.
+
+        :return: regions details
+        :rtype: ``dict``
+        """
+        action = "ReadRegions"
+        data = json.dumps({"DryRun": dry_run})
+        signer = OSCRequestSignerAlgorithmV4(access_key=self.key,
+                                             access_secret=self.secret,
+                                             version=self.version,
+                                             connection=self.connection)
+        headers = signer.get_request_headers(action=action,
+                                             data=data,
+                                             service_name=self.service_name,
+                                             region=self.region)
+        endpoint = self._get_outscale_endpoint(self.region,
+                                               self.version,
+                                               action)
+        return requests.post(endpoint, data=data, headers=headers)
+
+    def create_public_ip(self, dry_run=False):

Review comment:
       Methods which are not part of a standard Libcloud API need to be prefixed with ``ex_`` - so ``ex_create_public_ip``, ``ex_delete_public_ip``, etc.




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [libcloud] Kami commented on a change in pull request #1476: New compute driver OUTSCALE

Posted by GitBox <gi...@apache.org>.
Kami commented on a change in pull request #1476:
URL: https://github.com/apache/libcloud/pull/1476#discussion_r479777826



##########
File path: libcloud/compute/drivers/outscale.py
##########
@@ -0,0 +1,1018 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""
+Outscale SDK
+"""
+
+import json
+
+import requests
+
+from libcloud.compute.base import NodeDriver
+from libcloud.compute.types import Provider
+from libcloud.common.osc import OSCRequestSignerAlgorithmV4
+from libcloud.common.base import ConnectionUserAndKey
+from libcloud.compute.base import \
+    Node,\
+    NodeImage, \
+    KeyPair, \
+    StorageVolume, \
+    VolumeSnapshot, \
+    NodeLocation
+from libcloud.compute.types import NodeState
+
+
+class OutscaleNodeDriver(NodeDriver):
+    """
+    Outscale SDK node driver
+    """
+
+    type = Provider.OUTSCALE
+    name = 'Outscale API'
+    website = 'http://www.outscale.com'
+
+    def __init__(self,
+                 key: str = None,
+                 secret: str = None,
+                 region: str = 'eu-west-2',
+                 service: str = 'api',
+                 version: str = 'latest'
+                 ):
+        self.key = key
+        self.secret = secret
+        self.region = region
+        self.connection = ConnectionUserAndKey(self.key, self.secret)
+        self.connection.region_name = region
+        self.connection.service_name = service
+        self.service_name = service
+        self.version = version
+        self.signer = OSCRequestSignerAlgorithmV4(
+            access_key=self.key,
+            access_secret=self.secret,
+            version=self.version,
+            connection=self.connection
+        )
+        self.NODE_STATE = {
+            'pending': NodeState.PENDING,
+            'running': NodeState.RUNNING,
+            'shutting-down': NodeState.UNKNOWN,
+            'terminated': NodeState.TERMINATED,
+            'stopped': NodeState.STOPPED
+        }
+
+    def list_locations(self, ex_dry_run: bool = False):
+        """
+        Lists available regions details.
+        :param      ex_dry_run: If true, checks whether you have the required
+        permissions to perform the action.
+        :type       ex_dry_run: ``bool``
+        :return: regions details
+        :rtype: ``dict``
+        """
+        action = "ReadRegions"
+        data = json.dumps({"DryRun": ex_dry_run})
+        response = self._call_api(action, data)
+        return self._to_locations(response.json()["Regions"])
+
+    def ex_create_public_ip(self, dry_run: bool = False):
+        """
+        Create a new public ip.
+
+        :param      dry_run: If true, checks whether you have the required
+        permissions to perform the action.
+        :type       dry_run: ``bool``
+
+        :return: the created public ip
+        :rtype: ``dict``
+            """
+        action = "CreatePublicIp"
+        data = json.dumps({"DryRun": dry_run})
+        if self._call_api(action, data).status_code == 200:
+            return True
+        return False
+
+    def ex_delete_public_ip(self,
+                            dry_run: bool = False,
+                            public_ip: str = None,
+                            public_ip_id: str = None):
+        """
+        Delete instances.

Review comment:
       Some comments are out of sync with code, but I will update / fix that when merging the pr :)




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org