def is_profile_configured(vm_): try: # Check for required profile parameters before sending any API calls. if vm_['profile'] and config.is_profile_configured(__opts__, __active_provider_name__ or __virtualname__, vm_['profile'], vm_=vm_) is False: return False alias, driver = __active_provider_name__.split(':') profile_data = __opts__['providers'][alias][driver]['profiles'][vm_['profile']] if profile_data.get('storage_size') or profile_data.get('storage_tier'): required_keys = ['storage_size', 'storage_tier'] for key in required_keys: if profile_data.get(key) is None: log.error( 'both storage_size and storage_tier required for profile {profile}. ' 'Please check your profile configuration'.format(profile=vm_['profile']) ) return False locations = avail_locations() for location in locations.values(): if location['code'] == profile_data['location']: if 'storage' not in location['features']: log.error( 'Choosen location {location} for profile {profile} does not support storage feature. ' 'Please check your profile configuration'.format( location=location['code'], profile=vm_['profile'] ) ) return False if profile_data.get('storage_snapshot_count') or profile_data.get('storage_snapshot_frequency'): required_keys = ['storage_size', 'storage_tier'] for key in required_keys: if profile_data.get(key) is None: log.error( 'both storage_snapshot_count and storage_snapshot_frequency required for profile {profile}. ' 'Please check your profile configuration'.format(profile=vm_['profile']) ) return False except AttributeError: pass return True
def test_no_clonefrom_just_image(self): ''' Tests that the profile is configured correctly when deploying using an image ''' profile_additions = { 'image': 'some-image.iso' } provider_config = deepcopy(PROVIDER_CONFIG) profile = deepcopy(PROFILE) profile['base-gold'].update(profile_additions) provider_config_additions = { 'profiles': profile } provider_config['vcenter01']['vmware'].update(provider_config_additions) vm_ = {'profile': profile} with patch.dict(vmware.__opts__, {'providers': provider_config}, clean=True): self.assertEqual(config.is_profile_configured(vmware.__opts__, 'vcenter01:vmware', 'base-gold', vm_=vm_), True)
def create(vm_): ''' Create a single VM from a data dict CLI Example: .. code-block:: bash salt-cloud -p proxmox-ubuntu vmhostname ''' try: # Check for required profile parameters before sending any API calls. if vm_['profile'] and config.is_profile_configured( __opts__, __active_provider_name__ or 'proxmox', vm_['profile'], vm_=vm_) is False: return False except AttributeError: pass ret = {} __utils__['cloud.fire_event']( 'event', 'starting create', 'salt/cloud/{0}/creating'.format(vm_['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', vm_['name']) if 'use_dns' in vm_ and 'ip_address' not in vm_: use_dns = vm_['use_dns'] if use_dns: from socket import gethostbyname, gaierror try: ip_address = gethostbyname(six.text_type(vm_['name'])) except gaierror: log.debug('Resolving of %s failed', vm_['name']) else: vm_['ip_address'] = six.text_type(ip_address) try: newid = _get_next_vmid() data = create_node(vm_, newid) except Exception as exc: log.error( 'Error creating %s on PROXMOX\n\n' 'The following exception was thrown when trying to ' 'run the initial deployment: \n%s', vm_['name'], exc, # Show the traceback if the debug logging level is enabled exc_info_on_loglevel=logging.DEBUG) return False ret['creation_data'] = data name = vm_['name'] # hostname which we know if 'clone' in vm_ and vm_['clone'] is True: vmid = newid else: vmid = data['vmid'] # vmid which we have received host = data['node'] # host which we have received nodeType = data['technology'] # VM tech (Qemu / OpenVZ) # Determine which IP to use in order of preference: if 'ip_address' in vm_: ip_address = six.text_type(vm_['ip_address']) elif 'public_ips' in data: ip_address = six.text_type(data['public_ips'][0]) # first IP elif 'private_ips' in data: ip_address = six.text_type(data['private_ips'][0]) # first IP else: raise SaltCloudExecutionFailure( "Could not determine an IP address to use") log.debug('Using IP address %s', ip_address) # wait until the vm has been created so we can start it if not wait_for_created(data['upid'], timeout=300): return { 'Error': 'Unable to create {0}, command timed out'.format(name) } if 'clone' in vm_ and vm_['clone'] is True and vm_['technology'] == 'qemu': # If we cloned a machine, see if we need to reconfigure any of the options such as net0, # ide2, etc. This enables us to have a different cloud-init ISO mounted for each VM that's # brought up # TODO: Support other settings here too as these are not the only ones that can be modified # after a clone operation log.info('Configuring cloned VM') # Modify the settings for the VM one at a time so we can see any problems with the values # as quickly as possible for setting_number in range(3): setting = 'ide{0}'.format(setting_number) if setting in vm_: postParams = {} postParams[setting] = vm_[setting] query('post', 'nodes/{0}/qemu/{1}/config'.format(vm_['host'], vmid), postParams) for setting_number in range(5): setting = 'sata{0}'.format(setting_number) if setting in vm_: postParams = {} postParams[setting] = vm_[setting] query('post', 'nodes/{0}/qemu/{1}/config'.format(vm_['host'], vmid), postParams) for setting_number in range(13): setting = 'scsi{0}'.format(setting_number) if setting in vm_: postParams = {} postParams[setting] = vm_[setting] query('post', 'nodes/{0}/qemu/{1}/config'.format(vm_['host'], vmid), postParams) # net strings are a list of comma seperated settings. We need to merge the settings so that # the setting in the profile only changes the settings it touches and the other settings # are left alone. An example of why this is necessary is because the MAC address is set # in here and generally you don't want to alter or have to know the MAC address of the new # instance, but you may want to set the VLAN bridge for example for setting_number in range(20): setting = 'net{0}'.format(setting_number) if setting in vm_: data = query( 'get', 'nodes/{0}/qemu/{1}/config'.format(vm_['host'], vmid)) # Generate a dictionary of settings from the existing string new_setting = {} if setting in data: new_setting.update(_stringlist_to_dictionary( data[setting])) # Merge the new settings (as a dictionary) into the existing dictionary to get the # new merged settings new_setting.update(_stringlist_to_dictionary(vm_[setting])) # Convert the dictionary back into a string list postParams = {setting: _dictionary_to_stringlist(new_setting)} query('post', 'nodes/{0}/qemu/{1}/config'.format(vm_['host'], vmid), postParams) # VM has been created. Starting.. if not start(name, vmid, call='action'): log.error('Node %s (%s) failed to start!', name, vmid) raise SaltCloudExecutionFailure # Wait until the VM has fully started log.debug('Waiting for state "running" for vm %s on %s', vmid, host) if not wait_for_state(vmid, 'running'): return {'Error': 'Unable to start {0}, command timed out'.format(name)} ssh_username = config.get_cloud_config_value('ssh_username', vm_, __opts__, default='root') ssh_password = config.get_cloud_config_value( 'password', vm_, __opts__, ) ret['ip_address'] = ip_address ret['username'] = ssh_username ret['password'] = ssh_password vm_['ssh_host'] = ip_address vm_['password'] = ssh_password ret = __utils__['cloud.bootstrap'](vm_, __opts__) # Report success! log.info('Created Cloud VM \'%s\'', vm_['name']) log.debug('\'%s\' VM creation details:\n%s', vm_['name'], pprint.pformat(data)) __utils__['cloud.fire_event']( 'event', 'created instance', 'salt/cloud/{0}/created'.format(vm_['name']), args=__utils__['cloud.filter_event']( 'created', vm_, ['name', 'profile', 'provider', 'driver']), sock_dir=__opts__['sock_dir'], ) return ret
def create(vm_): ''' Create a single instance from a data dict. CLI Examples: .. code-block:: bash salt-cloud -p qingcloud-ubuntu-c1m1 hostname1 salt-cloud -m /path/to/mymap.sls -P ''' try: # Check for required profile parameters before sending any API calls. if vm_['profile'] and config.is_profile_configured(__opts__, __active_provider_name__ or 'qingcloud', vm_['profile'], vm_=vm_) is False: return False except AttributeError: pass # Since using "provider: <provider-engine>" is deprecated, alias provider # to use driver: "driver: <provider-engine>" if 'provider' in vm_: vm_['driver'] = vm_.pop('provider') __utils__['cloud.fire_event']( 'event', 'starting create', 'salt/cloud/{0}/creating'.format(vm_['name']), args={ 'name': vm_['name'], 'profile': vm_['profile'], 'provider': vm_['driver'], }, sock_dir=__opts__['sock_dir'], transport=__opts__['transport'] ) log.info('Creating Cloud VM {0}'.format(vm_['name'])) # params params = { 'action': 'RunInstances', 'instance_name': vm_['name'], 'zone': _get_location(vm_), 'instance_type': _get_size(vm_), 'image_id': _get_image(vm_), 'vxnets.1': vm_['vxnets'], 'login_mode': vm_['login_mode'], 'login_keypair': vm_['login_keypair'], } __utils__['cloud.fire_event']( 'event', 'requesting instance', 'salt/cloud/{0}/requesting'.format(vm_['name']), args={'kwargs': params}, sock_dir=__opts__['sock_dir'], transport=__opts__['transport'] ) result = query(params) new_instance_id = result['instances'][0] try: data = salt.utils.cloud.wait_for_ip( _query_node_data, update_args=(new_instance_id,), timeout=config.get_cloud_config_value( 'wait_for_ip_timeout', vm_, __opts__, default=10 * 60 ), interval=config.get_cloud_config_value( 'wait_for_ip_interval', vm_, __opts__, default=10 ), ) except (SaltCloudExecutionTimeout, SaltCloudExecutionFailure) as exc: try: # It might be already up, let's destroy it! destroy(vm_['name']) except SaltCloudSystemExit: pass finally: raise SaltCloudSystemExit(str(exc)) private_ip = data['private_ips'][0] log.debug('VM {0} is now running'.format(private_ip)) vm_['ssh_host'] = private_ip # The instance is booted and accessible, let's Salt it! __utils__['cloud.bootstrap'](vm_, __opts__) log.info('Created Cloud VM \'{0[name]}\''.format(vm_)) log.debug( '\'{0[name]}\' VM creation details:\n{1}'.format( vm_, pprint.pformat(data) ) ) __utils__['cloud.fire_event']( 'event', 'created instance', 'salt/cloud/{0}/created'.format(vm_['name']), args={ 'name': vm_['name'], 'profile': vm_['profile'], 'provider': vm_['driver'], }, sock_dir=__opts__['sock_dir'], transport=__opts__['transport'] ) return data
def create(server_): ''' Create a single BareMetal server from a data dict. ''' try: # Check for required profile parameters before sending any API calls. if server_['profile'] and config.is_profile_configured(__opts__, __active_provider_name__ or 'scaleway', server_['profile']) is False: return False except AttributeError: pass # Since using "provider: <provider-engine>" is deprecated, alias provider # to use driver: "driver: <provider-engine>" if 'provider' in server_: server_['driver'] = server_.pop('provider') salt.utils.cloud.fire_event( 'event', 'starting create', 'salt/cloud/{0}/creating'.format(server_['name']), { 'name': server_['name'], 'profile': server_['profile'], 'provider': server_['driver'], }, transport=__opts__['transport'] ) log.info('Creating a BareMetal server {0}'.format(server_['name'])) access_key = config.get_cloud_config_value( 'access_key', get_configured_provider(), __opts__, search_global=False ) kwargs = { 'name': server_['name'], 'organization': access_key, 'image': get_image(server_), } salt.utils.cloud.fire_event( 'event', 'requesting instance', 'salt/cloud/{0}/requesting'.format(server_['name']), {'kwargs': kwargs}, transport=__opts__['transport'] ) try: ret = create_node(kwargs) except Exception as exc: log.error( 'Error creating {0} on Scaleway\n\n' 'The following exception was thrown when trying to ' 'run the initial deployment: {1}'.format( server_['name'], str(exc) ), # Show the traceback if the debug logging level is enabled exc_info_on_loglevel=logging.DEBUG ) return False def __query_node_data(server_name): ''' Called to check if the server has a public IP address. ''' data = show_instance(server_name, 'action') if data and data.get('public_ip'): return data return False try: data = salt.utils.cloud.wait_for_ip( __query_node_data, update_args=(server_['name'],), timeout=config.get_cloud_config_value( 'wait_for_ip_timeout', server_, __opts__, default=10 * 60), interval=config.get_cloud_config_value( 'wait_for_ip_interval', server_, __opts__, default=10), ) except (SaltCloudExecutionTimeout, SaltCloudExecutionFailure) as exc: try: # It might be already up, let's destroy it! destroy(server_['name']) except SaltCloudSystemExit: pass finally: raise SaltCloudSystemExit(str(exc)) server_['ssh_host'] = data['public_ip']['address'] server_['ssh_password'] = config.get_cloud_config_value( 'ssh_password', server_, __opts__ ) ret = salt.utils.cloud.bootstrap(server_, __opts__) ret.update(data) log.info('Created BareMetal server \'{0[name]}\''.format(server_)) log.debug( '\'{0[name]}\' BareMetal server creation details:\n{1}'.format( server_, pprint.pformat(data) ) ) salt.utils.cloud.fire_event( 'event', 'created instance', 'salt/cloud/{0}/created'.format(server_['name']), { 'name': server_['name'], 'profile': server_['profile'], 'provider': server_['driver'], }, transport=__opts__['transport'] ) return ret
def create(vm_): ''' Create a single VM from a data dict ''' try: # Check for required profile parameters before sending any API calls. if config.is_profile_configured(__opts__, __active_provider_name__ or 'cloudstack', vm_['profile']) is False: return False except AttributeError: pass salt.utils.cloud.fire_event( 'event', 'starting create', 'salt/cloud/{0}/creating'.format(vm_['name']), { 'name': vm_['name'], 'profile': vm_['profile'], 'provider': vm_['provider'], }, transport=__opts__['transport'] ) log.info('Creating Cloud VM {0}'.format(vm_['name'])) conn = get_conn() kwargs = { 'name': vm_['name'], 'image': get_image(conn, vm_), 'size': get_size(conn, vm_), 'location': get_location(conn, vm_), } if get_keypair(vm_) is not False: kwargs['ex_keyname'] = get_keypair(vm_) if get_networkid(vm_) is not False: kwargs['networkids'] = get_networkid(vm_) kwargs['networks'] = ( # The only attr that is used is 'id'. CloudStackNetwork(None, None, None, kwargs['networkids'], None, None), ) if get_project(conn, vm_) is not False: kwargs['project'] = get_project(conn, vm_) salt.utils.cloud.fire_event( 'event', 'requesting instance', 'salt/cloud/{0}/requesting'.format(vm_['name']), {'kwargs': {'name': kwargs['name'], 'image': kwargs['image'].name, 'size': kwargs['size'].name}}, transport=__opts__['transport'] ) displayname = cloudstack_displayname(vm_) if displayname: kwargs['ex_displayname'] = displayname else: kwargs['ex_displayname'] = kwargs['name'] volumes = {} ex_blockdevicemappings = block_device_mappings(vm_) if ex_blockdevicemappings: for ex_blockdevicemapping in ex_blockdevicemappings: if 'VirtualName' not in ex_blockdevicemapping: ex_blockdevicemapping['VirtualName'] = '{0}-{1}'.format(vm_['name'], len(volumes)) salt.utils.cloud.fire_event( 'event', 'requesting volume', 'salt/cloud/{0}/requesting'.format(ex_blockdevicemapping['VirtualName']), {'kwargs': {'name': ex_blockdevicemapping['VirtualName'], 'device': ex_blockdevicemapping['DeviceName'], 'size': ex_blockdevicemapping['VolumeSize']}}, ) try: volumes[ex_blockdevicemapping['DeviceName']] = conn.create_volume( ex_blockdevicemapping['VolumeSize'], ex_blockdevicemapping['VirtualName'] ) except Exception as exc: log.error( 'Error creating volume {0} on CLOUDSTACK\n\n' 'The following exception was thrown by libcloud when trying to ' 'requesting a volume: \n{1}'.format( ex_blockdevicemapping['VirtualName'], exc ), # Show the traceback if the debug logging level is enabled exc_info_on_loglevel=logging.DEBUG ) return False else: ex_blockdevicemapping = {} try: data = conn.create_node(**kwargs) except Exception as exc: log.error( 'Error creating {0} on CLOUDSTACK\n\n' 'The following exception was thrown by libcloud when trying to ' 'run the initial deployment: \n{1}'.format( vm_['name'], str(exc) ), # Show the traceback if the debug logging level is enabled exc_info_on_loglevel=logging.DEBUG ) return False for device_name in six.iterkeys(volumes): try: conn.attach_volume(data, volumes[device_name], device_name) except Exception as exc: log.error( 'Error attaching volume {0} on CLOUDSTACK\n\n' 'The following exception was thrown by libcloud when trying to ' 'attach a volume: \n{1}'.format( ex_blockdevicemapping.get('VirtualName', 'UNKNOWN'), exc ), # Show the traceback if the debug logging level is enabled exc_info=log.isEnabledFor(logging.DEBUG) ) return False ssh_username = config.get_cloud_config_value( 'ssh_username', vm_, __opts__, default='root' ) vm_['ssh_host'] = get_ip(data) vm_['password'] = data.extra['password'] vm_['key_filename'] = get_key() ret = salt.utils.cloud.bootstrap(vm_, __opts__) ret.update(data.__dict__) if 'password' in data.extra: del data.extra['password'] log.info('Created Cloud VM {0[name]!r}'.format(vm_)) log.debug( '{0[name]!r} VM creation details:\n{1}'.format( vm_, pprint.pformat(data.__dict__) ) ) salt.utils.cloud.fire_event( 'event', 'created instance', 'salt/cloud/{0}/created'.format(vm_['name']), { 'name': vm_['name'], 'profile': vm_['profile'], 'provider': vm_['provider'], }, transport=__opts__['transport'] ) return ret
def create(vm_info): """ Creates a virtual machine from the given VM information. This is what is used to request a virtual machine to be created by the cloud provider, wait for it to become available, and then (optionally) log in and install Salt on it. Fires: "starting create" : This event is tagged salt/cloud/<vm name>/creating. The payload contains the names of the VM, profile and provider. @param vm_info {dict} { name: <str> profile: <dict> provider: <provider> clone_from: <vm_name> } @return dict of resulting vm. !!!Passwords can and should be included!!! """ log.debug("Creating virtualbox with %s" % vm_info) try: # Check for required profile parameters before sending any API calls. # TODO should this be a call to config.is_provider_configured ? if vm_info['profile'] and config.is_profile_configured( __opts__, __active_provider_name__ or 'virtualbox', vm_info['profile'] ) is False: return False except AttributeError: pass # For now we can only clone if 'clone_from' not in vm_info: log.error('"clone_from" not in profile configuration!') return False salt.utils.cloud.fire_event( 'event', 'starting create', 'salt/cloud/{0}/creating'.format(vm_info['name']), { 'name': vm_info['name'], 'profile': vm_info['profile'], 'provider': vm_info['provider'], }, transport=__opts__['transport'] ) # TODO Calculate kwargs with parameters required by virtualbox # to create the virtual machine. request_kwargs = { 'name': vm_info['name'], 'clone_from': vm_info['clone_from'] } salt.utils.cloud.fire_event( 'event', 'requesting instance', 'salt/cloud/{0}/requesting'.format(vm_info['name']), request_kwargs, transport=__opts__['transport'] ) # TODO request a new VM! vm_result = vb_clone_vm(**request_kwargs) # TODO Prepare deployment of salt on the vm # Any private data, including passwords and keys (including public keys) # should be stripped from the deploy kwargs before the event is fired. deploy_kwargs = { } salt.utils.cloud.fire_event( 'event', 'deploying salt', 'salt/cloud/{0}/deploying'.format(vm_info['name']), deploy_kwargs, transport=__opts__['transport'] ) deploy_kwargs.update({ # TODO Add private data }) # TODO wait for target machine to become available # TODO deploy! # Do we have to call this? salt.utils.cloud.deploy_script(None, **deploy_kwargs) salt.utils.cloud.fire_event( 'event', 'created machine', 'salt/cloud/{0}/created'.format(vm_info['name']), vm_result, transport=__opts__['transport'] ) # Passwords should be included in this object!! return vm_result
def create(vm_): ''' Create a single Linode VM. ''' name = vm_['name'] try: # Check for required profile parameters before sending any API calls. if vm_['profile'] and config.is_profile_configured(__opts__, __active_provider_name__ or 'linode', vm_['profile'], vm_=vm_) is False: return False except AttributeError: pass # Since using "provider: <provider-engine>" is deprecated, alias provider # to use driver: "driver: <provider-engine>" if 'provider' in vm_: vm_['driver'] = vm_.pop('provider') if _validate_name(name) is False: return False __utils__['cloud.fire_event']( 'event', 'starting create', 'salt/cloud/{0}/creating'.format(name), args={ 'name': name, 'profile': vm_['profile'], 'provider': vm_['driver'], }, sock_dir=__opts__['sock_dir'], transport=__opts__['transport'] ) log.info('Creating Cloud VM {0}'.format(name)) data = {} kwargs = {'name': name} plan_id = None size = vm_.get('size') if size: kwargs['size'] = size plan_id = get_plan_id(kwargs={'label': size}) datacenter_id = None location = vm_.get('location') if location: try: datacenter_id = get_datacenter_id(location) except KeyError: # Linode's default datacenter is Dallas, but we still have to set one to # use the create function from Linode's API. Dallas's datacenter id is 2. datacenter_id = 2 clonefrom_name = vm_.get('clonefrom') cloning = True if clonefrom_name else False if cloning: linode_id = get_linode_id_from_name(clonefrom_name) clone_source = get_linode(kwargs={'linode_id': linode_id}) kwargs = { 'clonefrom': clonefrom_name, 'image': 'Clone of {0}'.format(clonefrom_name), } if size is None: size = clone_source['TOTALRAM'] kwargs['size'] = size plan_id = clone_source['PLANID'] if location is None: datacenter_id = clone_source['DATACENTERID'] # Create new Linode from cloned Linode try: result = clone(kwargs={'linode_id': linode_id, 'datacenter_id': datacenter_id, 'plan_id': plan_id}) except Exception as err: log.error( 'Error cloning \'{0}\' on Linode.\n\n' 'The following exception was thrown by Linode when trying to ' 'clone the specified machine:\n' '{1}'.format( clonefrom_name, err ), exc_info_on_loglevel=logging.DEBUG ) return False else: kwargs['image'] = vm_['image'] # Create Linode try: result = _query('linode', 'create', args={ 'PLANID': plan_id, 'DATACENTERID': datacenter_id }) except Exception as err: log.error( 'Error creating {0} on Linode\n\n' 'The following exception was thrown by Linode when trying to ' 'run the initial deployment:\n' '{1}'.format( name, err ), exc_info_on_loglevel=logging.DEBUG ) return False if 'ERRORARRAY' in result: for error_data in result['ERRORARRAY']: log.error('Error creating {0} on Linode\n\n' 'The Linode API returned the following: {1}\n'.format( name, error_data['ERRORMESSAGE'] ) ) return False __utils__['cloud.fire_event']( 'event', 'requesting instance', 'salt/cloud/{0}/requesting'.format(name), args={'kwargs': kwargs}, sock_dir=__opts__['sock_dir'], transport=__opts__['transport'] ) node_id = _clean_data(result)['LinodeID'] data['id'] = node_id if not _wait_for_status(node_id, status=(_get_status_id_by_name('brand_new'))): log.error( 'Error creating {0} on LINODE\n\n' 'while waiting for initial ready status'.format(name), exc_info_on_loglevel=logging.DEBUG ) # Update the Linode's Label to reflect the given VM name update_linode(node_id, update_args={'Label': name}) log.debug('Set name for {0} - was linode{1}.'.format(name, node_id)) # Add private IP address if requested private_ip_assignment = get_private_ip(vm_) if private_ip_assignment: create_private_ip(node_id) # Define which ssh_interface to use ssh_interface = _get_ssh_interface(vm_) # If ssh_interface is set to use private_ips, but assign_private_ip # wasn't set to True, let's help out and create a private ip. if ssh_interface == 'private_ips' and private_ip_assignment is False: create_private_ip(node_id) private_ip_assignment = True if cloning: config_id = get_config_id(kwargs={'linode_id': node_id})['config_id'] else: # Create disks and get ids log.debug('Creating disks for {0}'.format(name)) root_disk_id = create_disk_from_distro(vm_, node_id)['DiskID'] swap_disk_id = create_swap_disk(vm_, node_id)['DiskID'] # Create a ConfigID using disk ids config_id = create_config(kwargs={'name': name, 'linode_id': node_id, 'root_disk_id': root_disk_id, 'swap_disk_id': swap_disk_id})['ConfigID'] # Boot the Linode boot(kwargs={'linode_id': node_id, 'config_id': config_id, 'check_running': False}) node_data = get_linode(kwargs={'linode_id': node_id}) ips = get_ips(node_id) state = int(node_data['STATUS']) data['image'] = kwargs['image'] data['name'] = name data['size'] = size data['state'] = _get_status_descr_by_id(state) data['private_ips'] = ips['private_ips'] data['public_ips'] = ips['public_ips'] # Pass the correct IP address to the bootstrap ssh_host key if ssh_interface == 'private_ips': vm_['ssh_host'] = data['private_ips'][0] else: vm_['ssh_host'] = data['public_ips'][0] # If a password wasn't supplied in the profile or provider config, set it now. vm_['password'] = get_password(vm_) # Make public_ips and private_ips available to the bootstrap script. vm_['public_ips'] = ips['public_ips'] vm_['private_ips'] = ips['private_ips'] # Send event that the instance has booted. salt.utils.cloud.fire_event( 'event', 'waiting for ssh', 'salt/cloud/{0}/waiting_for_ssh'.format(name), {'ip_address': vm_['ssh_host']}, transport=__opts__['transport'] ) # Bootstrap! ret = __utils__['cloud.bootstrap'](vm_, __opts__) ret.update(data) log.info('Created Cloud VM \'{0}\''.format(name)) log.debug( '\'{0}\' VM creation details:\n{1}'.format( name, pprint.pformat(data) ) ) __utils__['cloud.fire_event']( 'event', 'created instance', 'salt/cloud/{0}/created'.format(name), args={ 'name': name, 'profile': vm_['profile'], 'provider': vm_['driver'], }, sock_dir=__opts__['sock_dir'], transport=__opts__['transport'] ) return ret
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 'profitbricks'), vm_['profile']) is False): return False except AttributeError: pass if 'image_alias' in vm_ and not version_compatible('4.0'): raise SaltCloudNotFound( "The 'image_alias' parameter requires the profitbricks " "SDK v4.0.0 or greater.") if 'image' not in vm_ and 'image_alias' not in vm_: log.error('The image or image_alias parameter is required.') signal_event(vm_, 'creating', 'starting create') data = None datacenter_id = get_datacenter_id() conn = get_conn() # Assemble list of network interfaces from the cloud profile config. nics = _get_nics(vm_) # Assemble list of volumes from the cloud profile config. volumes = [_get_system_volume(vm_)] if 'volumes' in vm_: volumes.extend(_get_data_volumes(vm_)) # Assembla the composite server object. server = _get_server(vm_, volumes, nics) signal_event(vm_, 'requesting', 'requesting instance') try: data = conn.create_server(datacenter_id=datacenter_id, server=server) log.info('Create server request ID: {0}'.format(data['requestId']), exc_info_on_loglevel=logging.DEBUG) _wait_for_completion(conn, data, get_wait_timeout(vm_), 'create_server') except PBError as exc: log.error( 'Error creating {0} on ProfitBricks\n\n' 'The following exception was thrown by the profitbricks library ' 'when trying to run the initial deployment: \n{1}:\n{2}'.format( vm_['name'], exc, exc.content), exc_info_on_loglevel=logging.DEBUG) return False except Exception as exc: # pylint: disable=W0703 log.error('Error creating {0} \n\n' 'Error: \n{1}'.format(vm_['name'], exc), exc_info_on_loglevel=logging.DEBUG) return False vm_['server_id'] = data['id'] def __query_node_data(vm_, data): ''' Query node data until node becomes available. ''' running = False try: data = show_instance(vm_['name'], 'action') if not data: return False log.debug( 'Loaded node data for {0}:\nname: {1}\nstate: {2}'.format( vm_['name'], pprint.pformat(data['name']), data['state'])) except Exception as err: log.error( 'Failed to get nodes list: {0}'.format(err), # Show the trackback if the debug logging level is enabled exc_info_on_loglevel=logging.DEBUG) # Trigger a failure in the wait for IP function return False running = data['state'] == 'RUNNING' if not running: # Still not running, trigger another iteration return if ssh_interface(vm_) == 'private_lan' and data['private_ips']: vm_['ssh_host'] = data['private_ips'][0] if ssh_interface(vm_) != 'private_lan' and data['public_ips']: vm_['ssh_host'] = data['public_ips'][0] return data try: data = salt.utils.cloud.wait_for_ip( __query_node_data, update_args=(vm_, data), timeout=config.get_cloud_config_value('wait_for_ip_timeout', vm_, __opts__, default=10 * 60), interval=config.get_cloud_config_value('wait_for_ip_interval', vm_, __opts__, default=10), ) except (SaltCloudExecutionTimeout, SaltCloudExecutionFailure) as exc: try: # It might be already up, let's destroy it! destroy(vm_['name']) except SaltCloudSystemExit: pass finally: raise SaltCloudSystemExit(str(exc.message)) log.debug('VM is now running') log.info('Created Cloud VM {0}'.format(vm_)) log.debug('{0} VM creation details:\n{1}'.format(vm_, pprint.pformat(data))) signal_event(vm_, 'created', 'created instance') if 'ssh_host' in vm_: vm_['key_filename'] = get_key_filename(vm_) ret = __utils__['cloud.bootstrap'](vm_, __opts__) ret.update(data) return ret else: raise SaltCloudSystemExit('A valid IP address was not found.')
def create(vm_): ''' Create a single VM from a data dict ''' # Check for required profile parameters before sending any API calls. if config.is_profile_configured(__opts__, __active_provider_name__ or 'aliyun', vm_['profile']) is False: return False # Since using "provider: <provider-engine>" is deprecated, alias provider # to use driver: "driver: <provider-engine>" if 'provider' in vm_: vm_['driver'] = vm_.pop('provider') salt.utils.cloud.fire_event('event', 'starting create', 'salt/cloud/{0}/creating'.format(vm_['name']), { 'name': vm_['name'], 'profile': vm_['profile'], 'provider': vm_['driver'], }, transport=__opts__['transport']) log.info('Creating Cloud VM {0}'.format(vm_['name'])) kwargs = { 'name': vm_['name'], 'size_id': get_size(vm_), 'image_id': get_image(vm_), 'region_id': __get_location(vm_), 'securitygroup_id': get_securitygroup(vm_), } salt.utils.cloud.fire_event('event', 'requesting instance', 'salt/cloud/{0}/requesting'.format( vm_['name']), {'kwargs': kwargs}, transport=__opts__['transport']) try: ret = create_node(kwargs) except Exception as exc: log.error( 'Error creating {0} on Aliyun ECS\n\n' 'The following exception was thrown when trying to ' 'run the initial deployment: {1}'.format(vm_['name'], str(exc)), # Show the traceback if the debug logging level is enabled exc_info_on_loglevel=logging.DEBUG) return False def __query_node_data(vm_name): data = show_instance(vm_name, call='action') if not data: # Trigger an error in the wait_for_ip function return False if data.get('PublicIpAddress', None) is not None: return data try: data = salt.utils.cloud.wait_for_ip( __query_node_data, update_args=(vm_['name'], ), timeout=config.get_cloud_config_value('wait_for_ip_timeout', vm_, __opts__, default=10 * 60), interval=config.get_cloud_config_value('wait_for_ip_interval', vm_, __opts__, default=10), ) except (SaltCloudExecutionTimeout, SaltCloudExecutionFailure) as exc: try: # It might be already up, let's destroy it! destroy(vm_['name']) except SaltCloudSystemExit: pass finally: raise SaltCloudSystemExit(str(exc)) public_ip = data['PublicIpAddress'][0] log.debug('VM {0} is now running'.format(public_ip)) vm_['ssh_host'] = public_ip # The instance is booted and accessible, let's Salt it! ret = salt.utils.cloud.bootstrap(vm_, __opts__) ret.update(data.__dict__) log.info('Created Cloud VM {0[name]!r}'.format(vm_)) log.debug('{0[name]!r} VM creation details:\n{1}'.format( vm_, pprint.pformat(data))) salt.utils.cloud.fire_event('event', 'created instance', 'salt/cloud/{0}/created'.format(vm_['name']), { 'name': vm_['name'], 'profile': vm_['profile'], 'provider': vm_['driver'], }, transport=__opts__['transport']) return ret
def create(server_): ''' Create a single BareMetal server from a data dict. ''' try: # Check for required profile parameters before sending any API calls. if server_['profile'] and config.is_profile_configured( __opts__, __active_provider_name__ or 'scaleway', server_['profile']) is False: return False except AttributeError: pass # Since using "provider: <provider-engine>" is deprecated, alias provider # to use driver: "driver: <provider-engine>" if 'provider' in server_: server_['driver'] = server_.pop('provider') salt.utils.cloud.fire_event('event', 'starting create', 'salt/cloud/{0}/creating'.format( server_['name']), { 'name': server_['name'], 'profile': server_['profile'], 'provider': server_['driver'], }, transport=__opts__['transport']) log.info('Creating a BareMetal server {0}'.format(server_['name'])) access_key = config.get_cloud_config_value('access_key', get_configured_provider(), __opts__, search_global=False) kwargs = { 'name': server_['name'], 'organization': access_key, 'image': get_image(server_), } salt.utils.cloud.fire_event('event', 'requesting instance', 'salt/cloud/{0}/requesting'.format( server_['name']), {'kwargs': kwargs}, transport=__opts__['transport']) try: ret = create_node(kwargs) except Exception as exc: log.error( 'Error creating {0} on Scaleway\n\n' 'The following exception was thrown when trying to ' 'run the initial deployment: {1}'.format(server_['name'], str(exc)), # Show the traceback if the debug logging level is enabled exc_info_on_loglevel=logging.DEBUG) return False def __query_node_data(server_name): ''' Called to check if the server has a public IP address. ''' data = show_instance(server_name, 'action') if data and data.get('public_ip'): return data return False try: data = salt.utils.cloud.wait_for_ip( __query_node_data, update_args=(server_['name'], ), timeout=config.get_cloud_config_value('wait_for_ip_timeout', server_, __opts__, default=10 * 60), interval=config.get_cloud_config_value('wait_for_ip_interval', server_, __opts__, default=10), ) except (SaltCloudExecutionTimeout, SaltCloudExecutionFailure) as exc: try: # It might be already up, let's destroy it! destroy(server_['name']) except SaltCloudSystemExit: pass finally: raise SaltCloudSystemExit(str(exc)) server_['ssh_host'] = data['public_ip']['address'] server_['ssh_password'] = config.get_cloud_config_value( 'ssh_password', server_, __opts__) ret = salt.utils.cloud.bootstrap(server_, __opts__) ret.update(data) log.info('Created BareMetal server {0[name]!r}'.format(server_)) log.debug('{0[name]!r} BareMetal server creation details:\n{1}'.format( server_, pprint.pformat(data))) salt.utils.cloud.fire_event('event', 'created instance', 'salt/cloud/{0}/created'.format( server_['name']), { 'name': server_['name'], 'profile': server_['profile'], 'provider': server_['driver'], }, transport=__opts__['transport']) return ret
def create(vm_): ''' Provision a single machine ''' clone_strategy = vm_.get('clone_strategy') or 'full' if clone_strategy not in set(['quick', 'full']): raise SaltCloudSystemExit("'clone_strategy' must be one of quick or full. Got '{0}'".format(clone_strategy)) ip_source = vm_.get('ip_source') or 'ip-learning' if ip_source not in set(['ip-learning', 'qemu-agent']): raise SaltCloudSystemExit("'ip_source' must be one of qemu-agent or ip-learning. Got '{0}'".format(ip_source)) log.info("Cloning machine '{0}' with strategy '{1}'".format(vm_['name'], clone_strategy)) try: # Check for required profile parameters before sending any API calls. if vm_['profile'] and config.is_profile_configured(__opts__, __active_provider_name__ or 'libvirt', vm_['profile']) is False: return False except AttributeError: pass # TODO: check name qemu/libvirt will choke on some characters (like '/')? name = vm_['name'] __utils__['cloud.fire_event']( 'event', 'starting create', 'salt/cloud/{0}/creating'.format(name), { 'name': name, 'profile': vm_['profile'], 'provider': vm_['driver'], }, sock_dir=__opts__['sock_dir'], transport=__opts__['transport'] ) key_filename = config.get_cloud_config_value( 'private_key', vm_, __opts__, search_global=False, default=None ) if key_filename is not None and not os.path.isfile(key_filename): raise SaltCloudConfigError( 'The defined key_filename \'{0}\' does not exist'.format( key_filename ) ) vm_['key_filename'] = key_filename # wait_for_instance requires private_key vm_['private_key'] = key_filename cleanup = [] try: # clone the vm base = vm_['base_domain'] conn = __get_conn(vm_['url']) try: # for idempotency the salt-bootstrap needs -F argument # script_args: -F clone_domain = conn.lookupByName(name) except libvirtError as e: domain = conn.lookupByName(base) # TODO: ensure base is shut down before cloning xml = domain.XMLDesc(0) kwargs = { 'name': name, 'base_domain': base, } __utils__['cloud.fire_event']( 'event', 'requesting instance', 'salt/cloud/{0}/requesting'.format(name), {'kwargs': kwargs}, sock_dir=__opts__['sock_dir'], transport=__opts__['transport'] ) log.debug("Source machine XML '{0}'".format(xml)) domain_xml = ElementTree.fromstring(xml) domain_xml.find('./name').text = name domain_xml.find('./description').text = "Cloned from {0}".format(base) domain_xml.remove(domain_xml.find('./uuid')) for iface_xml in domain_xml.findall('./devices/interface'): iface_xml.remove(iface_xml.find('./mac')) # enable IP learning, this might be a default behaviour... if iface_xml.find("./filterref/parameter[@name='CTRL_IP_LEARNING']") is None: iface_xml.append(ElementTree.fromstring(IP_LEARNING_XML)) # If a qemu agent is defined we need to fix the path to its socket # <channel type='unix'> # <source mode='bind' path='/var/lib/libvirt/qemu/channel/target/domain-<dom-name>/org.qemu.guest_agent.0'/> # <target type='virtio' name='org.qemu.guest_agent.0'/> # <address type='virtio-serial' controller='0' bus='0' port='2'/> # </channel> for agent_xml in domain_xml.findall("""./devices/channel[@type='unix']"""): # is org.qemu.guest_agent.0 an option? if agent_xml.find("""./target[@type='virtio'][@name='org.qemu.guest_agent.0']""") is not None: source_element = agent_xml.find("""./source[@mode='bind']""") # see if there is a path element that needs rewriting if 'path' in source_element.attrib: path = source_element.attrib['path'] new_path = path.replace('/domain-{0}/'.format(base), '/domain-{0}/'.format(name)) log.debug("Rewriting agent socket path to {0}".format(new_path)) source_element.attrib['path'] = new_path for disk in domain_xml.findall("""./devices/disk[@device='disk'][@type='file']"""): # print "Disk: ", ElementTree.tostring(disk) # check if we can clone driver = disk.find("./driver[@name='qemu']") if driver is None: # Err on the safe side raise SaltCloudExecutionFailure("Non qemu driver disk encountered bailing out.") disk_type = driver.attrib.get('type') log.info("disk attributes {0}".format(disk.attrib)) if disk_type == 'qcow2': source = disk.find("./source").attrib['file'] pool, volume = find_pool_and_volume(conn, source) if clone_strategy == 'quick': new_volume = pool.createXML(create_volume_with_backing_store_xml(volume), 0) else: new_volume = pool.createXMLFrom(create_volume_xml(volume), volume, 0) cleanup.append({'what': 'volume', 'item': new_volume}) disk.find("./source").attrib['file'] = new_volume.path() elif disk_type == 'raw': source = disk.find("./source").attrib['file'] pool, volume = find_pool_and_volume(conn, source) # TODO: more control on the cloned disk type new_volume = pool.createXMLFrom(create_volume_xml(volume), volume, 0) cleanup.append({'what': 'volume', 'item': new_volume}) disk.find("./source").attrib['file'] = new_volume.path() else: raise SaltCloudExecutionFailure("Disk type '{0}' not supported".format(disk_type)) log.debug("Clone XML '{0}'".format(domain_xml)) clone_xml = ElementTree.tostring(domain_xml) clone_domain = conn.defineXMLFlags(clone_xml, libvirt.VIR_DOMAIN_DEFINE_VALIDATE) cleanup.append({'what': 'domain', 'item': clone_domain}) clone_domain.createWithFlags(libvirt.VIR_DOMAIN_START_FORCE_BOOT) log.debug("VM '{0}'".format(vm_)) if ip_source == 'qemu-agent': ip_source = libvirt.VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_AGENT elif ip_source == 'ip-learning': ip_source = libvirt.VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_LEASE address = salt.utils.cloud.wait_for_ip( get_domain_ip, update_args=(clone_domain, 0, ip_source), timeout=config.get_cloud_config_value('wait_for_ip_timeout', vm_, __opts__, default=10 * 60), interval=config.get_cloud_config_value('wait_for_ip_interval', vm_, __opts__, default=10), interval_multiplier=config.get_cloud_config_value('wait_for_ip_interval_multiplier', vm_, __opts__, default=1), ) log.info('Address = {0}'.format(address)) vm_['ssh_host'] = address # the bootstrap script needs to be installed first in /etc/salt/cloud.deploy.d/ # salt-cloud -u is your friend ret = __utils__['cloud.bootstrap'](vm_, __opts__) __utils__['cloud.fire_event']( 'event', 'created instance', 'salt/cloud/{0}/created'.format(name), { 'name': name, 'profile': vm_['profile'], 'provider': vm_['driver'], }, sock_dir=__opts__['sock_dir'], transport=__opts__['transport'] ) return ret except Exception as e: # pylint: disable=broad-except # Try to clean up in as much cases as possible log.info('Cleaning up after exception clean up items: {0}'.format(cleanup)) for leftover in cleanup: what = leftover['what'] item = leftover['item'] if what == 'domain': destroy_domain(conn, item) if what == 'volume': item.delete() raise e
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 {0}'.format(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 = [str(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': str(count), 'diskImage': { 'capacity': str(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 {0} .' '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.'.format(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, } } 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 {0} on SoftLayer\n\n' 'The following exception was thrown when trying to ' 'run the initial deployment: \n{1}'.format(name, str(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 \ len(node['operatingSystem']['passwords']) > 0: 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 create(vm_): """ Create a single VM from a data dict """ try: # Check for required profile parameters before sending any API calls. if (vm_.get("profile") and config.is_profile_configured( __opts__, _get_active_provider_name() or __virtualname__, vm_["profile"], vm_=vm_, ) is False): return False except AttributeError: pass client = _connect_client() name = vm_.get("name") if not name: raise SaltCloudException("Missing server name") # Get the required configuration server_type = client.server_types.get_by_name(vm_.get("size")) if server_type is None: raise SaltCloudException("The server size is not supported") image = client.images.get_by_name(vm_.get("image")) if image is None: raise SaltCloudException("The server image is not supported") __utils__["cloud.fire_event"]( "event", "starting create", "salt/cloud/{}/creating".format(vm_["name"]), args=__utils__["cloud.filter_event"]( "creating", vm_, ["name", "profile", "provider", "driver"], ), sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], ) # Get the ssh_keys ssh_keys = vm_.get("ssh_keys", None) if ssh_keys: names, ssh_keys = ssh_keys[:], [] for n in names: ssh_key = client.ssh_keys.get_by_name(n) if ssh_key is None: log.error("Invalid ssh key %s.", n) else: ssh_keys.append(ssh_key) # Get the location location = vm_.get("location", None) if location: location = client.locations.get_by_name(location) if location is None: raise SaltCloudException("The server location is not supported") # Get the datacenter datacenter = vm_.get("datacenter", None) if datacenter: datacenter = client.datacenters.get_by_name(datacenter) if datacenter is None: raise SaltCloudException("The server datacenter is not supported") # Get the volumes volumes = vm_.get("volumes", None) if volumes: volumes = [vol for vol in client.volumes.get_all() if vol in volumes] # Get the networks networks = vm_.get("networks", None) if networks: networks = [ vol for vol in client.networks.get_all() if vol in networks ] # Create the machine response = client.servers.create( name=name, server_type=server_type, image=image, ssh_keys=ssh_keys, volumes=volumes, networks=networks, location=location, user_data=vm_.get("user_data", None), labels=vm_.get("labels", None), datacenter=datacenter, automount=vm_.get("automount", None), ) # Bootstrap if ssh keys are configured server = response.server vm_.update({ "ssh_host": server.public_net.ipv4.ip or server.public_net.ipv6.ip, "ssh_password": response.root_password, "key_filename": config.get_cloud_config_value("private_key", vm_, __opts__, search_global=False, default=None), }) ret = __utils__["cloud.bootstrap"](vm_, __opts__) log.info("Created Cloud VM '%s'", vm_["name"]) ret["created"] = True __utils__["cloud.fire_event"]( "event", "created instance", "salt/cloud/{}/created".format(vm_["name"]), args=__utils__["cloud.filter_event"]( "created", vm_, ["name", "profile", "provider", "driver"], ), sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], ) return ret
def create(vm_): ''' Create a single VM from a data dict ''' # Check for required profile parameters before sending any API calls. if config.is_profile_configured(__opts__, __active_provider_name__ or 'cloudstack', vm_['profile']) is False: return False salt.utils.cloud.fire_event( 'event', 'starting create', 'salt/cloud/{0}/creating'.format(vm_['name']), { 'name': vm_['name'], 'profile': vm_['profile'], 'provider': vm_['provider'], }, transport=__opts__['transport'] ) log.info('Creating Cloud VM {0}'.format(vm_['name'])) conn = get_conn() kwargs = { 'name': vm_['name'], 'image': get_image(conn, vm_), 'size': get_size(conn, vm_), 'location': get_location(conn, vm_), } if get_keypair(vm_) is not False: kwargs['ex_keyname'] = get_keypair(vm_) if get_networkid(vm_) is not False: kwargs['networkids'] = get_networkid(vm_) kwargs['networks'] = ( # The only attr that is used is 'id'. CloudStackNetwork(None, None, None, kwargs['networkids'], None, None), ) if get_project(conn, vm_) is not False: kwargs['project'] = get_project(conn, vm_) salt.utils.cloud.fire_event( 'event', 'requesting instance', 'salt/cloud/{0}/requesting'.format(vm_['name']), {'kwargs': {'name': kwargs['name'], 'image': kwargs['image'].name, 'size': kwargs['size'].name}}, transport=__opts__['transport'] ) displayname = cloudstack_displayname(vm_) if displayname: kwargs['ex_displayname'] = displayname else: kwargs['ex_displayname'] = kwargs['name'] volumes = {} ex_blockdevicemappings = block_device_mappings(vm_) if ex_blockdevicemappings: for ex_blockdevicemapping in ex_blockdevicemappings: if 'VirtualName' not in ex_blockdevicemapping: ex_blockdevicemapping['VirtualName'] = '{0}-{1}'.format(vm_['name'], len(volumes)) salt.utils.cloud.fire_event( 'event', 'requesting volume', 'salt/cloud/{0}/requesting'.format(ex_blockdevicemapping['VirtualName']), {'kwargs': {'name': ex_blockdevicemapping['VirtualName'], 'device': ex_blockdevicemapping['DeviceName'], 'size': ex_blockdevicemapping['VolumeSize']}}, ) try: volumes[ex_blockdevicemapping['DeviceName']] = conn.create_volume( ex_blockdevicemapping['VolumeSize'], ex_blockdevicemapping['VirtualName'] ) except Exception as exc: log.error( 'Error creating volume {0} on CLOUDSTACK\n\n' 'The following exception was thrown by libcloud when trying to ' 'requesting a volume: \n{1}'.format( ex_blockdevicemapping['VirtualName'], exc ), # Show the traceback if the debug logging level is enabled exc_info_on_loglevel=logging.DEBUG ) return False else: ex_blockdevicemapping = {} try: data = conn.create_node(**kwargs) except Exception as exc: log.error( 'Error creating {0} on CLOUDSTACK\n\n' 'The following exception was thrown by libcloud when trying to ' 'run the initial deployment: \n{1}'.format( vm_['name'], str(exc) ), # Show the traceback if the debug logging level is enabled exc_info_on_loglevel=logging.DEBUG ) return False for device_name in six.iterkeys(volumes): try: conn.attach_volume(data, volumes[device_name], device_name) except Exception as exc: log.error( 'Error attaching volume {0} on CLOUDSTACK\n\n' 'The following exception was thrown by libcloud when trying to ' 'attach a volume: \n{1}'.format( ex_blockdevicemapping.get('VirtualName', 'UNKNOWN'), exc ), # Show the traceback if the debug logging level is enabled exc_info=log.isEnabledFor(logging.DEBUG) ) return False ssh_username = config.get_cloud_config_value( 'ssh_username', vm_, __opts__, default='root' ) ret = {} if config.get_cloud_config_value('deploy', vm_, __opts__) is True: deploy_script = script(vm_) deploy_kwargs = { 'opts': __opts__, 'host': get_ip(data), 'username': ssh_username, 'password': data.extra['password'], 'key_filename': get_key(), 'script': deploy_script.script, 'name': vm_['name'], 'tmp_dir': config.get_cloud_config_value( 'tmp_dir', vm_, __opts__, default='/tmp/.saltcloud' ), 'deploy_command': config.get_cloud_config_value( 'deploy_command', vm_, __opts__, default='/tmp/.saltcloud/deploy.sh', ), 'start_action': __opts__['start_action'], 'parallel': __opts__['parallel'], 'sock_dir': __opts__['sock_dir'], 'conf_file': __opts__['conf_file'], 'minion_pem': vm_['priv_key'], 'minion_pub': vm_['pub_key'], 'keep_tmp': __opts__['keep_tmp'], 'preseed_minion_keys': vm_.get('preseed_minion_keys', None), 'sudo': config.get_cloud_config_value( 'sudo', vm_, __opts__, default=(ssh_username != 'root') ), 'sudo_password': config.get_cloud_config_value( 'sudo_password', vm_, __opts__, default=None ), 'tty': config.get_cloud_config_value( 'tty', vm_, __opts__, default=False ), 'display_ssh_output': config.get_cloud_config_value( 'display_ssh_output', vm_, __opts__, default=True ), 'script_args': config.get_cloud_config_value( 'script_args', vm_, __opts__ ), 'script_env': config.get_cloud_config_value('script_env', vm_, __opts__), 'minion_conf': salt.utils.cloud.minion_config(__opts__, vm_) } # Deploy salt-master files, if necessary if config.get_cloud_config_value('make_master', vm_, __opts__) is True: deploy_kwargs['make_master'] = True deploy_kwargs['master_pub'] = vm_['master_pub'] deploy_kwargs['master_pem'] = vm_['master_pem'] master_conf = salt.utils.cloud.master_config(__opts__, vm_) deploy_kwargs['master_conf'] = master_conf if master_conf.get('syndic_master', None): deploy_kwargs['make_syndic'] = True deploy_kwargs['make_minion'] = config.get_cloud_config_value( 'make_minion', vm_, __opts__, default=True ) # Check for Windows install params win_installer = config.get_cloud_config_value('win_installer', vm_, __opts__) if win_installer: deploy_kwargs['win_installer'] = win_installer minion = salt.utils.cloud.minion_config(__opts__, vm_) deploy_kwargs['master'] = minion['master'] deploy_kwargs['username'] = config.get_cloud_config_value( 'win_username', vm_, __opts__, default='Administrator' ) deploy_kwargs['password'] = config.get_cloud_config_value( 'win_password', vm_, __opts__, default='' ) # Store what was used to the deploy the VM event_kwargs = copy.deepcopy(deploy_kwargs) del event_kwargs['minion_pem'] del event_kwargs['minion_pub'] del event_kwargs['sudo_password'] if 'password' in event_kwargs: del event_kwargs['password'] ret['deploy_kwargs'] = event_kwargs salt.utils.cloud.fire_event( 'event', 'executing deploy script', 'salt/cloud/{0}/deploying'.format(vm_['name']), {'kwargs': event_kwargs}, transport=__opts__['transport'] ) deployed = False if win_installer: deployed = salt.utils.cloud.deploy_windows(**deploy_kwargs) else: deployed = salt.utils.cloud.deploy_script(**deploy_kwargs) if deployed: log.info('Salt installed on {0}'.format(vm_['name'])) else: log.error( 'Failed to start Salt on Cloud VM {0}'.format( vm_['name'] ) ) ret.update(data.__dict__) if 'password' in data.extra: del data.extra['password'] log.info('Created Cloud VM {0[name]!r}'.format(vm_)) log.debug( '{0[name]!r} VM creation details:\n{1}'.format( vm_, pprint.pformat(data.__dict__) ) ) salt.utils.cloud.fire_event( 'event', 'created instance', 'salt/cloud/{0}/created'.format(vm_['name']), { 'name': vm_['name'], 'profile': vm_['profile'], 'provider': vm_['provider'], }, transport=__opts__['transport'] ) return ret
def create(vm_): ''' Create a single VM from a data dict CLI Example: .. code-block:: bash salt-cloud -p profile_name vm_name ''' try: # Check for required profile parameters before sending any API calls. if vm_['profile'] and config.is_profile_configured(__opts__, __active_provider_name__ or 'joyent', vm_['profile'], vm_=vm_) is False: return False except AttributeError: pass # Since using "provider: <provider-engine>" is deprecated, alias provider # to use driver: "driver: <provider-engine>" if 'provider' in vm_: vm_['driver'] = vm_.pop('provider') key_filename = config.get_cloud_config_value( 'private_key', vm_, __opts__, search_global=False, default=None ) __utils__['cloud.fire_event']( 'event', 'starting create', 'salt/cloud/{0}/creating'.format(vm_['name']), args={ 'name': vm_['name'], 'profile': vm_['profile'], 'provider': vm_['driver'], }, sock_dir=__opts__['sock_dir'], transport=__opts__['transport'] ) log.info( 'Creating Cloud VM {0} in {1}'.format( vm_['name'], vm_.get('location', DEFAULT_LOCATION) ) ) # added . for fqdn hostnames salt.utils.cloud.check_name(vm_['name'], 'a-zA-Z0-9-.') kwargs = { 'name': vm_['name'], 'image': get_image(vm_), 'size': get_size(vm_), 'location': vm_.get('location', DEFAULT_LOCATION) } # Let's not assign a default here; only assign a network value if # one is explicitly configured if 'networks' in vm_: kwargs['networks'] = vm_.get('networks') __utils__['cloud.fire_event']( 'event', 'requesting instance', 'salt/cloud/{0}/requesting'.format(vm_['name']), args={'kwargs': kwargs}, sock_dir=__opts__['sock_dir'], transport=__opts__['transport'] ) data = create_node(**kwargs) if data == {}: log.error('Error creating {0} on JOYENT'.format(vm_['name'])) return False query_instance(vm_) data = show_instance(vm_['name'], call='action') vm_['key_filename'] = key_filename vm_['ssh_host'] = data[1]['primaryIp'] __utils__['cloud.bootstrap'](vm_, __opts__) __utils__['cloud.fire_event']( 'event', 'created instance', 'salt/cloud/{0}/created'.format(vm_['name']), args={ 'name': vm_['name'], 'profile': vm_['profile'], 'provider': vm_['driver'], }, sock_dir=__opts__['sock_dir'], transport=__opts__['transport'] ) return data[1]
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 'profitbricks', vm_['profile']) is False: return False except AttributeError: pass datacenter_id = get_datacenter_id() conn = get_conn() data = None # Apply component overrides to the size from the cloud profile config. vm_size = override_size(vm_) # Retrieve list of SSH public keys ssh_keys = get_public_keys(vm_) # Fetch image and construct volume image = get_image(conn, vm_) volume = Volume( name='{0} Storage'.format(vm_['name']), size=vm_size['disk'], image=image['id'], ssh_keys=ssh_keys ) # Construct server server = Server( name=vm_['name'], ram=vm_size['ram'], cores=vm_size['cores'], create_volumes=[volume] ) salt.utils.cloud.fire_event( 'event', 'requesting instance', 'salt/cloud/{0}/requesting'.format(vm_['name']), {'name': vm_['name']}, transport=__opts__['transport'] ) try: data = conn.create_server(datacenter_id=datacenter_id, server=server) _wait_for_completion(conn, data, 120, "create_server") except Exception as exc: # pylint: disable=W0703 log.error( 'Error creating {0} on ProfitBricks\n\n' 'The following exception was thrown by the profitbricks library ' 'when trying to run the initial deployment: \n{1}'.format( vm_['name'], exc ), exc_info_on_loglevel=logging.DEBUG ) return False create_network_interfaces(conn, datacenter_id, data['id'], vm_) set_public_lan(conn, vm_) def __query_node_data(vm_, data): ''' Query node data until node becomes available. ''' running = False try: data = show_instance(vm_['name'], 'action') if not data: return False log.debug( 'Loaded node data for {0}:\nname: {1}\nstate: {2}'.format( vm_['name'], pprint.pformat(data['name']), data['vmState'] ) ) except Exception as err: log.error( 'Failed to get nodes list: {0}'.format( err ), # Show the trackback if the debug logging level is enabled exc_info_on_loglevel=logging.DEBUG ) # Trigger a failure in the wait for IP function return False running = data['vmState'] == 'RUNNING' if not running: # Still not running, trigger another iteration return if ssh_interface(vm_) == 'private_lan' and data['private_ips']: vm_['ssh_host'] = data['private_ips'][0] if ssh_interface(vm_) != 'private_lan' and data['public_ips']: vm_['ssh_host'] = data['public_ips'][0] return data try: data = salt.utils.cloud.wait_for_ip( __query_node_data, update_args=(vm_, data), timeout=config.get_cloud_config_value( 'wait_for_ip_timeout', vm_, __opts__, default=10 * 60), interval=config.get_cloud_config_value( 'wait_for_ip_interval', vm_, __opts__, default=10), ) except (SaltCloudExecutionTimeout, SaltCloudExecutionFailure) as exc: try: # It might be already up, let's destroy it! destroy(vm_['name']) except SaltCloudSystemExit: pass finally: raise SaltCloudSystemExit(str(exc.message)) log.debug('VM is now running') log.info('Created Cloud VM {0[name]!r}'.format(vm_)) log.debug( '{0[name]!r} VM creation details:\n{1}'.format( vm_, pprint.pformat(data) ) ) salt.utils.cloud.fire_event( 'event', 'created instance', 'salt/cloud/{0}/created'.format(vm_['name']), { 'name': vm_['name'], 'profile': vm_['profile'], 'provider': vm_['driver'], }, transport=__opts__['transport'] ) if 'ssh_host' in vm_: vm_['key_filename'] = get_key_filename(vm_) ret = salt.utils.cloud.bootstrap(vm_, __opts__) ret.update(data) return ret else: raise SaltCloudSystemExit('A valid IP address was not found.')
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__, _get_active_provider_name() or "cloudstack", vm_["profile"], vm_=vm_, ) is False): return False except AttributeError: pass __utils__["cloud.fire_event"]( "event", "starting create", "salt/cloud/{}/creating".format(vm_["name"]), sock_dir=__opts__["sock_dir"], args=__utils__["cloud.filter_event"]( "creating", vm_, ["name", "profile", "provider", "driver"]), transport=__opts__["transport"], ) log.info("Creating Cloud VM %s", vm_["name"]) conn = get_conn() # pylint: disable=not-callable kwargs = { "name": vm_["name"], "image": get_image(conn, vm_), "size": get_size(conn, vm_), "location": get_location(conn, vm_), } # pylint: enable=not-callable sg = get_security_groups(conn, vm_) if sg is not False: kwargs["ex_security_groups"] = sg if get_keypair(vm_) is not False: kwargs["ex_keyname"] = get_keypair(vm_) if get_networkid(vm_) is not False: kwargs["networkids"] = get_networkid(vm_) kwargs["networks"] = ( # The only attr that is used is 'id'. CloudStackNetwork(None, None, None, kwargs["networkids"], None, None), ) if get_project(conn, vm_) is not False: kwargs["project"] = get_project(conn, vm_) event_data = kwargs.copy() event_data["image"] = kwargs["image"].name event_data["size"] = kwargs["size"].name __utils__["cloud.fire_event"]( "event", "requesting instance", "salt/cloud/{}/requesting".format(vm_["name"]), sock_dir=__opts__["sock_dir"], args={ "kwargs": __utils__["cloud.filter_event"]( "requesting", event_data, ["name", "profile", "provider", "driver", "image", "size"], ), }, transport=__opts__["transport"], ) displayname = cloudstack_displayname(vm_) if displayname: kwargs["ex_displayname"] = displayname else: kwargs["ex_displayname"] = kwargs["name"] volumes = {} ex_blockdevicemappings = block_device_mappings(vm_) if ex_blockdevicemappings: for ex_blockdevicemapping in ex_blockdevicemappings: if "VirtualName" not in ex_blockdevicemapping: ex_blockdevicemapping["VirtualName"] = "{}-{}".format( vm_["name"], len(volumes)) __utils__["cloud.fire_event"]( "event", "requesting volume", "salt/cloud/{}/requesting".format( ex_blockdevicemapping["VirtualName"]), sock_dir=__opts__["sock_dir"], args={ "kwargs": { "name": ex_blockdevicemapping["VirtualName"], "device": ex_blockdevicemapping["DeviceName"], "size": ex_blockdevicemapping["VolumeSize"], } }, ) try: volumes[ ex_blockdevicemapping["DeviceName"]] = conn.create_volume( ex_blockdevicemapping["VolumeSize"], ex_blockdevicemapping["VirtualName"], ) except Exception as exc: # pylint: disable=broad-except log.error( "Error creating volume %s on CLOUDSTACK\n\n" "The following exception was thrown by libcloud when trying to " "requesting a volume: \n%s", ex_blockdevicemapping["VirtualName"], exc, # Show the traceback if the debug logging level is enabled exc_info_on_loglevel=logging.DEBUG, ) return False else: ex_blockdevicemapping = {} try: data = conn.create_node(**kwargs) except Exception as exc: # pylint: disable=broad-except log.error( "Error creating %s on CLOUDSTACK\n\n" "The following exception was thrown by libcloud when trying to " "run the initial deployment: \n%s", vm_["name"], exc, # Show the traceback if the debug logging level is enabled exc_info_on_loglevel=logging.DEBUG, ) return False for device_name in volumes: try: conn.attach_volume(data, volumes[device_name], device_name) except Exception as exc: # pylint: disable=broad-except log.error( "Error attaching volume %s on CLOUDSTACK\n\n" "The following exception was thrown by libcloud when trying to " "attach a volume: \n%s", ex_blockdevicemapping.get("VirtualName", "UNKNOWN"), exc, # Show the traceback if the debug logging level is enabled exc_info=log.isEnabledFor(logging.DEBUG), ) return False ssh_username = config.get_cloud_config_value("ssh_username", vm_, __opts__, default="root") vm_["ssh_host"] = get_ip(data) vm_["password"] = data.extra["password"] vm_["key_filename"] = get_key() ret = __utils__["cloud.bootstrap"](vm_, __opts__) ret.update(data.__dict__) if "password" in data.extra: del data.extra["password"] log.info("Created Cloud VM '%s'", vm_["name"]) log.debug("'%s' VM creation details:\n%s", vm_["name"], pprint.pformat(data.__dict__)) __utils__["cloud.fire_event"]( "event", "created instance", "salt/cloud/{}/created".format(vm_["name"]), sock_dir=__opts__["sock_dir"], args=__utils__["cloud.filter_event"]( "created", vm_, ["name", "profile", "provider", "driver"]), transport=__opts__["transport"], ) return ret
def create(vm_): ''' Create a single VM from a data dict ''' try: # Check for required profile parameters before sending any API calls. if config.is_profile_configured(__opts__, __active_provider_name__ or 'aws', vm_['profile']) is False: return False except AttributeError: pass key_filename = config.get_cloud_config_value( 'private_key', vm_, __opts__, search_global=False, default=None ) if key_filename is not None and not os.path.isfile(key_filename): raise SaltCloudConfigError( 'The defined key_filename {0!r} does not exist'.format( key_filename ) ) location = get_location(vm_) log.info('Creating Cloud VM {0} in {1}'.format(vm_['name'], location)) conn = get_conn(location=location) usernames = ssh_username(vm_) kwargs = { 'ssh_key': config.get_cloud_config_value( 'private_key', vm_, __opts__, search_global=False ), 'name': vm_['name'], 'image': get_image(conn, vm_), 'size': get_size(conn, vm_), 'location': get_availability_zone(conn, vm_) } ex_keyname = keyname(vm_) if ex_keyname: kwargs['ex_keyname'] = ex_keyname ex_securitygroup = securitygroup(vm_) if ex_securitygroup: kwargs['ex_securitygroup'] = ex_securitygroup ex_blockdevicemappings = block_device_mappings(vm_) if ex_blockdevicemappings: kwargs['ex_blockdevicemappings'] = ex_blockdevicemappings ex_iam_profile = iam_profile(vm_) if ex_iam_profile: # libcloud does not implement 'iam_profile' yet. # A pull request has been suggested # https://github.com/apache/libcloud/pull/150 raise SaltCloudConfigError( 'libcloud does not implement \'iam_profile\' yet. ' 'Use EC2 driver instead.' ) tags = config.get_cloud_config_value('tag', vm_, __opts__, {}, search_global=False) if not isinstance(tags, dict): raise SaltCloudConfigError( '\'tag\' should be a dict.' ) kwargs['ex_metadata'] = config.get_cloud_config_value('metadata', vm_, __opts__, default={}, search_global=False) if not isinstance(kwargs['ex_metadata'], dict): raise SaltCloudConfigError( '\'metadata\' should be a dict.' ) try: data = conn.create_node(**kwargs) except Exception as exc: log.error( 'Error creating {0} on AWS\n\n' 'The following exception was thrown by libcloud when trying to ' 'run the initial deployment: {1}\n'.format( vm_['name'], exc ), # Show the traceback if the debug logging level is enabled exc_info_on_loglevel=logging.DEBUG ) return False log.info('Created node {0}'.format(vm_['name'])) def __get_node_data(conn, vm_name): data = get_node(conn, vm_name) if data is None: # Trigger a failure in the waiting function return False if ssh_interface(vm_) == 'private_ips' and data.private_ips: return data if ssh_interface(vm_) == 'public_ips' and data.public_ips: return data try: data = salt.utils.cloud.wait_for_ip( __get_node_data, update_args=(conn, vm_['name']), timeout=config.get_cloud_config_value( 'wait_for_ip_timeout', vm_, __opts__, default=5 * 60), interval=config.get_cloud_config_value( 'wait_for_ip_interval', vm_, __opts__, default=0.5), ) except (SaltCloudExecutionTimeout, SaltCloudExecutionFailure) as exc: try: # It might be already up, let's destroy it! destroy(vm_['name']) except SaltCloudSystemExit: pass finally: raise SaltCloudSystemExit(str(exc)) if tags: set_tags(vm_['name'], tags, call='action') if ssh_interface(vm_) == 'private_ips': log.info('Salt node data. Private_ip: {0}'.format(data.private_ips[0])) ip_address = data.private_ips[0] else: log.info('Salt node data. Public_ip: {0}'.format(data.public_ips[0])) ip_address = data.public_ips[0] if salt.utils.cloud.get_salt_interface(vm_, __opts__) == 'private_ips': salt_ip_address = data.private_ips[0] log.info('Salt interface set to: {0}'.format(salt_ip_address)) else: salt_ip_address = data.public_ips[0] log.debug('Salt interface set to: {0}'.format(salt_ip_address)) username = '******' ssh_connect_timeout = config.get_cloud_config_value( 'ssh_connect_timeout', vm_, __opts__, 900 # 15 minutes ) ssh_port = config.get_cloud_config_value( 'ssh_port', vm_, __opts__, 22 ) if salt.utils.cloud.wait_for_port(ip_address, timeout=ssh_connect_timeout): for user in usernames: if salt.utils.cloud.wait_for_passwd( host=ip_address, username=user, ssh_timeout=config.get_cloud_config_value( 'wait_for_passwd_timeout', vm_, __opts__, default=1 * 60 ), key_filename=key_filename, known_hosts_file=config.get_cloud_config_value( 'known_hosts_file', vm_, __opts__, default='/dev/null' ), ): username = user break else: raise SaltCloudSystemExit( 'Failed to authenticate against remote ssh' ) ret = {} if config.get_cloud_config_value('deploy', vm_, __opts__) is True: deploy_script = script(vm_) deploy_kwargs = { 'opts': __opts__, 'host': ip_address, 'port': ssh_port, 'salt_host': salt_ip_address, 'username': username, 'key_filename': key_filename, 'tmp_dir': config.get_cloud_config_value( 'tmp_dir', vm_, __opts__, default='/tmp/.saltcloud' ), 'deploy_command': config.get_cloud_config_value( 'deploy_command', vm_, __opts__, default='/tmp/.saltcloud/deploy.sh', ), 'tty': config.get_cloud_config_value( 'tty', vm_, __opts__, default=True ), 'script': deploy_script.script, 'name': vm_['name'], 'sudo': config.get_cloud_config_value( 'sudo', vm_, __opts__, default=(username != 'root') ), 'sudo_password': config.get_cloud_config_value( 'sudo_password', vm_, __opts__, default=None ), 'start_action': __opts__['start_action'], 'parallel': __opts__['parallel'], 'conf_file': __opts__['conf_file'], 'sock_dir': __opts__['sock_dir'], 'minion_pem': vm_['priv_key'], 'minion_pub': vm_['pub_key'], 'keep_tmp': __opts__['keep_tmp'], 'preseed_minion_keys': vm_.get('preseed_minion_keys', None), 'display_ssh_output': config.get_cloud_config_value( 'display_ssh_output', vm_, __opts__, default=True ), 'script_args': config.get_cloud_config_value( 'script_args', vm_, __opts__ ), 'script_env': config.get_cloud_config_value('script_env', vm_, __opts__), 'minion_conf': salt.utils.cloud.minion_config(__opts__, vm_) } # Deploy salt-master files, if necessary if config.get_cloud_config_value('make_master', vm_, __opts__) is True: deploy_kwargs['make_master'] = True deploy_kwargs['master_pub'] = vm_['master_pub'] deploy_kwargs['master_pem'] = vm_['master_pem'] master_conf = salt.utils.cloud.master_config(__opts__, vm_) deploy_kwargs['master_conf'] = master_conf if master_conf.get('syndic_master', None): deploy_kwargs['make_syndic'] = True deploy_kwargs['make_minion'] = config.get_cloud_config_value( 'make_minion', vm_, __opts__, default=True ) # Check for Windows install params win_installer = config.get_cloud_config_value('win_installer', vm_, __opts__) if win_installer: deploy_kwargs['win_installer'] = win_installer minion = salt.utils.cloud.minion_config(__opts__, vm_) deploy_kwargs['master'] = minion['master'] deploy_kwargs['username'] = config.get_cloud_config_value( 'win_username', vm_, __opts__, default='Administrator' ) deploy_kwargs['password'] = config.get_cloud_config_value( 'win_password', vm_, __opts__, default='' ) # Store what was used to the deploy the VM ret['deploy_kwargs'] = deploy_kwargs deployed = False if win_installer: deployed = salt.utils.cloud.deploy_windows(**deploy_kwargs) else: deployed = salt.utils.cloud.deploy_script(**deploy_kwargs) if deployed: log.info('Salt installed on {name}'.format(**vm_)) else: log.error('Failed to start Salt on Cloud VM {name}'.format(**vm_)) ret.update(data.__dict__) log.info('Created Cloud VM {0[name]!r}'.format(vm_)) log.debug( '{0[name]!r} VM creation details:\n{1}'.format( vm_, pprint.pformat(data.__dict__) ) ) volumes = config.get_cloud_config_value( 'volumes', vm_, __opts__, search_global=True ) if volumes: log.info('Create and attach volumes to node {0}'.format(data.name)) create_attach_volumes(volumes, location, data) return ret
def create(vm_): ''' Create a single VM from a data dict CLI Example: .. code-block:: bash salt-cloud -p proxmox-ubuntu vmhostname ''' try: # Check for required profile parameters before sending any API calls. if vm_['profile'] and config.is_profile_configured(__opts__, __active_provider_name__ or 'proxmox', vm_['profile'], vm_=vm_) is False: return False except AttributeError: pass # Since using "provider: <provider-engine>" is deprecated, alias provider # to use driver: "driver: <provider-engine>" if 'provider' in vm_: vm_['driver'] = vm_.pop('provider') ret = {} salt.utils.cloud.fire_event( 'event', 'starting create', 'salt/cloud/{0}/creating'.format(vm_['name']), { 'name': vm_['name'], 'profile': vm_['profile'], 'provider': vm_['driver'], }, transport=__opts__['transport'] ) log.info('Creating Cloud VM {0}'.format(vm_['name'])) if 'use_dns' in vm_ and 'ip_address' not in vm_: use_dns = vm_['use_dns'] if use_dns: from socket import gethostbyname, gaierror try: ip_address = gethostbyname(str(vm_['name'])) except gaierror: log.debug('Resolving of {hostname} failed'.format(hostname=str(vm_['name']))) else: vm_['ip_address'] = str(ip_address) try: newid = _get_next_vmid() data = create_node(vm_, newid) except Exception as exc: log.error( 'Error creating {0} on PROXMOX\n\n' 'The following exception was thrown when trying to ' 'run the initial deployment: \n{1}'.format( vm_['name'], str(exc) ), # Show the traceback if the debug logging level is enabled exc_info_on_loglevel=logging.DEBUG ) return False ret['creation_data'] = data name = vm_['name'] # hostname which we know if 'clone' in vm_ and vm_['clone'] is True: vmid = newid else: vmid = data['vmid'] # vmid which we have received host = data['node'] # host which we have received nodeType = data['technology'] # VM tech (Qemu / OpenVZ) # Determine which IP to use in order of preference: if 'ip_address' in vm_: ip_address = str(vm_['ip_address']) elif 'public_ips' in data: ip_address = str(data['public_ips'][0]) # first IP elif 'private_ips' in data: ip_address = str(data['private_ips'][0]) # first IP else: raise SaltCloudExecutionFailure # err.. not a good idea i reckon log.debug('Using IP address {0}'.format(ip_address)) # wait until the vm has been created so we can start it if not wait_for_created(data['upid'], timeout=300): return {'Error': 'Unable to create {0}, command timed out'.format(name)} # VM has been created. Starting.. if not start(name, vmid, call='action'): log.error('Node {0} ({1}) failed to start!'.format(name, vmid)) raise SaltCloudExecutionFailure # Wait until the VM has fully started log.debug('Waiting for state "running" for vm {0} on {1}'.format(vmid, host)) if not wait_for_state(vmid, 'running'): return {'Error': 'Unable to start {0}, command timed out'.format(name)} ssh_username = config.get_cloud_config_value( 'ssh_username', vm_, __opts__, default='root' ) ssh_password = config.get_cloud_config_value( 'password', vm_, __opts__, ) ret['ip_address'] = ip_address ret['username'] = ssh_username ret['password'] = ssh_password vm_['ssh_host'] = ip_address vm_['password'] = ssh_password ret = salt.utils.cloud.bootstrap(vm_, __opts__) # Report success! log.info('Created Cloud VM \'{0[name]}\''.format(vm_)) log.debug( '\'{0[name]}\' VM creation details:\n{1}'.format( vm_, pprint.pformat(data) ) ) salt.utils.cloud.fire_event( 'event', 'created instance', 'salt/cloud/{0}/created'.format(vm_['name']), { 'name': vm_['name'], 'profile': vm_['profile'], 'provider': vm_['driver'], }, ) return ret
def create(vm_): ''' Create a single VM from a data dict ''' try: # Check for required profile parameters before sending any API calls. if config.is_profile_configured(__opts__, __active_provider_name__ or 'openstack', vm_['profile']) is False: return False except AttributeError: pass # Since using "provider: <provider-engine>" is deprecated, alias provider # to use driver: "driver: <provider-engine>" if 'provider' in vm_: vm_['driver'] = vm_.pop('provider') deploy = config.get_cloud_config_value('deploy', vm_, __opts__) key_filename = config.get_cloud_config_value( 'ssh_key_file', vm_, __opts__, search_global=False, default=None ) if key_filename is not None: key_filename = os.path.expanduser(key_filename) if not os.path.isfile(key_filename): raise SaltCloudConfigError( 'The defined ssh_key_file {0!r} does not exist'.format( key_filename ) ) vm_['key_filename'] = key_filename salt.utils.cloud.fire_event( 'event', 'starting create', 'salt/cloud/{0}/creating'.format(vm_['name']), { 'name': vm_['name'], 'profile': vm_['profile'], 'provider': vm_['driver'], }, transport=__opts__['transport'] ) conn = get_conn() if 'instance_id' in vm_: # This was probably created via another process, and doesn't have # things like salt keys created yet, so let's create them now. if 'pub_key' not in vm_ and 'priv_key' not in vm_: log.debug('Generating minion keys for {0[name]!r}'.format(vm_)) vm_['priv_key'], vm_['pub_key'] = salt.utils.cloud.gen_keys( salt.config.get_cloud_config_value( 'keysize', vm_, __opts__ ) ) data = conn.ex_get_node_details(vm_['instance_id']) if vm_['key_filename'] is None and 'change_password' in __opts__ and __opts__['change_password'] is True: vm_['password'] = sup.secure_password() conn.ex_set_password(data, vm_['password']) networks(vm_) else: # Put together all of the information required to request the instance, # and then fire off the request for it data, vm_ = request_instance(vm_) # Pull the instance ID, valid for both spot and normal instances vm_['instance_id'] = data.id def __query_node_data(vm_, data, floating): try: node = show_instance(vm_['name'], 'action') log.debug( 'Loaded node data for {0}:\n{1}'.format( vm_['name'], pprint.pformat(node) ) ) except Exception as err: log.error( 'Failed to get nodes list: {0}'.format( err ), # Show the traceback if the debug logging level is enabled exc_info_on_loglevel=logging.DEBUG ) # Trigger a failure in the wait for IP function return False running = node['state'] == NodeState.RUNNING if not running: # Still not running, trigger another iteration return if rackconnect(vm_) is True: check_libcloud_version((0, 14, 0), why='rackconnect: True') extra = node.get('extra') rc_status = extra.get('metadata', {}).get( 'rackconnect_automation_status', '') access_ip = extra.get('access_ip', '') if rc_status != 'DEPLOYED': log.debug('Waiting for Rackconnect automation to complete') return if managedcloud(vm_) is True: extra = node.get('extra') mc_status = extra.get('metadata', {}).get( 'rax_service_level_automation', '') if mc_status != 'Complete': log.debug('Waiting for managed cloud automation to complete') return public = node['public_ips'] if floating: try: name = data.name ip = floating[0].ip_address conn.ex_attach_floating_ip_to_node(data, ip) log.info( 'Attaching floating IP {0!r} to node {1!r}'.format( ip, name ) ) data.public_ips.append(ip) public = data.public_ips except Exception: # Note(pabelanger): Because we loop, we only want to attach the # floating IP address one. So, expect failures if the IP is # already attached. pass result = [] private = node['private_ips'] if private and not public: log.warn( 'Private IPs returned, but not public... Checking for ' 'misidentified IPs' ) for private_ip in private: private_ip = preferred_ip(vm_, [private_ip]) if salt.utils.cloud.is_public_ip(private_ip): log.warn('{0} is a public IP'.format(private_ip)) data.public_ips.append(private_ip) log.warn( 'Public IP address was not ready when we last checked.' ' Appending public IP address now.' ) public = data.public_ips else: log.warn('{0} is a private IP'.format(private_ip)) ignore_ip = ignore_cidr(vm_, private_ip) if private_ip not in data.private_ips and not ignore_ip: result.append(private_ip) if rackconnect(vm_) is True: if ssh_interface(vm_) != 'private_ips': data.public_ips = access_ip return data # populate return data with private_ips # when ssh_interface is set to private_ips and public_ips exist if not result and ssh_interface(vm_) == 'private_ips': for private_ip in private: ignore_ip = ignore_cidr(vm_, private_ip) if private_ip not in data.private_ips and not ignore_ip: result.append(private_ip) if result: log.debug('result = {0}'.format(result)) data.private_ips = result if ssh_interface(vm_) == 'private_ips': return data if public: data.public_ips = public if ssh_interface(vm_) != 'private_ips': return data try: data = salt.utils.cloud.wait_for_ip( __query_node_data, update_args=(vm_, data, vm_['floating']), timeout=config.get_cloud_config_value( 'wait_for_ip_timeout', vm_, __opts__, default=10 * 60), interval=config.get_cloud_config_value( 'wait_for_ip_interval', vm_, __opts__, default=10), ) except (SaltCloudExecutionTimeout, SaltCloudExecutionFailure) as exc: try: # It might be already up, let's destroy it! destroy(vm_['name']) except SaltCloudSystemExit: pass finally: raise SaltCloudSystemExit(str(exc)) log.debug('VM is now running') if ssh_interface(vm_) == 'private_ips': ip_address = preferred_ip(vm_, data.private_ips) elif rackconnect(vm_) is True and ssh_interface(vm_) != 'private_ips': ip_address = data.public_ips else: ip_address = preferred_ip(vm_, data.public_ips) log.debug('Using IP address {0}'.format(ip_address)) if salt.utils.cloud.get_salt_interface(vm_, __opts__) == 'private_ips': salt_ip_address = preferred_ip(vm_, data.private_ips) log.info('Salt interface set to: {0}'.format(salt_ip_address)) else: salt_ip_address = preferred_ip(vm_, data.public_ips) log.debug('Salt interface set to: {0}'.format(salt_ip_address)) if not ip_address: raise SaltCloudSystemExit('A valid IP address was not found') vm_['salt_host'] = salt_ip_address vm_['ssh_host'] = ip_address ret = salt.utils.cloud.bootstrap(vm_, __opts__) ret.update(data.__dict__) if hasattr(data, 'extra') and 'password' in data.extra: del data.extra['password'] log.info('Created Cloud VM {0[name]!r}'.format(vm_)) log.debug( '{0[name]!r} VM creation details:\n{1}'.format( vm_, pprint.pformat(data.__dict__) ) ) salt.utils.cloud.fire_event( 'event', 'created instance', 'salt/cloud/{0}/created'.format(vm_['name']), { 'name': vm_['name'], 'profile': vm_['profile'], 'provider': vm_['driver'], }, transport=__opts__['transport'] ) return ret
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__, _get_active_provider_name() or "dimensiondata", vm_["profile"]) is False): return False except AttributeError: pass __utils__["cloud.fire_event"]( "event", "starting create", "salt/cloud/{}/creating".format(vm_["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", vm_["name"]) conn = get_conn() location = conn.ex_get_location_by_id(vm_["location"]) images = conn.list_images(location=location) image = [x for x in images if x.id == vm_["image"]][0] network_domains = conn.ex_list_network_domains(location=location) try: network_domain = [ y for y in network_domains if y.name == vm_["network_domain"] ][0] except IndexError: network_domain = conn.ex_create_network_domain( location=location, name=vm_["network_domain"], plan="ADVANCED", description="", ) try: vlan = [ y for y in conn.ex_list_vlans(location=location, network_domain=network_domain) if y.name == vm_["vlan"] ][0] except (IndexError, KeyError): # Use the first VLAN in the network domain vlan = conn.ex_list_vlans(location=location, network_domain=network_domain)[0] kwargs = { "name": vm_["name"], "image": image, "ex_description": vm_["description"], "ex_network_domain": network_domain, "ex_vlan": vlan, "ex_is_started": vm_["is_started"], } event_data = _to_event_data(kwargs) __utils__["cloud.fire_event"]( "event", "requesting instance", "salt/cloud/{}/requesting".format(vm_["name"]), args=__utils__["cloud.filter_event"]("requesting", event_data, list(event_data)), sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], ) # Initial password (excluded from event payload) initial_password = NodeAuthPassword(vm_["auth"]) kwargs["auth"] = initial_password try: data = conn.create_node(**kwargs) except Exception as exc: # pylint: disable=broad-except log.error( "Error creating %s on DIMENSIONDATA\n\n" "The following exception was thrown by libcloud when trying to " "run the initial deployment: \n%s", vm_["name"], exc, exc_info_on_loglevel=logging.DEBUG, ) return False try: data = __utils__["cloud.wait_for_ip"]( _query_node_data, update_args=(vm_, data), timeout=config.get_cloud_config_value("wait_for_ip_timeout", vm_, __opts__, default=25 * 60), interval=config.get_cloud_config_value("wait_for_ip_interval", vm_, __opts__, default=30), max_failures=config.get_cloud_config_value( "wait_for_ip_max_failures", vm_, __opts__, default=60), ) except (SaltCloudExecutionTimeout, SaltCloudExecutionFailure) as exc: try: # It might be already up, let's destroy it! destroy(vm_["name"]) # pylint: disable=not-callable except SaltCloudSystemExit: pass finally: raise SaltCloudSystemExit(str(exc)) log.debug("VM is now running") if ssh_interface(vm_) == "private_ips": ip_address = preferred_ip(vm_, data.private_ips) else: ip_address = preferred_ip(vm_, data.public_ips) log.debug("Using IP address %s", ip_address) if __utils__["cloud.get_salt_interface"](vm_, __opts__) == "private_ips": salt_ip_address = preferred_ip(vm_, data.private_ips) log.info("Salt interface set to: %s", salt_ip_address) else: salt_ip_address = preferred_ip(vm_, data.public_ips) log.debug("Salt interface set to: %s", salt_ip_address) if not ip_address: raise SaltCloudSystemExit("No IP addresses could be found.") vm_["salt_host"] = salt_ip_address vm_["ssh_host"] = ip_address vm_["password"] = vm_["auth"] ret = __utils__["cloud.bootstrap"](vm_, __opts__) ret.update(data.__dict__) if "password" in data.extra: del data.extra["password"] log.info("Created Cloud VM '%s'", vm_["name"]) log.debug("'%s' VM creation details:\n%s", vm_["name"], pprint.pformat(data.__dict__)) __utils__["cloud.fire_event"]( "event", "created instance", "salt/cloud/{}/created".format(vm_["name"]), args=__utils__["cloud.filter_event"]( "created", vm_, ["name", "profile", "provider", "driver"]), sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], ) return ret
def create(vm_): ''' Create a single VM from a data dict CLI Example: .. code-block:: bash salt-cloud -p profile_name vm_name ''' try: # Check for required profile parameters before sending any API calls. if vm_['profile'] and config.is_profile_configured(__opts__, __active_provider_name__ or 'joyent', vm_['profile']) is False: return False except AttributeError: pass # Since using "provider: <provider-engine>" is deprecated, alias provider # to use driver: "driver: <provider-engine>" if 'provider' in vm_: vm_['driver'] = vm_.pop('provider') key_filename = config.get_cloud_config_value( 'private_key', vm_, __opts__, search_global=False, default=None ) salt.utils.cloud.fire_event( 'event', 'starting create', 'salt/cloud/{0}/creating'.format(vm_['name']), { 'name': vm_['name'], 'profile': vm_['profile'], 'provider': vm_['driver'], }, transport=__opts__['transport'] ) log.info( 'Creating Cloud VM {0} in {1}'.format( vm_['name'], vm_.get('location', DEFAULT_LOCATION) ) ) # added . for fqdn hostnames salt.utils.cloud.check_name(vm_['name'], 'a-zA-Z0-9-.') kwargs = { 'name': vm_['name'], 'image': get_image(vm_), 'size': get_size(vm_), 'location': vm_.get('location', DEFAULT_LOCATION) } salt.utils.cloud.fire_event( 'event', 'requesting instance', 'salt/cloud/{0}/requesting'.format(vm_['name']), {'kwargs': kwargs}, transport=__opts__['transport'] ) try: data = create_node(**kwargs) except Exception as exc: log.error( 'Error creating {0} on JOYENT\n\n' 'The following exception was thrown when trying to ' 'run the initial deployment: \n{1}'.format( vm_['name'], str(exc) ), # Show the traceback if the debug logging level is enabled exc_info_on_loglevel=logging.DEBUG ) return False query_instance(vm_) data = show_instance(vm_['name'], call='action') vm_['key_filename'] = key_filename vm_['ssh_host'] = data[1]['primaryIp'] salt.utils.cloud.bootstrap(vm_, __opts__) salt.utils.cloud.fire_event( 'event', 'created instance', 'salt/cloud/{0}/created'.format(vm_['name']), { 'name': vm_['name'], 'profile': vm_['profile'], 'provider': vm_['driver'], }, transport=__opts__['transport'] ) return data[1]
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_hw', 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(service='SoftLayer_Product_Order') kwargs = { 'complexType': 'SoftLayer_Container_Product_Order_Hardware_Server', 'quantity': 1, 'hardware': [{ 'hostname': hostname, 'domain': domain, }], # Baremetal Package 'packageId': 50, 'prices': [ # Size Ex: 1921: 2 x 2.0 GHz Core Bare Metal Instance - 2 GB Ram { 'id': vm_['size'] }, # HDD Ex: 19: 250GB SATA II { 'id': vm_['hdd'] }, # Image Ex: 13963: CentOS 6.0 - Minimal Install (64 bit) { 'id': vm_['image'] }, # The following items are currently required # Reboot / Remote Console { 'id': '905' }, # 1 IP Address { 'id': '21' }, # Host Ping Monitoring { 'id': '55' }, # Email and Ticket Notifications { 'id': '57' }, # Automated Notification Response { 'id': '58' }, # Unlimited SSL VPN Users & 1 PPTP VPN User per account { 'id': '420' }, # Nessus Vulnerability Assessment & Reporting { 'id': '418' }, ], } optional_products = config.get_cloud_config_value('optional_products', vm_, __opts__, default=[]) for product in optional_products: kwargs['prices'].append({'id': product}) # Default is 273 (100 Mbps Public & Private Networks) port_speed = config.get_cloud_config_value('port_speed', vm_, __opts__, default=273) kwargs['prices'].append({'id': port_speed}) # Default is 1800 (0 GB Bandwidth) bandwidth = config.get_cloud_config_value('bandwidth', vm_, __opts__, default=1800) kwargs['prices'].append({'id': bandwidth}) post_uri = config.get_cloud_config_value('post_uri', vm_, __opts__, default=None) if post_uri: kwargs['prices'].append({'id': post_uri}) vlan_id = config.get_cloud_config_value('vlan', vm_, __opts__, default=False) if vlan_id: kwargs['primaryNetworkComponent'] = { 'networkVlan': { 'id': vlan_id, } } location = get_location(vm_) if location: kwargs['location'] = location __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.placeOrder(kwargs) # Leaving the following line in, commented, for easy debugging #response = conn.verifyOrder(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 def wait_for_ip(): ''' Wait for the IP address to become available ''' nodes = list_nodes_full() if 'primaryIpAddress' in nodes[hostname]: return nodes[hostname]['primaryIpAddress'] 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), ) ssh_connect_timeout = config.get_cloud_config_value( # 15 minutes 'ssh_connect_timeout', vm_, __opts__, 900) if not salt.utils.cloud.wait_for_port(ip_address, timeout=ssh_connect_timeout): raise SaltCloudSystemExit('Failed to authenticate against remote ssh') pass_conn = get_conn(service='SoftLayer_Account') mask = { 'virtualGuests': { 'powerState': '', 'operatingSystem': { 'passwords': '' }, }, } def get_passwd(): ''' 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 len(node['operatingSystem']['passwords']) > 0: return node['operatingSystem']['passwords'][0]['password'] time.sleep(5) return False passwd = salt.utils.cloud.wait_for_fun( get_passwd, timeout=config.get_cloud_config_value('wait_for_fun_timeout', vm_, __opts__, default=15 * 60), ) response['password'] = passwd response['public_ip'] = ip_address ssh_username = config.get_cloud_config_value('ssh_username', vm_, __opts__, default='root') 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 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_hw', vm_['profile']) is False: return False except AttributeError: pass # Since using "provider: <provider-engine>" is deprecated, alias provider # to use driver: "driver: <provider-engine>" if 'provider' in vm_: vm_['driver'] = vm_.pop('provider') 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 salt.utils.cloud.fire_event( 'event', 'starting create', 'salt/cloud/{0}/creating'.format(name), { 'name': name, 'profile': vm_['profile'], 'provider': vm_['driver'], }, transport=__opts__['transport'] ) log.info('Creating Cloud VM {0}'.format(name)) conn = get_conn(service='SoftLayer_Product_Order') kwargs = { 'complexType': 'SoftLayer_Container_Product_Order_Hardware_Server', 'quantity': 1, 'hardware': [{ 'hostname': hostname, 'domain': domain, }], # Baremetal Package 'packageId': 50, 'prices': [ # Size Ex: 1921: 2 x 2.0 GHz Core Bare Metal Instance - 2 GB Ram {'id': vm_['size']}, # HDD Ex: 19: 250GB SATA II {'id': vm_['hdd']}, # Image Ex: 13963: CentOS 6.0 - Minimal Install (64 bit) {'id': vm_['image']}, # The following items are currently required # Reboot / Remote Console {'id': '905'}, # 1 IP Address {'id': '21'}, # Host Ping Monitoring {'id': '55'}, # Email and Ticket Notifications {'id': '57'}, # Automated Notification Response {'id': '58'}, # Unlimited SSL VPN Users & 1 PPTP VPN User per account {'id': '420'}, # Nessus Vulnerability Assessment & Reporting {'id': '418'}, ], } optional_products = config.get_cloud_config_value( 'optional_products', vm_, __opts__, default=[] ) for product in optional_products: kwargs['prices'].append({'id': product}) # Default is 273 (100 Mbps Public & Private Networks) port_speed = config.get_cloud_config_value( 'port_speed', vm_, __opts__, default=273 ) kwargs['prices'].append({'id': port_speed}) # Default is 1800 (0 GB Bandwidth) bandwidth = config.get_cloud_config_value( 'bandwidth', vm_, __opts__, default=1800 ) kwargs['prices'].append({'id': bandwidth}) post_uri = config.get_cloud_config_value( 'post_uri', vm_, __opts__, default=None ) if post_uri: kwargs['prices'].append({'id': post_uri}) vlan_id = config.get_cloud_config_value( 'vlan', vm_, __opts__, default=False ) if vlan_id: kwargs['primaryNetworkComponent'] = { 'networkVlan': { 'id': vlan_id, } } location = get_location(vm_) if location: kwargs['location'] = location salt.utils.cloud.fire_event( 'event', 'requesting instance', 'salt/cloud/{0}/requesting'.format(name), {'kwargs': kwargs}, transport=__opts__['transport'] ) try: response = conn.placeOrder(kwargs) # Leaving the following line in, commented, for easy debugging #response = conn.verifyOrder(kwargs) except Exception as exc: log.error( 'Error creating {0} on SoftLayer\n\n' 'The following exception was thrown when trying to ' 'run the initial deployment: \n{1}'.format( name, str(exc) ), # Show the traceback if the debug logging level is enabled exc_info_on_loglevel=logging.DEBUG ) return False def wait_for_ip(): ''' Wait for the IP address to become available ''' nodes = list_nodes_full() if 'primaryIpAddress' in nodes[hostname]: return nodes[hostname]['primaryIpAddress'] 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), ) ssh_connect_timeout = config.get_cloud_config_value( # 15 minutes 'ssh_connect_timeout', vm_, __opts__, 900 ) if not salt.utils.cloud.wait_for_port(ip_address, timeout=ssh_connect_timeout): raise SaltCloudSystemExit( 'Failed to authenticate against remote ssh' ) pass_conn = get_conn(service='SoftLayer_Account') mask = { 'virtualGuests': { 'powerState': '', 'operatingSystem': { 'passwords': '' }, }, } def get_passwd(): ''' 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 len(node['operatingSystem']['passwords']) > 0: return node['operatingSystem']['passwords'][0]['password'] time.sleep(5) return False passwd = salt.utils.cloud.wait_for_fun( get_passwd, timeout=config.get_cloud_config_value( 'wait_for_fun_timeout', vm_, __opts__, default=15 * 60), ) response['password'] = passwd response['public_ip'] = ip_address ssh_username = config.get_cloud_config_value( 'ssh_username', vm_, __opts__, default='root' ) vm_['ssh_host'] = ip_address vm_['password'] = passwd ret = salt.utils.cloud.bootstrap(vm_, __opts__) ret.update(response) salt.utils.cloud.fire_event( 'event', 'created instance', 'salt/cloud/{0}/created'.format(name), { 'name': name, 'profile': vm_['profile'], 'provider': vm_['driver'], }, transport=__opts__['transport'] ) return ret
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 'gogrid', vm_['profile'], vm_=vm_) is False: return False except AttributeError: pass __utils__['cloud.fire_event']( 'event', 'starting create', 'salt/cloud/{0}/creating'.format(vm_['name']), args=__utils__['cloud.filter_event']( 'creating', vm_, ['name', 'profile', 'provider', 'driver']), sock_dir=__opts__['sock_dir'], transport=__opts__['transport']) if len(vm_['name']) > 20: raise SaltCloudException( 'VM names must not be longer than 20 characters') log.info('Creating Cloud VM %s', vm_['name']) image_id = avail_images()[vm_['image']]['id'] if 'assign_public_ip' in vm_: host_ip = vm_['assign_public_ip'] else: public_ips = list_public_ips() if len(public_ips.keys()) < 1: raise SaltCloudException('No more IPs available') host_ip = list(public_ips)[0] create_kwargs = { 'name': vm_['name'], 'image': image_id, 'ram': vm_['size'], 'ip': host_ip, } __utils__['cloud.fire_event']( 'event', 'requesting instance', 'salt/cloud/{0}/requesting'.format(vm_['name']), args={ 'kwargs': __utils__['cloud.filter_event']('requesting', create_kwargs, list(create_kwargs)), }, sock_dir=__opts__['sock_dir'], transport=__opts__['transport']) try: data = _query('grid', 'server/add', args=create_kwargs) except Exception: log.error( 'Error creating %s on GOGRID\n\n' 'The following exception was thrown when trying to ' 'run the initial deployment:\n', vm_['name'], # Show the traceback if the debug logging level is enabled exc_info_on_loglevel=logging.DEBUG) return False ssh_username = config.get_cloud_config_value('ssh_username', vm_, __opts__, default='root') def wait_for_apipass(): ''' Wait for the password to become available, via the API ''' try: passwords = list_passwords() return passwords[vm_['name']][0]['password'] except KeyError: pass time.sleep(5) return False vm_['password'] = salt.utils.cloud.wait_for_fun( wait_for_apipass, timeout=config.get_cloud_config_value('wait_for_fun_timeout', vm_, __opts__, default=15 * 60), ) vm_['ssh_host'] = host_ip ret = __utils__['cloud.bootstrap'](vm_, __opts__) ret.update(data) log.info('Created Cloud VM \'%s\'', vm_['name']) log.debug('\'%s\' VM creation details:\n%s', vm_['name'], pprint.pformat(data)) __utils__['cloud.fire_event']( 'event', 'created instance', 'salt/cloud/{0}/created'.format(vm_['name']), args=__utils__['cloud.filter_event']( 'created', vm_, ['name', 'profile', 'provider', 'driver']), sock_dir=__opts__['sock_dir'], transport=__opts__['transport']) return ret
def create(vm_): ''' Create a single VM from a data dict ''' try: # Check for required profile parameters before sending any API calls. if config.is_profile_configured(__opts__, __active_provider_name__ or 'aliyun', vm_['profile']) is False: return False except AttributeError: pass # Since using "provider: <provider-engine>" is deprecated, alias provider # to use driver: "driver: <provider-engine>" if 'provider' in vm_: vm_['driver'] = vm_.pop('provider') salt.utils.cloud.fire_event( 'event', 'starting create', 'salt/cloud/{0}/creating'.format(vm_['name']), { 'name': vm_['name'], 'profile': vm_['profile'], 'provider': vm_['driver'], }, transport=__opts__['transport'] ) log.info('Creating Cloud VM {0}'.format(vm_['name'])) kwargs = { 'name': vm_['name'], 'size_id': get_size(vm_), 'image_id': get_image(vm_), 'region_id': __get_location(vm_), 'securitygroup_id': get_securitygroup(vm_), } salt.utils.cloud.fire_event( 'event', 'requesting instance', 'salt/cloud/{0}/requesting'.format(vm_['name']), {'kwargs': kwargs}, transport=__opts__['transport'] ) try: ret = create_node(kwargs) except Exception as exc: log.error( 'Error creating {0} on Aliyun ECS\n\n' 'The following exception was thrown when trying to ' 'run the initial deployment: {1}'.format( vm_['name'], str(exc) ), # Show the traceback if the debug logging level is enabled exc_info_on_loglevel=logging.DEBUG ) return False def __query_node_data(vm_name): data = show_instance(vm_name, call='action') if not data: # Trigger an error in the wait_for_ip function return False if data.get('PublicIpAddress', None) is not None: return data try: data = salt.utils.cloud.wait_for_ip( __query_node_data, update_args=(vm_['name'],), timeout=config.get_cloud_config_value( 'wait_for_ip_timeout', vm_, __opts__, default=10 * 60), interval=config.get_cloud_config_value( 'wait_for_ip_interval', vm_, __opts__, default=10), ) except (SaltCloudExecutionTimeout, SaltCloudExecutionFailure) as exc: try: # It might be already up, let's destroy it! destroy(vm_['name']) except SaltCloudSystemExit: pass finally: raise SaltCloudSystemExit(str(exc)) public_ip = data['PublicIpAddress'][0] log.debug('VM {0} is now running'.format(public_ip)) vm_['ssh_host'] = public_ip # The instance is booted and accessible, let's Salt it! ret = salt.utils.cloud.bootstrap(vm_, __opts__) ret.update(data.__dict__) log.info('Created Cloud VM {0[name]!r}'.format(vm_)) log.debug( '{0[name]!r} VM creation details:\n{1}'.format( vm_, pprint.pformat(data) ) ) salt.utils.cloud.fire_event( 'event', 'created instance', 'salt/cloud/{0}/created'.format(vm_['name']), { 'name': vm_['name'], 'profile': vm_['profile'], 'provider': vm_['driver'], }, transport=__opts__['transport'] ) return ret
def create(vm_): ''' Create a single instance from a data dict. CLI Examples: .. code-block:: bash salt-cloud -p qingcloud-ubuntu-c1m1 hostname1 salt-cloud -m /path/to/mymap.sls -P ''' try: # Check for required profile parameters before sending any API calls. if vm_['profile'] and config.is_profile_configured( __opts__, __active_provider_name__ or 'qingcloud', vm_['profile']) is False: return False except AttributeError: pass # Since using "provider: <provider-engine>" is deprecated, alias provider # to use driver: "driver: <provider-engine>" if 'provider' in vm_: vm_['driver'] = vm_.pop('provider') salt.utils.cloud.fire_event('event', 'starting create', 'salt/cloud/{0}/creating'.format(vm_['name']), { 'name': vm_['name'], 'profile': vm_['profile'], 'provider': vm_['driver'], }, transport=__opts__['transport']) log.info('Creating Cloud VM {0}'.format(vm_['name'])) # params params = { 'action': 'RunInstances', 'instance_name': vm_['name'], 'zone': _get_location(vm_), 'instance_type': _get_size(vm_), 'image_id': _get_image(vm_), 'vxnets.1': vm_['vxnets'], 'login_mode': vm_['login_mode'], 'login_keypair': vm_['login_keypair'], } salt.utils.cloud.fire_event('event', 'requesting instance', 'salt/cloud/{0}/requesting'.format( vm_['name']), {'kwargs': params}, transport=__opts__['transport']) result = query(params) new_instance_id = result['instances'][0] try: data = salt.utils.cloud.wait_for_ip( _query_node_data, update_args=(new_instance_id, ), timeout=config.get_cloud_config_value('wait_for_ip_timeout', vm_, __opts__, default=10 * 60), interval=config.get_cloud_config_value('wait_for_ip_interval', vm_, __opts__, default=10), ) except (SaltCloudExecutionTimeout, SaltCloudExecutionFailure) as exc: try: # It might be already up, let's destroy it! destroy(vm_['name']) except SaltCloudSystemExit: pass finally: raise SaltCloudSystemExit(str(exc)) private_ip = data['private_ips'][0] log.debug('VM {0} is now running'.format(private_ip)) vm_['ssh_host'] = private_ip # The instance is booted and accessible, let's Salt it! salt.utils.cloud.bootstrap(vm_, __opts__) log.info('Created Cloud VM {0[name]!r}'.format(vm_)) log.debug('{0[name]!r} VM creation details:\n{1}'.format( vm_, pprint.pformat(data))) salt.utils.cloud.fire_event('event', 'created instance', 'salt/cloud/{0}/created'.format(vm_['name']), { 'name': vm_['name'], 'profile': vm_['profile'], 'provider': vm_['driver'], }, transport=__opts__['transport']) return data
def create(vm_): ''' Create a single Linode VM. ''' try: # Check for required profile parameters before sending any API calls. if config.is_profile_configured(__opts__, __active_provider_name__ or 'linode', vm_['profile']) is False: return False except AttributeError: pass # Since using "provider: <provider-engine>" is deprecated, alias provider # to use driver: "driver: <provider-engine>" if 'provider' in vm_: vm_['driver'] = vm_.pop('provider') salt.utils.cloud.fire_event( 'event', 'starting create', 'salt/cloud/{0}/creating'.format(vm_['name']), { 'name': vm_['name'], 'profile': vm_['profile'], 'provider': vm_['driver'], }, transport=__opts__['transport'] ) log.info('Creating Cloud VM {0}'.format(vm_['name'])) data = {} kwargs = { 'name': vm_['name'], 'image': vm_['image'], 'size': vm_['size'], } plan_id = get_plan_id(vm_['size']) try: datacenter_id = get_datacenter_id(vm_['location']) except KeyError: # Linode's default datacenter is Dallas, but we still have to set one to # use the create function from Linode's API. Dallas's datacenter id is 2. datacenter_id = 2 if 'clonefrom' in vm_: linode_id = get_linode_id_from_name(vm_['clonefrom']) clone_source = get_linode(linode_id) kwargs.update({'clonefrom': vm_['clonefrom']}) kwargs['image'] = 'Clone of {0}'.format(vm_['clonefrom']) kwargs['size'] = clone_source['TOTALRAM'] try: result = clone(linode_id, datacenter_id, plan_id) except Exception: log.error( 'Error cloning {0} on Linode\n\n' 'The following exception was thrown by Linode when trying to ' 'clone the specified machine:\n'.format( vm_['clonefrom'] ), exc_info_on_loglevel=logging.DEBUG ) return False else: try: result = _query('linode', 'create', args={ 'PLANID': plan_id, 'DATACENTERID': datacenter_id }) except Exception: log.error( 'Error creating {0} on Linode\n\n' 'The following exception was thrown by Linode when trying to ' 'run the initial deployment:\n'.format( vm_['name'] ), exc_info_on_loglevel=logging.DEBUG ) return False salt.utils.cloud.fire_event( 'event', 'requesting instance', 'salt/cloud/{0}/requesting'.format(vm_['name']), {'kwargs': kwargs}, transport=__opts__['transport'] ) node_id = _clean_data(result)['LinodeID'] data['id'] = node_id if not _wait_for_status(node_id, status=(_get_status_id_by_name('brand_new'))): log.error( 'Error creating {0} on LINODE\n\n' 'while waiting for initial ready status'.format(vm_['name']), exc_info_on_loglevel=logging.DEBUG ) # Update the Linode's Label to reflect the given VM name update_linode(node_id, update_args={'Label': vm_['name']}) log.debug('Set name for {0} - was linode{1}.'.format(vm_['name'], node_id)) # Create disks and get ids log.debug('Creating disks for {0}'.format(vm_['name'])) root_disk_id = create_disk_from_distro(vm_, node_id)['DiskID'] swap_disk_id = create_swap_disk(vm_, node_id)['DiskID'] # Add private IP address if requested if get_private_ip(vm_): create_private_ip(vm_, node_id) # Create a ConfigID using disk ids config_id = create_config(vm_, node_id, root_disk_id, swap_disk_id)['ConfigID'] # Boot the VM and get the JobID from Linode boot_job_id = boot(node_id, config_id)['JobID'] if not _wait_for_job(node_id, boot_job_id): log.error('Boot failed for {0}.'.format(vm_['name'])) return False node_data = get_linode(node_id) ips = get_ips(node_id) state = int(node_data['STATUS']) data['image'] = vm_['image'] data['name'] = node_data['LABEL'] data['size'] = node_data['TOTALRAM'] data['state'] = _get_status_descr_by_id(state) data['private_ips'] = ips['private_ips'] data['public_ips'] = ips['public_ips'] vm_['ssh_host'] = data['public_ips'][0] # If a password wasn't supplied in the profile or provider config, set it now. vm_['password'] = get_password(vm_) # Bootstrap! ret = salt.utils.cloud.bootstrap(vm_, __opts__) ret.update(data) log.info('Created Cloud VM {0[name]!r}'.format(vm_)) log.debug( '{0[name]!r} VM creation details:\n{1}'.format( vm_, pprint.pformat(data) ) ) salt.utils.cloud.fire_event( 'event', 'created instance', 'salt/cloud/{0}/created'.format(vm_['name']), { 'name': vm_['name'], 'profile': vm_['profile'], 'provider': vm_['driver'], }, transport=__opts__['transport'] ) return ret
def create(server_): """ Create a single BareMetal server from a data dict. """ try: # Check for required profile parameters before sending any API calls. if (server_["profile"] and config.is_profile_configured( __opts__, __active_provider_name__ or "scaleway", server_["profile"], vm_=server_, ) is False): return False except AttributeError: pass __utils__["cloud.fire_event"]( "event", "starting create", "salt/cloud/{0}/creating".format(server_["name"]), args=__utils__["cloud.filter_event"]( "creating", server_, ["name", "profile", "provider", "driver"]), sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], ) log.info("Creating a BareMetal server %s", server_["name"]) access_key = config.get_cloud_config_value("access_key", get_configured_provider(), __opts__, search_global=False) commercial_type = config.get_cloud_config_value("commercial_type", server_, __opts__, default="C1") key_filename = config.get_cloud_config_value("ssh_key_file", server_, __opts__, search_global=False, default=None) if key_filename is not None and not os.path.isfile(key_filename): raise SaltCloudConfigError( "The defined key_filename '{0}' does not exist".format( key_filename)) ssh_password = config.get_cloud_config_value("ssh_password", server_, __opts__) kwargs = { "name": server_["name"], "organization": access_key, "image": get_image(server_), "commercial_type": commercial_type, } __utils__["cloud.fire_event"]( "event", "requesting instance", "salt/cloud/{0}/requesting".format(server_["name"]), args={ "kwargs": __utils__["cloud.filter_event"]("requesting", kwargs, list(kwargs)), }, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], ) try: ret = create_node(kwargs) except Exception as exc: # pylint: disable=broad-except log.error( "Error creating %s on Scaleway\n\n" "The following exception was thrown when trying to " "run the initial deployment: %s", server_["name"], exc, # Show the traceback if the debug logging level is enabled exc_info_on_loglevel=logging.DEBUG, ) return False def __query_node_data(server_name): """ Called to check if the server has a public IP address. """ data = show_instance(server_name, "action") if data and data.get("public_ip"): return data return False try: data = salt.utils.cloud.wait_for_ip( __query_node_data, update_args=(server_["name"], ), timeout=config.get_cloud_config_value("wait_for_ip_timeout", server_, __opts__, default=10 * 60), interval=config.get_cloud_config_value("wait_for_ip_interval", server_, __opts__, default=10), ) except (SaltCloudExecutionTimeout, SaltCloudExecutionFailure) as exc: try: # It might be already up, let's destroy it! destroy(server_["name"]) except SaltCloudSystemExit: pass finally: raise SaltCloudSystemExit(six.text_type(exc)) server_["ssh_host"] = data["public_ip"]["address"] server_["ssh_password"] = ssh_password server_["key_filename"] = key_filename ret = __utils__["cloud.bootstrap"](server_, __opts__) ret.update(data) log.info("Created BareMetal server '%s'", server_["name"]) log.debug( "'%s' BareMetal server creation details:\n%s", server_["name"], pprint.pformat(data), ) __utils__["cloud.fire_event"]( "event", "created instance", "salt/cloud/{0}/created".format(server_["name"]), args=__utils__["cloud.filter_event"]( "created", server_, ["name", "profile", "provider", "driver"]), sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], ) return ret
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 'nova', vm_['profile'], vm_=vm_) is False: return False except AttributeError: pass deploy = config.get_cloud_config_value('deploy', vm_, __opts__) key_filename = config.get_cloud_config_value('ssh_key_file', vm_, __opts__, search_global=False, default=None) if key_filename is not None and not os.path.isfile(key_filename): raise SaltCloudConfigError( 'The defined ssh_key_file \'{0}\' does not exist'.format( key_filename)) vm_['key_filename'] = key_filename # Since using "provider: <provider-engine>" is deprecated, alias provider # to use driver: "driver: <provider-engine>" if 'provider' in vm_: vm_['driver'] = vm_.pop('provider') salt.utils.cloud.fire_event('event', 'starting create', 'salt/cloud/{0}/creating'.format(vm_['name']), { 'name': vm_['name'], 'profile': vm_['profile'], 'provider': vm_['driver'], }, transport=__opts__['transport']) conn = get_conn() if 'instance_id' in vm_: # This was probably created via another process, and doesn't have # things like salt keys created yet, so let's create them now. if 'pub_key' not in vm_ and 'priv_key' not in vm_: log.debug('Generating minion keys for \'{0[name]}\''.format(vm_)) vm_['priv_key'], vm_['pub_key'] = salt.utils.cloud.gen_keys( salt.config.get_cloud_config_value('keysize', vm_, __opts__)) data = conn.server_show_libcloud(vm_['instance_id']) if vm_['key_filename'] is None and 'change_password' in __opts__ and __opts__[ 'change_password'] is True: vm_['password'] = sup.secure_password() conn.root_password(vm_['instance_id'], vm_['password']) else: # Put together all of the information required to request the instance, # and then fire off the request for it data, vm_ = request_instance(vm_) # Pull the instance ID, valid for both spot and normal instances vm_['instance_id'] = data.id def __query_node_data(vm_, data): try: node = show_instance(vm_['name'], 'action') log.debug('Loaded node data for {0}:\n{1}'.format( vm_['name'], pprint.pformat(node))) except Exception as err: log.error( 'Failed to get nodes list: {0}'.format(err), # Show the traceback if the debug logging level is enabled exc_info_on_loglevel=logging.DEBUG) # Trigger a failure in the wait for IP function return False running = node['state'] == 'ACTIVE' if not running: # Still not running, trigger another iteration return if rackconnect(vm_) is True: extra = node.get('extra', {}) rc_status = extra.get('metadata', {}).get('rackconnect_automation_status', '') if rc_status != 'DEPLOYED': log.debug('Waiting for Rackconnect automation to complete') return if managedcloud(vm_) is True: extra = conn.server_show_libcloud(node['id']).extra mc_status = extra.get('metadata', {}).get('rax_service_level_automation', '') if mc_status != 'Complete': log.debug('Waiting for managed cloud automation to complete') return access_ip = node.get('extra', {}).get('access_ip', '') rcv3 = rackconnectv3(vm_) in node['addresses'] sshif = ssh_interface(vm_) in node['addresses'] if any((rcv3, sshif)): networkname = rackconnectv3(vm_) if rcv3 else ssh_interface(vm_) for network in node['addresses'].get(networkname, []): if network['version'] is 4: access_ip = network['addr'] break vm_['cloudnetwork'] = True # Conditions to pass this # # Rackconnect v2: vm_['rackconnect'] = True # If this is True, then the server will not be accessible from the ipv4 addres in public_ips. # That interface gets turned off, and an ipv4 from the dedicated firewall is routed to the # server. In this case we can use the private_ips for ssh_interface, or the access_ip. # # Rackconnect v3: vm['rackconnectv3'] = <cloudnetwork> # If this is the case, salt will need to use the cloud network to login to the server. There # is no ipv4 address automatically provisioned for these servers when they are booted. SaltCloud # also cannot use the private_ips, because that traffic is dropped at the hypervisor. # # CloudNetwork: vm['cloudnetwork'] = True # If this is True, then we should have an access_ip at this point set to the ip on the cloud # network. If that network does not exist in the 'addresses' dictionary, then SaltCloud will # use the initial access_ip, and not overwrite anything. if any((cloudnetwork(vm_), rackconnect(vm_))) and (ssh_interface(vm_) != 'private_ips' or rcv3) and access_ip != '': data.public_ips = [ access_ip, ] return data result = [] if 'private_ips' not in node and 'public_ips' not in node and \ 'floating_ips' not in node and 'fixed_ips' not in node and \ 'access_ip' in node.get('extra', {}): result = [node['extra']['access_ip']] private = node.get('private_ips', []) public = node.get('public_ips', []) fixed = node.get('fixed_ips', []) floating = node.get('floating_ips', []) if private and not public: log.warning('Private IPs returned, but not public... Checking for ' 'misidentified IPs') for private_ip in private: private_ip = preferred_ip(vm_, [private_ip]) if salt.utils.cloud.is_public_ip(private_ip): log.warning('{0} is a public IP'.format(private_ip)) data.public_ips.append(private_ip) log.warning( ('Public IP address was not ready when we last' ' checked. Appending public IP address now.')) public = data.public_ips else: log.warning('{0} is a private IP'.format(private_ip)) ignore_ip = ignore_cidr(vm_, private_ip) if private_ip not in data.private_ips and not ignore_ip: result.append(private_ip) # populate return data with private_ips # when ssh_interface is set to private_ips and public_ips exist if not result and ssh_interface(vm_) == 'private_ips': for private_ip in private: ignore_ip = ignore_cidr(vm_, private_ip) if private_ip not in data.private_ips and not ignore_ip: result.append(private_ip) non_private_ips = [] if public: data.public_ips = public if ssh_interface(vm_) == 'public_ips': non_private_ips.append(public) if floating: data.floating_ips = floating if ssh_interface(vm_) == 'floating_ips': non_private_ips.append(floating) if fixed: data.fixed_ips = fixed if ssh_interface(vm_) == 'fixed_ips': non_private_ips.append(fixed) if non_private_ips: log.debug('result = {0}'.format(non_private_ips)) data.private_ips = result if ssh_interface(vm_) != 'private_ips': return data if result: log.debug('result = {0}'.format(result)) data.private_ips = result if ssh_interface(vm_) == 'private_ips': return data try: data = salt.utils.cloud.wait_for_ip( __query_node_data, update_args=(vm_, data), timeout=config.get_cloud_config_value('wait_for_ip_timeout', vm_, __opts__, default=10 * 60), interval=config.get_cloud_config_value('wait_for_ip_interval', vm_, __opts__, default=10), ) except (SaltCloudExecutionTimeout, SaltCloudExecutionFailure) as exc: try: # It might be already up, let's destroy it! destroy(vm_['name']) except SaltCloudSystemExit: pass finally: raise SaltCloudSystemExit(str(exc)) log.debug('VM is now running') if ssh_interface(vm_) == 'private_ips': ip_address = preferred_ip(vm_, data.private_ips) elif ssh_interface(vm_) == 'fixed_ips': ip_address = preferred_ip(vm_, data.fixed_ips) elif ssh_interface(vm_) == 'floating_ips': ip_address = preferred_ip(vm_, data.floating_ips) else: ip_address = preferred_ip(vm_, data.public_ips) log.debug('Using IP address {0}'.format(ip_address)) if salt.utils.cloud.get_salt_interface(vm_, __opts__) == 'private_ips': salt_ip_address = preferred_ip(vm_, data.private_ips) log.info('Salt interface set to: {0}'.format(salt_ip_address)) elif salt.utils.cloud.get_salt_interface(vm_, __opts__) == 'fixed_ips': salt_ip_address = preferred_ip(vm_, data.fixed_ips) log.info('Salt interface set to: {0}'.format(salt_ip_address)) elif salt.utils.cloud.get_salt_interface(vm_, __opts__) == 'floating_ips': salt_ip_address = preferred_ip(vm_, data.floating_ips) log.info('Salt interface set to: {0}'.format(salt_ip_address)) else: salt_ip_address = preferred_ip(vm_, data.public_ips) log.debug('Salt interface set to: {0}'.format(salt_ip_address)) if not ip_address: raise SaltCloudSystemExit('A valid IP address was not found') vm_['ssh_host'] = ip_address vm_['salt_host'] = salt_ip_address ret = salt.utils.cloud.bootstrap(vm_, __opts__) ret.update(data.__dict__) if 'password' in ret['extra']: del ret['extra']['password'] log.info('Created Cloud VM \'{0[name]}\''.format(vm_)) log.debug('\'{0[name]}\' VM creation details:\n{1}'.format( vm_, pprint.pformat(data.__dict__))) event_data = { 'name': vm_['name'], 'profile': vm_['profile'], 'provider': vm_['driver'], 'instance_id': vm_['instance_id'], 'floating_ips': data.floating_ips, 'fixed_ips': data.fixed_ips, 'private_ips': data.private_ips, 'public_ips': data.public_ips } salt.utils.cloud.fire_event('event', 'created instance', 'salt/cloud/{0}/created'.format(vm_['name']), event_data, transport=__opts__['transport']) salt.utils.cloud.cachedir_index_add(vm_['name'], vm_['profile'], 'nova', vm_['driver']) return ret
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 'oneandone'), vm_['profile']) is False): return False except AttributeError: pass data = None conn = get_conn() hdds = [] # Assemble the composite server object. server = _get_server(vm_) if not bool(server.specs['hardware']['fixed_instance_size_id'])\ and not bool(server.specs['server_type'] == 'baremetal'): # Assemble the hdds object. hdds = _get_hdds(vm_) __utils__['cloud.fire_event']( 'event', 'requesting instance', 'salt/cloud/{0}/requesting'.format(vm_['name']), args={'name': vm_['name']}, sock_dir=__opts__['sock_dir'], transport=__opts__['transport'] ) try: data = conn.create_server(server=server, hdds=hdds) _wait_for_completion(conn, get_wait_timeout(vm_), data['id']) except Exception as exc: # pylint: disable=W0703 log.error( 'Error creating %s on 1and1\n\n' 'The following exception was thrown by the 1and1 library ' 'when trying to run the initial deployment: \n%s', vm_['name'], exc, exc_info_on_loglevel=logging.DEBUG ) return False vm_['server_id'] = data['id'] password = data['first_password'] def __query_node_data(vm_, data): ''' Query node data until node becomes available. ''' running = False try: data = show_instance(vm_['name'], 'action') if not data: return False log.debug( 'Loaded node data for %s:\nname: %s\nstate: %s', vm_['name'], pprint.pformat(data['name']), data['status']['state'] ) except Exception as err: log.error( 'Failed to get nodes list: %s', err, # Show the trackback if the debug logging level is enabled exc_info_on_loglevel=logging.DEBUG ) # Trigger a failure in the wait for IP function return False running = data['status']['state'].lower() == 'powered_on' if not running: # Still not running, trigger another iteration return vm_['ssh_host'] = data['ips'][0]['ip'] return data try: data = salt.utils.cloud.wait_for_ip( __query_node_data, update_args=(vm_, data), timeout=config.get_cloud_config_value( 'wait_for_ip_timeout', vm_, __opts__, default=10 * 60), interval=config.get_cloud_config_value( 'wait_for_ip_interval', vm_, __opts__, default=10), ) except (SaltCloudExecutionTimeout, SaltCloudExecutionFailure) as exc: try: # It might be already up, let's destroy it! destroy(vm_['name']) except SaltCloudSystemExit: pass finally: raise SaltCloudSystemExit(six.text_type(exc.message)) log.debug('VM is now running') log.info('Created Cloud VM %s', vm_) log.debug('%s VM creation details:\n%s', vm_, pprint.pformat(data)) __utils__['cloud.fire_event']( 'event', 'created instance', 'salt/cloud/{0}/created'.format(vm_['name']), args={ 'name': vm_['name'], 'profile': vm_['profile'], 'provider': vm_['driver'], }, sock_dir=__opts__['sock_dir'], transport=__opts__['transport'] ) if 'ssh_host' in vm_: vm_['password'] = password vm_['key_filename'] = get_key_filename(vm_) ret = __utils__['cloud.bootstrap'](vm_, __opts__) ret.update(data) return ret else: raise SaltCloudSystemExit('A valid IP address was not found.')
def create(vm_): ''' Create a single VM from a data dict ''' try: # Check for required profile parameters before sending any API calls. if config.is_profile_configured(__opts__, __active_provider_name__ or 'softlayer', vm_['profile']) is False: return False except AttributeError: pass # Since using "provider: <provider-engine>" is deprecated, alias provider # to use driver: "driver: <provider-engine>" if 'provider' in vm_: vm_['driver'] = vm_.pop('provider') salt.utils.cloud.fire_event( 'event', 'starting create', 'salt/cloud/{0}/creating'.format(vm_['name']), { 'name': vm_['name'], 'profile': vm_['profile'], 'provider': vm_['driver'], }, transport=__opts__['transport'] ) log.info('Creating Cloud VM {0}'.format(vm_['name'])) conn = get_conn() kwargs = { 'hostname': vm_['name'], 'domain': vm_['domain'], 'startCpus': vm_['cpu_number'], 'maxMemory': vm_['ram'], 'localDiskFlag': vm_['local_disk'], 'hourlyBillingFlag': vm_['hourly_billing'], } if 'image' in vm_: kwargs['operatingSystemReferenceCode'] = vm_['image'] kwargs['blockDevices'] = [{ 'device': '0', 'diskImage': {'capacity': vm_['disk_size']}, }] 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, } } 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) }] salt.utils.cloud.fire_event( 'event', 'requesting instance', 'salt/cloud/{0}/requesting'.format(vm_['name']), {'kwargs': kwargs}, transport=__opts__['transport'] ) try: response = conn.createObject(kwargs) except Exception as exc: log.error( 'Error creating {0} on SoftLayer\n\n' 'The following exception was thrown when trying to ' 'run the initial deployment: \n{1}'.format( vm_['name'], str(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: ip_type = 'primaryBackendIpAddress' def wait_for_ip(): ''' Wait for the IP address to become available ''' nodes = list_nodes_full() if ip_type in nodes[vm_['name']]: return nodes[vm_['name']][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(vm_['name'], 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']: if 'passwords' in node['operatingSystem'] and len(node['operatingSystem']['passwords']) > 0: 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 = salt.utils.cloud.bootstrap(vm_, __opts__) ret.update(response) salt.utils.cloud.fire_event( 'event', 'created instance', 'salt/cloud/{0}/created'.format(vm_['name']), { 'name': vm_['name'], 'profile': vm_['profile'], 'provider': vm_['driver'], }, transport=__opts__['transport'] ) return ret
def create(vm_): """ Create a single VM from a data dict CLI Example: .. code-block:: bash salt-cloud -p profile_name vm_name """ try: # Check for required profile parameters before sending any API calls. if (vm_["profile"] and config.is_profile_configured( __opts__, __active_provider_name__ or "joyent", vm_["profile"], vm_=vm_) is False): return False except AttributeError: pass key_filename = config.get_cloud_config_value("private_key", vm_, __opts__, search_global=False, default=None) __utils__["cloud.fire_event"]( "event", "starting create", "salt/cloud/{}/creating".format(vm_["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 in %s", vm_["name"], vm_.get("location", DEFAULT_LOCATION)) # added . for fqdn hostnames salt.utils.cloud.check_name(vm_["name"], "a-zA-Z0-9-.") kwargs = { "name": vm_["name"], "image": get_image(vm_), "size": get_size(vm_), "location": vm_.get("location", DEFAULT_LOCATION), } # Let's not assign a default here; only assign a network value if # one is explicitly configured if "networks" in vm_: kwargs["networks"] = vm_.get("networks") __utils__["cloud.fire_event"]( "event", "requesting instance", "salt/cloud/{}/requesting".format(vm_["name"]), args={ "kwargs": __utils__["cloud.filter_event"]("requesting", kwargs, list(kwargs)), }, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], ) data = create_node(**kwargs) if data == {}: log.error("Error creating %s on JOYENT", vm_["name"]) return False query_instance(vm_) data = show_instance(vm_["name"], call="action") vm_["key_filename"] = key_filename vm_["ssh_host"] = data[1]["primaryIp"] __utils__["cloud.bootstrap"](vm_, __opts__) __utils__["cloud.fire_event"]( "event", "created instance", "salt/cloud/{}/created".format(vm_["name"]), args=__utils__["cloud.filter_event"]( "created", vm_, ["name", "profile", "provider", "driver"]), sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], ) return data[1]
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 'rackspace', vm_['profile'], vm_=vm_) is False: return False except AttributeError: pass # Since using "provider: <provider-engine>" is deprecated, alias provider # to use driver: "driver: <provider-engine>" if 'provider' in vm_: vm_['driver'] = vm_.pop('provider') __utils__['cloud.fire_event']( 'event', 'starting create', 'salt/cloud/{0}/creating'.format(vm_['name']), args={ 'name': vm_['name'], 'profile': vm_['profile'], 'provider': vm_['driver'], }, sock_dir=__opts__['sock_dir'], transport=__opts__['transport'] ) log.info('Creating Cloud VM {0}'.format(vm_['name'])) conn = get_conn() kwargs = { 'name': vm_['name'], 'image': get_image(conn, vm_), 'size': get_size(conn, vm_) } __utils__['cloud.fire_event']( 'event', 'requesting instance', 'salt/cloud/{0}/requesting'.format(vm_['name']), args={ 'kwargs': { 'name': kwargs['name'], 'image': kwargs['image'].name, 'size': kwargs['size'].name, } }, sock_dir=__opts__['sock_dir'], transport=__opts__['transport'] ) try: data = conn.create_node(**kwargs) except Exception as exc: log.error( 'Error creating {0} on RACKSPACE\n\n' 'The following exception was thrown by libcloud when trying to ' 'run the initial deployment: \n{1}'.format( vm_['name'], exc ), # Show the traceback if the debug logging level is enabled exc_info_on_loglevel=logging.DEBUG ) return False def __query_node_data(vm_, data): running = False try: node = show_instance(vm_['name'], 'action') running = (node['state'] == NodeState.RUNNING) log.debug( 'Loaded node data for {0}:\nname: {1}\nstate: {2}'.format( vm_['name'], pprint.pformat(node['name']), node['state'] ) ) except Exception as err: log.error( 'Failed to get nodes list: {0}'.format( err ), # Show the traceback if the debug logging level is enabled exc_info_on_loglevel=logging.DEBUG ) # Trigger a failure in the wait for IP function return False if not running: # Still not running, trigger another iteration return private = node['private_ips'] public = node['public_ips'] if private and not public: log.warning( 'Private IPs returned, but not public... Checking for ' 'misidentified IPs' ) for private_ip in private: private_ip = preferred_ip(vm_, [private_ip]) if salt.utils.cloud.is_public_ip(private_ip): log.warning('{0} is a public IP'.format(private_ip)) data.public_ips.append(private_ip) else: log.warning('{0} is a private IP'.format(private_ip)) if private_ip not in data.private_ips: data.private_ips.append(private_ip) if ssh_interface(vm_) == 'private_ips' and data.private_ips: return data if private: data.private_ips = private if ssh_interface(vm_) == 'private_ips': return data if public: data.public_ips = public if ssh_interface(vm_) != 'private_ips': return data try: data = salt.utils.cloud.wait_for_ip( __query_node_data, update_args=(vm_, data), timeout=config.get_cloud_config_value( 'wait_for_ip_timeout', vm_, __opts__, default=25 * 60), interval=config.get_cloud_config_value( 'wait_for_ip_interval', vm_, __opts__, default=10), ) except (SaltCloudExecutionTimeout, SaltCloudExecutionFailure) as exc: try: # It might be already up, let's destroy it! destroy(vm_['name']) except SaltCloudSystemExit: pass finally: raise SaltCloudSystemExit(str(exc)) log.debug('VM is now running') if ssh_interface(vm_) == 'private_ips': ip_address = preferred_ip(vm_, data.private_ips) else: ip_address = preferred_ip(vm_, data.public_ips) log.debug('Using IP address {0}'.format(ip_address)) if salt.utils.cloud.get_salt_interface(vm_, __opts__) == 'private_ips': salt_ip_address = preferred_ip(vm_, data.private_ips) log.info('Salt interface set to: {0}'.format(salt_ip_address)) else: salt_ip_address = preferred_ip(vm_, data.public_ips) log.debug('Salt interface set to: {0}'.format(salt_ip_address)) if not ip_address: raise SaltCloudSystemExit( 'No IP addresses could be found.' ) vm_['salt_host'] = salt_ip_address vm_['ssh_host'] = ip_address vm_['password'] = data.extra['password'] ret = __utils__['cloud.bootstrap'](vm_, __opts__) ret.update(data.__dict__) if 'password' in data.extra: del data.extra['password'] log.info('Created Cloud VM \'{0[name]}\''.format(vm_)) log.debug( '\'{0[name]}\' VM creation details:\n{1}'.format( vm_, pprint.pformat(data.__dict__) ) ) __utils__['cloud.fire_event']( 'event', 'created instance', 'salt/cloud/{0}/created'.format(vm_['name']), args={ 'name': vm_['name'], 'profile': vm_['profile'], 'provider': vm_['driver'], }, sock_dir=__opts__['sock_dir'], transport=__opts__['transport'] ) return ret
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 'cloudstack', vm_['profile'], vm_=vm_) is False: return False except AttributeError: pass __utils__['cloud.fire_event']('event', 'starting create', 'salt/cloud/{0}/creating'.format( vm_['name']), { 'name': vm_['name'], 'profile': vm_['profile'], 'provider': vm_['driver'], }, transport=__opts__['transport']) log.info('Creating Cloud VM {0}'.format(vm_['name'])) conn = get_conn() kwargs = { 'name': vm_['name'], 'image': get_image(conn, vm_), 'size': get_size(conn, vm_), 'location': get_location(conn, vm_), 'ex_security_groups': get_security_groups(conn, vm_) } if get_keypair(vm_) is not False: kwargs['ex_keyname'] = get_keypair(vm_) if get_networkid(vm_) is not False: kwargs['networkids'] = get_networkid(vm_) kwargs['networks'] = ( # The only attr that is used is 'id'. CloudStackNetwork(None, None, None, kwargs['networkids'], None, None), ) if get_project(conn, vm_) is not False: kwargs['project'] = get_project(conn, vm_) __utils__['cloud.fire_event']('event', 'requesting instance', 'salt/cloud/{0}/requesting'.format( vm_['name']), { 'kwargs': { 'name': kwargs['name'], 'image': kwargs['image'].name, 'size': kwargs['size'].name } }, transport=__opts__['transport']) displayname = cloudstack_displayname(vm_) if displayname: kwargs['ex_displayname'] = displayname else: kwargs['ex_displayname'] = kwargs['name'] volumes = {} ex_blockdevicemappings = block_device_mappings(vm_) if ex_blockdevicemappings: for ex_blockdevicemapping in ex_blockdevicemappings: if 'VirtualName' not in ex_blockdevicemapping: ex_blockdevicemapping['VirtualName'] = '{0}-{1}'.format( vm_['name'], len(volumes)) __utils__['cloud.fire_event']( 'event', 'requesting volume', 'salt/cloud/{0}/requesting'.format( ex_blockdevicemapping['VirtualName']), { 'kwargs': { 'name': ex_blockdevicemapping['VirtualName'], 'device': ex_blockdevicemapping['DeviceName'], 'size': ex_blockdevicemapping['VolumeSize'] } }, ) try: volumes[ ex_blockdevicemapping['DeviceName']] = conn.create_volume( ex_blockdevicemapping['VolumeSize'], ex_blockdevicemapping['VirtualName']) except Exception as exc: log.error( 'Error creating volume {0} on CLOUDSTACK\n\n' 'The following exception was thrown by libcloud when trying to ' 'requesting a volume: \n{1}'.format( ex_blockdevicemapping['VirtualName'], exc), # Show the traceback if the debug logging level is enabled exc_info_on_loglevel=logging.DEBUG) return False else: ex_blockdevicemapping = {} try: data = conn.create_node(**kwargs) except Exception as exc: log.error( 'Error creating {0} on CLOUDSTACK\n\n' 'The following exception was thrown by libcloud when trying to ' 'run the initial deployment: \n{1}'.format(vm_['name'], str(exc)), # Show the traceback if the debug logging level is enabled exc_info_on_loglevel=logging.DEBUG) return False for device_name in six.iterkeys(volumes): try: conn.attach_volume(data, volumes[device_name], device_name) except Exception as exc: log.error( 'Error attaching volume {0} on CLOUDSTACK\n\n' 'The following exception was thrown by libcloud when trying to ' 'attach a volume: \n{1}'.format( ex_blockdevicemapping.get('VirtualName', 'UNKNOWN'), exc), # Show the traceback if the debug logging level is enabled exc_info=log.isEnabledFor(logging.DEBUG)) return False ssh_username = config.get_cloud_config_value('ssh_username', vm_, __opts__, default='root') vm_['ssh_host'] = get_ip(data) vm_['password'] = data.extra['password'] vm_['key_filename'] = get_key() ret = __utils__['cloud.bootstrap'](vm_, __opts__) ret.update(data.__dict__) if 'password' in data.extra: del data.extra['password'] log.info('Created Cloud VM \'{0[name]}\''.format(vm_)) log.debug('\'{0[name]}\' VM creation details:\n{1}'.format( vm_, pprint.pformat(data.__dict__))) __utils__['cloud.fire_event']('event', 'created instance', 'salt/cloud/{0}/created'.format(vm_['name']), { 'name': vm_['name'], 'profile': vm_['profile'], 'provider': vm_['driver'], }, transport=__opts__['transport']) return ret
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 'dimensiondata', vm_['profile']) is False: return False except AttributeError: pass # Since using "provider: <provider-engine>" is deprecated, alias provider # to use driver: "driver: <provider-engine>" if 'provider' in vm_: vm_['driver'] = vm_.pop('provider') salt.utils.cloud.fire_event( 'event', 'starting create', 'salt/cloud/{0}/creating'.format(vm_['name']), { 'name': vm_['name'], 'profile': vm_['profile'], 'provider': vm_['driver'], }, transport=__opts__['transport'] ) log.info('Creating Cloud VM %s', vm_['name']) conn = get_conn() rootPw = NodeAuthPassword(vm_['auth']) try: location = conn.ex_get_location_by_id(vm_['location']) images = conn.list_images(location=location) image = [x for x in images if x.id == vm_['image']][0] networks = conn.ex_list_network_domains(location=location) network_domain = [y for y in networks if y.name == vm_['network_domain']][0] # Use the first VLAN in the network domain vlan = conn.ex_list_vlans(location=location, network_domain=network_domain)[0] kwargs = { 'name': vm_['name'], 'image': image, 'auth': rootPw, 'ex_description': vm_['description'], 'ex_network_domain': network_domain, 'ex_vlan': vlan, 'ex_is_started': vm_['is_started'] } data = conn.create_node(**kwargs) except Exception as exc: log.error( 'Error creating %s on DIMENSIONDATA\n\n' 'The following exception was thrown by libcloud when trying to ' 'run the initial deployment: \n%s', vm_['name'], exc, exc_info_on_loglevel=logging.DEBUG ) return False def __query_node_data(vm_, data): running = False try: node = show_instance(vm_['name'], 'action') running = (node['state'] == NodeState.RUNNING) log.debug( 'Loaded node data for %s:\nname: %s\nstate: %s', vm_['name'], pprint.pformat(node['name']), node['state'] ) except Exception as err: log.error( 'Failed to get nodes list: %s', err, # Show the traceback if the debug logging level is enabled exc_info_on_loglevel=logging.DEBUG ) # Trigger a failure in the wait for IP function return False if not running: # Still not running, trigger another iteration return private = node['private_ips'] public = node['public_ips'] if private and not public: log.warn( 'Private IPs returned, but not public... Checking for ' 'misidentified IPs' ) for private_ip in private: private_ip = preferred_ip(vm_, [private_ip]) if salt.utils.cloud.is_public_ip(private_ip): log.warn('%s is a public IP', private_ip) data.public_ips.append(private_ip) else: log.warn('%s is a private IP', private_ip) if private_ip not in data.private_ips: data.private_ips.append(private_ip) if ssh_interface(vm_) == 'private_ips' and data.private_ips: return data if private: data.private_ips = private if ssh_interface(vm_) == 'private_ips': return data if public: data.public_ips = public if ssh_interface(vm_) != 'private_ips': return data log.debug('DATA') log.debug(data) try: data = salt.utils.cloud.wait_for_ip( __query_node_data, update_args=(vm_, data), timeout=config.get_cloud_config_value( 'wait_for_ip_timeout', vm_, __opts__, default=25 * 60), interval=config.get_cloud_config_value( 'wait_for_ip_interval', vm_, __opts__, default=30), max_failures=config.get_cloud_config_value( 'wait_for_ip_max_failures', vm_, __opts__, default=60), ) except (SaltCloudExecutionTimeout, SaltCloudExecutionFailure) as exc: try: # It might be already up, let's destroy it! destroy(vm_['name']) except SaltCloudSystemExit: pass finally: raise SaltCloudSystemExit(str(exc)) log.debug('VM is now running') if ssh_interface(vm_) == 'private_ips': ip_address = preferred_ip(vm_, data.private_ips) else: ip_address = preferred_ip(vm_, data.public_ips) log.debug('Using IP address %s', ip_address) if salt.utils.cloud.get_salt_interface(vm_, __opts__) == 'private_ips': salt_ip_address = preferred_ip(vm_, data.private_ips) log.info('Salt interface set to: %s', salt_ip_address) else: salt_ip_address = preferred_ip(vm_, data.public_ips) log.debug('Salt interface set to: %s', salt_ip_address) if not ip_address: raise SaltCloudSystemExit( 'No IP addresses could be found.' ) vm_['salt_host'] = salt_ip_address vm_['ssh_host'] = ip_address vm_['password'] = vm_['auth'] ret = salt.utils.cloud.bootstrap(vm_, __opts__) ret.update(data.__dict__) if 'password' in data.extra: del data.extra['password'] log.info('Created Cloud VM \'{0[name]}\''.format(vm_)) log.debug( '\'{0[name]}\' VM creation details:\n{1}'.format( vm_, pprint.pformat(data.__dict__) ) ) salt.utils.cloud.fire_event( 'event', 'created instance', 'salt/cloud/{0}/created'.format(vm_['name']), { 'name': vm_['name'], 'profile': vm_['profile'], 'provider': vm_['driver'], }, transport=__opts__['transport'] ) return ret
def create(vm_): ''' Create a single VM from a data dict CLI Example: .. code-block:: bash salt-cloud -p profile_name vm_name ''' try: # Check for required profile parameters before sending any API calls. if vm_['profile'] and config.is_profile_configured(__opts__, __active_provider_name__ or 'joyent', vm_['profile'], vm_=vm_) is False: return False except AttributeError: pass key_filename = config.get_cloud_config_value( 'private_key', vm_, __opts__, search_global=False, default=None ) __utils__['cloud.fire_event']( 'event', 'starting create', 'salt/cloud/{0}/creating'.format(vm_['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 in %s', vm_['name'], vm_.get('location', DEFAULT_LOCATION) ) # added . for fqdn hostnames salt.utils.cloud.check_name(vm_['name'], 'a-zA-Z0-9-.') kwargs = { 'name': vm_['name'], 'image': get_image(vm_), 'size': get_size(vm_), 'location': vm_.get('location', DEFAULT_LOCATION) } # Let's not assign a default here; only assign a network value if # one is explicitly configured if 'networks' in vm_: kwargs['networks'] = vm_.get('networks') __utils__['cloud.fire_event']( 'event', 'requesting instance', 'salt/cloud/{0}/requesting'.format(vm_['name']), args={ 'kwargs': __utils__['cloud.filter_event']('requesting', kwargs, list(kwargs)), }, sock_dir=__opts__['sock_dir'], transport=__opts__['transport'] ) data = create_node(**kwargs) if data == {}: log.error('Error creating %s on JOYENT', vm_['name']) return False query_instance(vm_) data = show_instance(vm_['name'], call='action') vm_['key_filename'] = key_filename vm_['ssh_host'] = data[1]['primaryIp'] __utils__['cloud.bootstrap'](vm_, __opts__) __utils__['cloud.fire_event']( 'event', 'created instance', 'salt/cloud/{0}/created'.format(vm_['name']), args=__utils__['cloud.filter_event']('created', vm_, ['name', 'profile', 'provider', 'driver']), sock_dir=__opts__['sock_dir'], transport=__opts__['transport'] ) return data[1]
def create(vm_): """ Create a single VM from a data dict CLI Example: .. code-block:: bash salt-cloud -p proxmox-ubuntu vmhostname """ try: # Check for required profile parameters before sending any API calls. if (vm_["profile"] and config.is_profile_configured( __opts__, _get_active_provider_name() or "proxmox", vm_["profile"], vm_=vm_, ) is False): return False except AttributeError: pass ret = {} __utils__["cloud.fire_event"]( "event", "starting create", "salt/cloud/{}/creating".format(vm_["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", vm_["name"]) if "use_dns" in vm_ and "ip_address" not in vm_: use_dns = vm_["use_dns"] if use_dns: from socket import gethostbyname, gaierror try: ip_address = gethostbyname(str(vm_["name"])) except gaierror: log.debug("Resolving of %s failed", vm_["name"]) else: vm_["ip_address"] = str(ip_address) try: newid = _get_next_vmid() data = create_node(vm_, newid) except Exception as exc: # pylint: disable=broad-except log.error( "Error creating %s on PROXMOX\n\n" "The following exception was thrown when trying to " "run the initial deployment: \n%s", vm_["name"], exc, # Show the traceback if the debug logging level is enabled exc_info_on_loglevel=logging.DEBUG, ) return False ret["creation_data"] = data name = vm_["name"] # hostname which we know if "clone" in vm_ and vm_["clone"] is True: vmid = newid else: vmid = data["vmid"] # vmid which we have received host = data["node"] # host which we have received nodeType = data["technology"] # VM tech (Qemu / OpenVZ) agent_get_ip = vm_.get("agent_get_ip", False) if agent_get_ip is False: # Determine which IP to use in order of preference: if "ip_address" in vm_: ip_address = str(vm_["ip_address"]) elif "public_ips" in data: ip_address = str(data["public_ips"][0]) # first IP elif "private_ips" in data: ip_address = str(data["private_ips"][0]) # first IP else: raise SaltCloudExecutionFailure( "Could not determine an IP address to use") log.debug("Using IP address %s", ip_address) # wait until the vm has been created so we can start it if not wait_for_created(data["upid"], timeout=300): return {"Error": "Unable to create {}, command timed out".format(name)} if vm_.get("clone") is True: _reconfigure_clone(vm_, vmid) # VM has been created. Starting.. if not start(name, vmid, call="action"): log.error("Node %s (%s) failed to start!", name, vmid) raise SaltCloudExecutionFailure # Wait until the VM has fully started log.debug('Waiting for state "running" for vm %s on %s', vmid, host) if not wait_for_state(vmid, "running"): return {"Error": "Unable to start {}, command timed out".format(name)} if agent_get_ip is True: try: ip_address = salt.utils.cloud.wait_for_fun(_find_agent_ip, vm_=vm_, vmid=vmid) except (SaltCloudExecutionTimeout, SaltCloudExecutionFailure) as exc: try: # If VM was created but we can't connect, destroy it. destroy(vm_["name"]) except SaltCloudSystemExit: pass finally: raise SaltCloudSystemExit(str(exc)) log.debug("Using IP address %s", ip_address) ssh_username = config.get_cloud_config_value("ssh_username", vm_, __opts__, default="root") ssh_password = config.get_cloud_config_value( "password", vm_, __opts__, ) ret["ip_address"] = ip_address ret["username"] = ssh_username ret["password"] = ssh_password vm_["ssh_host"] = ip_address vm_["password"] = ssh_password ret = __utils__["cloud.bootstrap"](vm_, __opts__) # Report success! log.info("Created Cloud VM '%s'", vm_["name"]) log.debug("'%s' VM creation details:\n%s", vm_["name"], pprint.pformat(data)) __utils__["cloud.fire_event"]( "event", "created instance", "salt/cloud/{}/created".format(vm_["name"]), args=__utils__["cloud.filter_event"]( "created", vm_, ["name", "profile", "provider", "driver"]), sock_dir=__opts__["sock_dir"], ) return ret
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 "aliyun", vm_["profile"], vm_=vm_) is False): return False except AttributeError: pass __utils__["cloud.fire_event"]( "event", "starting create", "salt/cloud/{}/creating".format(vm_["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", vm_["name"]) kwargs = { "name": vm_["name"], "size_id": get_size(vm_), "image_id": get_image(vm_), "region_id": __get_location(vm_), "securitygroup_id": get_securitygroup(vm_), } if "vswitch_id" in vm_: kwargs["VSwitchId"] = vm_["vswitch_id"] if "internet_chargetype" in vm_: kwargs["InternetChargeType"] = vm_["internet_chargetype"] if "internet_maxbandwidthin" in vm_: kwargs["InternetMaxBandwidthIn"] = str(vm_["internet_maxbandwidthin"]) if "internet_maxbandwidthout" in vm_: kwargs["InternetMaxBandwidthOut"] = str( vm_["internet_maxbandwidthOut"]) if "hostname" in vm_: kwargs["HostName"] = vm_["hostname"] if "password" in vm_: kwargs["Password"] = vm_["password"] if "instance_name" in vm_: kwargs["InstanceName"] = vm_["instance_name"] if "systemdisk_category" in vm_: kwargs["SystemDisk.Category"] = vm_["systemdisk_category"] __utils__["cloud.fire_event"]( "event", "requesting instance", "salt/cloud/{}/requesting".format(vm_["name"]), args=__utils__["cloud.filter_event"]("requesting", kwargs, list(kwargs)), sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], ) try: ret = create_node(kwargs) except Exception as exc: # pylint: disable=broad-except log.error( "Error creating %s on Aliyun ECS\n\n" "The following exception was thrown when trying to " "run the initial deployment: %s", vm_["name"], str(exc), # Show the traceback if the debug logging level is enabled exc_info_on_loglevel=logging.DEBUG, ) return False # repair ip address error and start vm time.sleep(8) params = {"Action": "StartInstance", "InstanceId": ret} query(params) def __query_node_data(vm_name): data = show_instance(vm_name, call="action") if not data: # Trigger an error in the wait_for_ip function return False if data.get("PublicIpAddress", None) is not None: return data try: data = salt.utils.cloud.wait_for_ip( __query_node_data, update_args=(vm_["name"], ), timeout=config.get_cloud_config_value("wait_for_ip_timeout", vm_, __opts__, default=10 * 60), interval=config.get_cloud_config_value("wait_for_ip_interval", vm_, __opts__, default=10), ) except (SaltCloudExecutionTimeout, SaltCloudExecutionFailure) as exc: try: # It might be already up, let's destroy it! destroy(vm_["name"]) except SaltCloudSystemExit: pass finally: raise SaltCloudSystemExit(str(exc)) if data["public_ips"]: ssh_ip = data["public_ips"][0] elif data["private_ips"]: ssh_ip = data["private_ips"][0] else: log.info("No available ip:cant connect to salt") return False log.debug("VM %s is now running", ssh_ip) vm_["ssh_host"] = ssh_ip # The instance is booted and accessible, let's Salt it! ret = __utils__["cloud.bootstrap"](vm_, __opts__) ret.update(data) log.info("Created Cloud VM '%s'", vm_["name"]) log.debug("'%s' VM creation details:\n%s", vm_["name"], pprint.pformat(data)) __utils__["cloud.fire_event"]( "event", "created instance", "salt/cloud/{}/created".format(vm_["name"]), args=__utils__["cloud.filter_event"]( "created", vm_, ["name", "profile", "provider", "driver"]), sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], ) return ret
def create(vm_): ''' Create a single VM from a data dict ''' try: # Check for required profile parameters before sending any API calls. if config.is_profile_configured(__opts__, __active_provider_name__ or 'rackspace', vm_['profile']) is False: return False except AttributeError: pass deploy = config.get_cloud_config_value('deploy', vm_, __opts__) salt.utils.cloud.fire_event( 'event', 'starting create', 'salt/cloud/{0}/creating'.format(vm_['name']), { 'name': vm_['name'], 'profile': vm_['profile'], 'provider': vm_['provider'], }, transport=__opts__['transport'] ) log.info('Creating Cloud VM {0}'.format(vm_['name'])) conn = get_conn() kwargs = { 'name': vm_['name'], 'image': get_image(conn, vm_), 'size': get_size(conn, vm_) } salt.utils.cloud.fire_event( 'event', 'requesting instance', 'salt/cloud/{0}/requesting'.format(vm_['name']), {'kwargs': {'name': kwargs['name'], 'image': kwargs['image'].name, 'size': kwargs['size'].name}}, transport=__opts__['transport'] ) try: data = conn.create_node(**kwargs) except Exception as exc: log.error( 'Error creating {0} on RACKSPACE\n\n' 'The following exception was thrown by libcloud when trying to ' 'run the initial deployment: \n{1}'.format( vm_['name'], exc ), # Show the traceback if the debug logging level is enabled exc_info_on_loglevel=logging.DEBUG ) return False def __query_node_data(vm_, data): running = False try: node = show_instance(vm_['name'], 'action') running = (node['state'] == NodeState.RUNNING) log.debug( 'Loaded node data for {0}:\nname: {1}\nstate: {2}'.format( vm_['name'], pprint.pformat(node['name']), node['state'] ) ) except Exception as err: log.error( 'Failed to get nodes list: {0}'.format( err ), # Show the traceback if the debug logging level is enabled exc_info_on_loglevel=logging.DEBUG ) # Trigger a failure in the wait for IP function return False if not running: # Still not running, trigger another iteration return private = node['private_ips'] public = node['public_ips'] if private and not public: log.warn( 'Private IPs returned, but not public... Checking for ' 'misidentified IPs' ) for private_ip in private: private_ip = preferred_ip(vm_, [private_ip]) if salt.utils.cloud.is_public_ip(private_ip): log.warn('{0} is a public IP'.format(private_ip)) data.public_ips.append(private_ip) else: log.warn('{0} is a private IP'.format(private_ip)) if private_ip not in data.private_ips: data.private_ips.append(private_ip) if ssh_interface(vm_) == 'private_ips' and data.private_ips: return data if private: data.private_ips = private if ssh_interface(vm_) == 'private_ips': return data if public: data.public_ips = public if ssh_interface(vm_) != 'private_ips': return data try: data = salt.utils.cloud.wait_for_ip( __query_node_data, update_args=(vm_, data), timeout=config.get_cloud_config_value( 'wait_for_ip_timeout', vm_, __opts__, default=25 * 60), interval=config.get_cloud_config_value( 'wait_for_ip_interval', vm_, __opts__, default=10), ) except (SaltCloudExecutionTimeout, SaltCloudExecutionFailure) as exc: try: # It might be already up, let's destroy it! destroy(vm_['name']) except SaltCloudSystemExit: pass finally: raise SaltCloudSystemExit(str(exc)) log.debug('VM is now running') if ssh_interface(vm_) == 'private_ips': ip_address = preferred_ip(vm_, data.private_ips) else: ip_address = preferred_ip(vm_, data.public_ips) log.debug('Using IP address {0}'.format(ip_address)) if salt.utils.cloud.get_salt_interface(vm_, __opts__) == 'private_ips': salt_ip_address = preferred_ip(vm_, data.private_ips) log.info('Salt interface set to: {0}'.format(salt_ip_address)) else: salt_ip_address = preferred_ip(vm_, data.public_ips) log.debug('Salt interface set to: {0}'.format(salt_ip_address)) if not ip_address: raise SaltCloudSystemExit( 'No IP addresses could be found.' ) ssh_username = config.get_cloud_config_value( 'ssh_username', vm_, __opts__, default='root' ) ret = {} if deploy is True: deploy_script = script(vm_) deploy_kwargs = { 'opts': __opts__, 'host': ip_address, 'salt_host': salt_ip_address, 'username': ssh_username, 'password': data.extra['password'], 'script': deploy_script.script, 'name': vm_['name'], 'tmp_dir': config.get_cloud_config_value( 'tmp_dir', vm_, __opts__, default='/tmp/.saltcloud' ), 'deploy_command': config.get_cloud_config_value( 'deploy_command', vm_, __opts__, default='/tmp/.saltcloud/deploy.sh', ), 'start_action': __opts__['start_action'], 'parallel': __opts__['parallel'], 'sock_dir': __opts__['sock_dir'], 'conf_file': __opts__['conf_file'], 'minion_pem': vm_['priv_key'], 'minion_pub': vm_['pub_key'], 'keep_tmp': __opts__['keep_tmp'], 'preseed_minion_keys': vm_.get('preseed_minion_keys', None), 'sudo': config.get_cloud_config_value( 'sudo', vm_, __opts__, default=(ssh_username != 'root') ), 'sudo_password': config.get_cloud_config_value( 'sudo_password', vm_, __opts__, default=None ), 'tty': config.get_cloud_config_value( 'tty', vm_, __opts__, default=False ), 'display_ssh_output': config.get_cloud_config_value( 'display_ssh_output', vm_, __opts__, default=True ), 'script_args': config.get_cloud_config_value( 'script_args', vm_, __opts__ ), 'script_env': config.get_cloud_config_value('script_env', vm_, __opts__), 'minion_conf': salt.utils.cloud.minion_config(__opts__, vm_) } # Deploy salt-master files, if necessary if config.get_cloud_config_value('make_master', vm_, __opts__) is True: deploy_kwargs['make_master'] = True deploy_kwargs['master_pub'] = vm_['master_pub'] deploy_kwargs['master_pem'] = vm_['master_pem'] master_conf = salt.utils.cloud.master_config(__opts__, vm_) deploy_kwargs['master_conf'] = master_conf if master_conf.get('syndic_master', None): deploy_kwargs['make_syndic'] = True deploy_kwargs['make_minion'] = config.get_cloud_config_value( 'make_minion', vm_, __opts__, default=True ) # Check for Windows install params win_installer = config.get_cloud_config_value('win_installer', vm_, __opts__) if win_installer: deploy_kwargs['win_installer'] = win_installer minion = salt.utils.cloud.minion_config(__opts__, vm_) deploy_kwargs['master'] = minion['master'] deploy_kwargs['username'] = config.get_cloud_config_value( 'win_username', vm_, __opts__, default='Administrator' ) win_pass = config.get_cloud_config_value( 'win_password', vm_, __opts__, default='' ) if win_pass: deploy_kwargs['password'] = win_pass # Store what was used to the deploy the VM event_kwargs = copy.deepcopy(deploy_kwargs) del event_kwargs['minion_pem'] del event_kwargs['minion_pub'] del event_kwargs['sudo_password'] if 'password' in event_kwargs: del event_kwargs['password'] ret['deploy_kwargs'] = event_kwargs salt.utils.cloud.fire_event( 'event', 'executing deploy script', 'salt/cloud/{0}/deploying'.format(vm_['name']), {'kwargs': event_kwargs}, transport=__opts__['transport'] ) if win_installer: deployed = salt.utils.cloud.deploy_windows(**deploy_kwargs) else: deployed = salt.utils.cloud.deploy_script(**deploy_kwargs) if deployed: log.info('Salt installed on {0}'.format(vm_['name'])) else: log.error( 'Failed to deploy and start Salt on Cloud VM {0}'.format( vm_['name'] ) ) ret.update(data.__dict__) if 'password' in data.extra: del data.extra['password'] log.info('Created Cloud VM {0[name]!r}'.format(vm_)) log.debug( '{0[name]!r} VM creation details:\n{1}'.format( vm_, pprint.pformat(data.__dict__) ) ) salt.utils.cloud.fire_event( 'event', 'created instance', 'salt/cloud/{0}/created'.format(vm_['name']), { 'name': vm_['name'], 'profile': vm_['profile'], 'provider': vm_['provider'], }, transport=__opts__['transport'] ) return ret
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 'nova', vm_['profile']) is False: return False except AttributeError: pass deploy = config.get_cloud_config_value('deploy', vm_, __opts__) key_filename = config.get_cloud_config_value( 'ssh_key_file', vm_, __opts__, search_global=False, default=None ) if key_filename is not None and not os.path.isfile(key_filename): raise SaltCloudConfigError( 'The defined ssh_key_file \'{0}\' does not exist'.format( key_filename ) ) vm_['key_filename'] = key_filename # Since using "provider: <provider-engine>" is deprecated, alias provider # to use driver: "driver: <provider-engine>" if 'provider' in vm_: vm_['driver'] = vm_.pop('provider') salt.utils.cloud.fire_event( 'event', 'starting create', 'salt/cloud/{0}/creating'.format(vm_['name']), { 'name': vm_['name'], 'profile': vm_['profile'], 'provider': vm_['driver'], }, transport=__opts__['transport'] ) conn = get_conn() if 'instance_id' in vm_: # This was probably created via another process, and doesn't have # things like salt keys created yet, so let's create them now. if 'pub_key' not in vm_ and 'priv_key' not in vm_: log.debug('Generating minion keys for \'{0[name]}\''.format(vm_)) vm_['priv_key'], vm_['pub_key'] = salt.utils.cloud.gen_keys( salt.config.get_cloud_config_value( 'keysize', vm_, __opts__ ) ) data = conn.server_show_libcloud(vm_['instance_id']) if vm_['key_filename'] is None and 'change_password' in __opts__ and __opts__['change_password'] is True: vm_['password'] = sup.secure_password() conn.root_password(vm_['instance_id'], vm_['password']) else: # Put together all of the information required to request the instance, # and then fire off the request for it data, vm_ = request_instance(vm_) # Pull the instance ID, valid for both spot and normal instances vm_['instance_id'] = data.id def __query_node_data(vm_, data): try: node = show_instance(vm_['name'], 'action') log.debug( 'Loaded node data for {0}:\n{1}'.format( vm_['name'], pprint.pformat(node) ) ) except Exception as err: log.error( 'Failed to get nodes list: {0}'.format( err ), # Show the traceback if the debug logging level is enabled exc_info_on_loglevel=logging.DEBUG ) # Trigger a failure in the wait for IP function return False running = node['state'] == 'ACTIVE' if not running: # Still not running, trigger another iteration return rackconnectv3 = config.get_cloud_config_value( 'rackconnectv3', vm_, __opts__, default=False, search_global=False ) if rackconnectv3: networkname = rackconnectv3 for network in node['addresses'].get(networkname, []): if network['version'] is 4: access_ip = network['addr'] break vm_['rackconnect'] = True if ssh_interface(vm_) in node['addresses']: networkname = ssh_interface(vm_) for network in node['addresses'].get(networkname, []): if network['version'] is 4: node['extra']['access_ip'] = network['addr'] break vm_['cloudnetwork'] = True if rackconnect(vm_) is True: extra = node.get('extra', {}) rc_status = extra.get('metadata', {}).get( 'rackconnect_automation_status', '') access_ip = extra.get('access_ip', '') if rc_status != 'DEPLOYED' and not rackconnectv3: log.debug('Waiting for Rackconnect automation to complete') return if managedcloud(vm_) is True: extra = conn.server_show_libcloud( node['id'] ).extra mc_status = extra.get('metadata', {}).get( 'rax_service_level_automation', '') if mc_status != 'Complete': log.debug('Waiting for managed cloud automation to complete') return result = [] if 'private_ips' not in node and 'public_ips' not in node and \ 'access_ip' in node.get('extra', {}): result = [node['extra']['access_ip']] private = node.get('private_ips', []) public = node.get('public_ips', []) if private and not public: log.warn( 'Private IPs returned, but not public... Checking for ' 'misidentified IPs' ) for private_ip in private: private_ip = preferred_ip(vm_, [private_ip]) if salt.utils.cloud.is_public_ip(private_ip): log.warn('{0} is a public IP'.format(private_ip)) data.public_ips.append(private_ip) log.warn( ( 'Public IP address was not ready when we last' ' checked. Appending public IP address now.' ) ) public = data.public_ips else: log.warn('{0} is a private IP'.format(private_ip)) ignore_ip = ignore_cidr(vm_, private_ip) if private_ip not in data.private_ips and not ignore_ip: result.append(private_ip) if rackconnect(vm_) is True and (ssh_interface(vm_) != 'private_ips' or rackconnectv3): data.public_ips = access_ip return data # populate return data with private_ips # when ssh_interface is set to private_ips and public_ips exist if not result and ssh_interface(vm_) == 'private_ips': for private_ip in private: ignore_ip = ignore_cidr(vm_, private_ip) if private_ip not in data.private_ips and not ignore_ip: result.append(private_ip) if cloudnetwork(vm_) is True: data.public_ips = access_ip return data if public: data.public_ips = public if ssh_interface(vm_) != 'private_ips': return data if result: log.debug('result = {0}'.format(result)) data.private_ips = result if ssh_interface(vm_) == 'private_ips': return data try: data = salt.utils.cloud.wait_for_ip( __query_node_data, update_args=(vm_, data), timeout=config.get_cloud_config_value( 'wait_for_ip_timeout', vm_, __opts__, default=10 * 60), interval=config.get_cloud_config_value( 'wait_for_ip_interval', vm_, __opts__, default=10), ) except (SaltCloudExecutionTimeout, SaltCloudExecutionFailure) as exc: try: # It might be already up, let's destroy it! destroy(vm_['name']) except SaltCloudSystemExit: pass finally: raise SaltCloudSystemExit(str(exc)) log.debug('VM is now running') if ssh_interface(vm_) == 'private_ips': ip_address = preferred_ip(vm_, data.private_ips) elif rackconnect(vm_) is True and ssh_interface(vm_) != 'private_ips': ip_address = data.public_ips else: ip_address = preferred_ip(vm_, data.public_ips) log.debug('Using IP address {0}'.format(ip_address)) if salt.utils.cloud.get_salt_interface(vm_, __opts__) == 'private_ips': salt_ip_address = preferred_ip(vm_, data.private_ips) log.info('Salt interface set to: {0}'.format(salt_ip_address)) elif rackconnect(vm_) is True and salt.utils.cloud.get_salt_interface(vm_, __opts__) != 'private_ips': salt_ip_address = data.public_ips else: salt_ip_address = preferred_ip(vm_, data.public_ips) log.debug('Salt interface set to: {0}'.format(salt_ip_address)) if not ip_address: raise SaltCloudSystemExit('A valid IP address was not found') vm_['ssh_host'] = ip_address vm_['salt_host'] = salt_ip_address ret = salt.utils.cloud.bootstrap(vm_, __opts__) ret.update(data.__dict__) if 'password' in ret['extra']: del ret['extra']['password'] log.info('Created Cloud VM \'{0[name]}\''.format(vm_)) log.debug( '\'{0[name]}\' VM creation details:\n{1}'.format( vm_, pprint.pformat(data) ) ) salt.utils.cloud.fire_event( 'event', 'created instance', 'salt/cloud/{0}/created'.format(vm_['name']), { 'name': vm_['name'], 'profile': vm_['profile'], 'provider': vm_['driver'], }, transport=__opts__['transport'] ) return ret
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 'gogrid', vm_['profile'], vm_=vm_) is False: return False except AttributeError: pass # Since using "provider: <provider-engine>" is deprecated, alias provider # to use driver: "driver: <provider-engine>" if 'provider' in vm_: vm_['driver'] = vm_.pop('provider') __utils__['cloud.fire_event']( 'event', 'starting create', 'salt/cloud/{0}/creating'.format(vm_['name']), args={ 'name': vm_['name'], 'profile': vm_['profile'], 'provider': vm_['driver'], }, sock_dir=__opts__['sock_dir'], transport=__opts__['transport'] ) if len(vm_['name']) > 20: raise SaltCloudException('VM names must not be longer than 20 characters') log.info('Creating Cloud VM {0}'.format(vm_['name'])) image_id = avail_images()[vm_['image']]['id'] if 'assign_public_ip' in vm_: host_ip = vm_['assign_public_ip'] else: public_ips = list_public_ips() if len(public_ips.keys()) < 1: raise SaltCloudException('No more IPs available') host_ip = public_ips.keys()[0] create_kwargs = { 'name': vm_['name'], 'image': image_id, 'ram': vm_['size'], 'ip': host_ip, } __utils__['cloud.fire_event']( 'event', 'requesting instance', 'salt/cloud/{0}/requesting'.format(vm_['name']), args={'kwargs': create_kwargs}, sock_dir=__opts__['sock_dir'], transport=__opts__['transport'] ) try: data = _query('grid', 'server/add', args=create_kwargs) except Exception: log.error( 'Error creating {0} on GOGRID\n\n' 'The following exception was thrown when trying to ' 'run the initial deployment:\n'.format( vm_['name'] ), # Show the traceback if the debug logging level is enabled exc_info_on_loglevel=logging.DEBUG ) return False ssh_username = config.get_cloud_config_value( 'ssh_username', vm_, __opts__, default='root' ) def wait_for_apipass(): ''' Wait for the password to become available, via the API ''' try: passwords = list_passwords() return passwords[vm_['name']][0]['password'] except KeyError: pass time.sleep(5) return False vm_['password'] = salt.utils.cloud.wait_for_fun( wait_for_apipass, timeout=config.get_cloud_config_value( 'wait_for_fun_timeout', vm_, __opts__, default=15 * 60), ) vm_['ssh_host'] = host_ip ret = __utils__['cloud.bootstrap'](vm_, __opts__) ret.update(data) log.info('Created Cloud VM \'{0[name]}\''.format(vm_)) log.debug( '\'{0[name]}\' VM creation details:\n{1}'.format( vm_, pprint.pformat(data) ) ) __utils__['cloud.fire_event']( 'event', 'created instance', 'salt/cloud/{0}/created'.format(vm_['name']), args={ 'name': vm_['name'], 'profile': vm_['profile'], 'provider': vm_['driver'], }, sock_dir=__opts__['sock_dir'], transport=__opts__['transport'] ) return ret
def create(vm_): ''' Create a single Linode VM. ''' name = vm_['name'] try: # Check for required profile parameters before sending any API calls. if vm_['profile'] and config.is_profile_configured( __opts__, __active_provider_name__ or 'linode', vm_['profile'], vm_=vm_) is False: return False except AttributeError: pass # Since using "provider: <provider-engine>" is deprecated, alias provider # to use driver: "driver: <provider-engine>" if 'provider' in vm_: vm_['driver'] = vm_.pop('provider') if _validate_name(name) is False: return False __utils__['cloud.fire_event']('event', 'starting create', 'salt/cloud/{0}/creating'.format(name), args={ 'name': name, 'profile': vm_['profile'], 'provider': vm_['driver'], }, sock_dir=__opts__['sock_dir'], transport=__opts__['transport']) log.info('Creating Cloud VM {0}'.format(name)) data = {} kwargs = {'name': name} plan_id = None size = vm_.get('size') if size: kwargs['size'] = size plan_id = get_plan_id(kwargs={'label': size}) datacenter_id = None location = vm_.get('location') if location: try: datacenter_id = get_datacenter_id(location) except KeyError: # Linode's default datacenter is Dallas, but we still have to set one to # use the create function from Linode's API. Dallas's datacenter id is 2. datacenter_id = 2 clonefrom_name = vm_.get('clonefrom') cloning = True if clonefrom_name else False if cloning: linode_id = get_linode_id_from_name(clonefrom_name) clone_source = get_linode(kwargs={'linode_id': linode_id}) kwargs = { 'clonefrom': clonefrom_name, 'image': 'Clone of {0}'.format(clonefrom_name), } if size is None: size = clone_source['TOTALRAM'] kwargs['size'] = size plan_id = clone_source['PLANID'] if location is None: datacenter_id = clone_source['DATACENTERID'] # Create new Linode from cloned Linode try: result = clone( kwargs={ 'linode_id': linode_id, 'datacenter_id': datacenter_id, 'plan_id': plan_id }) except Exception as err: log.error( 'Error cloning \'{0}\' on Linode.\n\n' 'The following exception was thrown by Linode when trying to ' 'clone the specified machine:\n' '{1}'.format(clonefrom_name, err), exc_info_on_loglevel=logging.DEBUG) return False else: kwargs['image'] = vm_['image'] # Create Linode try: result = _query('linode', 'create', args={ 'PLANID': plan_id, 'DATACENTERID': datacenter_id }) except Exception as err: log.error( 'Error creating {0} on Linode\n\n' 'The following exception was thrown by Linode when trying to ' 'run the initial deployment:\n' '{1}'.format(name, err), exc_info_on_loglevel=logging.DEBUG) return False if 'ERRORARRAY' in result: for error_data in result['ERRORARRAY']: log.error('Error creating {0} on Linode\n\n' 'The Linode API returned the following: {1}\n'.format( name, error_data['ERRORMESSAGE'])) return False __utils__['cloud.fire_event']('event', 'requesting instance', 'salt/cloud/{0}/requesting'.format(name), args={ 'kwargs': kwargs }, sock_dir=__opts__['sock_dir'], transport=__opts__['transport']) node_id = _clean_data(result)['LinodeID'] data['id'] = node_id if not _wait_for_status(node_id, status=(_get_status_id_by_name('brand_new'))): log.error('Error creating {0} on LINODE\n\n' 'while waiting for initial ready status'.format(name), exc_info_on_loglevel=logging.DEBUG) # Update the Linode's Label to reflect the given VM name update_linode(node_id, update_args={'Label': name}) log.debug('Set name for {0} - was linode{1}.'.format(name, node_id)) # Add private IP address if requested private_ip_assignment = get_private_ip(vm_) if private_ip_assignment: create_private_ip(node_id) # Define which ssh_interface to use ssh_interface = _get_ssh_interface(vm_) # If ssh_interface is set to use private_ips, but assign_private_ip # wasn't set to True, let's help out and create a private ip. if ssh_interface == 'private_ips' and private_ip_assignment is False: create_private_ip(node_id) private_ip_assignment = True if cloning: config_id = get_config_id(kwargs={'linode_id': node_id})['config_id'] else: # Create disks and get ids log.debug('Creating disks for {0}'.format(name)) root_disk_id = create_disk_from_distro(vm_, node_id)['DiskID'] swap_disk_id = create_swap_disk(vm_, node_id)['DiskID'] # Create a ConfigID using disk ids config_id = create_config( kwargs={ 'name': name, 'linode_id': node_id, 'root_disk_id': root_disk_id, 'swap_disk_id': swap_disk_id })['ConfigID'] # Boot the Linode boot(kwargs={ 'linode_id': node_id, 'config_id': config_id, 'check_running': False }) node_data = get_linode(kwargs={'linode_id': node_id}) ips = get_ips(node_id) state = int(node_data['STATUS']) data['image'] = kwargs['image'] data['name'] = name data['size'] = size data['state'] = _get_status_descr_by_id(state) data['private_ips'] = ips['private_ips'] data['public_ips'] = ips['public_ips'] # Pass the correct IP address to the bootstrap ssh_host key if ssh_interface == 'private_ips': vm_['ssh_host'] = data['private_ips'][0] else: vm_['ssh_host'] = data['public_ips'][0] # If a password wasn't supplied in the profile or provider config, set it now. vm_['password'] = get_password(vm_) # Bootstrap! ret = __utils__['cloud.bootstrap'](vm_, __opts__) ret.update(data) log.info('Created Cloud VM \'{0}\''.format(name)) log.debug('\'{0}\' VM creation details:\n{1}'.format( name, pprint.pformat(data))) __utils__['cloud.fire_event']('event', 'created instance', 'salt/cloud/{0}/created'.format(name), args={ 'name': name, 'profile': vm_['profile'], 'provider': vm_['driver'], }, sock_dir=__opts__['sock_dir'], transport=__opts__['transport']) return ret
def create(vm_info): """ Creates a virtual machine from the given VM information. This is what is used to request a virtual machine to be created by the cloud provider, wait for it to become available, and then (optionally) log in and install Salt on it. Fires: "starting create" : This event is tagged salt/cloud/<vm name>/creating. The payload contains the names of the VM, profile and provider. @param vm_info { name: <str> profile: <dict> driver: <provider>:<profile> clonefrom: <vm_name> } @type vm_info dict @return dict of resulting vm. !!!Passwords can and should be included!!! """ try: # Check for required profile parameters before sending any API calls. if vm_info['profile'] and config.is_profile_configured( __opts__, __active_provider_name__ or 'virtualbox', vm_info['profile'] ) is False: return False except AttributeError: pass vm_name = vm_info["name"] deploy = config.get_cloud_config_value( 'deploy', vm_info, __opts__, search_global=False, default=True ) wait_for_ip_timeout = config.get_cloud_config_value( 'wait_for_ip_timeout', vm_info, __opts__, default=60 ) boot_timeout = config.get_cloud_config_value( 'boot_timeout', vm_info, __opts__, default=60 * 1000 ) power = config.get_cloud_config_value( 'power_on', vm_info, __opts__, default=False ) key_filename = config.get_cloud_config_value( 'private_key', vm_info, __opts__, search_global=False, default=None ) log.debug("Going to fire event: starting create") cloud.fire_event( 'event', 'starting create', 'salt/cloud/{0}/creating'.format(vm_info['name']), args={ 'name': vm_info['name'], 'profile': vm_info['profile'], 'driver': vm_info['driver'], }, sock_dir=__opts__['sock_dir'], transport=__opts__['transport'] ) # to create the virtual machine. request_kwargs = { 'name': vm_info['name'], 'clone_from': vm_info['clonefrom'] } cloud.fire_event( 'event', 'requesting instance', 'salt/cloud/{0}/requesting'.format(vm_info['name']), args=request_kwargs, sock_dir=__opts__['sock_dir'], transport=__opts__['transport'] ) vm_result = vb_clone_vm(**request_kwargs) # Booting and deploying if needed if power: vb_start_vm(vm_name, timeout=boot_timeout) ips = vb_wait_for_network_address(wait_for_ip_timeout, machine_name=vm_name) if len(ips): ip = ips[0] log.info("[ {0} ] IPv4 is: {1}".format(vm_name, ip)) # ssh or smb using ip and install salt only if deploy is True if deploy: vm_info['key_filename'] = key_filename vm_info['ssh_host'] = ip res = cloud.bootstrap(vm_info, __opts__) vm_result.update(res) cloud.fire_event( 'event', 'created machine', 'salt/cloud/{0}/created'.format(vm_info['name']), args=vm_result, sock_dir=__opts__['sock_dir'], transport=__opts__['transport'] ) # Passwords should be included in this object!! return vm_result
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 "parallels", vm_["profile"], vm_=vm_, ) is False): return False except AttributeError: pass __utils__["cloud.fire_event"]( "event", "starting create", "salt/cloud/{}/creating".format(vm_["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", vm_["name"]) try: data = create_node(vm_) except Exception as exc: # pylint: disable=broad-except log.error( "Error creating %s on PARALLELS\n\n" "The following exception was thrown when trying to " "run the initial deployment: \n%s", vm_["name"], exc, # Show the traceback if the debug logging level is enabled exc_info_on_loglevel=logging.DEBUG, ) return False name = vm_["name"] if not wait_until(name, "CREATED"): return {"Error": "Unable to start {}, command timed out".format(name)} start(vm_["name"], call="action") if not wait_until(name, "STARTED"): return {"Error": "Unable to start {}, command timed out".format(name)} def __query_node_data(vm_name): data = show_instance(vm_name, call="action") if "public-ip" not in data["network"]: # Trigger another iteration return return data try: data = salt.utils.cloud.wait_for_ip( __query_node_data, update_args=(vm_["name"], ), timeout=config.get_cloud_config_value("wait_for_ip_timeout", vm_, __opts__, default=5 * 60), interval=config.get_cloud_config_value("wait_for_ip_interval", vm_, __opts__, default=5), ) except (SaltCloudExecutionTimeout, SaltCloudExecutionFailure) as exc: try: # It might be already up, let's destroy it! destroy(vm_["name"]) except SaltCloudSystemExit: pass finally: raise SaltCloudSystemExit(str(exc)) comps = data["network"]["public-ip"]["address"].split("/") public_ip = comps[0] vm_["ssh_host"] = public_ip ret = __utils__["cloud.bootstrap"](vm_, __opts__) log.info("Created Cloud VM '%s'", vm_["name"]) log.debug("'%s' VM creation details:\n%s", vm_["name"], pprint.pformat(data)) __utils__["cloud.fire_event"]( "event", "created instance", "salt/cloud/{}/created".format(vm_["name"]), args=__utils__["cloud.filter_event"]( "created", vm_, ["name", "profile", "provider", "driver"]), sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], ) return data
def create(vm_): """ Create a single instance from a data dict. CLI Examples: .. code-block:: bash salt-cloud -p qingcloud-ubuntu-c1m1 hostname1 salt-cloud -m /path/to/mymap.sls -P """ try: # Check for required profile parameters before sending any API calls. if config.is_profile_configured(__opts__, __active_provider_name__ or "qingcloud", vm_["profile"]) is False: return False except AttributeError: pass # Since using "provider: <provider-engine>" is deprecated, alias provider # to use driver: "driver: <provider-engine>" if "provider" in vm_: vm_["driver"] = vm_.pop("provider") salt.utils.cloud.fire_event( "event", "starting create", "salt/cloud/{0}/creating".format(vm_["name"]), {"name": vm_["name"], "profile": vm_["profile"], "provider": vm_["driver"]}, transport=__opts__["transport"], ) log.info("Creating Cloud VM {0}".format(vm_["name"])) # params params = { "action": "RunInstances", "instance_name": vm_["name"], "zone": _get_location(vm_), "instance_type": _get_size(vm_), "image_id": _get_image(vm_), "vxnets.1": vm_["vxnets"], "login_mode": vm_["login_mode"], "login_keypair": vm_["login_keypair"], } salt.utils.cloud.fire_event( "event", "requesting instance", "salt/cloud/{0}/requesting".format(vm_["name"]), {"kwargs": params}, transport=__opts__["transport"], ) result = query(params) new_instance_id = result["instances"][0] try: data = salt.utils.cloud.wait_for_ip( _query_node_data, update_args=(new_instance_id,), timeout=config.get_cloud_config_value("wait_for_ip_timeout", vm_, __opts__, default=10 * 60), interval=config.get_cloud_config_value("wait_for_ip_interval", vm_, __opts__, default=10), ) except (SaltCloudExecutionTimeout, SaltCloudExecutionFailure) as exc: try: # It might be already up, let's destroy it! destroy(vm_["name"]) except SaltCloudSystemExit: pass finally: raise SaltCloudSystemExit(str(exc)) private_ip = data["private_ips"][0] log.debug("VM {0} is now running".format(private_ip)) vm_["ssh_host"] = private_ip # The instance is booted and accessible, let's Salt it! salt.utils.cloud.bootstrap(vm_, __opts__) log.info("Created Cloud VM {0[name]!r}".format(vm_)) log.debug("{0[name]!r} VM creation details:\n{1}".format(vm_, pprint.pformat(data))) salt.utils.cloud.fire_event( "event", "created instance", "salt/cloud/{0}/created".format(vm_["name"]), {"name": vm_["name"], "profile": vm_["profile"], "provider": vm_["driver"]}, transport=__opts__["transport"], ) return data
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 'vsphere', vm_['profile']) is False: return False except AttributeError: pass # Since using "provider: <provider-engine>" is deprecated, alias provider # to use driver: "driver: <provider-engine>" if 'provider' in vm_: vm_['driver'] = vm_.pop('provider') salt.utils.cloud.fire_event('event', 'starting create', 'salt/cloud/{0}/creating'.format(vm_['name']), { 'name': vm_['name'], 'profile': vm_['profile'], 'provider': vm_['driver'], }, transport=__opts__['transport']) log.info('Creating Cloud VM {0}'.format(vm_['name'])) conn = get_conn() salt.utils.cloud.fire_event('event', 'requesting instance', 'salt/cloud/{0}/requesting'.format( vm_['name']), {'kwargs': vm_}, transport=__opts__['transport']) folder = config.get_cloud_config_value('folder', vm_, __opts__, default=None) resourcepool = config.get_cloud_config_value('resourcepool', vm_, __opts__, default=None) datastore = config.get_cloud_config_value('datastore', vm_, __opts__, default=None) host = config.get_cloud_config_value('host', vm_, __opts__, default=None) template = config.get_cloud_config_value('template', vm_, __opts__, default=False) clone_kwargs = { 'name': vm_['name'], 'folder': folder, 'resourcepool': resourcepool, 'datastore': datastore, 'host': host, 'template': template, } log.debug('clone_kwargs are set to {0}'.format( pprint.pformat(clone_kwargs))) try: template = conn.get_vm_by_name(vm_['image']) new_instance = template.clone(**clone_kwargs) data = new_instance.get_properties() # pylint: disable=W0612 except Exception as exc: # pylint: disable=W0703 log.error( 'Error creating {0} on vSphere\n\n' 'The following exception was thrown when trying to ' 'run the initial deployment: \n{1}'.format(vm_['name'], str(exc)), # Show the traceback if the debug logging level is enabled exc_info_on_loglevel=logging.DEBUG) return False deploy_kwargs = None if config.get_cloud_config_value('deploy', vm_, __opts__) is True: deploy_kwargs = _deploy(vm_) ret = show_instance(name=vm_['name'], call='action') show_deploy_args = config.get_cloud_config_value('show_deploy_args', vm_, __opts__, default=False) if show_deploy_args: ret['deploy_kwargs'] = deploy_kwargs log.info('Created Cloud VM \'{0[name]}\''.format(vm_)) log.debug('\'{0[name]}\' VM creation details:\n{1}'.format( vm_, pprint.pformat(ret))) salt.utils.cloud.fire_event('event', 'created instance', 'salt/cloud/{0}/created'.format(vm_['name']), { 'name': vm_['name'], 'profile': vm_['profile'], 'provider': vm_['driver'], }, transport=__opts__['transport']) return ret
def create(vm_): ''' Create a single VM from a data dict ''' try: # Check for required profile parameters before sending any API calls. if config.is_profile_configured(__opts__, __active_provider_name__ or 'parallels', vm_['profile']) is False: return False except AttributeError: pass # Since using "provider: <provider-engine>" is deprecated, alias provider # to use driver: "driver: <provider-engine>" if 'provider' in vm_: vm_['driver'] = vm_.pop('provider') salt.utils.cloud.fire_event( 'event', 'starting create', 'salt/cloud/{0}/creating'.format(vm_['name']), { 'name': vm_['name'], 'profile': vm_['profile'], 'provider': vm_['driver'], }, transport=__opts__['transport'] ) log.info('Creating Cloud VM {0}'.format(vm_['name'])) try: data = create_node(vm_) except Exception as exc: log.error( 'Error creating {0} on PARALLELS\n\n' 'The following exception was thrown when trying to ' 'run the initial deployment: \n{1}'.format( vm_['name'], str(exc) ), # Show the traceback if the debug logging level is enabled exc_info_on_loglevel=logging.DEBUG ) return False name = vm_['name'] if not wait_until(name, 'CREATED'): return {'Error': 'Unable to start {0}, command timed out'.format(name)} start(vm_['name'], call='action') if not wait_until(name, 'STARTED'): return {'Error': 'Unable to start {0}, command timed out'.format(name)} def __query_node_data(vm_name): data = show_instance(vm_name, call='action') if 'public-ip' not in data['network']: # Trigger another iteration return return data try: data = salt.utils.cloud.wait_for_ip( __query_node_data, update_args=(vm_['name'],), timeout=config.get_cloud_config_value( 'wait_for_ip_timeout', vm_, __opts__, default=5 * 60), interval=config.get_cloud_config_value( 'wait_for_ip_interval', vm_, __opts__, default=5), ) except (SaltCloudExecutionTimeout, SaltCloudExecutionFailure) as exc: try: # It might be already up, let's destroy it! destroy(vm_['name']) except SaltCloudSystemExit: pass finally: raise SaltCloudSystemExit(str(exc)) comps = data['network']['public-ip']['address'].split('/') public_ip = comps[0] vm_['ssh_host'] = public_ip ret = salt.utils.cloud.bootstrap(vm_, __opts__) log.info('Created Cloud VM {0[name]!r}'.format(vm_)) log.debug( '{0[name]!r} VM creation details:\n{1}'.format( vm_, pprint.pformat(data) ) ) salt.utils.cloud.fire_event( 'event', 'created instance', 'salt/cloud/{0}/created'.format(vm_['name']), { 'name': vm_['name'], 'profile': vm_['profile'], 'provider': vm_['driver'], }, transport=__opts__['transport'] ) return data
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__, _get_active_provider_name() or "digitalocean", vm_["profile"], vm_=vm_, ) is False): return False except AttributeError: pass __utils__["cloud.fire_event"]( "event", "starting create", "salt/cloud/{}/creating".format(vm_["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", vm_["name"]) kwargs = { "name": vm_["name"], "size": get_size(vm_), "image": get_image(vm_), "region": get_location(vm_), "ssh_keys": [], "tags": [], } # backwards compat ssh_key_name = config.get_cloud_config_value("ssh_key_name", vm_, __opts__, search_global=False) if ssh_key_name: kwargs["ssh_keys"].append(get_keyid(ssh_key_name)) ssh_key_names = config.get_cloud_config_value("ssh_key_names", vm_, __opts__, search_global=False, default=False) if ssh_key_names: for key in ssh_key_names.split(","): kwargs["ssh_keys"].append(get_keyid(key)) key_filename = config.get_cloud_config_value("ssh_key_file", vm_, __opts__, search_global=False, default=None) if key_filename is not None and not os.path.isfile(key_filename): raise SaltCloudConfigError( "The defined key_filename '{}' does not exist".format( key_filename)) if not __opts__.get("ssh_agent", False) and key_filename is None: raise SaltCloudConfigError( "The DigitalOcean driver requires an ssh_key_file and an ssh_key_name " "because it does not supply a root password upon building the server." ) ssh_interface = config.get_cloud_config_value("ssh_interface", vm_, __opts__, search_global=False, default="public") if ssh_interface in ["private", "public"]: log.info("ssh_interface: Setting interface for ssh to %s", ssh_interface) kwargs["ssh_interface"] = ssh_interface else: raise SaltCloudConfigError( "The DigitalOcean driver requires ssh_interface to be defined as 'public' or 'private'." ) private_networking = config.get_cloud_config_value( "private_networking", vm_, __opts__, search_global=False, default=None, ) if private_networking is not None: if not isinstance(private_networking, bool): raise SaltCloudConfigError( "'private_networking' should be a boolean value.") kwargs["private_networking"] = private_networking if not private_networking and ssh_interface == "private": raise SaltCloudConfigError( "The DigitalOcean driver requires ssh_interface if defined as 'private' " "then private_networking should be set as 'True'.") backups_enabled = config.get_cloud_config_value( "backups_enabled", vm_, __opts__, search_global=False, default=None, ) if backups_enabled is not None: if not isinstance(backups_enabled, bool): raise SaltCloudConfigError( "'backups_enabled' should be a boolean value.") kwargs["backups"] = backups_enabled ipv6 = config.get_cloud_config_value( "ipv6", vm_, __opts__, search_global=False, default=None, ) if ipv6 is not None: if not isinstance(ipv6, bool): raise SaltCloudConfigError("'ipv6' should be a boolean value.") kwargs["ipv6"] = ipv6 monitoring = config.get_cloud_config_value( "monitoring", vm_, __opts__, search_global=False, default=None, ) if monitoring is not None: if not isinstance(monitoring, bool): raise SaltCloudConfigError( "'monitoring' should be a boolean value.") kwargs["monitoring"] = monitoring kwargs["tags"] = config.get_cloud_config_value("tags", vm_, __opts__, search_global=False, default=False) userdata_file = config.get_cloud_config_value("userdata_file", vm_, __opts__, search_global=False, default=None) if userdata_file is not None: try: with salt.utils.files.fopen(userdata_file, "r") as fp_: kwargs["user_data"] = salt.utils.cloud.userdata_template( __opts__, vm_, salt.utils.stringutils.to_unicode(fp_.read())) except Exception as exc: # pylint: disable=broad-except log.exception("Failed to read userdata from %s: %s", userdata_file, exc) create_dns_record = config.get_cloud_config_value( "create_dns_record", vm_, __opts__, search_global=False, default=None, ) if create_dns_record: log.info("create_dns_record: will attempt to write DNS records") default_dns_domain = None dns_domain_name = vm_["name"].split(".") if len(dns_domain_name) > 2: log.debug( "create_dns_record: inferring default dns_hostname, dns_domain from minion name as FQDN" ) default_dns_hostname = ".".join(dns_domain_name[:-2]) default_dns_domain = ".".join(dns_domain_name[-2:]) else: log.debug("create_dns_record: can't infer dns_domain from %s", vm_["name"]) default_dns_hostname = dns_domain_name[0] dns_hostname = config.get_cloud_config_value( "dns_hostname", vm_, __opts__, search_global=False, default=default_dns_hostname, ) dns_domain = config.get_cloud_config_value( "dns_domain", vm_, __opts__, search_global=False, default=default_dns_domain, ) if dns_hostname and dns_domain: log.info( 'create_dns_record: using dns_hostname="%s", dns_domain="%s"', dns_hostname, dns_domain, ) __add_dns_addr__ = lambda t, d: post_dns_record(dns_domain= dns_domain, name=dns_hostname, record_type=t, record_data=d) log.debug("create_dns_record: %s", __add_dns_addr__) else: log.error( "create_dns_record: could not determine dns_hostname and/or dns_domain" ) raise SaltCloudConfigError( "'create_dns_record' must be a dict specifying \"domain\" " 'and "hostname" or the minion name must be an FQDN.') __utils__["cloud.fire_event"]( "event", "requesting instance", "salt/cloud/{}/requesting".format(vm_["name"]), args=__utils__["cloud.filter_event"]("requesting", kwargs, list(kwargs)), sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], ) try: ret = create_node(kwargs) except Exception as exc: # pylint: disable=broad-except log.error( "Error creating %s on DIGITALOCEAN\n\n" "The following exception was thrown when trying to " "run the initial deployment: %s", vm_["name"], exc, # Show the traceback if the debug logging level is enabled exc_info_on_loglevel=logging.DEBUG, ) return False def __query_node_data(vm_name): data = show_instance(vm_name, "action") if not data: # Trigger an error in the wait_for_ip function return False if data["networks"].get("v4"): for network in data["networks"]["v4"]: if network["type"] == "public": return data return False try: data = salt.utils.cloud.wait_for_ip( __query_node_data, update_args=(vm_["name"], ), timeout=config.get_cloud_config_value("wait_for_ip_timeout", vm_, __opts__, default=10 * 60), interval=config.get_cloud_config_value("wait_for_ip_interval", vm_, __opts__, default=10), ) except (SaltCloudExecutionTimeout, SaltCloudExecutionFailure) as exc: try: # It might be already up, let's destroy it! destroy(vm_["name"]) except SaltCloudSystemExit: pass finally: raise SaltCloudSystemExit(str(exc)) if not vm_.get("ssh_host"): vm_["ssh_host"] = None # add DNS records, set ssh_host, default to first found IP, preferring IPv4 for ssh bootstrap script target addr_families, dns_arec_types = (("v4", "v6"), ("A", "AAAA")) arec_map = dict(list(zip(addr_families, dns_arec_types))) for facing, addr_family, ip_address in [ (net["type"], family, net["ip_address"]) for family in addr_families for net in data["networks"][family] ]: log.info('found %s IP%s interface for "%s"', facing, addr_family, ip_address) dns_rec_type = arec_map[addr_family] if facing == "public": if create_dns_record: __add_dns_addr__(dns_rec_type, ip_address) if facing == ssh_interface: if not vm_["ssh_host"]: vm_["ssh_host"] = ip_address if vm_["ssh_host"] is None: raise SaltCloudSystemExit( "No suitable IP addresses found for ssh minion bootstrapping: {}". format(repr(data["networks"]))) log.debug( "Found public IP address to use for ssh minion bootstrapping: %s", vm_["ssh_host"], ) vm_["key_filename"] = key_filename ret = __utils__["cloud.bootstrap"](vm_, __opts__) ret.update(data) log.info("Created Cloud VM '%s'", vm_["name"]) log.debug("'%s' VM creation details:\n%s", vm_["name"], pprint.pformat(data)) __utils__["cloud.fire_event"]( "event", "created instance", "salt/cloud/{}/created".format(vm_["name"]), args=__utils__["cloud.filter_event"]( "created", vm_, ["name", "profile", "provider", "driver"]), sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], ) return ret
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 'digital_ocean', vm_['profile']) is False: return False except AttributeError: pass # Since using "provider: <provider-engine>" is deprecated, alias provider # to use driver: "driver: <provider-engine>" if 'provider' in vm_: vm_['driver'] = vm_.pop('provider') salt.utils.cloud.fire_event( 'event', 'starting create', 'salt/cloud/{0}/creating'.format(vm_['name']), { 'name': vm_['name'], 'profile': vm_['profile'], 'provider': vm_['driver'], }, transport=__opts__['transport'] ) log.info('Creating Cloud VM {0}'.format(vm_['name'])) kwargs = { 'name': vm_['name'], 'size': get_size(vm_), 'image': get_image(vm_), 'region': get_location(vm_), 'ssh_keys': [] } # backwards compat ssh_key_name = config.get_cloud_config_value( 'ssh_key_name', vm_, __opts__, search_global=False ) if ssh_key_name: kwargs['ssh_keys'].append(get_keyid(ssh_key_name)) ssh_key_names = config.get_cloud_config_value( 'ssh_key_names', vm_, __opts__, search_global=False, default=False ) if ssh_key_names: for key in ssh_key_names.split(','): kwargs['ssh_keys'].append(get_keyid(key)) key_filename = config.get_cloud_config_value( 'ssh_key_file', vm_, __opts__, search_global=False, default=None ) if key_filename is not None and not os.path.isfile(key_filename): raise SaltCloudConfigError( 'The defined key_filename \'{0}\' does not exist'.format( key_filename ) ) if key_filename is None: raise SaltCloudConfigError( 'The DigitalOcean driver requires an ssh_key_file and an ssh_key_name ' 'because it does not supply a root password upon building the server.' ) private_networking = config.get_cloud_config_value( 'private_networking', vm_, __opts__, search_global=False, default=None, ) if private_networking is not None: if not isinstance(private_networking, bool): raise SaltCloudConfigError("'private_networking' should be a boolean value.") kwargs['private_networking'] = private_networking backups_enabled = config.get_cloud_config_value( 'backups_enabled', vm_, __opts__, search_global=False, default=None, ) if backups_enabled is not None: if not isinstance(backups_enabled, bool): raise SaltCloudConfigError("'backups_enabled' should be a boolean value.") kwargs['backups'] = backups_enabled ipv6 = config.get_cloud_config_value( 'ipv6', vm_, __opts__, search_global=False, default=None, ) if ipv6 is not None: if not isinstance(ipv6, bool): raise SaltCloudConfigError("'ipv6' should be a boolean value.") kwargs['ipv6'] = ipv6 create_dns_record = config.get_cloud_config_value( 'create_dns_record', vm_, __opts__, search_global=False, default=None, ) if create_dns_record: log.info('create_dns_record: will attempt to write DNS records') default_dns_domain = None dns_domain_name = vm_['name'].split('.') if len(dns_domain_name) > 2: log.debug('create_dns_record: inferring default dns_hostname, dns_domain from minion name as FQDN') default_dns_hostname = '.'.join(dns_domain_name[:-2]) default_dns_domain = '.'.join(dns_domain_name[-2:]) else: log.debug("create_dns_record: can't infer dns_domain from {0}".format(vm_['name'])) default_dns_hostname = dns_domain_name[0] dns_hostname = config.get_cloud_config_value( 'dns_hostname', vm_, __opts__, search_global=False, default=default_dns_hostname, ) dns_domain = config.get_cloud_config_value( 'dns_domain', vm_, __opts__, search_global=False, default=default_dns_domain, ) if dns_hostname and dns_domain: log.info('create_dns_record: using dns_hostname="{0}", dns_domain="{1}"'.format(dns_hostname, dns_domain)) __add_dns_addr__ = lambda t, d: post_dns_record(dns_domain, dns_hostname, t, d) log.debug('create_dns_record: {0}'.format(__add_dns_addr__)) else: log.error('create_dns_record: could not determine dns_hostname and/or dns_domain') raise SaltCloudConfigError( '\'create_dns_record\' must be a dict specifying "domain" ' 'and "hostname" or the minion name must be an FQDN.' ) salt.utils.cloud.fire_event( 'event', 'requesting instance', 'salt/cloud/{0}/requesting'.format(vm_['name']), {'kwargs': kwargs}, transport=__opts__['transport'] ) try: ret = create_node(kwargs) except Exception as exc: log.error( 'Error creating {0} on DIGITAL_OCEAN\n\n' 'The following exception was thrown when trying to ' 'run the initial deployment: {1}'.format( vm_['name'], str(exc) ), # Show the traceback if the debug logging level is enabled exc_info_on_loglevel=logging.DEBUG ) return False def __query_node_data(vm_name): data = show_instance(vm_name, 'action') if not data: # Trigger an error in the wait_for_ip function return False if data['networks'].get('v4'): for network in data['networks']['v4']: if network['type'] == 'public': return data return False try: data = salt.utils.cloud.wait_for_ip( __query_node_data, update_args=(vm_['name'],), timeout=config.get_cloud_config_value( 'wait_for_ip_timeout', vm_, __opts__, default=10 * 60), interval=config.get_cloud_config_value( 'wait_for_ip_interval', vm_, __opts__, default=10), ) except (SaltCloudExecutionTimeout, SaltCloudExecutionFailure) as exc: try: # It might be already up, let's destroy it! destroy(vm_['name']) except SaltCloudSystemExit: pass finally: raise SaltCloudSystemExit(str(exc)) if not vm_.get('ssh_host'): vm_['ssh_host'] = None # add DNS records, set ssh_host, default to first found IP, preferring IPv4 for ssh bootstrap script target addr_families, dns_arec_types = (('v4', 'v6'), ('A', 'AAAA')) arec_map = dict(list(zip(addr_families, dns_arec_types))) for facing, addr_family, ip_address in [(net['type'], family, net['ip_address']) for family in addr_families for net in data['networks'][family]]: log.info('found {0} IP{1} interface for "{2}"'.format(facing, addr_family, ip_address)) dns_rec_type = arec_map[addr_family] if facing == 'public': if create_dns_record: __add_dns_addr__(dns_rec_type, ip_address) if not vm_['ssh_host']: vm_['ssh_host'] = ip_address if vm_['ssh_host'] is None: raise SaltCloudSystemExit( 'No suitable IP addresses found for ssh minion bootstrapping: {0}'.format(repr(data['networks'])) ) log.debug('Found public IP address to use for ssh minion bootstrapping: {0}'.format(vm_['ssh_host'])) vm_['key_filename'] = key_filename ret = salt.utils.cloud.bootstrap(vm_, __opts__) ret.update(data) log.info('Created Cloud VM \'{0[name]}\''.format(vm_)) log.debug( '\'{0[name]}\' VM creation details:\n{1}'.format( vm_, pprint.pformat(data) ) ) salt.utils.cloud.fire_event( 'event', 'created instance', 'salt/cloud/{0}/created'.format(vm_['name']), { 'name': vm_['name'], 'profile': vm_['profile'], 'provider': vm_['driver'], }, transport=__opts__['transport'] ) return ret
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 'digital_ocean', vm_['profile'], vm_=vm_) is False: return False except AttributeError: pass # Since using "provider: <provider-engine>" is deprecated, alias provider # to use driver: "driver: <provider-engine>" if 'provider' in vm_: vm_['driver'] = vm_.pop('provider') salt.utils.cloud.fire_event('event', 'starting create', 'salt/cloud/{0}/creating'.format(vm_['name']), { 'name': vm_['name'], 'profile': vm_['profile'], 'provider': vm_['driver'], }, transport=__opts__['transport']) log.info('Creating Cloud VM {0}'.format(vm_['name'])) kwargs = { 'name': vm_['name'], 'size': get_size(vm_), 'image': get_image(vm_), 'region': get_location(vm_), 'ssh_keys': [] } # backwards compat ssh_key_name = config.get_cloud_config_value('ssh_key_name', vm_, __opts__, search_global=False) if ssh_key_name: kwargs['ssh_keys'].append(get_keyid(ssh_key_name)) ssh_key_names = config.get_cloud_config_value('ssh_key_names', vm_, __opts__, search_global=False, default=False) if ssh_key_names: for key in ssh_key_names.split(','): kwargs['ssh_keys'].append(get_keyid(key)) key_filename = config.get_cloud_config_value('ssh_key_file', vm_, __opts__, search_global=False, default=None) if key_filename is not None and not os.path.isfile(key_filename): raise SaltCloudConfigError( 'The defined key_filename \'{0}\' does not exist'.format( key_filename)) if key_filename is None: raise SaltCloudConfigError( 'The DigitalOcean driver requires an ssh_key_file and an ssh_key_name ' 'because it does not supply a root password upon building the server.' ) private_networking = config.get_cloud_config_value( 'private_networking', vm_, __opts__, search_global=False, default=None, ) if private_networking is not None: if not isinstance(private_networking, bool): raise SaltCloudConfigError( "'private_networking' should be a boolean value.") kwargs['private_networking'] = private_networking backups_enabled = config.get_cloud_config_value( 'backups_enabled', vm_, __opts__, search_global=False, default=None, ) if backups_enabled is not None: if not isinstance(backups_enabled, bool): raise SaltCloudConfigError( "'backups_enabled' should be a boolean value.") kwargs['backups'] = backups_enabled ipv6 = config.get_cloud_config_value( 'ipv6', vm_, __opts__, search_global=False, default=None, ) if ipv6 is not None: if not isinstance(ipv6, bool): raise SaltCloudConfigError("'ipv6' should be a boolean value.") kwargs['ipv6'] = ipv6 create_dns_record = config.get_cloud_config_value( 'create_dns_record', vm_, __opts__, search_global=False, default=None, ) if create_dns_record: log.info('create_dns_record: will attempt to write DNS records') default_dns_domain = None dns_domain_name = vm_['name'].split('.') if len(dns_domain_name) > 2: log.debug( 'create_dns_record: inferring default dns_hostname, dns_domain from minion name as FQDN' ) default_dns_hostname = '.'.join(dns_domain_name[:-2]) default_dns_domain = '.'.join(dns_domain_name[-2:]) else: log.debug( "create_dns_record: can't infer dns_domain from {0}".format( vm_['name'])) default_dns_hostname = dns_domain_name[0] dns_hostname = config.get_cloud_config_value( 'dns_hostname', vm_, __opts__, search_global=False, default=default_dns_hostname, ) dns_domain = config.get_cloud_config_value( 'dns_domain', vm_, __opts__, search_global=False, default=default_dns_domain, ) if dns_hostname and dns_domain: log.info( 'create_dns_record: using dns_hostname="{0}", dns_domain="{1}"' .format(dns_hostname, dns_domain)) __add_dns_addr__ = lambda t, d: post_dns_record( dns_domain, dns_hostname, t, d) log.debug('create_dns_record: {0}'.format(__add_dns_addr__)) else: log.error( 'create_dns_record: could not determine dns_hostname and/or dns_domain' ) raise SaltCloudConfigError( '\'create_dns_record\' must be a dict specifying "domain" ' 'and "hostname" or the minion name must be an FQDN.') salt.utils.cloud.fire_event('event', 'requesting instance', 'salt/cloud/{0}/requesting'.format( vm_['name']), {'kwargs': kwargs}, transport=__opts__['transport']) try: ret = create_node(kwargs) except Exception as exc: log.error( 'Error creating {0} on DIGITAL_OCEAN\n\n' 'The following exception was thrown when trying to ' 'run the initial deployment: {1}'.format(vm_['name'], str(exc)), # Show the traceback if the debug logging level is enabled exc_info_on_loglevel=logging.DEBUG) return False def __query_node_data(vm_name): data = show_instance(vm_name, 'action') if not data: # Trigger an error in the wait_for_ip function return False if data['networks'].get('v4'): for network in data['networks']['v4']: if network['type'] == 'public': return data return False try: data = salt.utils.cloud.wait_for_ip( __query_node_data, update_args=(vm_['name'], ), timeout=config.get_cloud_config_value('wait_for_ip_timeout', vm_, __opts__, default=10 * 60), interval=config.get_cloud_config_value('wait_for_ip_interval', vm_, __opts__, default=10), ) except (SaltCloudExecutionTimeout, SaltCloudExecutionFailure) as exc: try: # It might be already up, let's destroy it! destroy(vm_['name']) except SaltCloudSystemExit: pass finally: raise SaltCloudSystemExit(str(exc)) if not vm_.get('ssh_host'): vm_['ssh_host'] = None # add DNS records, set ssh_host, default to first found IP, preferring IPv4 for ssh bootstrap script target addr_families, dns_arec_types = (('v4', 'v6'), ('A', 'AAAA')) arec_map = dict(list(zip(addr_families, dns_arec_types))) for facing, addr_family, ip_address in [ (net['type'], family, net['ip_address']) for family in addr_families for net in data['networks'][family] ]: log.info('found {0} IP{1} interface for "{2}"'.format( facing, addr_family, ip_address)) dns_rec_type = arec_map[addr_family] if facing == 'public': if create_dns_record: __add_dns_addr__(dns_rec_type, ip_address) if not vm_['ssh_host']: vm_['ssh_host'] = ip_address if vm_['ssh_host'] is None: raise SaltCloudSystemExit( 'No suitable IP addresses found for ssh minion bootstrapping: {0}'. format(repr(data['networks']))) log.debug( 'Found public IP address to use for ssh minion bootstrapping: {0}'. format(vm_['ssh_host'])) vm_['key_filename'] = key_filename ret = salt.utils.cloud.bootstrap(vm_, __opts__) ret.update(data) log.info('Created Cloud VM \'{0[name]}\''.format(vm_)) log.debug('\'{0[name]}\' VM creation details:\n{1}'.format( vm_, pprint.pformat(data))) salt.utils.cloud.fire_event('event', 'created instance', 'salt/cloud/{0}/created'.format(vm_['name']), { 'name': vm_['name'], 'profile': vm_['profile'], 'provider': vm_['driver'], }, transport=__opts__['transport']) return ret
def create(vm_): ''' Create a single VM from a data dict CLI Example: .. code-block:: bash salt-cloud -p proxmox-ubuntu vmhostname ''' try: # Check for required profile parameters before sending any API calls. if config.is_profile_configured(__opts__, __active_provider_name__ or 'proxmox', vm_['profile']) is False: return False except AttributeError: pass # Since using "provider: <provider-engine>" is deprecated, alias provider # to use driver: "driver: <provider-engine>" if 'provider' in vm_: vm_['driver'] = vm_.pop('provider') ret = {} salt.utils.cloud.fire_event( 'event', 'starting create', 'salt/cloud/{0}/creating'.format(vm_['name']), { 'name': vm_['name'], 'profile': vm_['profile'], 'provider': vm_['driver'], }, transport=__opts__['transport'] ) log.info('Creating Cloud VM {0}'.format(vm_['name'])) if 'use_dns' in vm_ and 'ip_address' not in vm_: use_dns = vm_['use_dns'] if use_dns: from socket import gethostbyname, gaierror try: ip_address = gethostbyname(str(vm_['name'])) except gaierror: log.debug('Resolving of {hostname} failed'.format(hostname=str(vm_['name']))) else: vm_['ip_address'] = str(ip_address) try: data = create_node(vm_) except Exception as exc: log.error( 'Error creating {0} on PROXMOX\n\n' 'The following exception was thrown when trying to ' 'run the initial deployment: \n{1}'.format( vm_['name'], str(exc) ), # Show the traceback if the debug logging level is enabled exc_info_on_loglevel=logging.DEBUG ) return False ret['creation_data'] = data name = vm_['name'] # hostname which we know vmid = data['vmid'] # vmid which we have received host = data['node'] # host which we have received nodeType = data['technology'] # VM tech (Qemu / OpenVZ) # Determine which IP to use in order of preference: if 'ip_address' in vm_: ip_address = str(vm_['ip_address']) elif 'public_ips' in data: ip_address = str(data['public_ips'][0]) # first IP elif 'private_ips' in data: ip_address = str(data['private_ips'][0]) # first IP else: raise SaltCloudExecutionFailure # err.. not a good idea i reckon log.debug('Using IP address {0}'.format(ip_address)) # wait until the vm has been created so we can start it if not wait_for_created(data['upid'], timeout=300): return {'Error': 'Unable to create {0}, command timed out'.format(name)} # VM has been created. Starting.. if not start(name, vmid, call='action'): log.error('Node {0} ({1}) failed to start!'.format(name, vmid)) raise SaltCloudExecutionFailure # Wait until the VM has fully started log.debug('Waiting for state "running" for vm {0} on {1}'.format(vmid, host)) if not wait_for_state(vmid, 'running'): return {'Error': 'Unable to start {0}, command timed out'.format(name)} ssh_username = config.get_cloud_config_value( 'ssh_username', vm_, __opts__, default='root' ) ssh_password = config.get_cloud_config_value( 'password', vm_, __opts__, ) ret['ip_address'] = ip_address ret['username'] = ssh_username ret['password'] = ssh_password vm_['ssh_host'] = ip_address vm_['password'] = ssh_password ret = salt.utils.cloud.bootstrap(vm_, __opts__) # Report success! log.info('Created Cloud VM {0[name]!r}'.format(vm_)) log.debug( '{0[name]!r} VM creation details:\n{1}'.format( vm_, pprint.pformat(data) ) ) salt.utils.cloud.fire_event( 'event', 'created instance', 'salt/cloud/{0}/created'.format(vm_['name']), { 'name': vm_['name'], 'profile': vm_['profile'], 'provider': vm_['driver'], }, ) return ret
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 'aws', vm_['profile'], vm_=vm_) is False: return False except AttributeError: pass key_filename = config.get_cloud_config_value('private_key', vm_, __opts__, search_global=False, default=None) if key_filename is not None and not os.path.isfile(key_filename): raise SaltCloudConfigError( 'The defined key_filename {0!r} does not exist'.format( key_filename)) location = get_location(vm_) log.info('Creating Cloud VM {0} in {1}'.format(vm_['name'], location)) conn = get_conn(location=location) usernames = ssh_username(vm_) kwargs = { 'ssh_key': config.get_cloud_config_value('private_key', vm_, __opts__, search_global=False), 'name': vm_['name'], 'image': get_image(conn, vm_), 'size': get_size(conn, vm_), 'location': get_availability_zone(conn, vm_) } ex_keyname = keyname(vm_) if ex_keyname: kwargs['ex_keyname'] = ex_keyname ex_securitygroup = securitygroup(vm_) if ex_securitygroup: kwargs['ex_securitygroup'] = ex_securitygroup ex_blockdevicemappings = block_device_mappings(vm_) if ex_blockdevicemappings: kwargs['ex_blockdevicemappings'] = ex_blockdevicemappings ex_iam_profile = iam_profile(vm_) if ex_iam_profile: # libcloud does not implement 'iam_profile' yet. # A pull request has been suggested # https://github.com/apache/libcloud/pull/150 raise SaltCloudConfigError( 'libcloud does not implement \'iam_profile\' yet. ' 'Use EC2 driver instead.') tags = config.get_cloud_config_value('tag', vm_, __opts__, {}, search_global=False) if not isinstance(tags, dict): raise SaltCloudConfigError('\'tag\' should be a dict.') kwargs['ex_metadata'] = config.get_cloud_config_value('metadata', vm_, __opts__, default={}, search_global=False) if not isinstance(kwargs['ex_metadata'], dict): raise SaltCloudConfigError('\'metadata\' should be a dict.') try: data = conn.create_node(**kwargs) except Exception as exc: log.error( 'Error creating {0} on AWS\n\n' 'The following exception was thrown by libcloud when trying to ' 'run the initial deployment: {1}\n'.format(vm_['name'], exc), # Show the traceback if the debug logging level is enabled exc_info_on_loglevel=logging.DEBUG) return False log.info('Created node {0}'.format(vm_['name'])) def __get_node_data(conn, vm_name): data = get_node(conn, vm_name) if data is None: # Trigger a failure in the waiting function return False if ssh_interface(vm_) == 'private_ips' and data.private_ips: return data if ssh_interface(vm_) == 'public_ips' and data.public_ips: return data try: data = salt.utils.cloud.wait_for_ip( __get_node_data, update_args=(conn, vm_['name']), timeout=config.get_cloud_config_value('wait_for_ip_timeout', vm_, __opts__, default=5 * 60), interval=config.get_cloud_config_value('wait_for_ip_interval', vm_, __opts__, default=0.5), ) except (SaltCloudExecutionTimeout, SaltCloudExecutionFailure) as exc: try: # It might be already up, let's destroy it! destroy(vm_['name']) except SaltCloudSystemExit: pass finally: raise SaltCloudSystemExit(str(exc)) if tags: set_tags(vm_['name'], tags, call='action') if ssh_interface(vm_) == 'private_ips': log.info('Salt node data. Private_ip: {0}'.format(data.private_ips[0])) ip_address = data.private_ips[0] else: log.info('Salt node data. Public_ip: {0}'.format(data.public_ips[0])) ip_address = data.public_ips[0] if salt.utils.cloud.get_salt_interface(vm_, __opts__) == 'private_ips': salt_ip_address = data.private_ips[0] log.info('Salt interface set to: {0}'.format(salt_ip_address)) else: salt_ip_address = data.public_ips[0] log.debug('Salt interface set to: {0}'.format(salt_ip_address)) username = '******' ssh_connect_timeout = config.get_cloud_config_value( 'ssh_connect_timeout', vm_, __opts__, 900 # 15 minutes ) ssh_port = config.get_cloud_config_value('ssh_port', vm_, __opts__, 22) if salt.utils.cloud.wait_for_port(ip_address, timeout=ssh_connect_timeout): for user in usernames: if salt.utils.cloud.wait_for_passwd( host=ip_address, username=user, ssh_timeout=config.get_cloud_config_value( 'wait_for_passwd_timeout', vm_, __opts__, default=1 * 60), key_filename=key_filename, known_hosts_file=config.get_cloud_config_value( 'known_hosts_file', vm_, __opts__, default='/dev/null'), ): username = user break else: raise SaltCloudSystemExit( 'Failed to authenticate against remote ssh') ret = {} if config.get_cloud_config_value('deploy', vm_, __opts__) is True: deploy_script = script(vm_) deploy_kwargs = { 'opts': __opts__, 'host': ip_address, 'port': ssh_port, 'salt_host': salt_ip_address, 'username': username, 'key_filename': key_filename, 'tmp_dir': config.get_cloud_config_value('tmp_dir', vm_, __opts__, default='/tmp/.saltcloud'), 'deploy_command': config.get_cloud_config_value( 'deploy_command', vm_, __opts__, default='/tmp/.saltcloud/deploy.sh', ), 'tty': config.get_cloud_config_value('tty', vm_, __opts__, default=True), 'script': deploy_script.script, 'name': vm_['name'], 'sudo': config.get_cloud_config_value('sudo', vm_, __opts__, default=(username != 'root')), 'sudo_password': config.get_cloud_config_value('sudo_password', vm_, __opts__, default=None), 'start_action': __opts__['start_action'], 'parallel': __opts__['parallel'], 'conf_file': __opts__['conf_file'], 'sock_dir': __opts__['sock_dir'], 'minion_pem': vm_['priv_key'], 'minion_pub': vm_['pub_key'], 'keep_tmp': __opts__['keep_tmp'], 'preseed_minion_keys': vm_.get('preseed_minion_keys', None), 'display_ssh_output': config.get_cloud_config_value('display_ssh_output', vm_, __opts__, default=True), 'script_args': config.get_cloud_config_value('script_args', vm_, __opts__), 'script_env': config.get_cloud_config_value('script_env', vm_, __opts__), 'minion_conf': salt.utils.cloud.minion_config(__opts__, vm_) } # Deploy salt-master files, if necessary if config.get_cloud_config_value('make_master', vm_, __opts__) is True: deploy_kwargs['make_master'] = True deploy_kwargs['master_pub'] = vm_['master_pub'] deploy_kwargs['master_pem'] = vm_['master_pem'] master_conf = salt.utils.cloud.master_config(__opts__, vm_) deploy_kwargs['master_conf'] = master_conf if master_conf.get('syndic_master', None): deploy_kwargs['make_syndic'] = True deploy_kwargs['make_minion'] = config.get_cloud_config_value( 'make_minion', vm_, __opts__, default=True) # Check for Windows install params win_installer = config.get_cloud_config_value('win_installer', vm_, __opts__) if win_installer: deploy_kwargs['win_installer'] = win_installer minion = salt.utils.cloud.minion_config(__opts__, vm_) deploy_kwargs['master'] = minion['master'] deploy_kwargs['username'] = config.get_cloud_config_value( 'win_username', vm_, __opts__, default='Administrator') deploy_kwargs['password'] = config.get_cloud_config_value( 'win_password', vm_, __opts__, default='') # Store what was used to the deploy the VM ret['deploy_kwargs'] = deploy_kwargs deployed = False if win_installer: deployed = salt.utils.cloud.deploy_windows(**deploy_kwargs) else: deployed = salt.utils.cloud.deploy_script(**deploy_kwargs) if deployed: log.info('Salt installed on {name}'.format(**vm_)) else: log.error('Failed to start Salt on Cloud VM {name}'.format(**vm_)) ret.update(data.__dict__) log.info('Created Cloud VM {0[name]!r}'.format(vm_)) log.debug('{0[name]!r} VM creation details:\n{1}'.format( vm_, pprint.pformat(data.__dict__))) volumes = config.get_cloud_config_value('volumes', vm_, __opts__, search_global=True) if volumes: log.info('Create and attach volumes to node {0}'.format(data.name)) create_attach_volumes(volumes, location, data) return ret
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 'vsphere', vm_['profile']) is False: return False except AttributeError: pass # Since using "provider: <provider-engine>" is deprecated, alias provider # to use driver: "driver: <provider-engine>" if 'provider' in vm_: vm_['driver'] = vm_.pop('provider') salt.utils.cloud.fire_event( 'event', 'starting create', 'salt/cloud/{0}/creating'.format(vm_['name']), { 'name': vm_['name'], 'profile': vm_['profile'], 'provider': vm_['driver'], }, transport=__opts__['transport'] ) log.info('Creating Cloud VM {0}'.format(vm_['name'])) conn = get_conn() salt.utils.cloud.fire_event( 'event', 'requesting instance', 'salt/cloud/{0}/requesting'.format(vm_['name']), {'kwargs': vm_}, transport=__opts__['transport'] ) folder = config.get_cloud_config_value( 'folder', vm_, __opts__, default=None ) resourcepool = config.get_cloud_config_value( 'resourcepool', vm_, __opts__, default=None ) datastore = config.get_cloud_config_value( 'datastore', vm_, __opts__, default=None ) host = config.get_cloud_config_value( 'host', vm_, __opts__, default=None ) template = config.get_cloud_config_value( 'template', vm_, __opts__, default=False ) clone_kwargs = { 'name': vm_['name'], 'folder': folder, 'resourcepool': resourcepool, 'datastore': datastore, 'host': host, 'template': template, } log.debug('clone_kwargs are set to {0}'.format( pprint.pformat(clone_kwargs)) ) try: template = conn.get_vm_by_name(vm_['image']) new_instance = template.clone(**clone_kwargs) data = new_instance.get_properties() # pylint: disable=W0612 except Exception as exc: # pylint: disable=W0703 log.error( 'Error creating {0} on vSphere\n\n' 'The following exception was thrown when trying to ' 'run the initial deployment: \n{1}'.format( vm_['name'], str(exc) ), # Show the traceback if the debug logging level is enabled exc_info_on_loglevel=logging.DEBUG ) return False deploy_kwargs = None if config.get_cloud_config_value('deploy', vm_, __opts__) is True: deploy_kwargs = _deploy(vm_) ret = show_instance(name=vm_['name'], call='action') show_deploy_args = config.get_cloud_config_value( 'show_deploy_args', vm_, __opts__, default=False ) if show_deploy_args: ret['deploy_kwargs'] = deploy_kwargs log.info('Created Cloud VM \'{0[name]}\''.format(vm_)) log.debug( '\'{0[name]}\' VM creation details:\n{1}'.format( vm_, pprint.pformat(ret) ) ) salt.utils.cloud.fire_event( 'event', 'created instance', 'salt/cloud/{0}/created'.format(vm_['name']), { 'name': vm_['name'], 'profile': vm_['profile'], 'provider': vm_['driver'], }, transport=__opts__['transport'] ) return ret
def create(vm_): ''' Create a single Linode VM. ''' try: # Check for required profile parameters before sending any API calls. if vm_['profile'] and config.is_profile_configured( __opts__, __active_provider_name__ or 'linode', vm_['profile']) is False: return False except AttributeError: pass # Since using "provider: <provider-engine>" is deprecated, alias provider # to use driver: "driver: <provider-engine>" if 'provider' in vm_: vm_['driver'] = vm_.pop('provider') salt.utils.cloud.fire_event('event', 'starting create', 'salt/cloud/{0}/creating'.format(vm_['name']), { 'name': vm_['name'], 'profile': vm_['profile'], 'provider': vm_['driver'], }, transport=__opts__['transport']) log.info('Creating Cloud VM {0}'.format(vm_['name'])) data = {} kwargs = { 'name': vm_['name'], 'image': vm_['image'], 'size': vm_['size'], } plan_id = get_plan_id(vm_['size']) try: datacenter_id = get_datacenter_id(vm_['location']) except KeyError: # Linode's default datacenter is Dallas, but we still have to set one to # use the create function from Linode's API. Dallas's datacenter id is 2. datacenter_id = 2 if 'clonefrom' in vm_: linode_id = get_linode_id_from_name(vm_['clonefrom']) clone_source = get_linode(linode_id) kwargs.update({'clonefrom': vm_['clonefrom']}) kwargs['image'] = 'Clone of {0}'.format(vm_['clonefrom']) kwargs['size'] = clone_source['TOTALRAM'] try: result = clone(linode_id, datacenter_id, plan_id) except Exception: log.error( 'Error cloning {0} on Linode\n\n' 'The following exception was thrown by Linode when trying to ' 'clone the specified machine:\n'.format(vm_['clonefrom']), exc_info_on_loglevel=logging.DEBUG) return False else: try: result = _query('linode', 'create', args={ 'PLANID': plan_id, 'DATACENTERID': datacenter_id }) except Exception: log.error( 'Error creating {0} on Linode\n\n' 'The following exception was thrown by Linode when trying to ' 'run the initial deployment:\n'.format(vm_['name']), exc_info_on_loglevel=logging.DEBUG) return False salt.utils.cloud.fire_event('event', 'requesting instance', 'salt/cloud/{0}/requesting'.format( vm_['name']), {'kwargs': kwargs}, transport=__opts__['transport']) node_id = _clean_data(result)['LinodeID'] data['id'] = node_id if not _wait_for_status(node_id, status=(_get_status_id_by_name('brand_new'))): log.error('Error creating {0} on LINODE\n\n' 'while waiting for initial ready status'.format(vm_['name']), exc_info_on_loglevel=logging.DEBUG) # Update the Linode's Label to reflect the given VM name update_linode(node_id, update_args={'Label': vm_['name']}) log.debug('Set name for {0} - was linode{1}.'.format(vm_['name'], node_id)) # Create disks and get ids log.debug('Creating disks for {0}'.format(vm_['name'])) root_disk_id = create_disk_from_distro(vm_, node_id)['DiskID'] swap_disk_id = create_swap_disk(vm_, node_id)['DiskID'] # Add private IP address if requested if get_private_ip(vm_): create_private_ip(vm_, node_id) # Create a ConfigID using disk ids config_id = create_config(vm_, node_id, root_disk_id, swap_disk_id)['ConfigID'] # Boot the VM and get the JobID from Linode boot_job_id = boot(node_id, config_id)['JobID'] if not _wait_for_job(node_id, boot_job_id): log.error('Boot failed for {0}.'.format(vm_['name'])) return False node_data = get_linode(node_id) ips = get_ips(node_id) state = int(node_data['STATUS']) data['image'] = vm_['image'] data['name'] = node_data['LABEL'] data['size'] = node_data['TOTALRAM'] data['state'] = _get_status_descr_by_id(state) data['private_ips'] = ips['private_ips'] data['public_ips'] = ips['public_ips'] vm_['ssh_host'] = data['public_ips'][0] # If a password wasn't supplied in the profile or provider config, set it now. vm_['password'] = get_password(vm_) # Bootstrap! ret = salt.utils.cloud.bootstrap(vm_, __opts__) ret.update(data) log.info('Created Cloud VM {0[name]!r}'.format(vm_)) log.debug('{0[name]!r} VM creation details:\n{1}'.format( vm_, pprint.pformat(data))) salt.utils.cloud.fire_event('event', 'created instance', 'salt/cloud/{0}/created'.format(vm_['name']), { 'name': vm_['name'], 'profile': vm_['profile'], 'provider': vm_['driver'], }, transport=__opts__['transport']) return ret
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 'profitbricks'), vm_['profile']) is False): return False except AttributeError: pass data = None datacenter_id = get_datacenter_id() conn = get_conn() # Assemble list of network interfaces from the cloud profile config. nics = _get_nics(vm_) # Assemble list of volumes from the cloud profile config. volumes = [_get_system_volume(vm_)] if 'volumes' in vm_: volumes.extend(_get_data_volumes(vm_)) # Assembla the composite server object. server = _get_server(vm_, volumes, nics) __utils__['cloud.fire_event']( 'event', 'requesting instance', 'salt/cloud/{0}/requesting'.format(vm_['name']), args={'name': vm_['name']}, sock_dir=__opts__['sock_dir'], transport=__opts__['transport'] ) try: data = conn.create_server(datacenter_id=datacenter_id, server=server) log.info('Create server request ID: {0}'.format(data['requestId']), exc_info_on_loglevel=logging.DEBUG) _wait_for_completion(conn, data, get_wait_timeout(vm_), 'create_server') except Exception as exc: # pylint: disable=W0703 log.error( 'Error creating {0} on ProfitBricks\n\n' 'The following exception was thrown by the profitbricks library ' 'when trying to run the initial deployment: \n{1}'.format( vm_['name'], exc ), exc_info_on_loglevel=logging.DEBUG ) return False vm_['server_id'] = data['id'] def __query_node_data(vm_, data): ''' Query node data until node becomes available. ''' running = False try: data = show_instance(vm_['name'], 'action') if not data: return False log.debug( 'Loaded node data for {0}:\nname: {1}\nstate: {2}'.format( vm_['name'], pprint.pformat(data['name']), data['vmState'] ) ) except Exception as err: log.error( 'Failed to get nodes list: {0}'.format( err ), # Show the trackback if the debug logging level is enabled exc_info_on_loglevel=logging.DEBUG ) # Trigger a failure in the wait for IP function return False running = data['vmState'] == 'RUNNING' if not running: # Still not running, trigger another iteration return if ssh_interface(vm_) == 'private_lan' and data['private_ips']: vm_['ssh_host'] = data['private_ips'][0] if ssh_interface(vm_) != 'private_lan' and data['public_ips']: vm_['ssh_host'] = data['public_ips'][0] return data try: data = salt.utils.cloud.wait_for_ip( __query_node_data, update_args=(vm_, data), timeout=config.get_cloud_config_value( 'wait_for_ip_timeout', vm_, __opts__, default=10 * 60), interval=config.get_cloud_config_value( 'wait_for_ip_interval', vm_, __opts__, default=10), ) except (SaltCloudExecutionTimeout, SaltCloudExecutionFailure) as exc: try: # It might be already up, let's destroy it! destroy(vm_['name']) except SaltCloudSystemExit: pass finally: raise SaltCloudSystemExit(str(exc.message)) log.debug('VM is now running') log.info('Created Cloud VM {0}'.format(vm_)) log.debug( '{0} VM creation details:\n{1}'.format( vm_, pprint.pformat(data) ) ) __utils__['cloud.fire_event']( 'event', 'created instance', 'salt/cloud/{0}/created'.format(vm_['name']), args={ 'name': vm_['name'], 'profile': vm_['profile'], 'provider': vm_['driver'], }, sock_dir=__opts__['sock_dir'], transport=__opts__['transport'] ) if 'ssh_host' in vm_: vm_['key_filename'] = get_key_filename(vm_) ret = __utils__['cloud.bootstrap'](vm_, __opts__) ret.update(data) return ret else: raise SaltCloudSystemExit('A valid IP address was not found.')
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 "profitbricks"), vm_["profile"]) is False): return False except AttributeError: pass if "image_alias" in vm_ and not version_compatible("4.0"): raise SaltCloudNotFound( "The 'image_alias' parameter requires the profitbricks " "SDK v4.0.0 or greater.") if "image" not in vm_ and "image_alias" not in vm_: log.error("The image or image_alias parameter is required.") signal_event(vm_, "creating", "starting create") data = None datacenter_id = get_datacenter_id() conn = get_conn() # Assemble list of network interfaces from the cloud profile config. nics = _get_nics(vm_) # Assemble list of volumes from the cloud profile config. volumes = [_get_system_volume(vm_)] if "volumes" in vm_: volumes.extend(_get_data_volumes(vm_)) # Assembla the composite server object. server = _get_server(vm_, volumes, nics) signal_event(vm_, "requesting", "requesting instance") try: data = conn.create_server(datacenter_id=datacenter_id, server=server) log.info( "Create server request ID: %s", data["requestId"], exc_info_on_loglevel=logging.DEBUG, ) _wait_for_completion(conn, data, get_wait_timeout(vm_), "create_server") except PBError as exc: log.error( "Error creating %s on ProfitBricks\n\n" "The following exception was thrown by the profitbricks library " "when trying to run the initial deployment: \n%s", vm_["name"], exc, exc_info_on_loglevel=logging.DEBUG, ) return False except Exception as exc: # pylint: disable=W0703 log.error( "Error creating %s \n\nError: \n%s", vm_["name"], exc, exc_info_on_loglevel=logging.DEBUG, ) return False vm_["server_id"] = data["id"] def __query_node_data(vm_, data): """ Query node data until node becomes available. """ running = False try: data = show_instance(vm_["name"], "action") if not data: return False log.debug( "Loaded node data for %s:\nname: %s\nstate: %s", vm_["name"], pprint.pformat(data["name"]), data["state"], ) except Exception as err: # pylint: disable=broad-except log.error( "Failed to get nodes list: %s", err, # Show the trackback if the debug logging level is enabled exc_info_on_loglevel=logging.DEBUG, ) # Trigger a failure in the wait for IP function return False running = data["state"] == "RUNNING" if not running: # Still not running, trigger another iteration return if ssh_interface(vm_) == "private_lan" and data["private_ips"]: vm_["ssh_host"] = data["private_ips"][0] if ssh_interface(vm_) != "private_lan" and data["public_ips"]: vm_["ssh_host"] = data["public_ips"][0] return data try: data = salt.utils.cloud.wait_for_ip( __query_node_data, update_args=(vm_, data), timeout=config.get_cloud_config_value("wait_for_ip_timeout", vm_, __opts__, default=10 * 60), interval=config.get_cloud_config_value("wait_for_ip_interval", vm_, __opts__, default=10), ) except (SaltCloudExecutionTimeout, SaltCloudExecutionFailure) as exc: try: # It might be already up, let's destroy it! destroy(vm_["name"]) except SaltCloudSystemExit: pass finally: raise SaltCloudSystemExit(str(exc.message)) log.debug("VM is now running") log.info("Created Cloud VM %s", vm_) log.debug("%s VM creation details:\n%s", vm_, pprint.pformat(data)) signal_event(vm_, "created", "created instance") if "ssh_host" in vm_: vm_["key_filename"] = get_key_filename(vm_) ret = __utils__["cloud.bootstrap"](vm_, __opts__) ret.update(data) return ret else: raise SaltCloudSystemExit("A valid IP address was not found.")
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 # Since using "provider: <provider-engine>" is deprecated, alias provider # to use driver: "driver: <provider-engine>" if 'provider' in vm_: vm_['driver'] = vm_.pop('provider') 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={ 'name': name, 'profile': vm_['profile'], 'provider': vm_['driver'], }, sock_dir=__opts__['sock_dir'], transport=__opts__['transport'] ) log.info('Creating Cloud VM {0}'.format(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 = [str(disks)] elif isinstance(disks, str): 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': str(count), 'diskImage': {'capacity': str(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 {0} .' '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.'.format(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, } } 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 __utils__['cloud.fire_event']( 'event', 'requesting instance', 'salt/cloud/{0}/requesting'.format(name), args={'kwargs': kwargs}, sock_dir=__opts__['sock_dir'], transport=__opts__['transport'] ) try: response = conn.createObject(kwargs) except Exception as exc: log.error( 'Error creating {0} on SoftLayer\n\n' 'The following exception was thrown when trying to ' 'run the initial deployment: \n{1}'.format( name, str(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 or public_vlan is False: 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 \ len(node['operatingSystem']['passwords']) > 0: 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={ 'name': name, 'profile': vm_['profile'], 'provider': vm_['driver'], }, sock_dir=__opts__['sock_dir'], transport=__opts__['transport'] ) return ret
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 'dimensiondata', vm_['profile']) is False: return False except AttributeError: pass # Since using "provider: <provider-engine>" is deprecated, alias provider # to use driver: "driver: <provider-engine>" if 'provider' in vm_: vm_['driver'] = vm_.pop('provider') salt.utils.cloud.fire_event('event', 'starting create', 'salt/cloud/{0}/creating'.format(vm_['name']), { 'name': vm_['name'], 'profile': vm_['profile'], 'provider': vm_['driver'], }, transport=__opts__['transport']) log.info('Creating Cloud VM %s', vm_['name']) conn = get_conn() rootPw = NodeAuthPassword(vm_['auth']) try: location = conn.ex_get_location_by_id(vm_['location']) images = conn.list_images(location=location) image = [x for x in images if x.id == vm_['image']][0] networks = conn.ex_list_network_domains(location=location) network_domain = [ y for y in networks if y.name == vm_['network_domain'] ][0] # Use the first VLAN in the network domain vlan = conn.ex_list_vlans(location=location, network_domain=network_domain)[0] kwargs = { 'name': vm_['name'], 'image': image, 'auth': rootPw, 'ex_description': vm_['description'], 'ex_network_domain': network_domain, 'ex_vlan': vlan, 'ex_is_started': vm_['is_started'] } data = conn.create_node(**kwargs) except Exception as exc: log.error( 'Error creating %s on DIMENSIONDATA\n\n' 'The following exception was thrown by libcloud when trying to ' 'run the initial deployment: \n%s', vm_['name'], exc, exc_info_on_loglevel=logging.DEBUG) return False def __query_node_data(vm_, data): running = False try: node = show_instance(vm_['name'], 'action') running = (node['state'] == NodeState.RUNNING) log.debug('Loaded node data for %s:\nname: %s\nstate: %s', vm_['name'], pprint.pformat(node['name']), node['state']) except Exception as err: log.error( 'Failed to get nodes list: %s', err, # Show the traceback if the debug logging level is enabled exc_info_on_loglevel=logging.DEBUG) # Trigger a failure in the wait for IP function return False if not running: # Still not running, trigger another iteration return private = node['private_ips'] public = node['public_ips'] if private and not public: log.warning('Private IPs returned, but not public... Checking for ' 'misidentified IPs') for private_ip in private: private_ip = preferred_ip(vm_, [private_ip]) if salt.utils.cloud.is_public_ip(private_ip): log.warning('%s is a public IP', private_ip) data.public_ips.append(private_ip) else: log.warning('%s is a private IP', private_ip) if private_ip not in data.private_ips: data.private_ips.append(private_ip) if ssh_interface(vm_) == 'private_ips' and data.private_ips: return data if private: data.private_ips = private if ssh_interface(vm_) == 'private_ips': return data if public: data.public_ips = public if ssh_interface(vm_) != 'private_ips': return data log.debug('DATA') log.debug(data) try: data = salt.utils.cloud.wait_for_ip( __query_node_data, update_args=(vm_, data), timeout=config.get_cloud_config_value('wait_for_ip_timeout', vm_, __opts__, default=25 * 60), interval=config.get_cloud_config_value('wait_for_ip_interval', vm_, __opts__, default=30), max_failures=config.get_cloud_config_value( 'wait_for_ip_max_failures', vm_, __opts__, default=60), ) except (SaltCloudExecutionTimeout, SaltCloudExecutionFailure) as exc: try: # It might be already up, let's destroy it! destroy(vm_['name']) except SaltCloudSystemExit: pass finally: raise SaltCloudSystemExit(str(exc)) log.debug('VM is now running') if ssh_interface(vm_) == 'private_ips': ip_address = preferred_ip(vm_, data.private_ips) else: ip_address = preferred_ip(vm_, data.public_ips) log.debug('Using IP address %s', ip_address) if salt.utils.cloud.get_salt_interface(vm_, __opts__) == 'private_ips': salt_ip_address = preferred_ip(vm_, data.private_ips) log.info('Salt interface set to: %s', salt_ip_address) else: salt_ip_address = preferred_ip(vm_, data.public_ips) log.debug('Salt interface set to: %s', salt_ip_address) if not ip_address: raise SaltCloudSystemExit('No IP addresses could be found.') vm_['salt_host'] = salt_ip_address vm_['ssh_host'] = ip_address vm_['password'] = vm_['auth'] ret = salt.utils.cloud.bootstrap(vm_, __opts__) ret.update(data.__dict__) if 'password' in data.extra: del data.extra['password'] log.info('Created Cloud VM \'{0[name]}\''.format(vm_)) log.debug('\'{0[name]}\' VM creation details:\n{1}'.format( vm_, pprint.pformat(data.__dict__))) salt.utils.cloud.fire_event('event', 'created instance', 'salt/cloud/{0}/created'.format(vm_['name']), { 'name': vm_['name'], 'profile': vm_['profile'], 'provider': vm_['driver'], }, transport=__opts__['transport']) return ret