def exec_command(self, command, bufsize=-1, check_status=True): """Execute a command on the SSH server while preserving underling agent forwarding and sudo privileges. https://github.com/paramiko/paramiko/blob/1.8/paramiko/client.py#L348 :param command: the command to execute :type command: str :param bufsize: interpreted the same way as by the built-in C{file()} function in python :type bufsize: int :param check_staus: if enabled, waits for the command to complete and return an exception if the status is non-zero. :type check_staus: bool :returns the stdin, stdout, and stderr of the executing command :rtype: tuple(L{ChannelFile}, L{ChannelFile}, L{ChannelFile}) :raises SSHException: if the server fails to execute the command """ channel = self.transport.open_session() if self.forward_agent: AgentRequestHandler(channel) if self.sudoable: channel.get_pty() channel.exec_command(command) if check_status and channel.recv_exit_status() != 0: raise RuntimeError("Command execution error: {}".format(command)) stdin = channel.makefile('wb', bufsize) stdout = channel.makefile('rb', bufsize) stderr = channel.makefile_stderr('rb', bufsize) return (stdin, stdout, stderr)
def connect(self, hostname, **kwargs): self.hostname, self.config, forward_agent = self.parse_config(hostname) self.config.update(kwargs) super(SSHClient, self).connect(self.hostname, **self.config) if forward_agent: # Enable SSH forwarding session = self.get_transport().open_session() AgentRequestHandler(session)
def connect(state, host, **kwargs): ''' Connect to a single host. Returns the SSH client if succesful. Stateless by design so can be run in parallel. ''' logger.debug('Connecting to: {0} ({1})'.format(host.name, kwargs)) name = host.name hostname = host.data.ssh_hostname or name try: # Create new client & connect to the host client = SSHClient() client.set_missing_host_key_policy(MissingHostKeyPolicy()) client.connect(hostname, **kwargs) # Enable SSH forwarding session = client.get_transport().open_session() AgentRequestHandler(session) # Log logger.info('{0}{1}'.format( host.print_prefix, click.style('Connected', 'green'), )) return client except AuthenticationException as e: auth_kwargs = {} for key, value in kwargs.items(): if key in ('username', 'password'): auth_kwargs[key] = value continue if key == 'pkey' and value: auth_kwargs['key'] = host.data.ssh_key auth_args = ', '.join('{0}={1}'.format(key, value) for key, value in auth_kwargs.items()) _log_connect_error(host, 'Authentication error', auth_args) except SSHException as e: _log_connect_error(host, 'SSH error', e) except gaierror: _log_connect_error(host, 'Could not resolve hostname', hostname) except socket_error as e: _log_connect_error(host, 'Could not connect', e) except EOFError as e: _log_connect_error(host, 'EOF error', e)
def connect(state, host): ''' Connect to a single host. Returns the SSH client if succesful. Stateless by design so can be run in parallel. ''' kwargs = _make_paramiko_kwargs(state, host) logger.debug('Connecting to: {0} ({1})'.format(host.name, kwargs)) # Hostname can be provided via SSH config (alias), data, or the hosts name hostname = kwargs.pop( 'hostname', host.data.ssh_hostname or host.name, ) try: # Create new client & connect to the host client = SSHClient() client.set_missing_host_key_policy(MissingHostKeyPolicy()) client.connect(hostname, **kwargs) # Enable SSH forwarding session = client.get_transport().open_session() AgentRequestHandler(session) return client except AuthenticationException: auth_kwargs = {} for key, value in kwargs.items(): if key in ('username', 'password'): auth_kwargs[key] = value continue if key == 'pkey' and value: auth_kwargs['key'] = host.data.ssh_key auth_args = ', '.join('{0}={1}'.format(key, value) for key, value in auth_kwargs.items()) _raise_connect_error(host, 'Authentication error', auth_args) except SSHException as e: _raise_connect_error(host, 'SSH error', e) except gaierror: _raise_connect_error(host, 'Could not resolve hostname', hostname) except socket_error as e: _raise_connect_error(host, 'Could not connect', e) except EOFError as e: _raise_connect_error(host, 'EOF error', e)
async def run_async(self, command, stdin_param=None, get_pty=False, interval=10, callback=None, buff_size=1024): if not self.is_active(): log.error('ssh connection is not active') return transport = self.client.get_transport() channel = transport.open_session() if self.forward_agent: AgentRequestHandler(channel) if get_pty: channel.get_pty() channel.set_combine_stderr(True) channel.exec_command(command.encode(sys.stdout.encoding)) if stdin_param is not None: stdin = channel.makefile('wb', -1) stdin.write(stdin_param) stdin.flush() while not channel.exit_status_ready(): if callback is not None: callback(channel) await asyncio.sleep(interval) if channel.exit_status != 0: log.warn('%s exit status is not zero: %d' % (self.host, channel.exit_status)) stdout = stderr = b'' while channel.recv_ready(): stdout += channel.recv(buff_size) await asyncio.sleep(1) if stdout and self.stdout_queue is not None: s = stdout.decode(sys.stdout.encoding) self.stdout_queue.put_nowait(s) while channel.recv_stderr_ready(): stderr += channel.recv_stderr(buff_size) await asyncio.sleep(1) if stderr and self.stderr_queue is not None: s = stderr.decode(sys.stderr.encoding) self.stderr_queue.put_nowait(s) return channel.exit_status, stdout, stderr
def connect(state, host, **kwargs): ''' Connect to a single host. Returns the SSH client if succesful. Stateless by design so can be run in parallel. ''' logger.debug('Connecting to: {0} ({1})'.format(host.name, kwargs)) name = host.name hostname = host.data.ssh_hostname or name try: # Create new client & connect to the host client = SSHClient() client.set_missing_host_key_policy(MissingHostKeyPolicy()) client.connect(hostname, **kwargs) # Enable SSH forwarding session = client.get_transport().open_session() AgentRequestHandler(session) # Log logger.info('{0}{1}'.format( host.print_prefix, click.style('Connected', 'green'), )) return client except AuthenticationException as e: logger.error('Auth error on: {0}, {1}'.format(name, e)) except SSHException as e: logger.error('SSH error on: {0}, {1}'.format(name, e)) except gaierror: if hostname == name: logger.error('Could not resolve {0}'.format(name)) else: logger.error('Could not resolve for {0} (SSH host: {1})'.format( name, hostname)) except socket_error as e: logger.error( 'Could not connect: {0}:{1}, {2}'.format(name, kwargs.get('port', 22), e), ) except EOFError as e: logger.error('EOF error connecting to {0}: {1}'.format(name, e))
def connect( self, hostname, _pyinfra_ssh_forward_agent=None, _pyinfra_ssh_config_file=None, _pyinfra_ssh_known_hosts_file=None, _pyinfra_ssh_strict_host_key_checking=None, _pyinfra_ssh_paramiko_connect_kwargs=None, **kwargs, ): ( hostname, config, forward_agent, missing_host_key_policy, host_keys_file, ) = self.parse_config( hostname, kwargs, ssh_config_file=_pyinfra_ssh_config_file, strict_host_key_checking=_pyinfra_ssh_strict_host_key_checking, ) self.set_missing_host_key_policy(missing_host_key_policy) config.update(kwargs) if _pyinfra_ssh_known_hosts_file: host_keys_file = _pyinfra_ssh_known_hosts_file # Overwrite paramiko empty defaults with @memoize-d host keys object self._host_keys = get_host_keys(host_keys_file) self._host_keys_filename = host_keys_file if _pyinfra_ssh_paramiko_connect_kwargs: config.update(_pyinfra_ssh_paramiko_connect_kwargs) self._ssh_config = config super(SSHClient, self).connect(hostname, **config) if _pyinfra_ssh_forward_agent is not None: forward_agent = _pyinfra_ssh_forward_agent if forward_agent: # Enable SSH forwarding session = self.get_transport().open_session() AgentRequestHandler(session)
def remote_command(task: Task, command: str) -> Result: """ Executes a command remotely on the host Arguments: command (``str``): command to execute Returns: Result object with the following attributes set: * result (``str``): stderr or stdout * stdout (``str``): stdout * stderr (``str``): stderr Raises: :obj:`nornir.core.exceptions.CommandError`: when there is a command error """ client = task.host.get_connection("paramiko", task.nornir.config) connection_state = task.host.get_connection_state("paramiko") chan = client.get_transport().open_session() if connection_state["ssh_forward_agent"]: AgentRequestHandler(chan) chan.exec_command(command) exit_status_code = chan.recv_exit_status() with chan.makefile() as f: stdout = f.read().decode() with chan.makefile_stderr() as f: stderr = f.read().decode() if exit_status_code: raise CommandError(command, exit_status_code, stdout, stderr) result = stderr if stderr else stdout return Result(result=result, host=task.host, stderr=stderr, stdout=stdout)
def remote_command(task, command): """ Executes a command locally Arguments: command (``str``): command to execute Returns: :obj:`nornir.core.task.Result`: * result (``str``): stderr or stdout * stdout (``str``): stdout * stderr (``srr``): stderr Raises: :obj:`nornir.core.exceptions.CommandError`: when there is a command error """ client = task.host.get_connection("paramiko") chan = client.get_transport().open_session() if task.host._ssh_forward_agent: AgentRequestHandler(chan) chan.exec_command(command) exit_status_code = chan.recv_exit_status() with chan.makefile() as f: stdout = f.read().decode() with chan.makefile_stderr() as f: stderr = f.read().decode() if exit_status_code: raise CommandError(command, exit_status_code, stdout, stderr) result = stderr if stderr else stdout return Result(result=result, host=task.host, stderr=stderr, stdout=stdout)
def exec_command(self, cmd): transport = self._ssh.get_transport() ch = transport.open_session() AgentRequestHandler(ch) ch.exec_command(cmd) stdin = '' stdout = '' stderr = '' size = 1024 * 1024 # TODO: write stdin to channel while True: r, w, x = select.select([ch], [], [], 1) if len(r): if ch in r: while True: data = ch.recv_stderr(size) if not data: break stderr += data.decode(errors='replace') # for line in data.decode(errors='replace').splitlines(): # print(line.strip()) while True: data = ch.recv(size) if not data: break stdout += data.decode(errors='replace') # for line in data.decode(errors='replace').splitlines(): # print(line.strip()) if ch.exit_status_ready(): break return stdin, stdout, stderr, ch.recv_exit_status()
def create_session(self): channel = self.transport.open_session() if self.forward_agent: self._agent_handler = AgentRequestHandler(channel) return channel
def connect(self): """ Connect server. 连接服务器 """ # now connect try: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((self.asset, self.port)) except Exception as e: print('*** {} Connect failed: {}'.format(self.asset, str(e))) return try: t = paramiko.Transport(sock) try: t.start_client() except paramiko.SSHException: print('*** SSH negotiation failed.') return try: self.agent_auth(t, self.username) except Exception as e: print('密钥认证失败,请检查您的密钥: {}'.format(e)) if not t.is_authenticated(): try: self.manual_auth(t, self.user, self.asset) except Exception as err: print("ssh_key/dss_key/user_pass auth failed. {}".format( err)) t.close() return global channel win_size = self.get_win_size() self.channel = channel = t.open_session() # Forward local agent # Commands executed after this point will see the forwarded agent # on the remote end. AgentRequestHandler(channel) # 获取连接的隧道并设置窗口大小 Make a channel and set windows size channel.get_pty(term='xterm', height=win_size[0], width=win_size[1]) channel.invoke_shell() try: signal.signal(signal.SIGWINCH, self.set_win_size) except Exception as err: print("get_pty error {}".format(err)) self.posix_shell() # import pdb;pdb.set_trace() # Shutdown channel socket channel.close() except Exception as e: print('*** Caught exception: ' + str(e.__class__) + ': ' + str(e)) traceback.print_exc() try: t.close() except Exception as err: print("{}".format(err)) return