使用paramiko远程执行命令、下发文件的实例

写部署脚本时,难免涉及到一些远程执行命令或者传输文件。

之前一直使用sh库,调用sh.ssh远程执行一些命令,sh.scp传输文件,但是实际使用中还是比较麻烦的,光是模拟用户登陆这一点,还需要单独定义方法模拟输入。

感受一下:

from sh import ssh
PASS = 'xxxx'
def ssh_interact(line, stdin):
  line = line.strip()
  print(line)
  if line.endswith('password:'):
    stdin.put(PASS)
ssh('x.x.x.x', _out=ssh_interact)

来自官方文档

后来发现paramiko库更加优雅、便捷,所以准备用pramiko替换掉sh。

之前通过同事了解到,paramiko在远程执行python脚本时,脚本中的输出内容可能会通过stderr这个管道输出出来,所以直接用paramiko的SSHClient类中的exec_command方法执行,通过读stderr管道中有无输出来判断命令是否成功执行的方式是行不通的。所以用更底层一些的Channel类的recv_exit_status方法判断执行退出码更好一些。

安装

可以通过使用pip install paramiko安装,细节这里不再赘述。

封装

首先定义几个异常

# coding: utf-8
import os.path

from paramiko import SSHClient, AutoAddPolicy, AuthenticationException

class ConnectError(Exception):
  """
  连接错误时抛出的异常
  """
  pass

class RemoteExecError(Exception):
  """
  远程执行命令,失败时抛出的异常
  """
  pass

class SCPError(Exception):
  """
  远程下发文件时抛出的异常
  """
  pass
...
class Remote(object):
  def __init__(self, host, username, password=None, port=22, key_filename=None):
    self.host = host
    self.username = username
    self.password = password
    self.port = port
    self.key_filename = key_filename
    self._ssh = None

  def _connect(self):
    self._ssh = SSHClient()
    self._ssh.set_missing_host_key_policy(AutoAddPolicy())
    try:
      if self.key_filename:
        self._ssh.connect(self.host, username=self.username, port=self.port, key_filename=self.key_filename)
      else:
        self._ssh.connect(self.host, username=self.username, password=self.password, port=self.port)
    except AuthenticationException:
      self._ssh = None
      raise ConnectionError('连接失败,请确认用户名、密码、端口或密钥文件是否有效')
    except Exception as e:
      self._ssh = None
      raise ConnectionError('连接时出现意料外的错误:%s' % e)

  def get_ssh(self):
    if not self._ssh:
      self._connect()
    return self._ssh

实例化SSHClient类,通过它的connect()方法获取SSH连接。

需要注意的是,远程访问的主机若是第一次连接,属于未知设备需要认证,通过set_missing_host_key_policy()方法设置一种策略,这里使用的是AutoAddPolicy()。

这里的_connect支持两种方式登录,一种是提供主机的用户名密码,另一种是通过密钥文件。在连接时检查如果指定了密钥文件则使用这种方式登录,否则通过用户名密码登录。

_connect()虽然是实际的建立连接的方法,但实际对外接口是get_ssh(),如果已经有建立好的SSH连接直接返回,避免重复建立连接。

class Remote(object):
  ...
  def ssh(self, cmd, root_password=None, get_pty=False, super=False):
    cmd = self._prepare_cmd(cmd, root_password, super)
    stdout = self._exec(cmd, get_pty)
    return stdout

  def _prepare_cmd(self, cmd, root_password=None, super=False):
    if self.username != 'root' and super:
      if root_password:
        cmd = "echo '{}'|su - root -c '{}'".format(root_password, cmd)
      else:
        cmd = "echo '{}'|sudo -p '' -S su - root -c '{}'".format(self.password, cmd)
    return cmd

  def _exec(self, cmd, gty_pty=False):
    channel = self.get_ssh().get_transport().open_session()
    if get_pty:
      channel.get_pty()
    channel.exec_command(cmd)
    stdout = channel.makefile('r', -1).readlines()
    stderr = channel.makefile_stderr('r', -1).readlines()
    ret_code = channel.recv_exit_status()
    if ret_code:
      msg = ''.join(stderr) if stderr else ''.join(stdout)
      raise RemoteExecError(msg)
    return stdout

在远程执行某些命令时,可能需要管理员权限,这种时候需要做一些判断,首先判断登录提供的用户名如果不是root,则需要对命令做一些修改。这里的修改有两种情况,一是,该普通用户本身就有sudo权限,只需要把执行的命令加到sudo之后执行就可以,还有一种是普通用户没有sudo权限,需要通过su先切换到root身份之后再执行,这种情况下需要提供root密码。

还有一点要注意的是get_pty这个参数,实际在远程执行sudo命令时,一般主机都会需要通过tty才能执行,通过把get_pty值设置为True,可以模拟tty,但是随之而来也会有一个问题,如果是远程执行一个需要长期运行的进程,例如启动nginx服务,当远程命令执行后SSH退出之后,此次运行的所有程序也会随之结束,所以在需要通过远程命令运行某些服务或程序时,是不能指定get_pty参数的;但同时,如果是普通用户远程登录,是没有权限执行service命令的。建议的一种方式是修改/etc/sudoers配置文件,注释掉Defaults requiretty这行。

class Remote(object):
  ...

  def scp(self, local_file, remote_path):
    if not os.path.exists(local_file):
      raise SCPError("Local %s isn't exists" % local_file)
    if not os.path.isfile(local_file):
      raise SCPError("%s is not a File" % local_file)
    sftp = self.get_ssh().open_sftp()
    try:
      sftp.put(local_file, remote_path)
    except Exception as e:
      raise SCPError(e)

先确认要下发的文件存在,并且是文件不是目录,如果不是则抛出异常。同时,remote_path需要是远程主机的文件绝对目录,例如/tmp/xxx.xxx,而不能是/tmp。

使用

# coding: utf-8
from remote_client import RemoteClient

rc = RemoteClient('10.1.100.1', 'test', 'test_pass')
rc.ssh('whoami')  # [u'test\n']
rc.scp('/tmp/test.out', '/tmp/test.out')

总结

相较于sh,paramiko好用的不是一星半点,这里只是提供了一个简单的封装,paramiko本身还有很多其他用法,欢迎大家积极讨论。

以上只是本人的一点理解,如果有错误之处,欢迎指正。

以上这篇使用paramiko远程执行命令、下发文件的实例就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • python paramiko实现ssh远程访问的方法

    安装paramiko后,看下面例子: 复制代码 代码如下: import paramiko #设置ssh连接的远程主机地址和端口t=paramiko.Transport((ip,port))#设置登录名和密码t.connect(username=username,password=password)#连接成功后打开一个channelchan=t.open_session()#设置会话超时时间chan.settimeout(session_timeout)#打开远程的terminalchan.ge

  • python的paramiko模块实现远程控制和传输示例

    本文介绍了python的paramiko模块实现远程控制和传输示例,分享给大家,具体如下: 1 安装 sudo pip install paramiko 2 ssh实现远程控制 #LINUX下执行shell ssh username@ip #输入密码后就可以对远程机器进行操作 ssh username@ip command #输入密码后远程机器就执行command ssh运行后,想退出,可以kill掉ssh进程. 3 paramiko实现ssh import paramiko hostname

  • python利用paramiko连接远程服务器执行命令的方法

    python中的paramiko模块是用来实现ssh连接到远程服务器上的库,在进行连接的时候,可以用来执行命令,也可以用来上传文件. 1.得到一个连接的对象 在进行连接的时候,可以使用如下的代码: def connect(host): 'this is use the paramiko connect the host,return conn' ssh = paramiko.SSHClient() ssh.set_missing_host_key_policy(paramiko.AutoAddP

  • 使用paramiko远程执行命令、下发文件的实例

    写部署脚本时,难免涉及到一些远程执行命令或者传输文件. 之前一直使用sh库,调用sh.ssh远程执行一些命令,sh.scp传输文件,但是实际使用中还是比较麻烦的,光是模拟用户登陆这一点,还需要单独定义方法模拟输入. 感受一下: from sh import ssh PASS = 'xxxx' def ssh_interact(line, stdin): line = line.strip() print(line) if line.endswith('password:'): stdin.put

  • python 采用paramiko 远程执行命令及报错解决

    这篇文章主要介绍了python 采用paramiko 远程执行命令及报错解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 import sys import paramiko import config_reader from check_utils import standout_print, parse_remainsize_response_lines, error_out_print from time import time cla

  • Python Paramiko上传下载sftp文件及远程执行命令详解

    目录 一.简介 安装模块 二.上传文件 三.下载文件 四.远程执行命令 五.错误集锦 原因 解决 一.简介 Paramiko模块是基于Python实现的SSH远程安全连接,用于SSH远程执行命令.文件传输等功能. 安装模块 默认Python没有自带,需要手动安装: pip3 install paramiko 二.上传文件 #!/usr/bin/env python3 # coding: utf-8 import paramiko def sftp_upload_file(host,user,pa

  • 使paramiko库执行命令时在给定的时间强制退出功能的实现

    使用paramiko库ssh连接到远端云主机上时,非常偶现卡死现象,连接无法退出(可以是执行命令时云主机重启等造成).需要给定一段时间,不管命令执行是否卡住,都退出连接,显示命令执行超时错误. 实现方式: 线程+事件,在线程中执行ssh命令,给事件配置超时时间. 代码示例: 1 from threading import Thread, Event 2 import paramiko class SshClient(object): def __init__(self, ip, port, us

  • python 远程执行命令的详细代码

    1.简单版 # coding: utf-8 import paramiko import re from time import sleep def ssh(): ssh = paramiko.SSHClient() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) #指定当对方主机没有本机公钥的情况时应该怎么办,AutoAddPolicy表示自动在对方主机保存下本机的秘钥 ssh.connect('172.16.1.5',22,

  • 如何使用Go语言实现远程执行命令

    前言 远程执行命令有什么用?为什么要远程执行命令? 如果你只有2,3台服务器需要管理的时候,远程执行命令确实没有没多大作用,你可以登录到每台服务器上去完成各种操作. 当你的服务器大于3台的时候,远程执行的命令的方式就可以大大提高你的生产力了. 如果你有一个可以远程执行命令的工具,那么就可以像操作单台机器那样操作多台机器,机器越多,效率提高的越多. 远程执行命令最常用的方法就是利用 SSH 协议,将命令发送到远程机器上执行,并获取返回结果. 一般命令 所谓一般命令,就是在一定时间内会执行完的命令.

  • Linux下使用SSH远程执行命令方法收集

    说明:可以做SSH免密登录之后执行,这样可以省去每次执行输入密码的提示. 对于简单的命令: 如果是简单执行几个命令,则: ssh user@remoteNode "cd /home ; ls" 基本能完成常用的对于远程节点的管理了,几个注意的点: 双引号,必须有.如果不加双引号,第二个ls命令在本地执行 分号,两个命令之间用分号隔开 多行命令可以输入双引号后回车,结尾使用双引号包裹 对于脚本的方式: 有些远程执行的命令内容较多,单一命令无法完成,考虑脚本方式实现: #!/bin/bas

  • Zabbix远程执行命令的示例详解

    Zabbix触发器(trigger)达到阀值后会有动作(action)执行:发送告警信息或执行远程命令. 本文主要配置验证zabbix执行远程命令. 一.环境 Server:基于CentOS-7-x86_64-1511: Zabbix:zabbix-3.0.1server/agent. 二.注意事项 一些能想到的比较重要的注意事项: 1.远程执行命令是server端向agent端执行,不支持主动模式的agent: 2.不支持代理模式: 3.zabbix用户必须对命令具有执行权限,可以使用sudo

  • python基于socket模拟实现ssh远程执行命令

    一.subprocess.Popen() subprocess模块定义了一个类: Popen 类原型: class subprocess.Popen( args, bufsize = 0, executable = None, stdin = None, stdout = None, stderr = None, preexec_fn = None, close_fds = False, shell = False, cwd = None, env = None, universal_newli

  • linux下使用ssh远程执行命令批量导出数据库到本地

    前天正在跟前端的同事调试功能.服务器开好,模拟的玩家登录好,就在倒计时.这时突然运营的同事跑过来说要统计几个服务器玩家的一些情况,也就是需要从几个服的数据库导出部分玩家的数据.好吧,我看了一下时间,11:47.心想,跟前端调试完,去吃个饭再午休一下那就下午再给吧.没想对方来一句"就导个数据库而已,要这么久么?",而且还是直接跟我上司说的.我嚓,好吧,我导.可问题来了,平时的统计是由php做的,批量部署这些是由运维做的.服务端完全没有对应的工具.而且服务器是在阿里云上的,数据库的用户是限

随机推荐