def _get_server(vm_, volumes, nics): ''' Construct server instance from cloud profile config ''' # Apply component overrides to the size from the cloud profile config vm_size = _override_size(vm_) # Set the server availability zone from the cloud profile config availability_zone = config.get_cloud_config_value( 'availability_zone', vm_, __opts__, default=None, search_global=False ) # Assign CPU family from the cloud profile config cpu_family = config.get_cloud_config_value( 'cpu_family', vm_, __opts__, default=None, search_global=False ) # Contruct server object return Server( name=vm_['name'], ram=vm_size['ram'], availability_zone=availability_zone, cores=vm_size['cores'], cpu_family=cpu_family, create_volumes=volumes, nics=nics )
def regenerate_minion_keys(host, vm_, __opts__): logger.info('Regenerating minion keys for: {0}'.format(vm_['name'])) # Kill existing master keys key_cli = salt.key.KeyCLI(__opts__) matches = key_cli.key.name_match(vm_['name']) if matches: key_cli.key.delete_key(match_dict=matches) # Kill remote master keys kwargs = get_ssh_kwargs(host, vm_, __opts__) tty = config.get_cloud_config_value( 'tty', vm_, __opts__, default=True ) sudo = config.get_cloud_config_value( 'sudo', vm_, __opts__, default=True ) salt.utils.cloud.root_cmd('rm -rf /etc/salt/pki', tty, sudo, **kwargs) # Generate new keys for the minion minion_pem, minion_pub = salt.utils.cloud.gen_keys( config.get_cloud_config_value('keysize', vm_, __opts__) ) # Preauthorize the minion logger.info('Accepting key for {0}'.format(vm_['name'])) key_id = vm_.get('id', vm_['name']) salt.utils.cloud.accept_key( __opts__['pki_dir'], minion_pub, key_id ) return minion_pem, minion_pub
def get_conn(): ''' Return a conn object for the passed VM data ''' vm_ = get_configured_provider() driver = get_driver(Provider.DIMENSIONDATA) region = config.get_cloud_config_value( 'region', vm_, __opts__ ) user_id = config.get_cloud_config_value( 'user_id', vm_, __opts__ ) key = config.get_cloud_config_value( 'key', vm_, __opts__ ) if key is not None: log.debug('DimensionData authenticating using password') return driver( user_id, key, region=region )
def _authenticate(): ''' Retrieve CSRF and API tickets for the Proxmox API ''' global url, ticket, csrf, verify_ssl url = config.get_cloud_config_value( 'url', get_configured_provider(), __opts__, search_global=False ) username = config.get_cloud_config_value( 'user', get_configured_provider(), __opts__, search_global=False ), passwd = config.get_cloud_config_value( 'password', get_configured_provider(), __opts__, search_global=False ) verify_ssl = config.get_cloud_config_value( 'verify_ssl', get_configured_provider(), __opts__, search_global=False ) if verify_ssl is None: verify_ssl = True connect_data = {'username': username, 'password': passwd} full_url = 'https://{0}:8006/api2/json/access/ticket'.format(url) returned_data = requests.post( full_url, verify=verify_ssl, data=connect_data).json() ticket = {'PVEAuthCookie': returned_data['data']['ticket']} csrf = str(returned_data['data']['CSRFPreventionToken'])
def get_conn(): ''' Return a conn object for the passed VM data ''' vm_ = get_configured_provider() driver = get_driver(Provider.OPENSTACK) authinfo = { 'ex_force_auth_url': config.get_cloud_config_value( 'identity_url', vm_, __opts__, search_global=False ), 'ex_force_service_name': config.get_cloud_config_value( 'compute_name', vm_, __opts__, search_global=False ), 'ex_force_service_region': config.get_cloud_config_value( 'compute_region', vm_, __opts__, search_global=False ), 'ex_tenant_name': config.get_cloud_config_value( 'tenant', vm_, __opts__, search_global=False ), } service_type = config.get_cloud_config_value('service_type', vm_, __opts__, search_global=False) if service_type: authinfo['ex_force_service_type'] = service_type insecure = config.get_cloud_config_value( 'insecure', vm_, __opts__, search_global=False ) if insecure: import libcloud.security libcloud.security.VERIFY_SSL_CERT = False password = config.get_cloud_config_value( 'password', vm_, __opts__, search_global=False ) if password is not None: authinfo['ex_force_auth_version'] = '2.0_password' log.debug('OpenStack authenticating using password') return driver( config.get_cloud_config_value( 'user', vm_, __opts__, search_global=False ), password, **authinfo ) authinfo['ex_force_auth_version'] = '2.0_apikey' log.debug('OpenStack authenticating using apikey') return driver( config.get_cloud_config_value('user', vm_, __opts__, search_global=False), config.get_cloud_config_value('apikey', vm_, __opts__, search_global=False), **authinfo)
def check_for_ssh(cloud_map, hosts): """ Attempts to SSH to the given hosts. @param (stacks.models.Stack) - the stack the hosts belong to @param (list[stacks.models.Host]) - hosts to check for SSH @returns (list) - list of tuples (bool, Host) where the bool value is True if we could connect to Host over SSH, False otherwise """ opts = get_salt_cloud_opts() vms = get_stack_vm_map(cloud_map) mapper = get_stack_mapper(cloud_map) result = [] # Iterate over the given hosts. If the host hasn't been assigned a # hostname or is not physically running, there's nothing we can do # so we skip them for host in hosts: if host.hostname not in vms: continue # Build the standard vm_ object and inject some additional stuff # we'll need vm_ = vms[host.hostname] vm_provider_metadata = mapper.get_running_by_names(host.hostname) if not vm_provider_metadata: # host is not actually running so skip it continue provider, provider_type = vm_['provider'].split(':') vm_.update( vm_provider_metadata[provider][provider_type][vm_['name']] ) # Pull some values we need to test for SSH key_filename = config.get_cloud_config_value( 'private_key', vm_, opts, search_global=False, default=None ) username = config.get_cloud_config_value( 'ssh_username', vm_, opts, search_global=False, default=None ) hostname = config.get_cloud_config_value( 'private_ips', vm_, opts, search_global=False, default=None ) # Test SSH connection ok = salt.utils.cloud.wait_for_passwd( hostname, key_filename=key_filename, username=username, ssh_timeout=1, # 1 second timeout maxtries=3, # 3 max tries per host trysleep=0.5, # half second between tries display_ssh_output=False) result.append((ok, host)) return result
def get_password(vm_): ''' Return the password to use ''' return config.get_cloud_config_value( 'password', vm_, __opts__, default=config.get_cloud_config_value( 'passwd', vm_, __opts__, search_global=False ), search_global=False )
def get_conn(service="SoftLayer_Virtual_Guest"): """ Return a conn object for the passed VM data """ client = SoftLayer.Client( username=config.get_cloud_config_value("user", get_configured_provider(), __opts__, search_global=False), api_key=config.get_cloud_config_value("apikey", get_configured_provider(), __opts__, search_global=False), ) return client[service]
def query(params=None): ''' Make a web call to aliyun ECS REST API ''' path = 'https://ecs.aliyuncs.com/' access_key_id = config.get_cloud_config_value( 'id', get_configured_provider(), __opts__, search_global=False ) access_key_secret = config.get_cloud_config_value( 'key', get_configured_provider(), __opts__, search_global=False ) timestamp = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()) # public interface parameters parameters = { 'Format': 'JSON', 'Version': DEFAULT_ALIYUN_API_VERSION, 'AccessKeyId': access_key_id, 'SignatureVersion': '1.0', 'SignatureMethod': 'HMAC-SHA1', 'SignatureNonce': str(uuid.uuid1()), 'TimeStamp': timestamp, } # include action or function parameters if params: parameters.update(params) # Calculate the string for Signature signature = _compute_signature(parameters, access_key_secret) parameters['Signature'] = signature request = requests.get(path, params=parameters, verify=False) if request.status_code != 200: raise SaltCloudSystemExit( 'An error occurred while querying aliyun ECS. HTTP Code: {0} ' 'Error: {1!r}'.format( request.status_code, request.text ) ) log.debug(request.url) content = request.text #print content result = json.loads(content, object_hook=salt.utils.decode_dict) if 'Code' in result: raise SaltCloudSystemExit( pprint.pformat(result.get('Message', {})) ) return result
def query(method='droplets', droplet_id=None, command=None, args=None, http_method='get'): ''' Make a web call to DigitalOcean ''' base_path = str(config.get_cloud_config_value( 'api_root', get_configured_provider(), __opts__, search_global=False, default='https://api.digitalocean.com/v2' )) path = '{0}/{1}/'.format(base_path, method) if droplet_id: path += '{0}/'.format(droplet_id) if command: path += command if not isinstance(args, dict): args = {} personal_access_token = config.get_cloud_config_value( 'personal_access_token', get_configured_provider(), __opts__, search_global=False ) data = json.dumps(args) requester = getattr(requests, http_method) request = requester(path, data=data, headers={'Authorization': 'Bearer ' + personal_access_token, 'Content-Type': 'application/json'}) if request.status_code > 299: raise SaltCloudSystemExit( 'An error occurred while querying DigitalOcean. HTTP Code: {0} ' 'Error: \'{1}\''.format( request.status_code, # request.read() request.text ) ) log.debug(request.url) # success without data if request.status_code == 204: return True content = request.text result = json.loads(content) if result.get('status', '').lower() == 'error': raise SaltCloudSystemExit( pprint.pformat(result.get('error_message', {})) ) return result
def get_conn(): ''' Return a conn object for the passed VM data ''' vm_ = get_configured_provider() driver = get_driver(Provider.IBM) return driver( config.get_cloud_config_value('user', vm_, __opts__, search_global=False), config.get_cloud_config_value('password', vm_, __opts__, search_global=False) )
def __get_ssh_credentials(vm_): ''' Get configured SSH credentials. ''' ssh_user = config.get_cloud_config_value( 'ssh_username', vm_, __opts__, default=os.getenv('USER')) ssh_key = config.get_cloud_config_value( 'ssh_keyfile', vm_, __opts__, default=os.getenv('HOME') + '/.ssh/google_compute_engine') return ssh_user, ssh_key
def get_conn(): """ Return a conn object for the passed VM data """ vm_ = get_configured_provider() driver = get_driver(Provider.IBM) return driver( config.get_cloud_config_value("user", vm_, __opts__, search_global=False), config.get_cloud_config_value("password", vm_, __opts__, search_global=False), )
def get_conn(): """ Return a conn object for the passed VM data """ driver = get_driver(Provider.GOGRID) vm_ = get_configured_provider() return driver( config.get_cloud_config_value("apikey", vm_, __opts__, search_global=False), config.get_cloud_config_value("sharedsecret", vm_, __opts__, search_global=False), )
def get_conn(): """ Return a conn object for the passed VM data """ vm_ = get_configured_provider() auth_minion = config.get_cloud_config_value("auth_minion", vm_, __opts__, search_global=False) config_profile = config.get_cloud_config_value("config_profile", vm_, __opts__, search_global=False) if config_profile: return {"auth_minion": auth_minion, "profile": config_profile}
def get_password(vm_): """ Return the password to use """ return config.get_cloud_config_value( "password", vm_, __opts__, default=config.get_cloud_config_value("passwd", vm_, __opts__, search_global=False), search_global=False, )
def get_ssh_key_filename(vm_): ''' Return path to filename if get_auth() returns a NodeAuthSSHKey. ''' key_filename = config.get_cloud_config_value( 'ssh_key_file', vm_, __opts__, default=config.get_cloud_config_value( 'ssh_pubkey', vm_, __opts__, search_global=False ), search_global=False) if key_filename is not None and exists(expanduser(key_filename)): return expanduser(key_filename) return None
def query(method='droplets', droplet_id=None, command=None, args=None): ''' Make a web call to DigitalOcean ''' base_path = str(config.get_cloud_config_value( 'api_root', get_configured_provider(), __opts__, search_global=False, default='https://api.digitalocean.com/v1' )) path = '{0}/{1}/'.format(base_path, method) if droplet_id: path += '{0}/'.format(droplet_id) if command: path += command if type(args) is not dict: args = {} args['client_id'] = config.get_cloud_config_value( 'client_key', get_configured_provider(), __opts__, search_global=False ) args['api_key'] = config.get_cloud_config_value( 'api_key', get_configured_provider(), __opts__, search_global=False ) request = requests.get(path, params=args) if request.status_code != 200: raise SaltCloudSystemExit( 'An error occurred while querying DigitalOcean. HTTP Code: {0} ' 'Error: {1!r}'.format( request.getcode(), #request.read() request.text ) ) log.debug(request.url) content = request.text result = json.loads(content) if result.get('status', '').lower() == 'error': raise SaltCloudSystemExit( pprint.pformat(result.get('error_message', {})) ) return result
def get_conn(service='SoftLayer_Virtual_Guest'): ''' Return a conn object for the passed VM data ''' client = SoftLayer.Client( username=config.get_cloud_config_value( 'user', get_configured_provider(), __opts__, search_global=False ), api_key=config.get_cloud_config_value( 'apikey', get_configured_provider(), __opts__, search_global=False ), ) return client[service]
def _get_xml_rpc(): xml_rpc = config.get_cloud_config_value( 'xml_rpc', get_configured_provider(), __opts__ ) user = config.get_cloud_config_value( 'user', get_configured_provider(), __opts__ ) password = config.get_cloud_config_value( 'password', get_configured_provider(), __opts__ ) server = xmlrpclib.ServerProxy(xml_rpc) return server, user, password
def _get_xml_rpc(): xml_rpc = config.get_cloud_config_value( 'xml_rpc', get_configured_provider(), __opts__ ) user = config.get_cloud_config_value( 'user', get_configured_provider(), __opts__ ) password = config.get_cloud_config_value( 'password', get_configured_provider(), __opts__ ) server = salt.ext.six.moves.xmlrpc_client.ServerProxy(xml_rpc) return server, user, password
def get_conn(): ''' Return a conn object for the passed VM data ''' force_first_gen = config.get_cloud_config_value( 'force_first_gen', get_configured_provider(), __opts__, search_global=False, default=False ) compute_region = config.get_cloud_config_value( 'compute_region', get_configured_provider(), __opts__, search_global=False, default='DFW' ).upper() if force_first_gen: log.info('Rackspace driver will only have access to first-gen images') driver = get_driver(Provider.RACKSPACE) else: computed_provider = 'RACKSPACE_NOVA_{0}'.format(compute_region) try: driver = get_driver(getattr(Provider, computed_provider)) except AttributeError: log.info( 'Rackspace driver will only have access to first-gen images ' 'since it was unable to load the driver as {0}'.format( computed_provider ) ) driver = get_driver(Provider.RACKSPACE) except Exception: # http://goo.gl/qFgY42 driver = get_driver(Provider.RACKSPACE) return driver( config.get_cloud_config_value( 'user', get_configured_provider(), __opts__, search_global=False ), config.get_cloud_config_value( 'apikey', get_configured_provider(), __opts__, search_global=False ) )
def query(method='servers', server_id=None, command=None, args=None, http_method='get'): ''' Make a call to the Scaleway API. ''' base_path = str(config.get_cloud_config_value( 'api_root', get_configured_provider(), __opts__, search_global=False, default='https://api.scaleway.com' )) path = '{0}/{1}/'.format(base_path, method) if server_id: path += '{0}/'.format(server_id) if command: path += command if not isinstance(args, dict): args = {} token = config.get_cloud_config_value( 'token', get_configured_provider(), __opts__, search_global=False ) data = json.dumps(args) requester = getattr(requests, http_method) request = requester( path, data=data, headers={'X-Auth-Token': token, 'Content-Type': 'application/json'} ) if request.status_code > 299: raise SaltCloudSystemExit( 'An error occurred while querying Scaleway. HTTP Code: {0} ' 'Error: \'{1}\''.format( request.getcode(), request.text ) ) log.debug(request.url) # success without data if request.status_code == 204: return True return request.json()
def get_ssh_kwargs(host, vm_, __opts__): return { 'host': host.provider_private_dns, 'hostname': host.provider_private_dns, 'timeout': 3, 'display_ssh_output': False, 'key_filename': config.get_cloud_config_value( 'private_key', vm_, __opts__, search_global=False, default=None ), 'username': config.get_cloud_config_value( 'ssh_username', vm_, __opts__, search_global=False, default=None ) }
def get_conn(): ''' Return a conn object for the passed VM data ''' driver = get_driver(Provider.GOGRID) vm_ = get_configured_provider() return driver( config.get_cloud_config_value( 'apikey', vm_, __opts__, search_global=False ), config.get_cloud_config_value( 'sharedsecret', vm_, __opts__, search_global=False ) )
def get_password(vm_): ''' Return the password to use for a VM. vm_ The configuration to obtain the password from. ''' return config.get_cloud_config_value( 'password', vm_, __opts__, default=config.get_cloud_config_value( 'passwd', vm_, __opts__, search_global=False ), search_global=False )
def get_conn(): ''' Return a conn object for the passed VM data ''' certificate_path = config.get_cloud_config_value( 'certificate_path', get_configured_provider(), __opts__, search_global=False ) subscription_id = config.get_cloud_config_value( 'subscription_id', get_configured_provider(), __opts__, search_global=False ) return azure.servicemanagement.ServiceManagementService( subscription_id, certificate_path )
def get_conn(): ''' Return a conn object for the passed VM data ''' driver = get_driver(Provider.GCE) provider = get_configured_provider() project = config.get_cloud_config_value('project', provider, __opts__) email = config.get_cloud_config_value('service_account_email_address', provider, __opts__) private_key = config.get_cloud_config_value('service_account_private_key', provider, __opts__) gce = driver(email, private_key, project=project) gce.connection.user_agent_append('{0}/{1}'.format(_UA_PRODUCT, _UA_VERSION)) return gce
def _toggle_term_protect(name, enabled): ''' Toggle termination protection on a node ''' # region is required for all boto queries region = get_location(None) # init botocore vm_ = get_configured_provider() session = botocore.session.get_session() # pylint: disable=E0602 session.set_credentials( access_key=config.get_cloud_config_value( 'id', vm_, __opts__, search_global=False ), secret_key=config.get_cloud_config_value( 'key', vm_, __opts__, search_global=False ) ) service = session.get_service('ec2') endpoint = service.get_endpoint(region) # get the instance-id for the supplied node name conn = get_conn(location=region) node = get_node(conn, name) params = { 'instance_id': node.id, 'attribute': 'disableApiTermination', 'value': 'true' if enabled else 'false', } # get instance information operation = service.get_operation('modify-instance-attribute') http_response, response_data = operation.call(endpoint, **params) if http_response.status_code == 200: msg = 'Termination protection successfully {0} on {1}'.format( enabled and 'enabled' or 'disabled', name ) log.info(msg) return msg # No proper HTTP response!? msg = 'Bad response from AWS: {0}'.format(http_response.status_code) log.error(msg) return msg
def destroy(name): ''' Wrap core libcloudfuncs destroy method, adding check for termination protection ''' ret = {} newname = name if config.get_cloud_config_value('rename_on_destroy', get_configured_provider(), __opts__, search_global=False) is True: newname = '{0}-DEL{1}'.format(name, uuid.uuid4().hex) rename(name, kwargs={'newname': newname}, call='action') log.info( 'Machine will be identified as {0} until it has been ' 'cleaned up by AWS.'.format( newname ) ) ret['newname'] = newname try: result = libcloudfuncs_destroy(newname, get_conn()) ret.update({'Destroyed': result}) except Exception as exc: if not exc.message.startswith('OperationNotPermitted'): log.exception(exc) raise exc log.info( 'Failed: termination protection is enabled on {0}'.format( name ) ) return ret
def create_node(vm_, newid): """ Build and submit the requestdata to create a new node """ newnode = {} if "technology" not in vm_: vm_["technology"] = "openvz" # default virt tech if none is given if vm_["technology"] not in ["qemu", "openvz", "lxc"]: # Wrong VM type given log.error( "Wrong VM type. Valid options are: qemu, openvz (proxmox3) or lxc" " (proxmox4)") raise SaltCloudExecutionFailure if "host" not in vm_: # Use globally configured/default location vm_["host"] = config.get_cloud_config_value("default_host", get_configured_provider(), __opts__, search_global=False) if vm_["host"] is None: # No location given for the profile log.error("No host given to create this VM on") raise SaltCloudExecutionFailure # Required by both OpenVZ and Qemu (KVM) vmhost = vm_["host"] newnode["vmid"] = newid for prop in "cpuunits", "description", "memory", "onboot": if prop in vm_: # if the property is set, use it for the VM request newnode[prop] = vm_[prop] if vm_["technology"] == "openvz": # OpenVZ related settings, using non-default names: newnode["hostname"] = vm_["name"] newnode["ostemplate"] = vm_["image"] # optional VZ settings for prop in ( "cpus", "disk", "ip_address", "nameserver", "password", "swap", "poolid", "storage", ): if prop in vm_: # if the property is set, use it for the VM request newnode[prop] = vm_[prop] elif vm_["technology"] == "lxc": # LXC related settings, using non-default names: newnode["hostname"] = vm_["name"] newnode["ostemplate"] = vm_["image"] static_props = ( "cpuunits", "cpulimit", "rootfs", "cores", "description", "memory", "onboot", "net0", "password", "nameserver", "swap", "storage", "rootfs", ) for prop in _get_properties("/nodes/{node}/lxc", "POST", static_props): if prop in vm_: # if the property is set, use it for the VM request newnode[prop] = vm_[prop] if "pubkey" in vm_: newnode["ssh-public-keys"] = vm_["pubkey"] # inform user the "disk" option is not supported for LXC hosts if "disk" in vm_: log.warning( 'The "disk" option is not supported for LXC hosts and was ignored' ) # LXC specific network config # OpenVZ allowed specifying IP and gateway. To ease migration from # Proxmox 3, I've mapped the ip_address and gw to a generic net0 config. # If you need more control, please use the net0 option directly. # This also assumes a /24 subnet. if "ip_address" in vm_ and "net0" not in vm_: newnode["net0"] = ("bridge=vmbr0,ip=" + vm_["ip_address"] + "/24,name=eth0,type=veth") # gateway is optional and does not assume a default if "gw" in vm_: newnode["net0"] = newnode["net0"] + ",gw=" + vm_["gw"] elif vm_["technology"] == "qemu": # optional Qemu settings static_props = ( "acpi", "cores", "cpu", "pool", "storage", "sata0", "ostype", "ide2", "net0", ) for prop in _get_properties("/nodes/{node}/qemu", "POST", static_props): if prop in vm_: # if the property is set, use it for the VM request newnode[prop] = vm_[prop] # The node is ready. Lets request it to be added __utils__["cloud.fire_event"]( "event", "requesting instance", "salt/cloud/{}/requesting".format(vm_["name"]), args={ "kwargs": __utils__["cloud.filter_event"]("requesting", newnode, list(newnode)), }, sock_dir=__opts__["sock_dir"], ) log.debug("Preparing to generate a node using these parameters: %s ", newnode) if "clone" in vm_ and vm_["clone"] is True and vm_["technology"] == "qemu": postParams = {} postParams["newid"] = newnode["vmid"] for prop in "description", "format", "full", "name": if ("clone_" + prop in vm_ ): # if the property is set, use it for the VM request postParams[prop] = vm_["clone_" + prop] try: int(vm_["clone_from"]) except ValueError: if ":" in vm_["clone_from"]: vmhost = vm_["clone_from"].split(":")[0] vm_["clone_from"] = vm_["clone_from"].split(":")[1] node = query( "post", "nodes/{}/qemu/{}/clone".format(vmhost, vm_["clone_from"]), postParams, ) else: node = query("post", "nodes/{}/{}".format(vmhost, vm_["technology"]), newnode) return _parse_proxmox_upid(node, vm_)
def create(vm_): ''' Create a single VM from a data dict ''' 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'])) 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_['provider'], }, transport=__opts__['transport']) return ret
def request_instance(vm_=None, call=None): ''' Put together all of the information necessary to request an instance on Openstack and then fire off the request the instance. Returns data about the instance ''' if call == 'function': # Technically this function may be called other ways too, but it # definitely cannot be called with --function. raise SaltCloudSystemExit( 'The request_instance action must be called with -a or --action.') salt.utils.cloud.check_name(vm_['name'], 'a-zA-Z0-9._-') conn = get_conn() kwargs = {'name': vm_['name']} try: kwargs['image'] = get_image(conn, vm_) except Exception as exc: raise SaltCloudSystemExit('Error creating {0} on OPENSTACK\n\n' 'Could not find image {1}: {2}\n'.format( vm_['name'], vm_['image'], exc)) try: kwargs['size'] = get_size(conn, vm_) except Exception as exc: raise SaltCloudSystemExit('Error creating {0} on OPENSTACK\n\n' 'Could not find size {1}: {2}\n'.format( vm_['name'], vm_['size'], exc)) # Note: This currently requires libcloud trunk avz = config.get_cloud_config_value('availability_zone', vm_, __opts__, default=None, search_global=False) if avz is not None: kwargs['ex_availability_zone'] = avz kwargs['ex_keyname'] = config.get_cloud_config_value('ssh_key_name', vm_, __opts__, search_global=False) security_groups = config.get_cloud_config_value('security_groups', vm_, __opts__, search_global=False) if security_groups is not None: vm_groups = security_groups.split(',') avail_groups = conn.ex_list_security_groups() group_list = [] for vmg in vm_groups: if vmg in [ag.name for ag in avail_groups]: group_list.append(vmg) else: raise SaltCloudNotFound( 'No such security group: \'{0}\''.format(vmg)) kwargs['ex_security_groups'] = [ g for g in avail_groups if g.name in group_list ] networks = config.get_cloud_config_value('networks', vm_, __opts__, search_global=False) floating = [] if HAS014: if networks is not None: for net in networks: if 'fixed' in net: kwargs['networks'] = [ OpenStackNetwork(n, None, None, None) for n in net['fixed'] ] elif 'floating' in net: pool = OpenStack_1_1_FloatingIpPool( net['floating'], conn.connection) for idx in pool.list_floating_ips(): if idx.node_id is None: floating.append(idx) if not floating: # Note(pabelanger): We have no available floating IPs. # For now, we raise an exception and exit. # A future enhancement might be to allow salt-cloud # to dynamically allocate new address but that might raise SaltCloudSystemExit( 'Floating pool {0!r} does not have any more ' 'please create some more or use a different ' 'pool.'.format(net['floating'])) # otherwise, attempt to obtain list without specifying pool # this is the same as 'nova floating-ip-list' elif ssh_interface(vm_) != 'private_ips': try: # This try/except is here because it appears some # *cough* Rackspace *cough* # OpenStack providers return a 404 Not Found for the # floating ip pool URL if there are no pools setup pool = OpenStack_1_1_FloatingIpPool('', conn.connection) for idx in pool.list_floating_ips(): if idx.node_id is None: floating.append(idx) if not floating: # Note(pabelanger): We have no available floating IPs. # For now, we raise an exception and exit. # A future enhancement might be to allow salt-cloud to # dynamically allocate new address but that might be # tricky to manage. raise SaltCloudSystemExit( 'There are no more floating IP addresses ' 'available, please create some more') except Exception as e: if str(e).startswith('404'): pass else: raise vm_['floating'] = floating files = config.get_cloud_config_value('files', vm_, __opts__, search_global=False) if files: kwargs['ex_files'] = {} for src_path in files: with salt.utils.fopen(files[src_path], 'r') as fp_: kwargs['ex_files'][src_path] = fp_.read() userdata_file = config.get_cloud_config_value('userdata_file', vm_, __opts__, search_global=False) if userdata_file is not None: with salt.utils.fopen(userdata_file, 'r') as fp: kwargs['ex_userdata'] = fp.read() 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, 'profile': vm_['profile'] } }, transport=__opts__['transport']) default_profile = {} if 'profile' in vm_ and vm_['profile'] is not None: default_profile = {'profile': vm_['profile']} kwargs['ex_metadata'] = config.get_cloud_config_value( 'metadata', vm_, __opts__, default=default_profile, search_global=False) if not isinstance(kwargs['ex_metadata'], dict): raise SaltCloudConfigError('\'metadata\' should be a dict.') try: data = conn.create_node(**kwargs) return data, vm_ except Exception as exc: raise SaltCloudSystemExit( 'Error creating {0} on OpenStack\n\n' 'The following exception was thrown by libcloud when trying to ' 'run the initial deployment: {1}\n'.format(vm_['name'], exc))
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/{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"]) 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"] = six.text_type(vm_["internet_maxbandwidthin"]) if "internet_maxbandwidthout" in vm_: kwargs["InternetMaxBandwidthOut"] = six.text_type( 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/{0}/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"], six.text_type(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(six.text_type(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/{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_node(vm_): ''' Build and submit the requestdata to create a new node ''' newnode = {} if 'technology' not in vm_: vm_['technology'] = 'openvz' # default virt tech if none is given if vm_['technology'] not in ['qemu', 'openvz']: # Wrong VM type given raise SaltCloudExecutionFailure if 'host' not in vm_: # Use globally configured/default location vm_['host'] = config.get_cloud_config_value('default_host', get_configured_provider(), __opts__, search_global=False) if vm_['host'] is None: # No location given for the profile log.error('No host given to create this VM on') raise SaltCloudExecutionFailure # Required by both OpenVZ and Qemu (KVM) vmhost = vm_['host'] newnode['vmid'] = _get_next_vmid() for prop in ('cpuunits', 'description', 'memory', 'onboot'): if prop in vm_: # if the property is set, use it for the VM request newnode[prop] = vm_[prop] if vm_['technology'] == 'openvz': # OpenVZ related settings, using non-default names: newnode['hostname'] = vm_['name'] newnode['ostemplate'] = vm_['image'] # optional VZ settings for prop in ('cpus', 'disk', 'ip_address', 'nameserver', 'password', 'swap', 'poolid'): if prop in vm_: # if the property is set, use it for the VM request newnode[prop] = vm_[prop] elif vm_['technology'] == 'qemu': # optional Qemu settings for prop in ('acpi', 'cores', 'cpu', 'pool'): if prop in vm_: # if the property is set, use it for the VM request newnode[prop] = vm_[prop] # The node is ready. Lets request it to be added salt.utils.cloud.fire_event( 'event', 'requesting instance', 'salt/cloud/{0}/requesting'.format(vm_['name']), {'kwargs': newnode}, ) log.debug( 'Preparing to generate a node using these parameters: {0} '.format( newnode)) node = query('post', 'nodes/{0}/{1}'.format(vmhost, vm_['technology']), newnode) return _parse_proxmox_upid(node, vm_)
def create(vm_): """ Create a single VM from a data dict """ 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 '{}' does not exist".format(key_filename) ) vm_["key_filename"] = key_filename __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"], ) 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 '%s'", vm_["name"]) vm_["priv_key"], vm_["pub_key"] = __utils__["cloud.gen_keys"]( config.get_cloud_config_value("keysize", vm_, __opts__) ) else: # Put together all of the information required to request the instance, # and then fire off the request for it request_instance(conn=conn, call="action", vm_=vm_) data = show_instance(vm_.get("instance_id", vm_["name"]), conn=conn, call="action") log.debug("VM is now running") def __query_node(vm_): data = show_instance(vm_["name"], conn=conn, call="action") if "wait_for_metadata" in vm_: for key, value in vm_.get("wait_for_metadata", {}).items(): log.debug("Waiting for metadata: %s=%s", key, value) if data["metadata"].get(key, None) != value: log.debug( "Metadata is not ready: %s=%s", key, data["metadata"].get(key) ) return False return preferred_ip(vm_, data[ssh_interface(vm_)]) try: ip_address = __utils__["cloud.wait_for_fun"](__query_node, vm_=vm_) 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("Using IP address %s", ip_address) salt_interface = __utils__["cloud.get_salt_interface"](vm_, __opts__) salt_ip_address = preferred_ip(vm_, data[salt_interface]) log.debug("Salt interface set to: %s", 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 = __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)) event_data = { "name": vm_["name"], "profile": vm_["profile"], "provider": vm_["driver"], "instance_id": data["id"], "floating_ips": data["floating_ips"], "fixed_ips": data["fixed_ips"], "private_ips": data["private_ips"], "public_ips": data["public_ips"], } __utils__["cloud.fire_event"]( "event", "created instance", "salt/cloud/{}/created".format(vm_["name"]), args=__utils__["cloud.filter_event"]("created", event_data, list(event_data)), sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], ) __utils__["cloud.cachedir_index_add"]( vm_["name"], vm_["profile"], "nova", vm_["driver"] ) return ret
def request_instance(vm_=None, call=None): ''' Put together all of the information necessary to request an instance through Novaclient and then fire off the request the instance. Returns data about the instance ''' if call == 'function': # Technically this function may be called other ways too, but it # definitely cannot be called with --function. raise SaltCloudSystemExit( 'The request_instance action must be called with -a or --action.') log.info('Creating Cloud VM {0}'.format(vm_['name'])) salt.utils.cloud.check_name(vm_['name'], 'a-zA-Z0-9._-') conn = get_conn() kwargs = vm_.copy() try: kwargs['image_id'] = get_image(conn, vm_) except Exception as exc: raise SaltCloudSystemExit('Error creating {0} on OPENSTACK\n\n' 'Could not find image {1}: {2}\n'.format( vm_['name'], vm_['image'], exc)) try: kwargs['flavor_id'] = get_size(conn, vm_) except Exception as exc: raise SaltCloudSystemExit('Error creating {0} on OPENSTACK\n\n' 'Could not find size {1}: {2}\n'.format( vm_['name'], vm_['size'], exc)) kwargs['key_name'] = config.get_cloud_config_value('ssh_key_name', vm_, __opts__, search_global=False) security_groups = config.get_cloud_config_value('security_groups', vm_, __opts__, search_global=False) if security_groups is not None: vm_groups = security_groups.split(',') avail_groups = conn.secgroup_list() group_list = [] for vmg in vm_groups: if vmg in [name for name, details in six.iteritems(avail_groups)]: group_list.append(vmg) else: raise SaltCloudNotFound( 'No such security group: \'{0}\''.format(vmg)) kwargs['security_groups'] = group_list avz = config.get_cloud_config_value('availability_zone', vm_, __opts__, default=None, search_global=False) if avz is not None: kwargs['availability_zone'] = avz kwargs['nics'] = config.get_cloud_config_value('networks', vm_, __opts__, search_global=False, default=None) files = config.get_cloud_config_value('files', vm_, __opts__, search_global=False) if files: kwargs['files'] = {} for src_path in files: if os.path.exists(files[src_path]): with salt.utils.fopen(files[src_path], 'r') as fp_: kwargs['files'][src_path] = fp_.read() else: kwargs['files'][src_path] = files[src_path] userdata_file = config.get_cloud_config_value('userdata_file', vm_, __opts__, search_global=False) if userdata_file is not None: with salt.utils.fopen(userdata_file, 'r') as fp: kwargs['userdata'] = fp.read() kwargs['config_drive'] = config.get_cloud_config_value('config_drive', vm_, __opts__, search_global=False) kwargs.update(get_block_mapping_opts(vm_)) salt.utils.cloud.fire_event( 'event', 'requesting instance', 'salt/cloud/{0}/requesting'.format(vm_['name']), { 'kwargs': { 'name': kwargs['name'], 'image': kwargs.get('image_id', 'Boot From Volume'), 'size': kwargs['flavor_id'] } }, transport=__opts__['transport']) try: data = conn.boot(**kwargs) except Exception as exc: raise SaltCloudSystemExit( 'Error creating {0} on Nova\n\n' 'The following exception was thrown by libcloud when trying to ' 'run the initial deployment: {1}\n'.format(vm_['name'], exc)) if data.extra.get('password', None) is None and vm_.get( 'key_filename', None) is None: raise SaltCloudSystemExit('No password returned. Set ssh_key_file.') floating_ip_conf = config.get_cloud_config_value('floating_ip', vm_, __opts__, search_global=False, default={}) if floating_ip_conf.get('auto_assign', False): pool = floating_ip_conf.get('pool', 'public') floating_ip = None for fl_ip, opts in conn.floating_ip_list().iteritems(): if opts['fixed_ip'] is None and opts['pool'] == pool: floating_ip = fl_ip break if floating_ip is None: floating_ip = conn.floating_ip_create(pool)['ip'] try: conn.floating_ip_associate(kwargs['name'], floating_ip) vm_['floating_ip'] = floating_ip except Exception as exc: raise SaltCloudSystemExit( 'Error assigning floating_ip for {0} on Nova\n\n' 'The following exception was thrown by libcloud when trying to ' 'assing a floating ip: {1}\n'.format(vm_['name'], exc)) vm_['password'] = data.extra.get('password', '') return data, vm_
def request_instance(vm_=None, call=None): ''' Put together all of the information necessary to request an instance on Openstack and then fire off the request the instance. Returns data about the instance ''' if call == 'function': # Technically this function may be called other ways too, but it # definitely cannot be called with --function. raise SaltCloudSystemExit( 'The request_instance action must be called with -a or --action.') salt.utils.cloud.check_name(vm_['name'], 'a-zA-Z0-9._-') conn = get_conn() kwargs = {'name': vm_['name']} try: kwargs['image'] = get_image(conn, vm_) except Exception as exc: raise SaltCloudSystemExit('Error creating {0} on OPENSTACK\n\n' 'Could not find image {1}: {2}\n'.format( vm_['name'], vm_['image'], exc)) try: kwargs['size'] = get_size(conn, vm_) except Exception as exc: raise SaltCloudSystemExit('Error creating {0} on OPENSTACK\n\n' 'Could not find size {1}: {2}\n'.format( vm_['name'], vm_['size'], exc)) # Note: This currently requires libcloud trunk avz = config.get_cloud_config_value('availability_zone', vm_, __opts__, default=None, search_global=False) if avz is not None: kwargs['ex_availability_zone'] = avz kwargs['ex_keyname'] = config.get_cloud_config_value('ssh_key_name', vm_, __opts__, search_global=False) security_groups = config.get_cloud_config_value('security_groups', vm_, __opts__, search_global=False) if security_groups is not None: vm_groups = security_groups.split(',') avail_groups = conn.ex_list_security_groups() group_list = [] for vmg in vm_groups: if vmg in [ag.name for ag in avail_groups]: group_list.append(vmg) else: raise SaltCloudNotFound( 'No such security group: \'{0}\''.format(vmg)) kwargs['ex_security_groups'] = [ g for g in avail_groups if g.name in group_list ] networks(vm_, kwargs) files = config.get_cloud_config_value('files', vm_, __opts__, search_global=False) if files: kwargs['ex_files'] = {} for src_path in files: with salt.utils.fopen(files[src_path], 'r') as fp_: kwargs['ex_files'][src_path] = fp_.read() userdata_file = config.get_cloud_config_value('userdata_file', vm_, __opts__, search_global=False) if userdata_file is not None: with salt.utils.fopen(userdata_file, 'r') as fp: kwargs['ex_userdata'] = fp.read() config_drive = config.get_cloud_config_value('config_drive', vm_, __opts__, default=None, search_global=False) if config_drive is not None: kwargs['ex_config_drive'] = config_drive 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, 'profile': vm_['profile'] } }, transport=__opts__['transport']) default_profile = {} if 'profile' in vm_ and vm_['profile'] is not None: default_profile = {'profile': vm_['profile']} kwargs['ex_metadata'] = config.get_cloud_config_value( 'metadata', vm_, __opts__, default=default_profile, 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: raise SaltCloudSystemExit( 'Error creating {0} on OpenStack\n\n' 'The following exception was thrown by libcloud when trying to ' 'run the initial deployment: {1}\n'.format(vm_['name'], exc)) vm_['password'] = data.extra.get('password', None) return data, vm_
def get_conn(): ''' Return a conn object for the passed VM data ''' vm_ = get_configured_provider() driver = get_driver(Provider.OPENSTACK) authinfo = { 'ex_force_auth_url': config.get_cloud_config_value('identity_url', vm_, __opts__, search_global=False), 'ex_force_service_name': config.get_cloud_config_value('compute_name', vm_, __opts__, search_global=False), 'ex_force_service_region': config.get_cloud_config_value('compute_region', vm_, __opts__, search_global=False), 'ex_tenant_name': config.get_cloud_config_value('tenant', vm_, __opts__, search_global=False), } service_type = config.get_cloud_config_value('service_type', vm_, __opts__, search_global=False) if service_type: authinfo['ex_force_service_type'] = service_type base_url = config.get_cloud_config_value('base_url', vm_, __opts__, search_global=False) if base_url: authinfo['ex_force_base_url'] = base_url insecure = config.get_cloud_config_value('insecure', vm_, __opts__, search_global=False) if insecure: import libcloud.security libcloud.security.VERIFY_SSL_CERT = False user = config.get_cloud_config_value('user', vm_, __opts__, search_global=False) password = config.get_cloud_config_value('password', vm_, __opts__, search_global=False) if password is not None: authinfo['ex_force_auth_version'] = '2.0_password' log.debug('OpenStack authenticating using password') if password == 'USE_KEYRING': # retrieve password from system keyring credential_id = "salt.cloud.provider.{0}".format( __active_provider_name__) logging.debug("Retrieving keyring password for {0} ({1})".format( credential_id, user)) # attempt to retrieve driver specific password first driver_password = salt.utils.cloud.retrieve_password_from_keyring( credential_id, user) if driver_password is None: provider_password = salt.utils.cloud.retrieve_password_from_keyring( credential_id.split(':')[0], # fallback to provider level user) if provider_password is None: raise SaltCloudSystemExit( "Unable to retrieve password from keyring for provider {0}" .format(__active_provider_name__)) else: actual_password = provider_password else: actual_password = password return driver(user, actual_password, **authinfo) authinfo['ex_force_auth_version'] = '2.0_apikey' log.debug('OpenStack authenticating using apikey') return driver( user, config.get_cloud_config_value('apikey', vm_, __opts__, search_global=False), **authinfo)
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 ''' 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_['provider'], }, 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 get_salt_interface(vm_) == '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_['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 'softlayer', vm_['profile'], vm_=vm_) is False: return False except AttributeError: pass name = vm_['name'] hostname = name domain = config.get_cloud_config_value('domain', vm_, __opts__, default=None) if domain is None: SaltCloudSystemExit( 'A domain name is required for the SoftLayer driver.') if vm_.get('use_fqdn'): name = '.'.join([name, domain]) vm_['name'] = name __utils__['cloud.fire_event']( 'event', 'starting create', 'salt/cloud/{0}/creating'.format(name), args=__utils__['cloud.filter_event']( 'creating', vm_, ['name', 'profile', 'provider', 'driver']), sock_dir=__opts__['sock_dir'], transport=__opts__['transport']) log.info('Creating Cloud VM %s', name) conn = get_conn() kwargs = { 'hostname': hostname, 'domain': domain, 'startCpus': vm_['cpu_number'], 'maxMemory': vm_['ram'], 'hourlyBillingFlag': vm_['hourly_billing'], } local_disk_flag = config.get_cloud_config_value('local_disk', vm_, __opts__, default=False) kwargs['localDiskFlag'] = local_disk_flag if 'image' in vm_: kwargs['operatingSystemReferenceCode'] = vm_['image'] kwargs['blockDevices'] = [] disks = vm_['disk_size'] if isinstance(disks, int): disks = [six.text_type(disks)] elif isinstance(disks, six.string_types): disks = [size.strip() for size in disks.split(',')] count = 0 for disk in disks: # device number '1' is reserved for the SWAP disk if count == 1: count += 1 block_device = { 'device': six.text_type(count), 'diskImage': { 'capacity': six.text_type(disk) } } kwargs['blockDevices'].append(block_device) count += 1 # Upper bound must be 5 as we're skipping '1' for the SWAP disk ID if count > 5: log.warning( 'More that 5 disks were specified for %s .' 'The first 5 disks will be applied to the VM, ' 'but the remaining disks will be ignored.\n' 'Please adjust your cloud configuration to only ' 'specify a maximum of 5 disks.', name) break elif 'global_identifier' in vm_: kwargs['blockDeviceTemplateGroup'] = { 'globalIdentifier': vm_['global_identifier'] } location = get_location(vm_) if location: kwargs['datacenter'] = {'name': location} private_vlan = config.get_cloud_config_value('private_vlan', vm_, __opts__, default=False) if private_vlan: kwargs['primaryBackendNetworkComponent'] = { 'networkVlan': { 'id': private_vlan, } } private_network = config.get_cloud_config_value('private_network', vm_, __opts__, default=False) if bool(private_network) is True: kwargs['privateNetworkOnlyFlag'] = 'True' public_vlan = config.get_cloud_config_value('public_vlan', vm_, __opts__, default=False) if public_vlan: kwargs['primaryNetworkComponent'] = { 'networkVlan': { 'id': public_vlan, } } max_net_speed = config.get_cloud_config_value('max_net_speed', vm_, __opts__, default=10) if max_net_speed: kwargs['networkComponents'] = [{'maxSpeed': int(max_net_speed)}] post_uri = config.get_cloud_config_value('post_uri', vm_, __opts__, default=None) if post_uri: kwargs['postInstallScriptUri'] = post_uri dedicated_host_id = config.get_cloud_config_value('dedicated_host_id', vm_, __opts__, default=None) if dedicated_host_id: kwargs['dedicatedHost'] = {'id': dedicated_host_id} __utils__['cloud.fire_event']('event', 'requesting instance', 'salt/cloud/{0}/requesting'.format(name), args={ 'kwargs': __utils__['cloud.filter_event']( 'requesting', kwargs, list(kwargs)), }, sock_dir=__opts__['sock_dir'], transport=__opts__['transport']) try: response = conn.createObject(kwargs) except Exception as exc: log.error( 'Error creating %s on SoftLayer\n\n' 'The following exception was thrown when trying to ' 'run the initial deployment: \n%s', name, exc, # Show the traceback if the debug logging level is enabled exc_info_on_loglevel=logging.DEBUG) return False ip_type = 'primaryIpAddress' private_ssh = config.get_cloud_config_value('private_ssh', vm_, __opts__, default=False) private_wds = config.get_cloud_config_value('private_windows', vm_, __opts__, default=False) if private_ssh or private_wds or public_vlan is None: ip_type = 'primaryBackendIpAddress' def wait_for_ip(): ''' Wait for the IP address to become available ''' nodes = list_nodes_full() if ip_type in nodes[hostname]: return nodes[hostname][ip_type] time.sleep(1) return False ip_address = salt.utils.cloud.wait_for_fun( wait_for_ip, timeout=config.get_cloud_config_value('wait_for_fun_timeout', vm_, __opts__, default=15 * 60), ) if config.get_cloud_config_value('deploy', vm_, __opts__) is not True: return show_instance(hostname, call='action') SSH_PORT = 22 WINDOWS_DS_PORT = 445 managing_port = SSH_PORT if config.get_cloud_config_value('windows', vm_, __opts__) or \ config.get_cloud_config_value('win_installer', vm_, __opts__): managing_port = WINDOWS_DS_PORT ssh_connect_timeout = config.get_cloud_config_value( 'ssh_connect_timeout', vm_, __opts__, 15 * 60) connect_timeout = config.get_cloud_config_value('connect_timeout', vm_, __opts__, ssh_connect_timeout) if not salt.utils.cloud.wait_for_port( ip_address, port=managing_port, timeout=connect_timeout): raise SaltCloudSystemExit('Failed to authenticate against remote ssh') pass_conn = get_conn(service='SoftLayer_Account') mask = { 'virtualGuests': { 'powerState': '', 'operatingSystem': { 'passwords': '' }, }, } def get_credentials(): ''' Wait for the password to become available ''' node_info = pass_conn.getVirtualGuests(id=response['id'], mask=mask) for node in node_info: if node['id'] == response['id'] and \ 'passwords' in node['operatingSystem'] and \ 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 ''' salt.utils.cloud.fire_event( 'event', 'starting create', 'salt/cloud/{0}/creating'.format(vm_['name']), { 'name': vm_['name'], 'profile': vm_['profile'], 'provider': vm_['provider'], }, ) 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}, ) try: response = conn.createObject(kwargs) except Exception as exc: log.error( 'Error creating {0} on SoftLayer\n\n' 'The following exception was thrown by libcloud when trying to ' 'run the initial deployment: \n{1}'.format( vm_['name'], exc.message ), # Show the traceback if the debug logging level is enabled exc_info=log.isEnabledFor(logging.DEBUG) ) return False ip_type = 'primaryIpAddress' private_ssh = config.get_cloud_config_value( 'private_ssh', vm_, __opts__, default=False ) if private_ssh: 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_connect_timeout = config.get_cloud_config_value( 'ssh_connect_timeout', vm_, __opts__, 900 # 15 minutes ) 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']: if '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' ) ret = {} if config.get_cloud_config_value('deploy', vm_, __opts__) is True: deploy_script = script(vm_) deploy_kwargs = { 'host': ip_address, 'username': ssh_username, 'password': passwd, '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}, ) 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'] ) ) log.info('Created Cloud VM {0[name]!r}'.format(vm_)) log.debug( '{0[name]!r} VM creation details:\n{1}'.format( vm_, pprint.pformat(response) ) ) 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_['provider'], }, ) 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__, _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 'vsphere', 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']), 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() salt.utils.cloud.fire_event('event', 'requesting instance', 'salt/cloud/{0}/requesting'.format( vm_['name']), args={'kwargs': vm_}, sock_dir=__opts__['sock_dir'], 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']), 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 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!r} 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 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)) for network in data['networks']['v4']: if network['type'] == 'public': ip_address = network['ip_address'] vm_['key_filename'] = key_filename vm_['ssh_host'] = ip_address 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__, _get_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/{}/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/{}/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: # pylint: disable=broad-except 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 node["operatingSystem"]["passwords"]): 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/{}/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 ''' if 'driver' not in vm_: vm_['driver'] = vm_['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'] ) kwargs = { 'label': vm_['name'], 'OSID': vm_['image'], 'VPSPLANID': vm_['size'], 'DCID': vm_['location'], } log.info('Creating Cloud VM {0}'.format(vm_['name'])) salt.utils.cloud.fire_event( 'event', 'requesting instance', 'salt/cloud/{0}/requesting'.format(vm_['name']), {'kwargs': kwargs}, transport=__opts__['transport'], ) try: data = _query('server/create', method='POST', data=kwargs) except Exception as exc: log.error( 'Error creating {0} on Vultr\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 def wait_for_hostname(): ''' Wait for the IP address to become available ''' data = show_instance(vm_['name'], call='action') pprint.pprint(data) if str(data.get('main_ip', '0')) == '0': time.sleep(3) return False return data['main_ip'] def wait_for_default_password(): ''' Wait for the IP address to become available ''' data = show_instance(vm_['name'], call='action') pprint.pprint(data) if str(data.get('default_password', '')) == '': time.sleep(1) return False if '!' not in data['default_password']: time.sleep(1) return False return data['default_password'] vm_['ssh_host'] = salt.utils.cloud.wait_for_fun( wait_for_hostname, timeout=config.get_cloud_config_value( 'wait_for_fun_timeout', vm_, __opts__, default=15 * 60), ) vm_['password'] = salt.utils.cloud.wait_for_fun( wait_for_default_password, timeout=config.get_cloud_config_value( 'wait_for_fun_timeout', vm_, __opts__, default=15 * 60), ) __opts__['hard_timeout'] = config.get_cloud_config_value( 'hard_timeout', get_configured_provider(), __opts__, search_global=False, default=15, ) # Bootstrap ret = salt.utils.cloud.bootstrap(vm_, __opts__) ret.update(show_instance(vm_['name'], call='action')) 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 '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): 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']] if not result: temp_dd = node.get('addresses', {}) for k, addr_ll in temp_dd.iteritems(): for addr_dd in addr_ll: addr = addr_dd.get('addr', None) if addr is not None: result.append(addr.strip()) 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 'digital_ocean', 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'] ) 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 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 {}".format(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 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_domain, name=dns_hostname, record_type=t, record_data=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.' ) __utils__['cloud.fire_event']( 'event', 'requesting instance', 'salt/cloud/{0}/requesting'.format(vm_['name']), args=__utils__['cloud.filter_event']('requesting', kwargs, kwargs.keys()), sock_dir=__opts__['sock_dir'], 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 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: {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 = __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=__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 'dimensiondata', vm_['profile']) 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'] ) log.info('Creating Cloud VM %s', vm_['name']) conn = get_conn() rootPw = NodeAuthPassword(vm_['auth']) 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, 'auth': rootPw, 'ex_description': vm_['description'], 'ex_network_domain': network_domain, 'ex_vlan': vlan, 'ex_is_started': vm_['is_started'] } event_data = kwargs.copy() del event_data['auth'] __utils__['cloud.fire_event']( 'event', 'requesting instance', 'salt/cloud/{0}/requesting'.format(vm_['name']), args=__utils__['cloud.filter_event']('requesting', event_data, list(event_data)), sock_dir=__opts__['sock_dir'], transport=__opts__['transport'] ) try: 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 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__) ) ) __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 ''' salt.utils.cloud.fire_event( 'event', 'starting create', 'salt/cloud/{0}/creating'.format(vm_['name']), { 'name': vm_['name'], 'profile': vm_['profile'], 'provider': vm_['provider'], }, ) 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), ) 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}}, ) 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'], exc.message ), # 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 = { '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}, ) 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'], }, ) 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 # 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']), args={ 'name': server_['name'], 'profile': server_['profile'], 'provider': server_['driver'], }, sock_dir=__opts__['sock_dir'], 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) commercial_type = config.get_cloud_config_value('commercial_type', server_, __opts__, default='C1') kwargs = { 'name': server_['name'], 'organization': access_key, 'image': get_image(server_), 'commercial_type': commercial_type, } salt.utils.cloud.fire_event('event', 'requesting instance', 'salt/cloud/{0}/requesting'.format( server_['name']), args={'kwargs': kwargs}, sock_dir=__opts__['sock_dir'], 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']), args={ 'name': server_['name'], 'profile': server_['profile'], 'provider': server_['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 'gogrid', 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'] ) 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, } salt.utils.cloud.fire_event( 'event', 'requesting instance', 'salt/cloud/{0}/requesting'.format(vm_['name']), {'kwargs': create_kwargs}, 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 = 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 CLI Example: .. code-block:: bash salt-cloud -p proxmox-ubuntu vmhostname ''' ret = {} deploy = config.get_cloud_config_value('deploy', vm_, __opts__) if deploy is True and salt.utils.which('sshpass') is None: raise SaltCloudSystemExit( 'Cannot deploy salt in a VM if the \'sshpass\' binary is not ' 'present on the system.') 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'])) 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'], exc.message), # 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, host, nodeType, '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 # Check whether we need to deploy and are on OpenVZ rather than KVM which # does not (yet) provide support for automatic provisioning if config.get_cloud_config_value( 'deploy', vm_, __opts__) is True and config.get_cloud_config_value( 'technology', vm_, __opts__) == 'openvz': deploy_script = script(vm_) deploy_kwargs = { 'opts': __opts__, 'host': ip_address, 'username': ssh_username, 'password': ssh_password, 'script': deploy_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) 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'] # Store what was used to the deploy the VM ret['deploy_kwargs'] = deploy_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'])) # END Install Salt role(s) # 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_['provider'], }, ) return ret
def _query(action=None, command=None, args=None, method='GET', header_dict=None, data=None): ''' Make a web call to GoGrid .. versionadded:: Beryllium ''' vm_ = get_configured_provider() apikey = config.get_cloud_config_value( 'apikey', vm_, __opts__, search_global=False ) sharedsecret = config.get_cloud_config_value( 'sharedsecret', vm_, __opts__, search_global=False ) path = 'https://api.gogrid.com/api/' if action: path += action if command: path += '/{0}'.format(command) log.debug('GoGrid URL: {0}'.format(path)) if not isinstance(args, dict): args = {} epoch = str(int(time.time())) hashtext = ''.join((apikey, sharedsecret, epoch)) args['sig'] = hashlib.md5(hashtext).hexdigest() args['format'] = 'json' args['v'] = '1.0' args['api_key'] = apikey if header_dict is None: header_dict = {} if method != 'POST': header_dict['Accept'] = 'application/json' decode = True if method == 'DELETE': decode = False return_content = None result = salt.utils.http.query( path, method, params=args, data=data, header_dict=header_dict, decode=decode, decode_type='json', text=True, status=True, opts=__opts__, ) log.debug( 'GoGrid Response Status Code: {0}'.format( result['status'] ) ) return result['dict']
def query(method='droplets', droplet_id=None, command=None, args=None, http_method='get'): ''' Make a web call to DigitalOcean ''' base_path = str( config.get_cloud_config_value( 'api_root', get_configured_provider(), __opts__, search_global=False, default='https://api.digitalocean.com/v2')) path = '{0}/{1}/'.format(base_path, method) if droplet_id: path += '{0}/'.format(droplet_id) if command: path += command if not isinstance(args, dict): args = {} personal_access_token = config.get_cloud_config_value( 'personal_access_token', get_configured_provider(), __opts__, search_global=False) data = json.dumps(args) requester = getattr(requests, http_method) request = requester(path, data=data, headers={ 'Authorization': 'Bearer ' + personal_access_token, 'Content-Type': 'application/json' }) if request.status_code > 299: raise SaltCloudSystemExit( 'An error occurred while querying DigitalOcean. HTTP Code: {0} ' 'Error: \'{1}\''.format( request.status_code, # request.read() request.text)) log.debug(request.url) # success without data if request.status_code == 204: return True content = request.text result = json.loads(content) if result.get('status', '').lower() == 'error': raise SaltCloudSystemExit( pprint.pformat(result.get('error_message', {}))) return result
def _deploy(vm_): ''' run bootstrap script ''' # TODO: review salt.utils.cloud.bootstrap(vm_, __opts__) # TODO: review salt.utils.cloud.wait_for_ip ip_address = wait_for_ip(vm_) template_user = config.get_cloud_config_value('template_user', vm_, __opts__) template_password = config.get_cloud_config_value('template_password', vm_, __opts__) # new_instance = conn.get_vm_by_name(vm_['name']) # ret = new_instance.get_properties() ret = show_instance(name=vm_['name'], call='action') ret['ip_address'] = ip_address ret['username'] = template_user ret['password'] = template_password deploy_script = script(vm_) deploy_kwargs = { 'opts': __opts__, 'host': ip_address, 'username': template_user, 'password': template_password, 'script': deploy_script, 'name': vm_['name'], '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), '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_), 'sudo': config.get_cloud_config_value('sudo', vm_, __opts__, default=(template_user != 'root')), 'sudo_password': config.get_cloud_config_value('sudo_password', vm_, __opts__, default=None), 'key_filename': config.get_cloud_config_value('key_filename', vm_, __opts__, default=None) } # Store what was used to the deploy the VM ret['deploy_kwargs'] = deploy_kwargs # 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='') salt.utils.cloud.fire_event('event', 'executing deploy script', 'salt/cloud/{0}/deploying'.format(vm_['name']), args={'kwargs': deploy_kwargs}, sock_dir=__opts__['sock_dir'], 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'])) return ret['deploy_kwargs']
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']) 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]}\''.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_['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. Events fired: This function fires the event ``salt/cloud/vm_name/creating``, with the payload containing the names of the VM, profile, and provider. @param vm_info .. code-block:: text { name: <str> profile: <dict> driver: <provider>:<profile> clonefrom: <vm_name> clonemode: <mode> (default: state, choices: state, child, all) } @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) clone_mode = map_clonemode(vm_info) wait_for_pattern = vm_info[ 'waitforpattern'] if 'waitforpattern' in vm_info.keys() else None interface_index = vm_info[ 'interfaceindex'] if 'interfaceindex' in vm_info.keys() else 0 log.debug("Going to fire event: starting create") __utils__['cloud.fire_event']( 'event', 'starting create', 'salt/cloud/{0}/creating'.format(vm_info['name']), args=__utils__['cloud.filter_event']( 'creating', vm_info, ['name', 'profile', 'provider', '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'], 'clone_mode': clone_mode } __utils__['cloud.fire_event']( 'event', 'requesting instance', 'salt/cloud/{0}/requesting'.format(vm_info['name']), args=__utils__['cloud.filter_event']('requesting', request_kwargs, list(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, wait_for_pattern=wait_for_pattern) if ips: ip = ips[interface_index] log.info("[ %s ] IPv4 is: %s", 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 = __utils__['cloud.bootstrap'](vm_info, __opts__) vm_result.update(res) __utils__['cloud.fire_event']( 'event', 'created machine', 'salt/cloud/{0}/created'.format(vm_info['name']), args=__utils__['cloud.filter_event']('created', vm_result, list(vm_result)), sock_dir=__opts__['sock_dir'], transport=__opts__['transport']) # Passwords should be included in this object!! return vm_result