当业务比较大比较复杂的时候,单纯的使用 Ansible 有时候不会很好的完成相关的运维工作,这个时候就需要开发针对自己业务的一些模块或者 ansible 插件来完成这些工作,ansible 提供了一个 python api 接口用于开发编程,使用 python 开发更为自动化的运维管理系统,这个 python api 接口是 python 模块 ansible 下的一个类,即 runner

Ansible技术问答:http://linux.xyz/topic/Ansible

1、runner 安装部署

$ wget "https://pypi.python.org/packages/source/p/pip/pip-1.5.4.tar.gz#md5=834b2904f92d46aaa333267fb1c922bb" --no-check-certificate
$ tar -xzvf pip-1.5.4.tar.gz
$ cd pip-1.5.4
$ python setup.py install
$ pip install runner

runner 安装在/usr/lib/python2.6/site-packages/ansible/runner

注:runner 目录下面有个__init__.py 文件,init.py 的作用, 相当于 class 中的 def init(self):函数,用来初始化模块,把所在目录当作一个 package 处理

2、runner 使用说明

#!/usr/bin/python

#
coding = utf - 8
import ansible.runner
import json
Get_Host_Name = ansible.runner.Runner(#host_list = "/etc/ansible/xyz.py", ##可以使用动态 inventory 脚本 host_list = "/etc/ansible/hosts",
    module_name = 'shell',
    module_args = 'hostname',
    pattern = 'web',
    forks = 10).run()
print json.dumps(Get_Host_Name, indent = 4)

上面是一个简单的 ansible python api 的执行的例子,我们可以看到他调用的 runner 模块 run()方法是执行定义好的 runner 对象,并返回类型是字典的执行结果,可以封装解析成 json,如下:

{
    "dark": {#
        连接不上的主机的返回结果集合
            "192.168.0.6": {
                "msg": "SSH Error: Permission denied (publickey,password).\n while connecting to 192.168.0.6:22\nIt is sometimes useful to re-run the command using -vvvv, which prints SSH debug output to help diagnose the issue.",
                "failed": true
            }
    },
    "contacted": {#
        可以正常连接的主机的返回结果集合
            "192.168.0.5": {
                "changed": true,
                "end": "2016-04-28 14:19:09.407521",
                ##标准输出返回的内容 "stdout": "TMP-OPS-99-5",
                "cmd": [
                    "hostname"
                ],
                "start": "2016-04-28 14:19:09.390006",
                "delta": "0:00:00.017515",
                ##执行成功, 错误输出为空 "stderr": "",
                ##返回状态码: 0 "rc": 0,
                "invocation": {
                    "module_name": "shell",
                    "module_complex_args": {},
                    "module_args": "hostname"
                },
                "warnings": []
            },
            "192.168.0.4": {
                "changed": true,
                "end": "2016-04-28 14:19:08.369520",
                ##执行失败, 标准输出为空 "stdout": "",
                "cmd": [
                    "hostname"
                ],
                "start": "2016-04-28 14:19:08.352359",
                "delta": "0:00:00.017161",
                ##错误输出返回的内容 "stderr": "/bin/sh: hostname: command not found",
                "rc": 127,
                "invocation": {
                    "module_name": "shell",
                    "module_complex_args": {},
                    "module_args": "hostname"
                },
                "warnings": []
            }
    }
}

这些返回的结果对后面python 开发很有用,可以通过数据的字段值来判断执行有没有成功,或者可以获取一些关键数据等等

3、runner 参数讲解

import absible.runner
class Runner(object):
    
    def __init__(self,
                 
 ## 这里可以放静态 hosts 文件,也可以放 inventory 的脚本,脚本要 777 权限
                host_list=C.DEFAULT_HOST_LIST,
 ## 这个是 ansible 的路径,一般不用写
                module_path=None,
 ## 模块的名字,模块的位置要选定在/usr/share/absible 下,不然会识别不了
                module_name=C.DEFAULT_MODULE_NAME,
 ## 模块的参数,如“src=/tmp/a dest=/tmp/b”
                module_args=C.DEFAULT_MODULE_ARGS,
 ## 并发线程线
                forks=C.DEFAULT_FORKS,
 ## 超时的时间
                timeout=C.DEFAULT_TIMEOUT,
 ## inventory 的匹配
                pattern=C.DEFAULT_PATTERN,
## 远程主机用户的选择
                remote_user=C.DEFAULT_REMOTE_USER,
 ## 远程主机密码的选择
                remote_pass=C.DEFAULT_REMOTE_PASS,
 ## 远程主机端口的选择
                remote_port=None,
 ## 是否是 sudo
                sudo=False,
 ## sudo 用户名
                sudo_user=C.DEFAULT_SUDO_USER,
 ## sudo 密码
                sudo_pass=C.DEFAULT_SUDO_PASS,
 ## 连接方式 默认是用的 paramiko
                transport=C.DEFAULT_TRANSPORT,
 ## 回调的输出
                callbacks=None,
 ## 如果没有使用密码,可以指定 key
                private_key_file=C.DEFAULT_PRIVATE_KEY_FILE
 ):
 ......

4、runner 应用示例

获取各个远程主机的实际可用内存(free + cache + buffers)

#!/usr/bin/python

#
file: get_freeMemory.py# coding = utf - 8


import ansible.runner
import sys
import json# 获取远程主机的实际可用内存大小: MB
Get_Hosts_FreeMem = ansible.runner.Runner(
    host_list = "/etc/ansible/hosts"
    pattern = "*",
    module_name = "shell",
    module_args = "/usr/bin/free -m |grep 'buffers/cache' |/bin/awk '{print $3}'",
    forks = 10, ).run()

# 用 json 封装一下数据, 为了后面 print 显示结果更直观一些--调试使用# Get_Hosts_FreeMem = json.dumps(Get_Hosts_FreeMem, indent = 4)# print Get_Hosts_FreeMem + "\n\n"#
Get_Hosts_FreeMem = json.loads(Get_Hosts_FreeMem)# 能连通的主机

if Get_Hosts_FreeMem["contacted"]:
    for hostname, result in Get_Hosts_FreeMem["contacted"].items(): #可以正常获取到内存数据的主机
if Get_Hosts_FreeMem["contacted"][hostname]["stdout"]:
    print "主机:%s, 实际可用内存:%s" % (hostname, Get_Hosts_FreeMem["contacted"][hostname]["stdout"])# 不能正常获取到内存数据的主机
elif Get_Hosts_FreeMem["contacted"][hostname]["stderr"]:
    print "主机:%s, 获取内存失败:%s" % (hostname, Get_Hosts_FreeMem["contacted"][hostname]["stderr"])# 连接不上主机
if Get_Hosts_FreeMem["dark"]:
    for hostname, result in Get_Hosts_FreeMem["dark"].items():
    print "host:%s, 异常信息显示:%s" % (hostname, Get_Hosts_FreeMem["dark"][hostname]["msg"].replace("\n", " "))# pattern 没有可以匹配的主机

if not Get_Hosts_FreeMem["contacted"] and not Get_Hosts_FreeMem["dark"]:
    print "No hosts found"
sys.exit(1)

执行 python 脚本,结果如下:

主机:192.168.0.6, 实际可用内存:171
主机:192.168.0.5, 实际可用内存:171
主机:192.168.0.7, 异常信息显示:SSH Error: Permission denied (publickey,password).while connecting to 192.168.0.7:22 It is sometimes useful to rerun the command using -vvvv, which prints SSH debug output to help diagnose the issue.