Installs the salt-minion helper for machine state.

    By default the salt-minion package is installed from
    the saltstack PPA. If from_ppa is False you must ensure
    that the salt-minion package is available in the apt cache.
195108
def install_salt_support(from_ppa=True):
    
    if from_ppa:
        subprocess.check_call([
            '/usr/bin/add-apt-repository',
            '--yes',
            'ppa:saltstack/salt',
        ])
        subprocess.check_call(['/usr/bin/apt-get', 'update'])
    # We install salt-common as salt-minion would run the salt-minion
    # daemon.
    charmhelpers.fetch.apt_install('salt-common')
1332519
def _check_minions_directories(pki_dir):
    '''
    
    '''
    minions_accepted = os.path.join(pki_dir, salt.key.Key.ACC)
    minions_pre = os.path.join(pki_dir, salt.key.Key.PEND)
    minions_rejected = os.path.join(pki_dir, salt.key.Key.REJ)
    minions_denied = os.path.join(pki_dir, salt.key.Key.DEN)

    return minions_accepted, minions_pre, minions_rejected, minions_denied
334176
def get_state(self, sls, saltenv, cachedir=None):
        '''
        
        '''
        if '.' in sls:
            sls = sls.replace('.', '/')
        sls_url = salt.utils.url.create(sls + '.sls')
        init_url = salt.utils.url.create(sls + '/init.sls')
        for path in [sls_url, init_url]:
            dest = self.cache_file(path, saltenv, cachedir=cachedir)
            if dest:
                return {'source': path, 'dest': dest}
        return {}
889349
def active(display_progress=False):
    '''
    
    '''
    ret = {}
    client = salt.client.get_local_client(__opts__['conf_file'])
    try:
        active_ = client.cmd('*', 'saltutil.running', timeout=__opts__['timeout'])
    except SaltClientError as client_error:
        print(client_error)
        return ret

    if display_progress:
        __jid_event__.fire_event({
            'message': 'Attempting to contact minions: {0}'.format(list(active_.keys()))
            }, 'progress')
    for minion, data in six.iteritems(active_):
        if display_progress:
            __jid_event__.fire_event({'message': 'Received reply from minion {0}'.format(minion)}, 'progress')
        if not isinstance(data, list):
            continue
        for job in data:
            if not job['jid'] in ret:
                ret[job['jid']] = _format_jid_instance(job['jid'], job)
                ret[job['jid']].update({'Running': [{minion: job.get('pid', None)}], 'Returned': []})
            else:
                ret[job['jid']]['Running'].append({minion: job['pid']})

    mminion = salt.minion.MasterMinion(__opts__)
    for jid in ret:
        returner = _get_returner((__opts__['ext_job_cache'], __opts__['master_job_cache']))
        data = mminion.returners['{0}.get_jid'.format(returner)](jid)
        if data:
            for minion in data:
                if minion not in ret[jid]['Returned']:
                    ret[jid]['Returned'].append(minion)

    return ret
845437
def salt(self, module, target='*', args=None, kwargs=None, ssh=False):
        
        if ssh:
            return salt.salt_ssh(self, target, module, args, kwargs)
        else:
            return salt.salt_master(self, target, module, args, kwargs)
1275161
def get_pillar(opts, grains, minion_id, saltenv=None, ext=None, funcs=None,
               pillar_override=None, pillarenv=None, extra_minion_data=None):
    '''
    
    '''
    file_client = opts['file_client']
    if opts.get('master_type') == 'disable' and file_client == 'remote':
        file_client = 'local'
    ptype = {
        'remote': RemotePillar,
        'local': Pillar
    }.get(file_client, Pillar)
    # If local pillar and we're caching, run through the cache system first
    log.debug('Determining pillar cache')
    if opts['pillar_cache']:
        log.info('Compiling pillar from cache')
        log.debug('get_pillar using pillar cache with ext: %s', ext)
        return PillarCache(opts, grains, minion_id, saltenv, ext=ext, functions=funcs,
                pillar_override=pillar_override, pillarenv=pillarenv)
    return ptype(opts, grains, minion_id, saltenv, ext, functions=funcs,
                 pillar_override=pillar_override, pillarenv=pillarenv,
                 extra_minion_data=extra_minion_data)
553077
def _setup_core(self):
        '''
        
        '''
        if not self.ready:
            # First call. Initialize.
            self.functions, self.returners, self.function_errors, self.executors = self._load_modules()
            self.serial = salt.payload.Serial(self.opts)
            self.mod_opts = self._prep_mod_opts()
#            self.matcher = Matcher(self.opts, self.functions)
            self.matchers = salt.loader.matchers(self.opts)
            self.beacons = salt.beacons.Beacon(self.opts, self.functions)
            uid = salt.utils.user.get_uid(user=self.opts.get('user', None))
            self.proc_dir = get_proc_dir(self.opts['cachedir'], uid=uid)
            self.grains_cache = self.opts['grains']
            self.ready = True
641778
async def install_agent(self, connection, nonce, machine_id):
        

        # The path where the Juju agent should be installed.
        data_dir = "/var/lib/juju"

        # Disabling this prevents `apt-get update` from running initially, so
        # charms will fail to deploy
        disable_package_commands = False

        client_facade = client.ClientFacade.from_connection(connection)
        results = await client_facade.ProvisioningScript(
            data_dir,
            disable_package_commands,
            machine_id,
            nonce,
        )

        self._run_configure_script(results.script)
416880
def salt_support():
    '''
    
    '''

    import salt.cli.support.collector
    if '' in sys.path:
        sys.path.remove('')
    client = salt.cli.support.collector.SaltSupport()
    _install_signal_handlers(client)
    client.run()
153917
def _resolve_deps(name, pkgs, **kwargs):
    '''
    
    '''
    missing_deps = []
    for pkg_file in pkgs:
        deb = apt.debfile.DebPackage(filename=pkg_file, cache=apt.Cache())
        if deb.check():
            missing_deps.extend(deb.missing_deps)

    if missing_deps:
        cmd = ['apt-get', '-q', '-y']
        cmd = cmd + ['-o', 'DPkg::Options::=--force-confold']
        cmd = cmd + ['-o', 'DPkg::Options::=--force-confdef']
        cmd.append('install')
        cmd.extend(missing_deps)

        ret = __salt__['cmd.retcode'](
            cmd,
            env=kwargs.get('env'),
            python_shell=False
        )

        if ret != 0:
            raise CommandExecutionError(
                'Error: unable to resolve dependencies for: {0}'.format(name)
            )
        else:
            try:
                cmd = ['apt-mark', 'auto'] + missing_deps
                __salt__['cmd.run'](
                    cmd,
                    env=kwargs.get('env'),
                    python_shell=False
                )
            except MinionError as exc:
                raise CommandExecutionError(exc)
    return
204535
def show_top(minion=None, saltenv='base'):
    '''
    
    '''
    id_, grains, _ = salt.utils.minions.get_minion_data(minion, __opts__)
    if not grains and minion == __opts__['id']:
        grains = salt.loader.grains(__opts__)
    pillar = salt.pillar.Pillar(
        __opts__,
        grains,
        id_,
        saltenv)

    top, errors = pillar.get_top()

    if errors:
        __jid_event__.fire_event({'data': errors, 'outputter': 'nested'}, 'progress')
        return errors

    # needed because pillar compilation clobbers grains etc via lazyLoader
    # this resets the masterminion back to known state
    __salt__['salt.cmd']('sys.reload_modules')

    return top
428360
def fileserver_update(fileserver):
    '''
    
    '''
    try:
        if not fileserver.servers:
            log.error(
                'No fileservers loaded, the master will not be able to '
                'serve files to minions'
            )
            raise salt.exceptions.SaltMasterError('No fileserver backends available')
        fileserver.update()
    except Exception as exc:
        log.error(
            'Exception %s occurred in file server update', exc,
            exc_info_on_loglevel=logging.DEBUG
        )
668867
def bootstrap_app():
    '''
    
    '''
    from salt.netapi.rest_cherrypy import app
    import salt.config

    __opts__ = salt.config.client_config(
            os.environ.get('SALT_MASTER_CONFIG', '/etc/salt/master'))
    return app.get_app(__opts__)
1268658
def compile_pillar(self):
        '''
        
        '''
        load = {'id': self.minion_id,
                'grains': self.grains,
                'saltenv': self.opts['saltenv'],
                'pillarenv': self.opts['pillarenv'],
                'pillar_override': self.pillar_override,
                'extra_minion_data': self.extra_minion_data,
                'ver': '2',
                'cmd': '_pillar'}
        if self.ext:
            load['ext'] = self.ext
        try:
            ret_pillar = yield self.channel.crypted_transfer_decode_dictentry(
                load,
                dictkey='pillar',
            )
        except Exception:
            log.exception('Exception getting pillar:')
            raise SaltClientError('Exception getting pillar.')

        if not isinstance(ret_pillar, dict):
            msg = ('Got a bad pillar from master, type {0}, expecting dict: '
                   '{1}').format(type(ret_pillar).__name__, ret_pillar)
            log.error(msg)
            # raise an exception! Pillar isn't empty, we can't sync it!
            raise SaltClientError(msg)
        raise tornado.gen.Return(ret_pillar)
1151688
def installed(name, enabled=True):
    '''
    

    '''
    ret = {'name': name,
           'result': True,
           'comment': '',
           'changes': {}}

    is_installed = __salt__['assistive.installed'](name)

    if is_installed:
        is_enabled = __salt__['assistive.enabled'](name)

        if enabled != is_enabled:
            __salt__['assistive.enable'](name, enabled)
            ret['comment'] = 'Updated enable to {0}'.format(enabled)
        else:
            ret['comment'] = 'Already in the correct state'

    else:
        __salt__['assistive.install'](name, enabled)
        ret['comment'] = 'Installed {0} into the assistive access panel'.format(name)

    return ret
136294
def installed(name, channel=None):
    '''
    
    '''
    ret = {'name': name,
           'changes': {},
           'pchanges': {},
           'result': None,
           'comment': ''}

    old = __salt__['snap.versions_installed'](name)
    if not old:
        if __opts__['test']:
            ret['comment'] = 'Package "{0}" would have been installed'.format(name)
            ret['pchanges']['new'] = name
            ret['pchanges']['old'] = None
            ret['result'] = None
            return ret

        install = __salt__['snap.install'](name, channel=channel)
        if install['result']:
            ret['comment'] = 'Package "{0}" was installed'.format(name)
            ret['changes']['new'] = name
            ret['changes']['old'] = None
            ret['result'] = True
            return ret

        ret['comment'] = 'Package "{0}" failed to install'.format(name)
        ret['comment'] += '\noutput:\n' + install['output']
        ret['result'] = False
        return ret

    # Currently snap always returns only one line?
    old_channel = old[0]['tracking']
    if old_channel != channel and channel is not None:
        if __opts__['test']:
            ret['comment'] = 'Package "{0}" would have been switched to channel {1}'.format(name, channel)
            ret['pchanges']['old_channel'] = old_channel
            ret['pchanges']['new_channel'] = channel
            ret['result'] = None
            return ret

        refresh = __salt__['snap.install'](name, channel=channel, refresh=True)
        if refresh['result']:
            ret['comment'] = 'Package "{0}" was switched to channel {1}'.format(name, channel)
            ret['pchanges']['old_channel'] = old_channel
            ret['pchanges']['new_channel'] = channel
            ret['result'] = True
            return ret

        ret['comment'] = 'Failed to switch Package "{0}" to channel {1}'.format(name, channel)
        ret['comment'] += '\noutput:\n' + install['output']
        ret['result'] = False
        return ret

    ret['comment'] = 'Package "{0}" is already installed'.format(name)
    if __opts__['test']:
        ret['result'] = None
        return ret

    ret['result'] = True
    return ret
768107
def _thread_return(cls, minion_instance, opts, data):
        '''
        
        '''
        fn_ = os.path.join(minion_instance.proc_dir, data['jid'])

        if opts['multiprocessing'] and not salt.utils.platform.is_windows():
            # Shutdown the multiprocessing before daemonizing
            salt.log.setup.shutdown_multiprocessing_logging()

            salt.utils.process.daemonize_if(opts)

            # Reconfigure multiprocessing logging after daemonizing
            salt.log.setup.setup_multiprocessing_logging()

        salt.utils.process.appendproctitle('{0}._thread_return {1}'.format(cls.__name__, data['jid']))

        sdata = {'pid': os.getpid()}
        sdata.update(data)
        log.info('Starting a new job %s with PID %s', data['jid'], sdata['pid'])
        with salt.utils.files.fopen(fn_, 'w+b') as fp_:
            fp_.write(minion_instance.serial.dumps(sdata))
        ret = {'success': False}
        function_name = data['fun']
        executors = data.get('module_executors') or \
                    getattr(minion_instance, 'module_executors', []) or \
                    opts.get('module_executors', ['direct_call'])
        allow_missing_funcs = any([
            minion_instance.executors['{0}.allow_missing_func'.format(executor)](function_name)
            for executor in executors
            if '{0}.allow_missing_func' in minion_instance.executors
        ])
        if function_name in minion_instance.functions or allow_missing_funcs is True:
            try:
                minion_blackout_violation = False
                if minion_instance.connected and minion_instance.opts['pillar'].get('minion_blackout', False):
                    whitelist = minion_instance.opts['pillar'].get('minion_blackout_whitelist', [])
                    # this minion is blacked out. Only allow saltutil.refresh_pillar and the whitelist
                    if function_name != 'saltutil.refresh_pillar' and function_name not in whitelist:
                        minion_blackout_violation = True
                # use minion_blackout_whitelist from grains if it exists
                if minion_instance.opts['grains'].get('minion_blackout', False):
                    whitelist = minion_instance.opts['grains'].get('minion_blackout_whitelist', [])
                    if function_name != 'saltutil.refresh_pillar' and function_name not in whitelist:
                        minion_blackout_violation = True
                if minion_blackout_violation:
                    raise SaltInvocationError('Minion in blackout mode. Set \'minion_blackout\' '
                                             'to False in pillar or grains to resume operations. Only '
                                             'saltutil.refresh_pillar allowed in blackout mode.')

                if function_name in minion_instance.functions:
                    func = minion_instance.functions[function_name]
                    args, kwargs = load_args_and_kwargs(
                        func,
                        data['arg'],
                        data)
                else:
                    # only run if function_name is not in minion_instance.functions and allow_missing_funcs is True
                    func = function_name
                    args, kwargs = data['arg'], data
                minion_instance.functions.pack['__context__']['retcode'] = 0
                if isinstance(executors, six.string_types):
                    executors = [executors]
                elif not isinstance(executors, list) or not executors:
                    raise SaltInvocationError("Wrong executors specification: {0}. String or non-empty list expected".
                        format(executors))
                if opts.get('sudo_user', '') and executors[-1] != 'sudo':
                    executors[-1] = 'sudo'  # replace the last one with sudo
                log.trace('Executors list %s', executors)  # pylint: disable=no-member

                for name in executors:
                    fname = '{0}.execute'.format(name)
                    if fname not in minion_instance.executors:
                        raise SaltInvocationError("Executor '{0}' is not available".format(name))
                    return_data = minion_instance.executors[fname](opts, data, func, args, kwargs)
                    if return_data is not None:
                        break

                if isinstance(return_data, types.GeneratorType):
                    ind = 0
                    iret = {}
                    for single in return_data:
                        if isinstance(single, dict) and isinstance(iret, dict):
                            iret.update(single)
                        else:
                            if not iret:
                                iret = []
                            iret.append(single)
                        tag = tagify([data['jid'], 'prog', opts['id'], six.text_type(ind)], 'job')
                        event_data = {'return': single}
                        minion_instance._fire_master(event_data, tag)
                        ind += 1
                    ret['return'] = iret
                else:
                    ret['return'] = return_data

                retcode = minion_instance.functions.pack['__context__'].get(
                    'retcode',
                    salt.defaults.exitcodes.EX_OK
                )
                if retcode == salt.defaults.exitcodes.EX_OK:
                    # No nonzero retcode in __context__ dunder. Check if return
                    # is a dictionary with a "result" or "success" key.
                    try:
                        func_result = all(return_data.get(x, True)
                                          for x in ('result', 'success'))
                    except Exception:
                        # return data is not a dict
                        func_result = True
                    if not func_result:
                        retcode = salt.defaults.exitcodes.EX_GENERIC

                ret['retcode'] = retcode
                ret['success'] = retcode == salt.defaults.exitcodes.EX_OK
            except CommandNotFoundError as exc:
                msg = 'Command required for \'{0}\' not found'.format(
                    function_name
                )
                log.debug(msg, exc_info=True)
                ret['return'] = '{0}: {1}'.format(msg, exc)
                ret['out'] = 'nested'
                ret['retcode'] = salt.defaults.exitcodes.EX_GENERIC
            except CommandExecutionError as exc:
                log.error(
                    'A command in \'%s\' had a problem: %s',
                    function_name, exc,
                    exc_info_on_loglevel=logging.DEBUG
                )
                ret['return'] = 'ERROR: {0}'.format(exc)
                ret['out'] = 'nested'
                ret['retcode'] = salt.defaults.exitcodes.EX_GENERIC
            except SaltInvocationError as exc:
                log.error(
                    'Problem executing \'%s\': %s',
                    function_name, exc,
                    exc_info_on_loglevel=logging.DEBUG
                )
                ret['return'] = 'ERROR executing \'{0}\': {1}'.format(
                    function_name, exc
                )
                ret['out'] = 'nested'
                ret['retcode'] = salt.defaults.exitcodes.EX_GENERIC
            except TypeError as exc:
                msg = 'Passed invalid arguments to {0}: {1}\n{2}'.format(
                    function_name, exc, func.__doc__ or ''
                )
                log.warning(msg, exc_info_on_loglevel=logging.DEBUG)
                ret['return'] = msg
                ret['out'] = 'nested'
                ret['retcode'] = salt.defaults.exitcodes.EX_GENERIC
            except Exception:
                msg = 'The minion function caused an exception'
                log.warning(msg, exc_info_on_loglevel=True)
                salt.utils.error.fire_exception(salt.exceptions.MinionError(msg), opts, job=data)
                ret['return'] = '{0}: {1}'.format(msg, traceback.format_exc())
                ret['out'] = 'nested'
                ret['retcode'] = salt.defaults.exitcodes.EX_GENERIC
        else:
            docs = minion_instance.functions['sys.doc']('{0}*'.format(function_name))
            if docs:
                docs[function_name] = minion_instance.functions.missing_fun_string(function_name)
                ret['return'] = docs
            else:
                ret['return'] = minion_instance.functions.missing_fun_string(function_name)
                mod_name = function_name.split('.')[0]
                if mod_name in minion_instance.function_errors:
                    ret['return'] += ' Possible reasons: \'{0}\''.format(
                        minion_instance.function_errors[mod_name]
                    )
            ret['success'] = False
            ret['retcode'] = salt.defaults.exitcodes.EX_GENERIC
            ret['out'] = 'nested'

        ret['jid'] = data['jid']
        ret['fun'] = data['fun']
        ret['fun_args'] = data['arg']
        if 'master_id' in data:
            ret['master_id'] = data['master_id']
        if 'metadata' in data:
            if isinstance(data['metadata'], dict):
                ret['metadata'] = data['metadata']
            else:
                log.warning('The metadata parameter must be a dictionary. Ignoring.')
        if minion_instance.connected:
            minion_instance._return_pub(
                ret,
                timeout=minion_instance._return_retry_timer()
            )

        # Add default returners from minion config
        # Should have been coverted to comma-delimited string already
        if isinstance(opts.get('return'), six.string_types):
            if data['ret']:
                data['ret'] = ','.join((data['ret'], opts['return']))
            else:
                data['ret'] = opts['return']

        log.debug('minion return: %s', ret)
        # TODO: make a list? Seems odd to split it this late :/
        if data['ret'] and isinstance(data['ret'], six.string_types):
            if 'ret_config' in data:
                ret['ret_config'] = data['ret_config']
            if 'ret_kwargs' in data:
                ret['ret_kwargs'] = data['ret_kwargs']
            ret['id'] = opts['id']
            for returner in set(data['ret'].split(',')):
                try:
                    returner_str = '{0}.returner'.format(returner)
                    if returner_str in minion_instance.returners:
                        minion_instance.returners[returner_str](ret)
                    else:
                        returner_err = minion_instance.returners.missing_fun_string(returner_str)
                        log.error(
                            'Returner %s could not be loaded: %s',
                            returner_str, returner_err
                        )
                except Exception as exc:
                    log.exception(
                        'The return failed for job %s: %s', data['jid'], exc
                    )