paramiko是一個用於作遠程控制的模塊,使用該模塊能夠對遠程服務器進行命令或文件操做,值得一說的是,fabric和ansible內部的遠程管理就是使用的paramiko來現實。其實它的底層是對ssh的上層代碼的一個封裝node
1、下載安裝python
1
2
3
|
#pycrypto,因爲 paramiko 模塊內部依賴pycrypto,因此先下載安裝pycrypto
tomcat@node:~$ pip install pycrypto
tomcat@node:~$ pip install paramiko
|
2、模塊使用linux
(1)基於用戶名密碼鏈接兩種方式:ios
-->第一種git
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
import
paramiko
# 建立SSH對象
ssh
=
paramiko.SSHClient()
# 容許鏈接不在know_hosts文件中的主機
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# 鏈接服務器
ssh.connect(hostname
=
'192.168.1.21'
, port
=
22
, username
=
'root'
, password
=
'123456'
)
# 執行命令
stdin, stdout, stderr
=
ssh.exec_command(
'ls'
)
# 獲取命令結果
result
=
stdout.read()
# 關閉鏈接
ssh.close()
|
-->二種:SSHClient 封裝 Transport github
1
2
3
4
5
6
7
8
9
10
11
12
|
import
paramiko
transport
=
paramiko.Transport((
'192.168.1.21'
,
22
))
transport.connect(username
=
'root'
, password
=
'123456'
)
ssh
=
paramiko.SSHClient()
ssh._transport
=
transport
stdin, stdout, stderr
=
ssh.exec_command(
'df'
)
print
stdout.read()
transport.close()
|
(2)基於公鑰密鑰鏈接的兩種方式:shell
-->第一種 json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
import
paramiko
private_key
=
paramiko.RSAKey.from_private_key_file(
'/root/.ssh/id_rsa'
)
# 建立SSH對象
ssh
=
paramiko.SSHClient()
# 容許鏈接不在know_hosts文件中的主機
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# 鏈接服務器
ssh.connect(hostname
=
'192.168.1.21'
, port
=
22
, username
=
'root'
, key
=
private_key)
# 執行命令
stdin, stdout, stderr
=
ssh.exec_command(
'df'
)
# 獲取命令結果
result
=
stdout.read()
# 關閉鏈接
ssh.close()
|
-->第二種:SSHClient 封裝 Transport windows
1
2
3
4
5
6
7
8
9
10
11
12
13
|
import
paramiko
private_key
=
paramiko.RSAKey.from_private_key_file(
'/root/.ssh/id_rsa'
)
transport
=
paramiko.Transport((
'192.168.1.21'
,
22
))
transport.connect(username
=
'root'
, pkey
=
private_key)
ssh
=
paramiko.SSHClient()
ssh._transport
=
transport
stdin, stdout, stderr
=
ssh.exec_command(
'df'
)
transport.close()
|
(1)基於用戶名密碼上傳下載:tomcat
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
import
paramiko
transport
=
paramiko.Transport((
'192.168.1.21'
,
22
))
transport.connect(username
=
'root'
,password
=
'123456'
)
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
15
16
|
import
paramiko
private_key
=
paramiko.RSAKey.from_private_key_file(
'/root/.ssh/id_rsa'
)
transport
=
paramiko.Transport((
'192.168.1.21'
,
22
))
transport.connect(username
=
'root'
, 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()
|
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
|
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import
paramiko
class
SSHConnection(
object
):
def
__init__(
self
, host
=
'192.168.1.21'
, port
=
22
, username
=
'root'
,pwd
=
'123456'
):
self
.host
=
host
self
.port
=
port
self
.username
=
username
self
.pwd
=
pwd
self
.__k
=
None
def
run(
self
):
self
.connect()
pass
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
cmd(
self
, command):
ssh
=
paramiko.SSHClient()
ssh._transport
=
self
.__transport
# 執行命令
stdin, stdout, stderr
=
ssh.exec_command(command)
# 獲取命令結果
result
=
stdout.read()
return
result
def
upload(
self
,local_path, target_path):
# 鏈接,上傳
sftp
=
paramiko.SFTPClient.from_transport(
self
.__transport)
# 將location.py 上傳至服務器 /tmp/test.py
sftp.put(local_path, target_path)
ssh
=
SSHConnection()
ssh.connect()
r1
=
ssh.cmd(
'df'
)
print
(r1.decode())
#ssh.upload('test.py', "/root/test.py")
ssh.upload(
's13_par.py'
,
"/root/s7.py"
)
ssh.close()
|
#!/usr/bin/env python # -*- coding:utf-8 -*- import paramiko import uuid class SSHConnection(object): def __init__(self, host='172.16.103.191', port=22, username='wupeiqi',pwd='123'): self.host = host self.port = port self.username = username self.pwd = pwd self.__k = None def create_file(self): file_name = str(uuid.uuid4()) with open(file_name,'w') as f: f.write('sb') return file_name def run(self): self.connect() self.upload('/home/wupeiqi/tttttttttttt.py') self.rename('/home/wupeiqi/tttttttttttt.py', '/home/wupeiqi/ooooooooo.py) 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,target_path): # 鏈接,上傳 file_name = self.create_file() sftp = paramiko.SFTPClient.from_transport(self.__transport) # 將location.py 上傳至服務器 /tmp/test.py sftp.put(file_name, target_path) def rename(self, old_path, new_path): ssh = paramiko.SSHClient() ssh._transport = self.__transport # 執行命令 cmd = "mv %s %s" % (old_path, new_path,) stdin, stdout, stderr = ssh.exec_command(cmd) # 獲取命令結果 result = stdout.read() def cmd(self, command): ssh = paramiko.SSHClient() ssh._transport = self.__transport # 執行命令 stdin, stdout, stderr = ssh.exec_command(command) # 獲取命令結果 result = stdout.read() return result ha = SSHConnection() ha.run()
1
2
3
4
5
6
|
# 對於更多限制命令,須要在系統中設置
/
etc
/
sudoers
Defaults requiretty
Defaults:cmdb !requiretty
Demo
|
堡壘機執行流程:
注:配置.brashrc實現ssh登錄後自動執行腳本,如:/usr/bin/python /home/wupeiqi/menu.py
實現過程(前戲)
# 利用sys.stdin,肆意妄爲執行操做
# 用戶在終端輸入內容,並將內容發送至遠程服務器
# 遠程服務器執行命令,並將結果返回
# 用戶終端顯示內容
版本一:能連上遠程服務器在終端任意輸入命令,但沒法作到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
|
import
paramiko
import
sys
import
os
import
socket
import
select
import
getpass
from
paramiko.py3compat
import
u
tran
=
paramiko.Transport((
'192.168.1.21'
,
22
,))
tran.start_client()
tran.auth_password(
'root'
,
'123456'
)
# 打開一個通道
chan
=
tran.open_session()
# 獲取一個終端
chan.get_pty()
# 激活器
chan.invoke_shell()
while
True
:
# 監視用戶輸入和服務器返回數據
# sys.stdin 處理用戶輸入
# chan 是以前建立的通道,用於接收服務器返回信息
readable, writeable, error
=
select.select([chan, sys.stdin, ],[],[],
1
)
if
chan
in
readable:
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
readable:
inp
=
sys.stdin.readline()
chan.sendall(inp)
chan.close()
tran.close()
|
版本二:在版本一上增長了命令補全功能和命令記錄
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
52
53
54
55
56
57
58
59
60
61
62
|
import
paramiko
import
sys
import
os
import
socket
import
select
import
getpass
import
termios
import
tty
from
paramiko.py3compat
import
u
tran
=
paramiko.Transport((
'192.168.1.21'
,
22
,))
tran.start_client()
tran.auth_password(
'root'
,
'123456'
)
# 打開一個通道
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()
|
版本三:windows、linux通用版本
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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
|
import
paramiko
import
sys
import
os
import
socket
import
getpass
from
paramiko.py3compat
import
u
# windows does not have termios...
try
:
import
termios
import
tty
has_termios
=
True
except
ImportError:
has_termios
=
False
def
interactive_shell(chan):
if
has_termios:
posix_shell(chan)
else
:
windows_shell(chan)
def
posix_shell(chan):
import
select
oldtty
=
termios.tcgetattr(sys.stdin)
try
:
tty.setraw(sys.stdin.fileno())
tty.setcbreak(sys.stdin.fileno())
chan.settimeout(
0.0
)
log
=
open
(
'handle.log'
,
'a+'
, encoding
=
'utf-8'
)
flag
=
False
temp_list
=
[]
while
True
:
r, w, e
=
select.select([chan, sys.stdin], [], [])
if
chan
in
r:
try
:
x
=
u(chan.recv(
1024
))
if
len
(x)
=
=
0
:
sys.stdout.write(
'\r\n*** EOF\r\n'
)
break
if
flag:
if
x.startswith(
'\r\n'
):
pass
else
:
temp_list.append(x)
flag
=
False
sys.stdout.write(x)
sys.stdout.flush()
except
socket.timeout:
pass
if
sys.stdin
in
r:
x
=
sys.stdin.read(
1
)
import
json
if
len
(x)
=
=
0
:
break
if
x
=
=
'\t'
:
flag
=
True
else
:
temp_list.append(x)
if
x
=
=
'\r'
:
log.write(''.join(temp_list))
log.flush()
temp_list.clear()
chan.send(x)
finally
:
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, oldtty)
def
windows_shell(chan):
import
threading
sys.stdout.write(
"Line-buffered terminal emulation. Press F6 or ^Z to send EOF.\r\n\r\n"
)
def
writeall(sock):
while
True
:
data
=
sock.recv(
256
)
if
not
data:
sys.stdout.write(
'\r\n*** EOF ***\r\n\r\n'
)
sys.stdout.flush()
break
sys.stdout.write(data)
sys.stdout.flush()
writer
=
threading.Thread(target
=
writeall, args
=
(chan,))
writer.start()
try
:
while
True
:
d
=
sys.stdin.read(
1
)
if
not
d:
break
chan.send(d)
except
EOFError:
# user hit ^Z or F6
pass
def
run():
default_username
=
getpass.getuser()
username
=
input
(
'Username [%s]: '
%
default_username)
if
len
(username)
=
=
0
:
username
=
default_username
hostname
=
input
(
'Hostname: '
)
if
len
(hostname)
=
=
0
:
print
(
'*** Hostname required.'
)
sys.exit(
1
)
tran
=
paramiko.Transport((hostname,
22
,))
tran.start_client()
default_auth
=
"p"
auth
=
input
(
'Auth by (p)assword or (r)sa key[%s] '
%
default_auth)
if
len
(auth)
=
=
0
:
auth
=
default_auth
if
auth
=
=
'r'
:
default_path
=
os.path.join(os.environ[
'HOME'
],
'.ssh'
,
'id_rsa'
)
path
=
input
(
'RSA key [%s]: '
%
default_path)
if
len
(path)
=
=
0
:
path
=
default_path
try
:
key
=
paramiko.RSAKey.from_private_key_file(path)
except
paramiko.PasswordRequiredException:
password
=
getpass.getpass(
'RSA key password: '
)
key
=
paramiko.RSAKey.from_private_key_file(path, password)
tran.auth_publickey(username, key)
else
:
pw
=
getpass.getpass(
'Password for %s@%s: '
%
(username, hostname))
tran.auth_password(username, pw)
# 打開一個通道
chan
=
tran.open_session()
# 獲取一個終端
chan.get_pty()
# 激活器
chan.invoke_shell()
interactive_shell(chan)
chan.close()
tran.close()
if
__name__
=
=
'__main__'
:
run()
|
更多參見:paramoko源碼 https://github.com/paramiko/paramiko