Beispiel #1
0
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
    )
Beispiel #2
0
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
Beispiel #3
0
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
    )
Beispiel #4
0
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'])
Beispiel #5
0
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)
Beispiel #6
0
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
Beispiel #7
0
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
Beispiel #10
0
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
Beispiel #11
0
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)
    )
Beispiel #12
0
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
Beispiel #13
0
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),
    )
Beispiel #14
0
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),
    )
Beispiel #15
0
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}
Beispiel #16
0
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
Beispiel #19
0
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
Beispiel #21
0
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
Beispiel #22
0
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
        )
    )
Beispiel #23
0
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()
Beispiel #24
0
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
        )

    }
Beispiel #25
0
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
        )
    )
Beispiel #26
0
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
    )
Beispiel #27
0
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
    )
Beispiel #28
0
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
Beispiel #29
0
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
Beispiel #30
0
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
Beispiel #31
0
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_)
Beispiel #32
0
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
Beispiel #33
0
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))
Beispiel #34
0
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
Beispiel #35
0
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_)
Beispiel #36
0
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
Beispiel #37
0
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_
Beispiel #38
0
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_
Beispiel #39
0
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)
Beispiel #40
0
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
Beispiel #41
0
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
Beispiel #42
0
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
Beispiel #43
0
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
Beispiel #44
0
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
Beispiel #45
0
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
Beispiel #46
0
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
Beispiel #47
0
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
Beispiel #48
0
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
Beispiel #49
0
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
Beispiel #50
0
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
Beispiel #51
0
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
Beispiel #52
0
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
Beispiel #53
0
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
Beispiel #54
0
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
Beispiel #55
0
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
Beispiel #56
0
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']
Beispiel #57
0
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
Beispiel #58
0
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']
Beispiel #59
0
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
Beispiel #60
0
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