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: [email protected]
