Python远程SSH: paramiko

xiaoxiao2021-02-28  33

转载注明出处:点击打开链接

 

 

一. 简介

  paramiko是一个基于SSH用于连接远程服务器并执行相关操作(SSHClient和SFTPClinet,即一个是远程连接,一个是上传下载服务),使用该模块可以对远程服务器进行命令或文件操作,值得一说的是,fabric和ansible内部的远程管理就是使用的paramiko来现实。

二. 使用

1. 下载安装

1

2

3

pycrypto,由于 paramiko 模块内部依赖pycrypto,所以先下载安装pycrypto

pip3 install pycrypto

pip3 install paramiko

2. 模块使用

SSHClient:

远程连接分为两种:(1)基于用户名密码连接 (2)基于公钥秘钥连接

通过是用paramiko远程操作,其实本质也分为两种:(1)只用SSHClient (2)自己创建一个transport

 

(1)基于用户名和密码的连接

1

2

3

4

5

6

7

8

9

10

11

12

13

14

import paramiko

 

# 创建SSH对象

ssh = paramiko.SSHClient()

# 允许连接不在know_hosts文件中的主机

ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

# 连接服务器

ssh.connect(hostname='c1.salt.com', port=22, username='GSuser', password='123')

# 执行命令

stdin, stdout, stderr = ssh.exec_command('ls')

# 获取命令结果

result = stdout.read()

# 关闭连接

ssh.close()

  SSHClient 封装 Transport

1

2

3

4

5

6

7

8

9

10

11

12

import paramiko

 

transport = paramiko.Transport(('hostname', 22))

transport.connect(username='GSuser', password='123')

 

ssh = paramiko.SSHClient()

ssh._transport = transport

 

stdin, stdout, stderr = ssh.exec_command('df')

print(stdout.read())

 

transport.close()

  (2)基于公钥秘钥连接

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

import paramiko

 

private_key = paramiko.RSAKey.from_private_key_file('/home/auto/.ssh/id_rsa')

# 创建SSH对象

ssh = paramiko.SSHClient()

# 允许连接不在know_hosts文件中的主机

ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

# 连接服务器

ssh.connect(hostname='c1.salt.com', port=22, username='wupeiqi', key=private_key)

# 执行命令

stdin, stdout, stderr = ssh.exec_command('df')

# 获取命令结果

result = stdout.read()

# 关闭连接

ssh.close()

  SSHClient 封装Transport

1

2

3

4

5

6

7

8

9

import paramiko

 

private_key = paramiko.RSAKey.from_private_key_file('/home/auto/.ssh/id_rsa')

transport = paramiko.Transport(('hostname', 22))

transport.connect(username='wupeiqi', pkey=private_key)

ssh = paramiko.SSHClient()

ssh._transport = transport

stdin, stdout, stderr = ssh.exec_command('df')

transport.close()


 

SFTPClient:

  用于连接远程服务器并进行上传下载功能。

(1)基于用户名密码上传下载

1

2

3

4

5

6

7

8

9

10

11

12

import paramiko

 

transport = paramiko.Transport(('hostname',22))

transport.connect(username='GSuser',password='123')

 

sftp = paramiko.SFTPClient.from_transport(transport)

# 将location.py 上传至服务器 /tmp/test.py

sftp.put('/tmp/location.py', '/tmp/test.py')

# 将remove_path 下载到本地 local_path

sftp.get('remove_path', 'local_path')

 

transport.close()

  

(2)基于公钥秘钥上传下载

1

2

3

4

5

6

7

8

9

10

11

12

13

14

import paramiko

 

private_key = paramiko.RSAKey.from_private_key_file('/home/auto/.ssh/id_rsa')

 

transport = paramiko.Transport(('hostname', 22))

transport.connect(username='GSuser', pkey=private_key )

 

sftp = paramiko.SFTPClient.from_transport(transport)

# 将location.py 上传至服务器 /tmp/test.py

sftp.put('/tmp/location.py', '/tmp/test.py')

# 将remove_path 下载到本地 local_path

sftp.get('remove_path', 'local_path')

 

transport.close()

  

  Demo: 实现远程命令执行和文件上传

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

#!/usr/bin/env python

# -*- coding:utf-8 -*-

import paramiko

 

class SSHConnection(object):

 

    def __init__(self, host='192.168.12.68', port=22, username='locojoy',pwd='123321QQ!'):

        self.host = host

        self.port = port

        self.username = username

        self.pwd = pwd

        self.__k = None

 

    def run(self):

        self.connect()  # 连接远程服务器

        self.upload('db.py','/tmp/1.py')  # 将本地的db.py文件上传到远端服务器的/tmp/目录下并改名为1.py

        self.cmd('df')  # 执行df 命令

        self.close()    # 关闭连接

 

    def connect(self):

        transport = paramiko.Transport((self.host, self.port))

        transport.connect(username=self.username, password=self.pwd)

        self.__transport = transport

 

    def close(self):

        self.__transport.close()

 

    def upload(self,local_path,target_path):

        sftp = paramiko.SFTPClient.from_transport(self.__transport)

        sftp.put(local_path,target_path)

 

    def cmd(self, command):

        ssh = paramiko.SSHClient()

        ssh._transport = self.__transport

        # 执行命令

        stdin, stdout, stderr = ssh.exec_command(command)

        # 获取命令结果

        result = stdout.read()

        print(result)

        return result

 

obj = SSHConnection()

obj.run()

  paramiko在堡垒机中的应用

(1)简单实例:远程连接一台主机,操作命令,linux版本,输入终端为回车则发送命令。不支持tab补全功能。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

import paramiko, sys, os, socket, select, getpass

from paramiko.py3compat import u   # 在python3中是这样使用的,如果在Python2中则注释这行

 

# 这个程序依赖于终端,只能在Liunx下运行,windows用其他的方式

 

tran = paramiko.Transport(('192.168.12.68', 22,))

tran.start_client()

tran.auth_password('locojoy', '123321QQ!')

 

# 打开一个通道

chan = tran.open_session()

# 获取一个终端

chan.get_pty()

# 激活器

chan.invoke_shell()

 

# 原始的方法利用终端进行收发消息

# 利用sys.stdin,肆意妄为执行操作

# 用户在终端输入内容,并将内容发送至远程服务器

# 远程服务器执行命令,并将结果返回

# 用户终端显示内容

 

while True:

    # 监视用户输入和服务器返回数据

    # sys.stdin 处理用户输入

    # chan 是之前创建的通道,用于接收服务器返回信息

    # 通过select监听终端(输入输出),一旦变化,就将拿到的数据发送给服务器

    # 通过监听socket句柄,如果有变化表示服务器要给我发消息

    readable, writeable, error = select.select([chan, sys.stdin, ],[],[],1)

    # 通过select.select 监听chan(打开的通道(和远程服务器连接的状态)), sys.stdin(输入),一旦变化就写入readable

    # 当chan变化时,加入到readable,远程服务器发送内容过来

    if chan in readable:

        try:

            x = u(chan.recv(1024))  # Python3用这个

            # x = chan.recv(1024)  Python2使用这个

            if len(x) == 0:

                print('\r\n*** EOF\r\n')

                break

            sys.stdout.write(x)   # 写入缓冲区

            sys.stdout.flush()    # 刷新,将缓冲区内容显示出来

        except socket.timeout:

            pass

    # 当sys.stdin 放入readable中时,将获取到的内容发送到远程服务器

    if sys.stdin in readable:

        inp = sys.stdin.readline()

        chan.sendall(inp)

 

chan.close()

tran.close()

(2)每按一个键就发送记录,并支持tab自动补全

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

import paramiko, sys, os, socket, select, getpass, termios, tty

from paramiko.py3compat import u

 

tran = paramiko.Transport(('10.211.55.4', 22,))

tran.start_client()

tran.auth_password('wupeiqi', '123')

# 打开一个通道

chan = tran.open_session()

# 获取一个终端

chan.get_pty()

# 激活器

chan.invoke_shell()

 

# 获取原tty属性

oldtty = termios.tcgetattr(sys.stdin)

try:

    # 为tty设置新属性

    # 默认当前tty设备属性:

    #   输入一行回车,执行

    #   CTRL+C 进程退出,遇到特殊字符,特殊处理。

    # 这是为原始模式,不认识所有特殊符号

    # 放置特殊字符应用在当前终端,如此设置,将所有的用户输入均发送到远程服务器

    tty.setraw(sys.stdin.fileno())  # 恢复终端原始状态,每按一个键就发送

    chan.settimeout(0.0)

 

    while True:

        # 监视 用户输入 和 远程服务器返回数据(socket)

        # 阻塞,直到句柄可读

        r, w, e = select.select([chan, sys.stdin], [], [], 1)

        if chan in r:  # 获取服务返回的内容

            try:

                x = u(chan.recv(1024))

                if len(x) == 0:

                    print('\r\n*** EOF\r\n')

                    break

                sys.stdout.write(x)

                sys.stdout.flush()

            except socket.timeout:

                pass

        if sys.stdin in r: # 发送命令

            x = sys.stdin.read(1) # 读取一个字符

            if len(x) == 0:

                break

            chan.send(x) # 发送一个字符

 

finally:

    # 重新设置终端属性,将终端状态还原

    termios.tcsetattr(sys.stdin, termios.TCSADRAIN, oldtty)

 

chan.close()

tran.close()

转载请注明原文地址: https://www.6miu.com/read-2625163.html

最新回复(0)