Ejemplo n.º 1
0
def is_profile_configured(vm_):
    try:
        # Check for required profile parameters before sending any API calls.
        if vm_['profile'] and config.is_profile_configured(__opts__,
                                                           __active_provider_name__ or __virtualname__,
                                                           vm_['profile'],
                                                           vm_=vm_) is False:
            return False

        alias, driver = __active_provider_name__.split(':')

        profile_data = __opts__['providers'][alias][driver]['profiles'][vm_['profile']]

        if profile_data.get('storage_size') or profile_data.get('storage_tier'):
            required_keys = ['storage_size', 'storage_tier']

            for key in required_keys:
                if profile_data.get(key) is None:
                    log.error(
                        'both storage_size and storage_tier required for profile {profile}. '
                        'Please check your profile configuration'.format(profile=vm_['profile'])
                    )
                    return False

            locations = avail_locations()

            for location in locations.values():
                if location['code'] == profile_data['location']:
                    if 'storage' not in location['features']:
                        log.error(
                            'Choosen location {location} for profile {profile} does not support storage feature. '
                            'Please check your profile configuration'.format(
                                location=location['code'], profile=vm_['profile']
                            )
                        )
                        return False

        if profile_data.get('storage_snapshot_count') or profile_data.get('storage_snapshot_frequency'):
            required_keys = ['storage_size', 'storage_tier']

            for key in required_keys:
                if profile_data.get(key) is None:
                    log.error(
                        'both storage_snapshot_count and storage_snapshot_frequency required for profile {profile}. '
                        'Please check your profile configuration'.format(profile=vm_['profile'])
                    )
                    return False

    except AttributeError:
        pass

    return True
Ejemplo n.º 2
0
    def test_no_clonefrom_just_image(self):
        '''
        Tests that the profile is configured correctly when deploying using an image
        '''

        profile_additions = {
            'image': 'some-image.iso'
        }

        provider_config = deepcopy(PROVIDER_CONFIG)
        profile = deepcopy(PROFILE)
        profile['base-gold'].update(profile_additions)

        provider_config_additions = {
            'profiles': profile
        }
        provider_config['vcenter01']['vmware'].update(provider_config_additions)
        vm_ = {'profile': profile}
        with patch.dict(vmware.__opts__, {'providers': provider_config}, clean=True):
            self.assertEqual(config.is_profile_configured(vmware.__opts__, 'vcenter01:vmware',
                                                          'base-gold', vm_=vm_), True)
Ejemplo n.º 3
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__,
                __active_provider_name__ or 'proxmox',
                vm_['profile'],
                vm_=vm_) is False:
            return False
    except AttributeError:
        pass

    ret = {}

    __utils__['cloud.fire_event'](
        'event',
        'starting create',
        'salt/cloud/{0}/creating'.format(vm_['name']),
        args=__utils__['cloud.filter_event'](
            'creating', vm_, ['name', 'profile', 'provider', 'driver']),
        sock_dir=__opts__['sock_dir'],
        transport=__opts__['transport'])

    log.info('Creating Cloud VM %s', vm_['name'])

    if 'use_dns' in vm_ and 'ip_address' not in vm_:
        use_dns = vm_['use_dns']
        if use_dns:
            from socket import gethostbyname, gaierror
            try:
                ip_address = gethostbyname(six.text_type(vm_['name']))
            except gaierror:
                log.debug('Resolving of %s failed', vm_['name'])
            else:
                vm_['ip_address'] = six.text_type(ip_address)

    try:
        newid = _get_next_vmid()
        data = create_node(vm_, newid)
    except Exception as exc:
        log.error(
            'Error creating %s on PROXMOX\n\n'
            'The following exception was thrown when trying to '
            'run the initial deployment: \n%s',
            vm_['name'],
            exc,
            # Show the traceback if the debug logging level is enabled
            exc_info_on_loglevel=logging.DEBUG)
        return False

    ret['creation_data'] = data
    name = vm_['name']  # hostname which we know
    if 'clone' in vm_ and vm_['clone'] is True:
        vmid = newid
    else:
        vmid = data['vmid']  # vmid which we have received
    host = data['node']  # host which we have received
    nodeType = data['technology']  # VM tech (Qemu / OpenVZ)

    # Determine which IP to use in order of preference:
    if 'ip_address' in vm_:
        ip_address = six.text_type(vm_['ip_address'])
    elif 'public_ips' in data:
        ip_address = six.text_type(data['public_ips'][0])  # first IP
    elif 'private_ips' in data:
        ip_address = six.text_type(data['private_ips'][0])  # first IP
    else:
        raise SaltCloudExecutionFailure(
            "Could not determine an IP address to use")

    log.debug('Using IP address %s', ip_address)

    # wait until the vm has been created so we can start it
    if not wait_for_created(data['upid'], timeout=300):
        return {
            'Error': 'Unable to create {0}, command timed out'.format(name)
        }

    if 'clone' in vm_ and vm_['clone'] is True and vm_['technology'] == 'qemu':
        # If we cloned a machine, see if we need to reconfigure any of the options such as net0,
        # ide2, etc. This enables us to have a different cloud-init ISO mounted for each VM that's
        # brought up

        # TODO: Support other settings here too as these are not the only ones that can be modified
        # after a clone operation
        log.info('Configuring cloned VM')

        # Modify the settings for the VM one at a time so we can see any problems with the values
        # as quickly as possible
        for setting_number in range(3):
            setting = 'ide{0}'.format(setting_number)
            if setting in vm_:
                postParams = {}
                postParams[setting] = vm_[setting]
                query('post',
                      'nodes/{0}/qemu/{1}/config'.format(vm_['host'],
                                                         vmid), postParams)

        for setting_number in range(5):
            setting = 'sata{0}'.format(setting_number)
            if setting in vm_:
                postParams = {}
                postParams[setting] = vm_[setting]
                query('post',
                      'nodes/{0}/qemu/{1}/config'.format(vm_['host'],
                                                         vmid), postParams)

        for setting_number in range(13):
            setting = 'scsi{0}'.format(setting_number)
            if setting in vm_:
                postParams = {}
                postParams[setting] = vm_[setting]
                query('post',
                      'nodes/{0}/qemu/{1}/config'.format(vm_['host'],
                                                         vmid), postParams)

        # net strings are a list of comma seperated settings. We need to merge the settings so that
        # the setting in the profile only changes the settings it touches and the other settings
        # are left alone. An example of why this is necessary is because the MAC address is set
        # in here and generally you don't want to alter or have to know the MAC address of the new
        # instance, but you may want to set the VLAN bridge for example
        for setting_number in range(20):
            setting = 'net{0}'.format(setting_number)
            if setting in vm_:
                data = query(
                    'get',
                    'nodes/{0}/qemu/{1}/config'.format(vm_['host'], vmid))

                # Generate a dictionary of settings from the existing string
                new_setting = {}
                if setting in data:
                    new_setting.update(_stringlist_to_dictionary(
                        data[setting]))

                # Merge the new settings (as a dictionary) into the existing dictionary to get the
                # new merged settings
                new_setting.update(_stringlist_to_dictionary(vm_[setting]))

                # Convert the dictionary back into a string list
                postParams = {setting: _dictionary_to_stringlist(new_setting)}
                query('post',
                      'nodes/{0}/qemu/{1}/config'.format(vm_['host'],
                                                         vmid), postParams)

    # VM has been created. Starting..
    if not start(name, vmid, call='action'):
        log.error('Node %s (%s) failed to start!', name, vmid)
        raise SaltCloudExecutionFailure

    # Wait until the VM has fully started
    log.debug('Waiting for state "running" for vm %s on %s', vmid, host)
    if not wait_for_state(vmid, 'running'):
        return {'Error': 'Unable to start {0}, command timed out'.format(name)}

    ssh_username = config.get_cloud_config_value('ssh_username',
                                                 vm_,
                                                 __opts__,
                                                 default='root')
    ssh_password = config.get_cloud_config_value(
        'password',
        vm_,
        __opts__,
    )

    ret['ip_address'] = ip_address
    ret['username'] = ssh_username
    ret['password'] = ssh_password

    vm_['ssh_host'] = ip_address
    vm_['password'] = ssh_password
    ret = __utils__['cloud.bootstrap'](vm_, __opts__)

    # Report success!
    log.info('Created Cloud VM \'%s\'', vm_['name'])
    log.debug('\'%s\' VM creation details:\n%s', vm_['name'],
              pprint.pformat(data))

    __utils__['cloud.fire_event'](
        'event',
        'created instance',
        'salt/cloud/{0}/created'.format(vm_['name']),
        args=__utils__['cloud.filter_event'](
            'created', vm_, ['name', 'profile', 'provider', 'driver']),
        sock_dir=__opts__['sock_dir'],
    )

    return ret
Ejemplo n.º 4
0
def create(vm_):
    '''
    Create a single instance from a data dict.

    CLI Examples:

    .. code-block:: bash

        salt-cloud -p qingcloud-ubuntu-c1m1 hostname1
        salt-cloud -m /path/to/mymap.sls -P
    '''
    try:
        # Check for required profile parameters before sending any API calls.
        if vm_['profile'] and config.is_profile_configured(__opts__,
                                                           __active_provider_name__ or 'qingcloud',
                                                           vm_['profile'],
                                                           vm_=vm_) is False:
            return False
    except AttributeError:
        pass

    # Since using "provider: <provider-engine>" is deprecated, alias provider
    # to use driver: "driver: <provider-engine>"
    if 'provider' in vm_:
        vm_['driver'] = vm_.pop('provider')

    __utils__['cloud.fire_event'](
        'event',
        'starting create',
        'salt/cloud/{0}/creating'.format(vm_['name']),
        args={
            'name': vm_['name'],
            'profile': vm_['profile'],
            'provider': vm_['driver'],
        },
        sock_dir=__opts__['sock_dir'],
        transport=__opts__['transport']
    )

    log.info('Creating Cloud VM {0}'.format(vm_['name']))

    # params
    params = {
        'action': 'RunInstances',
        'instance_name': vm_['name'],
        'zone': _get_location(vm_),
        'instance_type': _get_size(vm_),
        'image_id': _get_image(vm_),
        'vxnets.1': vm_['vxnets'],
        'login_mode': vm_['login_mode'],
        'login_keypair': vm_['login_keypair'],
    }

    __utils__['cloud.fire_event'](
        'event',
        'requesting instance',
        'salt/cloud/{0}/requesting'.format(vm_['name']),
        args={'kwargs': params},
        sock_dir=__opts__['sock_dir'],
        transport=__opts__['transport']
    )

    result = query(params)
    new_instance_id = result['instances'][0]

    try:
        data = salt.utils.cloud.wait_for_ip(
            _query_node_data,
            update_args=(new_instance_id,),
            timeout=config.get_cloud_config_value(
                'wait_for_ip_timeout', vm_, __opts__, default=10 * 60
            ),
            interval=config.get_cloud_config_value(
                'wait_for_ip_interval', vm_, __opts__, default=10
            ),
        )
    except (SaltCloudExecutionTimeout, SaltCloudExecutionFailure) as exc:
        try:
            # It might be already up, let's destroy it!
            destroy(vm_['name'])
        except SaltCloudSystemExit:
            pass
        finally:
            raise SaltCloudSystemExit(str(exc))

    private_ip = data['private_ips'][0]

    log.debug('VM {0} is now running'.format(private_ip))

    vm_['ssh_host'] = private_ip

    # The instance is booted and accessible, let's Salt it!
    __utils__['cloud.bootstrap'](vm_, __opts__)

    log.info('Created Cloud VM \'{0[name]}\''.format(vm_))

    log.debug(
        '\'{0[name]}\' VM creation details:\n{1}'.format(
            vm_, pprint.pformat(data)
        )
    )

    __utils__['cloud.fire_event'](
        'event',
        'created instance',
        'salt/cloud/{0}/created'.format(vm_['name']),
        args={
            'name': vm_['name'],
            'profile': vm_['profile'],
            'provider': vm_['driver'],
        },
        sock_dir=__opts__['sock_dir'],
        transport=__opts__['transport']
    )

    return data
Ejemplo n.º 5
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']) is False:
            return False
    except AttributeError:
        pass

    # Since using "provider: <provider-engine>" is deprecated, alias provider
    # to use driver: "driver: <provider-engine>"
    if 'provider' in server_:
        server_['driver'] = server_.pop('provider')

    salt.utils.cloud.fire_event(
        'event',
        'starting create',
        'salt/cloud/{0}/creating'.format(server_['name']),
        {
            'name': server_['name'],
            'profile': server_['profile'],
            'provider': server_['driver'],
        },
        transport=__opts__['transport']
    )

    log.info('Creating a BareMetal server {0}'.format(server_['name']))

    access_key = config.get_cloud_config_value(
        'access_key', get_configured_provider(), __opts__, search_global=False
    )

    kwargs = {
        'name': server_['name'],
        'organization': access_key,
        'image': get_image(server_),
    }

    salt.utils.cloud.fire_event(
        'event',
        'requesting instance',
        'salt/cloud/{0}/requesting'.format(server_['name']),
        {'kwargs': kwargs},
        transport=__opts__['transport']
    )

    try:
        ret = create_node(kwargs)
    except Exception as exc:
        log.error(
            'Error creating {0} on Scaleway\n\n'
            'The following exception was thrown when trying to '
            'run the initial deployment: {1}'.format(
                server_['name'],
                str(exc)
            ),
            # Show the traceback if the debug logging level is enabled
            exc_info_on_loglevel=logging.DEBUG
        )
        return False

    def __query_node_data(server_name):
        ''' Called to check if the server has a public IP address.
        '''
        data = show_instance(server_name, 'action')
        if data and data.get('public_ip'):
            return data
        return False

    try:
        data = salt.utils.cloud.wait_for_ip(
            __query_node_data,
            update_args=(server_['name'],),
            timeout=config.get_cloud_config_value(
                'wait_for_ip_timeout', server_, __opts__, default=10 * 60),
            interval=config.get_cloud_config_value(
                'wait_for_ip_interval', server_, __opts__, default=10),
        )
    except (SaltCloudExecutionTimeout, SaltCloudExecutionFailure) as exc:
        try:
            # It might be already up, let's destroy it!
            destroy(server_['name'])
        except SaltCloudSystemExit:
            pass
        finally:
            raise SaltCloudSystemExit(str(exc))

    server_['ssh_host'] = data['public_ip']['address']
    server_['ssh_password'] = config.get_cloud_config_value(
        'ssh_password', server_, __opts__
    )
    ret = salt.utils.cloud.bootstrap(server_, __opts__)

    ret.update(data)

    log.info('Created BareMetal server \'{0[name]}\''.format(server_))
    log.debug(
        '\'{0[name]}\' BareMetal server creation details:\n{1}'.format(
            server_, pprint.pformat(data)
        )
    )

    salt.utils.cloud.fire_event(
        'event',
        'created instance',
        'salt/cloud/{0}/created'.format(server_['name']),
        {
            'name': server_['name'],
            'profile': server_['profile'],
            'provider': server_['driver'],
        },
        transport=__opts__['transport']
    )

    return ret
Ejemplo n.º 6
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 'cloudstack',
                                        vm_['profile']) is False:
            return False
    except AttributeError:
        pass

    salt.utils.cloud.fire_event(
        'event',
        'starting create',
        'salt/cloud/{0}/creating'.format(vm_['name']),
        {
            'name': vm_['name'],
            'profile': vm_['profile'],
            'provider': vm_['provider'],
        },
        transport=__opts__['transport']
    )

    log.info('Creating Cloud VM {0}'.format(vm_['name']))
    conn = get_conn()
    kwargs = {
        'name': vm_['name'],
        'image': get_image(conn, vm_),
        'size': get_size(conn, vm_),
        'location': get_location(conn, vm_),
    }

    if get_keypair(vm_) is not False:
        kwargs['ex_keyname'] = get_keypair(vm_)

    if get_networkid(vm_) is not False:
        kwargs['networkids'] = get_networkid(vm_)
        kwargs['networks'] = (   # The only attr that is used is 'id'.
                                 CloudStackNetwork(None, None, None,
                                                   kwargs['networkids'],
                                                   None, None),
                             )

    if get_project(conn, vm_) is not False:
        kwargs['project'] = get_project(conn, vm_)

    salt.utils.cloud.fire_event(
        'event',
        'requesting instance',
        'salt/cloud/{0}/requesting'.format(vm_['name']),
        {'kwargs': {'name': kwargs['name'],
                    'image': kwargs['image'].name,
                    'size': kwargs['size'].name}},
        transport=__opts__['transport']
    )

    displayname = cloudstack_displayname(vm_)
    if displayname:
        kwargs['ex_displayname'] = displayname
    else:
        kwargs['ex_displayname'] = kwargs['name']

    volumes = {}
    ex_blockdevicemappings = block_device_mappings(vm_)
    if ex_blockdevicemappings:
        for ex_blockdevicemapping in ex_blockdevicemappings:
            if 'VirtualName' not in ex_blockdevicemapping:
                ex_blockdevicemapping['VirtualName'] = '{0}-{1}'.format(vm_['name'], len(volumes))
            salt.utils.cloud.fire_event(
              'event',
              'requesting volume',
              'salt/cloud/{0}/requesting'.format(ex_blockdevicemapping['VirtualName']),
              {'kwargs': {'name': ex_blockdevicemapping['VirtualName'],
                          'device': ex_blockdevicemapping['DeviceName'],
                          'size': ex_blockdevicemapping['VolumeSize']}},
            )
            try:
                volumes[ex_blockdevicemapping['DeviceName']] = conn.create_volume(
                        ex_blockdevicemapping['VolumeSize'],
                        ex_blockdevicemapping['VirtualName']
                    )
            except Exception as exc:
                log.error(
                    'Error creating volume {0} on CLOUDSTACK\n\n'
                    'The following exception was thrown by libcloud when trying to '
                    'requesting a volume: \n{1}'.format(
                        ex_blockdevicemapping['VirtualName'], exc
                    ),
                    # Show the traceback if the debug logging level is enabled
                    exc_info_on_loglevel=logging.DEBUG
                )
                return False
    else:
        ex_blockdevicemapping = {}
    try:
        data = conn.create_node(**kwargs)
    except Exception as exc:
        log.error(
            'Error creating {0} on CLOUDSTACK\n\n'
            'The following exception was thrown by libcloud when trying to '
            'run the initial deployment: \n{1}'.format(
                vm_['name'], str(exc)
            ),
            # Show the traceback if the debug logging level is enabled
            exc_info_on_loglevel=logging.DEBUG
        )
        return False

    for device_name in six.iterkeys(volumes):
        try:
            conn.attach_volume(data, volumes[device_name], device_name)
        except Exception as exc:
            log.error(
                'Error attaching volume {0} on CLOUDSTACK\n\n'
                'The following exception was thrown by libcloud when trying to '
                'attach a volume: \n{1}'.format(
                    ex_blockdevicemapping.get('VirtualName', 'UNKNOWN'), exc
                ),
                # Show the traceback if the debug logging level is enabled
                exc_info=log.isEnabledFor(logging.DEBUG)
            )
            return False

    ssh_username = config.get_cloud_config_value(
        'ssh_username', vm_, __opts__, default='root'
    )

    vm_['ssh_host'] = get_ip(data)
    vm_['password'] = data.extra['password']
    vm_['key_filename'] = get_key()
    ret = salt.utils.cloud.bootstrap(vm_, __opts__)

    ret.update(data.__dict__)

    if 'password' in data.extra:
        del data.extra['password']

    log.info('Created Cloud VM {0[name]!r}'.format(vm_))
    log.debug(
        '{0[name]!r} VM creation details:\n{1}'.format(
            vm_, pprint.pformat(data.__dict__)
        )
    )

    salt.utils.cloud.fire_event(
        'event',
        'created instance',
        'salt/cloud/{0}/created'.format(vm_['name']),
        {
            'name': vm_['name'],
            'profile': vm_['profile'],
            'provider': vm_['provider'],
        },
        transport=__opts__['transport']
    )

    return ret
def create(vm_info):
    """
    Creates a virtual machine from the given VM information.
    This is what is used to request a virtual machine to be created by the
    cloud provider, wait for it to become available,
    and then (optionally) log in and install Salt on it.

    Fires:
        "starting create" : This event is tagged salt/cloud/<vm name>/creating.
        The payload contains the names of the VM, profile and provider.

    @param vm_info {dict}
            {
                name: <str>
                profile: <dict>
                provider: <provider>
                clone_from: <vm_name>
            }
    @return dict of resulting vm. !!!Passwords can and should be included!!!
    """
    log.debug("Creating virtualbox with %s" % vm_info)
    try:
        # Check for required profile parameters before sending any API calls.
        # TODO should this be a call to config.is_provider_configured ?
        if vm_info['profile'] and config.is_profile_configured(
                __opts__,
                __active_provider_name__ or 'virtualbox',
                vm_info['profile']
        ) is False:
            return False
    except AttributeError:
        pass

    # For now we can only clone
    if 'clone_from' not in vm_info:
        log.error('"clone_from" not in profile configuration!')
        return False

    salt.utils.cloud.fire_event(
        'event',
        'starting create',
        'salt/cloud/{0}/creating'.format(vm_info['name']),
        {
            'name': vm_info['name'],
            'profile': vm_info['profile'],
            'provider': vm_info['provider'],
        },
        transport=__opts__['transport']
    )

    # TODO Calculate kwargs with parameters required by virtualbox
    # to create the virtual machine.
    request_kwargs = {
        'name': vm_info['name'],
        'clone_from': vm_info['clone_from']
    }

    salt.utils.cloud.fire_event(
        'event',
        'requesting instance',
        'salt/cloud/{0}/requesting'.format(vm_info['name']),
        request_kwargs,
        transport=__opts__['transport']
    )
    # TODO request a new VM!
    vm_result = vb_clone_vm(**request_kwargs)

    # TODO Prepare deployment of salt on the vm
    # Any private data, including passwords and keys (including public keys)
    # should be stripped from the deploy kwargs before the event is fired.
    deploy_kwargs = {
    }

    salt.utils.cloud.fire_event(
        'event',
        'deploying salt',
        'salt/cloud/{0}/deploying'.format(vm_info['name']),
        deploy_kwargs,
        transport=__opts__['transport']
    )

    deploy_kwargs.update({
        # TODO Add private data
    })

    # TODO wait for target machine to become available
    # TODO deploy!
    # Do we have to call this?
    salt.utils.cloud.deploy_script(None, **deploy_kwargs)

    salt.utils.cloud.fire_event(
        'event',
        'created machine',
        'salt/cloud/{0}/created'.format(vm_info['name']),
        vm_result,
        transport=__opts__['transport']
    )

    # Passwords should be included in this object!!
    return vm_result
Ejemplo n.º 8
0
def create(vm_):
    '''
    Create a single Linode VM.
    '''
    name = vm_['name']
    try:
        # Check for required profile parameters before sending any API calls.
        if vm_['profile'] and config.is_profile_configured(__opts__,
                                                           __active_provider_name__ or 'linode',
                                                           vm_['profile'],
                                                           vm_=vm_) is False:
            return False
    except AttributeError:
        pass

    # Since using "provider: <provider-engine>" is deprecated, alias provider
    # to use driver: "driver: <provider-engine>"
    if 'provider' in vm_:
        vm_['driver'] = vm_.pop('provider')

    if _validate_name(name) is False:
        return False

    __utils__['cloud.fire_event'](
        'event',
        'starting create',
        'salt/cloud/{0}/creating'.format(name),
        args={
            'name': name,
            'profile': vm_['profile'],
            'provider': vm_['driver'],
        },
        sock_dir=__opts__['sock_dir'],
        transport=__opts__['transport']
    )

    log.info('Creating Cloud VM {0}'.format(name))

    data = {}
    kwargs = {'name': name}

    plan_id = None
    size = vm_.get('size')
    if size:
        kwargs['size'] = size
        plan_id = get_plan_id(kwargs={'label': size})

    datacenter_id = None
    location = vm_.get('location')
    if location:
        try:
            datacenter_id = get_datacenter_id(location)
        except KeyError:
            # Linode's default datacenter is Dallas, but we still have to set one to
            # use the create function from Linode's API. Dallas's datacenter id is 2.
            datacenter_id = 2

    clonefrom_name = vm_.get('clonefrom')
    cloning = True if clonefrom_name else False
    if cloning:
        linode_id = get_linode_id_from_name(clonefrom_name)
        clone_source = get_linode(kwargs={'linode_id': linode_id})

        kwargs = {
            'clonefrom': clonefrom_name,
            'image': 'Clone of {0}'.format(clonefrom_name),
        }

        if size is None:
            size = clone_source['TOTALRAM']
            kwargs['size'] = size
            plan_id = clone_source['PLANID']

        if location is None:
            datacenter_id = clone_source['DATACENTERID']

        # Create new Linode from cloned Linode
        try:
            result = clone(kwargs={'linode_id': linode_id,
                                   'datacenter_id': datacenter_id,
                                   'plan_id': plan_id})
        except Exception as err:
            log.error(
                'Error cloning \'{0}\' on Linode.\n\n'
                'The following exception was thrown by Linode when trying to '
                'clone the specified machine:\n'
                '{1}'.format(
                    clonefrom_name,
                    err
                ),
                exc_info_on_loglevel=logging.DEBUG
            )
            return False
    else:
        kwargs['image'] = vm_['image']

        # Create Linode
        try:
            result = _query('linode', 'create', args={
                'PLANID': plan_id,
                'DATACENTERID': datacenter_id
            })
        except Exception as err:
            log.error(
                'Error creating {0} on Linode\n\n'
                'The following exception was thrown by Linode when trying to '
                'run the initial deployment:\n'
                '{1}'.format(
                    name,
                    err
                ),
                exc_info_on_loglevel=logging.DEBUG
            )
            return False

    if 'ERRORARRAY' in result:
        for error_data in result['ERRORARRAY']:
            log.error('Error creating {0} on Linode\n\n'
                    'The Linode API returned the following: {1}\n'.format(
                        name,
                        error_data['ERRORMESSAGE']
                        )
                    )
            return False

    __utils__['cloud.fire_event'](
        'event',
        'requesting instance',
        'salt/cloud/{0}/requesting'.format(name),
        args={'kwargs': kwargs},
        sock_dir=__opts__['sock_dir'],
        transport=__opts__['transport']
    )
    node_id = _clean_data(result)['LinodeID']
    data['id'] = node_id

    if not _wait_for_status(node_id, status=(_get_status_id_by_name('brand_new'))):
        log.error(
            'Error creating {0} on LINODE\n\n'
            'while waiting for initial ready status'.format(name),
            exc_info_on_loglevel=logging.DEBUG
        )

    # Update the Linode's Label to reflect the given VM name
    update_linode(node_id, update_args={'Label': name})
    log.debug('Set name for {0} - was linode{1}.'.format(name, node_id))

    # Add private IP address if requested
    private_ip_assignment = get_private_ip(vm_)
    if private_ip_assignment:
        create_private_ip(node_id)

    # Define which ssh_interface to use
    ssh_interface = _get_ssh_interface(vm_)

    # If ssh_interface is set to use private_ips, but assign_private_ip
    # wasn't set to True, let's help out and create a private ip.
    if ssh_interface == 'private_ips' and private_ip_assignment is False:
        create_private_ip(node_id)
        private_ip_assignment = True

    if cloning:
        config_id = get_config_id(kwargs={'linode_id': node_id})['config_id']
    else:
        # Create disks and get ids
        log.debug('Creating disks for {0}'.format(name))
        root_disk_id = create_disk_from_distro(vm_, node_id)['DiskID']
        swap_disk_id = create_swap_disk(vm_, node_id)['DiskID']

        # Create a ConfigID using disk ids
        config_id = create_config(kwargs={'name': name,
                                          'linode_id': node_id,
                                          'root_disk_id': root_disk_id,
                                          'swap_disk_id': swap_disk_id})['ConfigID']

    # Boot the Linode
    boot(kwargs={'linode_id': node_id,
                 'config_id': config_id,
                 'check_running': False})

    node_data = get_linode(kwargs={'linode_id': node_id})
    ips = get_ips(node_id)
    state = int(node_data['STATUS'])

    data['image'] = kwargs['image']
    data['name'] = name
    data['size'] = size
    data['state'] = _get_status_descr_by_id(state)
    data['private_ips'] = ips['private_ips']
    data['public_ips'] = ips['public_ips']

    # Pass the correct IP address to the bootstrap ssh_host key
    if ssh_interface == 'private_ips':
        vm_['ssh_host'] = data['private_ips'][0]
    else:
        vm_['ssh_host'] = data['public_ips'][0]

    # If a password wasn't supplied in the profile or provider config, set it now.
    vm_['password'] = get_password(vm_)

    # Make public_ips and private_ips available to the bootstrap script.
    vm_['public_ips'] = ips['public_ips']
    vm_['private_ips'] = ips['private_ips']

    # Send event that the instance has booted.
    salt.utils.cloud.fire_event(
        'event',
        'waiting for ssh',
        'salt/cloud/{0}/waiting_for_ssh'.format(name),
        {'ip_address': vm_['ssh_host']},
        transport=__opts__['transport']
    )

    # Bootstrap!
    ret = __utils__['cloud.bootstrap'](vm_, __opts__)

    ret.update(data)

    log.info('Created Cloud VM \'{0}\''.format(name))
    log.debug(
        '\'{0}\' VM creation details:\n{1}'.format(
            name, pprint.pformat(data)
        )
    )

    __utils__['cloud.fire_event'](
        'event',
        'created instance',
        'salt/cloud/{0}/created'.format(name),
        args={
            'name': name,
            'profile': vm_['profile'],
            'provider': vm_['driver'],
        },
        sock_dir=__opts__['sock_dir'],
        transport=__opts__['transport']
    )

    return ret
Ejemplo n.º 9
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 'profitbricks'),
                vm_['profile']) is False):
            return False
    except AttributeError:
        pass

    if 'image_alias' in vm_ and not version_compatible('4.0'):
        raise SaltCloudNotFound(
            "The 'image_alias' parameter requires the profitbricks "
            "SDK v4.0.0 or greater.")

    if 'image' not in vm_ and 'image_alias' not in vm_:
        log.error('The image or image_alias parameter is required.')

    signal_event(vm_, 'creating', 'starting create')

    data = None
    datacenter_id = get_datacenter_id()
    conn = get_conn()

    # Assemble list of network interfaces from the cloud profile config.
    nics = _get_nics(vm_)

    # Assemble list of volumes from the cloud profile config.
    volumes = [_get_system_volume(vm_)]
    if 'volumes' in vm_:
        volumes.extend(_get_data_volumes(vm_))

    # Assembla the composite server object.
    server = _get_server(vm_, volumes, nics)

    signal_event(vm_, 'requesting', 'requesting instance')

    try:
        data = conn.create_server(datacenter_id=datacenter_id, server=server)
        log.info('Create server request ID: {0}'.format(data['requestId']),
                 exc_info_on_loglevel=logging.DEBUG)

        _wait_for_completion(conn, data, get_wait_timeout(vm_),
                             'create_server')
    except PBError as exc:
        log.error(
            'Error creating {0} on ProfitBricks\n\n'
            'The following exception was thrown by the profitbricks library '
            'when trying to run the initial deployment: \n{1}:\n{2}'.format(
                vm_['name'], exc, exc.content),
            exc_info_on_loglevel=logging.DEBUG)
        return False
    except Exception as exc:  # pylint: disable=W0703
        log.error('Error creating {0} \n\n'
                  'Error: \n{1}'.format(vm_['name'], exc),
                  exc_info_on_loglevel=logging.DEBUG)
        return False

    vm_['server_id'] = data['id']

    def __query_node_data(vm_, data):
        '''
        Query node data until node becomes available.
        '''
        running = False
        try:
            data = show_instance(vm_['name'], 'action')
            if not data:
                return False
            log.debug(
                'Loaded node data for {0}:\nname: {1}\nstate: {2}'.format(
                    vm_['name'], pprint.pformat(data['name']), data['state']))
        except Exception as err:
            log.error(
                'Failed to get nodes list: {0}'.format(err),
                # Show the trackback if the debug logging level is enabled
                exc_info_on_loglevel=logging.DEBUG)
            # Trigger a failure in the wait for IP function
            return False

        running = data['state'] == 'RUNNING'
        if not running:
            # Still not running, trigger another iteration
            return

        if ssh_interface(vm_) == 'private_lan' and data['private_ips']:
            vm_['ssh_host'] = data['private_ips'][0]

        if ssh_interface(vm_) != 'private_lan' and data['public_ips']:
            vm_['ssh_host'] = data['public_ips'][0]

        return data

    try:
        data = salt.utils.cloud.wait_for_ip(
            __query_node_data,
            update_args=(vm_, data),
            timeout=config.get_cloud_config_value('wait_for_ip_timeout',
                                                  vm_,
                                                  __opts__,
                                                  default=10 * 60),
            interval=config.get_cloud_config_value('wait_for_ip_interval',
                                                   vm_,
                                                   __opts__,
                                                   default=10),
        )
    except (SaltCloudExecutionTimeout, SaltCloudExecutionFailure) as exc:
        try:
            # It might be already up, let's destroy it!
            destroy(vm_['name'])
        except SaltCloudSystemExit:
            pass
        finally:
            raise SaltCloudSystemExit(str(exc.message))

    log.debug('VM is now running')
    log.info('Created Cloud VM {0}'.format(vm_))
    log.debug('{0} VM creation details:\n{1}'.format(vm_,
                                                     pprint.pformat(data)))

    signal_event(vm_, 'created', 'created instance')

    if 'ssh_host' in vm_:
        vm_['key_filename'] = get_key_filename(vm_)
        ret = __utils__['cloud.bootstrap'](vm_, __opts__)
        ret.update(data)
        return ret
    else:
        raise SaltCloudSystemExit('A valid IP address was not found.')
Ejemplo n.º 10
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 'aliyun', vm_['profile']) is False:
        return False

    # Since using "provider: <provider-engine>" is deprecated, alias provider
    # to use driver: "driver: <provider-engine>"
    if 'provider' in vm_:
        vm_['driver'] = vm_.pop('provider')

    salt.utils.cloud.fire_event('event',
                                'starting create',
                                'salt/cloud/{0}/creating'.format(vm_['name']),
                                {
                                    'name': vm_['name'],
                                    'profile': vm_['profile'],
                                    'provider': vm_['driver'],
                                },
                                transport=__opts__['transport'])

    log.info('Creating Cloud VM {0}'.format(vm_['name']))
    kwargs = {
        'name': vm_['name'],
        'size_id': get_size(vm_),
        'image_id': get_image(vm_),
        'region_id': __get_location(vm_),
        'securitygroup_id': get_securitygroup(vm_),
    }

    salt.utils.cloud.fire_event('event',
                                'requesting instance',
                                'salt/cloud/{0}/requesting'.format(
                                    vm_['name']), {'kwargs': kwargs},
                                transport=__opts__['transport'])

    try:
        ret = create_node(kwargs)
    except Exception as exc:
        log.error(
            'Error creating {0} on Aliyun ECS\n\n'
            'The following exception was thrown when trying to '
            'run the initial deployment: {1}'.format(vm_['name'], str(exc)),
            # Show the traceback if the debug logging level is enabled
            exc_info_on_loglevel=logging.DEBUG)
        return False

    def __query_node_data(vm_name):
        data = show_instance(vm_name, call='action')
        if not data:
            # Trigger an error in the wait_for_ip function
            return False
        if data.get('PublicIpAddress', None) is not None:
            return data

    try:
        data = salt.utils.cloud.wait_for_ip(
            __query_node_data,
            update_args=(vm_['name'], ),
            timeout=config.get_cloud_config_value('wait_for_ip_timeout',
                                                  vm_,
                                                  __opts__,
                                                  default=10 * 60),
            interval=config.get_cloud_config_value('wait_for_ip_interval',
                                                   vm_,
                                                   __opts__,
                                                   default=10),
        )
    except (SaltCloudExecutionTimeout, SaltCloudExecutionFailure) as exc:
        try:
            # It might be already up, let's destroy it!
            destroy(vm_['name'])
        except SaltCloudSystemExit:
            pass
        finally:
            raise SaltCloudSystemExit(str(exc))

    public_ip = data['PublicIpAddress'][0]
    log.debug('VM {0} is now running'.format(public_ip))
    vm_['ssh_host'] = public_ip

    # The instance is booted and accessible, let's Salt it!
    ret = salt.utils.cloud.bootstrap(vm_, __opts__)
    ret.update(data.__dict__)

    log.info('Created Cloud VM {0[name]!r}'.format(vm_))
    log.debug('{0[name]!r} VM creation details:\n{1}'.format(
        vm_, pprint.pformat(data)))

    salt.utils.cloud.fire_event('event',
                                'created instance',
                                'salt/cloud/{0}/created'.format(vm_['name']), {
                                    'name': vm_['name'],
                                    'profile': vm_['profile'],
                                    'provider': vm_['driver'],
                                },
                                transport=__opts__['transport'])

    return ret
Ejemplo n.º 11
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']) is False:
            return False
    except AttributeError:
        pass

    # Since using "provider: <provider-engine>" is deprecated, alias provider
    # to use driver: "driver: <provider-engine>"
    if 'provider' in server_:
        server_['driver'] = server_.pop('provider')

    salt.utils.cloud.fire_event('event',
                                'starting create',
                                'salt/cloud/{0}/creating'.format(
                                    server_['name']), {
                                        'name': server_['name'],
                                        'profile': server_['profile'],
                                        'provider': server_['driver'],
                                    },
                                transport=__opts__['transport'])

    log.info('Creating a BareMetal server {0}'.format(server_['name']))

    access_key = config.get_cloud_config_value('access_key',
                                               get_configured_provider(),
                                               __opts__,
                                               search_global=False)

    kwargs = {
        'name': server_['name'],
        'organization': access_key,
        'image': get_image(server_),
    }

    salt.utils.cloud.fire_event('event',
                                'requesting instance',
                                'salt/cloud/{0}/requesting'.format(
                                    server_['name']), {'kwargs': kwargs},
                                transport=__opts__['transport'])

    try:
        ret = create_node(kwargs)
    except Exception as exc:
        log.error(
            'Error creating {0} on Scaleway\n\n'
            'The following exception was thrown when trying to '
            'run the initial deployment: {1}'.format(server_['name'],
                                                     str(exc)),
            # Show the traceback if the debug logging level is enabled
            exc_info_on_loglevel=logging.DEBUG)
        return False

    def __query_node_data(server_name):
        ''' Called to check if the server has a public IP address.
        '''
        data = show_instance(server_name, 'action')
        if data and data.get('public_ip'):
            return data
        return False

    try:
        data = salt.utils.cloud.wait_for_ip(
            __query_node_data,
            update_args=(server_['name'], ),
            timeout=config.get_cloud_config_value('wait_for_ip_timeout',
                                                  server_,
                                                  __opts__,
                                                  default=10 * 60),
            interval=config.get_cloud_config_value('wait_for_ip_interval',
                                                   server_,
                                                   __opts__,
                                                   default=10),
        )
    except (SaltCloudExecutionTimeout, SaltCloudExecutionFailure) as exc:
        try:
            # It might be already up, let's destroy it!
            destroy(server_['name'])
        except SaltCloudSystemExit:
            pass
        finally:
            raise SaltCloudSystemExit(str(exc))

    server_['ssh_host'] = data['public_ip']['address']
    server_['ssh_password'] = config.get_cloud_config_value(
        'ssh_password', server_, __opts__)
    ret = salt.utils.cloud.bootstrap(server_, __opts__)

    ret.update(data)

    log.info('Created BareMetal server {0[name]!r}'.format(server_))
    log.debug('{0[name]!r} BareMetal server creation details:\n{1}'.format(
        server_, pprint.pformat(data)))

    salt.utils.cloud.fire_event('event',
                                'created instance',
                                'salt/cloud/{0}/created'.format(
                                    server_['name']), {
                                        'name': server_['name'],
                                        'profile': server_['profile'],
                                        'provider': server_['driver'],
                                    },
                                transport=__opts__['transport'])

    return ret
Ejemplo n.º 12
0
def create(vm_):
    '''
    Provision a single machine
    '''
    clone_strategy = vm_.get('clone_strategy') or 'full'

    if clone_strategy not in set(['quick', 'full']):
        raise SaltCloudSystemExit("'clone_strategy' must be one of quick or full. Got '{0}'".format(clone_strategy))

    ip_source = vm_.get('ip_source') or 'ip-learning'

    if ip_source not in set(['ip-learning', 'qemu-agent']):
        raise SaltCloudSystemExit("'ip_source' must be one of qemu-agent or ip-learning. Got '{0}'".format(ip_source))

    log.info("Cloning machine '{0}' with strategy '{1}'".format(vm_['name'], clone_strategy))

    try:
        # Check for required profile parameters before sending any API calls.
        if vm_['profile'] and config.is_profile_configured(__opts__,
                                                           __active_provider_name__ or 'libvirt',
                                                           vm_['profile']) is False:
            return False
    except AttributeError:
        pass

    # TODO: check name qemu/libvirt will choke on some characters (like '/')?
    name = vm_['name']

    __utils__['cloud.fire_event'](
        'event',
        'starting create',
        'salt/cloud/{0}/creating'.format(name),
        {
            'name': name,
            'profile': vm_['profile'],
            'provider': vm_['driver'],
        },
        sock_dir=__opts__['sock_dir'],
        transport=__opts__['transport']
    )

    key_filename = config.get_cloud_config_value(
        'private_key', vm_, __opts__, search_global=False, default=None
    )
    if key_filename is not None and not os.path.isfile(key_filename):
        raise SaltCloudConfigError(
            'The defined key_filename \'{0}\' does not exist'.format(
                key_filename
            )
        )
    vm_['key_filename'] = key_filename
    # wait_for_instance requires private_key
    vm_['private_key'] = key_filename

    cleanup = []
    try:
        # clone the vm
        base = vm_['base_domain']
        conn = __get_conn(vm_['url'])

        try:
            # for idempotency the salt-bootstrap needs -F argument
            #  script_args: -F
            clone_domain = conn.lookupByName(name)
        except libvirtError as e:
            domain = conn.lookupByName(base)
            # TODO: ensure base is shut down before cloning
            xml = domain.XMLDesc(0)

            kwargs = {
                'name': name,
                'base_domain': base,
            }

            __utils__['cloud.fire_event'](
                'event',
                'requesting instance',
                'salt/cloud/{0}/requesting'.format(name),
                {'kwargs': kwargs},
                sock_dir=__opts__['sock_dir'],
                transport=__opts__['transport']
            )

            log.debug("Source machine XML '{0}'".format(xml))

            domain_xml = ElementTree.fromstring(xml)
            domain_xml.find('./name').text = name
            domain_xml.find('./description').text = "Cloned from {0}".format(base)
            domain_xml.remove(domain_xml.find('./uuid'))

            for iface_xml in domain_xml.findall('./devices/interface'):
                iface_xml.remove(iface_xml.find('./mac'))
                # enable IP learning, this might be a default behaviour...
                if iface_xml.find("./filterref/parameter[@name='CTRL_IP_LEARNING']") is None:
                    iface_xml.append(ElementTree.fromstring(IP_LEARNING_XML))

            # If a qemu agent is defined we need to fix the path to its socket
            # <channel type='unix'>
            #   <source mode='bind' path='/var/lib/libvirt/qemu/channel/target/domain-<dom-name>/org.qemu.guest_agent.0'/>
            #   <target type='virtio' name='org.qemu.guest_agent.0'/>
            #   <address type='virtio-serial' controller='0' bus='0' port='2'/>
            # </channel>
            for agent_xml in domain_xml.findall("""./devices/channel[@type='unix']"""):
                #  is org.qemu.guest_agent.0 an option?
                if agent_xml.find("""./target[@type='virtio'][@name='org.qemu.guest_agent.0']""") is not None:
                    source_element = agent_xml.find("""./source[@mode='bind']""")
                    # see if there is a path element that needs rewriting
                    if 'path' in source_element.attrib:
                        path = source_element.attrib['path']
                        new_path = path.replace('/domain-{0}/'.format(base), '/domain-{0}/'.format(name))
                        log.debug("Rewriting agent socket path to {0}".format(new_path))
                        source_element.attrib['path'] = new_path

            for disk in domain_xml.findall("""./devices/disk[@device='disk'][@type='file']"""):
                # print "Disk: ", ElementTree.tostring(disk)
                # check if we can clone
                driver = disk.find("./driver[@name='qemu']")
                if driver is None:
                    # Err on the safe side
                    raise SaltCloudExecutionFailure("Non qemu driver disk encountered bailing out.")
                disk_type = driver.attrib.get('type')
                log.info("disk attributes {0}".format(disk.attrib))
                if disk_type == 'qcow2':
                    source = disk.find("./source").attrib['file']
                    pool, volume = find_pool_and_volume(conn, source)
                    if clone_strategy == 'quick':
                        new_volume = pool.createXML(create_volume_with_backing_store_xml(volume), 0)
                    else:
                        new_volume = pool.createXMLFrom(create_volume_xml(volume), volume, 0)
                    cleanup.append({'what': 'volume', 'item': new_volume})

                    disk.find("./source").attrib['file'] = new_volume.path()
                elif disk_type == 'raw':
                    source = disk.find("./source").attrib['file']
                    pool, volume = find_pool_and_volume(conn, source)
                    # TODO: more control on the cloned disk type
                    new_volume = pool.createXMLFrom(create_volume_xml(volume), volume, 0)
                    cleanup.append({'what': 'volume', 'item': new_volume})

                    disk.find("./source").attrib['file'] = new_volume.path()
                else:
                    raise SaltCloudExecutionFailure("Disk type '{0}' not supported".format(disk_type))

            log.debug("Clone XML '{0}'".format(domain_xml))
            clone_xml = ElementTree.tostring(domain_xml)

            clone_domain = conn.defineXMLFlags(clone_xml, libvirt.VIR_DOMAIN_DEFINE_VALIDATE)
            cleanup.append({'what': 'domain', 'item': clone_domain})
            clone_domain.createWithFlags(libvirt.VIR_DOMAIN_START_FORCE_BOOT)

        log.debug("VM '{0}'".format(vm_))

        if ip_source == 'qemu-agent':
            ip_source = libvirt.VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_AGENT
        elif ip_source == 'ip-learning':
            ip_source = libvirt.VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_LEASE

        address = salt.utils.cloud.wait_for_ip(
            get_domain_ip,
            update_args=(clone_domain, 0, ip_source),
            timeout=config.get_cloud_config_value('wait_for_ip_timeout', vm_, __opts__, default=10 * 60),
            interval=config.get_cloud_config_value('wait_for_ip_interval', vm_, __opts__, default=10),
            interval_multiplier=config.get_cloud_config_value('wait_for_ip_interval_multiplier', vm_, __opts__, default=1),
        )

        log.info('Address = {0}'.format(address))

        vm_['ssh_host'] = address

        # the bootstrap script needs to be installed first in /etc/salt/cloud.deploy.d/
        # salt-cloud -u is your friend
        ret = __utils__['cloud.bootstrap'](vm_, __opts__)

        __utils__['cloud.fire_event'](
            'event',
            'created instance',
            'salt/cloud/{0}/created'.format(name),
            {
                'name': name,
                'profile': vm_['profile'],
                'provider': vm_['driver'],
            },
            sock_dir=__opts__['sock_dir'],
            transport=__opts__['transport']
        )

        return ret
    except Exception as e:  # pylint: disable=broad-except
        # Try to clean up in as much cases as possible
        log.info('Cleaning up after exception clean up items: {0}'.format(cleanup))
        for leftover in cleanup:
            what = leftover['what']
            item = leftover['item']
            if what == 'domain':
                destroy_domain(conn, item)
            if what == 'volume':
                item.delete()
        raise e
Ejemplo n.º 13
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 {0}'.format(name))
    conn = get_conn()
    kwargs = {
        'hostname': hostname,
        'domain': domain,
        'startCpus': vm_['cpu_number'],
        'maxMemory': vm_['ram'],
        'hourlyBillingFlag': vm_['hourly_billing'],
    }

    local_disk_flag = config.get_cloud_config_value('local_disk',
                                                    vm_,
                                                    __opts__,
                                                    default=False)
    kwargs['localDiskFlag'] = local_disk_flag

    if 'image' in vm_:
        kwargs['operatingSystemReferenceCode'] = vm_['image']
        kwargs['blockDevices'] = []
        disks = vm_['disk_size']

        if isinstance(disks, int):
            disks = [str(disks)]
        elif isinstance(disks, six.string_types):
            disks = [size.strip() for size in disks.split(',')]

        count = 0
        for disk in disks:
            # device number '1' is reserved for the SWAP disk
            if count == 1:
                count += 1
            block_device = {
                'device': str(count),
                'diskImage': {
                    'capacity': str(disk)
                }
            }
            kwargs['blockDevices'].append(block_device)
            count += 1

            # Upper bound must be 5 as we're skipping '1' for the SWAP disk ID
            if count > 5:
                log.warning('More that 5 disks were specified for {0} .'
                            'The first 5 disks will be applied to the VM, '
                            'but the remaining disks will be ignored.\n'
                            'Please adjust your cloud configuration to only '
                            'specify a maximum of 5 disks.'.format(name))
                break

    elif 'global_identifier' in vm_:
        kwargs['blockDeviceTemplateGroup'] = {
            'globalIdentifier': vm_['global_identifier']
        }

    location = get_location(vm_)
    if location:
        kwargs['datacenter'] = {'name': location}

    private_vlan = config.get_cloud_config_value('private_vlan',
                                                 vm_,
                                                 __opts__,
                                                 default=False)
    if private_vlan:
        kwargs['primaryBackendNetworkComponent'] = {
            'networkVlan': {
                'id': private_vlan,
            }
        }

    private_network = config.get_cloud_config_value('private_network',
                                                    vm_,
                                                    __opts__,
                                                    default=False)
    if bool(private_network) is True:
        kwargs['privateNetworkOnlyFlag'] = 'True'

    public_vlan = config.get_cloud_config_value('public_vlan',
                                                vm_,
                                                __opts__,
                                                default=False)
    if public_vlan:
        kwargs['primaryNetworkComponent'] = {
            'networkVlan': {
                'id': public_vlan,
            }
        }

    max_net_speed = config.get_cloud_config_value('max_net_speed',
                                                  vm_,
                                                  __opts__,
                                                  default=10)
    if max_net_speed:
        kwargs['networkComponents'] = [{'maxSpeed': int(max_net_speed)}]

    post_uri = config.get_cloud_config_value('post_uri',
                                             vm_,
                                             __opts__,
                                             default=None)
    if post_uri:
        kwargs['postInstallScriptUri'] = post_uri

    dedicated_host_id = config.get_cloud_config_value('dedicated_host_id',
                                                      vm_,
                                                      __opts__,
                                                      default=None)
    if dedicated_host_id:
        kwargs['dedicatedHost'] = {'id': dedicated_host_id}

    __utils__['cloud.fire_event']('event',
                                  'requesting instance',
                                  'salt/cloud/{0}/requesting'.format(name),
                                  args={
                                      'kwargs':
                                      __utils__['cloud.filter_event'](
                                          'requesting', kwargs, list(kwargs)),
                                  },
                                  sock_dir=__opts__['sock_dir'],
                                  transport=__opts__['transport'])

    try:
        response = conn.createObject(kwargs)
    except Exception as exc:
        log.error(
            'Error creating {0} on SoftLayer\n\n'
            'The following exception was thrown when trying to '
            'run the initial deployment: \n{1}'.format(name, str(exc)),
            # Show the traceback if the debug logging level is enabled
            exc_info_on_loglevel=logging.DEBUG)
        return False

    ip_type = 'primaryIpAddress'
    private_ssh = config.get_cloud_config_value('private_ssh',
                                                vm_,
                                                __opts__,
                                                default=False)
    private_wds = config.get_cloud_config_value('private_windows',
                                                vm_,
                                                __opts__,
                                                default=False)
    if private_ssh or private_wds or public_vlan is None:
        ip_type = 'primaryBackendIpAddress'

    def wait_for_ip():
        '''
        Wait for the IP address to become available
        '''
        nodes = list_nodes_full()
        if ip_type in nodes[hostname]:
            return nodes[hostname][ip_type]
        time.sleep(1)
        return False

    ip_address = salt.utils.cloud.wait_for_fun(
        wait_for_ip,
        timeout=config.get_cloud_config_value('wait_for_fun_timeout',
                                              vm_,
                                              __opts__,
                                              default=15 * 60),
    )
    if config.get_cloud_config_value('deploy', vm_, __opts__) is not True:
        return show_instance(hostname, call='action')

    SSH_PORT = 22
    WINDOWS_DS_PORT = 445
    managing_port = SSH_PORT
    if config.get_cloud_config_value('windows', vm_, __opts__) or \
            config.get_cloud_config_value('win_installer', vm_, __opts__):
        managing_port = WINDOWS_DS_PORT

    ssh_connect_timeout = config.get_cloud_config_value(
        'ssh_connect_timeout', vm_, __opts__, 15 * 60)
    connect_timeout = config.get_cloud_config_value('connect_timeout', vm_,
                                                    __opts__,
                                                    ssh_connect_timeout)
    if not salt.utils.cloud.wait_for_port(
            ip_address, port=managing_port, timeout=connect_timeout):
        raise SaltCloudSystemExit('Failed to authenticate against remote ssh')

    pass_conn = get_conn(service='SoftLayer_Account')
    mask = {
        'virtualGuests': {
            'powerState': '',
            'operatingSystem': {
                'passwords': ''
            },
        },
    }

    def get_credentials():
        '''
        Wait for the password to become available
        '''
        node_info = pass_conn.getVirtualGuests(id=response['id'], mask=mask)
        for node in node_info:
            if node['id'] == response['id'] and \
                            'passwords' in node['operatingSystem'] and \
                            len(node['operatingSystem']['passwords']) > 0:
                return node['operatingSystem']['passwords'][0][
                    'username'], node['operatingSystem']['passwords'][0][
                        'password']
        time.sleep(5)
        return False

    username, passwd = salt.utils.cloud.wait_for_fun(  # pylint: disable=W0633
        get_credentials,
        timeout=config.get_cloud_config_value('wait_for_fun_timeout',
                                              vm_,
                                              __opts__,
                                              default=15 * 60),
    )
    response['username'] = username
    response['password'] = passwd
    response['public_ip'] = ip_address

    ssh_username = config.get_cloud_config_value('ssh_username',
                                                 vm_,
                                                 __opts__,
                                                 default=username)

    vm_['ssh_host'] = ip_address
    vm_['password'] = passwd
    ret = __utils__['cloud.bootstrap'](vm_, __opts__)

    ret.update(response)

    __utils__['cloud.fire_event'](
        'event',
        'created instance',
        'salt/cloud/{0}/created'.format(name),
        args=__utils__['cloud.filter_event'](
            'created', vm_, ['name', 'profile', 'provider', 'driver']),
        sock_dir=__opts__['sock_dir'],
        transport=__opts__['transport'])

    return ret
Ejemplo n.º 14
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_.get("profile") and config.is_profile_configured(
                __opts__,
                _get_active_provider_name() or __virtualname__,
                vm_["profile"],
                vm_=vm_,
        ) is False):
            return False
    except AttributeError:
        pass

    client = _connect_client()

    name = vm_.get("name")
    if not name:
        raise SaltCloudException("Missing server name")

    # Get the required configuration
    server_type = client.server_types.get_by_name(vm_.get("size"))
    if server_type is None:
        raise SaltCloudException("The server size is not supported")

    image = client.images.get_by_name(vm_.get("image"))
    if image is None:
        raise SaltCloudException("The server image is not supported")

    __utils__["cloud.fire_event"](
        "event",
        "starting create",
        "salt/cloud/{}/creating".format(vm_["name"]),
        args=__utils__["cloud.filter_event"](
            "creating",
            vm_,
            ["name", "profile", "provider", "driver"],
        ),
        sock_dir=__opts__["sock_dir"],
        transport=__opts__["transport"],
    )

    # Get the ssh_keys
    ssh_keys = vm_.get("ssh_keys", None)
    if ssh_keys:
        names, ssh_keys = ssh_keys[:], []
        for n in names:
            ssh_key = client.ssh_keys.get_by_name(n)
            if ssh_key is None:
                log.error("Invalid ssh key %s.", n)
            else:
                ssh_keys.append(ssh_key)

    # Get the location
    location = vm_.get("location", None)
    if location:
        location = client.locations.get_by_name(location)

        if location is None:
            raise SaltCloudException("The server location is not supported")

    # Get the datacenter
    datacenter = vm_.get("datacenter", None)
    if datacenter:
        datacenter = client.datacenters.get_by_name(datacenter)

        if datacenter is None:
            raise SaltCloudException("The server datacenter is not supported")

    # Get the volumes
    volumes = vm_.get("volumes", None)
    if volumes:
        volumes = [vol for vol in client.volumes.get_all() if vol in volumes]

    # Get the networks
    networks = vm_.get("networks", None)
    if networks:
        networks = [
            vol for vol in client.networks.get_all() if vol in networks
        ]

    # Create the machine
    response = client.servers.create(
        name=name,
        server_type=server_type,
        image=image,
        ssh_keys=ssh_keys,
        volumes=volumes,
        networks=networks,
        location=location,
        user_data=vm_.get("user_data", None),
        labels=vm_.get("labels", None),
        datacenter=datacenter,
        automount=vm_.get("automount", None),
    )

    # Bootstrap if ssh keys are configured
    server = response.server
    vm_.update({
        "ssh_host":
        server.public_net.ipv4.ip or server.public_net.ipv6.ip,
        "ssh_password":
        response.root_password,
        "key_filename":
        config.get_cloud_config_value("private_key",
                                      vm_,
                                      __opts__,
                                      search_global=False,
                                      default=None),
    })

    ret = __utils__["cloud.bootstrap"](vm_, __opts__)

    log.info("Created Cloud VM '%s'", vm_["name"])
    ret["created"] = True

    __utils__["cloud.fire_event"](
        "event",
        "created instance",
        "salt/cloud/{}/created".format(vm_["name"]),
        args=__utils__["cloud.filter_event"](
            "created",
            vm_,
            ["name", "profile", "provider", "driver"],
        ),
        sock_dir=__opts__["sock_dir"],
        transport=__opts__["transport"],
    )

    return ret
Ejemplo n.º 15
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 'cloudstack',
                                    vm_['profile']) is False:
        return False

    salt.utils.cloud.fire_event(
        'event',
        'starting create',
        'salt/cloud/{0}/creating'.format(vm_['name']),
        {
            'name': vm_['name'],
            'profile': vm_['profile'],
            'provider': vm_['provider'],
        },
        transport=__opts__['transport']
    )

    log.info('Creating Cloud VM {0}'.format(vm_['name']))
    conn = get_conn()
    kwargs = {
        'name': vm_['name'],
        'image': get_image(conn, vm_),
        'size': get_size(conn, vm_),
        'location': get_location(conn, vm_),
    }

    if get_keypair(vm_) is not False:
        kwargs['ex_keyname'] = get_keypair(vm_)

    if get_networkid(vm_) is not False:
        kwargs['networkids'] = get_networkid(vm_)
        kwargs['networks'] = (   # The only attr that is used is 'id'.
                                 CloudStackNetwork(None, None, None,
                                                   kwargs['networkids'],
                                                   None, None),
                             )

    if get_project(conn, vm_) is not False:
        kwargs['project'] = get_project(conn, vm_)

    salt.utils.cloud.fire_event(
        'event',
        'requesting instance',
        'salt/cloud/{0}/requesting'.format(vm_['name']),
        {'kwargs': {'name': kwargs['name'],
                    'image': kwargs['image'].name,
                    'size': kwargs['size'].name}},
        transport=__opts__['transport']
    )

    displayname = cloudstack_displayname(vm_)
    if displayname:
        kwargs['ex_displayname'] = displayname
    else:
        kwargs['ex_displayname'] = kwargs['name']

    volumes = {}
    ex_blockdevicemappings = block_device_mappings(vm_)
    if ex_blockdevicemappings:
        for ex_blockdevicemapping in ex_blockdevicemappings:
            if 'VirtualName' not in ex_blockdevicemapping:
                ex_blockdevicemapping['VirtualName'] = '{0}-{1}'.format(vm_['name'], len(volumes))
            salt.utils.cloud.fire_event(
              'event',
              'requesting volume',
              'salt/cloud/{0}/requesting'.format(ex_blockdevicemapping['VirtualName']),
              {'kwargs': {'name': ex_blockdevicemapping['VirtualName'],
                          'device': ex_blockdevicemapping['DeviceName'],
                          'size': ex_blockdevicemapping['VolumeSize']}},
            )
            try:
                volumes[ex_blockdevicemapping['DeviceName']] = conn.create_volume(
                        ex_blockdevicemapping['VolumeSize'],
                        ex_blockdevicemapping['VirtualName']
                    )
            except Exception as exc:
                log.error(
                    'Error creating volume {0} on CLOUDSTACK\n\n'
                    'The following exception was thrown by libcloud when trying to '
                    'requesting a volume: \n{1}'.format(
                        ex_blockdevicemapping['VirtualName'], exc
                    ),
                    # Show the traceback if the debug logging level is enabled
                    exc_info_on_loglevel=logging.DEBUG
                )
                return False
    else:
        ex_blockdevicemapping = {}
    try:
        data = conn.create_node(**kwargs)
    except Exception as exc:
        log.error(
            'Error creating {0} on CLOUDSTACK\n\n'
            'The following exception was thrown by libcloud when trying to '
            'run the initial deployment: \n{1}'.format(
                vm_['name'], str(exc)
            ),
            # Show the traceback if the debug logging level is enabled
            exc_info_on_loglevel=logging.DEBUG
        )
        return False

    for device_name in six.iterkeys(volumes):
        try:
            conn.attach_volume(data, volumes[device_name], device_name)
        except Exception as exc:
            log.error(
                'Error attaching volume {0} on CLOUDSTACK\n\n'
                'The following exception was thrown by libcloud when trying to '
                'attach a volume: \n{1}'.format(
                    ex_blockdevicemapping.get('VirtualName', 'UNKNOWN'), exc
                ),
                # Show the traceback if the debug logging level is enabled
                exc_info=log.isEnabledFor(logging.DEBUG)
            )
            return False

    ssh_username = config.get_cloud_config_value(
        'ssh_username', vm_, __opts__, default='root'
    )

    ret = {}
    if config.get_cloud_config_value('deploy', vm_, __opts__) is True:
        deploy_script = script(vm_)
        deploy_kwargs = {
            'opts': __opts__,
            'host': get_ip(data),
            'username': ssh_username,
            'password': data.extra['password'],
            'key_filename': get_key(),
            'script': deploy_script.script,
            'name': vm_['name'],
            'tmp_dir': config.get_cloud_config_value(
                'tmp_dir', vm_, __opts__, default='/tmp/.saltcloud'
            ),
            'deploy_command': config.get_cloud_config_value(
                'deploy_command', vm_, __opts__,
                default='/tmp/.saltcloud/deploy.sh',
            ),
            'start_action': __opts__['start_action'],
            'parallel': __opts__['parallel'],
            'sock_dir': __opts__['sock_dir'],
            'conf_file': __opts__['conf_file'],
            'minion_pem': vm_['priv_key'],
            'minion_pub': vm_['pub_key'],
            'keep_tmp': __opts__['keep_tmp'],
            'preseed_minion_keys': vm_.get('preseed_minion_keys', None),
            'sudo': config.get_cloud_config_value(
                'sudo', vm_, __opts__, default=(ssh_username != 'root')
            ),
            'sudo_password': config.get_cloud_config_value(
                'sudo_password', vm_, __opts__, default=None
            ),
            'tty': config.get_cloud_config_value(
                'tty', vm_, __opts__, default=False
            ),
            'display_ssh_output': config.get_cloud_config_value(
                'display_ssh_output', vm_, __opts__, default=True
            ),
            'script_args': config.get_cloud_config_value(
                'script_args', vm_, __opts__
            ),
            'script_env': config.get_cloud_config_value('script_env', vm_, __opts__),
            'minion_conf': salt.utils.cloud.minion_config(__opts__, vm_)
        }

        # Deploy salt-master files, if necessary
        if config.get_cloud_config_value('make_master', vm_, __opts__) is True:
            deploy_kwargs['make_master'] = True
            deploy_kwargs['master_pub'] = vm_['master_pub']
            deploy_kwargs['master_pem'] = vm_['master_pem']
            master_conf = salt.utils.cloud.master_config(__opts__, vm_)
            deploy_kwargs['master_conf'] = master_conf

            if master_conf.get('syndic_master', None):
                deploy_kwargs['make_syndic'] = True

        deploy_kwargs['make_minion'] = config.get_cloud_config_value(
            'make_minion', vm_, __opts__, default=True
        )

        # Check for Windows install params
        win_installer = config.get_cloud_config_value('win_installer', vm_, __opts__)
        if win_installer:
            deploy_kwargs['win_installer'] = win_installer
            minion = salt.utils.cloud.minion_config(__opts__, vm_)
            deploy_kwargs['master'] = minion['master']
            deploy_kwargs['username'] = config.get_cloud_config_value(
                'win_username', vm_, __opts__, default='Administrator'
            )
            deploy_kwargs['password'] = config.get_cloud_config_value(
                'win_password', vm_, __opts__, default=''
            )

        # Store what was used to the deploy the VM
        event_kwargs = copy.deepcopy(deploy_kwargs)
        del event_kwargs['minion_pem']
        del event_kwargs['minion_pub']
        del event_kwargs['sudo_password']
        if 'password' in event_kwargs:
            del event_kwargs['password']
        ret['deploy_kwargs'] = event_kwargs

        salt.utils.cloud.fire_event(
            'event',
            'executing deploy script',
            'salt/cloud/{0}/deploying'.format(vm_['name']),
            {'kwargs': event_kwargs},
            transport=__opts__['transport']
        )

        deployed = False
        if win_installer:
            deployed = salt.utils.cloud.deploy_windows(**deploy_kwargs)
        else:
            deployed = salt.utils.cloud.deploy_script(**deploy_kwargs)

        if deployed:
            log.info('Salt installed on {0}'.format(vm_['name']))
        else:
            log.error(
                'Failed to start Salt on Cloud VM {0}'.format(
                    vm_['name']
                )
            )

    ret.update(data.__dict__)

    if 'password' in data.extra:
        del data.extra['password']

    log.info('Created Cloud VM {0[name]!r}'.format(vm_))
    log.debug(
        '{0[name]!r} VM creation details:\n{1}'.format(
            vm_, pprint.pformat(data.__dict__)
        )
    )

    salt.utils.cloud.fire_event(
        'event',
        'created instance',
        'salt/cloud/{0}/created'.format(vm_['name']),
        {
            'name': vm_['name'],
            'profile': vm_['profile'],
            'provider': vm_['provider'],
        },
        transport=__opts__['transport']
    )

    return ret
Ejemplo n.º 16
0
def create(vm_):
    '''
    Create a single VM from a data dict

    CLI Example:

    .. code-block:: bash

        salt-cloud -p profile_name vm_name
    '''
    try:
        # Check for required profile parameters before sending any API calls.
        if vm_['profile'] and config.is_profile_configured(__opts__,
                                                           __active_provider_name__ or 'joyent',
                                                           vm_['profile'],
                                                           vm_=vm_) is False:
            return False
    except AttributeError:
        pass

    # Since using "provider: <provider-engine>" is deprecated, alias provider
    # to use driver: "driver: <provider-engine>"
    if 'provider' in vm_:
        vm_['driver'] = vm_.pop('provider')

    key_filename = config.get_cloud_config_value(
        'private_key', vm_, __opts__, search_global=False, default=None
    )

    __utils__['cloud.fire_event'](
        'event',
        'starting create',
        'salt/cloud/{0}/creating'.format(vm_['name']),
        args={
            'name': vm_['name'],
            'profile': vm_['profile'],
            'provider': vm_['driver'],
        },
        sock_dir=__opts__['sock_dir'],
        transport=__opts__['transport']
    )

    log.info(
        'Creating Cloud VM {0} in {1}'.format(
            vm_['name'],
            vm_.get('location', DEFAULT_LOCATION)
        )
    )

    # added . for fqdn hostnames
    salt.utils.cloud.check_name(vm_['name'], 'a-zA-Z0-9-.')
    kwargs = {
        'name': vm_['name'],
        'image': get_image(vm_),
        'size': get_size(vm_),
        'location': vm_.get('location', DEFAULT_LOCATION)
    }
    # Let's not assign a default here; only assign a network value if
    # one is explicitly configured
    if 'networks' in vm_:
        kwargs['networks'] = vm_.get('networks')

    __utils__['cloud.fire_event'](
        'event',
        'requesting instance',
        'salt/cloud/{0}/requesting'.format(vm_['name']),
        args={'kwargs': kwargs},
        sock_dir=__opts__['sock_dir'],
        transport=__opts__['transport']
    )

    data = create_node(**kwargs)
    if data == {}:
        log.error('Error creating {0} on JOYENT'.format(vm_['name']))
        return False

    query_instance(vm_)
    data = show_instance(vm_['name'], call='action')

    vm_['key_filename'] = key_filename
    vm_['ssh_host'] = data[1]['primaryIp']

    __utils__['cloud.bootstrap'](vm_, __opts__)

    __utils__['cloud.fire_event'](
        'event',
        'created instance',
        'salt/cloud/{0}/created'.format(vm_['name']),
        args={
            'name': vm_['name'],
            'profile': vm_['profile'],
            'provider': vm_['driver'],
        },
        sock_dir=__opts__['sock_dir'],
        transport=__opts__['transport']
    )

    return data[1]
Ejemplo n.º 17
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 'profitbricks',
                                                           vm_['profile']) is False:
            return False
    except AttributeError:
        pass

    datacenter_id = get_datacenter_id()
    conn = get_conn()
    data = None

    # Apply component overrides to the size from the cloud profile config.
    vm_size = override_size(vm_)

    # Retrieve list of SSH public keys
    ssh_keys = get_public_keys(vm_)

    # Fetch image and construct volume
    image = get_image(conn, vm_)
    volume = Volume(
        name='{0} Storage'.format(vm_['name']),
        size=vm_size['disk'],
        image=image['id'],
        ssh_keys=ssh_keys
    )

    # Construct server
    server = Server(
        name=vm_['name'],
        ram=vm_size['ram'],
        cores=vm_size['cores'],
        create_volumes=[volume]
    )

    salt.utils.cloud.fire_event(
        'event',
        'requesting instance',
        'salt/cloud/{0}/requesting'.format(vm_['name']),
        {'name': vm_['name']},
        transport=__opts__['transport']
    )

    try:
        data = conn.create_server(datacenter_id=datacenter_id, server=server)
        _wait_for_completion(conn, data, 120, "create_server")
    except Exception as exc:  # pylint: disable=W0703
        log.error(
            'Error creating {0} on ProfitBricks\n\n'
            'The following exception was thrown by the profitbricks library '
            'when trying to run the initial deployment: \n{1}'.format(
                vm_['name'], exc
            ),
            exc_info_on_loglevel=logging.DEBUG
        )
        return False

    create_network_interfaces(conn, datacenter_id, data['id'], vm_)
    set_public_lan(conn, vm_)

    def __query_node_data(vm_, data):
        '''
        Query node data until node becomes available.
        '''
        running = False
        try:
            data = show_instance(vm_['name'], 'action')
            if not data:
                return False
            log.debug(
                'Loaded node data for {0}:\nname: {1}\nstate: {2}'.format(
                    vm_['name'],
                    pprint.pformat(data['name']),
                    data['vmState']
                )
            )
        except Exception as err:
            log.error(
                'Failed to get nodes list: {0}'.format(
                    err
                ),
                # Show the trackback if the debug logging level is enabled
                exc_info_on_loglevel=logging.DEBUG
            )
            # Trigger a failure in the wait for IP function
            return False

        running = data['vmState'] == 'RUNNING'
        if not running:
            # Still not running, trigger another iteration
            return

        if ssh_interface(vm_) == 'private_lan' and data['private_ips']:
            vm_['ssh_host'] = data['private_ips'][0]

        if ssh_interface(vm_) != 'private_lan' and data['public_ips']:
            vm_['ssh_host'] = data['public_ips'][0]

        return data

    try:
        data = salt.utils.cloud.wait_for_ip(
            __query_node_data,
            update_args=(vm_, data),
            timeout=config.get_cloud_config_value(
                'wait_for_ip_timeout', vm_, __opts__, default=10 * 60),
            interval=config.get_cloud_config_value(
                'wait_for_ip_interval', vm_, __opts__, default=10),
        )
    except (SaltCloudExecutionTimeout, SaltCloudExecutionFailure) as exc:
        try:
            # It might be already up, let's destroy it!
            destroy(vm_['name'])
        except SaltCloudSystemExit:
            pass
        finally:
            raise SaltCloudSystemExit(str(exc.message))

    log.debug('VM is now running')
    log.info('Created Cloud VM {0[name]!r}'.format(vm_))
    log.debug(
        '{0[name]!r} VM creation details:\n{1}'.format(
            vm_, pprint.pformat(data)
        )
    )

    salt.utils.cloud.fire_event(
        'event',
        'created instance',
        'salt/cloud/{0}/created'.format(vm_['name']),
        {
            'name': vm_['name'],
            'profile': vm_['profile'],
            'provider': vm_['driver'],
        },
        transport=__opts__['transport']
    )

    if 'ssh_host' in vm_:
        vm_['key_filename'] = get_key_filename(vm_)
        ret = salt.utils.cloud.bootstrap(vm_, __opts__)
        ret.update(data)
        return ret
    else:
        raise SaltCloudSystemExit('A valid IP address was not found.')
Ejemplo n.º 18
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 "cloudstack",
                vm_["profile"],
                vm_=vm_,
        ) is False):
            return False
    except AttributeError:
        pass

    __utils__["cloud.fire_event"](
        "event",
        "starting create",
        "salt/cloud/{}/creating".format(vm_["name"]),
        sock_dir=__opts__["sock_dir"],
        args=__utils__["cloud.filter_event"](
            "creating", vm_, ["name", "profile", "provider", "driver"]),
        transport=__opts__["transport"],
    )

    log.info("Creating Cloud VM %s", vm_["name"])
    conn = get_conn()
    # pylint: disable=not-callable
    kwargs = {
        "name": vm_["name"],
        "image": get_image(conn, vm_),
        "size": get_size(conn, vm_),
        "location": get_location(conn, vm_),
    }
    # pylint: enable=not-callable

    sg = get_security_groups(conn, vm_)
    if sg is not False:
        kwargs["ex_security_groups"] = sg

    if get_keypair(vm_) is not False:
        kwargs["ex_keyname"] = get_keypair(vm_)

    if get_networkid(vm_) is not False:
        kwargs["networkids"] = get_networkid(vm_)
        kwargs["networks"] = (  # The only attr that is used is 'id'.
            CloudStackNetwork(None, None, None, kwargs["networkids"], None,
                              None), )

    if get_project(conn, vm_) is not False:
        kwargs["project"] = get_project(conn, vm_)

    event_data = kwargs.copy()
    event_data["image"] = kwargs["image"].name
    event_data["size"] = kwargs["size"].name

    __utils__["cloud.fire_event"](
        "event",
        "requesting instance",
        "salt/cloud/{}/requesting".format(vm_["name"]),
        sock_dir=__opts__["sock_dir"],
        args={
            "kwargs":
            __utils__["cloud.filter_event"](
                "requesting",
                event_data,
                ["name", "profile", "provider", "driver", "image", "size"],
            ),
        },
        transport=__opts__["transport"],
    )

    displayname = cloudstack_displayname(vm_)
    if displayname:
        kwargs["ex_displayname"] = displayname
    else:
        kwargs["ex_displayname"] = kwargs["name"]

    volumes = {}
    ex_blockdevicemappings = block_device_mappings(vm_)
    if ex_blockdevicemappings:
        for ex_blockdevicemapping in ex_blockdevicemappings:
            if "VirtualName" not in ex_blockdevicemapping:
                ex_blockdevicemapping["VirtualName"] = "{}-{}".format(
                    vm_["name"], len(volumes))
            __utils__["cloud.fire_event"](
                "event",
                "requesting volume",
                "salt/cloud/{}/requesting".format(
                    ex_blockdevicemapping["VirtualName"]),
                sock_dir=__opts__["sock_dir"],
                args={
                    "kwargs": {
                        "name": ex_blockdevicemapping["VirtualName"],
                        "device": ex_blockdevicemapping["DeviceName"],
                        "size": ex_blockdevicemapping["VolumeSize"],
                    }
                },
            )
            try:
                volumes[
                    ex_blockdevicemapping["DeviceName"]] = conn.create_volume(
                        ex_blockdevicemapping["VolumeSize"],
                        ex_blockdevicemapping["VirtualName"],
                    )
            except Exception as exc:  # pylint: disable=broad-except
                log.error(
                    "Error creating volume %s on CLOUDSTACK\n\n"
                    "The following exception was thrown by libcloud when trying to "
                    "requesting a volume: \n%s",
                    ex_blockdevicemapping["VirtualName"],
                    exc,
                    # Show the traceback if the debug logging level is enabled
                    exc_info_on_loglevel=logging.DEBUG,
                )
                return False
    else:
        ex_blockdevicemapping = {}
    try:
        data = conn.create_node(**kwargs)
    except Exception as exc:  # pylint: disable=broad-except
        log.error(
            "Error creating %s on CLOUDSTACK\n\n"
            "The following exception was thrown by libcloud when trying to "
            "run the initial deployment: \n%s",
            vm_["name"],
            exc,
            # Show the traceback if the debug logging level is enabled
            exc_info_on_loglevel=logging.DEBUG,
        )
        return False

    for device_name in volumes:
        try:
            conn.attach_volume(data, volumes[device_name], device_name)
        except Exception as exc:  # pylint: disable=broad-except
            log.error(
                "Error attaching volume %s on CLOUDSTACK\n\n"
                "The following exception was thrown by libcloud when trying to "
                "attach a volume: \n%s",
                ex_blockdevicemapping.get("VirtualName", "UNKNOWN"),
                exc,
                # Show the traceback if the debug logging level is enabled
                exc_info=log.isEnabledFor(logging.DEBUG),
            )
            return False

    ssh_username = config.get_cloud_config_value("ssh_username",
                                                 vm_,
                                                 __opts__,
                                                 default="root")

    vm_["ssh_host"] = get_ip(data)
    vm_["password"] = data.extra["password"]
    vm_["key_filename"] = get_key()
    ret = __utils__["cloud.bootstrap"](vm_, __opts__)

    ret.update(data.__dict__)

    if "password" in data.extra:
        del data.extra["password"]

    log.info("Created Cloud VM '%s'", vm_["name"])
    log.debug("'%s' VM creation details:\n%s", vm_["name"],
              pprint.pformat(data.__dict__))

    __utils__["cloud.fire_event"](
        "event",
        "created instance",
        "salt/cloud/{}/created".format(vm_["name"]),
        sock_dir=__opts__["sock_dir"],
        args=__utils__["cloud.filter_event"](
            "created", vm_, ["name", "profile", "provider", "driver"]),
        transport=__opts__["transport"],
    )

    return ret
Ejemplo n.º 19
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 'aws',
                                        vm_['profile']) is False:
            return False
    except AttributeError:
        pass

    key_filename = config.get_cloud_config_value(
        'private_key', vm_, __opts__, search_global=False, default=None
    )
    if key_filename is not None and not os.path.isfile(key_filename):
        raise SaltCloudConfigError(
            'The defined key_filename {0!r} does not exist'.format(
                key_filename
            )
        )

    location = get_location(vm_)
    log.info('Creating Cloud VM {0} in {1}'.format(vm_['name'], location))
    conn = get_conn(location=location)
    usernames = ssh_username(vm_)
    kwargs = {
        'ssh_key': config.get_cloud_config_value(
            'private_key', vm_, __opts__, search_global=False
        ),
        'name': vm_['name'],
        'image': get_image(conn, vm_),
        'size': get_size(conn, vm_),
        'location': get_availability_zone(conn, vm_)
    }
    ex_keyname = keyname(vm_)
    if ex_keyname:
        kwargs['ex_keyname'] = ex_keyname
    ex_securitygroup = securitygroup(vm_)
    if ex_securitygroup:
        kwargs['ex_securitygroup'] = ex_securitygroup
    ex_blockdevicemappings = block_device_mappings(vm_)
    if ex_blockdevicemappings:
        kwargs['ex_blockdevicemappings'] = ex_blockdevicemappings

    ex_iam_profile = iam_profile(vm_)
    if ex_iam_profile:
        # libcloud does not implement 'iam_profile' yet.
        # A pull request has been suggested
        # https://github.com/apache/libcloud/pull/150
        raise SaltCloudConfigError(
            'libcloud does not implement \'iam_profile\' yet. '
            'Use EC2 driver instead.'
        )

    tags = config.get_cloud_config_value('tag', vm_, __opts__, {}, search_global=False)
    if not isinstance(tags, dict):
        raise SaltCloudConfigError(
                '\'tag\' should be a dict.'
        )
    kwargs['ex_metadata'] = config.get_cloud_config_value('metadata', vm_, __opts__, default={}, search_global=False)
    if not isinstance(kwargs['ex_metadata'], dict):
        raise SaltCloudConfigError(
                '\'metadata\' should be a dict.'
        )

    try:
        data = conn.create_node(**kwargs)
    except Exception as exc:
        log.error(
            'Error creating {0} on AWS\n\n'
            'The following exception was thrown by libcloud when trying to '
            'run the initial deployment: {1}\n'.format(
                vm_['name'], exc
            ),
            # Show the traceback if the debug logging level is enabled
            exc_info_on_loglevel=logging.DEBUG
        )
        return False

    log.info('Created node {0}'.format(vm_['name']))

    def __get_node_data(conn, vm_name):
        data = get_node(conn, vm_name)

        if data is None:
            # Trigger a failure in the waiting function
            return False

        if ssh_interface(vm_) == 'private_ips' and data.private_ips:
            return data

        if ssh_interface(vm_) == 'public_ips' and data.public_ips:
            return data

    try:
        data = salt.utils.cloud.wait_for_ip(
            __get_node_data,
            update_args=(conn, vm_['name']),
            timeout=config.get_cloud_config_value(
                'wait_for_ip_timeout', vm_, __opts__, default=5 * 60),
            interval=config.get_cloud_config_value(
                'wait_for_ip_interval', vm_, __opts__, default=0.5),
        )
    except (SaltCloudExecutionTimeout, SaltCloudExecutionFailure) as exc:
        try:
            # It might be already up, let's destroy it!
            destroy(vm_['name'])
        except SaltCloudSystemExit:
            pass
        finally:
            raise SaltCloudSystemExit(str(exc))

    if tags:
        set_tags(vm_['name'], tags, call='action')

    if ssh_interface(vm_) == 'private_ips':
        log.info('Salt node data. Private_ip: {0}'.format(data.private_ips[0]))
        ip_address = data.private_ips[0]
    else:
        log.info('Salt node data. Public_ip: {0}'.format(data.public_ips[0]))
        ip_address = data.public_ips[0]

    if salt.utils.cloud.get_salt_interface(vm_, __opts__) == 'private_ips':
        salt_ip_address = data.private_ips[0]
        log.info('Salt interface set to: {0}'.format(salt_ip_address))
    else:
        salt_ip_address = data.public_ips[0]
        log.debug('Salt interface set to: {0}'.format(salt_ip_address))

    username = '******'
    ssh_connect_timeout = config.get_cloud_config_value(
        'ssh_connect_timeout', vm_, __opts__, 900   # 15 minutes
    )
    ssh_port = config.get_cloud_config_value(
        'ssh_port', vm_, __opts__, 22
    )
    if salt.utils.cloud.wait_for_port(ip_address, timeout=ssh_connect_timeout):
        for user in usernames:
            if salt.utils.cloud.wait_for_passwd(
                    host=ip_address,
                    username=user,
                    ssh_timeout=config.get_cloud_config_value(
                        'wait_for_passwd_timeout', vm_, __opts__,
                        default=1 * 60
                    ),
                    key_filename=key_filename,
                    known_hosts_file=config.get_cloud_config_value(
                        'known_hosts_file', vm_, __opts__,
                        default='/dev/null'
                    ),
                ):
                username = user
                break
        else:
            raise SaltCloudSystemExit(
                'Failed to authenticate against remote ssh'
            )

    ret = {}
    if config.get_cloud_config_value('deploy', vm_, __opts__) is True:
        deploy_script = script(vm_)
        deploy_kwargs = {
            'opts': __opts__,
            'host': ip_address,
            'port': ssh_port,
            'salt_host': salt_ip_address,
            'username': username,
            'key_filename': key_filename,
            'tmp_dir': config.get_cloud_config_value(
                'tmp_dir', vm_, __opts__, default='/tmp/.saltcloud'
            ),
            'deploy_command': config.get_cloud_config_value(
                'deploy_command', vm_, __opts__,
                default='/tmp/.saltcloud/deploy.sh',
            ),
            'tty': config.get_cloud_config_value(
                'tty', vm_, __opts__, default=True
            ),
            'script': deploy_script.script,
            'name': vm_['name'],
            'sudo': config.get_cloud_config_value(
                'sudo', vm_, __opts__, default=(username != 'root')
            ),
            'sudo_password': config.get_cloud_config_value(
                'sudo_password', vm_, __opts__, default=None
            ),
            'start_action': __opts__['start_action'],
            'parallel': __opts__['parallel'],
            'conf_file': __opts__['conf_file'],
            'sock_dir': __opts__['sock_dir'],
            'minion_pem': vm_['priv_key'],
            'minion_pub': vm_['pub_key'],
            'keep_tmp': __opts__['keep_tmp'],
            'preseed_minion_keys': vm_.get('preseed_minion_keys', None),
            'display_ssh_output': config.get_cloud_config_value(
                'display_ssh_output', vm_, __opts__, default=True
            ),
            'script_args': config.get_cloud_config_value(
                'script_args', vm_, __opts__
            ),
            'script_env': config.get_cloud_config_value('script_env', vm_, __opts__),
            'minion_conf': salt.utils.cloud.minion_config(__opts__, vm_)
        }

        # Deploy salt-master files, if necessary
        if config.get_cloud_config_value('make_master', vm_, __opts__) is True:
            deploy_kwargs['make_master'] = True
            deploy_kwargs['master_pub'] = vm_['master_pub']
            deploy_kwargs['master_pem'] = vm_['master_pem']
            master_conf = salt.utils.cloud.master_config(__opts__, vm_)
            deploy_kwargs['master_conf'] = master_conf

            if master_conf.get('syndic_master', None):
                deploy_kwargs['make_syndic'] = True

        deploy_kwargs['make_minion'] = config.get_cloud_config_value(
            'make_minion', vm_, __opts__, default=True
        )

        # Check for Windows install params
        win_installer = config.get_cloud_config_value('win_installer', vm_, __opts__)
        if win_installer:
            deploy_kwargs['win_installer'] = win_installer
            minion = salt.utils.cloud.minion_config(__opts__, vm_)
            deploy_kwargs['master'] = minion['master']
            deploy_kwargs['username'] = config.get_cloud_config_value(
                'win_username', vm_, __opts__, default='Administrator'
            )
            deploy_kwargs['password'] = config.get_cloud_config_value(
                'win_password', vm_, __opts__, default=''
            )

        # Store what was used to the deploy the VM
        ret['deploy_kwargs'] = deploy_kwargs

        deployed = False
        if win_installer:
            deployed = salt.utils.cloud.deploy_windows(**deploy_kwargs)
        else:
            deployed = salt.utils.cloud.deploy_script(**deploy_kwargs)

        if deployed:
            log.info('Salt installed on {name}'.format(**vm_))
        else:
            log.error('Failed to start Salt on Cloud VM {name}'.format(**vm_))

    ret.update(data.__dict__)

    log.info('Created Cloud VM {0[name]!r}'.format(vm_))
    log.debug(
        '{0[name]!r} VM creation details:\n{1}'.format(
            vm_, pprint.pformat(data.__dict__)
        )
    )

    volumes = config.get_cloud_config_value(
        'volumes', vm_, __opts__, search_global=True
    )
    if volumes:
        log.info('Create and attach volumes to node {0}'.format(data.name))
        create_attach_volumes(volumes, location, data)

    return ret
Ejemplo n.º 20
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__,
                                                           __active_provider_name__ or 'proxmox',
                                                           vm_['profile'],
                                                           vm_=vm_) is False:
            return False
    except AttributeError:
        pass

    # Since using "provider: <provider-engine>" is deprecated, alias provider
    # to use driver: "driver: <provider-engine>"
    if 'provider' in vm_:
        vm_['driver'] = vm_.pop('provider')

    ret = {}

    salt.utils.cloud.fire_event(
        'event',
        'starting create',
        'salt/cloud/{0}/creating'.format(vm_['name']),
        {
            'name': vm_['name'],
            'profile': vm_['profile'],
            'provider': vm_['driver'],
        },
        transport=__opts__['transport']
    )

    log.info('Creating Cloud VM {0}'.format(vm_['name']))

    if 'use_dns' in vm_ and 'ip_address' not in vm_:
        use_dns = vm_['use_dns']
        if use_dns:
            from socket import gethostbyname, gaierror
            try:
                ip_address = gethostbyname(str(vm_['name']))
            except gaierror:
                log.debug('Resolving of {hostname} failed'.format(hostname=str(vm_['name'])))
            else:
                vm_['ip_address'] = str(ip_address)

    try:
        newid = _get_next_vmid()
        data = create_node(vm_, newid)
    except Exception as exc:
        log.error(
            'Error creating {0} on PROXMOX\n\n'
            'The following exception was thrown when trying to '
            'run the initial deployment: \n{1}'.format(
                vm_['name'], str(exc)
            ),
            # Show the traceback if the debug logging level is enabled
            exc_info_on_loglevel=logging.DEBUG
        )
        return False

    ret['creation_data'] = data
    name = vm_['name']        # hostname which we know
    if 'clone' in vm_ and vm_['clone'] is True:
        vmid = newid
    else:
        vmid = data['vmid']       # vmid which we have received
    host = data['node']       # host which we have received
    nodeType = data['technology']  # VM tech (Qemu / OpenVZ)

    # Determine which IP to use in order of preference:
    if 'ip_address' in vm_:
        ip_address = str(vm_['ip_address'])
    elif 'public_ips' in data:
        ip_address = str(data['public_ips'][0])  # first IP
    elif 'private_ips' in data:
        ip_address = str(data['private_ips'][0])  # first IP
    else:
        raise SaltCloudExecutionFailure  # err.. not a good idea i reckon

    log.debug('Using IP address {0}'.format(ip_address))

    # wait until the vm has been created so we can start it
    if not wait_for_created(data['upid'], timeout=300):
        return {'Error': 'Unable to create {0}, command timed out'.format(name)}

    # VM has been created. Starting..
    if not start(name, vmid, call='action'):
        log.error('Node {0} ({1}) failed to start!'.format(name, vmid))
        raise SaltCloudExecutionFailure

    # Wait until the VM has fully started
    log.debug('Waiting for state "running" for vm {0} on {1}'.format(vmid, host))
    if not wait_for_state(vmid, 'running'):
        return {'Error': 'Unable to start {0}, command timed out'.format(name)}

    ssh_username = config.get_cloud_config_value(
        'ssh_username', vm_, __opts__, default='root'
    )
    ssh_password = config.get_cloud_config_value(
        'password', vm_, __opts__,
    )

    ret['ip_address'] = ip_address
    ret['username'] = ssh_username
    ret['password'] = ssh_password

    vm_['ssh_host'] = ip_address
    vm_['password'] = ssh_password
    ret = salt.utils.cloud.bootstrap(vm_, __opts__)

    # Report success!
    log.info('Created Cloud VM \'{0[name]}\''.format(vm_))
    log.debug(
        '\'{0[name]}\' VM creation details:\n{1}'.format(
            vm_, pprint.pformat(data)
        )
    )

    salt.utils.cloud.fire_event(
        'event',
        'created instance',
        'salt/cloud/{0}/created'.format(vm_['name']),
        {
            'name': vm_['name'],
            'profile': vm_['profile'],
            'provider': vm_['driver'],
        },
    )

    return ret
Ejemplo n.º 21
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 'openstack',
                                        vm_['profile']) is False:
            return False
    except AttributeError:
        pass

    # Since using "provider: <provider-engine>" is deprecated, alias provider
    # to use driver: "driver: <provider-engine>"
    if 'provider' in vm_:
        vm_['driver'] = vm_.pop('provider')

    deploy = config.get_cloud_config_value('deploy', vm_, __opts__)
    key_filename = config.get_cloud_config_value(
        'ssh_key_file', vm_, __opts__, search_global=False, default=None
    )
    if key_filename is not None:
        key_filename = os.path.expanduser(key_filename)
        if not os.path.isfile(key_filename):
            raise SaltCloudConfigError(
                'The defined ssh_key_file {0!r} does not exist'.format(
                    key_filename
                )
            )

    vm_['key_filename'] = key_filename

    salt.utils.cloud.fire_event(
        'event',
        'starting create',
        'salt/cloud/{0}/creating'.format(vm_['name']),
        {
            'name': vm_['name'],
            'profile': vm_['profile'],
            'provider': vm_['driver'],
        },
        transport=__opts__['transport']
    )

    conn = get_conn()

    if 'instance_id' in vm_:
        # This was probably created via another process, and doesn't have
        # things like salt keys created yet, so let's create them now.
        if 'pub_key' not in vm_ and 'priv_key' not in vm_:
            log.debug('Generating minion keys for {0[name]!r}'.format(vm_))
            vm_['priv_key'], vm_['pub_key'] = salt.utils.cloud.gen_keys(
                salt.config.get_cloud_config_value(
                    'keysize',
                    vm_,
                    __opts__
                )
            )
        data = conn.ex_get_node_details(vm_['instance_id'])
        if vm_['key_filename'] is None and 'change_password' in __opts__ and __opts__['change_password'] is True:
            vm_['password'] = sup.secure_password()
            conn.ex_set_password(data, vm_['password'])
        networks(vm_)
    else:
        # Put together all of the information required to request the instance,
        # and then fire off the request for it
        data, vm_ = request_instance(vm_)

        # Pull the instance ID, valid for both spot and normal instances
        vm_['instance_id'] = data.id

    def __query_node_data(vm_, data, floating):
        try:
            node = show_instance(vm_['name'], 'action')
            log.debug(
                'Loaded node data for {0}:\n{1}'.format(
                    vm_['name'],
                    pprint.pformat(node)
                )
            )
        except Exception as err:
            log.error(
                'Failed to get nodes list: {0}'.format(
                    err
                ),
                # Show the traceback if the debug logging level is enabled
                exc_info_on_loglevel=logging.DEBUG
            )
            # Trigger a failure in the wait for IP function
            return False

        running = node['state'] == NodeState.RUNNING
        if not running:
            # Still not running, trigger another iteration
            return

        if rackconnect(vm_) is True:
            check_libcloud_version((0, 14, 0), why='rackconnect: True')
            extra = node.get('extra')
            rc_status = extra.get('metadata', {}).get(
                'rackconnect_automation_status', '')
            access_ip = extra.get('access_ip', '')

            if rc_status != 'DEPLOYED':
                log.debug('Waiting for Rackconnect automation to complete')
                return

        if managedcloud(vm_) is True:
            extra = node.get('extra')
            mc_status = extra.get('metadata', {}).get(
                'rax_service_level_automation', '')

            if mc_status != 'Complete':
                log.debug('Waiting for managed cloud automation to complete')
                return

        public = node['public_ips']
        if floating:
            try:
                name = data.name
                ip = floating[0].ip_address
                conn.ex_attach_floating_ip_to_node(data, ip)
                log.info(
                    'Attaching floating IP {0!r} to node {1!r}'.format(
                        ip, name
                    )
                )
                data.public_ips.append(ip)
                public = data.public_ips
            except Exception:
                # Note(pabelanger): Because we loop, we only want to attach the
                # floating IP address one. So, expect failures if the IP is
                # already attached.
                pass

        result = []
        private = node['private_ips']
        if private and not public:
            log.warn(
                'Private IPs returned, but not public... Checking for '
                'misidentified IPs'
            )
            for private_ip in private:
                private_ip = preferred_ip(vm_, [private_ip])
                if salt.utils.cloud.is_public_ip(private_ip):
                    log.warn('{0} is a public IP'.format(private_ip))
                    data.public_ips.append(private_ip)
                    log.warn(
                        'Public IP address was not ready when we last checked.'
                        ' Appending public IP address now.'
                    )
                    public = data.public_ips
                else:
                    log.warn('{0} is a private IP'.format(private_ip))
                    ignore_ip = ignore_cidr(vm_, private_ip)
                    if private_ip not in data.private_ips and not ignore_ip:
                        result.append(private_ip)

        if rackconnect(vm_) is True:
            if ssh_interface(vm_) != 'private_ips':
                data.public_ips = access_ip
                return data

        # populate return data with private_ips
        # when ssh_interface is set to private_ips and public_ips exist
        if not result and ssh_interface(vm_) == 'private_ips':
            for private_ip in private:
                ignore_ip = ignore_cidr(vm_, private_ip)
                if private_ip not in data.private_ips and not ignore_ip:
                    result.append(private_ip)

        if result:
            log.debug('result = {0}'.format(result))
            data.private_ips = result
            if ssh_interface(vm_) == 'private_ips':
                return data

        if public:
            data.public_ips = public
            if ssh_interface(vm_) != 'private_ips':
                return data

    try:
        data = salt.utils.cloud.wait_for_ip(
            __query_node_data,
            update_args=(vm_, data, vm_['floating']),
            timeout=config.get_cloud_config_value(
                'wait_for_ip_timeout', vm_, __opts__, default=10 * 60),
            interval=config.get_cloud_config_value(
                'wait_for_ip_interval', vm_, __opts__, default=10),
        )
    except (SaltCloudExecutionTimeout, SaltCloudExecutionFailure) as exc:
        try:
            # It might be already up, let's destroy it!
            destroy(vm_['name'])
        except SaltCloudSystemExit:
            pass
        finally:
            raise SaltCloudSystemExit(str(exc))

    log.debug('VM is now running')

    if ssh_interface(vm_) == 'private_ips':
        ip_address = preferred_ip(vm_, data.private_ips)
    elif rackconnect(vm_) is True and ssh_interface(vm_) != 'private_ips':
        ip_address = data.public_ips
    else:
        ip_address = preferred_ip(vm_, data.public_ips)
    log.debug('Using IP address {0}'.format(ip_address))

    if salt.utils.cloud.get_salt_interface(vm_, __opts__) == 'private_ips':
        salt_ip_address = preferred_ip(vm_, data.private_ips)
        log.info('Salt interface set to: {0}'.format(salt_ip_address))
    else:
        salt_ip_address = preferred_ip(vm_, data.public_ips)
        log.debug('Salt interface set to: {0}'.format(salt_ip_address))

    if not ip_address:
        raise SaltCloudSystemExit('A valid IP address was not found')

    vm_['salt_host'] = salt_ip_address
    vm_['ssh_host'] = ip_address
    ret = salt.utils.cloud.bootstrap(vm_, __opts__)
    ret.update(data.__dict__)

    if hasattr(data, 'extra') and 'password' in data.extra:
        del data.extra['password']

    log.info('Created Cloud VM {0[name]!r}'.format(vm_))
    log.debug(
        '{0[name]!r} VM creation details:\n{1}'.format(
            vm_, pprint.pformat(data.__dict__)
        )
    )

    salt.utils.cloud.fire_event(
        'event',
        'created instance',
        'salt/cloud/{0}/created'.format(vm_['name']),
        {
            'name': vm_['name'],
            'profile': vm_['profile'],
            'provider': vm_['driver'],
        },
        transport=__opts__['transport']
    )

    return ret
Ejemplo n.º 22
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 "dimensiondata", vm_["profile"])
                is False):
            return False
    except AttributeError:
        pass

    __utils__["cloud.fire_event"](
        "event",
        "starting create",
        "salt/cloud/{}/creating".format(vm_["name"]),
        args=__utils__["cloud.filter_event"](
            "creating", vm_, ["name", "profile", "provider", "driver"]),
        sock_dir=__opts__["sock_dir"],
        transport=__opts__["transport"],
    )

    log.info("Creating Cloud VM %s", vm_["name"])
    conn = get_conn()

    location = conn.ex_get_location_by_id(vm_["location"])
    images = conn.list_images(location=location)
    image = [x for x in images if x.id == vm_["image"]][0]
    network_domains = conn.ex_list_network_domains(location=location)
    try:
        network_domain = [
            y for y in network_domains if y.name == vm_["network_domain"]
        ][0]
    except IndexError:
        network_domain = conn.ex_create_network_domain(
            location=location,
            name=vm_["network_domain"],
            plan="ADVANCED",
            description="",
        )

    try:
        vlan = [
            y for y in conn.ex_list_vlans(location=location,
                                          network_domain=network_domain)
            if y.name == vm_["vlan"]
        ][0]
    except (IndexError, KeyError):
        # Use the first VLAN in the network domain
        vlan = conn.ex_list_vlans(location=location,
                                  network_domain=network_domain)[0]

    kwargs = {
        "name": vm_["name"],
        "image": image,
        "ex_description": vm_["description"],
        "ex_network_domain": network_domain,
        "ex_vlan": vlan,
        "ex_is_started": vm_["is_started"],
    }

    event_data = _to_event_data(kwargs)

    __utils__["cloud.fire_event"](
        "event",
        "requesting instance",
        "salt/cloud/{}/requesting".format(vm_["name"]),
        args=__utils__["cloud.filter_event"]("requesting", event_data,
                                             list(event_data)),
        sock_dir=__opts__["sock_dir"],
        transport=__opts__["transport"],
    )

    # Initial password (excluded from event payload)
    initial_password = NodeAuthPassword(vm_["auth"])
    kwargs["auth"] = initial_password

    try:
        data = conn.create_node(**kwargs)
    except Exception as exc:  # pylint: disable=broad-except
        log.error(
            "Error creating %s on DIMENSIONDATA\n\n"
            "The following exception was thrown by libcloud when trying to "
            "run the initial deployment: \n%s",
            vm_["name"],
            exc,
            exc_info_on_loglevel=logging.DEBUG,
        )
        return False

    try:
        data = __utils__["cloud.wait_for_ip"](
            _query_node_data,
            update_args=(vm_, data),
            timeout=config.get_cloud_config_value("wait_for_ip_timeout",
                                                  vm_,
                                                  __opts__,
                                                  default=25 * 60),
            interval=config.get_cloud_config_value("wait_for_ip_interval",
                                                   vm_,
                                                   __opts__,
                                                   default=30),
            max_failures=config.get_cloud_config_value(
                "wait_for_ip_max_failures", vm_, __opts__, default=60),
        )
    except (SaltCloudExecutionTimeout, SaltCloudExecutionFailure) as exc:
        try:
            # It might be already up, let's destroy it!
            destroy(vm_["name"])  # pylint: disable=not-callable
        except SaltCloudSystemExit:
            pass
        finally:
            raise SaltCloudSystemExit(str(exc))

    log.debug("VM is now running")
    if ssh_interface(vm_) == "private_ips":
        ip_address = preferred_ip(vm_, data.private_ips)
    else:
        ip_address = preferred_ip(vm_, data.public_ips)
    log.debug("Using IP address %s", ip_address)

    if __utils__["cloud.get_salt_interface"](vm_, __opts__) == "private_ips":
        salt_ip_address = preferred_ip(vm_, data.private_ips)
        log.info("Salt interface set to: %s", salt_ip_address)
    else:
        salt_ip_address = preferred_ip(vm_, data.public_ips)
        log.debug("Salt interface set to: %s", salt_ip_address)

    if not ip_address:
        raise SaltCloudSystemExit("No IP addresses could be found.")

    vm_["salt_host"] = salt_ip_address
    vm_["ssh_host"] = ip_address
    vm_["password"] = vm_["auth"]

    ret = __utils__["cloud.bootstrap"](vm_, __opts__)

    ret.update(data.__dict__)

    if "password" in data.extra:
        del data.extra["password"]

    log.info("Created Cloud VM '%s'", vm_["name"])
    log.debug("'%s' VM creation details:\n%s", vm_["name"],
              pprint.pformat(data.__dict__))

    __utils__["cloud.fire_event"](
        "event",
        "created instance",
        "salt/cloud/{}/created".format(vm_["name"]),
        args=__utils__["cloud.filter_event"](
            "created", vm_, ["name", "profile", "provider", "driver"]),
        sock_dir=__opts__["sock_dir"],
        transport=__opts__["transport"],
    )

    return ret
Ejemplo n.º 23
0
def create(vm_):
    '''
    Create a single VM from a data dict

    CLI Example:

    .. code-block:: bash

        salt-cloud -p profile_name vm_name
    '''
    try:
        # Check for required profile parameters before sending any API calls.
        if vm_['profile'] and config.is_profile_configured(__opts__,
                                                           __active_provider_name__ or 'joyent',
                                                           vm_['profile']) is False:
            return False
    except AttributeError:
        pass

    # Since using "provider: <provider-engine>" is deprecated, alias provider
    # to use driver: "driver: <provider-engine>"
    if 'provider' in vm_:
        vm_['driver'] = vm_.pop('provider')

    key_filename = config.get_cloud_config_value(
        'private_key', vm_, __opts__, search_global=False, default=None
    )

    salt.utils.cloud.fire_event(
        'event',
        'starting create',
        'salt/cloud/{0}/creating'.format(vm_['name']),
        {
            'name': vm_['name'],
            'profile': vm_['profile'],
            'provider': vm_['driver'],
        },
        transport=__opts__['transport']
    )

    log.info(
        'Creating Cloud VM {0} in {1}'.format(
            vm_['name'],
            vm_.get('location', DEFAULT_LOCATION)
        )
    )

    # added . for fqdn hostnames
    salt.utils.cloud.check_name(vm_['name'], 'a-zA-Z0-9-.')
    kwargs = {
        'name': vm_['name'],
        'image': get_image(vm_),
        'size': get_size(vm_),
        'location': vm_.get('location', DEFAULT_LOCATION)

    }

    salt.utils.cloud.fire_event(
        'event',
        'requesting instance',
        'salt/cloud/{0}/requesting'.format(vm_['name']),
        {'kwargs': kwargs},
        transport=__opts__['transport']
    )

    try:
        data = create_node(**kwargs)
    except Exception as exc:
        log.error(
            'Error creating {0} on JOYENT\n\n'
            'The following exception was thrown when trying to '
            'run the initial deployment: \n{1}'.format(
                vm_['name'], str(exc)
            ),
            # Show the traceback if the debug logging level is enabled
            exc_info_on_loglevel=logging.DEBUG
        )
        return False

    query_instance(vm_)
    data = show_instance(vm_['name'], call='action')

    vm_['key_filename'] = key_filename
    vm_['ssh_host'] = data[1]['primaryIp']

    salt.utils.cloud.bootstrap(vm_, __opts__)

    salt.utils.cloud.fire_event(
        'event',
        'created instance',
        'salt/cloud/{0}/created'.format(vm_['name']),
        {
            'name': vm_['name'],
            'profile': vm_['profile'],
            'provider': vm_['driver'],
        },
        transport=__opts__['transport']
    )

    return data[1]
Ejemplo n.º 24
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_hw',
                vm_['profile'],
                vm_=vm_) is False:
            return False
    except AttributeError:
        pass

    name = vm_['name']
    hostname = name
    domain = config.get_cloud_config_value('domain',
                                           vm_,
                                           __opts__,
                                           default=None)
    if domain is None:
        SaltCloudSystemExit(
            'A domain name is required for the SoftLayer driver.')

    if vm_.get('use_fqdn'):
        name = '.'.join([name, domain])
        vm_['name'] = name

    __utils__['cloud.fire_event'](
        'event',
        'starting create',
        'salt/cloud/{0}/creating'.format(name),
        args=__utils__['cloud.filter_event'](
            'creating', vm_, ['name', 'profile', 'provider', 'driver']),
        sock_dir=__opts__['sock_dir'],
        transport=__opts__['transport'])

    log.info('Creating Cloud VM %s', name)
    conn = get_conn(service='SoftLayer_Product_Order')
    kwargs = {
        'complexType':
        'SoftLayer_Container_Product_Order_Hardware_Server',
        'quantity':
        1,
        'hardware': [{
            'hostname': hostname,
            'domain': domain,
        }],
        # Baremetal Package
        'packageId':
        50,
        'prices': [
            # Size Ex: 1921: 2 x 2.0 GHz Core Bare Metal Instance - 2 GB Ram
            {
                'id': vm_['size']
            },
            # HDD Ex: 19: 250GB SATA II
            {
                'id': vm_['hdd']
            },
            # Image Ex: 13963: CentOS 6.0 - Minimal Install (64 bit)
            {
                'id': vm_['image']
            },

            # The following items are currently required
            # Reboot / Remote Console
            {
                'id': '905'
            },
            # 1 IP Address
            {
                'id': '21'
            },
            # Host Ping Monitoring
            {
                'id': '55'
            },
            # Email and Ticket Notifications
            {
                'id': '57'
            },
            # Automated Notification Response
            {
                'id': '58'
            },
            # Unlimited SSL VPN Users & 1 PPTP VPN User per account
            {
                'id': '420'
            },
            # Nessus Vulnerability Assessment & Reporting
            {
                'id': '418'
            },
        ],
    }

    optional_products = config.get_cloud_config_value('optional_products',
                                                      vm_,
                                                      __opts__,
                                                      default=[])
    for product in optional_products:
        kwargs['prices'].append({'id': product})

    # Default is 273 (100 Mbps Public & Private Networks)
    port_speed = config.get_cloud_config_value('port_speed',
                                               vm_,
                                               __opts__,
                                               default=273)
    kwargs['prices'].append({'id': port_speed})

    # Default is 1800 (0 GB Bandwidth)
    bandwidth = config.get_cloud_config_value('bandwidth',
                                              vm_,
                                              __opts__,
                                              default=1800)
    kwargs['prices'].append({'id': bandwidth})

    post_uri = config.get_cloud_config_value('post_uri',
                                             vm_,
                                             __opts__,
                                             default=None)
    if post_uri:
        kwargs['prices'].append({'id': post_uri})

    vlan_id = config.get_cloud_config_value('vlan',
                                            vm_,
                                            __opts__,
                                            default=False)
    if vlan_id:
        kwargs['primaryNetworkComponent'] = {
            'networkVlan': {
                'id': vlan_id,
            }
        }

    location = get_location(vm_)
    if location:
        kwargs['location'] = location

    __utils__['cloud.fire_event']('event',
                                  'requesting instance',
                                  'salt/cloud/{0}/requesting'.format(name),
                                  args={
                                      'kwargs':
                                      __utils__['cloud.filter_event'](
                                          'requesting', kwargs, list(kwargs)),
                                  },
                                  sock_dir=__opts__['sock_dir'],
                                  transport=__opts__['transport'])

    try:
        response = conn.placeOrder(kwargs)
        # Leaving the following line in, commented, for easy debugging
        #response = conn.verifyOrder(kwargs)
    except Exception as exc:
        log.error(
            'Error creating %s on SoftLayer\n\n'
            'The following exception was thrown when trying to '
            'run the initial deployment: \n%s',
            name,
            exc,
            # Show the traceback if the debug logging level is enabled
            exc_info_on_loglevel=logging.DEBUG)
        return False

    def wait_for_ip():
        '''
        Wait for the IP address to become available
        '''
        nodes = list_nodes_full()
        if 'primaryIpAddress' in nodes[hostname]:
            return nodes[hostname]['primaryIpAddress']
        time.sleep(1)
        return False

    ip_address = salt.utils.cloud.wait_for_fun(
        wait_for_ip,
        timeout=config.get_cloud_config_value('wait_for_fun_timeout',
                                              vm_,
                                              __opts__,
                                              default=15 * 60),
    )

    ssh_connect_timeout = config.get_cloud_config_value(
        # 15 minutes
        'ssh_connect_timeout',
        vm_,
        __opts__,
        900)
    if not salt.utils.cloud.wait_for_port(ip_address,
                                          timeout=ssh_connect_timeout):
        raise SaltCloudSystemExit('Failed to authenticate against remote ssh')

    pass_conn = get_conn(service='SoftLayer_Account')
    mask = {
        'virtualGuests': {
            'powerState': '',
            'operatingSystem': {
                'passwords': ''
            },
        },
    }

    def get_passwd():
        '''
        Wait for the password to become available
        '''
        node_info = pass_conn.getVirtualGuests(id=response['id'], mask=mask)
        for node in node_info:
            if node['id'] == response['id'] \
                    and 'passwords' in node['operatingSystem'] \
                    and len(node['operatingSystem']['passwords']) > 0:
                return node['operatingSystem']['passwords'][0]['password']
        time.sleep(5)
        return False

    passwd = salt.utils.cloud.wait_for_fun(
        get_passwd,
        timeout=config.get_cloud_config_value('wait_for_fun_timeout',
                                              vm_,
                                              __opts__,
                                              default=15 * 60),
    )
    response['password'] = passwd
    response['public_ip'] = ip_address

    ssh_username = config.get_cloud_config_value('ssh_username',
                                                 vm_,
                                                 __opts__,
                                                 default='root')

    vm_['ssh_host'] = ip_address
    vm_['password'] = passwd
    ret = __utils__['cloud.bootstrap'](vm_, __opts__)

    ret.update(response)

    __utils__['cloud.fire_event'](
        'event',
        'created instance',
        'salt/cloud/{0}/created'.format(name),
        args=__utils__['cloud.filter_event'](
            'created', vm_, ['name', 'profile', 'provider', 'driver']),
        sock_dir=__opts__['sock_dir'],
        transport=__opts__['transport'])

    return ret
Ejemplo n.º 25
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_hw',
                                                           vm_['profile']) is False:
            return False
    except AttributeError:
        pass

    # Since using "provider: <provider-engine>" is deprecated, alias provider
    # to use driver: "driver: <provider-engine>"
    if 'provider' in vm_:
        vm_['driver'] = vm_.pop('provider')

    name = vm_['name']
    hostname = name
    domain = config.get_cloud_config_value(
        'domain', vm_, __opts__, default=None
    )
    if domain is None:
        SaltCloudSystemExit(
            'A domain name is required for the SoftLayer driver.'
        )

    if vm_.get('use_fqdn'):
        name = '.'.join([name, domain])
        vm_['name'] = name

    salt.utils.cloud.fire_event(
        'event',
        'starting create',
        'salt/cloud/{0}/creating'.format(name),
        {
            'name': name,
            'profile': vm_['profile'],
            'provider': vm_['driver'],
        },
        transport=__opts__['transport']
    )

    log.info('Creating Cloud VM {0}'.format(name))
    conn = get_conn(service='SoftLayer_Product_Order')
    kwargs = {
        'complexType': 'SoftLayer_Container_Product_Order_Hardware_Server',
        'quantity': 1,
        'hardware': [{
            'hostname': hostname,
            'domain': domain,
        }],
        # Baremetal Package
        'packageId': 50,
        'prices': [
            # Size Ex: 1921: 2 x 2.0 GHz Core Bare Metal Instance - 2 GB Ram
            {'id': vm_['size']},
            # HDD Ex: 19: 250GB SATA II
            {'id': vm_['hdd']},
            # Image Ex: 13963: CentOS 6.0 - Minimal Install (64 bit)
            {'id': vm_['image']},

            # The following items are currently required
            # Reboot / Remote Console
            {'id': '905'},
            # 1 IP Address
            {'id': '21'},
            # Host Ping Monitoring
            {'id': '55'},
            # Email and Ticket Notifications
            {'id': '57'},
            # Automated Notification Response
            {'id': '58'},
            # Unlimited SSL VPN Users & 1 PPTP VPN User per account
            {'id': '420'},
            # Nessus Vulnerability Assessment & Reporting
            {'id': '418'},
        ],
    }

    optional_products = config.get_cloud_config_value(
        'optional_products', vm_, __opts__, default=[]
    )
    for product in optional_products:
        kwargs['prices'].append({'id': product})

    # Default is 273 (100 Mbps Public & Private Networks)
    port_speed = config.get_cloud_config_value(
        'port_speed', vm_, __opts__, default=273
    )
    kwargs['prices'].append({'id': port_speed})

    # Default is 1800 (0 GB Bandwidth)
    bandwidth = config.get_cloud_config_value(
        'bandwidth', vm_, __opts__, default=1800
    )
    kwargs['prices'].append({'id': bandwidth})

    post_uri = config.get_cloud_config_value(
        'post_uri', vm_, __opts__, default=None
    )
    if post_uri:
        kwargs['prices'].append({'id': post_uri})

    vlan_id = config.get_cloud_config_value(
        'vlan', vm_, __opts__, default=False
    )
    if vlan_id:
        kwargs['primaryNetworkComponent'] = {
            'networkVlan': {
                'id': vlan_id,
            }
        }

    location = get_location(vm_)
    if location:
        kwargs['location'] = location

    salt.utils.cloud.fire_event(
        'event',
        'requesting instance',
        'salt/cloud/{0}/requesting'.format(name),
        {'kwargs': kwargs},
        transport=__opts__['transport']
    )

    try:
        response = conn.placeOrder(kwargs)
        # Leaving the following line in, commented, for easy debugging
        #response = conn.verifyOrder(kwargs)
    except Exception as exc:
        log.error(
            'Error creating {0} on SoftLayer\n\n'
            'The following exception was thrown when trying to '
            'run the initial deployment: \n{1}'.format(
                name, str(exc)
            ),
            # Show the traceback if the debug logging level is enabled
            exc_info_on_loglevel=logging.DEBUG
        )
        return False

    def wait_for_ip():
        '''
        Wait for the IP address to become available
        '''
        nodes = list_nodes_full()
        if 'primaryIpAddress' in nodes[hostname]:
            return nodes[hostname]['primaryIpAddress']
        time.sleep(1)
        return False

    ip_address = salt.utils.cloud.wait_for_fun(
        wait_for_ip,
        timeout=config.get_cloud_config_value(
            'wait_for_fun_timeout', vm_, __opts__, default=15 * 60),
    )

    ssh_connect_timeout = config.get_cloud_config_value(
        # 15 minutes
        'ssh_connect_timeout', vm_, __opts__, 900
    )
    if not salt.utils.cloud.wait_for_port(ip_address,
                                         timeout=ssh_connect_timeout):
        raise SaltCloudSystemExit(
            'Failed to authenticate against remote ssh'
        )

    pass_conn = get_conn(service='SoftLayer_Account')
    mask = {
        'virtualGuests': {
            'powerState': '',
            'operatingSystem': {
                'passwords': ''
            },
        },
    }

    def get_passwd():
        '''
        Wait for the password to become available
        '''
        node_info = pass_conn.getVirtualGuests(id=response['id'], mask=mask)
        for node in node_info:
            if node['id'] == response['id'] \
                    and 'passwords' in node['operatingSystem'] \
                    and len(node['operatingSystem']['passwords']) > 0:
                return node['operatingSystem']['passwords'][0]['password']
        time.sleep(5)
        return False

    passwd = salt.utils.cloud.wait_for_fun(
        get_passwd,
        timeout=config.get_cloud_config_value(
            'wait_for_fun_timeout', vm_, __opts__, default=15 * 60),
    )
    response['password'] = passwd
    response['public_ip'] = ip_address

    ssh_username = config.get_cloud_config_value(
        'ssh_username', vm_, __opts__, default='root'
    )

    vm_['ssh_host'] = ip_address
    vm_['password'] = passwd
    ret = salt.utils.cloud.bootstrap(vm_, __opts__)

    ret.update(response)

    salt.utils.cloud.fire_event(
        'event',
        'created instance',
        'salt/cloud/{0}/created'.format(name),
        {
            'name': name,
            'profile': vm_['profile'],
            'provider': vm_['driver'],
        },
        transport=__opts__['transport']
    )

    return ret
Ejemplo n.º 26
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 'gogrid',
                vm_['profile'],
                vm_=vm_) is False:
            return False
    except AttributeError:
        pass

    __utils__['cloud.fire_event'](
        'event',
        'starting create',
        'salt/cloud/{0}/creating'.format(vm_['name']),
        args=__utils__['cloud.filter_event'](
            'creating', vm_, ['name', 'profile', 'provider', 'driver']),
        sock_dir=__opts__['sock_dir'],
        transport=__opts__['transport'])

    if len(vm_['name']) > 20:
        raise SaltCloudException(
            'VM names must not be longer than 20 characters')

    log.info('Creating Cloud VM %s', vm_['name'])
    image_id = avail_images()[vm_['image']]['id']
    if 'assign_public_ip' in vm_:
        host_ip = vm_['assign_public_ip']
    else:
        public_ips = list_public_ips()
        if len(public_ips.keys()) < 1:
            raise SaltCloudException('No more IPs available')
        host_ip = list(public_ips)[0]

    create_kwargs = {
        'name': vm_['name'],
        'image': image_id,
        'ram': vm_['size'],
        'ip': host_ip,
    }

    __utils__['cloud.fire_event'](
        'event',
        'requesting instance',
        'salt/cloud/{0}/requesting'.format(vm_['name']),
        args={
            'kwargs':
            __utils__['cloud.filter_event']('requesting', create_kwargs,
                                            list(create_kwargs)),
        },
        sock_dir=__opts__['sock_dir'],
        transport=__opts__['transport'])

    try:
        data = _query('grid', 'server/add', args=create_kwargs)
    except Exception:
        log.error(
            'Error creating %s on GOGRID\n\n'
            'The following exception was thrown when trying to '
            'run the initial deployment:\n',
            vm_['name'],
            # Show the traceback if the debug logging level is enabled
            exc_info_on_loglevel=logging.DEBUG)
        return False

    ssh_username = config.get_cloud_config_value('ssh_username',
                                                 vm_,
                                                 __opts__,
                                                 default='root')

    def wait_for_apipass():
        '''
        Wait for the password to become available, via the API
        '''
        try:
            passwords = list_passwords()
            return passwords[vm_['name']][0]['password']
        except KeyError:
            pass
        time.sleep(5)
        return False

    vm_['password'] = salt.utils.cloud.wait_for_fun(
        wait_for_apipass,
        timeout=config.get_cloud_config_value('wait_for_fun_timeout',
                                              vm_,
                                              __opts__,
                                              default=15 * 60),
    )

    vm_['ssh_host'] = host_ip
    ret = __utils__['cloud.bootstrap'](vm_, __opts__)
    ret.update(data)

    log.info('Created Cloud VM \'%s\'', vm_['name'])
    log.debug('\'%s\' VM creation details:\n%s', vm_['name'],
              pprint.pformat(data))

    __utils__['cloud.fire_event'](
        'event',
        'created instance',
        'salt/cloud/{0}/created'.format(vm_['name']),
        args=__utils__['cloud.filter_event'](
            'created', vm_, ['name', 'profile', 'provider', 'driver']),
        sock_dir=__opts__['sock_dir'],
        transport=__opts__['transport'])

    return ret
Ejemplo n.º 27
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 'aliyun',
                                        vm_['profile']) is False:
            return False
    except AttributeError:
        pass

    # Since using "provider: <provider-engine>" is deprecated, alias provider
    # to use driver: "driver: <provider-engine>"
    if 'provider' in vm_:
        vm_['driver'] = vm_.pop('provider')

    salt.utils.cloud.fire_event(
        'event',
        'starting create',
        'salt/cloud/{0}/creating'.format(vm_['name']),
        {
            'name': vm_['name'],
            'profile': vm_['profile'],
            'provider': vm_['driver'],
        },
        transport=__opts__['transport']
    )

    log.info('Creating Cloud VM {0}'.format(vm_['name']))
    kwargs = {
        'name': vm_['name'],
        'size_id': get_size(vm_),
        'image_id': get_image(vm_),
        'region_id': __get_location(vm_),
        'securitygroup_id': get_securitygroup(vm_),
    }

    salt.utils.cloud.fire_event(
        'event',
        'requesting instance',
        'salt/cloud/{0}/requesting'.format(vm_['name']),
        {'kwargs': kwargs},
        transport=__opts__['transport']
    )

    try:
        ret = create_node(kwargs)
    except Exception as exc:
        log.error(
            'Error creating {0} on Aliyun ECS\n\n'
            'The following exception was thrown when trying to '
            'run the initial deployment: {1}'.format(
                vm_['name'],
                str(exc)
            ),
            # Show the traceback if the debug logging level is enabled
            exc_info_on_loglevel=logging.DEBUG
        )
        return False

    def __query_node_data(vm_name):
        data = show_instance(vm_name, call='action')
        if not data:
            # Trigger an error in the wait_for_ip function
            return False
        if data.get('PublicIpAddress', None) is not None:
            return data

    try:
        data = salt.utils.cloud.wait_for_ip(
            __query_node_data,
            update_args=(vm_['name'],),
            timeout=config.get_cloud_config_value(
                'wait_for_ip_timeout', vm_, __opts__, default=10 * 60),
            interval=config.get_cloud_config_value(
                'wait_for_ip_interval', vm_, __opts__, default=10),
        )
    except (SaltCloudExecutionTimeout, SaltCloudExecutionFailure) as exc:
        try:
            # It might be already up, let's destroy it!
            destroy(vm_['name'])
        except SaltCloudSystemExit:
            pass
        finally:
            raise SaltCloudSystemExit(str(exc))

    public_ip = data['PublicIpAddress'][0]
    log.debug('VM {0} is now running'.format(public_ip))
    vm_['ssh_host'] = public_ip

    # The instance is booted and accessible, let's Salt it!
    ret = salt.utils.cloud.bootstrap(vm_, __opts__)
    ret.update(data.__dict__)

    log.info('Created Cloud VM {0[name]!r}'.format(vm_))
    log.debug(
        '{0[name]!r} VM creation details:\n{1}'.format(
            vm_, pprint.pformat(data)
        )
    )

    salt.utils.cloud.fire_event(
        'event',
        'created instance',
        'salt/cloud/{0}/created'.format(vm_['name']),
        {
            'name': vm_['name'],
            'profile': vm_['profile'],
            'provider': vm_['driver'],
        },
        transport=__opts__['transport']
    )

    return ret
Ejemplo n.º 28
0
def create(vm_):
    '''
    Create a single instance from a data dict.

    CLI Examples:

    .. code-block:: bash

        salt-cloud -p qingcloud-ubuntu-c1m1 hostname1
        salt-cloud -m /path/to/mymap.sls -P
    '''
    try:
        # Check for required profile parameters before sending any API calls.
        if vm_['profile'] and config.is_profile_configured(
                __opts__, __active_provider_name__ or 'qingcloud',
                vm_['profile']) is False:
            return False
    except AttributeError:
        pass

    # Since using "provider: <provider-engine>" is deprecated, alias provider
    # to use driver: "driver: <provider-engine>"
    if 'provider' in vm_:
        vm_['driver'] = vm_.pop('provider')

    salt.utils.cloud.fire_event('event',
                                'starting create',
                                'salt/cloud/{0}/creating'.format(vm_['name']),
                                {
                                    'name': vm_['name'],
                                    'profile': vm_['profile'],
                                    'provider': vm_['driver'],
                                },
                                transport=__opts__['transport'])

    log.info('Creating Cloud VM {0}'.format(vm_['name']))

    # params
    params = {
        'action': 'RunInstances',
        'instance_name': vm_['name'],
        'zone': _get_location(vm_),
        'instance_type': _get_size(vm_),
        'image_id': _get_image(vm_),
        'vxnets.1': vm_['vxnets'],
        'login_mode': vm_['login_mode'],
        'login_keypair': vm_['login_keypair'],
    }

    salt.utils.cloud.fire_event('event',
                                'requesting instance',
                                'salt/cloud/{0}/requesting'.format(
                                    vm_['name']), {'kwargs': params},
                                transport=__opts__['transport'])

    result = query(params)
    new_instance_id = result['instances'][0]

    try:
        data = salt.utils.cloud.wait_for_ip(
            _query_node_data,
            update_args=(new_instance_id, ),
            timeout=config.get_cloud_config_value('wait_for_ip_timeout',
                                                  vm_,
                                                  __opts__,
                                                  default=10 * 60),
            interval=config.get_cloud_config_value('wait_for_ip_interval',
                                                   vm_,
                                                   __opts__,
                                                   default=10),
        )
    except (SaltCloudExecutionTimeout, SaltCloudExecutionFailure) as exc:
        try:
            # It might be already up, let's destroy it!
            destroy(vm_['name'])
        except SaltCloudSystemExit:
            pass
        finally:
            raise SaltCloudSystemExit(str(exc))

    private_ip = data['private_ips'][0]

    log.debug('VM {0} is now running'.format(private_ip))

    vm_['ssh_host'] = private_ip

    # The instance is booted and accessible, let's Salt it!
    salt.utils.cloud.bootstrap(vm_, __opts__)

    log.info('Created Cloud VM {0[name]!r}'.format(vm_))

    log.debug('{0[name]!r} VM creation details:\n{1}'.format(
        vm_, pprint.pformat(data)))

    salt.utils.cloud.fire_event('event',
                                'created instance',
                                'salt/cloud/{0}/created'.format(vm_['name']), {
                                    'name': vm_['name'],
                                    'profile': vm_['profile'],
                                    'provider': vm_['driver'],
                                },
                                transport=__opts__['transport'])

    return data
Ejemplo n.º 29
0
def create(vm_):
    '''
    Create a single Linode VM.
    '''
    try:
        # Check for required profile parameters before sending any API calls.
        if config.is_profile_configured(__opts__,
                                        __active_provider_name__ or 'linode',
                                        vm_['profile']) is False:
            return False
    except AttributeError:
        pass

    # Since using "provider: <provider-engine>" is deprecated, alias provider
    # to use driver: "driver: <provider-engine>"
    if 'provider' in vm_:
        vm_['driver'] = vm_.pop('provider')

    salt.utils.cloud.fire_event(
        'event',
        'starting create',
        'salt/cloud/{0}/creating'.format(vm_['name']),
        {
            'name': vm_['name'],
            'profile': vm_['profile'],
            'provider': vm_['driver'],
        },
        transport=__opts__['transport']
    )

    log.info('Creating Cloud VM {0}'.format(vm_['name']))

    data = {}
    kwargs = {
        'name': vm_['name'],
        'image': vm_['image'],
        'size': vm_['size'],
    }

    plan_id = get_plan_id(vm_['size'])
    try:
        datacenter_id = get_datacenter_id(vm_['location'])
    except KeyError:
        # Linode's default datacenter is Dallas, but we still have to set one to
        # use the create function from Linode's API. Dallas's datacenter id is 2.
        datacenter_id = 2

    if 'clonefrom' in vm_:
        linode_id = get_linode_id_from_name(vm_['clonefrom'])
        clone_source = get_linode(linode_id)

        kwargs.update({'clonefrom': vm_['clonefrom']})
        kwargs['image'] = 'Clone of {0}'.format(vm_['clonefrom'])
        kwargs['size'] = clone_source['TOTALRAM']

        try:
            result = clone(linode_id, datacenter_id, plan_id)
        except Exception:
            log.error(
                'Error cloning {0} on Linode\n\n'
                'The following exception was thrown by Linode when trying to '
                'clone the specified machine:\n'.format(
                    vm_['clonefrom']
                ),
                exc_info_on_loglevel=logging.DEBUG
            )
            return False
    else:
        try:
            result = _query('linode', 'create', args={
                'PLANID': plan_id,
                'DATACENTERID': datacenter_id
            })
        except Exception:
            log.error(
                'Error creating {0} on Linode\n\n'
                'The following exception was thrown by Linode when trying to '
                'run the initial deployment:\n'.format(
                    vm_['name']
                ),
                exc_info_on_loglevel=logging.DEBUG
            )
            return False

    salt.utils.cloud.fire_event(
        'event',
        'requesting instance',
        'salt/cloud/{0}/requesting'.format(vm_['name']),
        {'kwargs': kwargs},
        transport=__opts__['transport']
    )

    node_id = _clean_data(result)['LinodeID']
    data['id'] = node_id

    if not _wait_for_status(node_id, status=(_get_status_id_by_name('brand_new'))):
        log.error(
            'Error creating {0} on LINODE\n\n'
            'while waiting for initial ready status'.format(vm_['name']),
            exc_info_on_loglevel=logging.DEBUG
        )

    # Update the Linode's Label to reflect the given VM name
    update_linode(node_id, update_args={'Label': vm_['name']})
    log.debug('Set name for {0} - was linode{1}.'.format(vm_['name'], node_id))

    # Create disks and get ids
    log.debug('Creating disks for {0}'.format(vm_['name']))
    root_disk_id = create_disk_from_distro(vm_, node_id)['DiskID']
    swap_disk_id = create_swap_disk(vm_, node_id)['DiskID']

    # Add private IP address if requested
    if get_private_ip(vm_):
        create_private_ip(vm_, node_id)

    # Create a ConfigID using disk ids
    config_id = create_config(vm_,
                              node_id,
                              root_disk_id,
                              swap_disk_id)['ConfigID']

    # Boot the VM and get the JobID from Linode
    boot_job_id = boot(node_id, config_id)['JobID']

    if not _wait_for_job(node_id, boot_job_id):
        log.error('Boot failed for {0}.'.format(vm_['name']))
        return False

    node_data = get_linode(node_id)
    ips = get_ips(node_id)
    state = int(node_data['STATUS'])

    data['image'] = vm_['image']
    data['name'] = node_data['LABEL']
    data['size'] = node_data['TOTALRAM']
    data['state'] = _get_status_descr_by_id(state)
    data['private_ips'] = ips['private_ips']
    data['public_ips'] = ips['public_ips']

    vm_['ssh_host'] = data['public_ips'][0]

    # If a password wasn't supplied in the profile or provider config, set it now.
    vm_['password'] = get_password(vm_)

    # Bootstrap!
    ret = salt.utils.cloud.bootstrap(vm_, __opts__)

    ret.update(data)

    log.info('Created Cloud VM {0[name]!r}'.format(vm_))
    log.debug(
        '{0[name]!r} VM creation details:\n{1}'.format(
            vm_, pprint.pformat(data)
        )
    )

    salt.utils.cloud.fire_event(
        'event',
        'created instance',
        'salt/cloud/{0}/created'.format(vm_['name']),
        {
            'name': vm_['name'],
            'profile': vm_['profile'],
            'provider': vm_['driver'],
        },
        transport=__opts__['transport']
    )

    return ret
Ejemplo n.º 30
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
Ejemplo n.º 31
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) and access_ip != '':
            data.public_ips = [
                access_ip,
            ]
            return data

        result = []

        if 'private_ips' not in node and 'public_ips' not in node and \
           'floating_ips' not in node and 'fixed_ips' not in node and \
           'access_ip' in node.get('extra', {}):
            result = [node['extra']['access_ip']]

        private = node.get('private_ips', [])
        public = node.get('public_ips', [])
        fixed = node.get('fixed_ips', [])
        floating = node.get('floating_ips', [])

        if private and not public:
            log.warning('Private IPs returned, but not public... Checking for '
                        'misidentified IPs')
            for private_ip in private:
                private_ip = preferred_ip(vm_, [private_ip])
                if salt.utils.cloud.is_public_ip(private_ip):
                    log.warning('{0} is a public IP'.format(private_ip))
                    data.public_ips.append(private_ip)
                    log.warning(
                        ('Public IP address was not ready when we last'
                         ' checked.  Appending public IP address now.'))
                    public = data.public_ips
                else:
                    log.warning('{0} is a private IP'.format(private_ip))
                    ignore_ip = ignore_cidr(vm_, private_ip)
                    if private_ip not in data.private_ips and not ignore_ip:
                        result.append(private_ip)

        # populate return data with private_ips
        # when ssh_interface is set to private_ips and public_ips exist
        if not result and ssh_interface(vm_) == 'private_ips':
            for private_ip in private:
                ignore_ip = ignore_cidr(vm_, private_ip)
                if private_ip not in data.private_ips and not ignore_ip:
                    result.append(private_ip)

        non_private_ips = []

        if public:
            data.public_ips = public
            if ssh_interface(vm_) == 'public_ips':
                non_private_ips.append(public)

        if floating:
            data.floating_ips = floating
            if ssh_interface(vm_) == 'floating_ips':
                non_private_ips.append(floating)

        if fixed:
            data.fixed_ips = fixed
            if ssh_interface(vm_) == 'fixed_ips':
                non_private_ips.append(fixed)

        if non_private_ips:
            log.debug('result = {0}'.format(non_private_ips))
            data.private_ips = result
            if ssh_interface(vm_) != 'private_ips':
                return data

        if result:
            log.debug('result = {0}'.format(result))
            data.private_ips = result
            if ssh_interface(vm_) == 'private_ips':
                return data

    try:
        data = salt.utils.cloud.wait_for_ip(
            __query_node_data,
            update_args=(vm_, data),
            timeout=config.get_cloud_config_value('wait_for_ip_timeout',
                                                  vm_,
                                                  __opts__,
                                                  default=10 * 60),
            interval=config.get_cloud_config_value('wait_for_ip_interval',
                                                   vm_,
                                                   __opts__,
                                                   default=10),
        )
    except (SaltCloudExecutionTimeout, SaltCloudExecutionFailure) as exc:
        try:
            # It might be already up, let's destroy it!
            destroy(vm_['name'])
        except SaltCloudSystemExit:
            pass
        finally:
            raise SaltCloudSystemExit(str(exc))

    log.debug('VM is now running')

    if ssh_interface(vm_) == 'private_ips':
        ip_address = preferred_ip(vm_, data.private_ips)
    elif ssh_interface(vm_) == 'fixed_ips':
        ip_address = preferred_ip(vm_, data.fixed_ips)
    elif ssh_interface(vm_) == 'floating_ips':
        ip_address = preferred_ip(vm_, data.floating_ips)
    else:
        ip_address = preferred_ip(vm_, data.public_ips)
    log.debug('Using IP address {0}'.format(ip_address))

    if salt.utils.cloud.get_salt_interface(vm_, __opts__) == 'private_ips':
        salt_ip_address = preferred_ip(vm_, data.private_ips)
        log.info('Salt interface set to: {0}'.format(salt_ip_address))
    elif salt.utils.cloud.get_salt_interface(vm_, __opts__) == 'fixed_ips':
        salt_ip_address = preferred_ip(vm_, data.fixed_ips)
        log.info('Salt interface set to: {0}'.format(salt_ip_address))
    elif salt.utils.cloud.get_salt_interface(vm_, __opts__) == 'floating_ips':
        salt_ip_address = preferred_ip(vm_, data.floating_ips)
        log.info('Salt interface set to: {0}'.format(salt_ip_address))
    else:
        salt_ip_address = preferred_ip(vm_, data.public_ips)
        log.debug('Salt interface set to: {0}'.format(salt_ip_address))

    if not ip_address:
        raise SaltCloudSystemExit('A valid IP address was not found')

    vm_['ssh_host'] = ip_address
    vm_['salt_host'] = salt_ip_address

    ret = salt.utils.cloud.bootstrap(vm_, __opts__)

    ret.update(data.__dict__)

    if 'password' in ret['extra']:
        del ret['extra']['password']

    log.info('Created Cloud VM \'{0[name]}\''.format(vm_))
    log.debug('\'{0[name]}\' VM creation details:\n{1}'.format(
        vm_, pprint.pformat(data.__dict__)))

    event_data = {
        'name': vm_['name'],
        'profile': vm_['profile'],
        'provider': vm_['driver'],
        'instance_id': vm_['instance_id'],
        'floating_ips': data.floating_ips,
        'fixed_ips': data.fixed_ips,
        'private_ips': data.private_ips,
        'public_ips': data.public_ips
    }

    salt.utils.cloud.fire_event('event',
                                'created instance',
                                'salt/cloud/{0}/created'.format(vm_['name']),
                                event_data,
                                transport=__opts__['transport'])
    salt.utils.cloud.cachedir_index_add(vm_['name'], vm_['profile'], 'nova',
                                        vm_['driver'])
    return ret
Ejemplo n.º 32
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
                                         'oneandone'),
                                        vm_['profile']) is False):
            return False
    except AttributeError:
        pass

    data = None
    conn = get_conn()
    hdds = []

    # Assemble the composite server object.
    server = _get_server(vm_)

    if not bool(server.specs['hardware']['fixed_instance_size_id'])\
        and not bool(server.specs['server_type'] == 'baremetal'):
        # Assemble the hdds object.
        hdds = _get_hdds(vm_)

    __utils__['cloud.fire_event'](
        'event',
        'requesting instance',
        'salt/cloud/{0}/requesting'.format(vm_['name']),
        args={'name': vm_['name']},
        sock_dir=__opts__['sock_dir'],
        transport=__opts__['transport']
    )

    try:
        data = conn.create_server(server=server, hdds=hdds)

        _wait_for_completion(conn,
                             get_wait_timeout(vm_),
                             data['id'])
    except Exception as exc:  # pylint: disable=W0703
        log.error(
            'Error creating %s on 1and1\n\n'
            'The following exception was thrown by the 1and1 library '
            'when trying to run the initial deployment: \n%s',
            vm_['name'], exc, exc_info_on_loglevel=logging.DEBUG
        )
        return False

    vm_['server_id'] = data['id']
    password = data['first_password']

    def __query_node_data(vm_, data):
        '''
        Query node data until node becomes available.
        '''
        running = False
        try:
            data = show_instance(vm_['name'], 'action')
            if not data:
                return False
            log.debug(
                'Loaded node data for %s:\nname: %s\nstate: %s',
                vm_['name'],
                pprint.pformat(data['name']),
                data['status']['state']
            )
        except Exception as err:
            log.error(
                'Failed to get nodes list: %s', err,
                # Show the trackback if the debug logging level is enabled
                exc_info_on_loglevel=logging.DEBUG
            )
            # Trigger a failure in the wait for IP function
            return False

        running = data['status']['state'].lower() == 'powered_on'
        if not running:
            # Still not running, trigger another iteration
            return

        vm_['ssh_host'] = data['ips'][0]['ip']

        return data

    try:
        data = salt.utils.cloud.wait_for_ip(
            __query_node_data,
            update_args=(vm_, data),
            timeout=config.get_cloud_config_value(
                'wait_for_ip_timeout', vm_, __opts__, default=10 * 60),
            interval=config.get_cloud_config_value(
                'wait_for_ip_interval', vm_, __opts__, default=10),
        )
    except (SaltCloudExecutionTimeout, SaltCloudExecutionFailure) as exc:
        try:
            # It might be already up, let's destroy it!
            destroy(vm_['name'])
        except SaltCloudSystemExit:
            pass
        finally:
            raise SaltCloudSystemExit(six.text_type(exc.message))

    log.debug('VM is now running')
    log.info('Created Cloud VM %s', vm_)
    log.debug('%s VM creation details:\n%s', vm_, pprint.pformat(data))

    __utils__['cloud.fire_event'](
        'event',
        'created instance',
        'salt/cloud/{0}/created'.format(vm_['name']),
        args={
            'name': vm_['name'],
            'profile': vm_['profile'],
            'provider': vm_['driver'],
        },
        sock_dir=__opts__['sock_dir'],
        transport=__opts__['transport']
    )

    if 'ssh_host' in vm_:
        vm_['password'] = password
        vm_['key_filename'] = get_key_filename(vm_)
        ret = __utils__['cloud.bootstrap'](vm_, __opts__)
        ret.update(data)
        return ret
    else:
        raise SaltCloudSystemExit('A valid IP address was not found.')
Ejemplo n.º 33
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 'softlayer',
                                        vm_['profile']) is False:
            return False
    except AttributeError:
        pass

    # Since using "provider: <provider-engine>" is deprecated, alias provider
    # to use driver: "driver: <provider-engine>"
    if 'provider' in vm_:
        vm_['driver'] = vm_.pop('provider')

    salt.utils.cloud.fire_event(
        'event',
        'starting create',
        'salt/cloud/{0}/creating'.format(vm_['name']),
        {
            'name': vm_['name'],
            'profile': vm_['profile'],
            'provider': vm_['driver'],
        },
        transport=__opts__['transport']
    )

    log.info('Creating Cloud VM {0}'.format(vm_['name']))
    conn = get_conn()
    kwargs = {
        'hostname': vm_['name'],
        'domain': vm_['domain'],
        'startCpus': vm_['cpu_number'],
        'maxMemory': vm_['ram'],
        'localDiskFlag': vm_['local_disk'],
        'hourlyBillingFlag': vm_['hourly_billing'],
    }

    if 'image' in vm_:
        kwargs['operatingSystemReferenceCode'] = vm_['image']
        kwargs['blockDevices'] = [{
            'device': '0',
            'diskImage': {'capacity': vm_['disk_size']},
        }]
    elif 'global_identifier' in vm_:
        kwargs['blockDeviceTemplateGroup'] = {
            'globalIdentifier': vm_['global_identifier']
        }

    location = get_location(vm_)
    if location:
        kwargs['datacenter'] = {'name': location}

    private_vlan = config.get_cloud_config_value(
        'private_vlan', vm_, __opts__, default=False
    )
    if private_vlan:
        kwargs['primaryBackendNetworkComponent'] = {
            'networkVlan': {
                'id': private_vlan,
            }
        }

    private_network = config.get_cloud_config_value(
        'private_network', vm_, __opts__, default=False
    )
    if bool(private_network) is True:
        kwargs['privateNetworkOnlyFlag'] = 'True'

    public_vlan = config.get_cloud_config_value(
        'public_vlan', vm_, __opts__, default=False
    )
    if public_vlan:
        kwargs['primaryNetworkComponent'] = {
            'networkVlan': {
                'id': public_vlan,
            }
        }

    max_net_speed = config.get_cloud_config_value(
        'max_net_speed', vm_, __opts__, default=10
    )
    if max_net_speed:
        kwargs['networkComponents'] = [{
            'maxSpeed': int(max_net_speed)
        }]

    salt.utils.cloud.fire_event(
        'event',
        'requesting instance',
        'salt/cloud/{0}/requesting'.format(vm_['name']),
        {'kwargs': kwargs},
        transport=__opts__['transport']
    )

    try:
        response = conn.createObject(kwargs)
    except Exception as exc:
        log.error(
            'Error creating {0} on SoftLayer\n\n'
            'The following exception was thrown when trying to '
            'run the initial deployment: \n{1}'.format(
                vm_['name'], str(exc)
            ),
            # Show the traceback if the debug logging level is enabled
            exc_info_on_loglevel=logging.DEBUG
        )
        return False

    ip_type = 'primaryIpAddress'
    private_ssh = config.get_cloud_config_value(
        'private_ssh', vm_, __opts__, default=False
    )
    private_wds = config.get_cloud_config_value(
        'private_windows', vm_, __opts__, default=False
    )
    if private_ssh or private_wds:
        ip_type = 'primaryBackendIpAddress'

    def wait_for_ip():
        '''
        Wait for the IP address to become available
        '''
        nodes = list_nodes_full()
        if ip_type in nodes[vm_['name']]:
            return nodes[vm_['name']][ip_type]
        time.sleep(1)
        return False

    ip_address = salt.utils.cloud.wait_for_fun(
        wait_for_ip,
        timeout=config.get_cloud_config_value(
            'wait_for_fun_timeout', vm_, __opts__, default=15 * 60),
    )
    if config.get_cloud_config_value('deploy', vm_, __opts__) is not True:
        return show_instance(vm_['name'], call='action')

    SSH_PORT = 22
    WINDOWS_DS_PORT = 445
    managing_port = SSH_PORT
    if config.get_cloud_config_value('windows', vm_, __opts__) or \
            config.get_cloud_config_value('win_installer', vm_, __opts__):
        managing_port = WINDOWS_DS_PORT

    ssh_connect_timeout = config.get_cloud_config_value(
        'ssh_connect_timeout', vm_, __opts__, 15 * 60
    )
    connect_timeout = config.get_cloud_config_value(
        'connect_timeout', vm_, __opts__, ssh_connect_timeout
    )
    if not salt.utils.cloud.wait_for_port(ip_address,
                                          port=managing_port,
                                          timeout=connect_timeout):
        raise SaltCloudSystemExit(
            'Failed to authenticate against remote ssh'
        )

    pass_conn = get_conn(service='SoftLayer_Account')
    mask = {
        'virtualGuests': {
            'powerState': '',
            'operatingSystem': {
                'passwords': ''
            },
        },
    }

    def get_credentials():
        '''
        Wait for the password to become available
        '''
        node_info = pass_conn.getVirtualGuests(id=response['id'], mask=mask)
        for node in node_info:
            if node['id'] == response['id']:
                if 'passwords' in node['operatingSystem'] and len(node['operatingSystem']['passwords']) > 0:
                    return node['operatingSystem']['passwords'][0]['username'], node['operatingSystem']['passwords'][0]['password']
        time.sleep(5)
        return False

    username, passwd = salt.utils.cloud.wait_for_fun(  # pylint: disable=W0633
        get_credentials,
        timeout=config.get_cloud_config_value(
            'wait_for_fun_timeout', vm_, __opts__, default=15 * 60),
    )
    response['username'] = username
    response['password'] = passwd
    response['public_ip'] = ip_address

    ssh_username = config.get_cloud_config_value(
        'ssh_username', vm_, __opts__, default=username
    )

    vm_['ssh_host'] = ip_address
    vm_['password'] = passwd
    ret = salt.utils.cloud.bootstrap(vm_, __opts__)

    ret.update(response)

    salt.utils.cloud.fire_event(
        'event',
        'created instance',
        'salt/cloud/{0}/created'.format(vm_['name']),
        {
            'name': vm_['name'],
            'profile': vm_['profile'],
            'provider': vm_['driver'],
        },
        transport=__opts__['transport']
    )

    return ret
Ejemplo n.º 34
0
def create(vm_):
    """
    Create a single VM from a data dict

    CLI Example:

    .. code-block:: bash

        salt-cloud -p profile_name vm_name
    """
    try:
        # Check for required profile parameters before sending any API calls.
        if (vm_["profile"] and config.is_profile_configured(
                __opts__,
                __active_provider_name__ or "joyent",
                vm_["profile"],
                vm_=vm_) is False):
            return False
    except AttributeError:
        pass

    key_filename = config.get_cloud_config_value("private_key",
                                                 vm_,
                                                 __opts__,
                                                 search_global=False,
                                                 default=None)

    __utils__["cloud.fire_event"](
        "event",
        "starting create",
        "salt/cloud/{}/creating".format(vm_["name"]),
        args=__utils__["cloud.filter_event"](
            "creating", vm_, ["name", "profile", "provider", "driver"]),
        sock_dir=__opts__["sock_dir"],
        transport=__opts__["transport"],
    )

    log.info("Creating Cloud VM %s in %s", vm_["name"],
             vm_.get("location", DEFAULT_LOCATION))

    # added . for fqdn hostnames
    salt.utils.cloud.check_name(vm_["name"], "a-zA-Z0-9-.")
    kwargs = {
        "name": vm_["name"],
        "image": get_image(vm_),
        "size": get_size(vm_),
        "location": vm_.get("location", DEFAULT_LOCATION),
    }
    # Let's not assign a default here; only assign a network value if
    # one is explicitly configured
    if "networks" in vm_:
        kwargs["networks"] = vm_.get("networks")

    __utils__["cloud.fire_event"](
        "event",
        "requesting instance",
        "salt/cloud/{}/requesting".format(vm_["name"]),
        args={
            "kwargs":
            __utils__["cloud.filter_event"]("requesting", kwargs,
                                            list(kwargs)),
        },
        sock_dir=__opts__["sock_dir"],
        transport=__opts__["transport"],
    )

    data = create_node(**kwargs)
    if data == {}:
        log.error("Error creating %s on JOYENT", vm_["name"])
        return False

    query_instance(vm_)
    data = show_instance(vm_["name"], call="action")

    vm_["key_filename"] = key_filename
    vm_["ssh_host"] = data[1]["primaryIp"]

    __utils__["cloud.bootstrap"](vm_, __opts__)

    __utils__["cloud.fire_event"](
        "event",
        "created instance",
        "salt/cloud/{}/created".format(vm_["name"]),
        args=__utils__["cloud.filter_event"](
            "created", vm_, ["name", "profile", "provider", "driver"]),
        sock_dir=__opts__["sock_dir"],
        transport=__opts__["transport"],
    )

    return data[1]
Ejemplo n.º 35
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 'rackspace',
                                                           vm_['profile'],
                                                           vm_=vm_) is False:
            return False
    except AttributeError:
        pass

    # Since using "provider: <provider-engine>" is deprecated, alias provider
    # to use driver: "driver: <provider-engine>"
    if 'provider' in vm_:
        vm_['driver'] = vm_.pop('provider')

    __utils__['cloud.fire_event'](
        'event',
        'starting create',
        'salt/cloud/{0}/creating'.format(vm_['name']),
        args={
            'name': vm_['name'],
            'profile': vm_['profile'],
            'provider': vm_['driver'],
        },
        sock_dir=__opts__['sock_dir'],
        transport=__opts__['transport']
    )

    log.info('Creating Cloud VM {0}'.format(vm_['name']))
    conn = get_conn()
    kwargs = {
        'name': vm_['name'],
        'image': get_image(conn, vm_),
        'size': get_size(conn, vm_)
    }

    __utils__['cloud.fire_event'](
        'event',
        'requesting instance',
        'salt/cloud/{0}/requesting'.format(vm_['name']),
        args={
            'kwargs': {
                'name': kwargs['name'],
                'image': kwargs['image'].name,
                'size': kwargs['size'].name,
            }
        },
        sock_dir=__opts__['sock_dir'],
        transport=__opts__['transport']
    )

    try:
        data = conn.create_node(**kwargs)
    except Exception as exc:
        log.error(
            'Error creating {0} on RACKSPACE\n\n'
            'The following exception was thrown by libcloud when trying to '
            'run the initial deployment: \n{1}'.format(
                vm_['name'], exc
            ),
            # Show the traceback if the debug logging level is enabled
            exc_info_on_loglevel=logging.DEBUG
        )
        return False

    def __query_node_data(vm_, data):
        running = False
        try:
            node = show_instance(vm_['name'], 'action')
            running = (node['state'] == NodeState.RUNNING)
            log.debug(
                'Loaded node data for {0}:\nname: {1}\nstate: {2}'.format(
                    vm_['name'],
                    pprint.pformat(node['name']),
                    node['state']
                )
            )
        except Exception as err:
            log.error(
                'Failed to get nodes list: {0}'.format(
                    err
                ),
                # Show the traceback if the debug logging level is enabled
                exc_info_on_loglevel=logging.DEBUG
            )
            # Trigger a failure in the wait for IP function
            return False

        if not running:
            # Still not running, trigger another iteration
            return

        private = node['private_ips']
        public = node['public_ips']

        if private and not public:
            log.warning(
                'Private IPs returned, but not public... Checking for '
                'misidentified IPs'
            )
            for private_ip in private:
                private_ip = preferred_ip(vm_, [private_ip])
                if salt.utils.cloud.is_public_ip(private_ip):
                    log.warning('{0} is a public IP'.format(private_ip))
                    data.public_ips.append(private_ip)
                else:
                    log.warning('{0} is a private IP'.format(private_ip))
                    if private_ip not in data.private_ips:
                        data.private_ips.append(private_ip)

            if ssh_interface(vm_) == 'private_ips' and data.private_ips:
                return data

        if private:
            data.private_ips = private
            if ssh_interface(vm_) == 'private_ips':
                return data

        if public:
            data.public_ips = public
            if ssh_interface(vm_) != 'private_ips':
                return data

    try:
        data = salt.utils.cloud.wait_for_ip(
            __query_node_data,
            update_args=(vm_, data),
            timeout=config.get_cloud_config_value(
                'wait_for_ip_timeout', vm_, __opts__, default=25 * 60),
            interval=config.get_cloud_config_value(
                'wait_for_ip_interval', vm_, __opts__, default=10),
        )
    except (SaltCloudExecutionTimeout, SaltCloudExecutionFailure) as exc:
        try:
            # It might be already up, let's destroy it!
            destroy(vm_['name'])
        except SaltCloudSystemExit:
            pass
        finally:
            raise SaltCloudSystemExit(str(exc))

    log.debug('VM is now running')
    if ssh_interface(vm_) == 'private_ips':
        ip_address = preferred_ip(vm_, data.private_ips)
    else:
        ip_address = preferred_ip(vm_, data.public_ips)
    log.debug('Using IP address {0}'.format(ip_address))

    if salt.utils.cloud.get_salt_interface(vm_, __opts__) == 'private_ips':
        salt_ip_address = preferred_ip(vm_, data.private_ips)
        log.info('Salt interface set to: {0}'.format(salt_ip_address))
    else:
        salt_ip_address = preferred_ip(vm_, data.public_ips)
        log.debug('Salt interface set to: {0}'.format(salt_ip_address))

    if not ip_address:
        raise SaltCloudSystemExit(
            'No IP addresses could be found.'
        )

    vm_['salt_host'] = salt_ip_address
    vm_['ssh_host'] = ip_address
    vm_['password'] = data.extra['password']

    ret = __utils__['cloud.bootstrap'](vm_, __opts__)

    ret.update(data.__dict__)

    if 'password' in data.extra:
        del data.extra['password']

    log.info('Created Cloud VM \'{0[name]}\''.format(vm_))
    log.debug(
        '\'{0[name]}\' VM creation details:\n{1}'.format(
            vm_, pprint.pformat(data.__dict__)
        )
    )

    __utils__['cloud.fire_event'](
        'event',
        'created instance',
        'salt/cloud/{0}/created'.format(vm_['name']),
        args={
            'name': vm_['name'],
            'profile': vm_['profile'],
            'provider': vm_['driver'],
        },
        sock_dir=__opts__['sock_dir'],
        transport=__opts__['transport']
    )

    return ret
Ejemplo n.º 36
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'],
                vm_=vm_) is False:
            return False
    except AttributeError:
        pass

    __utils__['cloud.fire_event']('event',
                                  'starting create',
                                  'salt/cloud/{0}/creating'.format(
                                      vm_['name']), {
                                          'name': vm_['name'],
                                          'profile': vm_['profile'],
                                          'provider': vm_['driver'],
                                      },
                                  transport=__opts__['transport'])

    log.info('Creating Cloud VM {0}'.format(vm_['name']))
    conn = get_conn()
    kwargs = {
        'name': vm_['name'],
        'image': get_image(conn, vm_),
        'size': get_size(conn, vm_),
        'location': get_location(conn, vm_),
        'ex_security_groups': get_security_groups(conn, vm_)
    }

    if get_keypair(vm_) is not False:
        kwargs['ex_keyname'] = get_keypair(vm_)

    if get_networkid(vm_) is not False:
        kwargs['networkids'] = get_networkid(vm_)
        kwargs['networks'] = (  # The only attr that is used is 'id'.
            CloudStackNetwork(None, None, None, kwargs['networkids'], None,
                              None), )

    if get_project(conn, vm_) is not False:
        kwargs['project'] = get_project(conn, vm_)

    __utils__['cloud.fire_event']('event',
                                  'requesting instance',
                                  'salt/cloud/{0}/requesting'.format(
                                      vm_['name']), {
                                          'kwargs': {
                                              'name': kwargs['name'],
                                              'image': kwargs['image'].name,
                                              'size': kwargs['size'].name
                                          }
                                      },
                                  transport=__opts__['transport'])

    displayname = cloudstack_displayname(vm_)
    if displayname:
        kwargs['ex_displayname'] = displayname
    else:
        kwargs['ex_displayname'] = kwargs['name']

    volumes = {}
    ex_blockdevicemappings = block_device_mappings(vm_)
    if ex_blockdevicemappings:
        for ex_blockdevicemapping in ex_blockdevicemappings:
            if 'VirtualName' not in ex_blockdevicemapping:
                ex_blockdevicemapping['VirtualName'] = '{0}-{1}'.format(
                    vm_['name'], len(volumes))
            __utils__['cloud.fire_event'](
                'event',
                'requesting volume',
                'salt/cloud/{0}/requesting'.format(
                    ex_blockdevicemapping['VirtualName']),
                {
                    'kwargs': {
                        'name': ex_blockdevicemapping['VirtualName'],
                        'device': ex_blockdevicemapping['DeviceName'],
                        'size': ex_blockdevicemapping['VolumeSize']
                    }
                },
            )
            try:
                volumes[
                    ex_blockdevicemapping['DeviceName']] = conn.create_volume(
                        ex_blockdevicemapping['VolumeSize'],
                        ex_blockdevicemapping['VirtualName'])
            except Exception as exc:
                log.error(
                    'Error creating volume {0} on CLOUDSTACK\n\n'
                    'The following exception was thrown by libcloud when trying to '
                    'requesting a volume: \n{1}'.format(
                        ex_blockdevicemapping['VirtualName'], exc),
                    # Show the traceback if the debug logging level is enabled
                    exc_info_on_loglevel=logging.DEBUG)
                return False
    else:
        ex_blockdevicemapping = {}
    try:
        data = conn.create_node(**kwargs)
    except Exception as exc:
        log.error(
            'Error creating {0} on CLOUDSTACK\n\n'
            'The following exception was thrown by libcloud when trying to '
            'run the initial deployment: \n{1}'.format(vm_['name'], str(exc)),
            # Show the traceback if the debug logging level is enabled
            exc_info_on_loglevel=logging.DEBUG)
        return False

    for device_name in six.iterkeys(volumes):
        try:
            conn.attach_volume(data, volumes[device_name], device_name)
        except Exception as exc:
            log.error(
                'Error attaching volume {0} on CLOUDSTACK\n\n'
                'The following exception was thrown by libcloud when trying to '
                'attach a volume: \n{1}'.format(
                    ex_blockdevicemapping.get('VirtualName', 'UNKNOWN'), exc),
                # Show the traceback if the debug logging level is enabled
                exc_info=log.isEnabledFor(logging.DEBUG))
            return False

    ssh_username = config.get_cloud_config_value('ssh_username',
                                                 vm_,
                                                 __opts__,
                                                 default='root')

    vm_['ssh_host'] = get_ip(data)
    vm_['password'] = data.extra['password']
    vm_['key_filename'] = get_key()
    ret = __utils__['cloud.bootstrap'](vm_, __opts__)

    ret.update(data.__dict__)

    if 'password' in data.extra:
        del data.extra['password']

    log.info('Created Cloud VM \'{0[name]}\''.format(vm_))
    log.debug('\'{0[name]}\' VM creation details:\n{1}'.format(
        vm_, pprint.pformat(data.__dict__)))

    __utils__['cloud.fire_event']('event',
                                  'created instance',
                                  'salt/cloud/{0}/created'.format(vm_['name']),
                                  {
                                      'name': vm_['name'],
                                      'profile': vm_['profile'],
                                      'provider': vm_['driver'],
                                  },
                                  transport=__opts__['transport'])

    return ret
Ejemplo n.º 37
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

    # Since using "provider: <provider-engine>" is deprecated, alias provider
    # to use driver: "driver: <provider-engine>"
    if 'provider' in vm_:
        vm_['driver'] = vm_.pop('provider')

    salt.utils.cloud.fire_event(
        'event',
        'starting create',
        'salt/cloud/{0}/creating'.format(vm_['name']),
        {
            'name': vm_['name'],
            'profile': vm_['profile'],
            'provider': vm_['driver'],
        },
        transport=__opts__['transport']
    )

    log.info('Creating Cloud VM %s', vm_['name'])
    conn = get_conn()
    rootPw = NodeAuthPassword(vm_['auth'])

    try:
        location = conn.ex_get_location_by_id(vm_['location'])
        images = conn.list_images(location=location)
        image = [x for x in images if x.id == vm_['image']][0]
        networks = conn.ex_list_network_domains(location=location)
        network_domain = [y for y in networks if y.name ==
                          vm_['network_domain']][0]
        # Use the first VLAN in the network domain
        vlan = conn.ex_list_vlans(location=location,
                                  network_domain=network_domain)[0]
        kwargs = {
            'name': vm_['name'],
            'image': image,
            'auth': rootPw,
            'ex_description': vm_['description'],
            'ex_network_domain': network_domain,
            'ex_vlan': vlan,
            'ex_is_started': vm_['is_started']
        }
        data = conn.create_node(**kwargs)
    except Exception as exc:
        log.error(
            'Error creating %s on DIMENSIONDATA\n\n'
            'The following exception was thrown by libcloud when trying to '
            'run the initial deployment: \n%s',
            vm_['name'], exc,
            exc_info_on_loglevel=logging.DEBUG
        )
        return False

    def __query_node_data(vm_, data):
        running = False
        try:
            node = show_instance(vm_['name'], 'action')
            running = (node['state'] == NodeState.RUNNING)
            log.debug(
                'Loaded node data for %s:\nname: %s\nstate: %s',
                vm_['name'],
                pprint.pformat(node['name']),
                node['state']
                )
        except Exception as err:
            log.error(
                'Failed to get nodes list: %s', err,
                # Show the traceback if the debug logging level is enabled
                exc_info_on_loglevel=logging.DEBUG
            )
            # Trigger a failure in the wait for IP function
            return False

        if not running:
            # Still not running, trigger another iteration
            return

        private = node['private_ips']
        public = node['public_ips']

        if private and not public:
            log.warn(
                'Private IPs returned, but not public... Checking for '
                'misidentified IPs'
            )
            for private_ip in private:
                private_ip = preferred_ip(vm_, [private_ip])
                if salt.utils.cloud.is_public_ip(private_ip):
                    log.warn('%s is a public IP', private_ip)
                    data.public_ips.append(private_ip)
                else:
                    log.warn('%s is a private IP', private_ip)
                    if private_ip not in data.private_ips:
                        data.private_ips.append(private_ip)

            if ssh_interface(vm_) == 'private_ips' and data.private_ips:
                return data

        if private:
            data.private_ips = private
            if ssh_interface(vm_) == 'private_ips':
                return data

        if public:
            data.public_ips = public
            if ssh_interface(vm_) != 'private_ips':
                return data

        log.debug('DATA')
        log.debug(data)

    try:
        data = salt.utils.cloud.wait_for_ip(
            __query_node_data,
            update_args=(vm_, data),
            timeout=config.get_cloud_config_value(
                'wait_for_ip_timeout', vm_, __opts__, default=25 * 60),
            interval=config.get_cloud_config_value(
                'wait_for_ip_interval', vm_, __opts__, default=30),
            max_failures=config.get_cloud_config_value(
                'wait_for_ip_max_failures', vm_, __opts__, default=60),
        )
    except (SaltCloudExecutionTimeout, SaltCloudExecutionFailure) as exc:
        try:
            # It might be already up, let's destroy it!
            destroy(vm_['name'])
        except SaltCloudSystemExit:
            pass
        finally:
            raise SaltCloudSystemExit(str(exc))

    log.debug('VM is now running')
    if ssh_interface(vm_) == 'private_ips':
        ip_address = preferred_ip(vm_, data.private_ips)
    else:
        ip_address = preferred_ip(vm_, data.public_ips)
    log.debug('Using IP address %s', ip_address)

    if salt.utils.cloud.get_salt_interface(vm_, __opts__) == 'private_ips':
        salt_ip_address = preferred_ip(vm_, data.private_ips)
        log.info('Salt interface set to: %s', salt_ip_address)
    else:
        salt_ip_address = preferred_ip(vm_, data.public_ips)
        log.debug('Salt interface set to: %s', salt_ip_address)

    if not ip_address:
        raise SaltCloudSystemExit(
            'No IP addresses could be found.'
        )

    vm_['salt_host'] = salt_ip_address
    vm_['ssh_host'] = ip_address
    vm_['password'] = vm_['auth']

    ret = salt.utils.cloud.bootstrap(vm_, __opts__)

    ret.update(data.__dict__)

    if 'password' in data.extra:
        del data.extra['password']

    log.info('Created Cloud VM \'{0[name]}\''.format(vm_))
    log.debug(
        '\'{0[name]}\' VM creation details:\n{1}'.format(
            vm_, pprint.pformat(data.__dict__)
        )
    )

    salt.utils.cloud.fire_event(
        'event',
        'created instance',
        'salt/cloud/{0}/created'.format(vm_['name']),
        {
            'name': vm_['name'],
            'profile': vm_['profile'],
            'provider': vm_['driver'],
        },
        transport=__opts__['transport']
    )

    return ret
Ejemplo n.º 38
0
def create(vm_):
    '''
    Create a single VM from a data dict

    CLI Example:

    .. code-block:: bash

        salt-cloud -p profile_name vm_name
    '''
    try:
        # Check for required profile parameters before sending any API calls.
        if vm_['profile'] and config.is_profile_configured(__opts__,
                                                           __active_provider_name__ or 'joyent',
                                                           vm_['profile'],
                                                           vm_=vm_) is False:
            return False
    except AttributeError:
        pass

    key_filename = config.get_cloud_config_value(
        'private_key', vm_, __opts__, search_global=False, default=None
    )

    __utils__['cloud.fire_event'](
        'event',
        'starting create',
        'salt/cloud/{0}/creating'.format(vm_['name']),
        args=__utils__['cloud.filter_event']('creating', vm_, ['name', 'profile', 'provider', 'driver']),
        sock_dir=__opts__['sock_dir'],
        transport=__opts__['transport']
    )

    log.info(
        'Creating Cloud VM %s in %s',
        vm_['name'], vm_.get('location', DEFAULT_LOCATION)
    )

    # added . for fqdn hostnames
    salt.utils.cloud.check_name(vm_['name'], 'a-zA-Z0-9-.')
    kwargs = {
        'name': vm_['name'],
        'image': get_image(vm_),
        'size': get_size(vm_),
        'location': vm_.get('location', DEFAULT_LOCATION)
    }
    # Let's not assign a default here; only assign a network value if
    # one is explicitly configured
    if 'networks' in vm_:
        kwargs['networks'] = vm_.get('networks')

    __utils__['cloud.fire_event'](
        'event',
        'requesting instance',
        'salt/cloud/{0}/requesting'.format(vm_['name']),
        args={
            'kwargs': __utils__['cloud.filter_event']('requesting', kwargs, list(kwargs)),
        },
        sock_dir=__opts__['sock_dir'],
        transport=__opts__['transport']
    )

    data = create_node(**kwargs)
    if data == {}:
        log.error('Error creating %s on JOYENT', vm_['name'])
        return False

    query_instance(vm_)
    data = show_instance(vm_['name'], call='action')

    vm_['key_filename'] = key_filename
    vm_['ssh_host'] = data[1]['primaryIp']

    __utils__['cloud.bootstrap'](vm_, __opts__)

    __utils__['cloud.fire_event'](
        'event',
        'created instance',
        'salt/cloud/{0}/created'.format(vm_['name']),
        args=__utils__['cloud.filter_event']('created', vm_, ['name', 'profile', 'provider', 'driver']),
        sock_dir=__opts__['sock_dir'],
        transport=__opts__['transport']
    )

    return data[1]
Ejemplo n.º 39
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
Ejemplo n.º 40
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/{}/creating".format(vm_["name"]),
        args=__utils__["cloud.filter_event"](
            "creating", vm_, ["name", "profile", "provider", "driver"]),
        sock_dir=__opts__["sock_dir"],
        transport=__opts__["transport"],
    )

    log.info("Creating Cloud VM %s", vm_["name"])
    kwargs = {
        "name": vm_["name"],
        "size_id": get_size(vm_),
        "image_id": get_image(vm_),
        "region_id": __get_location(vm_),
        "securitygroup_id": get_securitygroup(vm_),
    }
    if "vswitch_id" in vm_:
        kwargs["VSwitchId"] = vm_["vswitch_id"]
    if "internet_chargetype" in vm_:
        kwargs["InternetChargeType"] = vm_["internet_chargetype"]
    if "internet_maxbandwidthin" in vm_:
        kwargs["InternetMaxBandwidthIn"] = str(vm_["internet_maxbandwidthin"])
    if "internet_maxbandwidthout" in vm_:
        kwargs["InternetMaxBandwidthOut"] = str(
            vm_["internet_maxbandwidthOut"])
    if "hostname" in vm_:
        kwargs["HostName"] = vm_["hostname"]
    if "password" in vm_:
        kwargs["Password"] = vm_["password"]
    if "instance_name" in vm_:
        kwargs["InstanceName"] = vm_["instance_name"]
    if "systemdisk_category" in vm_:
        kwargs["SystemDisk.Category"] = vm_["systemdisk_category"]

    __utils__["cloud.fire_event"](
        "event",
        "requesting instance",
        "salt/cloud/{}/requesting".format(vm_["name"]),
        args=__utils__["cloud.filter_event"]("requesting", kwargs,
                                             list(kwargs)),
        sock_dir=__opts__["sock_dir"],
        transport=__opts__["transport"],
    )

    try:
        ret = create_node(kwargs)
    except Exception as exc:  # pylint: disable=broad-except
        log.error(
            "Error creating %s on Aliyun ECS\n\n"
            "The following exception was thrown when trying to "
            "run the initial deployment: %s",
            vm_["name"],
            str(exc),
            # Show the traceback if the debug logging level is enabled
            exc_info_on_loglevel=logging.DEBUG,
        )
        return False
    # repair ip address error and start vm
    time.sleep(8)
    params = {"Action": "StartInstance", "InstanceId": ret}
    query(params)

    def __query_node_data(vm_name):
        data = show_instance(vm_name, call="action")
        if not data:
            # Trigger an error in the wait_for_ip function
            return False
        if data.get("PublicIpAddress", None) is not None:
            return data

    try:
        data = salt.utils.cloud.wait_for_ip(
            __query_node_data,
            update_args=(vm_["name"], ),
            timeout=config.get_cloud_config_value("wait_for_ip_timeout",
                                                  vm_,
                                                  __opts__,
                                                  default=10 * 60),
            interval=config.get_cloud_config_value("wait_for_ip_interval",
                                                   vm_,
                                                   __opts__,
                                                   default=10),
        )
    except (SaltCloudExecutionTimeout, SaltCloudExecutionFailure) as exc:
        try:
            # It might be already up, let's destroy it!
            destroy(vm_["name"])
        except SaltCloudSystemExit:
            pass
        finally:
            raise SaltCloudSystemExit(str(exc))

    if data["public_ips"]:
        ssh_ip = data["public_ips"][0]
    elif data["private_ips"]:
        ssh_ip = data["private_ips"][0]
    else:
        log.info("No available ip:cant connect to salt")
        return False
    log.debug("VM %s is now running", ssh_ip)
    vm_["ssh_host"] = ssh_ip

    # The instance is booted and accessible, let's Salt it!
    ret = __utils__["cloud.bootstrap"](vm_, __opts__)
    ret.update(data)

    log.info("Created Cloud VM '%s'", vm_["name"])
    log.debug("'%s' VM creation details:\n%s", vm_["name"],
              pprint.pformat(data))

    __utils__["cloud.fire_event"](
        "event",
        "created instance",
        "salt/cloud/{}/created".format(vm_["name"]),
        args=__utils__["cloud.filter_event"](
            "created", vm_, ["name", "profile", "provider", "driver"]),
        sock_dir=__opts__["sock_dir"],
        transport=__opts__["transport"],
    )

    return ret
Ejemplo n.º 41
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 'rackspace',
                                        vm_['profile']) is False:
            return False
    except AttributeError:
        pass

    deploy = config.get_cloud_config_value('deploy', vm_, __opts__)
    salt.utils.cloud.fire_event(
        'event',
        'starting create',
        'salt/cloud/{0}/creating'.format(vm_['name']),
        {
            'name': vm_['name'],
            'profile': vm_['profile'],
            'provider': vm_['provider'],
        },
        transport=__opts__['transport']
    )

    log.info('Creating Cloud VM {0}'.format(vm_['name']))
    conn = get_conn()
    kwargs = {
        'name': vm_['name'],
        'image': get_image(conn, vm_),
        'size': get_size(conn, vm_)
    }

    salt.utils.cloud.fire_event(
        'event',
        'requesting instance',
        'salt/cloud/{0}/requesting'.format(vm_['name']),
        {'kwargs': {'name': kwargs['name'],
                    'image': kwargs['image'].name,
                    'size': kwargs['size'].name}},
        transport=__opts__['transport']
    )

    try:
        data = conn.create_node(**kwargs)
    except Exception as exc:
        log.error(
            'Error creating {0} on RACKSPACE\n\n'
            'The following exception was thrown by libcloud when trying to '
            'run the initial deployment: \n{1}'.format(
                vm_['name'], exc
            ),
            # Show the traceback if the debug logging level is enabled
            exc_info_on_loglevel=logging.DEBUG
        )
        return False

    def __query_node_data(vm_, data):
        running = False
        try:
            node = show_instance(vm_['name'], 'action')
            running = (node['state'] == NodeState.RUNNING)
            log.debug(
                'Loaded node data for {0}:\nname: {1}\nstate: {2}'.format(
                    vm_['name'],
                    pprint.pformat(node['name']),
                    node['state']
                )
            )
        except Exception as err:
            log.error(
                'Failed to get nodes list: {0}'.format(
                    err
                ),
                # Show the traceback if the debug logging level is enabled
                exc_info_on_loglevel=logging.DEBUG
            )
            # Trigger a failure in the wait for IP function
            return False

        if not running:
            # Still not running, trigger another iteration
            return

        private = node['private_ips']
        public = node['public_ips']

        if private and not public:
            log.warn(
                'Private IPs returned, but not public... Checking for '
                'misidentified IPs'
            )
            for private_ip in private:
                private_ip = preferred_ip(vm_, [private_ip])
                if salt.utils.cloud.is_public_ip(private_ip):
                    log.warn('{0} is a public IP'.format(private_ip))
                    data.public_ips.append(private_ip)
                else:
                    log.warn('{0} is a private IP'.format(private_ip))
                    if private_ip not in data.private_ips:
                        data.private_ips.append(private_ip)

            if ssh_interface(vm_) == 'private_ips' and data.private_ips:
                return data

        if private:
            data.private_ips = private
            if ssh_interface(vm_) == 'private_ips':
                return data

        if public:
            data.public_ips = public
            if ssh_interface(vm_) != 'private_ips':
                return data

    try:
        data = salt.utils.cloud.wait_for_ip(
            __query_node_data,
            update_args=(vm_, data),
            timeout=config.get_cloud_config_value(
                'wait_for_ip_timeout', vm_, __opts__, default=25 * 60),
            interval=config.get_cloud_config_value(
                'wait_for_ip_interval', vm_, __opts__, default=10),
        )
    except (SaltCloudExecutionTimeout, SaltCloudExecutionFailure) as exc:
        try:
            # It might be already up, let's destroy it!
            destroy(vm_['name'])
        except SaltCloudSystemExit:
            pass
        finally:
            raise SaltCloudSystemExit(str(exc))

    log.debug('VM is now running')
    if ssh_interface(vm_) == 'private_ips':
        ip_address = preferred_ip(vm_, data.private_ips)
    else:
        ip_address = preferred_ip(vm_, data.public_ips)
    log.debug('Using IP address {0}'.format(ip_address))

    if salt.utils.cloud.get_salt_interface(vm_, __opts__) == 'private_ips':
        salt_ip_address = preferred_ip(vm_, data.private_ips)
        log.info('Salt interface set to: {0}'.format(salt_ip_address))
    else:
        salt_ip_address = preferred_ip(vm_, data.public_ips)
        log.debug('Salt interface set to: {0}'.format(salt_ip_address))

    if not ip_address:
        raise SaltCloudSystemExit(
            'No IP addresses could be found.'
        )

    ssh_username = config.get_cloud_config_value(
        'ssh_username', vm_, __opts__, default='root'
    )

    ret = {}
    if deploy is True:
        deploy_script = script(vm_)
        deploy_kwargs = {
            'opts': __opts__,
            'host': ip_address,
            'salt_host': salt_ip_address,
            'username': ssh_username,
            'password': data.extra['password'],
            'script': deploy_script.script,
            'name': vm_['name'],
            'tmp_dir': config.get_cloud_config_value(
                'tmp_dir', vm_, __opts__, default='/tmp/.saltcloud'
            ),
            'deploy_command': config.get_cloud_config_value(
                'deploy_command', vm_, __opts__,
                default='/tmp/.saltcloud/deploy.sh',
            ),
            'start_action': __opts__['start_action'],
            'parallel': __opts__['parallel'],
            'sock_dir': __opts__['sock_dir'],
            'conf_file': __opts__['conf_file'],
            'minion_pem': vm_['priv_key'],
            'minion_pub': vm_['pub_key'],
            'keep_tmp': __opts__['keep_tmp'],
            'preseed_minion_keys': vm_.get('preseed_minion_keys', None),
            'sudo': config.get_cloud_config_value(
                'sudo', vm_, __opts__, default=(ssh_username != 'root')
            ),
            'sudo_password': config.get_cloud_config_value(
                'sudo_password', vm_, __opts__, default=None
            ),
            'tty': config.get_cloud_config_value(
                'tty', vm_, __opts__, default=False
            ),
            'display_ssh_output': config.get_cloud_config_value(
                'display_ssh_output', vm_, __opts__, default=True
            ),
            'script_args': config.get_cloud_config_value(
                'script_args', vm_, __opts__
            ),
            'script_env': config.get_cloud_config_value('script_env', vm_, __opts__),
            'minion_conf': salt.utils.cloud.minion_config(__opts__, vm_)
        }

        # Deploy salt-master files, if necessary
        if config.get_cloud_config_value('make_master', vm_, __opts__) is True:
            deploy_kwargs['make_master'] = True
            deploy_kwargs['master_pub'] = vm_['master_pub']
            deploy_kwargs['master_pem'] = vm_['master_pem']
            master_conf = salt.utils.cloud.master_config(__opts__, vm_)
            deploy_kwargs['master_conf'] = master_conf

            if master_conf.get('syndic_master', None):
                deploy_kwargs['make_syndic'] = True

        deploy_kwargs['make_minion'] = config.get_cloud_config_value(
            'make_minion', vm_, __opts__, default=True
        )

        # Check for Windows install params
        win_installer = config.get_cloud_config_value('win_installer', vm_, __opts__)
        if win_installer:
            deploy_kwargs['win_installer'] = win_installer
            minion = salt.utils.cloud.minion_config(__opts__, vm_)
            deploy_kwargs['master'] = minion['master']
            deploy_kwargs['username'] = config.get_cloud_config_value(
                'win_username', vm_, __opts__, default='Administrator'
            )
            win_pass = config.get_cloud_config_value(
                'win_password', vm_, __opts__, default=''
            )
            if win_pass:
                deploy_kwargs['password'] = win_pass

        # Store what was used to the deploy the VM
        event_kwargs = copy.deepcopy(deploy_kwargs)
        del event_kwargs['minion_pem']
        del event_kwargs['minion_pub']
        del event_kwargs['sudo_password']
        if 'password' in event_kwargs:
            del event_kwargs['password']
        ret['deploy_kwargs'] = event_kwargs

        salt.utils.cloud.fire_event(
            'event',
            'executing deploy script',
            'salt/cloud/{0}/deploying'.format(vm_['name']),
            {'kwargs': event_kwargs},
            transport=__opts__['transport']
        )

        if win_installer:
            deployed = salt.utils.cloud.deploy_windows(**deploy_kwargs)
        else:
            deployed = salt.utils.cloud.deploy_script(**deploy_kwargs)

        if deployed:
            log.info('Salt installed on {0}'.format(vm_['name']))
        else:
            log.error(
                'Failed to deploy and start Salt on Cloud VM {0}'.format(
                    vm_['name']
                )
            )

    ret.update(data.__dict__)

    if 'password' in data.extra:
        del data.extra['password']

    log.info('Created Cloud VM {0[name]!r}'.format(vm_))
    log.debug(
        '{0[name]!r} VM creation details:\n{1}'.format(
            vm_, pprint.pformat(data.__dict__)
        )
    )

    salt.utils.cloud.fire_event(
        'event',
        'created instance',
        'salt/cloud/{0}/created'.format(vm_['name']),
        {
            'name': vm_['name'],
            'profile': vm_['profile'],
            'provider': vm_['provider'],
        },
        transport=__opts__['transport']
    )

    return ret
Ejemplo n.º 42
0
Archivo: nova.py Proyecto: mahak/salt
def create(vm_):
    '''
    Create a single VM from a data dict
    '''
    try:
        # Check for required profile parameters before sending any API calls.
        if vm_['profile'] and config.is_profile_configured(__opts__,
                                                           __active_provider_name__ or 'nova',
                                                           vm_['profile']) is False:
            return False
    except AttributeError:
        pass

    deploy = config.get_cloud_config_value('deploy', vm_, __opts__)
    key_filename = config.get_cloud_config_value(
        'ssh_key_file', vm_, __opts__, search_global=False, default=None
    )
    if key_filename is not None and not os.path.isfile(key_filename):
        raise SaltCloudConfigError(
            'The defined ssh_key_file \'{0}\' does not exist'.format(
                key_filename
            )
        )

    vm_['key_filename'] = key_filename

    # Since using "provider: <provider-engine>" is deprecated, alias provider
    # to use driver: "driver: <provider-engine>"
    if 'provider' in vm_:
        vm_['driver'] = vm_.pop('provider')

    salt.utils.cloud.fire_event(
        'event',
        'starting create',
        'salt/cloud/{0}/creating'.format(vm_['name']),
        {
            'name': vm_['name'],
            'profile': vm_['profile'],
            'provider': vm_['driver'],
        },
        transport=__opts__['transport']
    )
    conn = get_conn()

    if 'instance_id' in vm_:
        # This was probably created via another process, and doesn't have
        # things like salt keys created yet, so let's create them now.
        if 'pub_key' not in vm_ and 'priv_key' not in vm_:
            log.debug('Generating minion keys for \'{0[name]}\''.format(vm_))
            vm_['priv_key'], vm_['pub_key'] = salt.utils.cloud.gen_keys(
                salt.config.get_cloud_config_value(
                    'keysize',
                    vm_,
                    __opts__
                )
            )
        data = conn.server_show_libcloud(vm_['instance_id'])
        if vm_['key_filename'] is None and 'change_password' in __opts__ and __opts__['change_password'] is True:
            vm_['password'] = sup.secure_password()
            conn.root_password(vm_['instance_id'], vm_['password'])
    else:
        # Put together all of the information required to request the instance,
        # and then fire off the request for it
        data, vm_ = request_instance(vm_)

        # Pull the instance ID, valid for both spot and normal instances
        vm_['instance_id'] = data.id

    def __query_node_data(vm_, data):
        try:
            node = show_instance(vm_['name'], 'action')
            log.debug(
                'Loaded node data for {0}:\n{1}'.format(
                    vm_['name'],
                    pprint.pformat(node)
                )
            )
        except Exception as err:
            log.error(
                'Failed to get nodes list: {0}'.format(
                    err
                ),
                # Show the traceback if the debug logging level is enabled
                exc_info_on_loglevel=logging.DEBUG
            )
            # Trigger a failure in the wait for IP function
            return False

        running = node['state'] == 'ACTIVE'
        if not running:
            # Still not running, trigger another iteration
            return

        rackconnectv3 = config.get_cloud_config_value(
            'rackconnectv3', vm_, __opts__, default=False,
            search_global=False
        )

        if rackconnectv3:
            networkname = rackconnectv3
            for network in node['addresses'].get(networkname, []):
                if network['version'] is 4:
                    access_ip = network['addr']
                    break
            vm_['rackconnect'] = True

        if ssh_interface(vm_) in node['addresses']:
            networkname = ssh_interface(vm_)
            for network in node['addresses'].get(networkname, []):
                if network['version'] is 4:
                    node['extra']['access_ip'] = network['addr']
                    break
            vm_['cloudnetwork'] = True

        if rackconnect(vm_) is True:
            extra = node.get('extra', {})
            rc_status = extra.get('metadata', {}).get(
                'rackconnect_automation_status', '')
            access_ip = extra.get('access_ip', '')

            if rc_status != 'DEPLOYED' and not rackconnectv3:
                log.debug('Waiting for Rackconnect automation to complete')
                return

        if managedcloud(vm_) is True:
            extra = conn.server_show_libcloud(
                node['id']
            ).extra
            mc_status = extra.get('metadata', {}).get(
                'rax_service_level_automation', '')

            if mc_status != 'Complete':
                log.debug('Waiting for managed cloud automation to complete')
                return

        result = []

        if 'private_ips' not in node and 'public_ips' not in node and \
           'access_ip' in node.get('extra', {}):
            result = [node['extra']['access_ip']]

        private = node.get('private_ips', [])
        public = node.get('public_ips', [])
        if private and not public:
            log.warn(
                'Private IPs returned, but not public... Checking for '
                'misidentified IPs'
            )
            for private_ip in private:
                private_ip = preferred_ip(vm_, [private_ip])
                if salt.utils.cloud.is_public_ip(private_ip):
                    log.warn('{0} is a public IP'.format(private_ip))
                    data.public_ips.append(private_ip)
                    log.warn(
                        (
                            'Public IP address was not ready when we last'
                            ' checked.  Appending public IP address now.'
                        )
                    )
                    public = data.public_ips
                else:
                    log.warn('{0} is a private IP'.format(private_ip))
                    ignore_ip = ignore_cidr(vm_, private_ip)
                    if private_ip not in data.private_ips and not ignore_ip:
                        result.append(private_ip)

        if rackconnect(vm_) is True and (ssh_interface(vm_) != 'private_ips' or rackconnectv3):
            data.public_ips = access_ip
            return data

        # populate return data with private_ips
        # when ssh_interface is set to private_ips and public_ips exist
        if not result and ssh_interface(vm_) == 'private_ips':
            for private_ip in private:
                ignore_ip = ignore_cidr(vm_, private_ip)
                if private_ip not in data.private_ips and not ignore_ip:
                    result.append(private_ip)

        if cloudnetwork(vm_) is True:
            data.public_ips = access_ip
            return data

        if public:
            data.public_ips = public
            if ssh_interface(vm_) != 'private_ips':
                return data

        if result:
            log.debug('result = {0}'.format(result))
            data.private_ips = result
            if ssh_interface(vm_) == 'private_ips':
                return data

    try:
        data = salt.utils.cloud.wait_for_ip(
            __query_node_data,
            update_args=(vm_, data),
            timeout=config.get_cloud_config_value(
                'wait_for_ip_timeout', vm_, __opts__, default=10 * 60),
            interval=config.get_cloud_config_value(
                'wait_for_ip_interval', vm_, __opts__, default=10),
        )
    except (SaltCloudExecutionTimeout, SaltCloudExecutionFailure) as exc:
        try:
            # It might be already up, let's destroy it!
            destroy(vm_['name'])
        except SaltCloudSystemExit:
            pass
        finally:
            raise SaltCloudSystemExit(str(exc))

    log.debug('VM is now running')

    if ssh_interface(vm_) == 'private_ips':
        ip_address = preferred_ip(vm_, data.private_ips)
    elif rackconnect(vm_) is True and ssh_interface(vm_) != 'private_ips':
        ip_address = data.public_ips
    else:
        ip_address = preferred_ip(vm_, data.public_ips)
    log.debug('Using IP address {0}'.format(ip_address))

    if salt.utils.cloud.get_salt_interface(vm_, __opts__) == 'private_ips':
        salt_ip_address = preferred_ip(vm_, data.private_ips)
        log.info('Salt interface set to: {0}'.format(salt_ip_address))
    elif rackconnect(vm_) is True and salt.utils.cloud.get_salt_interface(vm_, __opts__) != 'private_ips':
        salt_ip_address = data.public_ips
    else:
        salt_ip_address = preferred_ip(vm_, data.public_ips)
        log.debug('Salt interface set to: {0}'.format(salt_ip_address))

    if not ip_address:
        raise SaltCloudSystemExit('A valid IP address was not found')

    vm_['ssh_host'] = ip_address
    vm_['salt_host'] = salt_ip_address

    ret = salt.utils.cloud.bootstrap(vm_, __opts__)

    ret.update(data.__dict__)

    if 'password' in ret['extra']:
        del ret['extra']['password']

    log.info('Created Cloud VM \'{0[name]}\''.format(vm_))
    log.debug(
        '\'{0[name]}\' VM creation details:\n{1}'.format(
            vm_, pprint.pformat(data)
        )
    )

    salt.utils.cloud.fire_event(
        'event',
        'created instance',
        'salt/cloud/{0}/created'.format(vm_['name']),
        {
            'name': vm_['name'],
            'profile': vm_['profile'],
            'provider': vm_['driver'],
        },
        transport=__opts__['transport']
    )

    return ret
Ejemplo n.º 43
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 'gogrid',
                                                           vm_['profile'],
                                                           vm_=vm_) is False:
            return False
    except AttributeError:
        pass

    # Since using "provider: <provider-engine>" is deprecated, alias provider
    # to use driver: "driver: <provider-engine>"
    if 'provider' in vm_:
        vm_['driver'] = vm_.pop('provider')

    __utils__['cloud.fire_event'](
        'event',
        'starting create',
        'salt/cloud/{0}/creating'.format(vm_['name']),
        args={
            'name': vm_['name'],
            'profile': vm_['profile'],
            'provider': vm_['driver'],
        },
        sock_dir=__opts__['sock_dir'],
        transport=__opts__['transport']
    )

    if len(vm_['name']) > 20:
        raise SaltCloudException('VM names must not be longer than 20 characters')

    log.info('Creating Cloud VM {0}'.format(vm_['name']))
    image_id = avail_images()[vm_['image']]['id']
    if 'assign_public_ip' in vm_:
        host_ip = vm_['assign_public_ip']
    else:
        public_ips = list_public_ips()
        if len(public_ips.keys()) < 1:
            raise SaltCloudException('No more IPs available')
        host_ip = public_ips.keys()[0]

    create_kwargs = {
        'name': vm_['name'],
        'image': image_id,
        'ram': vm_['size'],
        'ip': host_ip,
    }

    __utils__['cloud.fire_event'](
        'event',
        'requesting instance',
        'salt/cloud/{0}/requesting'.format(vm_['name']),
        args={'kwargs': create_kwargs},
        sock_dir=__opts__['sock_dir'],
        transport=__opts__['transport']
    )

    try:
        data = _query('grid', 'server/add', args=create_kwargs)
    except Exception:
        log.error(
            'Error creating {0} on GOGRID\n\n'
            'The following exception was thrown when trying to '
            'run the initial deployment:\n'.format(
                vm_['name']
            ),
            # Show the traceback if the debug logging level is enabled
            exc_info_on_loglevel=logging.DEBUG
        )
        return False

    ssh_username = config.get_cloud_config_value(
        'ssh_username', vm_, __opts__, default='root'
    )

    def wait_for_apipass():
        '''
        Wait for the password to become available, via the API
        '''
        try:
            passwords = list_passwords()
            return passwords[vm_['name']][0]['password']
        except KeyError:
            pass
        time.sleep(5)
        return False

    vm_['password'] = salt.utils.cloud.wait_for_fun(
        wait_for_apipass,
        timeout=config.get_cloud_config_value(
            'wait_for_fun_timeout', vm_, __opts__, default=15 * 60),
    )

    vm_['ssh_host'] = host_ip
    ret = __utils__['cloud.bootstrap'](vm_, __opts__)
    ret.update(data)

    log.info('Created Cloud VM \'{0[name]}\''.format(vm_))
    log.debug(
        '\'{0[name]}\' VM creation details:\n{1}'.format(
            vm_, pprint.pformat(data)
        )
    )

    __utils__['cloud.fire_event'](
        'event',
        'created instance',
        'salt/cloud/{0}/created'.format(vm_['name']),
        args={
            'name': vm_['name'],
            'profile': vm_['profile'],
            'provider': vm_['driver'],
        },
        sock_dir=__opts__['sock_dir'],
        transport=__opts__['transport']
    )

    return ret
Ejemplo n.º 44
0
def create(vm_):
    '''
    Create a single Linode VM.
    '''
    name = vm_['name']
    try:
        # Check for required profile parameters before sending any API calls.
        if vm_['profile'] and config.is_profile_configured(
                __opts__,
                __active_provider_name__ or 'linode',
                vm_['profile'],
                vm_=vm_) is False:
            return False
    except AttributeError:
        pass

    # Since using "provider: <provider-engine>" is deprecated, alias provider
    # to use driver: "driver: <provider-engine>"
    if 'provider' in vm_:
        vm_['driver'] = vm_.pop('provider')

    if _validate_name(name) is False:
        return False

    __utils__['cloud.fire_event']('event',
                                  'starting create',
                                  'salt/cloud/{0}/creating'.format(name),
                                  args={
                                      'name': name,
                                      'profile': vm_['profile'],
                                      'provider': vm_['driver'],
                                  },
                                  sock_dir=__opts__['sock_dir'],
                                  transport=__opts__['transport'])

    log.info('Creating Cloud VM {0}'.format(name))

    data = {}
    kwargs = {'name': name}

    plan_id = None
    size = vm_.get('size')
    if size:
        kwargs['size'] = size
        plan_id = get_plan_id(kwargs={'label': size})

    datacenter_id = None
    location = vm_.get('location')
    if location:
        try:
            datacenter_id = get_datacenter_id(location)
        except KeyError:
            # Linode's default datacenter is Dallas, but we still have to set one to
            # use the create function from Linode's API. Dallas's datacenter id is 2.
            datacenter_id = 2

    clonefrom_name = vm_.get('clonefrom')
    cloning = True if clonefrom_name else False
    if cloning:
        linode_id = get_linode_id_from_name(clonefrom_name)
        clone_source = get_linode(kwargs={'linode_id': linode_id})

        kwargs = {
            'clonefrom': clonefrom_name,
            'image': 'Clone of {0}'.format(clonefrom_name),
        }

        if size is None:
            size = clone_source['TOTALRAM']
            kwargs['size'] = size
            plan_id = clone_source['PLANID']

        if location is None:
            datacenter_id = clone_source['DATACENTERID']

        # Create new Linode from cloned Linode
        try:
            result = clone(
                kwargs={
                    'linode_id': linode_id,
                    'datacenter_id': datacenter_id,
                    'plan_id': plan_id
                })
        except Exception as err:
            log.error(
                'Error cloning \'{0}\' on Linode.\n\n'
                'The following exception was thrown by Linode when trying to '
                'clone the specified machine:\n'
                '{1}'.format(clonefrom_name, err),
                exc_info_on_loglevel=logging.DEBUG)
            return False
    else:
        kwargs['image'] = vm_['image']

        # Create Linode
        try:
            result = _query('linode',
                            'create',
                            args={
                                'PLANID': plan_id,
                                'DATACENTERID': datacenter_id
                            })
        except Exception as err:
            log.error(
                'Error creating {0} on Linode\n\n'
                'The following exception was thrown by Linode when trying to '
                'run the initial deployment:\n'
                '{1}'.format(name, err),
                exc_info_on_loglevel=logging.DEBUG)
            return False

    if 'ERRORARRAY' in result:
        for error_data in result['ERRORARRAY']:
            log.error('Error creating {0} on Linode\n\n'
                      'The Linode API returned the following: {1}\n'.format(
                          name, error_data['ERRORMESSAGE']))
            return False

    __utils__['cloud.fire_event']('event',
                                  'requesting instance',
                                  'salt/cloud/{0}/requesting'.format(name),
                                  args={
                                      'kwargs': kwargs
                                  },
                                  sock_dir=__opts__['sock_dir'],
                                  transport=__opts__['transport'])
    node_id = _clean_data(result)['LinodeID']
    data['id'] = node_id

    if not _wait_for_status(node_id,
                            status=(_get_status_id_by_name('brand_new'))):
        log.error('Error creating {0} on LINODE\n\n'
                  'while waiting for initial ready status'.format(name),
                  exc_info_on_loglevel=logging.DEBUG)

    # Update the Linode's Label to reflect the given VM name
    update_linode(node_id, update_args={'Label': name})
    log.debug('Set name for {0} - was linode{1}.'.format(name, node_id))

    # Add private IP address if requested
    private_ip_assignment = get_private_ip(vm_)
    if private_ip_assignment:
        create_private_ip(node_id)

    # Define which ssh_interface to use
    ssh_interface = _get_ssh_interface(vm_)

    # If ssh_interface is set to use private_ips, but assign_private_ip
    # wasn't set to True, let's help out and create a private ip.
    if ssh_interface == 'private_ips' and private_ip_assignment is False:
        create_private_ip(node_id)
        private_ip_assignment = True

    if cloning:
        config_id = get_config_id(kwargs={'linode_id': node_id})['config_id']
    else:
        # Create disks and get ids
        log.debug('Creating disks for {0}'.format(name))
        root_disk_id = create_disk_from_distro(vm_, node_id)['DiskID']
        swap_disk_id = create_swap_disk(vm_, node_id)['DiskID']

        # Create a ConfigID using disk ids
        config_id = create_config(
            kwargs={
                'name': name,
                'linode_id': node_id,
                'root_disk_id': root_disk_id,
                'swap_disk_id': swap_disk_id
            })['ConfigID']

    # Boot the Linode
    boot(kwargs={
        'linode_id': node_id,
        'config_id': config_id,
        'check_running': False
    })

    node_data = get_linode(kwargs={'linode_id': node_id})
    ips = get_ips(node_id)
    state = int(node_data['STATUS'])

    data['image'] = kwargs['image']
    data['name'] = name
    data['size'] = size
    data['state'] = _get_status_descr_by_id(state)
    data['private_ips'] = ips['private_ips']
    data['public_ips'] = ips['public_ips']

    # Pass the correct IP address to the bootstrap ssh_host key
    if ssh_interface == 'private_ips':
        vm_['ssh_host'] = data['private_ips'][0]
    else:
        vm_['ssh_host'] = data['public_ips'][0]

    # If a password wasn't supplied in the profile or provider config, set it now.
    vm_['password'] = get_password(vm_)

    # Bootstrap!
    ret = __utils__['cloud.bootstrap'](vm_, __opts__)

    ret.update(data)

    log.info('Created Cloud VM \'{0}\''.format(name))
    log.debug('\'{0}\' VM creation details:\n{1}'.format(
        name, pprint.pformat(data)))

    __utils__['cloud.fire_event']('event',
                                  'created instance',
                                  'salt/cloud/{0}/created'.format(name),
                                  args={
                                      'name': name,
                                      'profile': vm_['profile'],
                                      'provider': vm_['driver'],
                                  },
                                  sock_dir=__opts__['sock_dir'],
                                  transport=__opts__['transport'])

    return ret
Ejemplo n.º 45
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.

    Fires:
        "starting create" : This event is tagged salt/cloud/<vm name>/creating.
        The payload contains the names of the VM, profile and provider.

    @param vm_info
            {
                name: <str>
                profile: <dict>
                driver: <provider>:<profile>
                clonefrom: <vm_name>
            }
    @type vm_info dict
    @return dict of resulting vm. !!!Passwords can and should be included!!!
    """
    try:
        # Check for required profile parameters before sending any API calls.
        if vm_info['profile'] and config.is_profile_configured(
            __opts__,
                __active_provider_name__ or 'virtualbox',
            vm_info['profile']
        ) is False:
            return False
    except AttributeError:
        pass

    vm_name = vm_info["name"]
    deploy = config.get_cloud_config_value(
        'deploy', vm_info, __opts__, search_global=False, default=True
    )
    wait_for_ip_timeout = config.get_cloud_config_value(
        'wait_for_ip_timeout', vm_info, __opts__, default=60
    )
    boot_timeout = config.get_cloud_config_value(
        'boot_timeout', vm_info, __opts__, default=60 * 1000
    )
    power = config.get_cloud_config_value(
        'power_on', vm_info, __opts__, default=False
    )
    key_filename = config.get_cloud_config_value(
        'private_key', vm_info, __opts__, search_global=False, default=None
    )

    log.debug("Going to fire event: starting create")
    cloud.fire_event(
        'event',
        'starting create',
        'salt/cloud/{0}/creating'.format(vm_info['name']),
        args={
            'name': vm_info['name'],
            'profile': vm_info['profile'],
            'driver': vm_info['driver'],
        },
        sock_dir=__opts__['sock_dir'],
        transport=__opts__['transport']
    )

    # to create the virtual machine.
    request_kwargs = {
        'name': vm_info['name'],
        'clone_from': vm_info['clonefrom']
    }

    cloud.fire_event(
        'event',
        'requesting instance',
        'salt/cloud/{0}/requesting'.format(vm_info['name']),
        args=request_kwargs,
        sock_dir=__opts__['sock_dir'],
        transport=__opts__['transport']
    )
    vm_result = vb_clone_vm(**request_kwargs)

    # Booting and deploying if needed
    if power:
        vb_start_vm(vm_name, timeout=boot_timeout)
        ips = vb_wait_for_network_address(wait_for_ip_timeout, machine_name=vm_name)

        if len(ips):
            ip = ips[0]
            log.info("[ {0} ] IPv4 is: {1}".format(vm_name, ip))
            # ssh or smb using ip and install salt only if deploy is True
            if deploy:
                vm_info['key_filename'] = key_filename
                vm_info['ssh_host'] = ip

                res = cloud.bootstrap(vm_info, __opts__)
                vm_result.update(res)

    cloud.fire_event(
        'event',
        'created machine',
        'salt/cloud/{0}/created'.format(vm_info['name']),
        args=vm_result,
        sock_dir=__opts__['sock_dir'],
        transport=__opts__['transport']
    )

    # Passwords should be included in this object!!
    return vm_result
Ejemplo n.º 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 (vm_["profile"] and config.is_profile_configured(
                __opts__,
                __active_provider_name__ or "parallels",
                vm_["profile"],
                vm_=vm_,
        ) is False):
            return False
    except AttributeError:
        pass

    __utils__["cloud.fire_event"](
        "event",
        "starting create",
        "salt/cloud/{}/creating".format(vm_["name"]),
        args=__utils__["cloud.filter_event"](
            "creating", vm_, ["name", "profile", "provider", "driver"]),
        sock_dir=__opts__["sock_dir"],
        transport=__opts__["transport"],
    )

    log.info("Creating Cloud VM %s", vm_["name"])

    try:
        data = create_node(vm_)
    except Exception as exc:  # pylint: disable=broad-except
        log.error(
            "Error creating %s on PARALLELS\n\n"
            "The following exception was thrown when trying to "
            "run the initial deployment: \n%s",
            vm_["name"],
            exc,
            # Show the traceback if the debug logging level is enabled
            exc_info_on_loglevel=logging.DEBUG,
        )
        return False

    name = vm_["name"]
    if not wait_until(name, "CREATED"):
        return {"Error": "Unable to start {}, command timed out".format(name)}
    start(vm_["name"], call="action")

    if not wait_until(name, "STARTED"):
        return {"Error": "Unable to start {}, command timed out".format(name)}

    def __query_node_data(vm_name):
        data = show_instance(vm_name, call="action")
        if "public-ip" not in data["network"]:
            # Trigger another iteration
            return
        return data

    try:
        data = salt.utils.cloud.wait_for_ip(
            __query_node_data,
            update_args=(vm_["name"], ),
            timeout=config.get_cloud_config_value("wait_for_ip_timeout",
                                                  vm_,
                                                  __opts__,
                                                  default=5 * 60),
            interval=config.get_cloud_config_value("wait_for_ip_interval",
                                                   vm_,
                                                   __opts__,
                                                   default=5),
        )
    except (SaltCloudExecutionTimeout, SaltCloudExecutionFailure) as exc:
        try:
            # It might be already up, let's destroy it!
            destroy(vm_["name"])
        except SaltCloudSystemExit:
            pass
        finally:
            raise SaltCloudSystemExit(str(exc))

    comps = data["network"]["public-ip"]["address"].split("/")
    public_ip = comps[0]

    vm_["ssh_host"] = public_ip
    ret = __utils__["cloud.bootstrap"](vm_, __opts__)

    log.info("Created Cloud VM '%s'", vm_["name"])
    log.debug("'%s' VM creation details:\n%s", vm_["name"],
              pprint.pformat(data))

    __utils__["cloud.fire_event"](
        "event",
        "created instance",
        "salt/cloud/{}/created".format(vm_["name"]),
        args=__utils__["cloud.filter_event"](
            "created", vm_, ["name", "profile", "provider", "driver"]),
        sock_dir=__opts__["sock_dir"],
        transport=__opts__["transport"],
    )

    return data
Ejemplo n.º 47
0
def create(vm_):
    """
    Create a single instance from a data dict.

    CLI Examples:

    .. code-block:: bash

        salt-cloud -p qingcloud-ubuntu-c1m1 hostname1
        salt-cloud -m /path/to/mymap.sls -P
    """
    try:
        # Check for required profile parameters before sending any API calls.
        if config.is_profile_configured(__opts__, __active_provider_name__ or "qingcloud", vm_["profile"]) is False:
            return False
    except AttributeError:
        pass

    # Since using "provider: <provider-engine>" is deprecated, alias provider
    # to use driver: "driver: <provider-engine>"
    if "provider" in vm_:
        vm_["driver"] = vm_.pop("provider")

    salt.utils.cloud.fire_event(
        "event",
        "starting create",
        "salt/cloud/{0}/creating".format(vm_["name"]),
        {"name": vm_["name"], "profile": vm_["profile"], "provider": vm_["driver"]},
        transport=__opts__["transport"],
    )

    log.info("Creating Cloud VM {0}".format(vm_["name"]))

    # params
    params = {
        "action": "RunInstances",
        "instance_name": vm_["name"],
        "zone": _get_location(vm_),
        "instance_type": _get_size(vm_),
        "image_id": _get_image(vm_),
        "vxnets.1": vm_["vxnets"],
        "login_mode": vm_["login_mode"],
        "login_keypair": vm_["login_keypair"],
    }

    salt.utils.cloud.fire_event(
        "event",
        "requesting instance",
        "salt/cloud/{0}/requesting".format(vm_["name"]),
        {"kwargs": params},
        transport=__opts__["transport"],
    )

    result = query(params)
    new_instance_id = result["instances"][0]

    try:
        data = salt.utils.cloud.wait_for_ip(
            _query_node_data,
            update_args=(new_instance_id,),
            timeout=config.get_cloud_config_value("wait_for_ip_timeout", vm_, __opts__, default=10 * 60),
            interval=config.get_cloud_config_value("wait_for_ip_interval", vm_, __opts__, default=10),
        )
    except (SaltCloudExecutionTimeout, SaltCloudExecutionFailure) as exc:
        try:
            # It might be already up, let's destroy it!
            destroy(vm_["name"])
        except SaltCloudSystemExit:
            pass
        finally:
            raise SaltCloudSystemExit(str(exc))

    private_ip = data["private_ips"][0]

    log.debug("VM {0} is now running".format(private_ip))

    vm_["ssh_host"] = private_ip

    # The instance is booted and accessible, let's Salt it!
    salt.utils.cloud.bootstrap(vm_, __opts__)

    log.info("Created Cloud VM {0[name]!r}".format(vm_))

    log.debug("{0[name]!r} VM creation details:\n{1}".format(vm_, pprint.pformat(data)))

    salt.utils.cloud.fire_event(
        "event",
        "created instance",
        "salt/cloud/{0}/created".format(vm_["name"]),
        {"name": vm_["name"], "profile": vm_["profile"], "provider": vm_["driver"]},
        transport=__opts__["transport"],
    )

    return data
Ejemplo n.º 48
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']) is False:
            return False
    except AttributeError:
        pass

    # Since using "provider: <provider-engine>" is deprecated, alias provider
    # to use driver: "driver: <provider-engine>"
    if 'provider' in vm_:
        vm_['driver'] = vm_.pop('provider')

    salt.utils.cloud.fire_event('event',
                                'starting create',
                                'salt/cloud/{0}/creating'.format(vm_['name']),
                                {
                                    'name': vm_['name'],
                                    'profile': vm_['profile'],
                                    'provider': vm_['driver'],
                                },
                                transport=__opts__['transport'])

    log.info('Creating Cloud VM {0}'.format(vm_['name']))
    conn = get_conn()

    salt.utils.cloud.fire_event('event',
                                'requesting instance',
                                'salt/cloud/{0}/requesting'.format(
                                    vm_['name']), {'kwargs': vm_},
                                transport=__opts__['transport'])

    folder = config.get_cloud_config_value('folder',
                                           vm_,
                                           __opts__,
                                           default=None)
    resourcepool = config.get_cloud_config_value('resourcepool',
                                                 vm_,
                                                 __opts__,
                                                 default=None)
    datastore = config.get_cloud_config_value('datastore',
                                              vm_,
                                              __opts__,
                                              default=None)
    host = config.get_cloud_config_value('host', vm_, __opts__, default=None)
    template = config.get_cloud_config_value('template',
                                             vm_,
                                             __opts__,
                                             default=False)

    clone_kwargs = {
        'name': vm_['name'],
        'folder': folder,
        'resourcepool': resourcepool,
        'datastore': datastore,
        'host': host,
        'template': template,
    }
    log.debug('clone_kwargs are set to {0}'.format(
        pprint.pformat(clone_kwargs)))

    try:
        template = conn.get_vm_by_name(vm_['image'])
        new_instance = template.clone(**clone_kwargs)
        data = new_instance.get_properties()  # pylint: disable=W0612
    except Exception as exc:  # pylint: disable=W0703
        log.error(
            'Error creating {0} on vSphere\n\n'
            'The following exception was thrown when trying to '
            'run the initial deployment: \n{1}'.format(vm_['name'], str(exc)),
            # Show the traceback if the debug logging level is enabled
            exc_info_on_loglevel=logging.DEBUG)
        return False

    deploy_kwargs = None
    if config.get_cloud_config_value('deploy', vm_, __opts__) is True:
        deploy_kwargs = _deploy(vm_)

    ret = show_instance(name=vm_['name'], call='action')
    show_deploy_args = config.get_cloud_config_value('show_deploy_args',
                                                     vm_,
                                                     __opts__,
                                                     default=False)
    if show_deploy_args:
        ret['deploy_kwargs'] = deploy_kwargs

    log.info('Created Cloud VM \'{0[name]}\''.format(vm_))
    log.debug('\'{0[name]}\' VM creation details:\n{1}'.format(
        vm_, pprint.pformat(ret)))

    salt.utils.cloud.fire_event('event',
                                'created instance',
                                'salt/cloud/{0}/created'.format(vm_['name']), {
                                    'name': vm_['name'],
                                    'profile': vm_['profile'],
                                    'provider': vm_['driver'],
                                },
                                transport=__opts__['transport'])
    return ret
Ejemplo n.º 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 config.is_profile_configured(__opts__,
                                        __active_provider_name__ or 'parallels',
                                        vm_['profile']) is False:
            return False
    except AttributeError:
        pass

    # Since using "provider: <provider-engine>" is deprecated, alias provider
    # to use driver: "driver: <provider-engine>"
    if 'provider' in vm_:
        vm_['driver'] = vm_.pop('provider')

    salt.utils.cloud.fire_event(
        'event',
        'starting create',
        'salt/cloud/{0}/creating'.format(vm_['name']),
        {
            'name': vm_['name'],
            'profile': vm_['profile'],
            'provider': vm_['driver'],
        },
        transport=__opts__['transport']
    )

    log.info('Creating Cloud VM {0}'.format(vm_['name']))

    try:
        data = create_node(vm_)
    except Exception as exc:
        log.error(
            'Error creating {0} on PARALLELS\n\n'
            'The following exception was thrown when trying to '
            'run the initial deployment: \n{1}'.format(
                vm_['name'], str(exc)
            ),
            # Show the traceback if the debug logging level is enabled
            exc_info_on_loglevel=logging.DEBUG
        )
        return False

    name = vm_['name']
    if not wait_until(name, 'CREATED'):
        return {'Error': 'Unable to start {0}, command timed out'.format(name)}
    start(vm_['name'], call='action')

    if not wait_until(name, 'STARTED'):
        return {'Error': 'Unable to start {0}, command timed out'.format(name)}

    def __query_node_data(vm_name):
        data = show_instance(vm_name, call='action')
        if 'public-ip' not in data['network']:
            # Trigger another iteration
            return
        return data

    try:
        data = salt.utils.cloud.wait_for_ip(
            __query_node_data,
            update_args=(vm_['name'],),
            timeout=config.get_cloud_config_value(
                'wait_for_ip_timeout', vm_, __opts__, default=5 * 60),
            interval=config.get_cloud_config_value(
                'wait_for_ip_interval', vm_, __opts__, default=5),
        )
    except (SaltCloudExecutionTimeout, SaltCloudExecutionFailure) as exc:
        try:
            # It might be already up, let's destroy it!
            destroy(vm_['name'])
        except SaltCloudSystemExit:
            pass
        finally:
            raise SaltCloudSystemExit(str(exc))

    comps = data['network']['public-ip']['address'].split('/')
    public_ip = comps[0]

    vm_['ssh_host'] = public_ip
    ret = salt.utils.cloud.bootstrap(vm_, __opts__)

    log.info('Created Cloud VM {0[name]!r}'.format(vm_))
    log.debug(
        '{0[name]!r} VM creation details:\n{1}'.format(
            vm_, pprint.pformat(data)
        )
    )

    salt.utils.cloud.fire_event(
        'event',
        'created instance',
        'salt/cloud/{0}/created'.format(vm_['name']),
        {
            'name': vm_['name'],
            'profile': vm_['profile'],
            'provider': vm_['driver'],
        },
        transport=__opts__['transport']
    )

    return data
Ejemplo n.º 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__,
                _get_active_provider_name() or "digitalocean",
                vm_["profile"],
                vm_=vm_,
        ) is False):
            return False
    except AttributeError:
        pass

    __utils__["cloud.fire_event"](
        "event",
        "starting create",
        "salt/cloud/{}/creating".format(vm_["name"]),
        args=__utils__["cloud.filter_event"](
            "creating", vm_, ["name", "profile", "provider", "driver"]),
        sock_dir=__opts__["sock_dir"],
        transport=__opts__["transport"],
    )

    log.info("Creating Cloud VM %s", vm_["name"])

    kwargs = {
        "name": vm_["name"],
        "size": get_size(vm_),
        "image": get_image(vm_),
        "region": get_location(vm_),
        "ssh_keys": [],
        "tags": [],
    }

    # backwards compat
    ssh_key_name = config.get_cloud_config_value("ssh_key_name",
                                                 vm_,
                                                 __opts__,
                                                 search_global=False)

    if ssh_key_name:
        kwargs["ssh_keys"].append(get_keyid(ssh_key_name))

    ssh_key_names = config.get_cloud_config_value("ssh_key_names",
                                                  vm_,
                                                  __opts__,
                                                  search_global=False,
                                                  default=False)

    if ssh_key_names:
        for key in ssh_key_names.split(","):
            kwargs["ssh_keys"].append(get_keyid(key))

    key_filename = config.get_cloud_config_value("ssh_key_file",
                                                 vm_,
                                                 __opts__,
                                                 search_global=False,
                                                 default=None)

    if key_filename is not None and not os.path.isfile(key_filename):
        raise SaltCloudConfigError(
            "The defined key_filename '{}' does not exist".format(
                key_filename))

    if not __opts__.get("ssh_agent", False) and key_filename is None:
        raise SaltCloudConfigError(
            "The DigitalOcean driver requires an ssh_key_file and an ssh_key_name "
            "because it does not supply a root password upon building the server."
        )

    ssh_interface = config.get_cloud_config_value("ssh_interface",
                                                  vm_,
                                                  __opts__,
                                                  search_global=False,
                                                  default="public")

    if ssh_interface in ["private", "public"]:
        log.info("ssh_interface: Setting interface for ssh to %s",
                 ssh_interface)
        kwargs["ssh_interface"] = ssh_interface
    else:
        raise SaltCloudConfigError(
            "The DigitalOcean driver requires ssh_interface to be defined as 'public' or 'private'."
        )

    private_networking = config.get_cloud_config_value(
        "private_networking",
        vm_,
        __opts__,
        search_global=False,
        default=None,
    )

    if private_networking is not None:
        if not isinstance(private_networking, bool):
            raise SaltCloudConfigError(
                "'private_networking' should be a boolean value.")
        kwargs["private_networking"] = private_networking

    if not private_networking and ssh_interface == "private":
        raise SaltCloudConfigError(
            "The DigitalOcean driver requires ssh_interface if defined as 'private' "
            "then private_networking should be set as 'True'.")

    backups_enabled = config.get_cloud_config_value(
        "backups_enabled",
        vm_,
        __opts__,
        search_global=False,
        default=None,
    )

    if backups_enabled is not None:
        if not isinstance(backups_enabled, bool):
            raise SaltCloudConfigError(
                "'backups_enabled' should be a boolean value.")
        kwargs["backups"] = backups_enabled

    ipv6 = config.get_cloud_config_value(
        "ipv6",
        vm_,
        __opts__,
        search_global=False,
        default=None,
    )

    if ipv6 is not None:
        if not isinstance(ipv6, bool):
            raise SaltCloudConfigError("'ipv6' should be a boolean value.")
        kwargs["ipv6"] = ipv6

    monitoring = config.get_cloud_config_value(
        "monitoring",
        vm_,
        __opts__,
        search_global=False,
        default=None,
    )

    if monitoring is not None:
        if not isinstance(monitoring, bool):
            raise SaltCloudConfigError(
                "'monitoring' should be a boolean value.")
        kwargs["monitoring"] = monitoring

    kwargs["tags"] = config.get_cloud_config_value("tags",
                                                   vm_,
                                                   __opts__,
                                                   search_global=False,
                                                   default=False)

    userdata_file = config.get_cloud_config_value("userdata_file",
                                                  vm_,
                                                  __opts__,
                                                  search_global=False,
                                                  default=None)
    if userdata_file is not None:
        try:
            with salt.utils.files.fopen(userdata_file, "r") as fp_:
                kwargs["user_data"] = salt.utils.cloud.userdata_template(
                    __opts__, vm_,
                    salt.utils.stringutils.to_unicode(fp_.read()))
        except Exception as exc:  # pylint: disable=broad-except
            log.exception("Failed to read userdata from %s: %s", userdata_file,
                          exc)

    create_dns_record = config.get_cloud_config_value(
        "create_dns_record",
        vm_,
        __opts__,
        search_global=False,
        default=None,
    )

    if create_dns_record:
        log.info("create_dns_record: will attempt to write DNS records")
        default_dns_domain = None
        dns_domain_name = vm_["name"].split(".")
        if len(dns_domain_name) > 2:
            log.debug(
                "create_dns_record: inferring default dns_hostname, dns_domain from minion name as FQDN"
            )
            default_dns_hostname = ".".join(dns_domain_name[:-2])
            default_dns_domain = ".".join(dns_domain_name[-2:])
        else:
            log.debug("create_dns_record: can't infer dns_domain from %s",
                      vm_["name"])
            default_dns_hostname = dns_domain_name[0]

        dns_hostname = config.get_cloud_config_value(
            "dns_hostname",
            vm_,
            __opts__,
            search_global=False,
            default=default_dns_hostname,
        )
        dns_domain = config.get_cloud_config_value(
            "dns_domain",
            vm_,
            __opts__,
            search_global=False,
            default=default_dns_domain,
        )
        if dns_hostname and dns_domain:
            log.info(
                'create_dns_record: using dns_hostname="%s", dns_domain="%s"',
                dns_hostname,
                dns_domain,
            )
            __add_dns_addr__ = lambda t, d: post_dns_record(dns_domain=
                                                            dns_domain,
                                                            name=dns_hostname,
                                                            record_type=t,
                                                            record_data=d)

            log.debug("create_dns_record: %s", __add_dns_addr__)
        else:
            log.error(
                "create_dns_record: could not determine dns_hostname and/or dns_domain"
            )
            raise SaltCloudConfigError(
                "'create_dns_record' must be a dict specifying \"domain\" "
                'and "hostname" or the minion name must be an FQDN.')

    __utils__["cloud.fire_event"](
        "event",
        "requesting instance",
        "salt/cloud/{}/requesting".format(vm_["name"]),
        args=__utils__["cloud.filter_event"]("requesting", kwargs,
                                             list(kwargs)),
        sock_dir=__opts__["sock_dir"],
        transport=__opts__["transport"],
    )

    try:
        ret = create_node(kwargs)
    except Exception as exc:  # pylint: disable=broad-except
        log.error(
            "Error creating %s on DIGITALOCEAN\n\n"
            "The following exception was thrown when trying to "
            "run the initial deployment: %s",
            vm_["name"],
            exc,
            # Show the traceback if the debug logging level is enabled
            exc_info_on_loglevel=logging.DEBUG,
        )
        return False

    def __query_node_data(vm_name):
        data = show_instance(vm_name, "action")
        if not data:
            # Trigger an error in the wait_for_ip function
            return False
        if data["networks"].get("v4"):
            for network in data["networks"]["v4"]:
                if network["type"] == "public":
                    return data
        return False

    try:
        data = salt.utils.cloud.wait_for_ip(
            __query_node_data,
            update_args=(vm_["name"], ),
            timeout=config.get_cloud_config_value("wait_for_ip_timeout",
                                                  vm_,
                                                  __opts__,
                                                  default=10 * 60),
            interval=config.get_cloud_config_value("wait_for_ip_interval",
                                                   vm_,
                                                   __opts__,
                                                   default=10),
        )
    except (SaltCloudExecutionTimeout, SaltCloudExecutionFailure) as exc:
        try:
            # It might be already up, let's destroy it!
            destroy(vm_["name"])
        except SaltCloudSystemExit:
            pass
        finally:
            raise SaltCloudSystemExit(str(exc))

    if not vm_.get("ssh_host"):
        vm_["ssh_host"] = None

    # add DNS records, set ssh_host, default to first found IP, preferring IPv4 for ssh bootstrap script target
    addr_families, dns_arec_types = (("v4", "v6"), ("A", "AAAA"))
    arec_map = dict(list(zip(addr_families, dns_arec_types)))
    for facing, addr_family, ip_address in [
        (net["type"], family, net["ip_address"]) for family in addr_families
            for net in data["networks"][family]
    ]:
        log.info('found %s IP%s interface for "%s"', facing, addr_family,
                 ip_address)
        dns_rec_type = arec_map[addr_family]
        if facing == "public":
            if create_dns_record:
                __add_dns_addr__(dns_rec_type, ip_address)
        if facing == ssh_interface:
            if not vm_["ssh_host"]:
                vm_["ssh_host"] = ip_address

    if vm_["ssh_host"] is None:
        raise SaltCloudSystemExit(
            "No suitable IP addresses found for ssh minion bootstrapping: {}".
            format(repr(data["networks"])))

    log.debug(
        "Found public IP address to use for ssh minion bootstrapping: %s",
        vm_["ssh_host"],
    )

    vm_["key_filename"] = key_filename
    ret = __utils__["cloud.bootstrap"](vm_, __opts__)
    ret.update(data)

    log.info("Created Cloud VM '%s'", vm_["name"])
    log.debug("'%s' VM creation details:\n%s", vm_["name"],
              pprint.pformat(data))

    __utils__["cloud.fire_event"](
        "event",
        "created instance",
        "salt/cloud/{}/created".format(vm_["name"]),
        args=__utils__["cloud.filter_event"](
            "created", vm_, ["name", "profile", "provider", "driver"]),
        sock_dir=__opts__["sock_dir"],
        transport=__opts__["transport"],
    )

    return ret
Ejemplo n.º 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 'digital_ocean',
                                                           vm_['profile']) is False:
            return False
    except AttributeError:
        pass

    # Since using "provider: <provider-engine>" is deprecated, alias provider
    # to use driver: "driver: <provider-engine>"
    if 'provider' in vm_:
        vm_['driver'] = vm_.pop('provider')

    salt.utils.cloud.fire_event(
        'event',
        'starting create',
        'salt/cloud/{0}/creating'.format(vm_['name']),
        {
            'name': vm_['name'],
            'profile': vm_['profile'],
            'provider': vm_['driver'],
        },
        transport=__opts__['transport']
    )

    log.info('Creating Cloud VM {0}'.format(vm_['name']))

    kwargs = {
        'name': vm_['name'],
        'size': get_size(vm_),
        'image': get_image(vm_),
        'region': get_location(vm_),
        'ssh_keys': []
    }

    # backwards compat
    ssh_key_name = config.get_cloud_config_value(
        'ssh_key_name', vm_, __opts__, search_global=False
    )

    if ssh_key_name:
        kwargs['ssh_keys'].append(get_keyid(ssh_key_name))

    ssh_key_names = config.get_cloud_config_value(
        'ssh_key_names', vm_, __opts__, search_global=False, default=False
    )

    if ssh_key_names:
        for key in ssh_key_names.split(','):
            kwargs['ssh_keys'].append(get_keyid(key))

    key_filename = config.get_cloud_config_value(
        'ssh_key_file', vm_, __opts__, search_global=False, default=None
    )

    if key_filename is not None and not os.path.isfile(key_filename):
        raise SaltCloudConfigError(
            'The defined key_filename \'{0}\' does not exist'.format(
                key_filename
            )
        )

    if key_filename is None:
        raise SaltCloudConfigError(
            'The DigitalOcean driver requires an ssh_key_file and an ssh_key_name '
            'because it does not supply a root password upon building the server.'
        )

    private_networking = config.get_cloud_config_value(
        'private_networking', vm_, __opts__, search_global=False, default=None,
    )

    if private_networking is not None:
        if not isinstance(private_networking, bool):
            raise SaltCloudConfigError("'private_networking' should be a boolean value.")
        kwargs['private_networking'] = private_networking

    backups_enabled = config.get_cloud_config_value(
        'backups_enabled', vm_, __opts__, search_global=False, default=None,
    )

    if backups_enabled is not None:
        if not isinstance(backups_enabled, bool):
            raise SaltCloudConfigError("'backups_enabled' should be a boolean value.")
        kwargs['backups'] = backups_enabled

    ipv6 = config.get_cloud_config_value(
        'ipv6', vm_, __opts__, search_global=False, default=None,
    )

    if ipv6 is not None:
        if not isinstance(ipv6, bool):
            raise SaltCloudConfigError("'ipv6' should be a boolean value.")
        kwargs['ipv6'] = ipv6

    create_dns_record = config.get_cloud_config_value(
        'create_dns_record', vm_, __opts__, search_global=False, default=None,
    )

    if create_dns_record:
        log.info('create_dns_record: will attempt to write DNS records')
        default_dns_domain = None
        dns_domain_name = vm_['name'].split('.')
        if len(dns_domain_name) > 2:
            log.debug('create_dns_record: inferring default dns_hostname, dns_domain from minion name as FQDN')
            default_dns_hostname = '.'.join(dns_domain_name[:-2])
            default_dns_domain = '.'.join(dns_domain_name[-2:])
        else:
            log.debug("create_dns_record: can't infer dns_domain from {0}".format(vm_['name']))
            default_dns_hostname = dns_domain_name[0]

        dns_hostname = config.get_cloud_config_value(
            'dns_hostname', vm_, __opts__, search_global=False, default=default_dns_hostname,
        )
        dns_domain = config.get_cloud_config_value(
            'dns_domain', vm_, __opts__, search_global=False, default=default_dns_domain,
        )
        if dns_hostname and dns_domain:
            log.info('create_dns_record: using dns_hostname="{0}", dns_domain="{1}"'.format(dns_hostname, dns_domain))
            __add_dns_addr__ = lambda t, d: post_dns_record(dns_domain, dns_hostname, t, d)
            log.debug('create_dns_record: {0}'.format(__add_dns_addr__))
        else:
            log.error('create_dns_record: could not determine dns_hostname and/or dns_domain')
            raise SaltCloudConfigError(
                '\'create_dns_record\' must be a dict specifying "domain" '
                'and "hostname" or the minion name must be an FQDN.'
            )

    salt.utils.cloud.fire_event(
        'event',
        'requesting instance',
        'salt/cloud/{0}/requesting'.format(vm_['name']),
        {'kwargs': kwargs},
        transport=__opts__['transport']
    )

    try:
        ret = create_node(kwargs)
    except Exception as exc:
        log.error(
            'Error creating {0} on DIGITAL_OCEAN\n\n'
            'The following exception was thrown when trying to '
            'run the initial deployment: {1}'.format(
                vm_['name'],
                str(exc)
            ),
            # Show the traceback if the debug logging level is enabled
            exc_info_on_loglevel=logging.DEBUG
        )
        return False

    def __query_node_data(vm_name):
        data = show_instance(vm_name, 'action')
        if not data:
            # Trigger an error in the wait_for_ip function
            return False
        if data['networks'].get('v4'):
            for network in data['networks']['v4']:
                if network['type'] == 'public':
                    return data
        return False

    try:
        data = salt.utils.cloud.wait_for_ip(
            __query_node_data,
            update_args=(vm_['name'],),
            timeout=config.get_cloud_config_value(
                'wait_for_ip_timeout', vm_, __opts__, default=10 * 60),
            interval=config.get_cloud_config_value(
                'wait_for_ip_interval', vm_, __opts__, default=10),
        )
    except (SaltCloudExecutionTimeout, SaltCloudExecutionFailure) as exc:
        try:
            # It might be already up, let's destroy it!
            destroy(vm_['name'])
        except SaltCloudSystemExit:
            pass
        finally:
            raise SaltCloudSystemExit(str(exc))

    if not vm_.get('ssh_host'):
        vm_['ssh_host'] = None

    # add DNS records, set ssh_host, default to first found IP, preferring IPv4 for ssh bootstrap script target
    addr_families, dns_arec_types = (('v4', 'v6'), ('A', 'AAAA'))
    arec_map = dict(list(zip(addr_families, dns_arec_types)))
    for facing, addr_family, ip_address in [(net['type'], family, net['ip_address'])
                                            for family in addr_families
                                            for net in data['networks'][family]]:
        log.info('found {0} IP{1} interface for "{2}"'.format(facing, addr_family, ip_address))
        dns_rec_type = arec_map[addr_family]
        if facing == 'public':
            if create_dns_record:
                __add_dns_addr__(dns_rec_type, ip_address)
            if not vm_['ssh_host']:
                vm_['ssh_host'] = ip_address

    if vm_['ssh_host'] is None:
        raise SaltCloudSystemExit(
            'No suitable IP addresses found for ssh minion bootstrapping: {0}'.format(repr(data['networks']))
        )

    log.debug('Found public IP address to use for ssh minion bootstrapping: {0}'.format(vm_['ssh_host']))

    vm_['key_filename'] = key_filename
    ret = salt.utils.cloud.bootstrap(vm_, __opts__)
    ret.update(data)

    log.info('Created Cloud VM \'{0[name]}\''.format(vm_))
    log.debug(
        '\'{0[name]}\' VM creation details:\n{1}'.format(
            vm_, pprint.pformat(data)
        )
    )

    salt.utils.cloud.fire_event(
        'event',
        'created instance',
        'salt/cloud/{0}/created'.format(vm_['name']),
        {
            'name': vm_['name'],
            'profile': vm_['profile'],
            'provider': vm_['driver'],
        },
        transport=__opts__['transport']
    )

    return ret
Ejemplo n.º 52
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

    # Since using "provider: <provider-engine>" is deprecated, alias provider
    # to use driver: "driver: <provider-engine>"
    if 'provider' in vm_:
        vm_['driver'] = vm_.pop('provider')

    salt.utils.cloud.fire_event('event',
                                'starting create',
                                'salt/cloud/{0}/creating'.format(vm_['name']),
                                {
                                    'name': vm_['name'],
                                    'profile': vm_['profile'],
                                    'provider': vm_['driver'],
                                },
                                transport=__opts__['transport'])

    log.info('Creating Cloud VM {0}'.format(vm_['name']))

    kwargs = {
        'name': vm_['name'],
        'size': get_size(vm_),
        'image': get_image(vm_),
        'region': get_location(vm_),
        'ssh_keys': []
    }

    # backwards compat
    ssh_key_name = config.get_cloud_config_value('ssh_key_name',
                                                 vm_,
                                                 __opts__,
                                                 search_global=False)

    if ssh_key_name:
        kwargs['ssh_keys'].append(get_keyid(ssh_key_name))

    ssh_key_names = config.get_cloud_config_value('ssh_key_names',
                                                  vm_,
                                                  __opts__,
                                                  search_global=False,
                                                  default=False)

    if ssh_key_names:
        for key in ssh_key_names.split(','):
            kwargs['ssh_keys'].append(get_keyid(key))

    key_filename = config.get_cloud_config_value('ssh_key_file',
                                                 vm_,
                                                 __opts__,
                                                 search_global=False,
                                                 default=None)

    if key_filename is not None and not os.path.isfile(key_filename):
        raise SaltCloudConfigError(
            'The defined key_filename \'{0}\' does not exist'.format(
                key_filename))

    if key_filename is None:
        raise SaltCloudConfigError(
            'The DigitalOcean driver requires an ssh_key_file and an ssh_key_name '
            'because it does not supply a root password upon building the server.'
        )

    private_networking = config.get_cloud_config_value(
        'private_networking',
        vm_,
        __opts__,
        search_global=False,
        default=None,
    )

    if private_networking is not None:
        if not isinstance(private_networking, bool):
            raise SaltCloudConfigError(
                "'private_networking' should be a boolean value.")
        kwargs['private_networking'] = private_networking

    backups_enabled = config.get_cloud_config_value(
        'backups_enabled',
        vm_,
        __opts__,
        search_global=False,
        default=None,
    )

    if backups_enabled is not None:
        if not isinstance(backups_enabled, bool):
            raise SaltCloudConfigError(
                "'backups_enabled' should be a boolean value.")
        kwargs['backups'] = backups_enabled

    ipv6 = config.get_cloud_config_value(
        'ipv6',
        vm_,
        __opts__,
        search_global=False,
        default=None,
    )

    if ipv6 is not None:
        if not isinstance(ipv6, bool):
            raise SaltCloudConfigError("'ipv6' should be a boolean value.")
        kwargs['ipv6'] = ipv6

    create_dns_record = config.get_cloud_config_value(
        'create_dns_record',
        vm_,
        __opts__,
        search_global=False,
        default=None,
    )

    if create_dns_record:
        log.info('create_dns_record: will attempt to write DNS records')
        default_dns_domain = None
        dns_domain_name = vm_['name'].split('.')
        if len(dns_domain_name) > 2:
            log.debug(
                'create_dns_record: inferring default dns_hostname, dns_domain from minion name as FQDN'
            )
            default_dns_hostname = '.'.join(dns_domain_name[:-2])
            default_dns_domain = '.'.join(dns_domain_name[-2:])
        else:
            log.debug(
                "create_dns_record: can't infer dns_domain from {0}".format(
                    vm_['name']))
            default_dns_hostname = dns_domain_name[0]

        dns_hostname = config.get_cloud_config_value(
            'dns_hostname',
            vm_,
            __opts__,
            search_global=False,
            default=default_dns_hostname,
        )
        dns_domain = config.get_cloud_config_value(
            'dns_domain',
            vm_,
            __opts__,
            search_global=False,
            default=default_dns_domain,
        )
        if dns_hostname and dns_domain:
            log.info(
                'create_dns_record: using dns_hostname="{0}", dns_domain="{1}"'
                .format(dns_hostname, dns_domain))
            __add_dns_addr__ = lambda t, d: post_dns_record(
                dns_domain, dns_hostname, t, d)
            log.debug('create_dns_record: {0}'.format(__add_dns_addr__))
        else:
            log.error(
                'create_dns_record: could not determine dns_hostname and/or dns_domain'
            )
            raise SaltCloudConfigError(
                '\'create_dns_record\' must be a dict specifying "domain" '
                'and "hostname" or the minion name must be an FQDN.')

    salt.utils.cloud.fire_event('event',
                                'requesting instance',
                                'salt/cloud/{0}/requesting'.format(
                                    vm_['name']), {'kwargs': kwargs},
                                transport=__opts__['transport'])

    try:
        ret = create_node(kwargs)
    except Exception as exc:
        log.error(
            'Error creating {0} on DIGITAL_OCEAN\n\n'
            'The following exception was thrown when trying to '
            'run the initial deployment: {1}'.format(vm_['name'], str(exc)),
            # Show the traceback if the debug logging level is enabled
            exc_info_on_loglevel=logging.DEBUG)
        return False

    def __query_node_data(vm_name):
        data = show_instance(vm_name, 'action')
        if not data:
            # Trigger an error in the wait_for_ip function
            return False
        if data['networks'].get('v4'):
            for network in data['networks']['v4']:
                if network['type'] == 'public':
                    return data
        return False

    try:
        data = salt.utils.cloud.wait_for_ip(
            __query_node_data,
            update_args=(vm_['name'], ),
            timeout=config.get_cloud_config_value('wait_for_ip_timeout',
                                                  vm_,
                                                  __opts__,
                                                  default=10 * 60),
            interval=config.get_cloud_config_value('wait_for_ip_interval',
                                                   vm_,
                                                   __opts__,
                                                   default=10),
        )
    except (SaltCloudExecutionTimeout, SaltCloudExecutionFailure) as exc:
        try:
            # It might be already up, let's destroy it!
            destroy(vm_['name'])
        except SaltCloudSystemExit:
            pass
        finally:
            raise SaltCloudSystemExit(str(exc))

    if not vm_.get('ssh_host'):
        vm_['ssh_host'] = None

    # add DNS records, set ssh_host, default to first found IP, preferring IPv4 for ssh bootstrap script target
    addr_families, dns_arec_types = (('v4', 'v6'), ('A', 'AAAA'))
    arec_map = dict(list(zip(addr_families, dns_arec_types)))
    for facing, addr_family, ip_address in [
        (net['type'], family, net['ip_address']) for family in addr_families
            for net in data['networks'][family]
    ]:
        log.info('found {0} IP{1} interface for "{2}"'.format(
            facing, addr_family, ip_address))
        dns_rec_type = arec_map[addr_family]
        if facing == 'public':
            if create_dns_record:
                __add_dns_addr__(dns_rec_type, ip_address)
            if not vm_['ssh_host']:
                vm_['ssh_host'] = ip_address

    if vm_['ssh_host'] is None:
        raise SaltCloudSystemExit(
            'No suitable IP addresses found for ssh minion bootstrapping: {0}'.
            format(repr(data['networks'])))

    log.debug(
        'Found public IP address to use for ssh minion bootstrapping: {0}'.
        format(vm_['ssh_host']))

    vm_['key_filename'] = key_filename
    ret = salt.utils.cloud.bootstrap(vm_, __opts__)
    ret.update(data)

    log.info('Created Cloud VM \'{0[name]}\''.format(vm_))
    log.debug('\'{0[name]}\' VM creation details:\n{1}'.format(
        vm_, pprint.pformat(data)))

    salt.utils.cloud.fire_event('event',
                                'created instance',
                                'salt/cloud/{0}/created'.format(vm_['name']), {
                                    'name': vm_['name'],
                                    'profile': vm_['profile'],
                                    'provider': vm_['driver'],
                                },
                                transport=__opts__['transport'])

    return ret
Ejemplo n.º 53
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 config.is_profile_configured(__opts__,
                                        __active_provider_name__ or 'proxmox',
                                        vm_['profile']) is False:
            return False
    except AttributeError:
        pass

    # Since using "provider: <provider-engine>" is deprecated, alias provider
    # to use driver: "driver: <provider-engine>"
    if 'provider' in vm_:
        vm_['driver'] = vm_.pop('provider')

    ret = {}

    salt.utils.cloud.fire_event(
        'event',
        'starting create',
        'salt/cloud/{0}/creating'.format(vm_['name']),
        {
            'name': vm_['name'],
            'profile': vm_['profile'],
            'provider': vm_['driver'],
        },
        transport=__opts__['transport']
    )

    log.info('Creating Cloud VM {0}'.format(vm_['name']))

    if 'use_dns' in vm_ and 'ip_address' not in vm_:
        use_dns = vm_['use_dns']
        if use_dns:
            from socket import gethostbyname, gaierror
            try:
                ip_address = gethostbyname(str(vm_['name']))
            except gaierror:
                log.debug('Resolving of {hostname} failed'.format(hostname=str(vm_['name'])))
            else:
                vm_['ip_address'] = str(ip_address)

    try:
        data = create_node(vm_)
    except Exception as exc:
        log.error(
            'Error creating {0} on PROXMOX\n\n'
            'The following exception was thrown when trying to '
            'run the initial deployment: \n{1}'.format(
                vm_['name'], str(exc)
            ),
            # Show the traceback if the debug logging level is enabled
            exc_info_on_loglevel=logging.DEBUG
        )
        return False

    ret['creation_data'] = data
    name = vm_['name']        # hostname which we know
    vmid = data['vmid']       # vmid which we have received
    host = data['node']       # host which we have received
    nodeType = data['technology']  # VM tech (Qemu / OpenVZ)

    # Determine which IP to use in order of preference:
    if 'ip_address' in vm_:
        ip_address = str(vm_['ip_address'])
    elif 'public_ips' in data:
        ip_address = str(data['public_ips'][0])  # first IP
    elif 'private_ips' in data:
        ip_address = str(data['private_ips'][0])  # first IP
    else:
        raise SaltCloudExecutionFailure  # err.. not a good idea i reckon

    log.debug('Using IP address {0}'.format(ip_address))

    # wait until the vm has been created so we can start it
    if not wait_for_created(data['upid'], timeout=300):
        return {'Error': 'Unable to create {0}, command timed out'.format(name)}

    # VM has been created. Starting..
    if not start(name, vmid, call='action'):
        log.error('Node {0} ({1}) failed to start!'.format(name, vmid))
        raise SaltCloudExecutionFailure

    # Wait until the VM has fully started
    log.debug('Waiting for state "running" for vm {0} on {1}'.format(vmid, host))
    if not wait_for_state(vmid, 'running'):
        return {'Error': 'Unable to start {0}, command timed out'.format(name)}

    ssh_username = config.get_cloud_config_value(
        'ssh_username', vm_, __opts__, default='root'
    )
    ssh_password = config.get_cloud_config_value(
        'password', vm_, __opts__,
    )

    ret['ip_address'] = ip_address
    ret['username'] = ssh_username
    ret['password'] = ssh_password

    vm_['ssh_host'] = ip_address
    vm_['password'] = ssh_password
    ret = salt.utils.cloud.bootstrap(vm_, __opts__)

    # Report success!
    log.info('Created Cloud VM {0[name]!r}'.format(vm_))
    log.debug(
        '{0[name]!r} VM creation details:\n{1}'.format(
            vm_, pprint.pformat(data)
        )
    )

    salt.utils.cloud.fire_event(
        'event',
        'created instance',
        'salt/cloud/{0}/created'.format(vm_['name']),
        {
            'name': vm_['name'],
            'profile': vm_['profile'],
            'provider': vm_['driver'],
        },
    )

    return ret
Ejemplo n.º 54
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 'aws',
                vm_['profile'],
                vm_=vm_) is False:
            return False
    except AttributeError:
        pass

    key_filename = config.get_cloud_config_value('private_key',
                                                 vm_,
                                                 __opts__,
                                                 search_global=False,
                                                 default=None)
    if key_filename is not None and not os.path.isfile(key_filename):
        raise SaltCloudConfigError(
            'The defined key_filename {0!r} does not exist'.format(
                key_filename))

    location = get_location(vm_)
    log.info('Creating Cloud VM {0} in {1}'.format(vm_['name'], location))
    conn = get_conn(location=location)
    usernames = ssh_username(vm_)
    kwargs = {
        'ssh_key':
        config.get_cloud_config_value('private_key',
                                      vm_,
                                      __opts__,
                                      search_global=False),
        'name':
        vm_['name'],
        'image':
        get_image(conn, vm_),
        'size':
        get_size(conn, vm_),
        'location':
        get_availability_zone(conn, vm_)
    }
    ex_keyname = keyname(vm_)
    if ex_keyname:
        kwargs['ex_keyname'] = ex_keyname
    ex_securitygroup = securitygroup(vm_)
    if ex_securitygroup:
        kwargs['ex_securitygroup'] = ex_securitygroup
    ex_blockdevicemappings = block_device_mappings(vm_)
    if ex_blockdevicemappings:
        kwargs['ex_blockdevicemappings'] = ex_blockdevicemappings

    ex_iam_profile = iam_profile(vm_)
    if ex_iam_profile:
        # libcloud does not implement 'iam_profile' yet.
        # A pull request has been suggested
        # https://github.com/apache/libcloud/pull/150
        raise SaltCloudConfigError(
            'libcloud does not implement \'iam_profile\' yet. '
            'Use EC2 driver instead.')

    tags = config.get_cloud_config_value('tag',
                                         vm_,
                                         __opts__, {},
                                         search_global=False)
    if not isinstance(tags, dict):
        raise SaltCloudConfigError('\'tag\' should be a dict.')
    kwargs['ex_metadata'] = config.get_cloud_config_value('metadata',
                                                          vm_,
                                                          __opts__,
                                                          default={},
                                                          search_global=False)
    if not isinstance(kwargs['ex_metadata'], dict):
        raise SaltCloudConfigError('\'metadata\' should be a dict.')

    try:
        data = conn.create_node(**kwargs)
    except Exception as exc:
        log.error(
            'Error creating {0} on AWS\n\n'
            'The following exception was thrown by libcloud when trying to '
            'run the initial deployment: {1}\n'.format(vm_['name'], exc),
            # Show the traceback if the debug logging level is enabled
            exc_info_on_loglevel=logging.DEBUG)
        return False

    log.info('Created node {0}'.format(vm_['name']))

    def __get_node_data(conn, vm_name):
        data = get_node(conn, vm_name)

        if data is None:
            # Trigger a failure in the waiting function
            return False

        if ssh_interface(vm_) == 'private_ips' and data.private_ips:
            return data

        if ssh_interface(vm_) == 'public_ips' and data.public_ips:
            return data

    try:
        data = salt.utils.cloud.wait_for_ip(
            __get_node_data,
            update_args=(conn, vm_['name']),
            timeout=config.get_cloud_config_value('wait_for_ip_timeout',
                                                  vm_,
                                                  __opts__,
                                                  default=5 * 60),
            interval=config.get_cloud_config_value('wait_for_ip_interval',
                                                   vm_,
                                                   __opts__,
                                                   default=0.5),
        )
    except (SaltCloudExecutionTimeout, SaltCloudExecutionFailure) as exc:
        try:
            # It might be already up, let's destroy it!
            destroy(vm_['name'])
        except SaltCloudSystemExit:
            pass
        finally:
            raise SaltCloudSystemExit(str(exc))

    if tags:
        set_tags(vm_['name'], tags, call='action')

    if ssh_interface(vm_) == 'private_ips':
        log.info('Salt node data. Private_ip: {0}'.format(data.private_ips[0]))
        ip_address = data.private_ips[0]
    else:
        log.info('Salt node data. Public_ip: {0}'.format(data.public_ips[0]))
        ip_address = data.public_ips[0]

    if salt.utils.cloud.get_salt_interface(vm_, __opts__) == 'private_ips':
        salt_ip_address = data.private_ips[0]
        log.info('Salt interface set to: {0}'.format(salt_ip_address))
    else:
        salt_ip_address = data.public_ips[0]
        log.debug('Salt interface set to: {0}'.format(salt_ip_address))

    username = '******'
    ssh_connect_timeout = config.get_cloud_config_value(
        'ssh_connect_timeout',
        vm_,
        __opts__,
        900  # 15 minutes
    )
    ssh_port = config.get_cloud_config_value('ssh_port', vm_, __opts__, 22)
    if salt.utils.cloud.wait_for_port(ip_address, timeout=ssh_connect_timeout):
        for user in usernames:
            if salt.utils.cloud.wait_for_passwd(
                    host=ip_address,
                    username=user,
                    ssh_timeout=config.get_cloud_config_value(
                        'wait_for_passwd_timeout',
                        vm_,
                        __opts__,
                        default=1 * 60),
                    key_filename=key_filename,
                    known_hosts_file=config.get_cloud_config_value(
                        'known_hosts_file', vm_, __opts__,
                        default='/dev/null'),
            ):
                username = user
                break
        else:
            raise SaltCloudSystemExit(
                'Failed to authenticate against remote ssh')

    ret = {}
    if config.get_cloud_config_value('deploy', vm_, __opts__) is True:
        deploy_script = script(vm_)
        deploy_kwargs = {
            'opts':
            __opts__,
            'host':
            ip_address,
            'port':
            ssh_port,
            'salt_host':
            salt_ip_address,
            'username':
            username,
            'key_filename':
            key_filename,
            'tmp_dir':
            config.get_cloud_config_value('tmp_dir',
                                          vm_,
                                          __opts__,
                                          default='/tmp/.saltcloud'),
            'deploy_command':
            config.get_cloud_config_value(
                'deploy_command',
                vm_,
                __opts__,
                default='/tmp/.saltcloud/deploy.sh',
            ),
            'tty':
            config.get_cloud_config_value('tty', vm_, __opts__, default=True),
            'script':
            deploy_script.script,
            'name':
            vm_['name'],
            'sudo':
            config.get_cloud_config_value('sudo',
                                          vm_,
                                          __opts__,
                                          default=(username != 'root')),
            'sudo_password':
            config.get_cloud_config_value('sudo_password',
                                          vm_,
                                          __opts__,
                                          default=None),
            'start_action':
            __opts__['start_action'],
            'parallel':
            __opts__['parallel'],
            'conf_file':
            __opts__['conf_file'],
            'sock_dir':
            __opts__['sock_dir'],
            'minion_pem':
            vm_['priv_key'],
            'minion_pub':
            vm_['pub_key'],
            'keep_tmp':
            __opts__['keep_tmp'],
            'preseed_minion_keys':
            vm_.get('preseed_minion_keys', None),
            'display_ssh_output':
            config.get_cloud_config_value('display_ssh_output',
                                          vm_,
                                          __opts__,
                                          default=True),
            'script_args':
            config.get_cloud_config_value('script_args', vm_, __opts__),
            'script_env':
            config.get_cloud_config_value('script_env', vm_, __opts__),
            'minion_conf':
            salt.utils.cloud.minion_config(__opts__, vm_)
        }

        # Deploy salt-master files, if necessary
        if config.get_cloud_config_value('make_master', vm_, __opts__) is True:
            deploy_kwargs['make_master'] = True
            deploy_kwargs['master_pub'] = vm_['master_pub']
            deploy_kwargs['master_pem'] = vm_['master_pem']
            master_conf = salt.utils.cloud.master_config(__opts__, vm_)
            deploy_kwargs['master_conf'] = master_conf

            if master_conf.get('syndic_master', None):
                deploy_kwargs['make_syndic'] = True

        deploy_kwargs['make_minion'] = config.get_cloud_config_value(
            'make_minion', vm_, __opts__, default=True)

        # Check for Windows install params
        win_installer = config.get_cloud_config_value('win_installer', vm_,
                                                      __opts__)
        if win_installer:
            deploy_kwargs['win_installer'] = win_installer
            minion = salt.utils.cloud.minion_config(__opts__, vm_)
            deploy_kwargs['master'] = minion['master']
            deploy_kwargs['username'] = config.get_cloud_config_value(
                'win_username', vm_, __opts__, default='Administrator')
            deploy_kwargs['password'] = config.get_cloud_config_value(
                'win_password', vm_, __opts__, default='')

        # Store what was used to the deploy the VM
        ret['deploy_kwargs'] = deploy_kwargs

        deployed = False
        if win_installer:
            deployed = salt.utils.cloud.deploy_windows(**deploy_kwargs)
        else:
            deployed = salt.utils.cloud.deploy_script(**deploy_kwargs)

        if deployed:
            log.info('Salt installed on {name}'.format(**vm_))
        else:
            log.error('Failed to start Salt on Cloud VM {name}'.format(**vm_))

    ret.update(data.__dict__)

    log.info('Created Cloud VM {0[name]!r}'.format(vm_))
    log.debug('{0[name]!r} VM creation details:\n{1}'.format(
        vm_, pprint.pformat(data.__dict__)))

    volumes = config.get_cloud_config_value('volumes',
                                            vm_,
                                            __opts__,
                                            search_global=True)
    if volumes:
        log.info('Create and attach volumes to node {0}'.format(data.name))
        create_attach_volumes(volumes, location, data)

    return ret
Ejemplo n.º 55
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']) is False:
            return False
    except AttributeError:
        pass

    # Since using "provider: <provider-engine>" is deprecated, alias provider
    # to use driver: "driver: <provider-engine>"
    if 'provider' in vm_:
        vm_['driver'] = vm_.pop('provider')

    salt.utils.cloud.fire_event(
        'event',
        'starting create',
        'salt/cloud/{0}/creating'.format(vm_['name']),
        {
            'name': vm_['name'],
            'profile': vm_['profile'],
            'provider': vm_['driver'],
        },
        transport=__opts__['transport']
    )

    log.info('Creating Cloud VM {0}'.format(vm_['name']))
    conn = get_conn()

    salt.utils.cloud.fire_event(
        'event',
        'requesting instance',
        'salt/cloud/{0}/requesting'.format(vm_['name']),
        {'kwargs': vm_},
        transport=__opts__['transport']
    )

    folder = config.get_cloud_config_value(
        'folder', vm_, __opts__, default=None
    )
    resourcepool = config.get_cloud_config_value(
        'resourcepool', vm_, __opts__, default=None
    )
    datastore = config.get_cloud_config_value(
        'datastore', vm_, __opts__, default=None
    )
    host = config.get_cloud_config_value(
        'host', vm_, __opts__, default=None
    )
    template = config.get_cloud_config_value(
        'template', vm_, __opts__, default=False
    )

    clone_kwargs = {
        'name': vm_['name'],
        'folder': folder,
        'resourcepool': resourcepool,
        'datastore': datastore,
        'host': host,
        'template': template,
    }
    log.debug('clone_kwargs are set to {0}'.format(
        pprint.pformat(clone_kwargs))
    )

    try:
        template = conn.get_vm_by_name(vm_['image'])
        new_instance = template.clone(**clone_kwargs)
        data = new_instance.get_properties()  # pylint: disable=W0612
    except Exception as exc:  # pylint: disable=W0703
        log.error(
            'Error creating {0} on vSphere\n\n'
            'The following exception was thrown when trying to '
            'run the initial deployment: \n{1}'.format(
                vm_['name'], str(exc)
            ),
            # Show the traceback if the debug logging level is enabled
            exc_info_on_loglevel=logging.DEBUG
        )
        return False

    deploy_kwargs = None
    if config.get_cloud_config_value('deploy', vm_, __opts__) is True:
        deploy_kwargs = _deploy(vm_)

    ret = show_instance(name=vm_['name'], call='action')
    show_deploy_args = config.get_cloud_config_value(
        'show_deploy_args', vm_, __opts__, default=False
    )
    if show_deploy_args:
        ret['deploy_kwargs'] = deploy_kwargs

    log.info('Created Cloud VM \'{0[name]}\''.format(vm_))
    log.debug(
        '\'{0[name]}\' VM creation details:\n{1}'.format(
            vm_, pprint.pformat(ret)
        )
    )

    salt.utils.cloud.fire_event(
        'event',
        'created instance',
        'salt/cloud/{0}/created'.format(vm_['name']),
        {
            'name': vm_['name'],
            'profile': vm_['profile'],
            'provider': vm_['driver'],
        },
        transport=__opts__['transport']
    )
    return ret
Ejemplo n.º 56
0
def create(vm_):
    '''
    Create a single Linode VM.
    '''
    try:
        # Check for required profile parameters before sending any API calls.
        if vm_['profile'] and config.is_profile_configured(
                __opts__, __active_provider_name__ or 'linode',
                vm_['profile']) is False:
            return False
    except AttributeError:
        pass

    # Since using "provider: <provider-engine>" is deprecated, alias provider
    # to use driver: "driver: <provider-engine>"
    if 'provider' in vm_:
        vm_['driver'] = vm_.pop('provider')

    salt.utils.cloud.fire_event('event',
                                'starting create',
                                'salt/cloud/{0}/creating'.format(vm_['name']),
                                {
                                    'name': vm_['name'],
                                    'profile': vm_['profile'],
                                    'provider': vm_['driver'],
                                },
                                transport=__opts__['transport'])

    log.info('Creating Cloud VM {0}'.format(vm_['name']))

    data = {}
    kwargs = {
        'name': vm_['name'],
        'image': vm_['image'],
        'size': vm_['size'],
    }

    plan_id = get_plan_id(vm_['size'])
    try:
        datacenter_id = get_datacenter_id(vm_['location'])
    except KeyError:
        # Linode's default datacenter is Dallas, but we still have to set one to
        # use the create function from Linode's API. Dallas's datacenter id is 2.
        datacenter_id = 2

    if 'clonefrom' in vm_:
        linode_id = get_linode_id_from_name(vm_['clonefrom'])
        clone_source = get_linode(linode_id)

        kwargs.update({'clonefrom': vm_['clonefrom']})
        kwargs['image'] = 'Clone of {0}'.format(vm_['clonefrom'])
        kwargs['size'] = clone_source['TOTALRAM']

        try:
            result = clone(linode_id, datacenter_id, plan_id)
        except Exception:
            log.error(
                'Error cloning {0} on Linode\n\n'
                'The following exception was thrown by Linode when trying to '
                'clone the specified machine:\n'.format(vm_['clonefrom']),
                exc_info_on_loglevel=logging.DEBUG)
            return False
    else:
        try:
            result = _query('linode',
                            'create',
                            args={
                                'PLANID': plan_id,
                                'DATACENTERID': datacenter_id
                            })
        except Exception:
            log.error(
                'Error creating {0} on Linode\n\n'
                'The following exception was thrown by Linode when trying to '
                'run the initial deployment:\n'.format(vm_['name']),
                exc_info_on_loglevel=logging.DEBUG)
            return False

    salt.utils.cloud.fire_event('event',
                                'requesting instance',
                                'salt/cloud/{0}/requesting'.format(
                                    vm_['name']), {'kwargs': kwargs},
                                transport=__opts__['transport'])

    node_id = _clean_data(result)['LinodeID']
    data['id'] = node_id

    if not _wait_for_status(node_id,
                            status=(_get_status_id_by_name('brand_new'))):
        log.error('Error creating {0} on LINODE\n\n'
                  'while waiting for initial ready status'.format(vm_['name']),
                  exc_info_on_loglevel=logging.DEBUG)

    # Update the Linode's Label to reflect the given VM name
    update_linode(node_id, update_args={'Label': vm_['name']})
    log.debug('Set name for {0} - was linode{1}.'.format(vm_['name'], node_id))

    # Create disks and get ids
    log.debug('Creating disks for {0}'.format(vm_['name']))
    root_disk_id = create_disk_from_distro(vm_, node_id)['DiskID']
    swap_disk_id = create_swap_disk(vm_, node_id)['DiskID']

    # Add private IP address if requested
    if get_private_ip(vm_):
        create_private_ip(vm_, node_id)

    # Create a ConfigID using disk ids
    config_id = create_config(vm_, node_id, root_disk_id,
                              swap_disk_id)['ConfigID']

    # Boot the VM and get the JobID from Linode
    boot_job_id = boot(node_id, config_id)['JobID']

    if not _wait_for_job(node_id, boot_job_id):
        log.error('Boot failed for {0}.'.format(vm_['name']))
        return False

    node_data = get_linode(node_id)
    ips = get_ips(node_id)
    state = int(node_data['STATUS'])

    data['image'] = vm_['image']
    data['name'] = node_data['LABEL']
    data['size'] = node_data['TOTALRAM']
    data['state'] = _get_status_descr_by_id(state)
    data['private_ips'] = ips['private_ips']
    data['public_ips'] = ips['public_ips']

    vm_['ssh_host'] = data['public_ips'][0]

    # If a password wasn't supplied in the profile or provider config, set it now.
    vm_['password'] = get_password(vm_)

    # Bootstrap!
    ret = salt.utils.cloud.bootstrap(vm_, __opts__)

    ret.update(data)

    log.info('Created Cloud VM {0[name]!r}'.format(vm_))
    log.debug('{0[name]!r} VM creation details:\n{1}'.format(
        vm_, pprint.pformat(data)))

    salt.utils.cloud.fire_event('event',
                                'created instance',
                                'salt/cloud/{0}/created'.format(vm_['name']), {
                                    'name': vm_['name'],
                                    'profile': vm_['profile'],
                                    'provider': vm_['driver'],
                                },
                                transport=__opts__['transport'])

    return ret
Ejemplo n.º 57
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
                                         'profitbricks'),
                                        vm_['profile']) is False):
            return False
    except AttributeError:
        pass

    data = None
    datacenter_id = get_datacenter_id()
    conn = get_conn()

    # Assemble list of network interfaces from the cloud profile config.
    nics = _get_nics(vm_)

    # Assemble list of volumes from the cloud profile config.
    volumes = [_get_system_volume(vm_)]
    if 'volumes' in vm_:
        volumes.extend(_get_data_volumes(vm_))

    # Assembla the composite server object.
    server = _get_server(vm_, volumes, nics)

    __utils__['cloud.fire_event'](
        'event',
        'requesting instance',
        'salt/cloud/{0}/requesting'.format(vm_['name']),
        args={'name': vm_['name']},
        sock_dir=__opts__['sock_dir'],
        transport=__opts__['transport']
    )

    try:
        data = conn.create_server(datacenter_id=datacenter_id, server=server)
        log.info('Create server request ID: {0}'.format(data['requestId']),
                 exc_info_on_loglevel=logging.DEBUG)

        _wait_for_completion(conn, data, get_wait_timeout(vm_),
                             'create_server')
    except Exception as exc:  # pylint: disable=W0703
        log.error(
            'Error creating {0} on ProfitBricks\n\n'
            'The following exception was thrown by the profitbricks library '
            'when trying to run the initial deployment: \n{1}'.format(
                vm_['name'], exc
            ),
            exc_info_on_loglevel=logging.DEBUG
        )
        return False

    vm_['server_id'] = data['id']

    def __query_node_data(vm_, data):
        '''
        Query node data until node becomes available.
        '''
        running = False
        try:
            data = show_instance(vm_['name'], 'action')
            if not data:
                return False
            log.debug(
                'Loaded node data for {0}:\nname: {1}\nstate: {2}'.format(
                    vm_['name'],
                    pprint.pformat(data['name']),
                    data['vmState']
                )
            )
        except Exception as err:
            log.error(
                'Failed to get nodes list: {0}'.format(
                    err
                ),
                # Show the trackback if the debug logging level is enabled
                exc_info_on_loglevel=logging.DEBUG
            )
            # Trigger a failure in the wait for IP function
            return False

        running = data['vmState'] == 'RUNNING'
        if not running:
            # Still not running, trigger another iteration
            return

        if ssh_interface(vm_) == 'private_lan' and data['private_ips']:
            vm_['ssh_host'] = data['private_ips'][0]

        if ssh_interface(vm_) != 'private_lan' and data['public_ips']:
            vm_['ssh_host'] = data['public_ips'][0]

        return data

    try:
        data = salt.utils.cloud.wait_for_ip(
            __query_node_data,
            update_args=(vm_, data),
            timeout=config.get_cloud_config_value(
                'wait_for_ip_timeout', vm_, __opts__, default=10 * 60),
            interval=config.get_cloud_config_value(
                'wait_for_ip_interval', vm_, __opts__, default=10),
        )
    except (SaltCloudExecutionTimeout, SaltCloudExecutionFailure) as exc:
        try:
            # It might be already up, let's destroy it!
            destroy(vm_['name'])
        except SaltCloudSystemExit:
            pass
        finally:
            raise SaltCloudSystemExit(str(exc.message))

    log.debug('VM is now running')
    log.info('Created Cloud VM {0}'.format(vm_))
    log.debug(
        '{0} VM creation details:\n{1}'.format(
            vm_, pprint.pformat(data)
        )
    )

    __utils__['cloud.fire_event'](
        'event',
        'created instance',
        'salt/cloud/{0}/created'.format(vm_['name']),
        args={
            'name': vm_['name'],
            'profile': vm_['profile'],
            'provider': vm_['driver'],
        },
        sock_dir=__opts__['sock_dir'],
        transport=__opts__['transport']
    )

    if 'ssh_host' in vm_:
        vm_['key_filename'] = get_key_filename(vm_)
        ret = __utils__['cloud.bootstrap'](vm_, __opts__)
        ret.update(data)
        return ret
    else:
        raise SaltCloudSystemExit('A valid IP address was not found.')
Ejemplo n.º 58
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 "profitbricks"),
                vm_["profile"]) is False):
            return False
    except AttributeError:
        pass

    if "image_alias" in vm_ and not version_compatible("4.0"):
        raise SaltCloudNotFound(
            "The 'image_alias' parameter requires the profitbricks "
            "SDK v4.0.0 or greater.")

    if "image" not in vm_ and "image_alias" not in vm_:
        log.error("The image or image_alias parameter is required.")

    signal_event(vm_, "creating", "starting create")

    data = None
    datacenter_id = get_datacenter_id()
    conn = get_conn()

    # Assemble list of network interfaces from the cloud profile config.
    nics = _get_nics(vm_)

    # Assemble list of volumes from the cloud profile config.
    volumes = [_get_system_volume(vm_)]
    if "volumes" in vm_:
        volumes.extend(_get_data_volumes(vm_))

    # Assembla the composite server object.
    server = _get_server(vm_, volumes, nics)

    signal_event(vm_, "requesting", "requesting instance")

    try:
        data = conn.create_server(datacenter_id=datacenter_id, server=server)
        log.info(
            "Create server request ID: %s",
            data["requestId"],
            exc_info_on_loglevel=logging.DEBUG,
        )

        _wait_for_completion(conn, data, get_wait_timeout(vm_),
                             "create_server")
    except PBError as exc:
        log.error(
            "Error creating %s on ProfitBricks\n\n"
            "The following exception was thrown by the profitbricks library "
            "when trying to run the initial deployment: \n%s",
            vm_["name"],
            exc,
            exc_info_on_loglevel=logging.DEBUG,
        )
        return False
    except Exception as exc:  # pylint: disable=W0703
        log.error(
            "Error creating %s \n\nError: \n%s",
            vm_["name"],
            exc,
            exc_info_on_loglevel=logging.DEBUG,
        )
        return False

    vm_["server_id"] = data["id"]

    def __query_node_data(vm_, data):
        """
        Query node data until node becomes available.
        """
        running = False
        try:
            data = show_instance(vm_["name"], "action")
            if not data:
                return False
            log.debug(
                "Loaded node data for %s:\nname: %s\nstate: %s",
                vm_["name"],
                pprint.pformat(data["name"]),
                data["state"],
            )
        except Exception as err:  # pylint: disable=broad-except
            log.error(
                "Failed to get nodes list: %s",
                err,
                # Show the trackback if the debug logging level is enabled
                exc_info_on_loglevel=logging.DEBUG,
            )
            # Trigger a failure in the wait for IP function
            return False

        running = data["state"] == "RUNNING"
        if not running:
            # Still not running, trigger another iteration
            return

        if ssh_interface(vm_) == "private_lan" and data["private_ips"]:
            vm_["ssh_host"] = data["private_ips"][0]

        if ssh_interface(vm_) != "private_lan" and data["public_ips"]:
            vm_["ssh_host"] = data["public_ips"][0]

        return data

    try:
        data = salt.utils.cloud.wait_for_ip(
            __query_node_data,
            update_args=(vm_, data),
            timeout=config.get_cloud_config_value("wait_for_ip_timeout",
                                                  vm_,
                                                  __opts__,
                                                  default=10 * 60),
            interval=config.get_cloud_config_value("wait_for_ip_interval",
                                                   vm_,
                                                   __opts__,
                                                   default=10),
        )
    except (SaltCloudExecutionTimeout, SaltCloudExecutionFailure) as exc:
        try:
            # It might be already up, let's destroy it!
            destroy(vm_["name"])
        except SaltCloudSystemExit:
            pass
        finally:
            raise SaltCloudSystemExit(str(exc.message))

    log.debug("VM is now running")
    log.info("Created Cloud VM %s", vm_)
    log.debug("%s VM creation details:\n%s", vm_, pprint.pformat(data))

    signal_event(vm_, "created", "created instance")

    if "ssh_host" in vm_:
        vm_["key_filename"] = get_key_filename(vm_)
        ret = __utils__["cloud.bootstrap"](vm_, __opts__)
        ret.update(data)
        return ret
    else:
        raise SaltCloudSystemExit("A valid IP address was not found.")
Ejemplo n.º 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 'softlayer',
                                                           vm_['profile'],
                                                           vm_=vm_) is False:
            return False
    except AttributeError:
        pass

    # Since using "provider: <provider-engine>" is deprecated, alias provider
    # to use driver: "driver: <provider-engine>"
    if 'provider' in vm_:
        vm_['driver'] = vm_.pop('provider')

    name = vm_['name']
    hostname = name
    domain = config.get_cloud_config_value(
        'domain', vm_, __opts__, default=None
    )
    if domain is None:
        SaltCloudSystemExit(
            'A domain name is required for the SoftLayer driver.'
        )

    if vm_.get('use_fqdn'):
        name = '.'.join([name, domain])
        vm_['name'] = name

    __utils__['cloud.fire_event'](
        'event',
        'starting create',
        'salt/cloud/{0}/creating'.format(name),
        args={
            'name': name,
            'profile': vm_['profile'],
            'provider': vm_['driver'],
        },
        sock_dir=__opts__['sock_dir'],
        transport=__opts__['transport']
    )

    log.info('Creating Cloud VM {0}'.format(name))
    conn = get_conn()
    kwargs = {
        'hostname': hostname,
        'domain': domain,
        'startCpus': vm_['cpu_number'],
        'maxMemory': vm_['ram'],
        'hourlyBillingFlag': vm_['hourly_billing'],
    }

    local_disk_flag = config.get_cloud_config_value(
        'local_disk', vm_, __opts__, default=False
    )
    kwargs['localDiskFlag'] = local_disk_flag

    if 'image' in vm_:
        kwargs['operatingSystemReferenceCode'] = vm_['image']
        kwargs['blockDevices'] = []
        disks = vm_['disk_size']

        if isinstance(disks, int):
            disks = [str(disks)]
        elif isinstance(disks, str):
            disks = [size.strip() for size in disks.split(',')]

        count = 0
        for disk in disks:
            # device number '1' is reserved for the SWAP disk
            if count == 1:
                count += 1
            block_device = {'device': str(count),
                            'diskImage': {'capacity': str(disk)}}
            kwargs['blockDevices'].append(block_device)
            count += 1

            # Upper bound must be 5 as we're skipping '1' for the SWAP disk ID
            if count > 5:
                log.warning('More that 5 disks were specified for {0} .'
                            'The first 5 disks will be applied to the VM, '
                            'but the remaining disks will be ignored.\n'
                            'Please adjust your cloud configuration to only '
                            'specify a maximum of 5 disks.'.format(name))
                break

    elif 'global_identifier' in vm_:
        kwargs['blockDeviceTemplateGroup'] = {
            'globalIdentifier': vm_['global_identifier']
        }

    location = get_location(vm_)
    if location:
        kwargs['datacenter'] = {'name': location}

    private_vlan = config.get_cloud_config_value(
        'private_vlan', vm_, __opts__, default=False
    )
    if private_vlan:
        kwargs['primaryBackendNetworkComponent'] = {
            'networkVlan': {
                'id': private_vlan,
            }
        }

    private_network = config.get_cloud_config_value(
        'private_network', vm_, __opts__, default=False
    )
    if bool(private_network) is True:
        kwargs['privateNetworkOnlyFlag'] = 'True'

    public_vlan = config.get_cloud_config_value(
        'public_vlan', vm_, __opts__, default=False
    )
    if public_vlan:
        kwargs['primaryNetworkComponent'] = {
            'networkVlan': {
                'id': public_vlan,
            }
        }

    max_net_speed = config.get_cloud_config_value(
        'max_net_speed', vm_, __opts__, default=10
    )
    if max_net_speed:
        kwargs['networkComponents'] = [{
            'maxSpeed': int(max_net_speed)
        }]

    post_uri = config.get_cloud_config_value(
        'post_uri', vm_, __opts__, default=None
    )
    if post_uri:
        kwargs['postInstallScriptUri'] = post_uri

    __utils__['cloud.fire_event'](
        'event',
        'requesting instance',
        'salt/cloud/{0}/requesting'.format(name),
        args={'kwargs': kwargs},
        sock_dir=__opts__['sock_dir'],
        transport=__opts__['transport']
    )

    try:
        response = conn.createObject(kwargs)
    except Exception as exc:
        log.error(
            'Error creating {0} on SoftLayer\n\n'
            'The following exception was thrown when trying to '
            'run the initial deployment: \n{1}'.format(
                name, str(exc)
            ),
            # Show the traceback if the debug logging level is enabled
            exc_info_on_loglevel=logging.DEBUG
        )
        return False

    ip_type = 'primaryIpAddress'
    private_ssh = config.get_cloud_config_value(
        'private_ssh', vm_, __opts__, default=False
    )
    private_wds = config.get_cloud_config_value(
        'private_windows', vm_, __opts__, default=False
    )
    if private_ssh or private_wds or public_vlan is None or public_vlan is False:
        ip_type = 'primaryBackendIpAddress'

    def wait_for_ip():
        '''
        Wait for the IP address to become available
        '''
        nodes = list_nodes_full()
        if ip_type in nodes[hostname]:
            return nodes[hostname][ip_type]
        time.sleep(1)
        return False

    ip_address = salt.utils.cloud.wait_for_fun(
        wait_for_ip,
        timeout=config.get_cloud_config_value(
            'wait_for_fun_timeout', vm_, __opts__, default=15 * 60),
    )
    if config.get_cloud_config_value('deploy', vm_, __opts__) is not True:
        return show_instance(hostname, call='action')

    SSH_PORT = 22
    WINDOWS_DS_PORT = 445
    managing_port = SSH_PORT
    if config.get_cloud_config_value('windows', vm_, __opts__) or \
            config.get_cloud_config_value('win_installer', vm_, __opts__):
        managing_port = WINDOWS_DS_PORT

    ssh_connect_timeout = config.get_cloud_config_value(
        'ssh_connect_timeout', vm_, __opts__, 15 * 60
    )
    connect_timeout = config.get_cloud_config_value(
        'connect_timeout', vm_, __opts__, ssh_connect_timeout
    )
    if not salt.utils.cloud.wait_for_port(ip_address,
                                          port=managing_port,
                                          timeout=connect_timeout):
        raise SaltCloudSystemExit(
            'Failed to authenticate against remote ssh'
        )

    pass_conn = get_conn(service='SoftLayer_Account')
    mask = {
        'virtualGuests': {
            'powerState': '',
            'operatingSystem': {
                'passwords': ''
            },
        },
    }

    def get_credentials():
        '''
        Wait for the password to become available
        '''
        node_info = pass_conn.getVirtualGuests(id=response['id'], mask=mask)
        for node in node_info:
            if node['id'] == response['id'] and \
                            'passwords' in node['operatingSystem'] and \
                            len(node['operatingSystem']['passwords']) > 0:
                return node['operatingSystem']['passwords'][0]['username'], node['operatingSystem']['passwords'][0]['password']
        time.sleep(5)
        return False

    username, passwd = salt.utils.cloud.wait_for_fun(  # pylint: disable=W0633
        get_credentials,
        timeout=config.get_cloud_config_value(
            'wait_for_fun_timeout', vm_, __opts__, default=15 * 60),
    )
    response['username'] = username
    response['password'] = passwd
    response['public_ip'] = ip_address

    ssh_username = config.get_cloud_config_value(
        'ssh_username', vm_, __opts__, default=username
    )

    vm_['ssh_host'] = ip_address
    vm_['password'] = passwd
    ret = __utils__['cloud.bootstrap'](vm_, __opts__)

    ret.update(response)

    __utils__['cloud.fire_event'](
        'event',
        'created instance',
        'salt/cloud/{0}/created'.format(name),
        args={
            'name': name,
            'profile': vm_['profile'],
            'provider': vm_['driver'],
        },
        sock_dir=__opts__['sock_dir'],
        transport=__opts__['transport']
    )

    return ret
Ejemplo n.º 60
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

    # Since using "provider: <provider-engine>" is deprecated, alias provider
    # to use driver: "driver: <provider-engine>"
    if 'provider' in vm_:
        vm_['driver'] = vm_.pop('provider')

    salt.utils.cloud.fire_event('event',
                                'starting create',
                                'salt/cloud/{0}/creating'.format(vm_['name']),
                                {
                                    'name': vm_['name'],
                                    'profile': vm_['profile'],
                                    'provider': vm_['driver'],
                                },
                                transport=__opts__['transport'])

    log.info('Creating Cloud VM %s', vm_['name'])
    conn = get_conn()
    rootPw = NodeAuthPassword(vm_['auth'])

    try:
        location = conn.ex_get_location_by_id(vm_['location'])
        images = conn.list_images(location=location)
        image = [x for x in images if x.id == vm_['image']][0]
        networks = conn.ex_list_network_domains(location=location)
        network_domain = [
            y for y in networks if y.name == vm_['network_domain']
        ][0]
        # Use the first VLAN in the network domain
        vlan = conn.ex_list_vlans(location=location,
                                  network_domain=network_domain)[0]
        kwargs = {
            'name': vm_['name'],
            'image': image,
            'auth': rootPw,
            'ex_description': vm_['description'],
            'ex_network_domain': network_domain,
            'ex_vlan': vlan,
            'ex_is_started': vm_['is_started']
        }
        data = conn.create_node(**kwargs)
    except Exception as exc:
        log.error(
            'Error creating %s on DIMENSIONDATA\n\n'
            'The following exception was thrown by libcloud when trying to '
            'run the initial deployment: \n%s',
            vm_['name'],
            exc,
            exc_info_on_loglevel=logging.DEBUG)
        return False

    def __query_node_data(vm_, data):
        running = False
        try:
            node = show_instance(vm_['name'], 'action')
            running = (node['state'] == NodeState.RUNNING)
            log.debug('Loaded node data for %s:\nname: %s\nstate: %s',
                      vm_['name'], pprint.pformat(node['name']), node['state'])
        except Exception as err:
            log.error(
                'Failed to get nodes list: %s',
                err,
                # Show the traceback if the debug logging level is enabled
                exc_info_on_loglevel=logging.DEBUG)
            # Trigger a failure in the wait for IP function
            return False

        if not running:
            # Still not running, trigger another iteration
            return

        private = node['private_ips']
        public = node['public_ips']

        if private and not public:
            log.warning('Private IPs returned, but not public... Checking for '
                        'misidentified IPs')
            for private_ip in private:
                private_ip = preferred_ip(vm_, [private_ip])
                if salt.utils.cloud.is_public_ip(private_ip):
                    log.warning('%s is a public IP', private_ip)
                    data.public_ips.append(private_ip)
                else:
                    log.warning('%s is a private IP', private_ip)
                    if private_ip not in data.private_ips:
                        data.private_ips.append(private_ip)

            if ssh_interface(vm_) == 'private_ips' and data.private_ips:
                return data

        if private:
            data.private_ips = private
            if ssh_interface(vm_) == 'private_ips':
                return data

        if public:
            data.public_ips = public
            if ssh_interface(vm_) != 'private_ips':
                return data

        log.debug('DATA')
        log.debug(data)

    try:
        data = salt.utils.cloud.wait_for_ip(
            __query_node_data,
            update_args=(vm_, data),
            timeout=config.get_cloud_config_value('wait_for_ip_timeout',
                                                  vm_,
                                                  __opts__,
                                                  default=25 * 60),
            interval=config.get_cloud_config_value('wait_for_ip_interval',
                                                   vm_,
                                                   __opts__,
                                                   default=30),
            max_failures=config.get_cloud_config_value(
                'wait_for_ip_max_failures', vm_, __opts__, default=60),
        )
    except (SaltCloudExecutionTimeout, SaltCloudExecutionFailure) as exc:
        try:
            # It might be already up, let's destroy it!
            destroy(vm_['name'])
        except SaltCloudSystemExit:
            pass
        finally:
            raise SaltCloudSystemExit(str(exc))

    log.debug('VM is now running')
    if ssh_interface(vm_) == 'private_ips':
        ip_address = preferred_ip(vm_, data.private_ips)
    else:
        ip_address = preferred_ip(vm_, data.public_ips)
    log.debug('Using IP address %s', ip_address)

    if salt.utils.cloud.get_salt_interface(vm_, __opts__) == 'private_ips':
        salt_ip_address = preferred_ip(vm_, data.private_ips)
        log.info('Salt interface set to: %s', salt_ip_address)
    else:
        salt_ip_address = preferred_ip(vm_, data.public_ips)
        log.debug('Salt interface set to: %s', salt_ip_address)

    if not ip_address:
        raise SaltCloudSystemExit('No IP addresses could be found.')

    vm_['salt_host'] = salt_ip_address
    vm_['ssh_host'] = ip_address
    vm_['password'] = vm_['auth']

    ret = salt.utils.cloud.bootstrap(vm_, __opts__)

    ret.update(data.__dict__)

    if 'password' in data.extra:
        del data.extra['password']

    log.info('Created Cloud VM \'{0[name]}\''.format(vm_))
    log.debug('\'{0[name]}\' VM creation details:\n{1}'.format(
        vm_, pprint.pformat(data.__dict__)))

    salt.utils.cloud.fire_event('event',
                                'created instance',
                                'salt/cloud/{0}/created'.format(vm_['name']), {
                                    'name': vm_['name'],
                                    'profile': vm_['profile'],
                                    'provider': vm_['driver'],
                                },
                                transport=__opts__['transport'])

    return ret