产品与解决方案 Robot Framework+SSHLibrary 实现自动化运维质量检测

超爱fitnesse · 2015年06月10日 · 最后由 mrwnb 回复于 2022年10月19日 · 3250 次阅读
本帖已被设为精华帖!

Robot Framework+SSHLibrary 介绍

首先,介绍一下 robotframework,oschina 这么介绍:

Robot Framework 是一个关键词驱动的自动测试框架。测试用例位于 HTML 或者 TSV(以 tab 分隔值) 文件,使用在测试库中实现的关键词来在测试中运行程序。因为 Robot Framework 是灵活和可扩展的,所以它很合适用于测试具有多种接口的复杂软件:用户接口,命令行,webservice,编程接口等。

Robot FrameworkCumcumber http://www.oschina.net/p/cucumber 具有相似的能力,都属于 BDD 自动化测试工具。
但是 Cumcumber 只能顺序验证测试步骤,比如:

Given  我在登录页
When  我输入帐号"zhangsan"
And      我输入密码"123456"
And      我点击登录按钮
Then    我能看到我的昵称"张三"

上述的 "我在登录页" 等步骤的定义,都在 Cumcumber 的 step_definitions.rb 中,用 ruby 语言定义。

如果对 Cumcumber 测试安卓手机 APP 感兴趣,可以参阅 使用 calabash 测试开源中国 Android 客户端

Robot Framework在语义级别就提供了 FOR 循环和 IF 判断,自定义 Keyword 直接在.robot 文件中,不需要写一句 Python 语句。

然后再去官网 http://robotframework.org/ ,到 TestLibraries 看看都提供了什么测试库:

STANDARD 库中包含 OperatingSystem,String,Collections,提供了调用本地 shell 命令,字符串处理,和 Python 集合的处理能力。

EXTERNAL 库中有手机 APP 测试相关的测试库、网页测试相关、http 测试相关、数据库相关、ssh 相关。

我最看中的就是其中 SSHLibrary,它提供 ssh 登录和执行远程命令的能力,并能用 sftp 上传下载文件。

SSHLibrary 对 python 库 paramiko 进行了封装,所以他是Farbric的兄弟,Fabric 常用于自动化运维,但是缺少对运维结果的检测能力。

所以,Robot Framework+SSHLibrary 天生就适合做网站的自动化运维质量检测。

自动化运行质量检测,包含那些内容?

  • mysql, mongo, nginx 等工具的配置是否正确
  • mysql, mongo, nginx 等工具的进程是否已崩溃
  • mysql, mongo, nginx 的数据等目录的 owner 是否正确
  • 网站服务器各结点的网络配置是否正确
  • 各 tomcat, jetty 服务的版本是否符合预期

后面通过一个一个的小例子,来演示 Robot Framework+SSHLibrary 怎样达到自动化运维质量检测

Debian/Ubunbu 下安装 Robot Framework+SSHLibrary

Python 默认已安装

pip: python 环境下模块安装工具

sudo apt-get install python-pip 

python-dev: 某些 python 模块安装需要 Python.h,所以要安装 python-dev

sudo apt-get install python-dev

robotframework: http://robotframework.org

sudo pip install robotframework

如果使用默认 pip 源很慢,可以指定豆瓣的 pip 源:

sudo pip install robotframework -i http://pypi.douban.com/simple

SSHLibrary: https://github.com/robotframework/SSHLibrary

pip install robotframework-sshlibrary

Redhat/CentOS 下安装 Robot Framework+SSHLibrary

只要把 Debian 对应安装命令中的 apt-get 改成 yum, dev 改成 devel
Python 默认已安装

pip: python 环境下模块安装工具

sudo yum install python-pip 

python-devel: 某些 python 模块安装需要 Python.h,所以要安装 python-devel

sudo yum install python-devel

robotframework: http://robotframework.org

sudo pip install robotframework

SSHLibrary: https://github.com/robotframework/SSHLibrary

pip install robotframework-sshlibrary

RobotFramework+SSHLibrary 远程调用命令示例

示例来自: http://robotframework.org/SSHLibrary/

注意

  • 下面的 ${HOST}, ${USERNAME}, ${PASSWORD} 请使用自己远程机器名、帐号和密码
  • 还要确保远程机器已经开启了 sshd 服务

测试用例文件:

shen@debian:~/robotframework$ cat executing-commands.robot
*** Settings ***
Documentation          This example demonstrates executing commands on a remote machine
...                    and getting their output and the return code.
...
...                    Notice how connections are handled as part of the suite setup and
...                    teardown. This saves some time when executing several test cases.

Library                SSHLibrary
Suite Setup            Open Connection And Log In
Suite Teardown         Close All Connections

*** Variables ***
${HOST}                localhost
${USERNAME}            shen
${PASSWORD}            123456

*** Test Cases ***
Execute Command And Verify Output
    [Documentation]    Execute Command can be used to ran commands on the remote machine.
    ...                The keyword returns the standard output by default.
    ${output}=    Execute Command    echo Hello SSHLibrary!
    Should Be Equal    ${output}    Hello SSHLibrary!

Execute Command And Verify Return Code
    [Documentation]    Often getting the return code of the command is enough.
    ...                This behaviour can be adjusted as Execute Command arguments.
    ${rc}=    Execute Command    echo Success guaranteed.    return_stdout=False    return_rc=True
    Should Be Equal    ${rc}    ${0}

Executing Commands In An Interactive Session
    [Documentation]    Execute Command always executes the command in a new shell.
    ...                This means that changes to the environment are not persisted
    ...                between subsequent Execute Command keyword calls.
    ...                Write and Read Until variants can be used to operate in the same shell.
    Write    cd ..
    Write    echo Hello from the parent directory!
    ${output}=    Read Until    directory!
    Should End With     ${output}    Hello from the parent directory!

*** Keywords ***
Open Connection And Log In
   Open Connection    ${HOST}
   Login    ${USERNAME}    ${PASSWORD}

gedit 打开 executing-commands.robot 的效果:

执行结果:

shen@debian:~/robotframework$ pybot executing-commands.robot 
==============================================================================
Executing Commands :: This example demonstrates executing commands on a rem...
==============================================================================
Execute Command And Verify Output :: Execute Command can be used t... | PASS |
------------------------------------------------------------------------------
Execute Command And Verify Return Code :: Often getting the return... | PASS |
------------------------------------------------------------------------------
Executing Commands In An Interactive Session :: Execute Command al... | PASS |
------------------------------------------------------------------------------
Executing Commands :: This example demonstrates executing commands... | PASS |
3 critical tests, 3 passed, 0 failed
3 tests total, 3 passed, 0 failed
==============================================================================
Output:  /home/shen/robotframework/output.xml
Log:     /home/shen/robotframework/log.html
Report:  /home/shen/robotframework/report.html

Robot Framework+SSHLibrary 实现自动化运维质量检测

example-100: 直接在命令行输入 ssh 密码

为了能方便演示,每个例子都有各编号如 100,对应的代码目录~/robotframework/100
上述基本 ssh 例子先简化如下:

shen@debian:~/robotframework/100$ cat example-100.robot
*** Settings ***
Documentation          ssh示例

Library                SSHLibrary
Suite Setup            Open Connection And Log In
Suite Teardown         Close All Connections

*** Variables ***
${HOST}                localhost
${USERNAME}            shen
${PASSWORD}            123456

*** Test Cases ***
远程执行命令并检验输出
    ${output}=    Execute Command    echo Hello SSHLibrary!
    Should Be Equal    ${output}    Hello SSHLibrary!

*** Keywords ***
Open Connection And Log In
   Open Connection    ${HOST}
   Login    ${USERNAME}    ${PASSWORD}

说明: 上述检验内容是 ssh 到 localhost,执行 shell 命令: echo Hello SSHLibrary!

应该看到 stdout 为 Hello SSHLibrary!

下面用手工执行 ssh 来模拟上述检验:

在使用 if 判断变量 output 时,碰到了单引号和双引号的替换规则问题,而且 bash 的 if-else-fi 真心难写。

只有下面 if 中的单双引号使用是正确的:

if [ "$output" == 'Hello SSHLibrary!' ]; then echo -e "| \033[32mPASS\033[0m |"; else echo -e "| \033[31mFAIL\033[0m |"; fi

回到正题,我想在 pybot 命令行直接输入 ssh 密码,可以这样执行:

因为输入的是错误密码,所以提示: Authentication failed for user 'shen'.

规则 1: pybot 命令行中输入的变量值会覆盖 robot 文件中*** Variables ***中定义的变量值

example-110: 执行测试时打印调试信息

上面的 example-100.robot 运行时,屏幕上只打印了 testcase 名称和测试结果绿色 PASS 或红色 FAIL。

在运行目录下生成了 3 个文件:output.xml, log.html, report.html,先分别打开看看:

我不习惯去看 html 文件,所以我想在运行时直接打印 output 变量的内容。

先去官网找到Log To Console的帮助信息: http://robotframework.org/robotframework/latest/libraries/BuiltIn.html#Log%20To%20Console

官网帮助中的 robotframework 测试用例格式都是表格,但是最实用的是 txt 格式,测试用例文件的后缀可以是.txt 或.robot

表格格式的分隔方式就是一个一个格子,txt 格式对应分隔符是两个以上空格或者一个以上 Tab。

shen@debian:~/robotframework/110$ cat example-110.robot
*** Settings ***
Documentation          ssh示例

Library                SSHLibrary
Suite Setup            Open Connection And Log In
Suite Teardown         Close All Connections

*** Variables ***
${HOST}                localhost
${USERNAME}            shen
${PASSWORD}            123456

*** Test Cases ***
远程执行命令并检验输出
    ${output}=         Execute Command    echo Hello SSHLibrary!
    Log To Console     \n\${output}的内容:"\x1b[1;33m${output}\x1b[0m"
    Should Be Equal    ${output}    Hello SSHLibrary!

*** Keywords ***
Open Connection And Log In
   Open Connection    ${HOST}
   Login              ${USERNAME}    ${PASSWORD}

请注意新增行:

Log To Console     \n\${output}的内容:"\x1b[1;33m${output}\x1b[0m"

执行测试结果:

说明:
\x1b[1;33m${output}\x1b[0m 是以高亮黄色打印变量 ${output}的内容。\x1b 与 echo 打印彩色时的\033 是相同的。

但是 robotframework 测试用例文件的语法中不支持\0nn 八进制,只支持\xnn 十六进制。
Log To Console右边必须先输入两个以上空格或 1 个以上 Tab,再输入变量;两个变量之间也要如此分隔。

规则 2: robotframework 测试用例文件中字符 $ 要用\$ 转义,\xnn 指定十六进制字符。

example-120: 我要把服务器的结点信息保存在外部文件中

首先看一下 pybot 的-h 帮助:
执行命令: pybot -h,其中的-v 参数可以指定一个变量的值,-V 可以从一个文件中指定多个变量。

shen@debian:~/robotframework/120$ cat node-list.py
SSH_SERVERS = ['node01', 'node02', 'node03']

NODE_IP_MAP = {
    'node01':'localhost',
    'node02':'127.0.0.1',
    'node03':'192.168.0.107',
}
shen@debian:~/robotframework/120$ cat example-120.robot 
*** Settings ***
Documentation          ssh示例

Library                Collections
Library                SSHLibrary
Suite Teardown         Close All Connections

*** Variables ***

*** Test Cases ***
远程执行命令并检验输出
    :FOR    ${node}    IN    @{SSH_SERVERS}
    \    ${node_ip}=    Get From Dictionary    ${NODE_IP_MAP}     ${node}
    \    Log To Console     \n正在登录 ${node}(${node_ip}) ...
    \    Open Connection And Log In "${node_ip}"
    \    Log To Console     \n正在${node}(${node_ip})执行命令: echo Hello SSHLibrary!
    \    ${output}=         Execute Command    echo Hello SSHLibrary!
    \    Log To Console     \n\${output}的内容:"\x1b[1;33m${output}\x1b[0m"
    \    Should Be Equal    ${output}    Hello SSHLibrary!

*** Keywords ***
Open Connection And Log In "${node_ip}"
   Open Connection    ${node_ip}
   Login              ${USERNAME}    ${PASSWORD}

请注意例子 120 的几处新内容:

  • node-list.py 定义了所有结点的 ip 信息和 ssh 服务器列表,使用 python 的列表和字典定义
  • example-120.robot 中引入了新测试库: Collections http://robotframework.org/robotframework/latest/libraries/Collections.html
  • 重新定义了关键字:Open Connection And Log In,可以接受参数 ${node_ip}
  • 使用 FOR 循环遍历 SSH_SERVERS 中的每个结点。

example-130: 我要确保服务器结点的 python 版本都是 2.7.3

shen@debian:~/robotframework/130$ cat node-list.py
PYTHON_SERVERS = ['node01', 'node03']

SSH_SERVERS = ['node01', 'node02', 'node03']

NODE_IP_MAP = {
    'node01':'localhost',
    'node02':'127.0.0.1',
    'node03':'192.168.0.107',
}
shen@debian:~/robotframework/130$ cat versions.py
VERSIONS = {
    'python':'2.7.3',
    'gcc':'4.7.2',
    'ssh':'OpenSSH_6.0p1',
}
shen@debian:~/robotframework/130$ cat example-130.robot 
*** Settings ***
Documentation          ssh示例

Library                Collections
Library                SSHLibrary
Suite Teardown         Close All Connections

*** Variables ***

*** Test Cases ***
远程执行命令并检验输出
    :FOR    ${node}    IN    @{SSH_SERVERS}
    \    ${node_ip}=    Get From Dictionary    ${NODE_IP_MAP}     ${node}
    \    Log To Console     \n正在登录 ${node}(${node_ip}) ...
    \    Open Connection And Log In "${node_ip}"
    \    Log To Console     \n正在${node}(${node_ip})执行命令: echo Hello SSHLibrary!
    \    ${output}=         Execute Command    echo Hello SSHLibrary!
    \    Log To Console     \n\${output}的内容:"\x1b[1;33m${output}\x1b[0m"
    \    Should Be Equal    ${output}    Hello SSHLibrary!

检查python版本
    :FOR    ${node}    IN    @{PYTHON_SERVERS}
    \    ${node_ip}=    Get From Dictionary    ${NODE_IP_MAP}     ${node}
    \    Open Connection And Log In "${node_ip}"
    \    Log To Console     \n正在${node}(${node_ip})执行命令: python --version 2>&1 | cut -d' ' -f 2
    \    ${output}=         Execute Command    python --version 2>&1 | cut -d' ' -f 2
    \    ${version}=    Get From Dictionary    ${VERSIONS}     python
    \    Log To Console     \npython版本${output} == 期望版本${version} ?
    \    Should Be Equal    ${output}    ${version}

*** Keywords ***
Open Connection And Log In "${node_ip}"
   Open Connection    ${node_ip}
   Login              ${USERNAME}    ${PASSWORD}

执行测试命令:

pybot -v USERNAME:shen -v PASSWORD:123456 -V node-list.py -V versions.py example-130.robot

如果更改期望版本为 2.6.6:

shen@debian:~/robotframework/130$ cat versions.py
VERSIONS = {
    'python':'2.6.6',
    'gcc':'4.7.2',
    'ssh':'OpenSSH_6.0p1',
}

测试结果如下:

因为测试用例 “检查 python 版本” 中的第一个结点的 python 版本检查断言:Should Be Equal ${output} ${version}失败,

所以 robotframework 直接退出本测试用例的执行,不会再去检查第二个结点的 python 版本。

example-140: 检查交互式输出的内容

shen@debian:~/robotframework/140$ cat example-140.robot 
*** Settings ***
Documentation          交互式检查python版本

Library                Collections
Library                SSHLibrary
Suite Teardown         Close All Connections

*** Variables ***

*** Test Cases ***
交互式检查python版本
    :FOR    ${node}    IN    @{PYTHON_SERVERS}
    \    ${node_ip}=    Get From Dictionary    ${NODE_IP_MAP}     ${node}
    \    Open Connection And Log In "${node_ip}"
    \    Write    python
    \    ${output}=    Read Until    >>>
    \    Log To Console     \n${node}(${node_ip})执行命令python的输出:---\n${output}\n---
    \    ${version}=    Get From Dictionary    ${VERSIONS}     python
    \    Log To Console     \n${node}(${node_ip})的python版本 == ${version} ?
    \    Should Contain     ${output}    ${version}


*** Keywords ***
Open Connection And Log In "${node_ip}"
   Open Connection    ${node_ip}
   Login              ${USERNAME}    ${PASSWORD}

执行测试结果:

example-150: 关键字定义放在独立文件中

shen@debian:~/robotframework/150$ cat keywords.robot 
*** Settings ***
Library                Collections
Library                SSHLibrary

*** Keywords ***
Check Python Version "${servers}" "${version}"
    :FOR    ${node}    IN    @{servers}
    \    ${node_ip}=    Get From Dictionary    ${NODE_IP_MAP}     ${node}
    \    Open Connection    ${node_ip}
    \    Login              ${USERNAME}    ${PASSWORD}    
    \    Write    python
    \    ${output}=    Read Until    >>>
    \    Log To Console     \n${node}(${node_ip})执行命令python的输出:---\n${output}\n---
    \    Log To Console     \n${node}(${node_ip})的python版本 == ${version} ?
    \    Should Contain     ${output}    ${version}


shen@debian:~/robotframework/150$ cat example-150.robot 
*** Settings ***
Documentation          交互式检查python版本

Resource               keywords.robot
Suite Teardown         Close All Connections

*** Variables ***

*** Test Cases ***
交互式检查python版本
    ${version}=    Get From Dictionary    ${VERSIONS}     python
    Check Python Version "${PYTHON_SERVERS}" "${version}"

*** Keywords ***

shen@debian:~/robotframework/150$ pybot -v USERNAME:shen -v PASSWORD:123456 -V node-list.py -V versions.py example-150.robot 
==============================================================================
Example-150 :: 交互式检查python版本                                           
==============================================================================
交互式检查python版本                                                  .
node01(localhost)执行命令python的输出:---
Python 2.7.3 (default, Mar 13 2014, 11:03:55) 
[GCC 4.7.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>>
---

node01(localhost)的python版本 == 2.7.3 ?

node03(192.168.0.107)执行命令python的输出:---
Python 2.7.3 (default, Mar 13 2014, 11:03:55) 
[GCC 4.7.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>>
---

node03(192.168.0.107)的python版本 == 2.7.3 ?
交互式检查python版本                                                  | PASS |
------------------------------------------------------------------------------
Example-150 :: 交互式检查python版本                                   | PASS |
1 critical test, 1 passed, 0 failed
1 test total, 1 passed, 0 failed
==============================================================================
Output:  /home/shen/robotframework/150/output.xml
Log:     /home/shen/robotframework/150/log.html
Report:  /home/shen/robotframework/150/report.html
shen@debian:~/robotframework/150$ 

example-160: 执行测试的彩色打印导出到文件

复用 example-150 的测试用例

pybot -C on -v USERNAME:shen -v PASSWORD:123456 -V node-list.py -V versions.py example-150.robot | tee ../160/color_output.txt

后面还有什么?

欢迎大家继续提出问题,我将尽力以上述 example 的方式给出答案。

共收到 7 条回复 时间 点赞

测试人员拓展一下视野,其实你比你认为的更能干!
测试和运维是两个相通的行业,可以用测试工具做运维,比如本博所介绍的,
也可以用运维工具帮助测试,比如运维中的监控工具、日志集合工具,都对测试有直接的帮助。

#1 楼 @htmlbiji 赞同你的观点。
另外,Robotframework 不是 BDD 框架,它主要是关键字驱动的。你文章中这方面的描述有点自相矛盾。
我帮你移到 产品与解决方案 这个区了。

#1 楼 @htmlbiji 貌似来自 OSChina 的图都挂了,能否修复一下?

写了这么多 辛苦 不过 rf 不适合做运维 用来做测试还是很强大的

#3 楼 @chenhengjie123
图片都重新上传了。

#5 楼 @htmlbiji 好的,感谢!

RF 低代码,对于无基础的测试人员还是挺友好的,但 ssh 连接上服务器后要多注意不同命令行下换行的区别,比如 redis 下 write 命令换行是\r\n

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册