Ansible playbook 编程
Ansible playbook 编程详解与各种小案例
主机规划
添加用户账号
说明:
1、 运维人员使用的登录账号;
2、 所有的业务都放在 /app/ 下「yun用户的家目录」,避免业务数据乱放;
3、 该用户也被 ansible 使用,因为几乎所有的生产环境都是禁止 root 远程登录的(因此该 yun 用户也进行了 sudo 提权)。
# 使用一个专门的用户,避免直接使用root用户
# 添加用户、指定家目录并指定用户密码
# sudo提权
# 让其它普通用户可以进入该目录查看信息
useradd -u -d /app yun && echo '' | /usr/bin/passwd --stdin yun
echo "yun ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
chmod /app/
Ansible 配置清单Inventory
之后文章都是如下主机配置清单
[yun@ansi-manager ansible_info]$ pwd
/app/ansible_info
[yun@ansi-manager ansible_info]$ cat hosts_key
# 方式1、主机 + 端口 + 密钥
[manageservers]
172.16.1.180: [proxyservers]
172.16.1.18[:]: # 方式2:别名 + 主机 + 端口 + 密码
[webservers]
web01 ansible_ssh_host=172.16.1.183 ansible_ssh_port=
web02 ansible_ssh_host=172.16.1.184 ansible_ssh_port=
web03 ansible_ssh_host=172.16.1.185 ansible_ssh_port=
条件判断-when
when 判断在 ansible 任务中的使用频率非常高。
例如判断主机是否已经安装指定的软件包;对机器的操作系统进行判断然后再根据不同的方法「yum或apt等」进行软件包安装;根据操作系统的版本判断进行软件包的安装「是安装MySQL还是Mariadb」等。
示例:根据主机名的不同,下载不同的文件
[yun@ansi-manager object04]$ pwd
/app/ansible_info/object04
[yun@ansi-manager object04]$ ll
total
-rw-rw-r-- yun yun Oct : test_when.yml
[yun@ansi-manager object04]$ cat test_when.yml
---
# 根据 hostname 的不同下载不同的图片
# 特殊组 all,对所有机器有效
- hosts: all tasks:
- name: "download picture jvm-01-01.png"
get_url:
url: http://www.zhangblog.com/uploads/jvm/jvm-01-01.png
dest: /tmp/
when: ansible_hostname == "ansi-haproxy01" - name: "download picture jvm-01-02.png"
get_url:
url: http://www.zhangblog.com/uploads/jvm/jvm-01-02.png
dest: /tmp/
when: ansible_hostname == "ansi-haproxy02" - name: "other download picture jvm-01-03.png"
get_url:
url: http://www.zhangblog.com/uploads/jvm/jvm-01-03.png
dest: /tmp/
# 从 facts 中获取的变量,ansible_facts['ansible_hostname'] != "ansi-haproxy01" 错误写法;ansible_hostname != "ansi-haproxy01" 正确写法
#when: (ansible_hostname != "ansi-haproxy01") and (ansible_hostname != "ansi-haproxy02") # 写法一
#或者如下3行 列表之间关系是 (and 与) 等同于上一行
#when:
# - ansible_hostname != "ansi-haproxy01"
# - ansible_hostname != "ansi-haproxy02"
#when: ansible_hostname is not match "ansi-haproxy0*" # 写法二
when: (ansible_hostname is match "ansi-manager") or (ansible_hostname is match "ansi-web*") # 写法三 [yun@ansi-manager object04]$ ansible-playbook -b -i ../hosts_key --syntax-check test_when.yml # 语法检测
[yun@ansi-manager object04]$ ansible-playbook -b -i ../hosts_key -C test_when.yml # 预执行,测试执行
[yun@ansi-manager object04]$ ansible-playbook -b -i ../hosts_key test_when.yml # 执行 PLAY [all] ******************************************************************************************************* TASK [Gathering Facts] *******************************************************************************************
ok: [web01]
ok: [web02]
ok: [web03]
ok: [172.16.1.180]
ok: [172.16.1.181]
ok: [172.16.1.182] TASK [download picture jvm--.png] ****************************************************************************
skipping: [172.16.1.180]
skipping: [web01]
skipping: [web02]
skipping: [web03]
skipping: [172.16.1.182]
changed: [172.16.1.181] TASK [download picture jvm--.png] ****************************************************************************
skipping: [172.16.1.180]
skipping: [web01]
skipping: [web02]
skipping: [web03]
skipping: [172.16.1.181]
changed: [172.16.1.182] TASK [other download picture jvm--.png] **********************************************************************
skipping: [172.16.1.181]
skipping: [172.16.1.182]
changed: [web02]
changed: [web01]
changed: [172.16.1.180]
changed: [web03] PLAY RECAP *******************************************************************************************************
172.16.1.180 : ok= changed= unreachable= failed= skipped= rescued= ignored=
172.16.1.181 : ok= changed= unreachable= failed= skipped= rescued= ignored=
172.16.1.182 : ok= changed= unreachable= failed= skipped= rescued= ignored=
web01 : ok= changed= unreachable= failed= skipped= rescued= ignored=
web02 : ok= changed= unreachable= failed= skipped= rescued= ignored=
web03 : ok= changed= unreachable= failed= skipped= rescued= ignored=
标准循环
注意:
1、循环语法有两种:loop 和 with_。
2、loop 是在ansible 2.5 添加的,with_ 是一直存在的,推荐使用 loop。在未来 with_ 可能被弃用。
简单列表循环
如果我们需要在 playbook 中启动多个服务,或者下载多个文件;按照之前所学的,那么我们需要写多个 task。但这样会使得 playbook 变得臃肿,因此这时我们就需要引进循环了。
示例:一次启动多个服务,下载多个文件
使用 loop 方式【推荐】
[yun@ansi-manager object04]$ pwd
/app/ansible_info/object04
[yun@ansi-manager object04]$ ll
total
-rw-rw-r-- yun yun Aug : test_loop.yml
[yun@ansi-manager object04]$ cat test_loop.yml
---
# 启动多个服务 和下载多个文件
- hosts: proxyservers tasks:
- name: "start httpd, rpcbind, network server"
service:
name: "{{ item }}" # 需要用引号引起来
state: started
loop:
- httpd
- rpcbind
- network - name: "download multiple file"
get_url:
url: "{{ item }}" # 需要用引号引起来
dest: /tmp/
loop:
- http://www.zhangblog.com/uploads/jvm/jvm-01-01.png
- http://www.zhangblog.com/uploads/jvm/jvm-01-02.png
- http://www.zhangblog.com/uploads/jvm/jvm-01-03.png [yun@ansi-manager object04]$ ansible-playbook -b -i ../hosts_key --syntax-check test_loop.yml # 语法检测
[yun@ansi-manager object04]$ ansible-playbook -b -i ../hosts_key -C test_loop.yml # 预执行,测试执行
[yun@ansi-manager object04]$ ansible-playbook -b -i ../hosts_key test_loop.yml # 执行
备注:以上方法可用在 yum 模块中。
使用 with_items 方式
其中 playbook 文件中仅把 loop 变为了 with_items。
[yun@ansi-manager object04]$ pwd
/app/ansible_info/object04
[yun@ansi-manager object04]$ ll
total
-rw-rw-r-- yun yun Aug : test_with_items.yml
[yun@ansi-manager object04]$ cat test_with_items.yml
---
# 启动多个服务 和下载多个文件
- hosts: proxyservers tasks:
- name: "start httpd, rpcbind, network server"
service:
name: "{{ item }}" # 需要用引号引起来
state: started
with_items:
- httpd
- rpcbind
- network - name: "download multiple file"
get_url:
url: "{{ item }}" # 需要用引号引起来
dest: /tmp/
with_items:
- http://www.zhangblog.com/uploads/jvm/jvm-01-01.png
- http://www.zhangblog.com/uploads/jvm/jvm-01-02.png
- http://www.zhangblog.com/uploads/jvm/jvm-01-03.png [yun@ansi-manager object04]$ ansible-playbook -b -i ../hosts_key --syntax-check test_with_items.yml # 语法检测
[yun@ansi-manager object04]$ ansible-playbook -b -i ../hosts_key -C test_with_items.yml # 预执行,测试执行
[yun@ansi-manager object04]$ ansible-playbook -b -i ../hosts_key test_with_items.yml # 执行
如果用在 yum 模块中则会报如下弃用告警,因此该方法不适用于 yum 模块。
遍历哈希列表
如果我们需要创建多个用户并且每个用户都有指定的附加组;或者要创建多个文件,每个文件属主、属组、权限不一样;或者需要拷贝文件,但是每个文件的位置不一样,且属主、属组、权限不一样等等;那之前所学的简单循环就不能满足我们的需求了。这时「哈希列表循环」就闪亮登场了。
示例:
使用 loop 方式【推荐】
[yun@ansi-manager object04]$ pwd
/app/ansible_info/object04
[yun@ansi-manager object04]$ ll
total
drwxrwxr-x yun yun Oct : file
-rw-rw-r-- yun yun Oct : test_loop_hash.yml
[yun@ansi-manager object04]$ cat file/config_test.conf.j2 [yun@ansi-manager object04]$ cat file/yml_test_j2.yml [yun@ansi-manager object04]$ cat test_loop_hash.yml
---
# 使用循环字典创建多个用户,创建多个文件,拷贝多个文件
- hosts: proxyservers tasks:
- name: "Create multiple user"
user:
name: "{{ item.user }}"
groups: "{{ item.groups }}"
loop:
- { user: "testuser1", groups: "root" }
- { user: "testuser2", groups: "root,yun" } - name: "Create multiple file or dir"
file:
path: "{{ item.path }}"
owner: "{{ item.owner }}"
group: "{{ item.group }}"
mode: "{{ item.mode }}"
state: "{{ item.state }}"
loop:
- { path: "/tmp/with_items_testdir", owner: "yun", group: "root", mode: "", state: "directory" }
- { path: "/tmp/with_items_testfile", owner: "bin", group: "bin", mode: "", state: "touch" } - name: "copy multiple file"
copy:
src: "{{ item.src }}"
dest: "{{ item.dest }}"
owner: "{{ item.owner }}"
group: "{{ item.group }}"
loop:
- { src: "./file/config_test.conf.j2", dest: "/tmp/with_items_testdir/", owner: "yun", group: "root" }
- { src: "./file/yml_test_j2.yml", dest: "/tmp/yml_test.yml", owner: "yun", group: "yun" } [yun@ansi-manager object04]$ ansible-playbook -b -i ../hosts_key --syntax-check test_loop_hash.yml # 语法检测
[yun@ansi-manager object04]$ ansible-playbook -b -i ../hosts_key -C test_loop_hash.yml # 预执行,测试执行
[yun@ansi-manager object04]$ ansible-playbook -b -i ../hosts_key test_loop_hash.yml # 执行
使用 with_items 方式
其中 playbook 文件中仅把 loop 变为了 with_items。
[yun@ansi-manager object04]$ pwd
/app/ansible_info/object04
[yun@ansi-manager object04]$ ll
total
drwxrwxr-x yun yun Oct : file
-rw-rw-r-- yun yun Oct : test_with_items_hash.yml
[yun@ansi-manager object04]$ cat file/config_test.conf.j2 [yun@ansi-manager object04]$ cat file/yml_test_j2.yml [yun@ansi-manager object04]$ cat test_with_items_hash.yml
---
# 使用循环字典创建多个用户,创建多个文件,拷贝多个文件
- hosts: proxyservers tasks:
- name: "Create multiple user"
user:
name: "{{ item.user }}"
groups: "{{ item.groups }}"
with_items:
- { user: "testuser1", groups: "root" }
- { user: "testuser2", groups: "root,yun" } - name: "Create multiple file or dir"
file:
path: "{{ item.path }}"
owner: "{{ item.owner }}"
group: "{{ item.group }}"
mode: "{{ item.mode }}"
state: "{{ item.state }}"
with_items:
- { path: "/tmp/with_items_testdir", owner: "yun", group: "root", mode: "", state: "directory" }
- { path: "/tmp/with_items_testfile", owner: "bin", group: "bin", mode: "", state: "touch" } - name: "copy multiple file"
copy:
src: "{{ item.src }}"
dest: "{{ item.dest }}"
owner: "{{ item.owner }}"
group: "{{ item.group }}"
with_items:
- { src: "./file/config_test.conf.j2", dest: "/tmp/with_items_testdir/", owner: "yun", group: "root" }
- { src: "./file/yml_test_j2.yml", dest: "/tmp/yml_test.yml", owner: "yun", group: "yun" } [yun@ansi-manager object04]$ ansible-playbook -b -i ../hosts_key --syntax-check test_with_items_hash.yml # 语法检测
[yun@ansi-manager object04]$ ansible-playbook -b -i ../hosts_key -C test_with_items_hash.yml # 预执行,测试执行
[yun@ansi-manager object04]$ ansible-playbook -b -i ../hosts_key test_with_items_hash.yml # 执行
遍历字典
示例:
使用 loop 方式【推荐】
[yun@ansi-manager object04]$ pwd
/app/ansible_info/object04
[yun@ansi-manager object04]$ ll
total
-rw-rw-r-- yun yun Oct : test_loop_dict.yml
[yun@ansi-manager object04]$ cat test_loop_dict.yml
---
# 打印信息
- hosts: manageservers
vars:
users:
alice:
name: Alice Appleworth
telephone: --
bob:
name: Bob Bananarama
telephone: -- tasks:
- name: "print user info"
debug:
msg: "User {{ item.key }}, userfullname: {{ item.value.name }} ({{ item.value.telephone }})"
# 将字典转换为适合循环的项表 第一种方式推荐
loop: "{{ users|dict2items }}"
#loop: "{{ lookup('dict', users) }}" [yun@ansi-manager object04]$ ansible-playbook -b -i ../hosts_key --syntax-check test_loop_dict.yml # 语法检测
[yun@ansi-manager object04]$ ansible-playbook -b -i ../hosts_key -C test_loop_dict.yml # 预执行,测试执行
[yun@ansi-manager object04]$ ansible-playbook -b -i ../hosts_key test_loop_dict.yml # 执行
使用 with_items 方式
[yun@ansi-manager object04]$ pwd
/app/ansible_info/object04
[yun@ansi-manager object04]$ ll
total
-rw-rw-r-- yun yun Oct : test_with_items_dict.yml
[yun@ansi-manager object04]$ cat test_with_items_dict.yml
---
# 打印信息
- hosts: manageservers
vars:
users:
alice:
name: Alice Appleworth
telephone: --
bob:
name: Bob Bananarama
telephone: -- tasks:
- name: "print user info"
debug:
msg: "User {{ item.key }}, userfullname: {{ item.value.name }} ({{ item.value.telephone }})"
# with_dict 会直接解析字典
with_dict: "{{ users }}" [yun@ansi-manager object04]$ ansible-playbook -b -i ../hosts_key --syntax-check test_with_items_dict.yml # 语法检测
[yun@ansi-manager object04]$ ansible-playbook -b -i ../hosts_key -C test_with_items_dict.yml # 预执行,测试执行
[yun@ansi-manager object04]$ ansible-playbook -b -i ../hosts_key test_with_items_dict.yml # 执行
变量循环-vars
针对yum 安装多个包很有用,其他则会报出警告。
[yun@ansi-manager object04]$ pwd
/app/ansible_info/object04
[yun@ansi-manager object04]$ ll
total
-rw-rw-r-- yun yun Oct : test_cycle_vars.yml
[yun@ansi-manager object04]$ cat test_cycle_vars.yml
---
# 批量包安装
- hosts: proxyservers tasks:
- name: "Install multiple packages"
yum:
name: "{{ multi_package }}"
state: present
vars:
multi_package:
- tree
- nc
- tcpdump [yun@ansi-manager object04]$ ansible-playbook -b -i ../hosts_key --syntax-check test_cycle_vars.yml # 语法检测
[yun@ansi-manager object04]$ ansible-playbook -b -i ../hosts_key -C test_cycle_vars.yml # 预执行,测试执行
[yun@ansi-manager object04]$ ansible-playbook -b -i ../hosts_key test_cycle_vars.yml # 执行
该方法不一定适用于其他模块
触发器-handlers
当我们修改了服务的配置文件时,这时我们需要去重启服务,那么 handlers 就可以派上用场了。
注意事项:
1、无论多少个 task 通知了相同的 handlers,handlers 仅会在所有 tasks 结束后运行一次。
2、只有 task 发生改变了才会通知 handlers,没有改变则不会通知和触发 handlers。
3、不能用 handlers 替代 task 。
[yun@ansi-manager object05]$ pwd
/app/ansible_info/object05
[yun@ansi-manager object05]$ ll
total
drwxrwxr-x yun yun Aug : file
-rw-rw-r-- yun yun Aug : test_handlers.yml
[yun@ansi-manager object05]$ ll file/ # 涉及配置文件
total
-rw-r--r-- yun yun Aug : httpd.conf.j2
[yun@ansi-manager object05]$ vim file/httpd.conf.j2 # 配置文件修改的地方
…………
# Change this to Listen on specific IP addresses as shown below to
# prevent Apache from glomming onto all bound IP addresses.
#
#Listen 12.34.56.78:
###### 端口改为变量
Listen {{ httpd_port }} …………
[yun@ansi-manager object05]$ cat test_handlers.yml # yml 文件
---
# 比如安装配置启动 httpd。当我们修改配置文件,重启 httpd 服务
# 要求:修改配置,重启一个或多个服务
- hosts: proxyservers
# 这里为了演示方便,因此变量直接就写在了该文件中
vars:
- httpd_port: tasks:
- name: "Install httpd"
yum:
name: "{{ packages }}"
state: present
vars:
packages:
- httpd
- httpd-tools - name: "Httpd config"
template:
src: ./file/httpd.conf.j2
dest: /etc/httpd/conf/httpd.conf
# 一个通知
# notify: "Restart httpd server"
# 多个通知
notify:
- "Restart httpd server"
- "Restart crond server" - name: "Start httpd server"
systemd:
name: httpd
state: started
enabled: yes handlers:
- name: "Restart httpd server"
systemd:
name: httpd
state: restarted - name: "Restart crond server"
systemd:
name: crond
state: restarted [yun@ansi-manager object05]$ ansible-playbook -b -i ../hosts_key --syntax-check test_handlers.yml # 语法检测
[yun@ansi-manager object05]$ ansible-playbook -b -i ../hosts_key -C test_handlers.yml # 预执行,测试执行
[yun@ansi-manager object05]$ ansible-playbook -b -i ../hosts_key test_handlers.yml # 执行
任务标签-tags
默认情况下,当我们执行一个 playbook 时,会执行该 playbook 中所有的任务。如果只想执行一个 task 或者部分 task 用于调试或者需求就是执行部分 task。那么可以使用 ansible 的标签(tags)功能给单独 task 或者全部 task 打上标签。之后利用这些标签来指定要运行哪些 playbook 任务,或不运行哪些 playbook 任务。
打标签方式
对一个 task 打一个标签;
对一个 task 打多个标签;
对多个 task 打一个标签
标签如何运用
-t TAGS, --tags=TAGS:执行指定的 tag 标签任务;多个标签使用逗号分开
--skip-tags=SKIP_TAGS:跳过指定标签不执行,执行指定外的 task「标签作用于 task 上,即使该task还有其他标签,这个 task 也不会被执行」;多个标签使用逗号分开
[yun@ansi-manager object05]$ pwd
/app/ansible_info/object05
[yun@ansi-manager object05]$ ll
total
drwxrwxr-x yun yun Oct : file
-rw-rw-r-- yun yun Oct : test_tags.yml
[yun@ansi-manager object05]$ cat test_tags.yml
---
# tags 标签测试
- hosts: proxyservers
# 这里为了演示方便,因此变量直接就写在了该文件中
vars:
- httpd_port: tasks:
- name: "Install httpd"
yum:
name: "{{ packages }}"
state: present
vars:
packages:
- httpd
- httpd-tools
tags:
- httpd_server
- httpd_install - name: "Httpd config"
template:
src: ./file/httpd.conf.j2
dest: /etc/httpd/conf/httpd.conf
notify: "Restart httpd server"
tags:
- httpd_server
- httpd_config - name: "Start httpd server"
systemd:
name: httpd
state: started
enabled: yes
tags:
- httpd_server
- httpd_start - name: "Create dir"
file:
path: /tmp/with_items_testdir
state: directory
tags: create_dir handlers:
- name: "Restart httpd server"
systemd:
name: httpd
state: restarted
playbook 标签查看
[yun@ansi-manager object05]$ ansible-playbook -b -i ../hosts_key --syntax-check test_tags.yml # 语法检测
## 查看 playbook 中的任务和标签
[yun@ansi-manager object05]$ ansible-playbook -b -i ../hosts_key test_tags.yml --list-tasks playbook: test_tags.yml play # (proxyservers): proxyservers TAGS: []
tasks:
Install httpd TAGS: [httpd_install, httpd_server]
Httpd config TAGS: [httpd_config, httpd_server]
Start httpd server TAGS: [httpd_server, httpd_start]
Create dir TAGS: [create_dir]
## 查看 playbook 中的标签
[yun@ansi-manager object05]$ ansible-playbook -b -i ../hosts_key test_tags.yml --list-tags playbook: test_tags.yml play # (proxyservers): proxyservers TAGS: []
TASK TAGS: [create_dir, httpd_config, httpd_install, httpd_server, httpd_start]
playbook 执行
## 单个标签执行
[yun@ansi-manager object05]$ ansible-playbook -b -i ../hosts_key test_tags.yml -t httpd_install
[yun@ansi-manager object05]$ ansible-playbook -b -i ../hosts_key test_tags.yml -t httpd_server
## 多个标签执行
[yun@ansi-manager object05]$ ansible-playbook -b -i ../hosts_key test_tags.yml -t httpd_install,httpd_config,httpd_start
## 跳过哪些标签不执行「标签作用于 task 上,即使该 task 还有其他标签,这个 task 也不会被执行」
[yun@ansi-manager object05]$ ansible-playbook -b -i ../hosts_key test_tags.yml --skip-tags httpd_server
[yun@ansi-manager object05]$ ansible-playbook -b -i ../hosts_key test_tags.yml --skip-tags httpd_install,create_dir
## 执行整个 playbook
[yun@ansi-manager object05]$ ansible-playbook -b -i ../hosts_key test_tags.yml
文件引用/复用-include与import
在实际应用中,是不可能将所有 task 写在一个 playbook 中的,需要进行拆分,方便后期重复使用。这样后面写其他 playbook 的时候,如果有重复的,那么直接引用之前写的即可。
Includes 与 Imports
1、include 和 import 虽然功能相近,但是 ansible 执行引擎对他们的处理却截然不同。
2、所有 import* 语句都会在解析 playbook 时进行预处理。「提前准备好工具」
3、所有 include* 语句都是在执行 playbook 时遇到再处理。「需要什么工具,再拿什么工具」
PS:include 模块:这个模块还将支持一段时间,但在不久的将来可能会弃用「最好不要使用这个模块」。
示例
[yun@ansi-manager object05]$ pwd
/app/ansible_info/object05
[yun@ansi-manager object05]$ ll
total
drwxrwxr-x yun yun Aug : file_yml
-rw-rw-r-- yun yun Aug : test_include.yml
[yun@ansi-manager object05]$ ll file_yml/
total
-rw-rw-r-- yun yun Aug : httpd_config.yml
-rw-rw-r-- yun yun Aug : httpd_install.yml
-rw-rw-r-- yun yun Aug : httpd_restart.yml
-rw-rw-r-- yun yun Aug : httpd_start.yml
## 每个小 yml 文件的具体内容
[yun@ansi-manager object05]$ cat file_yml/httpd_install.yml
- name: "Install httpd"
yum:
name: "{{ packages }}"
state: present
vars:
packages:
- httpd
- httpd-tools [yun@ansi-manager object05]$ cat file_yml/httpd_config.yml
- name: "Httpd config"
template:
src: ./file/httpd.conf.j2
dest: /etc/httpd/conf/httpd.conf
notify: "Restart httpd server" [yun@ansi-manager object05]$ cat file_yml/httpd_start.yml
- name: "Start httpd server"
systemd:
name: httpd
state: started
enabled: yes [yun@ansi-manager object05]$ cat file_yml/httpd_restart.yml
- name: "Restart httpd server"
systemd:
name: httpd
state: restarted ###### 主调用 yml 文件内容 ######
[yun@ansi-manager object05]$ cat test_include.yml
---
# 调用其他 yml 文件
- hosts: proxyservers
# 这里为了演示方便,因此变量直接就写在了该文件中
vars:
- httpd_port: tasks:
- include_tasks: ./file_yml/httpd_install.yml
- include_tasks: ./file_yml/httpd_config.yml
- include_tasks: ./file_yml/httpd_start.yml handlers:
# 使用 import 进行预处理,这样防止 notify 时,在 handlers 找不到对应的信息
- import_tasks: ./file_yml/httpd_restart.yml [yun@ansi-manager object05]$ ansible-playbook -b -i ../hosts_key --syntax-check test_include.yml # 语法检测
[yun@ansi-manager object05]$ ansible-playbook -b -i ../hosts_key -C test_include.yml # 预执行,测试执行
[yun@ansi-manager object05]$ ansible-playbook -b -i ../hosts_key test_include.yml # 执行
忽略错误-ignore_errors
在 playbook 执行过程中,默认情况下如果有错误发生,那么后面的 task 就不执行,并且退出当前的 playbook。
如果我们对某些 task 执行结果不关心,不管执行是否成功,后面的 task 也要继续执行。那就需要通过 ignore_errors 来忽略当前 task 的错误结果,让后面的 task 继续往下执行。
[yun@ansi-manager object05]$ pwd
/app/ansible_info/object05
[yun@ansi-manager object05]$ ll
total
-rw-rw-r-- yun yun Aug : test_ignore_errors.yml
[yun@ansi-manager object05]$ cat test_ignore_errors.yml
---
# ignore_errors 测试
- hosts: proxyservers tasks:
- name: "Install httpd"
yum:
name: "{{ packages }}"
state: present
vars:
packages:
- httpd
- httpd-tools - name: "Shell false"
shell: /bin/false
# 是否忽略该 task 的错误 「打开或关闭注释,对比」
ignore_errors: True - name: "Create dir"
file:
path: /tmp/with_items_testdir
state: directory [yun@ansi-manager object05]$ ansible-playbook -b -i ../hosts_key --syntax-check test_ignore_errors.yml # 语法检测
[yun@ansi-manager object05]$ ansible-playbook -b -i ../hosts_key -C test_ignore_errors.yml # 预执行,测试执行
[yun@ansi-manager object05]$ ansible-playbook -b -i ../hosts_key test_ignore_errors.yml # 执行
默认情况
使用了 ignore_errors 的情况
自定义错误判定条件-failed_when
命令不依赖返回状态码来判定是否执行失败,而是要查看命令返回内容来决定,比如返回内容中包括 command not found 字符串,则判定为失败。
[yun@ansi-manager object05]$ pwd
/app/ansible_info/object05
[yun@ansi-manager object05]$ ll
total
-rw-rw-r-- yun yun Aug : test_custom_error.yml
[yun@ansi-manager object05]$ cat test_custom_error.yml
---
# 自定义错误条件
- hosts: proxyservers tasks:
- name: "this command prints 'command not found' if not find"
shell: "kkk -x" # 测试一
#shell: "/bin/kkk -x" # 测试二
register: shell_result
failed_when: "'command not found' in shell_result['stderr']" - name: "print shell_result info"
debug:
msg: "{{ shell_result['stderr'] }}" [yun@ansi-manager object05]$ ansible-playbook -b -i ../hosts_key --syntax-check test_custom_error.yml # 语法检测
[yun@ansi-manager object05]$ ansible-playbook -b -i ../hosts_key -C test_custom_error.yml # 预执行,测试执行
[yun@ansi-manager object05]$ ansible-playbook -b -i ../hosts_key test_custom_error.yml # 执行
强制调用触发器-force_handlers
通常情况下,当 task 执行失败后,playbook 会终止。任何在此之前已经被 task notify 的 handlers 都不会被执行。
此时,如果你在 playbook 中设置了 force_handlers: yes 参数,则被通知的 handlers 就会被强制执行(有些特殊场景可能会使用到)。
如示例,在一个 playbook 中,如果配置文件的 task 已经被执行成功,并且 notify 了 handlers,之后必须重启服务。那么我们会强制要求:即使后续的 task 执行失败,之前被通知的 handlers 也必须执行。
如果不强制执行就变成了,第一次执行时:配置文件修改成功,但由于之后有 task 执行失败,导致 playbook 终止,后续 handlers 没有被调用,对应服务没有重启;第二次执行时:配置文件没发生改变「因此第一次已经更新了配置文件」,因此不会通知 handlers。最终结果就是配置改变了,但是就是没有重启服务。显然不符合我们的初衷。
[yun@ansi-manager object05]$ pwd
/app/ansible_info/object05
[yun@ansi-manager object05]$ ll
total
drwxrwxr-x yun yun Aug : file
-rw-rw-r-- yun yun Aug : test_error_deal.yml
[yun@ansi-manager object05]$ cat test_error_deal.yml
---
# 即使 task 执行错误,之前已 notify 的 handlers 必须被执行
- hosts: proxyservers
# 这里为了演示方便,因此变量直接就写在了该文件中
vars:
- httpd_port:
# 即使 task 执行错误,之前已 notify 的 handlers 必须被执行
force_handlers: yes tasks:
- name: "Install httpd"
yum:
name: "{{ packages }}"
state: present
vars:
packages:
- httpd
- httpd-tools - name: "Httpd config"
template:
src: ./file/httpd.conf.j2
dest: /etc/httpd/conf/httpd.conf
notify: "Restart httpd server" - name: "Start httpd server"
systemd:
name: httpd
state: started
enabled: yes # /bin/false 返回状态码为1,不为0
- name: "Shell task"
shell: /bin/false - name: "Create dir"
file:
path: /tmp/with_items_testdir
state: directory handlers:
- name: "Restart httpd server"
systemd:
name: httpd
state: restarted [yun@ansi-manager object05]$ ansible-playbook -b -i ../hosts_key --syntax-check test_error_deal.yml # 语法检测
[yun@ansi-manager object05]$ ansible-playbook -b -i ../hosts_key -C test_error_deal.yml # 预执行,测试执行
[yun@ansi-manager object05]$ ansible-playbook -b -i ../hosts_key test_error_deal.yml # 执行
抑制changed状态-changed_when
ansible 会自动判断模块执行状态,command、shell 及其它模块如果修改了远程主机状态则被判定为 changed 状态,不过也可以自己决定达到 changed 状态的条件。
当我们在 playbook 中使用 shell 或者 command 模块时,每次 task 执行状态都是 changed。原因是因为每次我们都去执行获取当前数据,而不是一个固化的状态。
但在实际应用中,我们可能不需要 shell 或者 command 模块执行后的 changed 状态,这时我们就需要通过 changed_when: false 来抑制这个改变。
当然上述的 changed_when: false 可以在任何模块中使用,不局限于 shell 和 command 模块,只是我们常用于这两个模块而已。
[yun@ansi-manager object05]$ pwd
/app/ansible_info/object05
[yun@ansi-manager object05]$ ll
total
-rw-rw-r-- yun yun Aug : test_changed_when.yml
[yun@ansi-manager object05]$ cat test_changed_when.yml
---
# 使用 changed_when: false 抑制 changed 状态
- hosts: proxyservers tasks:
- name: "Shell task"
shell: netstat -lntp | grep 'httpd'
register: check_httpd
# changed_when: false # 任何时候,都不为 changed 状态
#### check_httpd['stdout'] 不包含 httpd 为 true,否则 false
changed_when: "'httpd' not in check_httpd['stdout']" # 结果为 false - name: "Debug output"
debug:
msg: "{{ check_httpd.stdout }}" [yun@ansi-manager object05]$ ansible-playbook -b -i ../hosts_key --syntax-check test_changed_when.yml # 语法检测
[yun@ansi-manager object05]$ ansible-playbook -b -i ../hosts_key -C test_changed_when.yml # 预执行,测试执行
[yun@ansi-manager object05]$ ansible-playbook -b -i ../hosts_key test_changed_when.yml # 执行
完毕!
———END———
如果觉得不错就关注下呗 (-^O^-) !
Ansible playbook 编程的更多相关文章
- Ansible playbook API 开发 调用测试
Ansible是Agentless的轻量级批量配置管理工具,由于出现的比较晚(13年)基于Ansible进行开发的相关文档较少,因此,这里通过一些小的实验,结合现有资料以及源码,探索一下Ansible ...
- ansible playbook实践(四)-如何调试写好的playbook文件
有时,我们写了一个长长,功能很强悍的yaml文件,但是,我们有可能会担心,写的yaml文件是否正确,是否有漏洞危机,毕竟是要修改线上的机器,那么,有可能我们可以从以下几个检查维度来进行,确保在大规模应 ...
- ansible playbook批量改ssh配置文件,远程用户Permission denied
最近手里的数百台服务器需要改/etc/ssh/sshd_config的参数,禁止root直接登陆,也就是说 [root@t0 ~]# cat /etc/ssh/sshd_config | grep R ...
- ansible笔记(11):初识ansible playbook(二)
ansible笔记():初识ansible playbook(二) 有前文作为基础,如下示例是非常容易理解的: --- - hosts: test211 remote_user: root tasks ...
- ansible笔记(10):初识ansible playbook
ansible笔记():初识ansible playbook 假设,我们想要在test70主机上安装nginx并启动,我们可以在ansible主机中执行如下3条命令 ansible test70 -m ...
- Ansible playbook 批量修改服务器密码 先普通后root用户
fsckzy Ansible playbook 批量修改服务器密码 客户的需求:修改所有服务器密码,密码规则为Rfv5%+主机名后3位 背景:服务器有CentOS6.7,SuSE9.10.11,r ...
- 写Ansible playbook添加zabbix被监控的对象
本主题达到的效果是能通过编写Ansible Playbook,创建zabbix主机组,把被监控的对象加入到zabbix监控系统中,同时链接到对象的模板. 1.准备工作 在zabbix服务器上面,我们需 ...
- Ansible playbook基础组件介绍
本节内容: ansible playbook介绍 ansible playbook基础组件 playbook中使用变量 一.ansible playbook介绍 playbook是由一个或多个“pla ...
- ansible playbook基本操作
一.ansible playbook简单使用 相当于是把模块写入到配置文件里面 vim /etc/ansible/test.yml //写入如下内容: --- - hosts: 127.0.0.1 r ...
随机推荐
- ArcGIS Server的安装
1.双击ArcGIS Server安装目录下的Setup.exe. 2.点击“Next”. 3.选择“I accept the license agreement”,点击“Next”. 4.点击“Ch ...
- 不可思议的hexo,五分钟教你免费搭一个高逼格技术博客
引言 作为程序员拥有一个属于自己的个人技术博客,绝对是百利无一害的事,不仅方便出门装b,面试时亮出博客地址也会让面试官对你的好感度倍增.经常能在很多大佬的技术文章的文末,看到这样一句话: " ...
- Java并发编程锁系列之ReentrantLock对象总结
Java并发编程锁系列之ReentrantLock对象总结 在Java并发编程中,根据不同维度来区分锁的话,锁可以分为十五种.ReentranckLock就是其中的多个分类. 本文主要内容:重入锁理解 ...
- 如何测试Linux命令运行时间?
良许在工作中,写过一个 Shell 脚本,这个脚本可以从 4 个 NTP 服务器轮流获取时间,然后将最可靠的时间设置为系统时间. 因为我们对于时间的要求比较高,需要在短时间内就获取到正确的时间.所以我 ...
- 《Three.js 入门指南》3.1.1 - 基本几何形状-立方体(CubeGeometry)
3.1 基本几何形状 立方体(CubeGeometry) 构造函数: THREE.CubeGeometry(width, height, depth, widthSegments, heightSeg ...
- Html 慕课园编程练习10-1
23:10:25 2019-08-14 自己写的这个好丑.... 题目:利用之前我们学过的JavaScript知识,实现选项卡切换的效果. 效果图: (另外 这个动图是怎么插入的 用url就行 复制就 ...
- 以数字资产模型为核心驱动的一站式IoT数据分析实践
[摘要] 一个不会直播的云服务架构师,不是一个好的攻城狮! 在这个全民直播的时代 一个不会直播的云服务架构师 不是一个好的攻城狮 3月23日15:00-15:50,华为云IoT物联网数据分析服务架构师 ...
- layui经典模块化前端UI框架初识
layui产生背景 layui相对于vue来说确实稍有逊色,但是官网提供的入门文档以及完善的框架结构,使的很多人开始用layui来开发前端页面,那么什么人会去使用layui呢? 针对后端开发人员,在对 ...
- easy-mock 本地部署(挤需体验三番钟,里造会干我一样,爱象节款mock)
前言 很多小伙伴问我怎么在自己公司的项目里面添加配置mock,在vue项目里面都知道怎么配置mock,在大型前端项目里面就一脸疑惑了. 我就回答他,你今天会在vue项目里面用,那天换公司是用angul ...
- 29.2 Iterator 迭代器
/* * 集合的遍历方式: * 1.toArray(),可以把集合转换成数组,然后遍历数组即可 * 2.iterator(),可以返回一个迭代器对象,我们可以通过迭代器对象来迭代集合 * * Iter ...