%PDF- %PDF-
Direktori : /proc/self/root/lib/python2.7/site-packages/salt/cloud/clouds/ |
Current File : //proc/self/root/lib/python2.7/site-packages/salt/cloud/clouds/softlayer.py |
# -*- coding: utf-8 -*- ''' SoftLayer Cloud Module ====================== The SoftLayer cloud module is used to control access to the SoftLayer VPS system. Use of this module only requires the ``apikey`` parameter. Set up the cloud configuration at: ``/etc/salt/cloud.providers`` or ``/etc/salt/cloud.providers.d/softlayer.conf``: .. code-block:: yaml my-softlayer-config: # SoftLayer account api key user: MYLOGIN apikey: JVkbSJDGHSDKUKSDJfhsdklfjgsjdkflhjlsdfffhgdgjkenrtuinv driver: softlayer The SoftLayer Python Library needs to be installed in order to use the SoftLayer salt.cloud modules. See: https://pypi.python.org/pypi/SoftLayer :depends: softlayer ''' # Import python libs from __future__ import absolute_import, print_function, unicode_literals import logging import time # Import salt cloud libs import salt.utils.cloud import salt.config as config from salt.exceptions import SaltCloudSystemExit # Import 3rd-party libs from salt.ext import six # Attempt to import softlayer lib try: import SoftLayer HAS_SLLIBS = True except ImportError: HAS_SLLIBS = False # Get logging started log = logging.getLogger(__name__) __virtualname__ = 'softlayer' # Only load in this module if the SoftLayer configurations are in place def __virtual__(): ''' Check for SoftLayer configurations. ''' if get_configured_provider() is False: return False if get_dependencies() is False: return False return __virtualname__ def get_configured_provider(): ''' Return the first configured instance. ''' return config.is_provider_configured( __opts__, __active_provider_name__ or __virtualname__, ('apikey',) ) def get_dependencies(): ''' Warn if dependencies aren't met. ''' return config.check_driver_dependencies( __virtualname__, {'softlayer': HAS_SLLIBS} ) def script(vm_): ''' Return the script deployment object ''' deploy_script = salt.utils.cloud.os_script( config.get_cloud_config_value('script', vm_, __opts__), vm_, __opts__, salt.utils.cloud.salt_config_to_yaml( salt.utils.cloud.minion_config(__opts__, vm_) ) ) return deploy_script def get_conn(service='SoftLayer_Virtual_Guest'): ''' Return a conn object for the passed VM data ''' client = SoftLayer.Client( username=config.get_cloud_config_value( 'user', get_configured_provider(), __opts__, search_global=False ), api_key=config.get_cloud_config_value( 'apikey', get_configured_provider(), __opts__, search_global=False ), ) return client[service] def avail_locations(call=None): ''' List all available locations ''' if call == 'action': raise SaltCloudSystemExit( 'The avail_locations function must be called with ' '-f or --function, or with the --list-locations option' ) ret = {} conn = get_conn() response = conn.getCreateObjectOptions() #return response for datacenter in response['datacenters']: #return data center ret[datacenter['template']['datacenter']['name']] = { 'name': datacenter['template']['datacenter']['name'], } return ret def avail_sizes(call=None): ''' Return a dict of all available VM sizes on the cloud provider with relevant data. This data is provided in three dicts. ''' if call == 'action': raise SaltCloudSystemExit( 'The avail_sizes function must be called with ' '-f or --function, or with the --list-sizes option' ) ret = { 'block devices': {}, 'memory': {}, 'processors': {}, } conn = get_conn() response = conn.getCreateObjectOptions() for device in response['blockDevices']: #return device['template']['blockDevices'] ret['block devices'][device['itemPrice']['item']['description']] = { 'name': device['itemPrice']['item']['description'], 'capacity': device['template']['blockDevices'][0]['diskImage']['capacity'], } for memory in response['memory']: ret['memory'][memory['itemPrice']['item']['description']] = { 'name': memory['itemPrice']['item']['description'], 'maxMemory': memory['template']['maxMemory'], } for processors in response['processors']: ret['processors'][processors['itemPrice']['item']['description']] = { 'name': processors['itemPrice']['item']['description'], 'start cpus': processors['template']['startCpus'], } return ret def avail_images(call=None): ''' Return a dict of all available VM images on the cloud provider. ''' if call == 'action': raise SaltCloudSystemExit( 'The avail_images function must be called with ' '-f or --function, or with the --list-images option' ) ret = {} conn = get_conn() response = conn.getCreateObjectOptions() for image in response['operatingSystems']: ret[image['itemPrice']['item']['description']] = { 'name': image['itemPrice']['item']['description'], 'template': image['template']['operatingSystemReferenceCode'], } return ret def list_custom_images(call=None): ''' Return a dict of all custom VM images on the cloud provider. ''' if call != 'function': raise SaltCloudSystemExit( 'The list_vlans function must be called with -f or --function.' ) ret = {} conn = get_conn('SoftLayer_Account') response = conn.getBlockDeviceTemplateGroups() for image in response: if 'globalIdentifier' not in image: continue ret[image['name']] = { 'id': image['id'], 'name': image['name'], 'globalIdentifier': image['globalIdentifier'], } if 'note' in image: ret[image['name']]['note'] = image['note'] return ret def get_location(vm_=None): ''' Return the location to use, in this order: - CLI parameter - VM parameter - Cloud profile setting ''' return __opts__.get( 'location', config.get_cloud_config_value( 'location', vm_ or get_configured_provider(), __opts__, #default=DEFAULT_LOCATION, search_global=False ) ) def create(vm_): ''' Create a single VM from a data dict ''' try: # Check for required profile parameters before sending any API calls. if vm_['profile'] and config.is_profile_configured(__opts__, __active_provider_name__ or 'softlayer', vm_['profile'], vm_=vm_) is False: return False except AttributeError: pass name = vm_['name'] hostname = name domain = config.get_cloud_config_value( 'domain', vm_, __opts__, default=None ) if domain is None: SaltCloudSystemExit( 'A domain name is required for the SoftLayer driver.' ) if vm_.get('use_fqdn'): name = '.'.join([name, domain]) vm_['name'] = name __utils__['cloud.fire_event']( 'event', 'starting create', 'salt/cloud/{0}/creating'.format(name), args=__utils__['cloud.filter_event']('creating', vm_, ['name', 'profile', 'provider', 'driver']), sock_dir=__opts__['sock_dir'], transport=__opts__['transport'] ) log.info('Creating Cloud VM %s', name) conn = get_conn() kwargs = { 'hostname': hostname, 'domain': domain, 'startCpus': vm_['cpu_number'], 'maxMemory': vm_['ram'], 'hourlyBillingFlag': vm_['hourly_billing'], } local_disk_flag = config.get_cloud_config_value( 'local_disk', vm_, __opts__, default=False ) kwargs['localDiskFlag'] = local_disk_flag if 'image' in vm_: kwargs['operatingSystemReferenceCode'] = vm_['image'] kwargs['blockDevices'] = [] disks = vm_['disk_size'] if isinstance(disks, int): disks = [six.text_type(disks)] elif isinstance(disks, six.string_types): disks = [size.strip() for size in disks.split(',')] count = 0 for disk in disks: # device number '1' is reserved for the SWAP disk if count == 1: count += 1 block_device = {'device': six.text_type(count), 'diskImage': {'capacity': six.text_type(disk)}} kwargs['blockDevices'].append(block_device) count += 1 # Upper bound must be 5 as we're skipping '1' for the SWAP disk ID if count > 5: log.warning('More that 5 disks were specified for %s .' 'The first 5 disks will be applied to the VM, ' 'but the remaining disks will be ignored.\n' 'Please adjust your cloud configuration to only ' 'specify a maximum of 5 disks.', name) break elif 'global_identifier' in vm_: kwargs['blockDeviceTemplateGroup'] = { 'globalIdentifier': vm_['global_identifier'] } location = get_location(vm_) if location: kwargs['datacenter'] = {'name': location} private_vlan = config.get_cloud_config_value( 'private_vlan', vm_, __opts__, default=False ) if private_vlan: kwargs['primaryBackendNetworkComponent'] = { 'networkVlan': { 'id': private_vlan, } } private_network = config.get_cloud_config_value( 'private_network', vm_, __opts__, default=False ) if bool(private_network) is True: kwargs['privateNetworkOnlyFlag'] = 'True' public_vlan = config.get_cloud_config_value( 'public_vlan', vm_, __opts__, default=False ) if public_vlan: kwargs['primaryNetworkComponent'] = { 'networkVlan': { 'id': public_vlan, } } public_security_groups = config.get_cloud_config_value( 'public_security_groups', vm_, __opts__, default=False ) if public_security_groups: secgroups = [{'securityGroup': {'id': int(sg)}} for sg in public_security_groups] pnc = kwargs.get('primaryNetworkComponent', {}) pnc['securityGroupBindings'] = secgroups kwargs.update({'primaryNetworkComponent': pnc}) private_security_groups = config.get_cloud_config_value( 'private_security_groups', vm_, __opts__, default=False ) if private_security_groups: secgroups = [{'securityGroup': {'id': int(sg)}} for sg in private_security_groups] pbnc = kwargs.get('primaryBackendNetworkComponent', {}) pbnc['securityGroupBindings'] = secgroups kwargs.update({'primaryBackendNetworkComponent': pbnc}) max_net_speed = config.get_cloud_config_value( 'max_net_speed', vm_, __opts__, default=10 ) if max_net_speed: kwargs['networkComponents'] = [{ 'maxSpeed': int(max_net_speed) }] post_uri = config.get_cloud_config_value( 'post_uri', vm_, __opts__, default=None ) if post_uri: kwargs['postInstallScriptUri'] = post_uri dedicated_host_id = config.get_cloud_config_value( 'dedicated_host_id', vm_, __opts__, default=None ) if dedicated_host_id: kwargs['dedicatedHost'] = {'id': dedicated_host_id} __utils__['cloud.fire_event']( 'event', 'requesting instance', 'salt/cloud/{0}/requesting'.format(name), args={ 'kwargs': __utils__['cloud.filter_event']('requesting', kwargs, list(kwargs)), }, sock_dir=__opts__['sock_dir'], transport=__opts__['transport'] ) try: response = conn.createObject(kwargs) except Exception as exc: log.error( 'Error creating %s on SoftLayer\n\n' 'The following exception was thrown when trying to ' 'run the initial deployment: \n%s', name, exc, # Show the traceback if the debug logging level is enabled exc_info_on_loglevel=logging.DEBUG ) return False ip_type = 'primaryIpAddress' private_ssh = config.get_cloud_config_value( 'private_ssh', vm_, __opts__, default=False ) private_wds = config.get_cloud_config_value( 'private_windows', vm_, __opts__, default=False ) if private_ssh or private_wds or public_vlan is None: ip_type = 'primaryBackendIpAddress' def wait_for_ip(): ''' Wait for the IP address to become available ''' nodes = list_nodes_full() if ip_type in nodes[hostname]: return nodes[hostname][ip_type] time.sleep(1) return False ip_address = salt.utils.cloud.wait_for_fun( wait_for_ip, timeout=config.get_cloud_config_value( 'wait_for_fun_timeout', vm_, __opts__, default=15 * 60), ) if config.get_cloud_config_value('deploy', vm_, __opts__) is not True: return show_instance(hostname, call='action') SSH_PORT = 22 WINDOWS_DS_PORT = 445 managing_port = SSH_PORT if config.get_cloud_config_value('windows', vm_, __opts__) or \ config.get_cloud_config_value('win_installer', vm_, __opts__): managing_port = WINDOWS_DS_PORT ssh_connect_timeout = config.get_cloud_config_value( 'ssh_connect_timeout', vm_, __opts__, 15 * 60 ) connect_timeout = config.get_cloud_config_value( 'connect_timeout', vm_, __opts__, ssh_connect_timeout ) if not salt.utils.cloud.wait_for_port(ip_address, port=managing_port, timeout=connect_timeout): raise SaltCloudSystemExit( 'Failed to authenticate against remote ssh' ) pass_conn = get_conn(service='SoftLayer_Account') mask = { 'virtualGuests': { 'powerState': '', 'operatingSystem': { 'passwords': '' }, }, } def get_credentials(): ''' Wait for the password to become available ''' node_info = pass_conn.getVirtualGuests(id=response['id'], mask=mask) for node in node_info: if node['id'] == response['id'] and \ 'passwords' in node['operatingSystem'] and \ node['operatingSystem']['passwords']: return node['operatingSystem']['passwords'][0]['username'], node['operatingSystem']['passwords'][0]['password'] time.sleep(5) return False username, passwd = salt.utils.cloud.wait_for_fun( # pylint: disable=W0633 get_credentials, timeout=config.get_cloud_config_value( 'wait_for_fun_timeout', vm_, __opts__, default=15 * 60), ) response['username'] = username response['password'] = passwd response['public_ip'] = ip_address ssh_username = config.get_cloud_config_value( 'ssh_username', vm_, __opts__, default=username ) vm_['ssh_host'] = ip_address vm_['password'] = passwd ret = __utils__['cloud.bootstrap'](vm_, __opts__) ret.update(response) __utils__['cloud.fire_event']( 'event', 'created instance', 'salt/cloud/{0}/created'.format(name), args=__utils__['cloud.filter_event']('created', vm_, ['name', 'profile', 'provider', 'driver']), sock_dir=__opts__['sock_dir'], transport=__opts__['transport'] ) return ret def list_nodes_full(mask='mask[id]', call=None): ''' Return a list of the VMs that are on the provider ''' if call == 'action': raise SaltCloudSystemExit( 'The list_nodes_full function must be called with -f or --function.' ) ret = {} conn = get_conn(service='SoftLayer_Account') response = conn.getVirtualGuests() for node_id in response: hostname = node_id['hostname'] ret[hostname] = node_id __utils__['cloud.cache_node_list'](ret, __active_provider_name__.split(':')[0], __opts__) return ret def list_nodes(call=None): ''' Return a list of the VMs that are on the provider ''' if call == 'action': raise SaltCloudSystemExit( 'The list_nodes function must be called with -f or --function.' ) ret = {} nodes = list_nodes_full() if 'error' in nodes: raise SaltCloudSystemExit( 'An error occurred while listing nodes: {0}'.format( nodes['error']['Errors']['Error']['Message'] ) ) for node in nodes: ret[node] = { 'id': nodes[node]['hostname'], 'ram': nodes[node]['maxMemory'], 'cpus': nodes[node]['maxCpu'], } if 'primaryIpAddress' in nodes[node]: ret[node]['public_ips'] = nodes[node]['primaryIpAddress'] if 'primaryBackendIpAddress' in nodes[node]: ret[node]['private_ips'] = nodes[node]['primaryBackendIpAddress'] if 'status' in nodes[node]: ret[node]['state'] = six.text_type(nodes[node]['status']['name']) return ret def list_nodes_select(call=None): ''' Return a list of the VMs that are on the provider, with select fields ''' return salt.utils.cloud.list_nodes_select( list_nodes_full(), __opts__['query.selection'], call, ) def show_instance(name, call=None): ''' Show the details from SoftLayer concerning a guest ''' if call != 'action': raise SaltCloudSystemExit( 'The show_instance action must be called with -a or --action.' ) nodes = list_nodes_full() __utils__['cloud.cache_node'](nodes[name], __active_provider_name__, __opts__) return nodes[name] def destroy(name, call=None): ''' Destroy a node. CLI Example: .. code-block:: bash salt-cloud --destroy mymachine ''' if call == 'function': raise SaltCloudSystemExit( 'The destroy action must be called with -d, --destroy, ' '-a or --action.' ) __utils__['cloud.fire_event']( 'event', 'destroying instance', 'salt/cloud/{0}/destroying'.format(name), args={'name': name}, sock_dir=__opts__['sock_dir'], transport=__opts__['transport'] ) node = show_instance(name, call='action') conn = get_conn() response = conn.deleteObject(id=node['id']) __utils__['cloud.fire_event']( 'event', 'destroyed instance', 'salt/cloud/{0}/destroyed'.format(name), args={'name': name}, sock_dir=__opts__['sock_dir'], transport=__opts__['transport'] ) if __opts__.get('update_cachedir', False) is True: __utils__['cloud.delete_minion_cachedir'](name, __active_provider_name__.split(':')[0], __opts__) return response def list_vlans(call=None): ''' List all VLANs associated with the account ''' if call != 'function': raise SaltCloudSystemExit( 'The list_vlans function must be called with -f or --function.' ) conn = get_conn(service='SoftLayer_Account') return conn.getNetworkVlans()