You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@libcloud.apache.org by to...@apache.org on 2020/08/30 14:50:12 UTC

[libcloud] 03/10: Changed code so it use with Libcloud resources' class on Outscale Provider

This is an automated email from the ASF dual-hosted git repository.

tomaz pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/libcloud.git

commit bf576d18ecbfab23a477f7125a00d94eff1b9eee
Author: Tio Gobin <ti...@epitech.eu>
AuthorDate: Sun Aug 23 18:49:15 2020 +0200

    Changed code so it use with Libcloud resources' class on Outscale Provider
---
 libcloud/compute/drivers/outscale.py | 270 +++++++++++++++++++++--------------
 1 file changed, 160 insertions(+), 110 deletions(-)

diff --git a/libcloud/compute/drivers/outscale.py b/libcloud/compute/drivers/outscale.py
index 97a4015..58bd08f 100644
--- a/libcloud/compute/drivers/outscale.py
+++ b/libcloud/compute/drivers/outscale.py
@@ -24,7 +24,7 @@ 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
+from libcloud.compute.base import Node, NodeImage, KeyPair, StorageVolume, VolumeSnapshot
 from libcloud.compute.types import NodeState
 
 
@@ -743,85 +743,103 @@ class OutscaleNodeDriver(NodeDriver):
         key_pair = requests.post(endpoint, data=data, headers=headers).json()["Keypairs"][0]
         return self._to_key_pair(key_pair)
 
-    def delete_key_pair(self, name: str):
+    def delete_key_pair(self, key_pair: KeyPair):
         """
         Delete an image.
 
-        :param      name: the name of the keypair you want to delete (required)
-        :type       name: ``str``
+        :param      key_pair: the name of the keypair you want to delete (required)
+        :type       key_pair: ``KeyPair``
 
-        :return: request
-        :rtype: ``dict``
+        :return: boolean
+        :rtype: ``bool``
         """
         action = "DeleteKeypair"
-        data = '{"KeypairName": "' + name + '"}'
+        data = '{"KeypairName": "' + key_pair.name + '"}'
         headers = self._ex_generate_headers(action, data)
         endpoint = self._get_outscale_endpoint(self.region,
                                                self.version,
                                                action)
-        return requests.post(endpoint, data=data, headers=headers)
+        if requests.post(endpoint, data=data, headers=headers).status_code == 200:
+            return True
+        return False
+
+    def _to_volume(self, volume):
+        name = ""
+        for tag in volume["Tags"]:
+            if tag["Key"] == "Name":
+                name = tag["Value"]
+        return StorageVolume(
+            id=volume["VolumeId"],
+            name=name,
+            size=volume["Size"],
+            driver=self,
+            state=volume["State"],
+            extra=volume
+        )
+
+    def _to_volumes(self, volumes):
+        return [self._to_volumes(volume) for volume in volumes]
 
-    def create_snapshot(self,
-                        description: str = None,
-                        dry_run: bool = False,
-                        file_location: str = None,
-                        snapshot_size: int = None,
-                        source_region_name: str = None,
-                        source_snapshot_id: str = None,
-                        volume_id: str = None,
-                        ):
+    def create_volume_snapshot(
+        self,
+        ex_description: str = None,
+        ex_dry_run: bool = False,
+        ex_file_location: str = None,
+        ex_snapshot_size: int = None,
+        ex_source_region_name: str = None,
+        ex_source_snapshot: VolumeSnapshot = None,
+        volume: StorageVolume = None):
         """
         Create a new snapshot.
 
-        :param      description: a description for the new OMI
-        :type       description: ``str``
+        :param      ex_description: a description for the new OMI
+        :type       ex_description: ``str``
 
-        :param      snapshot_size: The size of the snapshot created in your
+        :param      ex_snapshot_size: The size of the snapshot created in your
         account, in bytes. This size must be
         exactly the same as the source snapshot one.
-        :type       snapshot_size: ``integer``
+        :type       ex_snapshot_size: ``integer``
 
-        :param      source_snapshot_id: The ID of the snapshot you want to
+        :param      ex_source_snapshot: The ID of the snapshot you want to
         copy.
-        :type       source_snapshot_id: ``str``
+        :type       ex_source_snapshot: ``str``
 
-        :param      volume_id: The ID of the volume you want to create a
+        :param      volume: The ID of the volume you want to create a
         snapshot of.
-        :type       volume_id: ``str``
+        :type       volume: ``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      ex_source_region_name: The name of the source Region,
+        which must be the same as the Region of your account.
+        :type       ex_source_region_name: ``str``
 
-        :param      file_location: The pre-signed URL of the OMI manifest
+        :param      ex_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``
+        :type       ex_file_location: ``str``
 
-        :param      dry_run: If true, checks whether you have the required
+        :param      ex_dry_run: If true, checks whether you have the required
         permissions to perform the action.
-        :type       dry_run: ``bool``
+        :type       ex_dry_run: ``bool``
 
         :return: the created snapshot
         :rtype: ``dict``
         """
         data = {
-            "DryRun": dry_run,
+            "DryRun": ex_dry_run,
         }
-        if description is not None:
-            data.update({"Description": description})
-        if file_location is not None:
-            data.update({"FileLocation": file_location})
-        if snapshot_size is not None:
-            data.update({"SnapshotSize": snapshot_size})
-        if source_region_name is not None:
-            data.update({"SourceRegionName": source_region_name})
-        if source_snapshot_id is not None:
-            data.update({"SourceSnapshotId": source_snapshot_id})
-        if volume_id is not None:
-            data.update({"VolumeId": volume_id})
+        if ex_description is not None:
+            data.update({"Description": ex_description})
+        if ex_file_location is not None:
+            data.update({"FileLocation": ex_file_location})
+        if ex_snapshot_size is not None:
+            data.update({"SnapshotSize": ex_snapshot_size})
+        if ex_source_region_name is not None:
+            data.update({"SourceRegionName": ex_source_region_name})
+        if ex_source_snapshot is not None:
+            data.update({"SourceSnapshotId": ex_source_snapshot.id})
+        if volume is not None:
+            data.update({"VolumeId": volume.id})
         data = json.dumps(data)
         action = "CreateSnapshot"
         headers = self._ex_generate_headers(action, data)
@@ -830,7 +848,25 @@ class OutscaleNodeDriver(NodeDriver):
                                                action)
         return requests.post(endpoint, data=data, headers=headers)
 
-    def list_snapshots(self, data: str = "{}"):
+    def _to_snapshot(self, snapshot):
+        name = None
+        for tag in snapshot["Tags"]:
+            if tag["Key"] == "Name":
+                name = tag["Value"]
+        return VolumeSnapshot(
+            id=snapshot["SnapshotId"],
+            name=name,
+            size=snapshot["Size"],
+            driver=self,
+            state=snapshot["State"],
+            created=None,
+            extra=snapshot
+        )
+
+    def _to_snapshots(self, snapshots):
+        return [self._to_snapshot(snapshot) for snapshot in snapshots]
+
+    def list_snapshots(self, ex_data: str = "{}"):
         """
         List all snapshots.
 
@@ -838,84 +874,88 @@ class OutscaleNodeDriver(NodeDriver):
         :rtype: ``dict``
         """
         action = "ReadSnapshots"
-        headers = self._ex_generate_headers(action, data)
+        headers = self._ex_generate_headers(action, ex_data)
         endpoint = self._get_outscale_endpoint(self.region,
                                                self.version,
                                                action)
-        return requests.post(endpoint, data=data, headers=headers)
+        snapshots = requests.post(endpoint, data=ex_data, headers=headers).json()
 
-    def delete_snapshot(self, snapshot_id: str):
+        return self._to_snapshots(snapshots)
+
+    def destroy_volume_snapshot(self, snapshot: VolumeSnapshot):
         """
         Delete a snapshot.
 
-        :param      snapshot_id: the ID of the snapshot
+        :param      snapshot: the ID of the snapshot
                     you want to delete (required)
-        :type       snapshot_id: ``str``
+        :type       snapshot: ``str``
 
         :return: request
         :rtype: ``dict``
         """
         action = "DeleteSnapshot"
-        data = '{"SnapshotId": "' + snapshot_id + '"}'
+        data = '{"SnapshotId": "' + snapshot.id + '"}'
         headers = self._ex_generate_headers(action, data)
         endpoint = self._get_outscale_endpoint(self.region,
                                                self.version,
                                                action)
-        return requests.post(endpoint, data=data, headers=headers)
+        if requests.post(endpoint, data=data, headers=headers).status_code == 200:
+            return True
+        return False
 
     def create_volume(
         self,
-        subregion_name: str,
-        dry_run: bool = False,
-        iops: int = None,
+        ex_subregion_name: str,
+        ex_dry_run: bool = False,
+        ex_iops: int = None,
         size: int = None,
-        snapshot_id: str = None,
-        volume_type: str = None,
+        snapshot: VolumeSnapshot = None,
+        ex_volume_type: str = None,
     ):
         """
         Create a new volume.
 
-        :param      snapshot_id: the ID of the snapshot from which
+        :param      snapshot: the ID of the snapshot from which
                     you want to create the volume (required)
-        :type       snapshot_id: ``str``
+        :type       snapshot: ``str``
 
-        :param      dry_run: If true, checks whether you have the required
+        :param      ex_dry_run: If true, checks whether you have the required
         permissions to perform the action.
-        :type       dry_run: ``bool``
+        :type       ex_dry_run: ``bool``
 
         :param      size: the size of the volume, in gibibytes (GiB),
                     the maximum allowed size for a volume is 14,901 GiB
         :type       size: ``int``
 
-        :param      subregion_name: The Subregion in which you want to
+        :param      ex_subregion_name: The Subregion in which you want to
         create the volume.
-        :type       subregion_name: ``str``
+        :type       ex_subregion_name: ``str``
 
-        :param      volume_type: the type of volume you want to create (io1
+        :param      ex_volume_type: the type of volume you want to create (io1
         | gp2 | standard)
-        :type       volume_type: ``str``
+        :type       ex_volume_type: ``str``
 
-        :param      iops: The number of I/O operations per second (IOPS).
+        :param      ex_iops: The number of I/O operations per second (IOPS).
         This parameter must be specified only if
         you create an io1 volume. The maximum number of IOPS allowed for io1
         volumes is 13000.
-        :type       iops: ``integer``
+        :type       ex_iops: ``integer``
 
         :return: the created volume
         :rtype: ``dict``
         """
         data = {
-            "DryRun": dry_run,
-            "SubregionName": subregion_name
+            "DryRun": ex_dry_run,
+            "SubregionName": ex_subregion_name
         }
-        if iops is not None:
-            data.update({"Iops": iops})
+        if ex_iops is not None:
+            data.update({"Iops": ex_iops})
         if size is not None:
             data.update({"Size": size})
-        if snapshot_id is not None:
-            data.update({"SnapshotId": snapshot_id})
-        if volume_type is not None:
-            data.update({"VolumeType": volume_type})
+        if snapshot is not None:
+            data.update({"SnapshotId": snapshot.id})
+        if ex_volume_type is not None:
+            data.update({"VolumeType": ex_volume_type})
         data = json.dumps(data)
         action = "CreateVolume"
         headers = self._ex_generate_headers(action, data)
@@ -923,9 +963,12 @@ class OutscaleNodeDriver(NodeDriver):
         endpoint = self._get_outscale_endpoint(self.region,
                                                self.version,
                                                action)
-        return requests.post(endpoint, data=data, headers=headers)
 
-    def list_volumes(self, data: str = "{}"):
+        volume = requests.post(endpoint, data=data, headers=headers).json()["Volume"]
+
+        return self._to_volume(volume)
+
+    def list_volumes(self, ex_data: str = "{}"):
         """
         List all volumes.
 
@@ -933,94 +976,101 @@ class OutscaleNodeDriver(NodeDriver):
         :rtype: ``dict``
         """
         action = "ReadVolumes"
-        headers = self._ex_generate_headers(action, data)
+        headers = self._ex_generate_headers(action, ex_data)
         endpoint = self._get_outscale_endpoint(self.region,
                                                self.version,
                                                action)
-        return requests.post(endpoint, data=data, headers=headers)
+        volumes = requests.post(endpoint, data=ex_data, headers=headers).json()["Volumes"]
+        return self._to_volumes(volumes)
 
-    def delete_volume(self, volume_id: str):
+    def destroy_volume(self, volume: StorageVolume):
         """
         Delete a volume.
 
-        :param      volume_id: the ID of the volume
+        :param      volume: the ID of the volume
                     you want to delete (required)
-        :type       volume_id: ``str``
+        :type       volume: ``str``
 
         :return: request
         :rtype: ``dict``
         """
         action = "DeleteVolume"
-        data = '{"VolumeId": "' + volume_id + '"}'
+        data = '{"VolumeId": "' + volume.id + '"}'
         headers = self._ex_generate_headers(action, data)
         endpoint = self._get_outscale_endpoint(self.region,
                                                self.version,
                                                action)
-        return requests.post(endpoint, data=data, headers=headers)
+        if requests.post(endpoint, data=data, headers=headers).status_code == 200:
+            return True
+        return False
 
-    def attach_volume(self, node_id: str, volume_id: str, device_name: str):
+    def attach_volume(self, node: Node, volume: StorageVolume, device: str = None):
         """
         Attach a volume.
 
-        :param      node_id: the ID of the VM you want
+        :param      node: the ID of the VM you want
                     to attach the volume to (required)
-        :type       node_id: ``str``
+        :type       node: ``str``
 
-        :param      volume_id: the ID of the volume
+        :param      volume: the ID of the volume
                     you want to attach (required)
-        :type       volume_id: ``str``
+        :type       volume: ``str``
 
-        :param      device_name: the name of the device (required)
-        :type       device_name: ``str``
+        :param      device: the name of the device (required)
+        :type       device: ``str``
 
         :return: the attached volume
         :rtype: ``dict``
         """
         action = "LinkVolume"
         data = json.dumps({
-            "VmId": node_id,
-            "VolumeId": volume_id,
-            "DeviceName": device_name
+            "VmId": node.id,
+            "VolumeId": volume.id,
+            "DeviceName": device
         })
         headers = self._ex_generate_headers(action, data)
         endpoint = self._get_outscale_endpoint(self.region,
                                                self.version,
                                                action)
-        return requests.post(endpoint, data=data, headers=headers)
+        if requests.post(endpoint, data=data, headers=headers).status_code == 200:
+            return True
+        return False
 
     def detach_volume(self,
-                      volume_id: str,
-                      dry_run: bool = False,
-                      force_unlink: bool = False):
+                      volume: StorageVolume,
+                      ex_dry_run: bool = False,
+                      ex_force_unlink: bool = False):
         """
         Detach a volume.
 
-        :param      volume_id: the ID of the volume you want to detach
+        :param      volume: the ID of the volume you want to detach
         (required)
-        :type       volume_id: ``str``
+        :type       volume: ``str``
 
-        :param      force_unlink: Forces the detachment of the volume in
+        :param      ex_force_unlink: Forces the detachment of the volume in
         case of previous failure.
         Important: This action may damage your data or file systems.
-        :type       force_unlink: ``bool``
+        :type       ex_force_unlink: ``bool``
 
-        :param      dry_run: If true, checks whether you have the required
+        :param      ex_dry_run: If true, checks whether you have the required
         permissions to perform the action.
-        :type       dry_run: ``bool``
+        :type       ex_dry_run: ``bool``
 
         :return: the attached volume
         :rtype: ``dict``
         """
         action = "UnlinkVolume"
-        data = {"DryRun": dry_run, "VolumeId": volume_id}
-        if force_unlink is not None:
-            data.update({"ForceUnlink": force_unlink})
+        data = {"DryRun": ex_dry_run, "VolumeId": volume.id}
+        if ex_force_unlink is not None:
+            data.update({"ForceUnlink": ex_force_unlink})
         data = json.dumps(data)
         headers = self._ex_generate_headers(action, data)
         endpoint = self._get_outscale_endpoint(self.region,
                                                self.version,
                                                action)
-        return requests.post(endpoint, data=data, headers=headers)
+        if requests.post(endpoint, data=data, headers=headers).status_code == 200:
+            return True
+        return False
 
     @staticmethod
     def _get_outscale_endpoint(region: str, version: str, action: str):