标签:salt-ssh
Salt Master和Minions之间可以通过SSH方式进行通信。 Salt SSH系统不会取代原有的通信系统,只是提供另外一种可选的方法不需要安装ZeroMQ和agent。但是执行效率没有ZeroMQ快。
/usr/bin/salt-ssh
#!/usr/bin/python # EASY-INSTALL-ENTRY-SCRIPT: ‘salt==2014.7.0‘,‘console_scripts‘,‘salt-ssh‘ __requires__ = ‘salt==2014.7.0‘ import sys from pkg_resources import load_entry_point if __name__ == ‘__main__‘: sys.exit( load_entry_point(‘salt==2014.7.0‘, ‘console_scripts‘, ‘salt-ssh‘)() )
/usr/lib/python2.6/site-packages/salt/scripts.py
def salt_ssh(): ‘‘‘ Execute the salt-ssh system ‘‘‘ if ‘‘ in sys.path: sys.path.remove(‘‘) client = None try: client = salt.cli.SaltSSH() client.run() except KeyboardInterrupt, err: trace = traceback.format_exc() try: hardcrash = client.options.hard_crash except (AttributeError, KeyError): hardcrash = False _handle_interrupt( SystemExit(‘\nExiting gracefully on Ctrl-c‘), err, hardcrash, trace=trace) except salt.exceptions.SaltClientError as err: trace = traceback.format_exc() try: hardcrash = client.options.hard_crash except (AttributeError, KeyError): hardcrash = False _handle_interrupt( SystemExit(err), err, hardcrash, trace=trace)
/usr/lib/python2.6/site-packages/salt/cli/__init__.py
class SaltSSH(parsers.SaltSSHOptionParser): ‘‘‘ Used to Execute the salt ssh routine ‘‘‘ def run(self): self.parse_args() ssh = salt.client.ssh.SSH(self.config) ssh.run()
/usr/lib/python2.6/site-packages/salt/client/ssh/__init__.py
class SSH(object): ‘‘‘ Create an SSH execution system ‘‘‘ def __init__(self, opts): pull_sock = os.path.join(opts[‘sock_dir‘], ‘master_event_pull.ipc‘) if os.path.isfile(pull_sock) and HAS_ZMQ: self.event = salt.utils.event.get_event( ‘master‘, listen=False) else: self.event = None self.opts = opts self.opts[‘_ssh_version‘] = ssh_version() self.tgt_type = self.opts[‘selected_target_option‘] if self.opts[‘selected_target_option‘] else ‘glob‘ self.roster = salt.roster.Roster(opts, opts.get(‘roster‘)) self.targets = self.roster.targets( self.opts[‘tgt‘], self.tgt_type) priv = self.opts.get( ‘ssh_priv‘, os.path.join( self.opts[‘pki_dir‘], ‘ssh‘, ‘salt-ssh.rsa‘ ) ) if not os.path.isfile(priv): try: salt.client.ssh.shell.gen_key(priv) except OSError: self.defaults = { ‘user‘: self.opts.get( ‘ssh_user‘, salt.config.DEFAULT_MASTER_OPTS[‘ssh_user‘] ), ‘port‘: self.opts.get( ‘ssh_port‘, salt.config.DEFAULT_MASTER_OPTS[‘ssh_port‘] ), ‘passwd‘: self.opts.get( ‘ssh_passwd‘, salt.config.DEFAULT_MASTER_OPTS[‘ssh_passwd‘] ), ‘priv‘: priv, ‘timeout‘: self.opts.get( ‘ssh_timeout‘, salt.config.DEFAULT_MASTER_OPTS[‘ssh_timeout‘] ) + self.opts.get( ‘timeout‘, salt.config.DEFAULT_MASTER_OPTS[‘timeout‘] ), ‘sudo‘: self.opts.get( ‘ssh_sudo‘, salt.config.DEFAULT_MASTER_OPTS[‘ssh_sudo‘] ), } if self.opts.get(‘rand_thin_dir‘): self.defaults[‘thin_dir‘] = os.path.join( ‘/tmp‘, ‘.{0}‘.format(uuid.uuid4().hex[:6])) self.opts[‘wipe_ssh‘] = ‘True‘ self.serial = salt.payload.Serial(opts) self.returners = salt.loader.returners(self.opts, {}) self.fsclient = salt.fileclient.FSClient(self.opts) self.mods = mod_data(self.fsclient) def get_pubkey(self): ‘‘‘ Return the key string for the SSH public key ‘‘‘ priv = self.opts.get( ‘ssh_priv‘, os.path.join( self.opts[‘pki_dir‘], ‘ssh‘, ‘salt-ssh.rsa‘ ) ) pub = ‘{0}.pub‘.format(priv) with open(pub, ‘r‘) as fp_: return ‘{0} rsa root@master‘.format(fp_.read().split()[1]) def key_deploy(self, host, ret): ‘‘‘ Deploy the SSH key if the minions don‘t auth ‘‘‘ if not isinstance(ret[host], dict): if self.opts.get(‘ssh_key_deploy‘): target = self.targets[host] if ‘passwd‘ in target: self._key_deploy_run(host, target, False) return ret if ret[host].get(‘stderr‘, ‘‘).count(‘Permission denied‘): target = self.targets[host] # permission denied, attempt to auto deploy ssh key print((‘Permission denied for host {0}, do you want to deploy ‘ ‘the salt-ssh key? (password required):‘).format(host)) deploy = raw_input(‘[Y/n] ‘) if deploy.startswith((‘n‘, ‘N‘)): return ret target[‘passwd‘] = getpass.getpass( ‘Password for {0}@{1}: ‘.format(target[‘user‘], host) ) return self._key_deploy_run(host, target, True) return ret def _key_deploy_run(self, host, target, re_run=True): ‘‘‘ The ssh-copy-id routine ‘‘‘ argv = [ ‘ssh.set_auth_key‘, target.get(‘user‘, ‘root‘), self.get_pubkey(), ] single = Single( self.opts, argv, host, mods=self.mods, fsclient=self.fsclient, **target) if salt.utils.which(‘ssh-copy-id‘): # we have ssh-copy-id, use it! stdout, stderr, retcode = single.shell.copy_id() else: stdout, stderr, retcode = single.run() if re_run: target.pop(‘passwd‘) single = Single( self.opts, self.opts[‘argv‘], host, mods=self.mods, fsclient=self.fsclient, **target) stdout, stderr, retcode = single.cmd_block() try: data = salt.utils.find_json(stdout) return {host: data.get(‘local‘, data)} except Exception: if stderr: return {host: stderr} return {host: ‘Bad Return‘} if os.EX_OK != retcode: return {host: stderr} return {host: stdout} def handle_routine(self, que, opts, host, target): ‘‘‘ Run the routine in a "Thread", put a dict on the queue ‘‘‘ opts = copy.deepcopy(opts) single = Single( opts, opts[‘argv‘], host, mods=self.mods, fsclient=self.fsclient, **target) ret = {‘id‘: single.id} stdout, stderr, retcode = single.run() # This job is done, yield try: data = salt.utils.find_json(stdout) if len(data) < 2 and ‘local‘ in data: ret[‘ret‘] = data[‘local‘] else: ret[‘ret‘] = { ‘stdout‘: stdout, ‘stderr‘: stderr, ‘retcode‘: retcode, } except Exception: ret[‘ret‘] = { ‘stdout‘: stdout, ‘stderr‘: stderr, ‘retcode‘: retcode, } que.put(ret) def handle_ssh(self): ‘‘‘ Spin up the needed threads or processes and execute the subsequent routines ‘‘‘ que = multiprocessing.Queue() running = {} target_iter = self.targets.__iter__() returned = set() rets = set() init = False if not self.targets: raise salt.exceptions.SaltClientError(‘No matching targets found in roster.‘) while True: if len(running) < self.opts.get(‘ssh_max_procs‘, 25) and not init: try: host = next(target_iter) except StopIteration: init = True continue for default in self.defaults: if default not in self.targets[host]: self.targets[host][default] = self.defaults[default] args = ( que, self.opts, host, self.targets[host], ) routine = multiprocessing.Process( target=self.handle_routine, args=args) routine.start() running[host] = {‘thread‘: routine} continue ret = {} try: ret = que.get(False) if ‘id‘ in ret: returned.add(ret[‘id‘]) except Exception: pass for host in running: if host in returned: if not running[host][‘thread‘].is_alive(): running[host][‘thread‘].join() rets.add(host) for host in rets: if host in running: running.pop(host) if ret: if not isinstance(ret, dict): continue yield {ret[‘id‘]: ret[‘ret‘]} if len(rets) >= len(self.targets): break def run_iter(self): ‘‘‘ Execute and yield returns as they come in, do not print to the display ‘‘‘ for ret in self.handle_ssh(): yield ret def cache_job(self, jid, id_, ret): ‘‘‘ Cache the job information ‘‘‘ self.returners[‘{0}.returner‘.format(self.opts[‘master_job_cache‘])]({‘jid‘: jid, ‘id‘: id_, ‘return‘: ret}) def run(self): ‘‘‘ Execute the overall routine ‘‘‘ fstr = ‘{0}.prep_jid‘.format(self.opts[‘master_job_cache‘]) jid = self.returners[fstr]() # Save the invocation information argv = self.opts[‘argv‘] if self.opts[‘raw_shell‘]: fun = ‘ssh._raw‘ args = argv else: fun = argv[0] if argv else ‘‘ args = argv[1:] job_load = { ‘jid‘: jid, ‘tgt_type‘: self.tgt_type, ‘tgt‘: self.opts[‘tgt‘], ‘user‘: self.opts[‘user‘], ‘fun‘: fun, ‘arg‘: args, } # save load to the master job cache self.returners[‘{0}.save_load‘.format(self.opts[‘master_job_cache‘])](jid, job_load) if self.opts.get(‘verbose‘): msg = ‘Executing job with jid {0}‘.format(jid) print(msg) print(‘-‘ * len(msg) + ‘\n‘) print(‘‘) sret = {} outputter = self.opts.get(‘output‘, ‘nested‘) for ret in self.handle_ssh(): host = ret.keys()[0] self.cache_job(jid, host, ret[host]) ret = self.key_deploy(host, ret) if not isinstance(ret[host], dict): p_data = {host: ret[host]} elif ‘return‘ not in ret[host]: p_data = ret else: outputter = ret[host].get(‘out‘, self.opts.get(‘output‘, ‘nested‘)) p_data = {host: ret[host].get(‘return‘, {})} if self.opts.get(‘static‘): sret.update(p_data) else: salt.output.display_output( p_data, outputter, self.opts) if self.event: self.event.fire_event( ret, salt.utils.event.tagify( [jid, ‘ret‘, host], ‘job‘)) if self.opts.get(‘static‘): salt.output.display_output( sret, outputter, self.opts)
使用案例:
在Master端创建/etc/salt/roster
web1: 10.10.41.20
web1: host: 192.168.42.1 # The IP addr or DNS hostname user: fred # Remote executions will be executed as user fred passwd: foobarbaz # The password to use for login, if omitted, keys are used sudo: True # Whether to sudo to root, not enabled by default web2: host: 192.168.42.2
参考资料:
http://docs.saltstack.com/en/2014.7/topics/ssh/index.html
本文出自 “Linux SA John” 博客,请务必保留此出处http://john88wang.blog.51cto.com/2165294/1660495
标签:salt-ssh
原文地址:http://john88wang.blog.51cto.com/2165294/1660495