本网站相关文章:

Expect

作者: Don Libes

Definity

功能: Expect 是一个免费的编程工具语言, 用来实现自动和交互式任务进行通信.

定义: Expect 是一个用来实现自动交互功能的软件套件, 随着时间流逝 expect 的功能越加完善

Expect 基于 TCL 语言, 基于上面的定义, 可以了解 Expect 主要用于系统管理员以及嵌入式开发, 系统管理员可以基于它进行自动化的脚本编写:

  • 模拟输入, 可能是命令, 可能是程序的输入值
  • 根据输出进行下一步的操作

整个 expect 脚本都是基于上面的两步操作, 可以了解, expect 主要是自动化工作, 将已经预先了解的, 但是需要人工繁琐的重复的工作以一种输入A, 期望输出A-OUTPU的方式进行自动化. 减少人工输入错误, 一次执行成功, 后续工作量为 0 的成本. 后续的 pexpect, paramiko, fabric 都是基于此种最初/最终的目的提出的.

应用场景:

  • 某些提供某种命令行工具, 但是缺乏脚本编程的能力, 仅仅为了用户管理产品, 此时需要利用 expect 收集输出
  • 测试套件, 用于嵌入式

当然, 对于图形化, expect 则毫无用武之地.

Theory

最简单层次: Expect 的工作方式像一个通用化的 Chat 脚本工具, Chat 脚本最早用于 UUCP 网络内, 以用来实现计算机之间需要建立连接时进行特定的登录会话的自动化.

Chat 脚本: 由一系列 expect-send 对组成, expect 等待输出中输出特定的字符, 通常为提示符, 然后发送特定的响应. 例如实现一个简单的登录过程. Expect 就是参考 Chat, 利用 spawn 来启动衍生子进程, 随后使用expectsend来实现交互过程.

  • 脚本启动 spawn 命令, 创建子进程
  • 脚本 expect
  • 脚本 send 新的命令: command1
  • 脚本 expect 新的响应: output1

整个逻辑基于此, 并使用 before/after 等来判断返回值, 以绝对后续是否需要继续.

Example

默认 telnet 登录会话:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 打开telnet会话
spawn telnet $remote_server
expect "username:"

# 2-1 用户名
send "$my_user_id\r"
expect "password:"
# 2-2 密码
send "$my_password\r"
expect "%"
# 2-3 写入变量, 这里没有考察返回值, 即不调用expect, 此时没有返回值
set results $expect_out(buffer)

# 退出
send "exit\r"
expect eof

一个 expect 脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#!/usr/bin/expect -f

set hostname [lindex $argv 0]
set username [lindex $argv 1]
set password [lindex $argv 2]

spawn ssh -o StrictHostKeyChecking=no $username\@$hostname

expect {
timeout { send_user "\nTimeout Exceeded - Check Host\n"; exit 1 }
eof { send_user "\nSSH Connection To $hostname Failed\n"; exit 1 }
"*%" {}
"*assword:" {
send "$password\n"
}
}

expect "*%"
send "system service status\n"
expect "*%"
send "exit\n"
expect "*[Y/N]:"
send "y\n"
exit 0

Expect and SSH

Expect: Unix 系统中用来进行自动化控制和测试的软件工具,作为 Tcl 脚本语言的一个扩展, 该工具利用 Unix 伪终端包装其子进程, 允许任意程序通过终端接入进行自动化控制.
SSH: 一种加密的网络传输协议, 在不安全的网络中为网络服务提供安全的传输环境.
注意, 一种是协议, 一种是具体的软件工具. 当然, 基于 SSH 的自动化运维管理工具: fabric 实现的功能则类似 expect. 关于 ssh(ssh1/ssh2), 见参考ssh-configure介绍说明.

Pexpect

功能

对 expect 的 python 封装, 以便使用 python 来实现自动化交互工作, 其他功能大体同 Expect,关于具体的 expect 使用, 可以见以前的项目或者相关文章.

安装: pip install pexpect

Example

自动化的 ftp 操作:

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
import pexpect
import sys

# 启动子进程
child = pexpect.spawn('ftp server')
child.expect('(?i)name .*: ')
# 账号
child.sendline('anonymous')
child.expect('(?i)password')
# 密码
child.sendline('password8870')
child.expect('ftp> ')
# 设置二进制
child.sendline('bin')
child.expect('ftp> ')
# 下载文件
child.sendline('get test.txt')
child.expect('ftp> ')
# 使用interact, 直接进入远程控制终端, 注意使用interact, 确保sys.stdout不是默认
# 否则输入异常
child.interact()

# 退出
child.sendline('bye')
child.close()

转化

Paramiko

关于 paramiko 的详细介绍, 见后续文章fabric

功能

Paramiko–基于 python 实现的 SSH2 远程安全连接, 支持认证和密钥. 用以实现远程命令执行, 文件传输, 中间 SSH 代理等功能, 关于 SSH2 见 ssh-configure 的文章介绍. Paramiko 和 Pexpect 在结果上非常相似, 但是本质上的原理是不一样的, 前者基于 SSH2 , 是对
SSH 的封装( SFTP 等 ), 后者则是基于 Chat 语言进行expect and send工作的.
安装 paramiko 命令: pip install paramiko

整个 paramiko 的处理过程与 pexpect 大体类似, 总共分为 2 走:

  • 设置 paramiko 全局变量, 例如日志
  • 初始化连接, 从~/.ssh/known_hosts 读取默认的 keys 等
  • 连接和操作
  • 关闭连接

Example

连接远程服务器, 并打印目录中所有文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# coding:utf8
import paramiko

hostname='192.168.10.4'
username='bamboo'
password='password'

# 设置日志
paramiko.util.log_to_file('/tmp/paramiko.log')

# 初始化连接
ssh = paramiko.SSHClient()
ssh.load_system_host_keys()

# 连接
ssh.connect(hostname=hostname, username=username, password=password)
stdin, stdout, stderr = ssh.exec_command('ls -la')
print 'Output:\n', stdout.read()

# 关闭
ssh.close()

Fabric

关于 fabric 的详细介绍, 见后续文章fabric

Function

fabric–对 paramiko 的封装, 除去了后者操作的复杂度, 针对 SSH 命令行进行一系列的优化, 常常用于应用程序部署, 系统管理任务.
fabric–用于本地和远程 shell 命令, 用于命令执行, 文件上传/下载等等.

Configure

安装 fabric: pip install fabric

关于 fabric 的各个参数, 见官网文档介绍fabric

Example

将本地的 github 项目提交到远程服务器, 并重启远程服务器

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
from fabric.api import local, lcd, run, env, cd, roles, settings, with_settings, hosts, parallel, hide
from fabric.api import output, task, abort, prefix, path, quiet, remote_tunnel
from fabric.contrib.console import confirm

env.roledefs = {
'vps': ['root@106.0.10.1:29139'],
'bamboo': ['bamboo@106.2.3.193'],
'feng': ['ubuntu@150.19.4.228'],
}
env.use_ssh_config = True

# 装饰器: 指定相关条件, http://fabric-chs.readthedocs.io/zh_CN/chs/api/core/decorators.html
@roles('bamboo')
def bamboo():
"""用以替代shell"""
# 上下文管理器迭代语法: with, 支持嵌套和&操作
# 见https://www.rddoc.com/doc/Fabric/1.13.1/zh/api/core/context_managers/
# 远程命令
with cd('~/workspace/blog'):
# 上下文管理器: prefix
# 所有命令前缀: prefixCommand && childCommand
with prefix('export BAMBOO=/root'):
run('echo $BAMBOO')
run('pwd')
run('git pull origin master')
# 用以检查当前目录
run('pwd')
# 切换工作目录, 但是可能在未来删除, 不建议
with settings(cwd='~/workspace/blog'):
run('pwd')

参考: