Ejemplo n.º 1
0
def _assign_floating_ips(vm_, conn, kwargs):
    floating = []
    nets = config.get_cloud_config_value('networks',
                                         vm_,
                                         __opts__,
                                         search_global=False)

    if HAS014:
        if nets is not None:
            for net in nets:
                if 'fixed' in net:
                    kwargs['networks'] = [
                        OpenStackNetwork(n, None, None, None)
                        for n in net['fixed']
                    ]
                elif 'floating' in net:
                    pool = OpenStack_1_1_FloatingIpPool(
                        net['floating'], conn.connection)
                    try:
                        floating.append(pool.create_floating_ip())
                    except Exception as e:
                        log.debug(
                            'Cannot allocate IP from floating pool \'%s\'. Checking for unassociated ips.',
                            net['floating'])
                        for idx in pool.list_floating_ips():
                            if idx.node_id is None:
                                floating.append(idx)
                                break
                    if not floating:
                        raise SaltCloudSystemExit(
                            'There are no more floating IP addresses '
                            'available, please create some more')
        # otherwise, attempt to obtain list without specifying pool
        # this is the same as 'nova floating-ip-list'
        elif ssh_interface(vm_) != 'private_ips':
            try:
                # This try/except is here because it appears some
                # OpenStack providers return a 404 Not Found for the
                # floating ip pool URL if there are no pools setup
                pool = OpenStack_1_1_FloatingIpPool('', conn.connection)
                try:
                    floating.append(pool.create_floating_ip())
                except Exception as e:
                    log.debug(
                        'Cannot allocate IP from the default floating pool. Checking for unassociated ips.'
                    )
                    for idx in pool.list_floating_ips():
                        if idx.node_id is None:
                            floating.append(idx)
                            break
                if not floating:
                    log.warning(
                        'There are no more floating IP addresses '
                        'available, please create some more if necessary')
            except Exception as e:
                if str(e).startswith('404'):
                    pass
                else:
                    raise
    return floating
Ejemplo n.º 2
0
 def _to_lc_network(self, net):
     from libcloud.compute.drivers.openstack import OpenStackNetwork
     return OpenStackNetwork(id=net['id'],
                             name=net['name'],
                             cidr=net.get('cidr', None),
                             extra=net,
                             driver=self)
Ejemplo n.º 3
0
    def create_node(self, image, flavor, name, public_key_file,
                    networks=None, progress=None):
        create_kwargs = {}
        if networks:
            fake_networks = [OpenStackNetwork(n, None, None, self)
                             for n in networks]
            create_kwargs['networks'] = fake_networks

        conn = self._get_conn()
        fake_image = NodeImage(id=image, name=None, driver=conn)
        fake_flavor = NodeSize(id=flavor, name=None, ram=None, disk=None,
                               bandwidth=None, price=None, driver=conn)

        if progress:
            progress.write("Creating node {0} (image: {1}, flavor: {2})...\n"
                           .format(name, image, flavor))

        node = conn.create_node(name=name, image=fake_image,
                                size=fake_flavor, ex_files={
                                    "/root/.ssh/authorized_keys":
                                    public_key_file.read()
                                },
                                **create_kwargs)
        password = node.extra.get("password")

        if progress:
            progress.write("Created node {0} (id: {1}, password: {2})\n"
                           .format(name, node.id, password))

        return self._wait_for_node_to_become_active_host(conn,
                                                         node,
                                                         progress=progress)
Ejemplo n.º 4
0
def networks(vm_, kwargs=None):
    conn = get_conn()
    if kwargs is None:
        kwargs = {}
    networks = config.get_cloud_config_value('networks',
                                             vm_,
                                             __opts__,
                                             search_global=False)

    floating = []

    if HAS014:
        if networks is not None:
            for net in networks:
                if 'fixed' in net:
                    kwargs['networks'] = [
                        OpenStackNetwork(n, None, None, None)
                        for n in net['fixed']
                    ]
                elif 'floating' in net:
                    pool = OpenStack_1_1_FloatingIpPool(
                        net['floating'], conn.connection)
                    for idx in pool.list_floating_ips():
                        if idx.node_id is None:
                            floating.append(idx)
                    if not floating:
                        # Note(pabelanger): We have no available floating IPs.
                        # For now, we raise an exception and exit.
                        # A future enhancement might be to allow salt-cloud
                        # to dynamically allocate new address but that might
                        raise SaltCloudSystemExit(
                            'Floating pool {0!r} does not have any more '
                            'please create some more or use a different '
                            'pool.'.format(net['floating']))
        # otherwise, attempt to obtain list without specifying pool
        # this is the same as 'nova floating-ip-list'
        elif ssh_interface(vm_) != 'private_ips':
            try:
                # This try/except is here because it appears some
                # *cough* Rackspace *cough*
                # OpenStack providers return a 404 Not Found for the
                # floating ip pool URL if there are no pools setup
                pool = OpenStack_1_1_FloatingIpPool('', conn.connection)
                for idx in pool.list_floating_ips():
                    if idx.node_id is None:
                        floating.append(idx)
                if not floating:
                    # Note(pabelanger): We have no available floating IPs.
                    # For now, we raise an exception and exit.
                    # A future enhancement might be to allow salt-cloud to
                    # dynamically allocate new address but that might be
                    # tricky to manage.
                    raise SaltCloudSystemExit(
                        'There are no more floating IP addresses '
                        'available, please create some more')
            except Exception as e:
                if not str(e).startswith('404'):
                    raise
    vm_['floating'] = floating
Ejemplo n.º 5
0
def _to_lc_network(driver, network, subnet):
    from libcloud.compute.drivers.openstack import OpenStackNetwork
    lc_network = OpenStackNetwork(network['id'], network['name'],
                                  subnet['cidr'], driver, {
                                      "network": network,
                                      "subnet": subnet
                                  })
    return lc_network
Ejemplo n.º 6
0
def _assign_floating_ips(vm_, conn, kwargs):
    floating = []
    nets = config.get_cloud_config_value(
        'networks', vm_, __opts__, search_global=False
    )

    if HAS014:
        if nets is not None:
            for net in nets:
                if 'fixed' in net:
                    kwargs['networks'] = [
                        OpenStackNetwork(n, None, None, None)
                        for n in net['fixed']
                    ]
                elif 'floating' in net:
                    pool = OpenStack_1_1_FloatingIpPool(
                        net['floating'], conn.connection
                    )
                    for idx in pool.list_floating_ips():
                        if idx.node_id is None:
                            floating.append(idx)
                    if not floating:
                        try:
                            floating.append(pool.create_floating_ip())
                        except Exception as e:
                            raise SaltCloudSystemExit(
                                'Floating pool \'{0}\' does not have any more '
                                'please create some more or use a different '
                                'pool.'.format(net['floating'])
                            )
        # otherwise, attempt to obtain list without specifying pool
        # this is the same as 'nova floating-ip-list'
        elif ssh_interface(vm_) != 'private_ips':
            try:
                # This try/except is here because it appears some
                # *cough* Rackspace *cough*
                # OpenStack providers return a 404 Not Found for the
                # floating ip pool URL if there are no pools setup
                pool = OpenStack_1_1_FloatingIpPool(
                    '', conn.connection
                )
                for idx in pool.list_floating_ips():
                    if idx.node_id is None:
                        floating.append(idx)
                if not floating:
                    try:
                        floating.append(pool.create_floating_ip())
                    except Exception as e:
                        raise SaltCloudSystemExit(
                            'There are no more floating IP addresses '
                            'available, please create some more'
                        )
            except Exception as e:
                if str(e).startswith('404'):
                    pass
                else:
                    raise
    return floating
Ejemplo n.º 7
0
    def test_list_networks_returns_network_information(self):
        conn = mock.Mock()
        api = self._get_api_with_mocked_conn(conn)

        network1 = OpenStackNetwork(id="abcdef",
                                    cidr="192.168.0.0/16",
                                    name="awesome network",
                                    driver=None)
        conn.ex_list_networks.return_value = [network1]

        self.assertEquals([{
            'id': network1.id,
            'name': network1.name,
            'cidr': network1.cidr
        }], api.list_networks())
Ejemplo n.º 8
0
def request_instance(vm_=None, call=None):
    '''
    Put together all of the information necessary to request an instance on Openstack
    and then fire off the request the instance.

    Returns data about the instance
    '''
    if call == 'function':
        # Technically this function may be called other ways too, but it
        # definitely cannot be called with --function.
        raise SaltCloudSystemExit(
            'The request_instance action must be called with -a or --action.')
    salt.utils.cloud.check_name(vm_['name'], 'a-zA-Z0-9._-')
    conn = get_conn()
    kwargs = {'name': vm_['name']}

    try:
        kwargs['image'] = get_image(conn, vm_)
    except Exception as exc:
        raise SaltCloudSystemExit('Error creating {0} on OPENSTACK\n\n'
                                  'Could not find image {1}: {2}\n'.format(
                                      vm_['name'], vm_['image'], exc))

    try:
        kwargs['size'] = get_size(conn, vm_)
    except Exception as exc:
        raise SaltCloudSystemExit('Error creating {0} on OPENSTACK\n\n'
                                  'Could not find size {1}: {2}\n'.format(
                                      vm_['name'], vm_['size'], exc))

    # Note: This currently requires libcloud trunk
    avz = config.get_cloud_config_value('availability_zone',
                                        vm_,
                                        __opts__,
                                        default=None,
                                        search_global=False)
    if avz is not None:
        kwargs['ex_availability_zone'] = avz

    kwargs['ex_keyname'] = config.get_cloud_config_value('ssh_key_name',
                                                         vm_,
                                                         __opts__,
                                                         search_global=False)

    security_groups = config.get_cloud_config_value('security_groups',
                                                    vm_,
                                                    __opts__,
                                                    search_global=False)
    if security_groups is not None:
        vm_groups = security_groups.split(',')
        avail_groups = conn.ex_list_security_groups()
        group_list = []

        for vmg in vm_groups:
            if vmg in [ag.name for ag in avail_groups]:
                group_list.append(vmg)
            else:
                raise SaltCloudNotFound(
                    'No such security group: \'{0}\''.format(vmg))

        kwargs['ex_security_groups'] = [
            g for g in avail_groups if g.name in group_list
        ]

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

    floating = []

    if HAS014:
        if networks is not None:
            for net in networks:
                if 'fixed' in net:
                    kwargs['networks'] = [
                        OpenStackNetwork(n, None, None, None)
                        for n in net['fixed']
                    ]
                elif 'floating' in net:
                    pool = OpenStack_1_1_FloatingIpPool(
                        net['floating'], conn.connection)
                    for idx in pool.list_floating_ips():
                        if idx.node_id is None:
                            floating.append(idx)
                    if not floating:
                        # Note(pabelanger): We have no available floating IPs.
                        # For now, we raise an exception and exit.
                        # A future enhancement might be to allow salt-cloud
                        # to dynamically allocate new address but that might
                        raise SaltCloudSystemExit(
                            'Floating pool {0!r} does not have any more '
                            'please create some more or use a different '
                            'pool.'.format(net['floating']))
        # otherwise, attempt to obtain list without specifying pool
        # this is the same as 'nova floating-ip-list'
        elif ssh_interface(vm_) != 'private_ips':
            try:
                # This try/except is here because it appears some
                # *cough* Rackspace *cough*
                # OpenStack providers return a 404 Not Found for the
                # floating ip pool URL if there are no pools setup
                pool = OpenStack_1_1_FloatingIpPool('', conn.connection)
                for idx in pool.list_floating_ips():
                    if idx.node_id is None:
                        floating.append(idx)
                if not floating:
                    # Note(pabelanger): We have no available floating IPs.
                    # For now, we raise an exception and exit.
                    # A future enhancement might be to allow salt-cloud to
                    # dynamically allocate new address but that might be
                    # tricky to manage.
                    raise SaltCloudSystemExit(
                        'There are no more floating IP addresses '
                        'available, please create some more')
            except Exception as e:
                if str(e).startswith('404'):
                    pass
                else:
                    raise
    vm_['floating'] = floating

    files = config.get_cloud_config_value('files',
                                          vm_,
                                          __opts__,
                                          search_global=False)
    if files:
        kwargs['ex_files'] = {}
        for src_path in files:
            with salt.utils.fopen(files[src_path], 'r') as fp_:
                kwargs['ex_files'][src_path] = fp_.read()

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

    if userdata_file is not None:
        with salt.utils.fopen(userdata_file, 'r') as fp:
            kwargs['ex_userdata'] = fp.read()

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

    default_profile = {}
    if 'profile' in vm_ and vm_['profile'] is not None:
        default_profile = {'profile': vm_['profile']}

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

    try:
        data = conn.create_node(**kwargs)
    except Exception as exc:
        raise SaltCloudSystemExit(
            'Error creating {0} on OpenStack\n\n'
            'The following exception was thrown by libcloud when trying to '
            'run the initial deployment: {1}\n'.format(vm_['name'], exc))

    vm_['password'] = data.extra.get('password', None)
    return data, vm_
Ejemplo n.º 9
0
Archivo: nova.py Proyecto: vonion/salt
def create(vm_):
    '''
    Create a single VM from a data dict
    '''
    deploy = config.get_cloud_config_value('deploy', vm_, __opts__)
    key_filename = config.get_cloud_config_value('ssh_key_file',
                                                 vm_,
                                                 __opts__,
                                                 search_global=False,
                                                 default=None)
    if key_filename is not None and not os.path.isfile(key_filename):
        raise SaltCloudConfigError(
            'The defined ssh_key_file {0!r} does not exist'.format(
                key_filename))

    if deploy is True and key_filename is None and \
            salt.utils.which('sshpass') is None:
        raise SaltCloudSystemExit(
            'Cannot deploy salt in a VM if the \'ssh_key_file\' setting '
            'is not set and \'sshpass\' binary is not present on the '
            'system for the password.')

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

    log.info('Creating Cloud VM {0}'.format(vm_['name']))
    salt.utils.cloud.check_name(vm_['name'], 'a-zA-Z0-9._-')
    conn = get_conn()
    kwargs = {'name': vm_['name']}

    try:
        kwargs['image'] = get_image(conn, vm_)
    except Exception as exc:
        log.error(
            'Error creating {0} on OPENSTACK\n\n'
            'Could not find image {1}: {2}\n'.format(vm_['name'], vm_['image'],
                                                     exc),
            # Show the traceback if the debug logging level is enabled
            exc_info=log.isEnabledFor(logging.DEBUG))
        return False

    try:
        kwargs['size'] = get_size(conn, vm_)
    except Exception as exc:
        log.error(
            'Error creating {0} on OPENSTACK\n\n'
            'Could not find size {1}: {2}\n'.format(vm_['name'], vm_['size'],
                                                    exc),
            # Show the traceback if the debug logging level is enabled
            exc_info=log.isEnabledFor(logging.DEBUG))
        return False

    kwargs['ex_keyname'] = config.get_cloud_config_value('ssh_key_name',
                                                         vm_,
                                                         __opts__,
                                                         search_global=False)

    security_groups = config.get_cloud_config_value('security_groups',
                                                    vm_,
                                                    __opts__,
                                                    search_global=False)
    if security_groups is not None:
        vm_groups = security_groups.split(',')
        avail_groups = conn.ex_list_security_groups()
        group_list = []

        for vmg in vm_groups:
            if vmg in [ag.name for ag in avail_groups]:
                group_list.append(vmg)
            else:
                raise SaltCloudNotFound(
                    'No such security group: \'{0}\''.format(vmg))

        kwargs['ex_security_groups'] = [
            g for g in avail_groups if g.name in group_list
        ]

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

    floating = []

    if HAS014 and networks is not None:
        for net in networks:
            if 'fixed' in net:
                kwargs['networks'] = [
                    OpenStackNetwork(n, None, None, None) for n in net['fixed']
                ]
            elif 'floating' in net:
                pool = OpenStack_1_1_FloatingIpPool(net['floating'],
                                                    conn.connection)
                for idx in pool.list_floating_ips():
                    if idx.node_id is None:
                        floating.append(idx)
                if not floating:
                    # Note(pabelanger): We have no available floating IPs. For
                    # now, we raise an execption and exit. A future enhancement
                    # might be to allow salt-cloud to dynamically allociate new
                    # address but that might be tricky to manage.
                    raise SaltCloudSystemExit(
                        "Floating pool '%s' has not more address available, "
                        "please create some more or use a different pool." %
                        net['floating'])

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

    if userdata_file is not None:
        with salt.utils.fopen(userdata_file, 'r') as fp:
            kwargs['ex_userdata'] = fp.read()

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

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

    def __query_node_data(vm_, data, floating):
        try:
            nodelist = list_nodes()
            log.debug('Loaded node data for {0}:\n{1}'.format(
                vm_['name'], pprint.pformat(nodelist[vm_['name']])))
        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=log.isEnabledFor(logging.DEBUG))
            # Trigger a failure in the wait for IP function
            return False

        running = nodelist[vm_['name']]['state'] == node_state(
            NodeState.RUNNING)
        if not running:
            # Still not running, trigger another iteration
            return

        if rackconnect(vm_) is True:
            extra = nodelist[vm_['name']].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 = nodelist[vm_['name']].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

        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}" to node "{1}"'.format(
                    ip, name))
            except Exception as e:
                # 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 = nodelist[vm_['name']]['private_ips']
        public = nodelist[vm_['name']]['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:
            if ssh_interface(vm_) != 'private_ips':
                data.public_ips = access_ip
                return data

        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, 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(exc.message)

    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 not ip_address:
        raise SaltCloudSystemExit('A valid IP address was not found')

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

    deploy_kwargs = {
        'host':
        ip_address,
        'name':
        vm_['name'],
        'sock_dir':
        __opts__['sock_dir'],
        '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'],
        '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_)
    }

    if ssh_username != 'root':
        deploy_kwargs['username'] = ssh_username
        deploy_kwargs['tty'] = True

    log.debug('Using {0} as SSH username'.format(ssh_username))

    if key_filename is not None:
        deploy_kwargs['key_filename'] = key_filename
        log.debug('Using {0} as SSH key file'.format(key_filename))
    elif 'password' in data.extra:
        deploy_kwargs['password'] = data.extra['password']
        log.debug('Logging into SSH using password')

    ret = {}
    if config.get_cloud_config_value('deploy', vm_, __opts__) is True:
        deploy_script = script(vm_)
        deploy_kwargs['script'] = deploy_script.script

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

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

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

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

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

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

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

        if deployed:
            log.info('Salt installed on {0}'.format(vm_['name']))
        else:
            log.error('Failed to 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'],
        },
    )

    return ret
Ejemplo n.º 10
0
def create(vm_):
    '''
    Create a single VM from a data dict
    '''
    deploy = config.get_config_value('deploy', vm_, __opts__)
    key_filename = config.get_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!r} does not exist'.format(
                key_filename
            )
        )

    if deploy is True and key_filename is None and \
            salt.utils.which('sshpass') is None:
        raise SaltCloudSystemExit(
            'Cannot deploy salt in a VM if the \'ssh_key_file\' setting '
            'is not set and \'sshpass\' binary is not present on the '
            'system for the password.'
        )

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

    log.info('Creating Cloud VM {0}'.format(vm_['name']))
    salt.cloud.utils.check_name(vm_['name'], 'a-zA-Z0-9._-')
    conn = get_conn()
    kwargs = {
        'name': vm_['name']
    }

    try:
        kwargs['image'] = get_image(conn, vm_)
    except Exception as exc:
        log.error(
            'Error creating {0} on OPENSTACK\n\n'
            'Could not find image {1}: {2}\n'.format(
                vm_['name'], vm_['image'], exc
            ),
            # Show the traceback if the debug logging level is enabled
            exc_info=log.isEnabledFor(logging.DEBUG)
        )
        return False

    try:
        kwargs['size'] = get_size(conn, vm_)
    except Exception as exc:
        log.error(
            'Error creating {0} on OPENSTACK\n\n'
            'Could not find size {1}: {2}\n'.format(
                vm_['name'], vm_['size'], exc
            ),
            # Show the traceback if the debug logging level is enabled
            exc_info=log.isEnabledFor(logging.DEBUG)
        )
        return False

    kwargs['ex_keyname'] = config.get_config_value(
        'ssh_key_name', vm_, __opts__, search_global=False
    )

    security_groups = config.get_config_value(
        'security_groups', vm_, __opts__, search_global=False
    )
    if security_groups is not None:
        vm_groups = security_groups.split(',')
        avail_groups = conn.ex_list_security_groups()
        group_list = []

        for vmg in vm_groups:
            if vmg in [ag.name for ag in avail_groups]:
                group_list.append(vmg)
            else:
                raise SaltCloudNotFound(
                    'No such security group: \'{0}\''.format(vmg)
                )

        kwargs['ex_security_groups'] = [
            g for g in avail_groups if g.name in group_list
        ]

    networks = config.get_config_value(
        'networks', vm_, __opts__, search_global=False
    )

    floating = []

    if HAS014 and networks is not None:
        for net in networks:
            if 'fixed' in net:
                kwargs['networks'] = [
                    OpenStackNetwork(n, None, None, None) for n in net['fixed']
                ]
            elif 'floating' in net:
                pool = OpenStack_1_1_FloatingIpPool(
                    net['floating'], conn.connection
                )
                for idx in pool.list_floating_ips():
                    if idx.node_id is None:
                        floating.append(idx)
                if not floating:
                    # Note(pabelanger): We have no available floating IPs. For
                    # now, we raise an execption and exit. A future enhancement
                    # might be to allow salt-cloud to dynamically allociate new
                    # address but that might be tricky to manage.
                    raise SaltCloudSystemExit(
                        "Floating pool '%s' has not more address available, "
                        "please create some more or use a different pool." %
                        net['floating']
                    )

    files = config.get_config_value(
        'files', vm_, __opts__, search_global=False
    )
    if files:
        kwargs['ex_files'] = {}
        for src_path in files:
            with salt.utils.fopen(files[src_path], 'r') as fp_:
                kwargs['ex_files'][src_path] = fp_.read()

    userdata_file = config.get_config_value(
        'userdata_file', vm_, __opts__, search_global=False
    )

    if userdata_file is not None:
        with salt.utils.fopen(userdata_file, 'r') as fp:
            kwargs['ex_userdata'] = fp.read()

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

    kwargs['ex_metadata'] = config.get_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 OpenStack\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=log.isEnabledFor(logging.DEBUG)
        )
        return False

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

        running = nodelist[vm_['name']]['state'] == node_state(
            NodeState.RUNNING
        )
        if not running:
            # Still not running, trigger another iteration
            return

        if rackconnect(vm_) is True:
            extra = nodelist[vm_['name']].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 = nodelist[vm_['name']].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

        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}" to node "{1}"'.format(ip, name)
                )
            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 = nodelist[vm_['name']]['private_ips']
        public = nodelist[vm_['name']]['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.cloud.utils.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

        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