date: 2020-03-16title: ansible添加主机及when、loop使用 #标题
tags: ansible #标签
categories: ansible # 分类
add_host
[root@nginx ansible]# cat test.yaml
---
- name: add new host to test1 and test2
hosts: test1
gather_facts: false
tasks:
- name: add new host to test1 and test2
add_host: # 使用add_hosts模块
name: 192.168.20.3 # 指定主机名或IP
groups: # groups用来指定要添加到哪个主机组
- test1
- test2
ansible_port: 22
my_var: "hello world"
- name: ping test1 group in play1
ping:
- name: test new host in play2
hosts: test1
gather_facts: false
tasks:
- name: ping test1 group
ping:
- name: test new host in play3
hosts: test2
gather_facts: false
tasks:
- name: ping test2 group
ping:
hosts文件中定义的主机列表如下:
[root@nginx ansible]# tail -2 hosts # 没有定义test2主机组和20.3的主机
[test1]
192.168.20.2
执行结果如下:
上面playbook的执行结果中,将会显示play2和play3中都出现新主机192.168.20.3,而在play1中的ping则不会出现192.168.20.3。
setup和gather_facts
setup和gather_facts模块用来收集客户端的主机信息,使用方法如下:
# ansible test1 -m gather_facts
或者
# ansible test1 -m setup
两者区别:
- setup最早提供,而gather_facts模块是在ansible 2.8才提供的,gather_facts很有可能内部封装的就是setup模块。
- gather_facts比setup模块多一个功能:并行收集多个节点信息,而且在探测到要收集多个节点信息时会自动并行。
默认执行playbook文件时,ansible都会自动执行gather_facts模块去收集节点信息,这会造成卡顿,可以取消执行收集信息的操作,如下:
[root@nginx ansible]# cat a.yml
---
- name: test
hosts: test1
gather_facts: false # 添加此配置,以取消收集客户端信息
tasks:
- name: test
ping:
但有些时候,我们必须要收集客户端的信息,并使用它,下面将写下如何使用它。
收集到的信息格式如下:
上面是直接在终端打印出来了,那么在playbook中访问的话,方法如下:
[root@nginx ansible]# cat b.yml
---
- name: test
hosts: test1
tasks:
- name: test access variables
debug:
var: ansible_distribution
返回结果如下:
when条件判断
[root@nginx ansible]# cat a.yml
---
- name: test
hosts: test1
gather_facts: false
tasks:
- debug:
var: item
when: # when指定item大于3并小于5才为True。
- item > 3
- item < 5
loop: [1,2,3,4,5,6,7] # loop是循环将值赋给上面的item
返回结果如下:
可以看到在执行时跳过了1,2,3,5,6,7,只执行了4,上面的playbook文件还可以这样写:
[root@nginx ansible]# cat a.yml
---
- name: test
hosts: test1
gather_facts: false
tasks:
- debug:
var: item
when: item > 3 and item < 5 # and是与,还有or是或
with_items:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
when根据条件判断是否执行该任务
- name: "查看python3是否安装,忽略提示"
shell: python3 #执行一条命令,将结果赋值给register定义的result
register: result
ignore_errors: True #忽略错误提示
#拷贝Python-3.6.5
- name: "copy Python3-6.5 to dest"
copy: src=Python-3.6.5.tgz dest=/usr/local/src/Python-3.6.5.tgz
when: result is failed #当result返回的是个错误的时候,执行此tasks
#编译安装python3.6.5
- name: "compile install"
shell: pip install --upgrade supervisor requests;cd /usr/local/src/;tar zxf Python-3.6.5.tgz; cd Python-3.6.5;./configure --prefix=/usr/local/python3 --with-ssl;make;make install
when: result is failed
#软连接python3
- name: "ln -s python3"
file: src=/usr/local/python3/bin/python3 dest=/usr/bin/python3 state=link
when: result is failed
when和gather_facts结合使用
针对不同的操作系统加载不同的文件
我们想象这样一个场景:ansible管理了很多服务器,有不同的操作系统,然后在不同的系统版本上需要执行的任务不一样,比如要安装httpd服务,在redhat系统中包名为httpd,在debian系统中的包名为apache2。
对于这种因环境不同而配置不同任务的场景,通常是为不同环境定义不同的任务文件或者不同的变量文件,然后使用when的环境判断加载不同的文件到playbook文件中。
如下:
---
- name: test
hosts: test1
gather_facts: true
tasks:
- include_tasks: CentOS.yml
when: ansible_distribution == "CentOS" # 当ansible_distribution的值为centos时,加载上面的文件
- include_tasks: Debian.yml
when: ansible_distribution == "Debian" # 当ansible_distribution的值为debian时,加载上面的文件
# 至于ansible_distribution的值,则是gather_facts收集到的客户端信息保存到内置变量中的
上面的playbook实现了针对不同的操作系统导入不同的文件,但是代码有冗余性,可以修改为下面这样:
[root@nginx ansible]# cat a.yml
---
- name: test
hosts: test1
gather_facts: true
tasks:
- include_tasks: "{{ansible_distribution}}.yml"
with循环指令
当when指令和循环指令一起使用时,when的判断操作在每轮循环内执行。
loop指令用于循环,在ansible 2.5加入的,官方推荐使用loop指令,而不是with_xxx,比如:with_list、with_dict、with_item等。
相对来说with_xxx更为直观一些,with和loop都能实现一样的功能。
with_list
with_list:迭代一个列表
[root@nginx ansible]# cat a.yml # 以下是在test1主机组上创建两个文件
- name: test
hosts: test1
gather_facts: false
tasks:
- file:
name: "/tmp/{{item}}" # 这里使用item调用循环的文件名
state: touch
with_list: # 这里定义的是文件名列表,若要使用loop指令来实现同样的功能,只需将with_list改为loop即可
- "filename1"
- "filename2"
with_items和with_flattened
with_list用于迭代简单的列表,但有时候列表中会嵌套列表。这时就需要使用with_items,with_items可以完全替代with_list,这里不过多解释,如用到嵌套列表,自行百度吧。
with_indexed_items
如果迭代列表时,还想要获取每个元素的索引位置,则可以使用with_indexed_items
。
例如:
[root@nginx ansible]# cat a.yml
- name: test
hosts: test1
gather_facts: false
vars:
a: [b,[c,d],e]
tasks:
- debug:
msg: "index: {{item.0}},value: {{item.1}}"
with_indexed_items: "{{a}}"
执行结果如下:
ok: [192.168.20.2] => (item=[0, u'b']) => {
"msg": "index: 0,value: b"
}
ok: [192.168.20.2] => (item=[1, u'c']) => {
"msg": "index: 1,value: c"
}
ok: [192.168.20.2] => (item=[2, u'd']) => {
"msg": "index: 2,value: d"
}
ok: [192.168.20.2] => (item=[3, u'e']) => {
"msg": "index: 3,value: e"
}
with_dict
with_dict 用于迭代一个字典结构,迭代时可以使用item.key表示每个字典元素中的key,item.value表示每个字典元素的value。
例如:
- name: test
hosts: test1
gather_facts: false
vars:
users:
ray_key:
name: ray
age: 18
lvjianzhao_key:
name: lvjianzhao
age: 25
tasks:
- debug:
msg: "who: {{item.key}} &&
name: {{item.value.name}} &&
age: {{item.value.age}}"
with_dict: "{{users}}"
执行结果如下:
ok: [192.168.20.2] => (item={'value': {u'age': 25, u'name': u'lvjianzhao'}, 'key': u'lvjianzhao_key'}) => {
"msg": "who: lvjianzhao_key && name: lvjianzhao && age: 25"
}
ok: [192.168.20.2] => (item={'value': {u'age': 18, u'name': u'ray'}, 'key': u'ray_key'}) => {
"msg": "who: ray_key && name: ray && age: 18"
}
with_fileglob
with_fileglob用于迭代通配到的每个文件名。
例如:
[root@nginx ansible]# cat a.yml
- name: test
hosts: test1
gather_facts: false
tasks:
- copy:
src: "{{item}}"
dest: /tmp/
with_fileglob: # 指定本地/etc目录下匹配到的文件
- /etc/m*.conf
- /etc/*.cnf
执行结果如下:
TASK [copy] *************************
changed: [192.168.20.2] => (item=/etc/mke2fs.conf)
changed: [192.168.20.2] => (item=/etc/mtools.conf)
changed: [192.168.20.2] => (item=/etc/man_db.conf)
changed: [192.168.20.2] => (item=/etc/my.cnf)
with_lines
with_lines用于迭代命令输出结果的每一行。
这个功能非常使用,比如find找出一堆文件,然后进行操作,比如copy。
例如:
[root@nginx ansible]# cat a.yml
- name: test
hosts: test1
gather_facts: false
tasks:
- copy:
src: "{{item}}"
dest: /tmp/
with_lines:
- find /etc/ -type f -name "a*.sh"
执行结果如下:
changed: [192.168.20.2] => (item=/etc/profile.d/abrt-console-notification.sh)
changed: [192.168.20.2] => (item=/etc/dhcp/dhclient-exit-hooks.d/azure-cloud.sh)
循环和when
当with_xxx或loop和when指令一起使用时,when将在循环内部进行条件判断,也就是说,when决定每轮迭代时是否执行一个任务,而不是决定整个循环是否进行。
例如:
[root@nginx ansible]# cat a.yml
- name: test
hosts: test1
gather_facts: false
tasks:
- debug:
var: item
loop: [1,2,3,4,5]
when: item >= 3
上面的执行结果就是会输出3,4,5三个元素。
输出结果如下:
TASK [debug] *********************************************************************************
skipping: [192.168.20.2] => (item=1)
skipping: [192.168.20.2] => (item=2)
ok: [192.168.20.2] => (item=3) => {
"ansible_loop_var": "item",
"item": 3
}
ok: [192.168.20.2] => (item=4) => {
"ansible_loop_var": "item",
"item": 4
}
ok: [192.168.20.2] => (item=5) => {
"ansible_loop_var": "item",
"item": 5
}