Ansible_Grammar - QLGQ/learning-python GitHub Wiki
获取远程主机系统信息
Facts是一个非常有用的组件,实现获取远程主机的系统信息,包括主机名、IP地址、操作系统、分区信息、硬件信息等,可以配合playbook实现更加个性化、灵活的功能需求,比如在httpd.conf模板中引用Facts的主机名信息作为ServerName参数的值。通过运行ansible hostname -m setup
可获取Facts信息,例如,获取192.168.1.21的Facts信息需运行:ansible 192.168.1.21 -m setup。
在模板文件中这样引用Facts信息:
{{ ansible_devices.sda.model }}
{{ ansible_hostname }}
变量
在实际应用场景中,我们希望一些任务、配置根据设备性能的不同而产生差异,比如使用本机CPU核数动态配置Nginx的worker_processes参数,可能有一组主机的应用配置文件几乎相同,但略有不同的配置项可以引用变量。在ansible中使用变量的目的是方便处理系统之间的差异。
变量名的命名规则由字母、数字和下划线组合而成,变量必须以字母开头。
Jinja2过滤器
Jinja2是Python下一个广泛应用的模板引擎,它的设计思想类似于Django的模板引擎,并扩展了其语法和一系列强大的功能,官网地址:http://jinja.pocoo.org/。下面介绍一下ansible使用Jinja2强大的过滤(Filter)功能。
使用格式:{{ 变量名|过滤方法 }}
。
下面是实现获取一个文件路径变量过滤出文件名的一个示例:{{ path|basename }}。获取文件所处的目录名:{{ path|dirname }}。
下面为一个完整的示例,实现从“/etc/profile”中过滤出文件名“profile”,并输出重定向到/tmp/testshell文件中。
---
- hosts: 192.168.1.21
vars:
filename: /etc/profile
tasks:
- name: "shell1"
shell: echo {{ filename|basename }} >> /tmp/testshell
本地Facts
我们可以通过Facts来获取远程目标主机的系统信息,当这些信息还不能满足我们的功能需求时,可以通过编写自定义的Facts模块来实现。当然,还有一个更简单的实现方法,就是通过本地Facts来实现。只需在目标设备/etc/ansible/facts.d目录定义JSON、INI或可执行文件的JSON输出,文件扩展名要求使用“.fact”,这些文件都可以作为ansible的本地Facts,例如,在目标设备192.168.1.21定义三个变量,供以后playbook进行引用。
【/etc/ansible/facts.d/preferences.fact】
[general]
max_memory_size=32
max_user_processes=3730
open_files=65535
在主控端运行ansible 192.168.1.21 -m setup -a "filter=ansible_local"可看到定义的结果。 注意返回JSON的层次结构,preferences(facts文件名前缀) --> general(INI的节名) --> key:value(INI的键与值),最后就可以在我们的模板或playbook中通过以下方式进行调用:
{{ ansible_local.preferences.general.open_files }}`。
注册变量
变量的另一个用途是将一条命令的运行结果保存到变量中,供后面的playbook使用。下面是一个简单的示例:
- hosts: web_servers
tasks:
- shell: /usr/bin/foo
register: foo_result
ignore_errors: True
- shell: /usr/bin/bar
when: foo_result.rc == 5
上面示例注册了一个foo_result变量,变量值为shell:/usr/bin/foo的运行结果,ignore_errors:True为忽略错误。变量注册完成后,就可以在后面playbook中使用了,当条件语句when: foo_result.rc == 5成立时,shell: /usr/bin/bar命令才会运行,其中foo_result.rc为返回/usr/bin/foo的resultcode(返回码)。
条件语句
有时候我们想跳过某些主机的执行步骤,比如符合特定版本的操作系统将不安装某个软件包,或者磁盘空间爆满了将进行清理的步骤。在ansible中很容易做到这一点,通过when子句实现,其中将引用Jinja2表达式。下面是一个示例:
tasks:
- command: /bin/false
register: result
ignore_errors: True
- command: /bin/something
when: result|failed
- command: /bin/something_else
when: result|success
- command: /bin/still/something_else
when: result|skipped
“when: result|success”的意思为当变量result执行结果为成功状态时,将执行/bin/something_else命令,其他同理,其中success为ansible内部过滤器方法,返回True代表命令运行成功。
循环
通常一个任务会做很多事情,如创建大量的用户、安装很多包,或重复轮询特定的步骤,直到某种条件结果为止,ansible为我们提供了此支持。下面是一个简单的示例:
- name: add several users
user: name={{ item }} state=present groups=wheel
with_items:
- testuser1
- testuser2
这个示例实现了一个批量创建系统用户的功能,with_items会自动循环执行上面的语句“user: name={{ item }} state=present groups=wheel”,循环的次数为with_items的元素个数,这里有两个元素,分别为testuser1、testuser2,会分别替换{{ item }}项。这个示例与下面的示例是等价的:
- name: add user testuser1
user: name=testuser1 state=present groups=wheel
- name: add user testuser2
user: name=testuser2 state=present groups=wheel
当然,元素也支持字典的形式,如下:
- name: add several users
user: name={{ item.name }} state=present groups={{ item.groups }}
with_items:
- { name: 'testuser1', groups: 'wheel' }
- { name: 'testuser2', groups: 'wheel' }
循环也支持列表(List)的形式,不过是通过with_flattened语句来实现的,例如:
----
# file: roles/foo/vars/main.yml
packages_base:
- [ 'foo-package', 'bar-package' ]
packages_apps:
- [ ['one-package', 'two-package'] ]
- [ ['red-package', 'blue-package'] ]
以上定义了两个列表变量,分别是需要安装的软件包名,以便后面进行如下引用:
- name: flattened loop demo
yum: name={{ item }} state=installed
with_flattened:
- packages_base
- packages_apps