xbot.plugins.ssh 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- xbot.plugins.ssh-0.1.0/LICENSE +24 -0
- xbot.plugins.ssh-0.1.0/MANIFEST.in +2 -0
- xbot.plugins.ssh-0.1.0/PKG-INFO +274 -0
- xbot.plugins.ssh-0.1.0/README.md +128 -0
- xbot.plugins.ssh-0.1.0/README.zh.md +128 -0
- xbot.plugins.ssh-0.1.0/demo/lib/__init__.py +0 -0
- xbot.plugins.ssh-0.1.0/demo/lib/testbed.py +48 -0
- xbot.plugins.ssh-0.1.0/demo/lib/testcase.py +15 -0
- xbot.plugins.ssh-0.1.0/demo/testcases/__init__.py +0 -0
- xbot.plugins.ssh-0.1.0/demo/testcases/tc_sftp.py +99 -0
- xbot.plugins.ssh-0.1.0/demo/testcases/tc_ssh.py +73 -0
- xbot.plugins.ssh-0.1.0/pyproject.toml +3 -0
- xbot.plugins.ssh-0.1.0/requirements.txt +2 -0
- xbot.plugins.ssh-0.1.0/setup.cfg +4 -0
- xbot.plugins.ssh-0.1.0/setup.py +64 -0
- xbot.plugins.ssh-0.1.0/tests/__init__.py +0 -0
- xbot.plugins.ssh-0.1.0/tests/run.py +39 -0
- xbot.plugins.ssh-0.1.0/tests/test_sftp.py +88 -0
- xbot.plugins.ssh-0.1.0/tests/test_ssh.py +99 -0
- xbot.plugins.ssh-0.1.0/tests/test_utils.py +18 -0
- xbot.plugins.ssh-0.1.0/venv/bin/jp.py +54 -0
- xbot.plugins.ssh-0.1.0/venv/bin/rst2html.py +23 -0
- xbot.plugins.ssh-0.1.0/venv/bin/rst2html4.py +26 -0
- xbot.plugins.ssh-0.1.0/venv/bin/rst2html5.py +34 -0
- xbot.plugins.ssh-0.1.0/venv/bin/rst2latex.py +26 -0
- xbot.plugins.ssh-0.1.0/venv/bin/rst2man.py +26 -0
- xbot.plugins.ssh-0.1.0/venv/bin/rst2odt.py +30 -0
- xbot.plugins.ssh-0.1.0/venv/bin/rst2odt_prepstyles.py +67 -0
- xbot.plugins.ssh-0.1.0/venv/bin/rst2pseudoxml.py +23 -0
- xbot.plugins.ssh-0.1.0/venv/bin/rst2s5.py +24 -0
- xbot.plugins.ssh-0.1.0/venv/bin/rst2xetex.py +27 -0
- xbot.plugins.ssh-0.1.0/venv/bin/rst2xml.py +23 -0
- xbot.plugins.ssh-0.1.0/venv/bin/rstpep2html.py +25 -0
- xbot.plugins.ssh-0.1.0/xbot/plugins/ssh/__init__.py +0 -0
- xbot.plugins.ssh-0.1.0/xbot/plugins/ssh/errors.py +19 -0
- xbot.plugins.ssh-0.1.0/xbot/plugins/ssh/sftp.py +211 -0
- xbot.plugins.ssh-0.1.0/xbot/plugins/ssh/ssh.py +309 -0
- xbot.plugins.ssh-0.1.0/xbot/plugins/ssh/utils.py +30 -0
- xbot.plugins.ssh-0.1.0/xbot/plugins/ssh/version.py +3 -0
- xbot.plugins.ssh-0.1.0/xbot.plugins.ssh.egg-info/PKG-INFO +274 -0
- xbot.plugins.ssh-0.1.0/xbot.plugins.ssh.egg-info/SOURCES.txt +42 -0
- xbot.plugins.ssh-0.1.0/xbot.plugins.ssh.egg-info/dependency_links.txt +1 -0
- xbot.plugins.ssh-0.1.0/xbot.plugins.ssh.egg-info/requires.txt +4 -0
- xbot.plugins.ssh-0.1.0/xbot.plugins.ssh.egg-info/top_level.txt +6 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
BSD 2-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2022-2023, zhaowcheng <zhaowcheng@163.com>
|
|
4
|
+
|
|
5
|
+
Redistribution and use in source and binary forms, with or without
|
|
6
|
+
modification, are permitted provided that the following conditions are met:
|
|
7
|
+
|
|
8
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
9
|
+
list of conditions and the following disclaimer.
|
|
10
|
+
|
|
11
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
12
|
+
this list of conditions and the following disclaimer in the documentation
|
|
13
|
+
and/or other materials provided with the distribution.
|
|
14
|
+
|
|
15
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
16
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
17
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
18
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
19
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
20
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
21
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
22
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
23
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
24
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: xbot.plugins.ssh
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: SSH library for xbot.framework
|
|
5
|
+
Home-page: https://github.com/zhaowcheng/xbot.plugins.ssh
|
|
6
|
+
Author: zhaowcheng
|
|
7
|
+
Author-email: zhaowcheng@163.com
|
|
8
|
+
License: UNKNOWN
|
|
9
|
+
Project-URL: Homepage, https://github.com/zhaowcheng/xbot.plugins.ssh
|
|
10
|
+
Project-URL: Issues, https://github.com/zhaowcheng/xbot.plugins.ssh/issues
|
|
11
|
+
Platform: UNKNOWN
|
|
12
|
+
Classifier: License :: OSI Approved :: BSD License
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.6
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.7
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Requires-Python: >=3.6
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
License-File: LICENSE
|
|
25
|
+
|
|
26
|
+
## Introduction
|
|
27
|
+
|
|
28
|
+
`xbot.plugins.ssh` provides ssh and sftp support for [xbot.framework](https://github.com/zhaowcheng/xbot.framework)
|
|
29
|
+
|
|
30
|
+
## Installation
|
|
31
|
+
|
|
32
|
+
Install via pip:
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
pip install xbot.plugins.ssh
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Getting Started
|
|
39
|
+
|
|
40
|
+
```python
|
|
41
|
+
import os
|
|
42
|
+
import shutil
|
|
43
|
+
|
|
44
|
+
from xbot.plugins.ssh.ssh import SSHConnection
|
|
45
|
+
from xbot.plugins.ssh.sftp import SFTPConnection
|
|
46
|
+
|
|
47
|
+
# Modify the following information to your own before trying to run.
|
|
48
|
+
host = '192.168.8.8'
|
|
49
|
+
user = 'xbot'
|
|
50
|
+
pwd = 'xbot'
|
|
51
|
+
|
|
52
|
+
# Create ssh connection.
|
|
53
|
+
sshconn = SSHConnection()
|
|
54
|
+
sshconn.connect(host, user, pwd)
|
|
55
|
+
|
|
56
|
+
# Expect the return code of command is 0.
|
|
57
|
+
sshconn.exec('ls -l', expect=0)
|
|
58
|
+
|
|
59
|
+
# Expect the return code of command is 2.
|
|
60
|
+
sshconn.exec('ls /errpath', expect=2)
|
|
61
|
+
|
|
62
|
+
# Expect the output of command contains `username`.
|
|
63
|
+
sshconn.exec('whoami', expect=user)
|
|
64
|
+
|
|
65
|
+
# Don't check the result of command.
|
|
66
|
+
sshconn.exec('ls -l', expect=None)
|
|
67
|
+
sshconn.exec('ls /errpath', expect=None)
|
|
68
|
+
|
|
69
|
+
# Execute command with sudo.
|
|
70
|
+
sshconn.sudo('whoami', expect='root')
|
|
71
|
+
|
|
72
|
+
# Interactive command.
|
|
73
|
+
sshconn.exec("read -p 'input: '", prompts={'input:': 'hello'})
|
|
74
|
+
|
|
75
|
+
# Attributes and methods of SSHCommandResult.
|
|
76
|
+
cmd = 'echo -e "jack 20\ntom 30"'
|
|
77
|
+
result = sshconn.exec(cmd)
|
|
78
|
+
assert str(result) == 'jack 20\ntom 30'
|
|
79
|
+
assert result.rc == 0
|
|
80
|
+
assert result.cmd == cmd
|
|
81
|
+
assert result.getfield('tom', 2) == '30'
|
|
82
|
+
assert result.getcol(2) == ['20', '30']
|
|
83
|
+
|
|
84
|
+
# Create sftp connection.
|
|
85
|
+
sftpconn = SFTPConnection()
|
|
86
|
+
sftpconn.connect(host, user, pwd)
|
|
87
|
+
|
|
88
|
+
# Preparing for sftp testing.
|
|
89
|
+
lhome = os.environ.get('HOME') or os.environ['HOMEPATH']
|
|
90
|
+
lputdir = os.path.join(lhome, 'lputdir')
|
|
91
|
+
lgetdir = os.path.join(lhome, 'lgetdir')
|
|
92
|
+
rputdir = '/tmp/rputgetdir'
|
|
93
|
+
rgetdir = rputdir
|
|
94
|
+
if os.path.exists(lputdir):
|
|
95
|
+
shutil.rmtree(lputdir)
|
|
96
|
+
if sftpconn.exists(rputdir):
|
|
97
|
+
sshconn.exec(f'rm -rf {rputdir}')
|
|
98
|
+
sftpconn.makedirs(rputdir)
|
|
99
|
+
os.makedirs(os.path.join(lputdir, 'dir', 'subdir'))
|
|
100
|
+
os.system('whoami > %s' % os.path.join(lputdir, 'file'))
|
|
101
|
+
os.system('whoami > %s' % os.path.join(lputdir, 'dir', 'subfile'))
|
|
102
|
+
|
|
103
|
+
# Put directory.
|
|
104
|
+
l = os.path.join(lputdir, 'dir')
|
|
105
|
+
sftpconn.putdir(l, rputdir)
|
|
106
|
+
p1 = sftpconn.join(rputdir, 'dir', 'subdir')
|
|
107
|
+
assert sftpconn.exists(p1) == True
|
|
108
|
+
p2 = sftpconn.join(rputdir, 'dir', 'subfile')
|
|
109
|
+
assert sftpconn.exists(p2) == True
|
|
110
|
+
|
|
111
|
+
# Put file.
|
|
112
|
+
l = os.path.join(lputdir, 'file')
|
|
113
|
+
sftpconn.putfile(l, rputdir)
|
|
114
|
+
p1 = sftpconn.join(rputdir, 'file')
|
|
115
|
+
assert sftpconn.exists(p1) == True
|
|
116
|
+
sftpconn.putfile(l, rputdir, 'newfile') # rename
|
|
117
|
+
p2 = sftpconn.join(rputdir, 'newfile')
|
|
118
|
+
assert sftpconn.exists(p2) == True
|
|
119
|
+
|
|
120
|
+
# Get directory.
|
|
121
|
+
r = sftpconn.join(rgetdir, 'dir')
|
|
122
|
+
sftpconn.getdir(r, lgetdir)
|
|
123
|
+
p1 = os.path.join(lgetdir, 'dir', 'subdir')
|
|
124
|
+
assert os.path.exists(p1) == True
|
|
125
|
+
p2 = os.path.join(lgetdir, 'dir', 'subfile')
|
|
126
|
+
assert os.path.exists(p2) == True
|
|
127
|
+
|
|
128
|
+
# Get file.
|
|
129
|
+
r = sftpconn.join(rgetdir, 'file')
|
|
130
|
+
sftpconn.getfile(r, lgetdir)
|
|
131
|
+
p1 = os.path.join(lgetdir, 'file')
|
|
132
|
+
assert os.path.exists(p1) == True
|
|
133
|
+
sftpconn.getfile(r, lgetdir, 'newfile') # rename
|
|
134
|
+
p2 = os.path.join(lgetdir, 'newfile')
|
|
135
|
+
assert os.path.exists(p2) == True
|
|
136
|
+
|
|
137
|
+
# Open file.
|
|
138
|
+
p = sftpconn.join(rputdir, 'file')
|
|
139
|
+
with sftpconn.open(p, 'w') as fp:
|
|
140
|
+
fp.write('xbot')
|
|
141
|
+
with sftpconn.open(p, 'r') as fp:
|
|
142
|
+
assert fp.read().decode('utf-8') == 'xbot'
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## Demo Project
|
|
146
|
+
|
|
147
|
+
Here is a [demo](https://github.com/zhaowcheng/xbot.plugins.ssh/tree/v0.1.0/demo) project showing how to use `xbot.plugins.ssh` in a test project.
|
|
148
|
+
|
|
149
|
+
***
|
|
150
|
+
|
|
151
|
+
## 简介
|
|
152
|
+
|
|
153
|
+
`xbot.plugins.ssh` 是为 [xbot.framework](https://github.com/zhaowcheng/xbot.framework) 提供 ssh 和 sftp 支持的插件。
|
|
154
|
+
|
|
155
|
+
## 安装
|
|
156
|
+
|
|
157
|
+
使用 pip 安装:
|
|
158
|
+
|
|
159
|
+
```
|
|
160
|
+
pip install xbot.plugins.ssh
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## 入门
|
|
164
|
+
|
|
165
|
+
```python
|
|
166
|
+
import os
|
|
167
|
+
import shutil
|
|
168
|
+
|
|
169
|
+
from xbot.plugins.ssh.ssh import SSHConnection
|
|
170
|
+
from xbot.plugins.ssh.sftp import SFTPConnection
|
|
171
|
+
|
|
172
|
+
# Modify the following information to your own before trying to run.
|
|
173
|
+
host = '192.168.8.8'
|
|
174
|
+
user = 'xbot'
|
|
175
|
+
pwd = 'xbot'
|
|
176
|
+
|
|
177
|
+
# Create ssh connection.
|
|
178
|
+
sshconn = SSHConnection()
|
|
179
|
+
sshconn.connect(host, user, pwd)
|
|
180
|
+
|
|
181
|
+
# Expect the return code of command is 0.
|
|
182
|
+
sshconn.exec('ls -l', expect=0)
|
|
183
|
+
|
|
184
|
+
# Expect the return code of command is 2.
|
|
185
|
+
sshconn.exec('ls /errpath', expect=2)
|
|
186
|
+
|
|
187
|
+
# Expect the output of command contains `username`.
|
|
188
|
+
sshconn.exec('whoami', expect=user)
|
|
189
|
+
|
|
190
|
+
# Don't check the result of command.
|
|
191
|
+
sshconn.exec('ls -l', expect=None)
|
|
192
|
+
sshconn.exec('ls /errpath', expect=None)
|
|
193
|
+
|
|
194
|
+
# Execute command with sudo.
|
|
195
|
+
sshconn.sudo('whoami', expect='root')
|
|
196
|
+
|
|
197
|
+
# Interactive command.
|
|
198
|
+
sshconn.exec("read -p 'input: '", prompts={'input:': 'hello'})
|
|
199
|
+
|
|
200
|
+
# Attributes and methods of SSHCommandResult.
|
|
201
|
+
cmd = 'echo -e "jack 20\ntom 30"'
|
|
202
|
+
result = sshconn.exec(cmd)
|
|
203
|
+
assert str(result) == 'jack 20\ntom 30'
|
|
204
|
+
assert result.rc == 0
|
|
205
|
+
assert result.cmd == cmd
|
|
206
|
+
assert result.getfield('tom', 2) == '30'
|
|
207
|
+
assert result.getcol(2) == ['20', '30']
|
|
208
|
+
|
|
209
|
+
# Create sftp connection.
|
|
210
|
+
sftpconn = SFTPConnection()
|
|
211
|
+
sftpconn.connect(host, user, pwd)
|
|
212
|
+
|
|
213
|
+
# Preparing for sftp testing.
|
|
214
|
+
lhome = os.environ.get('HOME') or os.environ['HOMEPATH']
|
|
215
|
+
lputdir = os.path.join(lhome, 'lputdir')
|
|
216
|
+
lgetdir = os.path.join(lhome, 'lgetdir')
|
|
217
|
+
rputdir = '/tmp/rputgetdir'
|
|
218
|
+
rgetdir = rputdir
|
|
219
|
+
if os.path.exists(lputdir):
|
|
220
|
+
shutil.rmtree(lputdir)
|
|
221
|
+
if sftpconn.exists(rputdir):
|
|
222
|
+
sshconn.exec(f'rm -rf {rputdir}')
|
|
223
|
+
sftpconn.makedirs(rputdir)
|
|
224
|
+
os.makedirs(os.path.join(lputdir, 'dir', 'subdir'))
|
|
225
|
+
os.system('whoami > %s' % os.path.join(lputdir, 'file'))
|
|
226
|
+
os.system('whoami > %s' % os.path.join(lputdir, 'dir', 'subfile'))
|
|
227
|
+
|
|
228
|
+
# Put directory.
|
|
229
|
+
l = os.path.join(lputdir, 'dir')
|
|
230
|
+
sftpconn.putdir(l, rputdir)
|
|
231
|
+
p1 = sftpconn.join(rputdir, 'dir', 'subdir')
|
|
232
|
+
assert sftpconn.exists(p1) == True
|
|
233
|
+
p2 = sftpconn.join(rputdir, 'dir', 'subfile')
|
|
234
|
+
assert sftpconn.exists(p2) == True
|
|
235
|
+
|
|
236
|
+
# Put file.
|
|
237
|
+
l = os.path.join(lputdir, 'file')
|
|
238
|
+
sftpconn.putfile(l, rputdir)
|
|
239
|
+
p1 = sftpconn.join(rputdir, 'file')
|
|
240
|
+
assert sftpconn.exists(p1) == True
|
|
241
|
+
sftpconn.putfile(l, rputdir, 'newfile') # rename
|
|
242
|
+
p2 = sftpconn.join(rputdir, 'newfile')
|
|
243
|
+
assert sftpconn.exists(p2) == True
|
|
244
|
+
|
|
245
|
+
# Get directory.
|
|
246
|
+
r = sftpconn.join(rgetdir, 'dir')
|
|
247
|
+
sftpconn.getdir(r, lgetdir)
|
|
248
|
+
p1 = os.path.join(lgetdir, 'dir', 'subdir')
|
|
249
|
+
assert os.path.exists(p1) == True
|
|
250
|
+
p2 = os.path.join(lgetdir, 'dir', 'subfile')
|
|
251
|
+
assert os.path.exists(p2) == True
|
|
252
|
+
|
|
253
|
+
# Get file.
|
|
254
|
+
r = sftpconn.join(rgetdir, 'file')
|
|
255
|
+
sftpconn.getfile(r, lgetdir)
|
|
256
|
+
p1 = os.path.join(lgetdir, 'file')
|
|
257
|
+
assert os.path.exists(p1) == True
|
|
258
|
+
sftpconn.getfile(r, lgetdir, 'newfile') # rename
|
|
259
|
+
p2 = os.path.join(lgetdir, 'newfile')
|
|
260
|
+
assert os.path.exists(p2) == True
|
|
261
|
+
|
|
262
|
+
# Open file.
|
|
263
|
+
p = sftpconn.join(rputdir, 'file')
|
|
264
|
+
with sftpconn.open(p, 'w') as fp:
|
|
265
|
+
fp.write('xbot')
|
|
266
|
+
with sftpconn.open(p, 'r') as fp:
|
|
267
|
+
assert fp.read().decode('utf-8') == 'xbot'
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
## 示例项目
|
|
271
|
+
|
|
272
|
+
展示如何在一个测试项目中使用本插件的示例:[demo](https://github.com/zhaowcheng/xbot.plugins.ssh/tree/v0.1.0/demo)
|
|
273
|
+
|
|
274
|
+
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<br>English | <a href="README.zh.md">中文</a>
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
***
|
|
6
|
+
|
|
7
|
+
## Introduction
|
|
8
|
+
|
|
9
|
+
`xbot.plugins.ssh` provides ssh and sftp support for [xbot.framework](https://github.com/zhaowcheng/xbot.framework)
|
|
10
|
+
|
|
11
|
+
## Installation
|
|
12
|
+
|
|
13
|
+
Install via pip:
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
pip install xbot.plugins.ssh
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Getting Started
|
|
20
|
+
|
|
21
|
+
```python
|
|
22
|
+
import os
|
|
23
|
+
import shutil
|
|
24
|
+
|
|
25
|
+
from xbot.plugins.ssh.ssh import SSHConnection
|
|
26
|
+
from xbot.plugins.ssh.sftp import SFTPConnection
|
|
27
|
+
|
|
28
|
+
# Modify the following information to your own before trying to run.
|
|
29
|
+
host = '192.168.8.8'
|
|
30
|
+
user = 'xbot'
|
|
31
|
+
pwd = 'xbot'
|
|
32
|
+
|
|
33
|
+
# Create ssh connection.
|
|
34
|
+
sshconn = SSHConnection()
|
|
35
|
+
sshconn.connect(host, user, pwd)
|
|
36
|
+
|
|
37
|
+
# Expect the return code of command is 0.
|
|
38
|
+
sshconn.exec('ls -l', expect=0)
|
|
39
|
+
|
|
40
|
+
# Expect the return code of command is 2.
|
|
41
|
+
sshconn.exec('ls /errpath', expect=2)
|
|
42
|
+
|
|
43
|
+
# Expect the output of command contains `username`.
|
|
44
|
+
sshconn.exec('whoami', expect=user)
|
|
45
|
+
|
|
46
|
+
# Don't check the result of command.
|
|
47
|
+
sshconn.exec('ls -l', expect=None)
|
|
48
|
+
sshconn.exec('ls /errpath', expect=None)
|
|
49
|
+
|
|
50
|
+
# Execute command with sudo.
|
|
51
|
+
sshconn.sudo('whoami', expect='root')
|
|
52
|
+
|
|
53
|
+
# Interactive command.
|
|
54
|
+
sshconn.exec("read -p 'input: '", prompts={'input:': 'hello'})
|
|
55
|
+
|
|
56
|
+
# Attributes and methods of SSHCommandResult.
|
|
57
|
+
cmd = 'echo -e "jack 20\ntom 30"'
|
|
58
|
+
result = sshconn.exec(cmd)
|
|
59
|
+
assert str(result) == 'jack 20\ntom 30'
|
|
60
|
+
assert result.rc == 0
|
|
61
|
+
assert result.cmd == cmd
|
|
62
|
+
assert result.getfield('tom', 2) == '30'
|
|
63
|
+
assert result.getcol(2) == ['20', '30']
|
|
64
|
+
|
|
65
|
+
# Create sftp connection.
|
|
66
|
+
sftpconn = SFTPConnection()
|
|
67
|
+
sftpconn.connect(host, user, pwd)
|
|
68
|
+
|
|
69
|
+
# Preparing for sftp testing.
|
|
70
|
+
lhome = os.environ.get('HOME') or os.environ['HOMEPATH']
|
|
71
|
+
lputdir = os.path.join(lhome, 'lputdir')
|
|
72
|
+
lgetdir = os.path.join(lhome, 'lgetdir')
|
|
73
|
+
rputdir = '/tmp/rputgetdir'
|
|
74
|
+
rgetdir = rputdir
|
|
75
|
+
if os.path.exists(lputdir):
|
|
76
|
+
shutil.rmtree(lputdir)
|
|
77
|
+
if sftpconn.exists(rputdir):
|
|
78
|
+
sshconn.exec(f'rm -rf {rputdir}')
|
|
79
|
+
sftpconn.makedirs(rputdir)
|
|
80
|
+
os.makedirs(os.path.join(lputdir, 'dir', 'subdir'))
|
|
81
|
+
os.system('whoami > %s' % os.path.join(lputdir, 'file'))
|
|
82
|
+
os.system('whoami > %s' % os.path.join(lputdir, 'dir', 'subfile'))
|
|
83
|
+
|
|
84
|
+
# Put directory.
|
|
85
|
+
l = os.path.join(lputdir, 'dir')
|
|
86
|
+
sftpconn.putdir(l, rputdir)
|
|
87
|
+
p1 = sftpconn.join(rputdir, 'dir', 'subdir')
|
|
88
|
+
assert sftpconn.exists(p1) == True
|
|
89
|
+
p2 = sftpconn.join(rputdir, 'dir', 'subfile')
|
|
90
|
+
assert sftpconn.exists(p2) == True
|
|
91
|
+
|
|
92
|
+
# Put file.
|
|
93
|
+
l = os.path.join(lputdir, 'file')
|
|
94
|
+
sftpconn.putfile(l, rputdir)
|
|
95
|
+
p1 = sftpconn.join(rputdir, 'file')
|
|
96
|
+
assert sftpconn.exists(p1) == True
|
|
97
|
+
sftpconn.putfile(l, rputdir, 'newfile') # rename
|
|
98
|
+
p2 = sftpconn.join(rputdir, 'newfile')
|
|
99
|
+
assert sftpconn.exists(p2) == True
|
|
100
|
+
|
|
101
|
+
# Get directory.
|
|
102
|
+
r = sftpconn.join(rgetdir, 'dir')
|
|
103
|
+
sftpconn.getdir(r, lgetdir)
|
|
104
|
+
p1 = os.path.join(lgetdir, 'dir', 'subdir')
|
|
105
|
+
assert os.path.exists(p1) == True
|
|
106
|
+
p2 = os.path.join(lgetdir, 'dir', 'subfile')
|
|
107
|
+
assert os.path.exists(p2) == True
|
|
108
|
+
|
|
109
|
+
# Get file.
|
|
110
|
+
r = sftpconn.join(rgetdir, 'file')
|
|
111
|
+
sftpconn.getfile(r, lgetdir)
|
|
112
|
+
p1 = os.path.join(lgetdir, 'file')
|
|
113
|
+
assert os.path.exists(p1) == True
|
|
114
|
+
sftpconn.getfile(r, lgetdir, 'newfile') # rename
|
|
115
|
+
p2 = os.path.join(lgetdir, 'newfile')
|
|
116
|
+
assert os.path.exists(p2) == True
|
|
117
|
+
|
|
118
|
+
# Open file.
|
|
119
|
+
p = sftpconn.join(rputdir, 'file')
|
|
120
|
+
with sftpconn.open(p, 'w') as fp:
|
|
121
|
+
fp.write('xbot')
|
|
122
|
+
with sftpconn.open(p, 'r') as fp:
|
|
123
|
+
assert fp.read().decode('utf-8') == 'xbot'
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Demo Project
|
|
127
|
+
|
|
128
|
+
Here is a [demo](https://github.com/zhaowcheng/xbot.plugins.ssh/tree/master/demo) project showing how to use `xbot.plugins.ssh` in a test project.
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<br>中文 | <a href="README.md">English</a>
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
***
|
|
6
|
+
|
|
7
|
+
## 简介
|
|
8
|
+
|
|
9
|
+
`xbot.plugins.ssh` 是为 [xbot.framework](https://github.com/zhaowcheng/xbot.framework) 提供 ssh 和 sftp 支持的插件。
|
|
10
|
+
|
|
11
|
+
## 安装
|
|
12
|
+
|
|
13
|
+
使用 pip 安装:
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
pip install xbot.plugins.ssh
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## 入门
|
|
20
|
+
|
|
21
|
+
```python
|
|
22
|
+
import os
|
|
23
|
+
import shutil
|
|
24
|
+
|
|
25
|
+
from xbot.plugins.ssh.ssh import SSHConnection
|
|
26
|
+
from xbot.plugins.ssh.sftp import SFTPConnection
|
|
27
|
+
|
|
28
|
+
# Modify the following information to your own before trying to run.
|
|
29
|
+
host = '192.168.8.8'
|
|
30
|
+
user = 'xbot'
|
|
31
|
+
pwd = 'xbot'
|
|
32
|
+
|
|
33
|
+
# Create ssh connection.
|
|
34
|
+
sshconn = SSHConnection()
|
|
35
|
+
sshconn.connect(host, user, pwd)
|
|
36
|
+
|
|
37
|
+
# Expect the return code of command is 0.
|
|
38
|
+
sshconn.exec('ls -l', expect=0)
|
|
39
|
+
|
|
40
|
+
# Expect the return code of command is 2.
|
|
41
|
+
sshconn.exec('ls /errpath', expect=2)
|
|
42
|
+
|
|
43
|
+
# Expect the output of command contains `username`.
|
|
44
|
+
sshconn.exec('whoami', expect=user)
|
|
45
|
+
|
|
46
|
+
# Don't check the result of command.
|
|
47
|
+
sshconn.exec('ls -l', expect=None)
|
|
48
|
+
sshconn.exec('ls /errpath', expect=None)
|
|
49
|
+
|
|
50
|
+
# Execute command with sudo.
|
|
51
|
+
sshconn.sudo('whoami', expect='root')
|
|
52
|
+
|
|
53
|
+
# Interactive command.
|
|
54
|
+
sshconn.exec("read -p 'input: '", prompts={'input:': 'hello'})
|
|
55
|
+
|
|
56
|
+
# Attributes and methods of SSHCommandResult.
|
|
57
|
+
cmd = 'echo -e "jack 20\ntom 30"'
|
|
58
|
+
result = sshconn.exec(cmd)
|
|
59
|
+
assert str(result) == 'jack 20\ntom 30'
|
|
60
|
+
assert result.rc == 0
|
|
61
|
+
assert result.cmd == cmd
|
|
62
|
+
assert result.getfield('tom', 2) == '30'
|
|
63
|
+
assert result.getcol(2) == ['20', '30']
|
|
64
|
+
|
|
65
|
+
# Create sftp connection.
|
|
66
|
+
sftpconn = SFTPConnection()
|
|
67
|
+
sftpconn.connect(host, user, pwd)
|
|
68
|
+
|
|
69
|
+
# Preparing for sftp testing.
|
|
70
|
+
lhome = os.environ.get('HOME') or os.environ['HOMEPATH']
|
|
71
|
+
lputdir = os.path.join(lhome, 'lputdir')
|
|
72
|
+
lgetdir = os.path.join(lhome, 'lgetdir')
|
|
73
|
+
rputdir = '/tmp/rputgetdir'
|
|
74
|
+
rgetdir = rputdir
|
|
75
|
+
if os.path.exists(lputdir):
|
|
76
|
+
shutil.rmtree(lputdir)
|
|
77
|
+
if sftpconn.exists(rputdir):
|
|
78
|
+
sshconn.exec(f'rm -rf {rputdir}')
|
|
79
|
+
sftpconn.makedirs(rputdir)
|
|
80
|
+
os.makedirs(os.path.join(lputdir, 'dir', 'subdir'))
|
|
81
|
+
os.system('whoami > %s' % os.path.join(lputdir, 'file'))
|
|
82
|
+
os.system('whoami > %s' % os.path.join(lputdir, 'dir', 'subfile'))
|
|
83
|
+
|
|
84
|
+
# Put directory.
|
|
85
|
+
l = os.path.join(lputdir, 'dir')
|
|
86
|
+
sftpconn.putdir(l, rputdir)
|
|
87
|
+
p1 = sftpconn.join(rputdir, 'dir', 'subdir')
|
|
88
|
+
assert sftpconn.exists(p1) == True
|
|
89
|
+
p2 = sftpconn.join(rputdir, 'dir', 'subfile')
|
|
90
|
+
assert sftpconn.exists(p2) == True
|
|
91
|
+
|
|
92
|
+
# Put file.
|
|
93
|
+
l = os.path.join(lputdir, 'file')
|
|
94
|
+
sftpconn.putfile(l, rputdir)
|
|
95
|
+
p1 = sftpconn.join(rputdir, 'file')
|
|
96
|
+
assert sftpconn.exists(p1) == True
|
|
97
|
+
sftpconn.putfile(l, rputdir, 'newfile') # rename
|
|
98
|
+
p2 = sftpconn.join(rputdir, 'newfile')
|
|
99
|
+
assert sftpconn.exists(p2) == True
|
|
100
|
+
|
|
101
|
+
# Get directory.
|
|
102
|
+
r = sftpconn.join(rgetdir, 'dir')
|
|
103
|
+
sftpconn.getdir(r, lgetdir)
|
|
104
|
+
p1 = os.path.join(lgetdir, 'dir', 'subdir')
|
|
105
|
+
assert os.path.exists(p1) == True
|
|
106
|
+
p2 = os.path.join(lgetdir, 'dir', 'subfile')
|
|
107
|
+
assert os.path.exists(p2) == True
|
|
108
|
+
|
|
109
|
+
# Get file.
|
|
110
|
+
r = sftpconn.join(rgetdir, 'file')
|
|
111
|
+
sftpconn.getfile(r, lgetdir)
|
|
112
|
+
p1 = os.path.join(lgetdir, 'file')
|
|
113
|
+
assert os.path.exists(p1) == True
|
|
114
|
+
sftpconn.getfile(r, lgetdir, 'newfile') # rename
|
|
115
|
+
p2 = os.path.join(lgetdir, 'newfile')
|
|
116
|
+
assert os.path.exists(p2) == True
|
|
117
|
+
|
|
118
|
+
# Open file.
|
|
119
|
+
p = sftpconn.join(rputdir, 'file')
|
|
120
|
+
with sftpconn.open(p, 'w') as fp:
|
|
121
|
+
fp.write('xbot')
|
|
122
|
+
with sftpconn.open(p, 'r') as fp:
|
|
123
|
+
assert fp.read().decode('utf-8') == 'xbot'
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## 示例项目
|
|
127
|
+
|
|
128
|
+
展示如何在一个测试项目中使用本插件的示例:[demo](https://github.com/zhaowcheng/xbot.plugins.ssh/tree/master/demo)
|
|
File without changes
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
from typing import Union
|
|
2
|
+
|
|
3
|
+
from xbot.framework import testbed
|
|
4
|
+
from xbot.plugins.ssh.ssh import SSHConnection
|
|
5
|
+
from xbot.plugins.ssh.sftp import SFTPConnection
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class TestBed(testbed.TestBed):
|
|
9
|
+
"""
|
|
10
|
+
TestBed for ssh demo.
|
|
11
|
+
"""
|
|
12
|
+
def __init__(self, filepath: str):
|
|
13
|
+
"""
|
|
14
|
+
:param filepath: testbed filepath.
|
|
15
|
+
"""
|
|
16
|
+
super().__init__(filepath)
|
|
17
|
+
self._conns = {
|
|
18
|
+
'ssh': {},
|
|
19
|
+
'sftp': {}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
def get_conn(
|
|
23
|
+
self,
|
|
24
|
+
typ: str,
|
|
25
|
+
role: str
|
|
26
|
+
) -> Union[SSHConnection, SFTPConnection]:
|
|
27
|
+
"""
|
|
28
|
+
Get specific connection to the specified role.
|
|
29
|
+
|
|
30
|
+
:param typ: connection type, 'ssh' or 'sftp'.
|
|
31
|
+
:param role: user role.
|
|
32
|
+
"""
|
|
33
|
+
typs = ('ssh', 'sftp')
|
|
34
|
+
if typ not in typs:
|
|
35
|
+
raise ValueError(f'Invalid connection type: {typ}, should be one of {typs}.')
|
|
36
|
+
for user in self.get('host.users'):
|
|
37
|
+
if user['role'] == role:
|
|
38
|
+
if role not in self._conns[typ]:
|
|
39
|
+
conn = SSHConnection() if typ == 'ssh' else SFTPConnection()
|
|
40
|
+
conn.connect(self.get('host.ip'),
|
|
41
|
+
user['name'],
|
|
42
|
+
user['password'],
|
|
43
|
+
port=self.get('host.sshport'))
|
|
44
|
+
self._conns[typ][role] = conn
|
|
45
|
+
return self._conns[typ][role]
|
|
46
|
+
raise ValueError(f'No such user: role={role}')
|
|
47
|
+
|
|
48
|
+
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from xbot.framework import testcase
|
|
2
|
+
|
|
3
|
+
from .testbed import TestBed
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class TestCase(testcase.TestCase):
|
|
7
|
+
"""
|
|
8
|
+
TestCase for ssh demo.
|
|
9
|
+
"""
|
|
10
|
+
@property
|
|
11
|
+
def testbed(self) -> TestBed:
|
|
12
|
+
"""
|
|
13
|
+
TestBed instance.
|
|
14
|
+
"""
|
|
15
|
+
return self.__testbed
|
|
File without changes
|