def prepare(self): ''' Run the preparation sequence required to start a salt-api daemon. If sub-classed, don't **ever** forget to run: super(YourSubClass, self).prepare() ''' super(SaltAPI, self).prepare() try: if self.config['verify_env']: logfile = self.config['log_file'] if logfile is not None and not logfile.startswith(('tcp://', 'udp://', 'file://')): # Logfile is not using Syslog, verify current_umask = os.umask(0o027) verify_files([logfile], self.config['user']) os.umask(current_umask) except OSError as err: log.exception('Failed to prepare salt environment') self.shutdown(err.errno) self.setup_logfile_logger() verify_log(self.config) log.info('Setting up the Salt API') self.api = salt.client.netapi.NetapiClient(self.config) self.daemonize_if_required() self.set_pidfile()
def run(self): ''' Execute salt-run ''' import salt.runner self.parse_args() # Setup file logging! self.setup_logfile_logger() verify_log(self.config) profiling_enabled = self.options.profiling_enabled runner = salt.runner.Runner(self.config) if self.options.doc: runner.print_docs() self.exit(salt.defaults.exitcodes.EX_OK) # Run this here so SystemExit isn't raised anywhere else when # someone tries to use the runners via the python API try: if check_user(self.config['user']): pr = activate_profile(profiling_enabled) try: ret = runner.run() if isinstance(ret, dict) and 'retcode' in ret.get( 'data', {}): self.exit(ret['data']['retcode']) finally: output_profile(pr, stats_path=self.options.profiling_path, stop=True) except SaltClientError as exc: raise SystemExit(str(exc))
def run(self): self.parse_args() self.setup_logfile_logger() verify_log(self.config) ssh = salt.client.ssh.SSH(self.config) ssh.run()
def run(self): ''' Execute salt-run ''' import salt.runner self.parse_args() # Setup file logging! self.setup_logfile_logger() verify_log(self.config) profiling_enabled = self.options.profiling_enabled runner = salt.runner.Runner(self.config) if self.options.doc: runner.print_docs() self.exit(salt.defaults.exitcodes.EX_OK) # Run this here so SystemExit isn't raised anywhere else when # someone tries to use the runners via the python API try: if check_user(self.config['user']): pr = activate_profile(profiling_enabled) try: ret = runner.run() if isinstance(ret, dict) and 'retcode' in ret: self.exit(ret['retcode']) finally: output_profile( pr, stats_path=self.options.profiling_path, stop=True) except SaltClientError as exc: raise SystemExit(str(exc))
def run(self): ''' Run the api ''' import salt.client.netapi self.parse_args() try: if self.config['verify_env']: logfile = self.config['log_file'] if logfile is not None and not logfile.startswith('tcp://') \ and not logfile.startswith('udp://') \ and not logfile.startswith('file://'): # Logfile is not using Syslog, verify salt.utils.verify.verify_files([logfile], self.config['user']) except OSError as err: log.error(err) sys.exit(err.errno) self.setup_logfile_logger() verify_log(self.config) client = salt.client.netapi.NetapiClient(self.config) self.daemonize_if_required() self.set_pidfile() client.run()
def prepare(self): ''' Run the preparation sequence required to start a salt syndic minion. If sub-classed, don't **ever** forget to run: super(YourSubClass, self).prepare() ''' super(Syndic, self).prepare() try: if self.config['verify_env']: verify_env( [ self.config['pki_dir'], self.config['cachedir'], self.config['sock_dir'], self.config['extension_modules'], ], self.config['user'], permissive=self.config['permissive_pki_access'], pki_dir=self.config['pki_dir'], ) except OSError as error: self.environment_failure(error) self.setup_logfile_logger() verify_log(self.config) self.action_log_info('Setting up "{0}"'.format(self.config['id'])) # Late import so logging works correctly import salt.minion self.daemonize_if_required() self.syndic = salt.minion.SyndicManager(self.config) self.set_pidfile()
def prepare(self): ''' Run the preparation sequence required to start a salt master server. If sub-classed, don't **ever** forget to run: super(YourSubClass, self).prepare() ''' super(Master, self).prepare() try: if self.config['verify_env']: v_dirs = [ self.config['pki_dir'], os.path.join(self.config['pki_dir'], 'minions'), os.path.join(self.config['pki_dir'], 'minions_pre'), os.path.join(self.config['pki_dir'], 'minions_denied'), os.path.join(self.config['pki_dir'], 'minions_autosign'), os.path.join(self.config['pki_dir'], 'minions_rejected'), self.config['cachedir'], os.path.join(self.config['cachedir'], 'jobs'), os.path.join(self.config['cachedir'], 'proc'), self.config['sock_dir'], self.config['token_dir'], self.config['syndic_dir'], self.config['sqlite_queue_dir'], ] verify_env( v_dirs, self.config['user'], permissive=self.config['permissive_pki_access'], root_dir=self.config['root_dir'], pki_dir=self.config['pki_dir'], ) # Clear out syndics from cachedir for syndic_file in os.listdir(self.config['syndic_dir']): os.remove( os.path.join(self.config['syndic_dir'], syndic_file)) except OSError as error: self.environment_failure(error) self.setup_logfile_logger() verify_log(self.config) self.action_log_info('Setting up') # TODO: AIO core is separate from transport if not verify_socket(self.config['interface'], self.config['publish_port'], self.config['ret_port']): self.shutdown(4, 'The ports are not available to bind') self.config['interface'] = ip_bracket(self.config['interface']) migrations.migrate_paths(self.config) # Late import so logging works correctly import salt.master self.master = salt.master.Master(self.config) self.daemonize_if_required() self.set_pidfile() salt.utils.process.notify_systemd()
def prepare(self): """ Run the preparation sequence required to start a salt-api daemon. If sub-classed, don't **ever** forget to run: super(YourSubClass, self).prepare() """ super().prepare() try: if self.config["verify_env"]: logfile = self.options.api_logfile if logfile is not None: # Logfile is not using Syslog, verify with salt.utils.files.set_umask(0o027): verify_log_files([logfile], self.config["user"]) except OSError as err: log.exception("Failed to prepare salt environment") self.shutdown(err.errno) self.setup_logfile_logger() verify_log(self.config) log.info("Setting up the Salt API") self.api = salt.client.netapi.NetapiClient(self.config) self.daemonize_if_required() self.set_pidfile()
def prepare(self): ''' Run the preparation sequence required to start a salt syndic minion. If sub-classed, don't **ever** forget to run: super(YourSubClass, self).prepare() ''' super(Syndic, self).prepare() try: if self.config['verify_env']: verify_env( [ self.config['pki_dir'], self.config['cachedir'], self.config['sock_dir'], self.config['extension_modules'], ], self.config['user'], permissive=self.config['permissive_pki_access'], root_dir=self.config['root_dir'], pki_dir=self.config['pki_dir'], ) except OSError as error: self.environment_failure(error) self.setup_logfile_logger() verify_log(self.config) self.action_log_info('Setting up "{0}"'.format(self.config['id'])) # Late import so logging works correctly import salt.minion self.daemonize_if_required() self.syndic = salt.minion.SyndicManager(self.config) self.set_pidfile()
def run(self): ''' Run the api ''' ui = salt.spm.SPMCmdlineInterface() self.parse_args() self.setup_logfile_logger() verify_log(self.config) client = salt.spm.SPMClient(ui, self.config) client.run(self.args)
def run(self): if '-H' in sys.argv or '--hosts' in sys.argv: sys.argv += ['x', 'x'] # Hack: pass a mandatory two options # that won't be used anyways with -H or --hosts self.parse_args() self.setup_logfile_logger() verify_log(self.config) ssh = salt.client.ssh.SSH(self.config) ssh.run()
def run(self): ''' Execute the salt call! ''' self.parse_args() if self.config['verify_env']: verify_env([ self.config['pki_dir'], self.config['cachedir'], ], self.config['user'], permissive=self.config['permissive_pki_access'], pki_dir=self.config['pki_dir'], ) if not self.config['log_file'].startswith(('tcp://', 'udp://', 'file://')): # Logfile is not using Syslog, verify verify_files( [self.config['log_file']], self.config['user'] ) if self.options.file_root: # check if the argument is pointing to a file on disk file_root = os.path.abspath(self.options.file_root) self.config['file_roots'] = {'base': _expand_glob_path([file_root])} if self.options.pillar_root: # check if the argument is pointing to a file on disk pillar_root = os.path.abspath(self.options.pillar_root) self.config['pillar_roots'] = {'base': _expand_glob_path([pillar_root])} if self.options.local: self.config['file_client'] = 'local' if self.options.master: self.config['master'] = self.options.master # Setup file logging! self.setup_logfile_logger() verify_log(self.config) caller = salt.cli.caller.Caller.factory(self.config) if self.options.doc: caller.print_docs() self.exit(salt.defaults.exitcodes.EX_OK) if self.options.grains_run: caller.print_grains() self.exit(salt.defaults.exitcodes.EX_OK) caller.run()
def run(self): ''' Execute salt-cp ''' self.parse_args() # Setup file logging! self.setup_logfile_logger() verify_log(self.config) cp_ = SaltCP(self.config) cp_.run()
def run(self): ''' Run the api ''' import salt.client.netapi self.parse_args() self.setup_logfile_logger() verify_log(self.config) self.daemonize_if_required() client = salt.client.netapi.NetapiClient(self.config) self.set_pidfile() client.run()
def run(self): ''' Execute salt-key ''' import salt.key self.parse_args() self.setup_logfile_logger() verify_log(self.config) key = salt.key.KeyCLI(self.config) if check_user(self.config['user']): key.run()
def prepare(self): ''' Run the preparation sequence required to start a salt syndic minion. If sub-classed, don't **ever** forget to run: super(YourSubClass, self).prepare() ''' super(Syndic, self).prepare() try: if self.config['verify_env']: verify_env( [ self.config['pki_dir'], self.config['cachedir'], self.config['sock_dir'], self.config['extension_modules'], ], self.config['user'], permissive=self.config['permissive_pki_access'], pki_dir=self.config['pki_dir'], ) logfile = self.config['log_file'] if logfile is not None and not logfile.startswith(('tcp://', 'udp://', 'file://')): # Logfile is not using Syslog, verify current_umask = os.umask(0o027) verify_files([logfile], self.config['user']) os.umask(current_umask) except OSError as err: log.exception('Failed to prepare salt environment') self.shutdown(err.errno) self.setup_logfile_logger() verify_log(self.config) log.info( 'Setting up the Salt Syndic Minion "{0}"'.format( self.config['id'] ) ) # Late import so logging works correctly import salt.minion self.daemonize_if_required() # if its a multisyndic, do so if isinstance(self.config.get('master'), list): self.syndic = salt.minion.MultiSyndic(self.config) else: self.syndic = salt.minion.Syndic(self.config) self.set_pidfile()
def test_verify_log(self): """ Test that verify_log works as expected """ message = "Insecure logging configuration detected! Sensitive data may be logged." mock_cheese = MagicMock() with patch.object(log, "warning", mock_cheese): verify_log({"log_level": "cheeseshop"}) mock_cheese.assert_called_once_with(message) mock_trace = MagicMock() with patch.object(log, "warning", mock_trace): verify_log({"log_level": "trace"}) mock_trace.assert_called_once_with(message) mock_none = MagicMock() with patch.object(log, "warning", mock_none): verify_log({}) mock_none.assert_called_once_with(message) mock_info = MagicMock() with patch.object(log, "warning", mock_info): verify_log({"log_level": "info"}) mock_info.assert_not_called()
def test_verify_log(self): """ Test that verify_log works as expected """ message = ( "Insecure logging configuration detected! Sensitive data may be logged." ) mock_cheese = MagicMock() with patch.object(log, "warning", mock_cheese): verify_log({"log_level": "cheeseshop"}) mock_cheese.assert_called_once_with(message) mock_trace = MagicMock() with patch.object(log, "warning", mock_trace): verify_log({"log_level": "trace"}) mock_trace.assert_called_once_with(message) mock_none = MagicMock() with patch.object(log, "warning", mock_none): verify_log({}) mock_none.assert_called_once_with(message) mock_info = MagicMock() with patch.object(log, "warning", mock_info): verify_log({"log_level": "info"}) self.assertTrue(mock_info.call_count == 0)
def test_verify_log(self): ''' Test that verify_log works as expected ''' message = 'Insecure logging configuration detected! Sensitive data may be logged.' mock_cheese = MagicMock() with patch.object(log, 'warning', mock_cheese): verify_log({'log_level': 'cheeseshop'}) mock_cheese.assert_called_once_with(message) mock_trace = MagicMock() with patch.object(log, 'warning', mock_trace): verify_log({'log_level': 'trace'}) mock_trace.assert_called_once_with(message) mock_none = MagicMock() with patch.object(log, 'warning', mock_none): verify_log({}) mock_none.assert_called_once_with(message) mock_info = MagicMock() with patch.object(log, 'warning', mock_info): verify_log({'log_level': 'info'}) self.assertTrue(mock_info.call_count == 0)
def prepare(self): ''' Run the preparation sequence required to start a salt syndic minion. If sub-classed, don't **ever** forget to run: super(YourSubClass, self).prepare() ''' super(SaltMaid, self).prepare() self.setup_logfile_logger() verify_log(self.config) self.action_log_info('Setting up "{0}"'.format(self.config['id'])) self.daemonize_if_required() self.set_pidfile()
def new_run(self): ''' Execute salt-cp ''' self.parse_args() # Setup file logging! self.setup_logfile_logger() verify_log(self.config) cp_ = SaltCP(self.config) if self.config['order_masters'] == True: cp_.new_run() else: cp_.run()
def run(self): """ Run the api """ ui = salt.spm.SPMCmdlineInterface() self.parse_args() self.setup_logfile_logger() v_dirs = [ self.config["spm_cache_dir"], ] verify_env( v_dirs, self.config["user"], root_dir=self.config["root_dir"], ) verify_log(self.config) client = salt.spm.SPMClient(ui, self.config) client.run(self.args)
def run(self): ''' Run the api ''' ui = salt.spm.SPMCmdlineInterface() self.parse_args() self.setup_logfile_logger() v_dirs = [ self.config['cachedir'], ] verify_env( v_dirs, self.config['user'], ) verify_log(self.config) client = salt.spm.SPMClient(ui, self.config) client.run(self.args)
def run(self): ''' Execute the salt call! ''' self.parse_args() if self.options.file_root: # check if the argument is pointing to a file on disk file_root = os.path.abspath(self.options.file_root) self.config['file_roots'] = { 'base': _expand_glob_path([file_root]) } if self.options.pillar_root: # check if the argument is pointing to a file on disk pillar_root = os.path.abspath(self.options.pillar_root) self.config['pillar_roots'] = { 'base': _expand_glob_path([pillar_root]) } if self.options.states_dir: # check if the argument is pointing to a file on disk states_dir = os.path.abspath(self.options.states_dir) self.config['states_dirs'] = [states_dir] if self.options.local: self.config['file_client'] = 'local' if self.options.master: self.config['master'] = self.options.master # Setup file logging! self.setup_logfile_logger() verify_log(self.config) caller = salt.cli.caller.Caller.factory(self.config) if self.options.doc: caller.print_docs() self.exit(salt.defaults.exitcodes.EX_OK) if self.options.grains_run: caller.print_grains() self.exit(salt.defaults.exitcodes.EX_OK) caller.run()
def run(self): ''' Execute salt-cp ''' self.parse_args() if self.config['verify_env']: if not self.config['log_file'].startswith( ('tcp://', 'udp://', 'file://')): # Logfile is not using Syslog, verify verify_files([self.config['log_file']], self.config['user']) # Setup file logging! self.setup_logfile_logger() verify_log(self.config) cp_ = SaltCP(self.config) cp_.run()
def run(self): ''' Execute salt-key ''' import salt.key self.parse_args() if self.config['verify_env']: verify_env_dirs = [] if not self.config['gen_keys']: if self.config['transport'] == 'raet': verify_env_dirs.extend([ self.config['pki_dir'], os.path.join(self.config['pki_dir'], 'accepted'), os.path.join(self.config['pki_dir'], 'pending'), os.path.join(self.config['pki_dir'], 'rejected'), ]) elif self.config['transport'] == 'zeromq': verify_env_dirs.extend([ self.config['pki_dir'], os.path.join(self.config['pki_dir'], 'minions'), os.path.join(self.config['pki_dir'], 'minions_pre'), os.path.join(self.config['pki_dir'], 'minions_rejected'), ]) verify_env( verify_env_dirs, self.config['user'], permissive=self.config['permissive_pki_access'], pki_dir=self.config['pki_dir'], ) if not self.config['log_file'].startswith( ('tcp://', 'udp://', 'file://')): # Logfile is not using Syslog, verify verify_files([self.config['key_logfile']], self.config['user']) self.setup_logfile_logger() verify_log(self.config) key = salt.key.KeyCLI(self.config) if check_user(self.config['user']): key.run()
def run(self): ''' Execute salt-key ''' import salt.key self.parse_args() multi = False if self.config.get('zmq_behavior') and self.config.get('transport') == 'raet': multi = True self.setup_logfile_logger() verify_log(self.config) if multi: key = salt.key.MultiKeyCLI(self.config) else: key = salt.key.KeyCLI(self.config) if check_user(self.config['user']): key.run()
def run(self): """ Execute salt-run """ import salt.runner self.parse_args() # Setup file logging! self.setup_logfile_logger() verify_log(self.config) profiling_enabled = self.options.profiling_enabled runner = salt.runner.Runner(self.config) if self.options.doc: runner.print_docs() self.exit(salt.defaults.exitcodes.EX_OK) # Run this here so SystemExit isn't raised anywhere else when # someone tries to use the runners via the python API try: if check_user(self.config["user"]): pr = salt.utils.profile.activate_profile(profiling_enabled) try: ret = runner.run() # In older versions ret['data']['retcode'] was used # for signaling the return code. This has been # changed for the orchestrate runner, but external # runners might still use it. For this reason, we # also check ret['data']['retcode'] if # ret['retcode'] is not available. if isinstance(ret, dict) and "retcode" in ret: self.exit(ret["retcode"]) elif isinstance(ret, dict) and "retcode" in ret.get("data", {}): self.exit(ret["data"]["retcode"]) finally: salt.utils.profile.output_profile( pr, stats_path=self.options.profiling_path, stop=True ) except SaltClientError as exc: raise SystemExit(str(exc))
def prepare(self): ''' Run the preparation sequence required to start a salt syndic minion. If sub-classed, don't **ever** forget to run: super(YourSubClass, self).prepare() ''' super(Syndic, self).prepare() try: if self.config['verify_env']: verify_env( [ self.config['pki_dir'], self.config['cachedir'], self.config['sock_dir'], self.config['extension_modules'], ], self.config['user'], permissive=self.config['permissive_pki_access'], pki_dir=self.config['pki_dir'], ) logfile = self.config['log_file'] if logfile is not None and not logfile.startswith( ('tcp://', 'udp://', 'file://')): # Logfile is not using Syslog, verify current_umask = os.umask(0o027) verify_files([logfile], self.config['user']) os.umask(current_umask) except OSError as error: self.environment_failure(error) self.setup_logfile_logger() verify_log(self.config) self.action_log_info('Setting up "{0}"'.format(self.config['id'])) # Late import so logging works correctly import salt.minion self.daemonize_if_required() self.syndic = salt.minion.SyndicManager(self.config) self.set_pidfile()
def run(self): """ Execute the salt call! """ self.parse_args() if self.options.file_root: # check if the argument is pointing to a file on disk file_root = os.path.abspath(self.options.file_root) self.config["file_roots"] = {"base": _expand_glob_path([file_root])} if self.options.pillar_root: # check if the argument is pointing to a file on disk pillar_root = os.path.abspath(self.options.pillar_root) self.config["pillar_roots"] = {"base": _expand_glob_path([pillar_root])} if self.options.states_dir: # check if the argument is pointing to a file on disk states_dir = os.path.abspath(self.options.states_dir) self.config["states_dirs"] = [states_dir] if self.options.local: self.config["file_client"] = "local" if self.options.master: self.config["master"] = self.options.master # Setup file logging! self.setup_logfile_logger() verify_log(self.config) caller = salt.cli.caller.Caller.factory(self.config) if self.options.doc: caller.print_docs() self.exit(salt.defaults.exitcodes.EX_OK) if self.options.grains_run: caller.print_grains() self.exit(salt.defaults.exitcodes.EX_OK) caller.run()
def run(self): ''' Execute salt-run ''' import salt.runner self.parse_args() if self.config['verify_env']: verify_env( [ self.config['pki_dir'], self.config['cachedir'], ], self.config['user'], permissive=self.config['permissive_pki_access'], pki_dir=self.config['pki_dir'], ) if not self.config['log_file'].startswith( ('tcp://', 'udp://', 'file://')): # Logfile is not using Syslog, verify verify_files([self.config['log_file']], self.config['user']) # Setup file logging! self.setup_logfile_logger() verify_log(self.config) runner = salt.runner.Runner(self.config) if self.options.doc: runner.print_docs() self.exit(salt.defaults.exitcodes.EX_OK) # Run this here so SystemExit isn't raised anywhere else when # someone tries to use the runners via the python API try: if check_user(self.config['user']): runner.run() except SaltClientError as exc: raise SystemExit(str(exc))
def prepare(self): ''' Run the preparation sequence required to start a salt minion. If sub-classed, don't **ever** forget to run: super(YourSubClass, self).prepare() ''' super(Minion, self).prepare() try: if self.config['verify_env']: confd = self.config.get('default_include') if confd: # If 'default_include' is specified in config, then use it if '*' in confd: # Value is of the form "minion.d/*.conf" confd = os.path.dirname(confd) if not os.path.isabs(confd): # If configured 'default_include' is not an absolute # path, consider it relative to folder of 'conf_file' # (/etc/salt by default) confd = os.path.join( os.path.dirname(self.config['conf_file']), confd ) else: confd = os.path.join( os.path.dirname(self.config['conf_file']), 'minion.d' ) v_dirs = [ self.config['pki_dir'], self.config['cachedir'], self.config['sock_dir'], self.config['extension_modules'], confd, ] if self.config.get('transport') == 'raet': v_dirs.append(os.path.join(self.config['pki_dir'], 'accepted')) v_dirs.append(os.path.join(self.config['pki_dir'], 'pending')) v_dirs.append(os.path.join(self.config['pki_dir'], 'rejected')) v_dirs.append(os.path.join(self.config['cachedir'], 'raet')) verify_env( v_dirs, self.config['user'], permissive=self.config['permissive_pki_access'], pki_dir=self.config['pki_dir'], ) except OSError as error: self.environment_failure(error) self.setup_logfile_logger() verify_log(self.config) log.info( 'Setting up the Salt Minion "{0}"'.format( self.config['id'] ) ) migrations.migrate_paths(self.config) # Bail out if we find a process running and it matches out pidfile if self.check_running(): self.action_log_info('An instance is already running. Exiting') self.shutdown(1) transport = self.config.get('transport').lower() # TODO: AIO core is separate from transport if transport in ('zeromq', 'tcp', 'detect'): # Late import so logging works correctly import salt.minion # If the minion key has not been accepted, then Salt enters a loop # waiting for it, if we daemonize later then the minion could halt # the boot process waiting for a key to be accepted on the master. # This is the latest safe place to daemonize self.daemonize_if_required() self.set_pidfile() if self.config.get('master_type') == 'func': salt.minion.eval_master_func(self.config) self.minion = salt.minion.MinionManager(self.config) elif transport == 'raet': import salt.daemons.flo self.daemonize_if_required() self.set_pidfile() self.minion = salt.daemons.flo.IofloMinion(self.config) else: log.error( 'The transport \'{0}\' is not supported. Please use one of the following: ' 'tcp, ' 'raet, ' 'or zeromq.'.format(transport) ) self.shutdown(1)
def prepare(self): ''' Run the preparation sequence required to start a salt master server. If sub-classed, don't **ever** forget to run: super(YourSubClass, self).prepare() ''' super(Master, self).prepare() try: if self.config['verify_env']: v_dirs = [ self.config['pki_dir'], os.path.join(self.config['pki_dir'], 'minions'), os.path.join(self.config['pki_dir'], 'minions_pre'), os.path.join(self.config['pki_dir'], 'minions_denied'), os.path.join(self.config['pki_dir'], 'minions_autosign'), os.path.join(self.config['pki_dir'], 'minions_rejected'), self.config['cachedir'], os.path.join(self.config['cachedir'], 'jobs'), os.path.join(self.config['cachedir'], 'proc'), self.config['sock_dir'], self.config['token_dir'], self.config['syndic_dir'], self.config['sqlite_queue_dir'], ] if self.config.get('transport') == 'raet': v_dirs.append(os.path.join(self.config['pki_dir'], 'accepted')) v_dirs.append(os.path.join(self.config['pki_dir'], 'pending')) v_dirs.append(os.path.join(self.config['pki_dir'], 'rejected')) v_dirs.append(os.path.join(self.config['cachedir'], 'raet')) verify_env( v_dirs, self.config['user'], permissive=self.config['permissive_pki_access'], pki_dir=self.config['pki_dir'], ) logfile = self.config['log_file'] if logfile is not None and not logfile.startswith(('tcp://', 'udp://', 'file://')): # Logfile is not using Syslog, verify current_umask = os.umask(0o027) verify_files([logfile], self.config['user']) os.umask(current_umask) # Clear out syndics from cachedir for syndic_file in os.listdir(self.config['syndic_dir']): os.remove(os.path.join(self.config['syndic_dir'], syndic_file)) except OSError as err: log.exception('Failed to prepare salt environment') self.shutdown(err.errno) self.setup_logfile_logger() verify_log(self.config) log.info('Setting up the Salt Master') # TODO: AIO core is separate from transport if self.config['transport'].lower() in ('zeromq', 'tcp'): if not verify_socket(self.config['interface'], self.config['publish_port'], self.config['ret_port']): self.shutdown(4, 'The ports are not available to bind') self.config['interface'] = ip_bracket(self.config['interface']) migrations.migrate_paths(self.config) # Late import so logging works correctly import salt.master self.master = salt.master.Master(self.config) else: # Add a udp port check here import salt.daemons.flo self.master = salt.daemons.flo.IofloMaster(self.config) self.daemonize_if_required() self.set_pidfile() salt.utils.process.notify_systemd()
def prepare(self): ''' Run the preparation sequence required to start a salt proxy minion. If sub-classed, don't **ever** forget to run: super(YourSubClass, self).prepare() ''' super(ProxyMinion, self).prepare() if not self.values.proxyid: self.error('salt-proxy requires --proxyid') # Proxies get their ID from the command line. This may need to change in # the future. # We used to set this here. Now it is set in ProxyMinionOptionParser # by passing it via setup_config to config.minion_config # self.config['id'] = self.values.proxyid try: if self.config['verify_env']: confd = self.config.get('default_include') if confd: # If 'default_include' is specified in config, then use it if '*' in confd: # Value is of the form "minion.d/*.conf" confd = os.path.dirname(confd) if not os.path.isabs(confd): # If configured 'default_include' is not an absolute # path, consider it relative to folder of 'conf_file' # (/etc/salt by default) confd = os.path.join( os.path.dirname(self.config['conf_file']), confd ) else: confd = os.path.join( os.path.dirname(self.config['conf_file']), 'proxy.d' ) v_dirs = [ self.config['pki_dir'], self.config['cachedir'], self.config['sock_dir'], self.config['extension_modules'], confd, ] if self.config.get('transport') == 'raet': v_dirs.append(os.path.join(self.config['pki_dir'], 'accepted')) v_dirs.append(os.path.join(self.config['pki_dir'], 'pending')) v_dirs.append(os.path.join(self.config['pki_dir'], 'rejected')) v_dirs.append(os.path.join(self.config['cachedir'], 'raet')) verify_env( v_dirs, self.config['user'], permissive=self.config['permissive_pki_access'], pki_dir=self.config['pki_dir'], ) except OSError as error: self.environment_failure(error) self.setup_logfile_logger() verify_log(self.config) self.action_log_info('Setting up "{0}"'.format(self.config['id'])) migrations.migrate_paths(self.config) # Bail out if we find a process running and it matches out pidfile if self.check_running(): self.action_log_info('An instance is already running. Exiting') self.shutdown(1) # TODO: AIO core is separate from transport if self.config['transport'].lower() in ('zeromq', 'tcp', 'detect'): # Late import so logging works correctly import salt.minion # If the minion key has not been accepted, then Salt enters a loop # waiting for it, if we daemonize later then the minion could halt # the boot process waiting for a key to be accepted on the master. # This is the latest safe place to daemonize self.daemonize_if_required() self.set_pidfile() if self.config.get('master_type') == 'func': salt.minion.eval_master_func(self.config) self.minion = salt.minion.ProxyMinionManager(self.config) else: # For proxy minions, this doesn't work yet. import salt.daemons.flo self.daemonize_if_required() self.set_pidfile() self.minion = salt.daemons.flo.IofloMinion(self.config)
def prepare(self): ''' Run the preparation sequence required to start a salt minion. If sub-classed, don't **ever** forget to run: super(YourSubClass, self).prepare() ''' super(ProxyMinion, self).prepare() if not self.values.proxyid: raise SaltSystemExit('salt-proxy requires --proxyid') # Proxies get their ID from the command line. This may need to change in # the future. self.config['id'] = self.values.proxyid try: if self.config['verify_env']: confd = self.config.get('default_include') if confd: # If 'default_include' is specified in config, then use it if '*' in confd: # Value is of the form "minion.d/*.conf" confd = os.path.dirname(confd) if not os.path.isabs(confd): # If configured 'default_include' is not an absolute # path, consider it relative to folder of 'conf_file' # (/etc/salt by default) confd = os.path.join( os.path.dirname(self.config['conf_file']), confd ) else: confd = os.path.join( os.path.dirname(self.config['conf_file']), 'minion.d' ) v_dirs = [ self.config['pki_dir'], self.config['cachedir'], self.config['sock_dir'], self.config['extension_modules'], confd, ] if self.config.get('transport') == 'raet': v_dirs.append(os.path.join(self.config['pki_dir'], 'accepted')) v_dirs.append(os.path.join(self.config['pki_dir'], 'pending')) v_dirs.append(os.path.join(self.config['pki_dir'], 'rejected')) v_dirs.append(os.path.join(self.config['cachedir'], 'raet')) verify_env( v_dirs, self.config['user'], permissive=self.config['permissive_pki_access'], pki_dir=self.config['pki_dir'], ) if 'proxy_log' in self.config: logfile = self.config['proxy_log'] else: logfile = self.config['log_file'] if logfile is not None and not logfile.startswith(('tcp://', 'udp://', 'file://')): # Logfile is not using Syslog, verify current_umask = os.umask(0o027) verify_files([logfile], self.config['user']) os.umask(current_umask) except OSError as err: log.exception('Failed to prepare salt environment') self.shutdown(err.errno) self.setup_logfile_logger() verify_log(self.config) log.info( 'Setting up a Salt Proxy Minion "{0}"'.format( self.config['id'] ) ) migrations.migrate_paths(self.config) # TODO: AIO core is separate from transport if self.config['transport'].lower() in ('zeromq', 'tcp'): # Late import so logging works correctly import salt.minion # If the minion key has not been accepted, then Salt enters a loop # waiting for it, if we daemonize later then the minion could halt # the boot process waiting for a key to be accepted on the master. # This is the latest safe place to daemonize self.daemonize_if_required() self.set_pidfile() # TODO Proxy minions don't currently support failover self.minion = salt.minion.ProxyMinion(self.config) else: # For proxy minions, this doesn't work yet. import salt.daemons.flo self.daemonize_if_required() self.set_pidfile() self.minion = salt.daemons.flo.IofloMinion(self.config)
def prepare(self): ''' Run the preparation sequence required to start a salt minion. If sub-classed, don't **ever** forget to run: super(YourSubClass, self).prepare() ''' super(Minion, self).prepare() try: if self.config['verify_env']: confd = self.config.get('default_include') if confd: # If 'default_include' is specified in config, then use it if '*' in confd: # Value is of the form "minion.d/*.conf" confd = os.path.dirname(confd) if not os.path.isabs(confd): # If configured 'default_include' is not an absolute # path, consider it relative to folder of 'conf_file' # (/etc/salt by default) confd = os.path.join( os.path.dirname(self.config['conf_file']), confd ) else: confd = os.path.join( os.path.dirname(self.config['conf_file']), 'minion.d' ) v_dirs = [ self.config['pki_dir'], self.config['cachedir'], self.config['sock_dir'], self.config['extension_modules'], confd, ] if self.config.get('transport') == 'raet': v_dirs.append(os.path.join(self.config['pki_dir'], 'accepted')) v_dirs.append(os.path.join(self.config['pki_dir'], 'pending')) v_dirs.append(os.path.join(self.config['pki_dir'], 'rejected')) v_dirs.append(os.path.join(self.config['cachedir'], 'raet')) verify_env( v_dirs, self.config['user'], permissive=self.config['permissive_pki_access'], pki_dir=self.config['pki_dir'], ) logfile = self.config['log_file'] if logfile is not None and not logfile.startswith(('tcp://', 'udp://', 'file://')): # Logfile is not using Syslog, verify current_umask = os.umask(0o027) verify_files([logfile], self.config['user']) os.umask(current_umask) except OSError as err: log.exception('Failed to prepare salt environment') self.shutdown(err.errno) self.setup_logfile_logger() verify_log(self.config) log.info( 'Setting up the Salt Minion "{0}"'.format( self.config['id'] ) ) migrations.migrate_paths(self.config) # Bail out if we find a process running and it matches out pidfile if self.check_running(): log.exception('Salt minion is already running. Exiting.') self.shutdown(1) # TODO: AIO core is separate from transport if self.config['transport'].lower() in ('zeromq', 'tcp'): # Late import so logging works correctly import salt.minion # If the minion key has not been accepted, then Salt enters a loop # waiting for it, if we daemonize later then the minion could halt # the boot process waiting for a key to be accepted on the master. # This is the latest safe place to daemonize self.daemonize_if_required() self.set_pidfile() if isinstance(self.config.get('master'), list): if self.config.get('master_type') == 'failover': self.minion = salt.minion.Minion(self.config) else: self.minion = salt.minion.MultiMinion(self.config) else: self.minion = salt.minion.Minion(self.config) else: import salt.daemons.flo self.daemonize_if_required() self.set_pidfile() self.minion = salt.daemons.flo.IofloMinion(self.config)
def run(self): ''' Execute the salt-cloud command line ''' # Parse shell arguments self.parse_args() salt_master_user = self.config.get('user') if salt_master_user is None: salt_master_user = salt.utils.get_user() if not check_user(salt_master_user): self.error( 'If salt-cloud is running on a master machine, salt-cloud ' 'needs to run as the same user as the salt-master, \'{0}\'. ' 'If salt-cloud is not running on a salt-master, the ' 'appropriate write permissions must be granted to \'{1}\'. ' 'Please run salt-cloud as root, \'{0}\', or change ' 'permissions for \'{1}\'.'.format( salt_master_user, syspaths.CONFIG_DIR ) ) try: if self.config['verify_env']: verify_env( [os.path.dirname(self.config['conf_file'])], salt_master_user ) logfile = self.config['log_file'] if logfile is not None and not logfile.startswith('tcp://') \ and not logfile.startswith('udp://') \ and not logfile.startswith('file://'): # Logfile is not using Syslog, verify verify_files([logfile], salt_master_user) except (IOError, OSError) as err: log.error('Error while verifying the environment: {0}'.format(err)) sys.exit(err.errno) # Setup log file logging self.setup_logfile_logger() verify_log(self.config) if self.options.update_bootstrap: ret = salt.utils.cloud.update_bootstrap(self.config) salt.output.display_output(ret, self.options.output, opts=self.config) self.exit(salt.defaults.exitcodes.EX_OK) log.info('salt-cloud starting') try: mapper = salt.cloud.Map(self.config) except SaltCloudSystemExit as exc: self.handle_exception(exc.args, exc) except SaltCloudException as exc: msg = 'There was an error generating the mapper.' self.handle_exception(msg, exc) names = self.config.get('names', None) if names is not None: filtered_rendered_map = {} for map_profile in mapper.rendered_map: filtered_map_profile = {} for name in mapper.rendered_map[map_profile]: if name in names: filtered_map_profile[name] = mapper.rendered_map[map_profile][name] if filtered_map_profile: filtered_rendered_map[map_profile] = filtered_map_profile mapper.rendered_map = filtered_rendered_map ret = {} if self.selected_query_option is not None: if self.selected_query_option == 'list_providers': try: ret = mapper.provider_list() except (SaltCloudException, Exception) as exc: msg = 'There was an error listing providers: {0}' self.handle_exception(msg, exc) elif self.selected_query_option == 'list_profiles': provider = self.options.list_profiles try: ret = mapper.profile_list(provider) except(SaltCloudException, Exception) as exc: msg = 'There was an error listing profiles: {0}' self.handle_exception(msg, exc) elif self.config.get('map', None): log.info( 'Applying map from \'{0}\'.'.format(self.config['map']) ) try: ret = mapper.interpolated_map( query=self.selected_query_option ) except (SaltCloudException, Exception) as exc: msg = 'There was an error with a custom map: {0}' self.handle_exception(msg, exc) else: try: ret = mapper.map_providers_parallel( query=self.selected_query_option ) except (SaltCloudException, Exception) as exc: msg = 'There was an error with a map: {0}' self.handle_exception(msg, exc) elif self.options.list_locations is not None: try: ret = mapper.location_list( self.options.list_locations ) except (SaltCloudException, Exception) as exc: msg = 'There was an error listing locations: {0}' self.handle_exception(msg, exc) elif self.options.list_images is not None: try: ret = mapper.image_list( self.options.list_images ) except (SaltCloudException, Exception) as exc: msg = 'There was an error listing images: {0}' self.handle_exception(msg, exc) elif self.options.list_sizes is not None: try: ret = mapper.size_list( self.options.list_sizes ) except (SaltCloudException, Exception) as exc: msg = 'There was an error listing sizes: {0}' self.handle_exception(msg, exc) elif self.options.destroy and (self.config.get('names', None) or self.config.get('map', None)): map_file = self.config.get('map', None) names = self.config.get('names', ()) if map_file is not None: if names != (): msg = 'Supplying a mapfile, \'{0}\', in addition to instance names {1} ' \ 'with the \'--destroy\' or \'-d\' function is not supported. ' \ 'Please choose to delete either the entire map file or individual ' \ 'instances.'.format(map_file, names) self.handle_exception(msg, SaltCloudSystemExit) log.info('Applying map from \'{0}\'.'.format(map_file)) matching = mapper.delete_map(query='list_nodes') else: matching = mapper.get_running_by_names( names, profile=self.options.profile ) if not matching: print('No machines were found to be destroyed') self.exit(salt.defaults.exitcodes.EX_OK) msg = 'The following virtual machines are set to be destroyed:\n' names = set() for alias, drivers in six.iteritems(matching): msg += ' {0}:\n'.format(alias) for driver, vms in six.iteritems(drivers): msg += ' {0}:\n'.format(driver) for name in vms: msg += ' {0}\n'.format(name) names.add(name) try: if self.print_confirm(msg): ret = mapper.destroy(names, cached=True) except (SaltCloudException, Exception) as exc: msg = 'There was an error destroying machines: {0}' self.handle_exception(msg, exc) elif self.options.action and (self.config.get('names', None) or self.config.get('map', None)): if self.config.get('map', None): log.info( 'Applying map from \'{0}\'.'.format(self.config['map']) ) try: names = mapper.get_vmnames_by_action(self.options.action) except SaltCloudException as exc: msg = 'There was an error actioning virtual machines.' self.handle_exception(msg, exc) else: names = self.config.get('names', None) kwargs = {} machines = [] msg = ( 'The following virtual machines are set to be actioned with ' '"{0}":\n'.format( self.options.action ) ) for name in names: if '=' in name: # This is obviously not a machine name, treat it as a kwarg key, value = name.split('=', 1) kwargs[key] = value else: msg += ' {0}\n'.format(name) machines.append(name) names = machines try: if self.print_confirm(msg): ret = mapper.do_action(names, kwargs) except (SaltCloudException, Exception) as exc: msg = 'There was an error actioning machines: {0}' self.handle_exception(msg, exc) elif self.options.function: kwargs = {} args = self.args[:] for arg in args[:]: if '=' in arg: key, value = arg.split('=', 1) kwargs[key] = value args.remove(arg) if args: self.error( 'Any arguments passed to --function need to be passed ' 'as kwargs. Ex: image=ami-54cf5c3d. Remaining ' 'arguments: {0}'.format(args) ) try: ret = mapper.do_function( self.function_provider, self.function_name, kwargs ) except (SaltCloudException, Exception) as exc: msg = 'There was an error running the function: {0}' self.handle_exception(msg, exc) elif self.options.profile and self.config.get('names', False): try: ret = mapper.run_profile( self.options.profile, self.config.get('names') ) except (SaltCloudException, Exception) as exc: msg = 'There was a profile error: {0}' self.handle_exception(msg, exc) elif self.options.set_password: username = self.credential_username provider_name = "salt.cloud.provider.{0}".format(self.credential_provider) # TODO: check if provider is configured # set the password salt.utils.cloud.store_password_in_keyring(provider_name, username) elif self.config.get('map', None) and \ self.selected_query_option is None: if len(mapper.rendered_map) == 0: sys.stderr.write('No nodes defined in this map') self.exit(salt.defaults.exitcodes.EX_GENERIC) try: ret = {} run_map = True log.info( 'Applying map from \'{0}\'.'.format(self.config['map']) ) dmap = mapper.map_data() msg = '' if 'errors' in dmap: # display profile errors msg += 'Found the following errors:\n' for profile_name, error in six.iteritems(dmap['errors']): msg += ' {0}: {1}\n'.format(profile_name, error) sys.stderr.write(msg) sys.stderr.flush() msg = '' if 'existing' in dmap: msg += ('The following virtual machines already exist:\n') for name in dmap['existing']: msg += ' {0}\n'.format(name) if dmap['create']: msg += ('The following virtual machines are set to be ' 'created:\n') for name in dmap['create']: msg += ' {0}\n'.format(name) if 'destroy' in dmap: msg += ('The following virtual machines are set to be ' 'destroyed:\n') for name in dmap['destroy']: msg += ' {0}\n'.format(name) if not dmap['create'] and not dmap.get('destroy', None): if not dmap.get('existing', None): # nothing to create or destroy & nothing exists print(msg) self.exit(1) else: # nothing to create or destroy, print existing run_map = False if run_map: if self.print_confirm(msg): ret = mapper.run_map(dmap) if self.config.get('parallel', False) is False: log.info('Complete') if dmap.get('existing', None): for name in dmap['existing']: if 'ec2' in dmap['existing'][name]['provider']: msg = 'Instance already exists, or is terminated and has the same name.' else: msg = 'Already running.' ret[name] = {'Message': msg} except (SaltCloudException, Exception) as exc: msg = 'There was a query error: {0}' self.handle_exception(msg, exc) elif self.options.bootstrap: host = self.options.bootstrap if len(self.args) > 0: if '=' not in self.args[0]: minion_id = self.args.pop(0) else: minion_id = host else: minion_id = host vm_ = { 'driver': '', 'ssh_host': host, 'name': minion_id, } args = self.args[:] for arg in args[:]: if '=' in arg: key, value = arg.split('=', 1) vm_[key] = value args.remove(arg) if args: self.error( 'Any arguments passed to --bootstrap need to be passed as ' 'kwargs. Ex: ssh_username=larry. Remaining arguments: {0}'.format(args) ) try: ret = salt.utils.cloud.bootstrap(vm_, self.config) except (SaltCloudException, Exception) as exc: msg = 'There was an error bootstrapping the minion: {0}' self.handle_exception(msg, exc) else: self.error('Nothing was done. Using the proper arguments?') salt.output.display_output(ret, self.options.output, opts=self.config) self.exit(salt.defaults.exitcodes.EX_OK)
def run(self): """ Execute the salt command line """ import salt.client self.parse_args() # Setup file logging! self.setup_logfile_logger() verify_log(self.config) try: # We don't need to bail on config file permission errors # if the CLI # process is run with the -a flag skip_perm_errors = self.options.eauth != "" self.local_client = salt.client.get_local_client( self.get_config_file_path(), skip_perm_errors=skip_perm_errors, auto_reconnect=True ) except SaltClientError as exc: self.exit(2, "{0}\n".format(exc)) return if self.options.batch or self.options.static: # _run_batch() will handle all output and # exit with the appropriate error condition # Execution will not continue past this point # in batch mode. self._run_batch() return if self.options.timeout <= 0: self.options.timeout = self.local_client.opts["timeout"] kwargs = { "tgt": self.config["tgt"], "fun": self.config["fun"], "arg": self.config["arg"], "timeout": self.options.timeout, "show_timeout": self.options.show_timeout, "show_jid": self.options.show_jid, } if "token" in self.config: try: with salt.utils.fopen(os.path.join(self.config["cachedir"], ".root_key"), "r") as fp_: kwargs["key"] = fp_.readline() except IOError: kwargs["token"] = self.config["token"] kwargs["delimiter"] = self.options.delimiter if self.selected_target_option: kwargs["tgt_type"] = self.selected_target_option else: kwargs["tgt_type"] = "glob" if getattr(self.options, "return"): kwargs["ret"] = getattr(self.options, "return") if getattr(self.options, "return_config"): kwargs["ret_config"] = getattr(self.options, "return_config") if getattr(self.options, "return_kwargs"): kwargs["ret_kwargs"] = yamlify_arg(getattr(self.options, "return_kwargs")) if getattr(self.options, "module_executors"): kwargs["module_executors"] = yamlify_arg(getattr(self.options, "module_executors")) if getattr(self.options, "metadata"): kwargs["metadata"] = yamlify_arg(getattr(self.options, "metadata")) # If using eauth and a token hasn't already been loaded into # kwargs, prompt the user to enter auth credentials if "token" not in kwargs and "key" not in kwargs and self.options.eauth: # This is expensive. Don't do it unless we need to. import salt.auth resolver = salt.auth.Resolver(self.config) res = resolver.cli(self.options.eauth) if self.options.mktoken and res: tok = resolver.token_cli(self.options.eauth, res) if tok: kwargs["token"] = tok.get("token", "") if not res: sys.stderr.write("ERROR: Authentication failed\n") sys.exit(2) kwargs.update(res) kwargs["eauth"] = self.options.eauth if self.config["async"]: jid = self.local_client.cmd_async(**kwargs) print_cli("Executed command with job ID: {0}".format(jid)) return # local will be None when there was an error if not self.local_client: return retcodes = [] errors = [] try: if self.options.subset: cmd_func = self.local_client.cmd_subset kwargs["sub"] = True kwargs["cli"] = True else: cmd_func = self.local_client.cmd_cli if self.options.progress: kwargs["progress"] = True self.config["progress"] = True ret = {} for progress in cmd_func(**kwargs): out = "progress" try: self._progress_ret(progress, out) except salt.exceptions.LoaderError as exc: raise salt.exceptions.SaltSystemExit(exc) if "return_count" not in progress: ret.update(progress) self._progress_end(out) self._print_returns_summary(ret) elif self.config["fun"] == "sys.doc": ret = {} out = "" for full_ret in self.local_client.cmd_cli(**kwargs): ret_, out, retcode = self._format_ret(full_ret) ret.update(ret_) self._output_ret(ret, out) else: if self.options.verbose: kwargs["verbose"] = True ret = {} for full_ret in cmd_func(**kwargs): try: ret_, out, retcode = self._format_ret(full_ret) retcodes.append(retcode) self._output_ret(ret_, out) ret.update(full_ret) except KeyError: errors.append(full_ret) # Returns summary if self.config["cli_summary"] is True: if self.config["fun"] != "sys.doc": if self.options.output is None: self._print_returns_summary(ret) self._print_errors_summary(errors) # NOTE: Return code is set here based on if all minions # returned 'ok' with a retcode of 0. # This is the final point before the 'salt' cmd returns, # which is why we set the retcode here. if retcodes.count(0) < len(retcodes): sys.stderr.write("ERROR: Minions returned with non-zero exit code\n") sys.exit(11) except (SaltInvocationError, EauthAuthenticationError, SaltClientError) as exc: ret = str(exc) self._output_ret(ret, "")
def run(self): ''' Execute the salt command line ''' import salt.auth import salt.client self.parse_args() # Setup file logging! self.setup_logfile_logger() verify_log(self.config) try: # We don't need to bail on config file permission errors # if the CLI # process is run with the -a flag skip_perm_errors = self.options.eauth != '' local = salt.client.get_local_client( self.get_config_file_path(), skip_perm_errors=skip_perm_errors) except SaltClientError as exc: self.exit(2, '{0}\n'.format(exc)) return if self.options.batch or self.options.static: self._run_batch() else: if self.options.timeout <= 0: self.options.timeout = local.opts['timeout'] kwargs = { 'tgt': self.config['tgt'], 'fun': self.config['fun'], 'arg': self.config['arg'], 'timeout': self.options.timeout, 'show_timeout': self.options.show_timeout, 'show_jid': self.options.show_jid} if 'token' in self.config: try: with salt.utils.fopen(os.path.join(self.config['cachedir'], '.root_key'), 'r') as fp_: kwargs['key'] = fp_.readline() except IOError: kwargs['token'] = self.config['token'] kwargs['delimiter'] = self.options.delimiter if self.selected_target_option: kwargs['expr_form'] = self.selected_target_option else: kwargs['expr_form'] = 'glob' if getattr(self.options, 'return'): kwargs['ret'] = getattr(self.options, 'return') if getattr(self.options, 'return_config'): kwargs['ret_config'] = getattr(self.options, 'return_config') if getattr(self.options, 'return_kwargs'): kwargs['ret_kwargs'] = yamlify_arg( getattr(self.options, 'return_kwargs')) if getattr(self.options, 'module_executors'): kwargs['module_executors'] = yamlify_arg(getattr(self.options, 'module_executors')) if getattr(self.options, 'metadata'): kwargs['metadata'] = yamlify_arg( getattr(self.options, 'metadata')) # If using eauth and a token hasn't already been loaded into # kwargs, prompt the user to enter auth credentials if 'token' not in kwargs and 'key' not in kwargs and self.options.eauth: resolver = salt.auth.Resolver(self.config) res = resolver.cli(self.options.eauth) if self.options.mktoken and res: tok = resolver.token_cli( self.options.eauth, res ) if tok: kwargs['token'] = tok.get('token', '') if not res: sys.stderr.write('ERROR: Authentication failed\n') sys.exit(2) kwargs.update(res) kwargs['eauth'] = self.options.eauth if self.config['async']: jid = local.cmd_async(**kwargs) print_cli('Executed command with job ID: {0}'.format(jid)) return retcodes = [] try: # local will be None when there was an error errors = [] if local: if self.options.subset: cmd_func = local.cmd_subset kwargs['sub'] = self.options.subset kwargs['cli'] = True else: cmd_func = local.cmd_cli if self.options.progress: kwargs['progress'] = True self.config['progress'] = True ret = {} for progress in cmd_func(**kwargs): out = 'progress' try: self._progress_ret(progress, out) except salt.exceptions.LoaderError as exc: raise salt.exceptions.SaltSystemExit(exc) if 'return_count' not in progress: ret.update(progress) self._progress_end(out) self._print_returns_summary(ret) elif self.config['fun'] == 'sys.doc': ret = {} out = '' for full_ret in local.cmd_cli(**kwargs): ret_, out, retcode = self._format_ret(full_ret) ret.update(ret_) self._output_ret(ret, out) else: if self.options.verbose: kwargs['verbose'] = True ret = {} for full_ret in cmd_func(**kwargs): try: ret_, out, retcode = self._format_ret(full_ret) retcodes.append(retcode) self._output_ret(ret_, out) ret.update(full_ret) except KeyError: errors.append(full_ret) # Returns summary if self.config['cli_summary'] is True: if self.config['fun'] != 'sys.doc': if self.options.output is None: self._print_returns_summary(ret) self._print_errors_summary(errors) # NOTE: Return code is set here based on if all minions # returned 'ok' with a retcode of 0. # This is the final point before the 'salt' cmd returns, # which is why we set the retcode here. if retcodes.count(0) < len(retcodes): sys.stderr.write('ERROR: Minions returned with non-zero exit code\n') sys.exit(11) except (SaltInvocationError, EauthAuthenticationError, SaltClientError) as exc: ret = str(exc) out = '' self._output_ret(ret, out)