Server IP : 85.214.239.14 / Your IP : 3.144.104.118 Web Server : Apache/2.4.62 (Debian) System : Linux h2886529.stratoserver.net 4.9.0 #1 SMP Tue Jan 9 19:45:01 MSK 2024 x86_64 User : www-data ( 33) PHP Version : 7.4.18 Disable Function : pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare, MySQL : OFF | cURL : OFF | WGET : ON | Perl : ON | Python : ON | Sudo : ON | Pkexec : OFF Directory : /proc/self/root/lib/python3/dist-packages/libcloud/compute/drivers/ |
Upload File : |
# 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. """ Softlayer driver """ import time try: from cryptography.hazmat.primitives.asymmetric import rsa from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import serialization crypto = True except ImportError: crypto = False from libcloud.common.softlayer import SoftLayerConnection, SoftLayerException from libcloud.compute.types import Provider, NodeState from libcloud.compute.base import NodeDriver, Node, NodeLocation, NodeSize, \ NodeImage, KeyPair from libcloud.compute.types import KeyPairDoesNotExistError DEFAULT_DOMAIN = 'example.com' DEFAULT_CPU_SIZE = 1 DEFAULT_RAM_SIZE = 2048 DEFAULT_DISK_SIZE = 100 DATACENTERS = { 'hou02': {'country': 'US'}, 'sea01': {'country': 'US', 'name': 'Seattle - West Coast U.S.'}, 'wdc01': {'country': 'US', 'name': 'Washington, DC - East Coast U.S.'}, 'dal01': {'country': 'US'}, 'dal02': {'country': 'US'}, 'dal04': {'country': 'US'}, 'dal05': {'country': 'US', 'name': 'Dallas - Central U.S.'}, 'dal06': {'country': 'US'}, 'dal07': {'country': 'US'}, 'sjc01': {'country': 'US', 'name': 'San Jose - West Coast U.S.'}, 'sng01': {'country': 'SG', 'name': 'Singapore - Southeast Asia'}, 'ams01': {'country': 'NL', 'name': 'Amsterdam - Western Europe'}, 'tok02': {'country': 'JP', 'name': 'Tokyo - Japan'}, } NODE_STATE_MAP = { 'RUNNING': NodeState.RUNNING, 'HALTED': NodeState.UNKNOWN, 'PAUSED': NodeState.UNKNOWN, 'INITIATING': NodeState.PENDING } SL_BASE_TEMPLATES = [ { 'name': '1 CPU, 1GB ram, 25GB', 'ram': 1024, 'disk': 25, 'cpus': 1, }, { 'name': '1 CPU, 1GB ram, 100GB', 'ram': 1024, 'disk': 100, 'cpus': 1, }, { 'name': '1 CPU, 2GB ram, 100GB', 'ram': 2 * 1024, 'disk': 100, 'cpus': 1, }, { 'name': '1 CPU, 4GB ram, 100GB', 'ram': 4 * 1024, 'disk': 100, 'cpus': 1, }, { 'name': '2 CPU, 2GB ram, 100GB', 'ram': 2 * 1024, 'disk': 100, 'cpus': 2, }, { 'name': '2 CPU, 4GB ram, 100GB', 'ram': 4 * 1024, 'disk': 100, 'cpus': 2, }, { 'name': '2 CPU, 8GB ram, 100GB', 'ram': 8 * 1024, 'disk': 100, 'cpus': 2, }, { 'name': '4 CPU, 4GB ram, 100GB', 'ram': 4 * 1024, 'disk': 100, 'cpus': 4, }, { 'name': '4 CPU, 8GB ram, 100GB', 'ram': 8 * 1024, 'disk': 100, 'cpus': 4, }, { 'name': '6 CPU, 4GB ram, 100GB', 'ram': 4 * 1024, 'disk': 100, 'cpus': 6, }, { 'name': '6 CPU, 8GB ram, 100GB', 'ram': 8 * 1024, 'disk': 100, 'cpus': 6, }, { 'name': '8 CPU, 8GB ram, 100GB', 'ram': 8 * 1024, 'disk': 100, 'cpus': 8, }, { 'name': '8 CPU, 16GB ram, 100GB', 'ram': 16 * 1024, 'disk': 100, 'cpus': 8, }] SL_TEMPLATES = {} for i, template in enumerate(SL_BASE_TEMPLATES): # Add local disk templates local = template.copy() local['local_disk'] = True SL_TEMPLATES[i] = local class SoftLayerNodeDriver(NodeDriver): """ SoftLayer node driver Extra node attributes: - password: root password - hourlyRecurringFee: hourly price (if applicable) - recurringFee : flat rate (if applicable) - recurringMonths : The number of months in which the recurringFee will be incurred. """ connectionCls = SoftLayerConnection name = 'SoftLayer' website = 'http://www.softlayer.com/' type = Provider.SOFTLAYER features = {'create_node': ['generates_password', 'ssh_key']} api_name = 'softlayer' def _to_node(self, host): try: password = \ host['operatingSystem']['passwords'][0]['password'] except (IndexError, KeyError): password = None hourlyRecurringFee = host.get('billingItem', {}).get( 'hourlyRecurringFee', 0) recurringFee = host.get('billingItem', {}).get('recurringFee', 0) recurringMonths = host.get('billingItem', {}).get('recurringMonths', 0) createDate = host.get('createDate', None) # When machine is launching it gets state halted # we change this to pending state = NODE_STATE_MAP.get(host['powerState']['keyName'], NodeState.UNKNOWN) if not password and state == NodeState.UNKNOWN: state = NODE_STATE_MAP['INITIATING'] public_ips = [] private_ips = [] if 'primaryIpAddress' in host: public_ips.append(host['primaryIpAddress']) if 'primaryBackendIpAddress' in host: private_ips.append(host['primaryBackendIpAddress']) image = host.get('operatingSystem', {}).get('softwareLicense', {}) \ .get('softwareDescription', {}) \ .get('longDescription', None) return Node( id=host['id'], name=host['fullyQualifiedDomainName'], state=state, public_ips=public_ips, private_ips=private_ips, driver=self, extra={ 'hostname': host['hostname'], 'fullyQualifiedDomainName': host['fullyQualifiedDomainName'], 'password': password, 'maxCpu': host.get('maxCpu', None), 'datacenter': host.get('datacenter', {}).get('longName', None), 'maxMemory': host.get('maxMemory', None), 'image': image, 'hourlyRecurringFee': hourlyRecurringFee, 'recurringFee': recurringFee, 'recurringMonths': recurringMonths, 'created': createDate, } ) def destroy_node(self, node): self.connection.request( 'SoftLayer_Virtual_Guest', 'deleteObject', id=node.id ) return True def reboot_node(self, node): self.connection.request( 'SoftLayer_Virtual_Guest', 'rebootSoft', id=node.id ) return True def start_node(self, node): self.connection.request( 'SoftLayer_Virtual_Guest', 'powerOn', id=node.id ) return True def stop_node(self, node): self.connection.request( 'SoftLayer_Virtual_Guest', 'powerOff', id=node.id ) return True def ex_start_node(self, node): # NOTE: This method is here for backward compatibility reasons after # this method was promoted to be part of the standard compute API in # Libcloud v2.7.0 return self.start_node(node=node) def ex_stop_node(self, node): # NOTE: This method is here for backward compatibility reasons after # this method was promoted to be part of the standard compute API in # Libcloud v2.7.0 return self.stop_node(node=node) def _get_order_information(self, node_id, timeout=1200, check_interval=5): mask = { 'billingItem': '', 'powerState': '', 'operatingSystem': {'passwords': ''}, 'provisionDate': '', } for i in range(0, timeout, check_interval): res = self.connection.request( 'SoftLayer_Virtual_Guest', 'getObject', id=node_id, object_mask=mask ).object if res.get('provisionDate', None): return res time.sleep(check_interval) raise SoftLayerException('Timeout on getting node details') def create_node(self, name, size=None, image=None, location=None, ex_domain=None, ex_cpus=None, ex_disk=None, ex_ram=None, ex_bandwidth=None, ex_local_disk=None, ex_datacenter=None, ex_os=None, ex_keyname=None, ex_hourly=True): """Create a new SoftLayer node @inherits: :class:`NodeDriver.create_node` :keyword ex_domain: e.g. libcloud.org :type ex_domain: ``str`` :keyword ex_cpus: e.g. 2 :type ex_cpus: ``int`` :keyword ex_disk: e.g. 100 :type ex_disk: ``int`` :keyword ex_ram: e.g. 2048 :type ex_ram: ``int`` :keyword ex_bandwidth: e.g. 100 :type ex_bandwidth: ``int`` :keyword ex_local_disk: e.g. True :type ex_local_disk: ``bool`` :keyword ex_datacenter: e.g. Dal05 :type ex_datacenter: ``str`` :keyword ex_os: e.g. UBUNTU_LATEST :type ex_os: ``str`` :keyword ex_keyname: The name of the key pair :type ex_keyname: ``str`` """ os = 'DEBIAN_LATEST' if ex_os: os = ex_os elif image: os = image.id size = size or NodeSize(id=123, name='Custom', ram=None, disk=None, bandwidth=None, price=None, driver=self.connection.driver) ex_size_data = SL_TEMPLATES.get(int(size.id)) or {} # plan keys are ints cpu_count = ex_cpus or ex_size_data.get('cpus') or \ DEFAULT_CPU_SIZE ram = ex_ram or ex_size_data.get('ram') or \ DEFAULT_RAM_SIZE bandwidth = ex_bandwidth or size.bandwidth or 10 hourly = ex_hourly local_disk = 'true' if ex_size_data.get('local_disk') is False: local_disk = 'false' if ex_local_disk is False: local_disk = 'false' disk_size = DEFAULT_DISK_SIZE if size.disk: disk_size = size.disk if ex_disk: disk_size = ex_disk datacenter = '' if ex_datacenter: datacenter = ex_datacenter elif location: datacenter = location.id domain = ex_domain if domain is None: if name.find('.') != -1: domain = name[name.find('.') + 1:] if domain is None: # TODO: domain is a required argument for the Sofylayer API, but it # it shouldn't be. domain = DEFAULT_DOMAIN newCCI = { 'hostname': name, 'domain': domain, 'startCpus': cpu_count, 'maxMemory': ram, 'networkComponents': [{'maxSpeed': bandwidth}], 'hourlyBillingFlag': hourly, 'operatingSystemReferenceCode': os, 'localDiskFlag': local_disk, 'blockDevices': [ { 'device': '0', 'diskImage': { 'capacity': disk_size, } } ] } if datacenter: newCCI['datacenter'] = {'name': datacenter} if ex_keyname: newCCI['sshKeys'] = [ { 'id': self._key_name_to_id(ex_keyname) } ] res = self.connection.request( 'SoftLayer_Virtual_Guest', 'createObject', newCCI ).object node_id = res['id'] raw_node = self._get_order_information(node_id) return self._to_node(raw_node) def list_key_pairs(self): result = self.connection.request( 'SoftLayer_Account', 'getSshKeys' ).object elems = [x for x in result] key_pairs = self._to_key_pairs(elems=elems) return key_pairs def get_key_pair(self, name): key_id = self._key_name_to_id(name=name) result = self.connection.request( 'SoftLayer_Security_Ssh_Key', 'getObject', id=key_id ).object return self._to_key_pair(result) # TODO: Check this with the libcloud guys, # can we create new dependencies? def create_key_pair(self, name, ex_size=4096): if crypto is False: raise NotImplementedError('create_key_pair needs' 'the cryptography library') key = rsa.generate_private_key( public_exponent=65537, key_size=4096, backend=default_backend() ) public_key = key.public_key().public_bytes( encoding=serialization.Encoding.OpenSSH, format=serialization.PublicFormat.OpenSSH ) new_key = { 'key': public_key, 'label': name, 'notes': '', } result = self.connection.request( 'SoftLayer_Security_Ssh_Key', 'createObject', new_key ).object result['private'] = key.private_bytes( encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.TraditionalOpenSSL, encryption_algorithm=serialization.NoEncryption() ) return self._to_key_pair(result) def import_key_pair_from_string(self, name, key_material): new_key = { 'key': key_material, 'label': name, 'notes': '', } result = self.connection.request( 'SoftLayer_Security_Ssh_Key', 'createObject', new_key ).object key_pair = self._to_key_pair(result) return key_pair def delete_key_pair(self, key_pair): key = self._key_name_to_id(key_pair) result = self.connection.request( 'SoftLayer_Security_Ssh_Key', 'deleteObject', id=key ).object return result def _to_image(self, img): return NodeImage( id=img['template']['operatingSystemReferenceCode'], name=img['itemPrice']['item']['description'], driver=self.connection.driver ) def list_images(self, location=None): result = self.connection.request( 'SoftLayer_Virtual_Guest', 'getCreateObjectOptions' ).object return [self._to_image(i) for i in result['operatingSystems']] def get_image(self, image_id): """ Gets an image based on an image_id. :param image_id: Image identifier :type image_id: ``str`` :return: A NodeImage object :rtype: :class:`NodeImage` """ images = self.list_images() images = [image for image in images if image.id == image_id] if len(images) < 1: raise SoftLayerException('could not find the image with id %s' % image_id) image = images[0] return image def _to_size(self, id, size): return NodeSize( id=id, name=size['name'], ram=size['ram'], disk=size['disk'], bandwidth=size.get('bandwidth'), price=self._get_size_price(str(id)), driver=self.connection.driver, ) def list_sizes(self, location=None): return [self._to_size(id, s) for id, s in SL_TEMPLATES.items()] def _to_loc(self, loc): country = 'UNKNOWN' loc_id = loc['template']['datacenter']['name'] name = loc_id if loc_id in DATACENTERS: country = DATACENTERS[loc_id]['country'] name = DATACENTERS[loc_id].get('name', loc_id) return NodeLocation(id=loc_id, name=name, country=country, driver=self) def list_locations(self): res = self.connection.request( 'SoftLayer_Virtual_Guest', 'getCreateObjectOptions' ).object return [self._to_loc(loc) for loc in res['datacenters']] def list_nodes(self): mask = { 'virtualGuests': { 'powerState': '', 'hostname': '', 'maxMemory': '', 'datacenter': '', 'operatingSystem': {'passwords': ''}, 'billingItem': '', }, } res = self.connection.request( 'SoftLayer_Account', 'getVirtualGuests', object_mask=mask ).object return [self._to_node(h) for h in res] def _to_key_pairs(self, elems): key_pairs = [self._to_key_pair(elem=elem) for elem in elems] return key_pairs def _to_key_pair(self, elem): key_pair = KeyPair(name=elem['label'], public_key=elem['key'], fingerprint=elem['fingerprint'], private_key=elem.get('private', None), driver=self, extra={'id': elem['id']}) return key_pair def _key_name_to_id(self, name): result = self.connection.request( 'SoftLayer_Account', 'getSshKeys' ).object key_id = [x for x in result if x['label'] == name] if len(key_id) == 0: raise KeyPairDoesNotExistError(name, self) else: return int(key_id[0]['id'])