Ansible 流程控制
一、playbook 条件语句
1.1 条件语句简介
什么是条件语句
判断某个条件成立,则执行某个task
为何要用条件语句?有很多场景例如
1、比如目标主机的最小内存必须达到多少,才能执行该task
2、根据命令输出结果的不同以触发不同的task
3、根据不同目标主机的facts,执行不同的task
4、判断某个服务的配置文件是否发生变更,以确定是否需要重启服务
1.2 条件语句用法
(1)基本示例
在ansible中,使用条件判断的关键字就是when。
when关键字后面跟着的是python的表达式,在表达式中你能够使用任何的变量或者fact,当表达式的结果返回的是false,便会跳过本次的任务
示例: 判断条件中的facts变量名可以通过ansible group5 -m setup进行查询
[root@lb workspace]# cat test1.yaml
- hosts: group3
tasks:
- name: Install httpd
yum:
name: httpd
state: present
when: ansible_distribution == "Rocky"
- name: Install nginx
yum:
name: nginx
state: present
when: ansible_distribution == "CentOS"
(2)比较运算符
可用于比较数字或字符串
==
!=
>
<
>=
<=
示例
when: ansible_machine == "x86_64"
when: ansible_memory_mb.real.free <= 512
当你用到一些facts值时,你不确定值是什么大小写是啥,你需要事先用下面的命令进行查看
# ansible group3 -m setup |less
# ansible group3 -m setup |grep -i distribution 查看出对应的值,再写条件
(3)逻辑运算符
除了比较运算符,还支持逻辑运算符:
- and:逻辑与,当左边和右边两个表达式同时为真,则返回真
- or:逻辑或,当左右和右边两个表达式任意一个为真,则返回真n
- ot:逻辑否,对表达式取反
- ():当一组表达式组合在一起,形成一个更大的表达式,组合内的所有表达式都是逻辑与的关系
示例
# 逻辑或
when: ansible_distribution == "Rocky" or ansible_distribution == "CentOS"
# 逻辑与
when: ansible_distribution_version == "9.3" and ansible_kernel == "5.14.0-362.8.1.el9_3.x86_64"
when:
- ansible_distribution_version == "9.3"
- ansible_kernel == "5.14.0-362.8.1.el9_3.x86_64"
# 组合
when: =>
( ansible_distribution == "Rocky" and ansible_distribution_major_version == "9" )
or
( ansible_distribution == "CentOS" and ansible_distribution_major_version == "7")
(4) 更复杂一些的判断
可以快速看一眼,了解都有哪些能力,有个基本印象,后续用的时候临时查就行
— egon:真正高效的学习方法,并非是记住所有东西,而是有所取舍,抓重点
https://egonlin.com/?p=9836
(5)一些逻辑判断示例
示例1:判断命令的结果
====================》判断register注册变量的返回结果
- name: restart httpd if postfix is running
hosts: group1
tasks:
- name: get postfix server status
command: /usr/bin/systemctl is-active postfix
ignore_errors: yes
register: result
- name: 打印debug信息,帮你看到结果,正式yaml可以去掉
debug:
msg:
- "命令的结果:{{ result }}"
- "命令的状态码: {{ result.rc }}"
- name: restart apache httpd based on postfix status
service:
name: httpd
state: restarted
when: result.rc == 0
示例2:判断系统版本
[root@m01 project]# vim xitong.yml
- hosts: web_group
tasks:
- name: Install Centos httpd
shell: "yum install -y httpd"
when: ansible_distribution == "CentOS"
- name: Install Ubuntu httpd
shell: "apt-get apache2"
when: ansible_distribution == "Ubuntu"
示例3:判断主机名,即在目标主机上hostname查看到的结果
[root@m01 project]# cat base.yml
- name: Create www Group
group:
name: www
gid: 666
state: present
when: ansible_fqdn != "db01"
- name: Create www User
user:
name: www
uid: 666
group: www
shell: /sbin/nologin
create_home: false
state: present
when: ansible_fqdn != "db01"
示例4:判断服务是否安装
[root@m01 project]# cat php.yml
- hosts: web_group
tasks:
- name: Tar php Package
unarchive:
src: /project/package/php.tar.gz
dest: /tmp/
#使用shell模块,检查php是否安装,将结果赋值给注册的变量
- name: Check php Install Status
shell: "rpm -qa | grep php | wc -l"
register: get_php_instll_status
#调用注册的变量,当变量中stdout_lines为0的时候,才会安装php
- name: Install php Server
shell: "yum localinstall -y /tmp/*.rpm"
when: get_php_instll_status.stdout_lines == 0
示例5:使用列表的形式判断系统版本
[root@m01 project]# vim startserver.yml
- hosts: web_group
tasks:
- name: Start CentOS 6 Server
shell: "/etc/init.d/httpd start"
when:
- ansible_distribution == "CentOS"
- ansible_distribution_major_version == "6"
- name: Start CentOS 7 Server
shell: "systemctl start httpd"
when:
- ansible_distribution == "CentOS"
- ansible_distribution_major_version == "7"
示例6:多条件and连接与列表形式效果一样
[root@m01 project]# vim startserver.yml
- hosts: web_group
tasks:
- name: Start CentOS 6 Server
shell: "/etc/init.d/httpd start"
when: (ansible_distribution == "CentOS") and (ansible_distribution_major_version == "6")
- name: Start CentOS 7 Server
shell: "systemctl start httpd"
when: (ansible_distribution == "CentOS") and (ansible_distribution_major_version == "7")
示例7:判断服务是否启动
- hosts: web_group
tasks:
- name: Check Httpd Server
command: systemctl is-active httpd
ignore_errors: yes
register: check_httpd
- name: debug outprint
debug: var=check_httpd
- name: Httpd Restart
service:
name: httpd
state: restarted
when: check_httpd.rc == 0
二、playbook 循环语句
2.1 简介
1、什么是循环
循环就是重复做某件事,对应loop语法(Ansible2.5版本中新增)
2、为何要用循环
我们在编写playbook的时候,不可避免的要执行一些重复性操作,比如
1、循环安装软件包列表
2、批量创建用户
3、操作某个目录下的所有文件等
循环语法就是用来实现这些重复性动作的,没有循环语法你只能将实现某段功能的代码重写多遍造成冗余
2.2 循环语句用法
在Ansible 2.5版本中新增语法loop循环,等价于with_list。
大多数时候,with_xxx的循环都可以通过一定的手段转换成loop循环,
所以从Ansible 2.5版本之后,原来经常使用的with_items循环都可以尝试转换成loop。
在playbook中使用循环,直接使用loop关键字即可。
示例1:启动httpd和crond服务:
- hosts: group1
tasks:
- name: httpd and crond are running
service:
name: "{{ item }}" # item是固定的变量名
state: restarted
loop:
- crond
- httpd
也可以将loop循环的列表提前赋值给一个变量,然后在循环语句中调用:
#cat /workspace/my_vars.yaml
test_services:
- crond
- httpd
# cat install_pkgs.yml
- hosts: group1
vars_files:
- /workspace/my_vars.yaml
tasks:
- name: postfix and crond are running
service:
name: "{{ item }}"
state: started
loop: "{{ test_services }}"
一个更复杂的示例
- hosts: group1
tasks:
# 1、先创建了一个www组
- name: add www group
group:
name: www
# 2、然后循环创建了两个用户
- name: add several users
user:
name: "{{ item.name }}"
state: present
groups: "{{ item.groups }}"
loop:
- { name: 'egon1', groups: 'temp_group' } # temp_group不存在的话会报错
- { name: 'egon2', groups: 'www' }
此外还有语法:loop_control,自行了解吧
2.3 旧的循环语法
1、定义循环安装服务(待安装的包名扔到一个列表里,yum会遍历循环安装)
[root@m01 project]# vim yum.yml
- hosts: group1
gather_facts: no
tasks:
- name: Install Redis Server
yum:
name: "{{ package }}"
state: present
vars:
package:
- redis
- httpd
2、定义循环启动服务
#错误写法: 不用试了,试不成功的
[root@m01 project]# vim start.yml
- hosts: web_group
tasks:
- name: Start Server
systemd:
name: "{{ package }}"
state: started
vars:
package:
- redis
- httpd
#正确写法
[root@m01 project]# vim start.yml
- hosts: web_group
tasks:
- name: Start Server
systemd:
name: "{{ item }}"
state: started
with_items:
- redis
- httpd
3、字典定义变量
[root@m01 project]# cat user.yml
- hosts: group1
tasks:
- name: Create Some Group
group:
name: "{{ item.name }}"
gid: "{{ item.gid }}"
state: present
with_items:
- { name: "lhf", gid: "777" }
- { name: "test", gid: "888" }
- { name: "egon", gid: "999" }
- name: Create Some User
user:
name: "{{ item.name }}"
uid: "{{ item.uid }}"
group: "{{ item.group }}"
shell: "{{ item.shell }}"
create_home: "{{ item.create_home }}"
with_items:
- { name: "lhf", uid: "777", group: "lhf", shell: "/sbin/nologin", create_home: "false" }
- { name: "test", uid: "888", group: "test", shell: "/bin/bash", create_home: "false" }
- { name: "egon", uid: "999", group: "egon", shell: "/bin/bash", create_home: "true" }
4、在Ansible 2.5以前更多的旧循环语法见:https://egonlin.com/?p=9843
三、playbook 任务标签
3.1.标签的作用
在大型项目当中,通常一个playbook会有非常多的task。而我们每次执行这个playbook时,都会将所有task运行一遍。而事实上,在实际使用过程中,我们可能只是想要执行其中的一部分任务而已,并不想把整个playbook完整跑一遍。这个时候就需要用到tags。
Ansible的标签(tag)功能可以给单独任务甚至整个playbook打上标签,
然后我们利用这些标签来指定要运行playbook中的个别任务,或不执行指定的任务。
3.2 标签使用示例
控制端准备配置文件
cat > /workspace/welcome.conf << "EOF"
<LocationMatch "^/+$">
Options -Indexes
ErrorDocument 403 /.noindex.html
</LocationMatch>
<Directory /usr/share/httpd/noindex>
AllowOverride None
Require all granted
</Directory>
Alias /.noindex.html /usr/share/httpd/noindex/index.html
Alias /poweredby.png /usr/share/httpd/icons/apache_pb3.png
Alias /system_noindex_logo.png /usr/share/httpd/icons/system_noindex_logo.png
EOF
示例
- hosts: group5
tasks:
- name: Install httpd
yum:
name: httpd
state: present
tags: install_httpd
- name: Cofiguration httpd
copy:
src: /workspace/welcome.conf
dest: /etc/httpd/conf.d/welcome.conf
tags: conf_httpd
notify:
- restart httpd
- name: Start httpd
service:
name: httpd
state: started
enabled: true
tags: start_httpd
handlers:
- name: restart httpd
systemd:
name: httpd
state: restarted
在上面的示例中,我们为两个task定义了三个tags:
- install_httpd
- conf_httpd
- start_httpd
查看标签
ansible-playbook 1.yml --list-tags
指定某个tag运行
ansible-playbook 1.yml --tags "install_httpd"
一次指定多个tag执行:
ansible-playbook 1.yml --tags "conf_httpd,start_httpd"
排除指定tag的task
ansible-playbook 1.yml --skip-tags "install_httpd" # 除了它其他task都执行
3.3.打标签的方式
1.对一个task打一个标签
2.对多个task打一个标签
3.对一个task打多个标签
1、对一个task打一个标签
- hosts: nginx
- name: Config Nginx Server
copy:
src: /etc/nginx/nginx.conf
dest: /etc/nginx/
notify: restart_nginx
tags: reconf_nginx
2、对多个task打一个标签
- hosts: nginx
- name: Config Nginx Server
copy:
src: /etc/nginx/nginx.conf
dest: /etc/nginx/
notify: restart_nginx
tags: reconf_nginx
- name: Config Nginx wordpress
copy:
src: /project/conf/linux.wp.com.conf
dest: /etc/nginx/conf.d/
notify: reload_nginx
when: (ansible_fqdn == "web01") or (ansible_fqdn == "web02")
tags: reconf_nginx
3、对一个task打多个标签
- hosts: nginx
- name: Config Nginx Server
copy:
src: /etc/nginx/nginx.conf
dest: /etc/nginx/
notify: restart_nginx
# 格式1
tags:
- reconf_nginx
- reconfig_nginx
# 格式2
# tags: ["reconf_nginx","reconfig_nginx"]
# 格式3:
# tags: ["reconf_nginx","reconfig_nginx"]
了解高级用法:https://egonlin.com/?p=9850