the5fire的技术博客

关注python、vim、linux、web开发和互联网--life is short, we need python.


探索ansible执行原理

作者:the5fire | 标签:       | 发布:2014-02-26 7:24 a.m. | 阅读量: 16747, 16460

书接上篇文章: ansbile中文指南 ,实验最后那个playbook时始终难以完成启动django项目的操作,于是就去跟随着ansible执行的过程,看了下源码。

1. runner

不得不说的这个runner接口,这是ansible下层用来执行远程命令的一个接口,无论是上一篇说的Ad-Hoc命令的执行: ansible -i ~/hosts all -m command -a 'who' ,还是最后一个执行playbook的命令: ansible-playbook playbook.yml ,下面掉得都是这个接口。

在ansible官网文档的Python API处也是介绍的这个接口: Python API 。比如要执行上面那个Ad-Hoc的命令,直接调用这个接口的话得这么写:

import ansible.runner

runner = ansible.runner.Runner(
    module_name='command',
    module_args='who',
    pattern='local',
    forks=10
)
datastructure = runner.run()
print datastructure

打印出来的结果是这样的:

{
 'dark': {

 },
 'contacted': {
     '127.0.0.1': {
     u'changed': True,
     u'end': u'2014-02-25 22:11:16.566084',
     u'stdout': u'Guest    console  Feb  1 16:29 \nthe5fire console  Jan 20 19:50 \nthe5fire ttys023  Feb 25 22:11 \t(localhost)\nthe5fire ttys024  Feb 24 22:20 \t(localhost)',
     u'cmd': [
         u'who'
     ],
     u'rc': 0,
     u'start': u'2014-02-25 22:11:16.556888',
     u'stderr': u'',
     u'delta': u'0:00:00.009196',
     'invocation': {
         'module_name': 'command',
         'module_args': 'who'
     }
     }
 }
}

从这个地方我们可以了解到为什么对于受控制服务器需要安装simplejson,因为控制服务器和受控服务器都需要通过json格式进行数据传递的。

2. 整体的流程图

有了上面的认识,runner之上的东西就比较好理解了,都是业务相关的东西,比如:收集CLI(命令行界面)的数据、获取playbook.yml中的数据,以及对应的解析等等。

根据我的理解,画了一个大概的图出来,可以用来参考:

http://the5fireblog.b0.upaiyun.com/staticfile/ansible-exec.png

图上是一个大概的流程,只是针对playbook来说(Ad-Hoc的执行是直接掉得runner)。

首先ansbile-playbook接受到参数: playbook.yml,然后读取这个yml文件,根据这个yml文件生成Playbook对象,代码: class Playbook

在这个Playbook中加载yml文件,在执行时生成Play对象,在Play对象中又包含了Task对象,一个Task对象可以算是一个最小的执行单元。

到了Task这一步之后就应该调用runner接口了,这个接口的调用还是在Playbook这个类中: Playbook._run_task_internal 。而这个runner接口,上面已经介绍了,到此也就大体了解上层的执行过程了。

3. 再继续探索runner下层

上面已经探索了ansible-playbook在执行时的流程,这里再继续深入了解一下,想看看ansible到底是如何执行的。

在runner这个类中,具体执行某一个task时是通过一个Action Module来完成的,这个action module是根据参数确定的,比如咱配置的是异步操作还是同步操作,这个不深究,默认是加载normal中的ActionModule,位置: normal 。在这个Action中对要执行的命令做了处理,对shell和command进行了处理,然后调用runner中的 self.runner._execute_module 来执行对应模块的操作,也就是playbook上写的git或者shell这样的模块。

到这整个过程其实还是挺无趣的,不过这个_execute_module里面的过程还是有点意思的。这个过程做了什么事呢?

首先,根据对应模块加载了library下面的对应的模块代码比如shell加载的是:library/commands/command这个代码,(这里要注意,上面加载的是normal的action模块,在那个模块里对shell进行了处理,变为command,因此这里就是command了)。找到这个具体的模块文件之后,ansible会加载一个module_common.py,对其进行渲染(把咱们定义的命令,比如:virtualenv ~demo,渲染到这个文件中)。

渲染完毕之后,会把这个文件copy到远程服务器的用户家目录下的.ansible/tmp/ansible-xxxxxx 这样的文件夹下(那个ansible-xxxx中xxx表示不知道是以什么方式生成的字符序列,可能是时间戳)。如果咱们定义的是一个shell,这里会多一个command的py文件,并且是可执行的。如果是git,这个文件名就是git。

传输完毕之后,就是执行了。ansible默认是以兼容的ssh来进行远程命令执行的,执行的方法就是,通过subprocess,来执行ssh和已经传输到远程服务器的可执行的python文件,通过PIPE的方式把执行结果输出回来,输出的CLI上。

大概就是这么个过程,只是大致的看了下整个的执行过程,很多地方复杂的逻辑都忽略了,最后的通过subprocess的方式执行ssh远程操作,并把结果通过PIPE输出回来不是特别理解其原理。

有兴趣的同学,如果耐心看了本文,并且也看了源码的话,不妨交流交流。


----EOF-----

扫码关注,或者搜索微信公众号:码农悟凡


其他分类: