Ansible 包含
##一、什么是 include?
在日常编程中,我们会将通用、公用的代码片段抽离出来,以便于解耦和复用。而 ansible 中也有类似的思想体现,那就是include
、include_vars
、include_tasks
以及 import_tasks
,我们先看下本文大致内容
二、include 关键字
include tasks 任务
通过 include 我们可以对剧本的部分进行抽离,比如,以下两个剧本:
playbook-1
---
- hosts: ecs[0]
gather_facts: no
tasks:
- name: "打印开始信息"
debug:
msg: "【{{ '%Y-%m-%d %H:%M:%S' | strftime }}】脚本开始执行,当前主机:{{ inventory_hostname }}..."
- name: "创建 t3 文件"
file:
path: /tmp/testdir/t3.txt
state: touch
playbook-2
---
- hosts: ecs[0]
gather_facts: no
tasks:
- name: "打印开始信息"
debug:
msg: "【{{ '%Y-%m-%d %H:%M:%S' | strftime }}】脚本开始执行,当前主机:{{ inventory_hostname }}..."
- name: "创建 t4 文件"
file:
path: /tmp/testdir/t4.txt
state: touch
抽离通用的 task
至 tasks/tasks-demo1.yml
---
- name: "打印开始信息"
debug:
msg: "【{{ '%Y-%m-%d %H:%M:%S' | strftime }}】脚本开始执行,当前主机:{{ inventory_hostname }}..."
剧本定义
---
- hosts: ecs[0]
gather_facts: no
tasks:
# 包含引入 task 定义文件
- include: tasks/tasks-demo1.yml
- name: "创建 t3 文件"
file:
path: /tmp/testdir/t3.txt
state: touch
当使用 include 模块引用对应的文件时,文件中的任务会在被引用处执行,就如同写在被引用处一样
执行效果
$ ansible-playbook playbook-include-demo1-0.yml
PLAY [ecs[0]] ******
TASK [打印开始信息] ******
ok: [ecs-1.aliyun.sz] => {
"msg": "【2021-10-11 19:57:33】脚本开始执行,当前主机:ecs-1.aliyun.sz..."
}
TASK [创建 t3 文件] ******
changed: [ecs-1.aliyun.sz]
PLAY RECAP ******
ecs-1.aliyun.sz : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
OK,可以看到总工作执行了两个任务,第一个任务是从 tasks 文件中 include 进来,第二个任务是剧本 tasks 关键字定义的,也就是说 include
关键字本身并不算是一个任务,这点需要注意,后续 include_tasks 时会进行对比说明~
include handlers 回调
include 除了可以用在 tasks 字段,还可以用在 handlers,关于 handler 大致内容
OK,复习完了以后开始编写剧本
handler 定义
---
- name: "create file handler"
debug:
msg: "【{{ '%Y-%m-%d %H:%M:%S' | strftime }}】文件创建完成,当前主机:{{ inventory_hostname }}..."
剧本定义
---
- hosts: ecs[0]
gather_facts: no
tasks:
# 包含引入 task 定义文件
- include: tasks/tasks-demo1.yml
- name: "创建文件"
file:
path: /tmp/testdir/t3.txt
state: touch
# 直接通知 handler
notify: "create file handler"
handlers:
# 包含引入 handler 定义文件
- include: tasks/tasks-demo1-1.yml
执行效果
$ ansible-playbook playbook-include-demo1-1.yml
PLAY [ecs[0]] ******
TASK [打印开始信息] ******
ok: [ecs-1.aliyun.sz] => {
"msg": "【2021-10-10 09:34:56】脚本开始执行,当前主机:ecs-1.aliyun.sz..."
}
TASK [创建文件] ******
changed: [ecs-1.aliyun.sz]
RUNNING HANDLER [create file handler] ******
ok: [ecs-1.aliyun.sz] => {
"msg": "【2021-10-10 09:34:57】文件创建完成,当前主机:ecs-1.aliyun.sz..."
}
PLAY RECAP ******
ecs-1.aliyun.sz : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
include 参数化包含任务
任务定义
---
- name: "变量输出"
debug:
msg: "【{{ '%Y-%m-%d %H:%M:%S' | strftime }}】变量输出,username:{{ username }},gender:{{ gender }}"
剧本定义
---
- hosts: ecs[0]
gather_facts: no
tasks:
# 包含引入 task 定义文件
- include: tasks/tasks-demo1-2.yml
vars:
username: "Da"
gender: "Male"
- name: "创建文件"
file:
path: /tmp/testdir/t3.txt
state: touch
include 给”包含”打tags
之前我们学过 ansible tags,它主要是用来在执行剧本时,跳过或执行包含某个标识的任务,先复习下:
tags 同样可以应用于 include,如下所示:
---
- hosts: ecs[0]
gather_facts: no
tasks:
# 包含引入 task 定义文件
- include: tasks/tasks-demo1.yml
tags: print-start-info
- include: tasks/tasks-demo1-2.yml
tags: print-vars
vars:
username: "Da"
gender: "Male"
- name: "创建文件"
tags: always
file:
path: /tmp/testdir/t3.txt
state: touch
执行时,我们只执行包含 print-var
标签的,由于 创建文件
任务包含 always
标签,所以即使不指明,它还是会被运行的,效果如下
$ ansible-playbook --tags=print-vars playbook-include-demo1-3.yml
PLAY [ecs[0]] ******
TASK [变量输出] ******
ok: [ecs-1.aliyun.sz] => {
"msg": "【2021-10-10 10:03:26】变量输出,username:Da,gender:Male"
}
TASK [创建文件] ******
changed: [ecs-1.aliyun.sz]
PLAY RECAP ******
ecs-1.aliyun.sz : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
跳过指定标签
$ ansible-playbook --skip-tags=print-vars,print-start-info playbook-include-demo1-3.yml
PLAY [ecs[0]] ******
TASK [创建文件] ******
changed: [ecs-1.aliyun.sz]
PLAY RECAP ******
ecs-1.aliyun.sz : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
列出标签
$ ansible-playbook --list-tags playbook-include-demo1-3.yml
playbook: playbook-include-demo1-3.yml
play #1 (ecs[0]): ecs[0] TAGS: []
TASK TAGS: [always, print-start-info, print-vars]
include 条件判断
用来条件判断的 when
关键字,也可以用在 include
中,老规矩先复习下
剧本定义
---
- hosts: ecs[0]
gather_facts: yes
tasks:
# 包含引入 task 定义文件
- include: tasks/tasks-demo1.yml
tags: print-start-info
when: ansible_distribution == "CentOS" and ansible_distribution_major_version == "7"
- name: "创建文件"
tags: always
file:
path: /tmp/testdir/t3.txt
state: touch
执行效果
$ ansible-playbook playbook-include-demo1-4.yml
PLAY [ecs[0]] ******
TASK [Gathering Facts] ******
ok: [ecs-1.aliyun.sz]
TASK [打印开始信息] ******
ok: [ecs-1.aliyun.sz] => {
"msg": "【2021-10-10 10:20:36】脚本开始执行,当前主机:ecs-1.aliyun.sz..."
}
TASK [创建文件] ******
changed: [ecs-1.aliyun.sz]
PLAY RECAP ******
ecs-1.aliyun.sz : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
include 循环
既然都支持了 参数化、标签、判断,那怎么少得了循环呢,复习下
复习完了后,我们先思考下,loop
在此处的发挥的作用是什么呢?
其实不难理解,那就是 “迭代 可执行对象 将参数传递给 include 循环执行” ,这句话可能有点绕,不过看了小例子就明白了
任务定义
---
- name: "Tasks-A"
debug:
msg: "【{{ '%Y-%m-%d %H:%M:%S' | strftime }}】变量输出,item:{{ item }}---Task-A"
- name: "Tasks-B"
debug:
msg: "【{{ '%Y-%m-%d %H:%M:%S' | strftime }}】变量输出,item:{{ item }}---Task-B"
剧本定义
---
- hosts: ecs[0]
gather_facts: no
tasks:
# 包含引入 task 定义文件
- include: tasks/tasks-demo1-5.yml
# 迭代列表 [1, 2] 循环包含 include 默认会将 item 参数传递过去
loop: [1, 2]
执行效果
$ ansible-playbook playbook-include-demo1-5.yml
PLAY [ecs[0]] ******
TASK [include] ******
included: /prodata/scripts/ansibleLearn/tasks/tasks-demo1-5.yml for ecs-1.aliyun.sz
included: /prodata/scripts/ansibleLearn/tasks/tasks-demo1-5.yml for ecs-1.aliyun.sz
# 第一次导入,传入 item 变量 = 1
TASK [Tasks-A] ******
ok: [ecs-1.aliyun.sz] => {
"msg": "【2021-10-10 10:30:38】变量输出,item:1---Task-A"
}
TASK [Tasks-B] ******
ok: [ecs-1.aliyun.sz] => {
"msg": "【2021-10-10 10:30:38】变量输出,item:1---Task-B"
}
# 第二次导入,传入 item 变量 = 2
TASK [Tasks-A] ******
ok: [ecs-1.aliyun.sz] => {
"msg": "【2021-10-10 10:30:38】变量输出,item:2---Task-A"
}
TASK [Tasks-B] ******
ok: [ecs-1.aliyun.sz] => {
"msg": "【2021-10-10 10:30:38】变量输出,item:2---Task-B"
}
PLAY RECAP ******
ecs-1.aliyun.sz : ok=6 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
看到这不禁又产生一个疑惑,loop 将元素通过 item 传递给 include 中的 task,那假如 task 本身也有 loop,出现这种 ”双层循环” 的情况时,task 中的 item 信息到底是什么呢?试试不就知道了嘛~
任务定义
---
- name: "Include-Tasks"
debug:
msg: "【{{ '%Y-%m-%d %H:%M:%S' | strftime }}】变量输出,item:{{ item }}"
loop: [inner-a, inner-b]
剧本定义
---
- hosts: ecs[0]
gather_facts: no
tasks:
# 包含引入 task 定义文件
- include: tasks/tasks-demo1-6.yml
# 迭代列表 [outer-1, outer-2] 循环包含 include 默认会将 item 参数传递过去
loop: [outer-1, outer-2]
执行效果
$ ansible-playbook playbook-include-demo1-6.yml
PLAY [ecs[0]] ******
TASK [include] ******
included: /prodata/scripts/ansibleLearn/tasks/tasks-demo1-6.yml for ecs-1.aliyun.sz
included: /prodata/scripts/ansibleLearn/tasks/tasks-demo1-6.yml for ecs-1.aliyun.sz
TASK [Include-Tasks] ******
[WARNING]: The loop variable 'item' is already in use. You should set the `loop_var` value in the `loop_control` option for the task to something
else to avoid variable collisions and unexpected behavior.
ok: [ecs-1.aliyun.sz] => (item=inner-a) => {
"msg": "【2021-10-10 12:45:03】变量输出,item:inner-a"
}
ok: [ecs-1.aliyun.sz] => (item=inner-b) => {
"msg": "【2021-10-10 12:45:03】变量输出,item:inner-b"
}
TASK [Include-Tasks] ******
[WARNING]: The loop variable 'item' is already in use. You should set the `loop_var` value in the `loop_control` option for the task to something
else to avoid variable collisions and unexpected behavior.
ok: [ecs-1.aliyun.sz] => (item=inner-a) => {
"msg": "【2021-10-10 12:45:03】变量输出,item:inner-a"
}
ok: [ecs-1.aliyun.sz] => (item=inner-b) => {
"msg": "【2021-10-10 12:45:03】变量输出,item:inner-b"
}
PLAY RECAP ******
ecs-1.aliyun.sz : ok=4 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
返回信息中包含一段非常醒目的警告
[WARNING]: The loop variable ‘item’ is already in use. You should set the
loop_var
value in theloop_control
option for the task to something else to avoid variable collisions and unexpected behavior.
提示 item
已经被使用了,建议使用 loop_control
关键字设置 loop_var
变量,以避免变量冲突产生意外的问题
OK,我们处理下剧本和任务
---
- name: "Include-Tasks"
debug:
msg: "【{{ '%Y-%m-%d %H:%M:%S' | strftime }}】变量输出,item:{{outer_item}}-{{ item }}"
loop: [inner-a, inner-b]
剧本定义
---
- hosts: ecs[0]
gather_facts: no
tasks:
# 包含引入 task 定义文件
- include: tasks/tasks-demo1-6.yml
# 迭代列表 [1, 2] 循环包含 include 默认会将 item 参数传递过去
loop: [outer-1, outer-2]
loop_control:
loop_var: outer_item
执行效果
$ ansible-playbook playbook-include-demo1-6.yml
PLAY [ecs[0]] ******
TASK [include] ******
included: /prodata/scripts/ansibleLearn/tasks/tasks-demo1-6.yml for ecs-1.aliyun.sz
included: /prodata/scripts/ansibleLearn/tasks/tasks-demo1-6.yml for ecs-1.aliyun.sz
TASK [Include-Tasks] ******
ok: [ecs-1.aliyun.sz] => (item=inner-a) => {
"msg": "【2021-10-10 12:53:08】变量输出,item:outer-1-inner-a"
}
ok: [ecs-1.aliyun.sz] => (item=inner-b) => {
"msg": "【2021-10-10 12:53:08】变量输出,item:outer-1-inner-b"
}
TASK [Include-Tasks] ******
ok: [ecs-1.aliyun.sz] => (item=inner-a) => {
"msg": "【2021-10-10 12:53:08】变量输出,item:outer-2-inner-a"
}
ok: [ecs-1.aliyun.sz] => (item=inner-b) => {
"msg": "【2021-10-10 12:53:08】变量输出,item:outer-2-inner-b"
}
PLAY RECAP ******
ecs-1.aliyun.sz : ok=4 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
不过,include 关键字在 ansible 2.4 版本标记为 deprecated 状态,并且相关功能也于 2.8 版本后逐个移除,主要原因是 include 的功能太混杂了,什么 tasks、handlers、play,ansible 官方认为 include 的功能需要进一步的细化拆分,到目前为止,include 功能拆分为以下几个关键字:
或许你会有些疑惑,为什么出现两个看起来有些类似的关键字,“include_tasks” 与 “import_tasks” 有什么区别?这个问题涉及到了 动态导入 与 静态导入 ,我们暂时按下不谈,后面会详细讨论二者的区别与如何选择
除此外,还有其他几个相关的用于 包含 & 导入 的关键字:
var_files、include_vars 是我们在 playbook-变量 小节已经了解过的内容,所以不再赘述,其他的关键字我们会在本节或后续的内容中一一说明
三、include_vars 关键字
详见 Ansible Playbook 变量——include_vars
四、include_tasks 关键字
include_tasks 包含任务
了解了 include
的用法,再学习 include_tasks
就很简单了,首先定义一个任务
---
- name: 打印开始信息
debug:
msg: "【{{ '%Y-%m-%d %H:%M:%S' | strftime }}】脚本开始执行,当前主机:{{ inventory_hostname }}..."
然后,在 playbook 中,我们可以在 tasks 字段使用 include_tasks
指令引入文件中的任务列表
---
- hosts: ecs[0]
gather_facts: no
tasks:
# include_tasks 包含引入 task 定义文件
- include_tasks: tasks/tasks-demo1.yml
- name: "创建文件"
file:
path: /tmp/testdir/t3.txt
state: touch
执行效果
$ ansible-playbook playbook-include_tasks-demo1-1.yml
PLAY [ecs[0]] ******
# 第一个任务:include_tasks 包含 tasks-demo1 文件中的 tasks
TASK [include_tasks] ******
included: /prodata/scripts/ansibleLearn/tasks/tasks-demo1.yml for ecs-1.aliyun.sz
# 第二个任务:执行 tasks-demo1 文件中的 “打印开始信息” 任务
TASK [打印开始信息] ******
ok: [ecs-1.aliyun.sz] => {
"msg": "【2021-10-11 19:46:54】脚本开始执行,当前主机:ecs-1.aliyun.sz..."
}
# 第三个任务:执行 playbook 中的 “创建文件” 任务
TASK [创建文件] ******
changed: [ecs-1.aliyun.sz]
PLAY RECAP ******
ecs-1.aliyun.sz : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
喏,可以看到与 include
不同,include_tasks
本身也会被当作一次 “任务” 执行,正是因为 include_tasks
关键字被当作认作 task
所以在 tags
的处理上,两者截然不同,后续在 include_tasks
的 tags 使用上详细说明
include_tasks 回调
上面我们提到了 include_tasks
关键字本身会当作任务执行,当它在 handlers 关键字中使用时也与 include 有所不同,具体如下:
此前我们的使用方式:
tasks:
# 包含引入 task 定义文件
- include: tasks/tasks-demo1.yml
- name: "创建文件"
file:
path: /tmp/testdir/t3.txt
state: touch
# 直接通知文件里某个 handler task
notify: "create file handler"
handlers:
# 包含引入 handler 定义文件
- include: tasks/tasks-demo1-1.yml
换做 include_tasks
关键字看看会发生什么?
---
- hosts: ecs[0]
gather_facts: no
tasks:
- include_tasks: tasks/tasks-demo1.yml
- name: "创建文件"
file:
path: /tmp/testdir/t3.txt
state: touch
notify: "create file handler"
handlers:
- include_tasks: tasks/tasks-demo1-1.yml
执行效果
$ ansible-playbook playbook-include_tasks-demo1-2.yml
PLAY [ecs[0]] ******
TASK [include_tasks] ******
included: /prodata/scripts/ansibleLearn/tasks/tasks-demo1.yml for ecs-1.aliyun.sz
TASK [打印开始信息] ******
ok: [ecs-1.aliyun.sz] => {
"msg": "【2021-10-11 20:23:51】脚本开始执行,当前主机:ecs-1.aliyun.sz..."
}
TASK [创建文件] ******
ERROR! The requested handler 'create file handler' was not found in either the main handlers list nor in the listening handlers
错误的提示信息也比较醒目,既没有 handlers 列表中找到名为 create file handler
回调,也没有在 handlers 列表中找到谁在使用 listen 关键字监听 create file handler
知道错误原因,那处理思路也基本有了
- 一、为 include_tasks task 命名
- 二、在对应的 handler 上设置 listen 监听对应的回调事件
先看第一种处理思路:include_tasks task 命名
剧本定义
---
- hosts: ecs[0]
gather_facts: no
tasks:
- include_tasks: tasks/tasks-demo1.yml
- name: "创建文件"
file:
path: /tmp/testdir/t3.txt
state: touch
# 通知指定 handler task
notify: "create file handler"
handlers:
# 为 include_tasks 这个 task 命名
- name: "create file handler"
include_tasks: tasks/tasks-demo1-1.yml
执行效果
$ ansible-playbook playbook-include_tasks-demo1-2.yml
PLAY [ecs[0]] ******
# 第一个任务:include_tasks 包含 tasks-demo1 文件中的 tasks
TASK [include_tasks] ******
included: /prodata/scripts/ansibleLearn/tasks/tasks-demo1.yml for ecs-1.aliyun.sz
# 第二个任务:执行 tasks-demo1 文件中的 “打印开始信息” 任务
TASK [打印开始信息] ******
ok: [ecs-1.aliyun.sz] => {
"msg": "【2021-10-11 20:30:13】脚本开始执行,当前主机:ecs-1.aliyun.sz..."
}
# 第三个任务:执行 playbook 中的 “创建文件” 任务
TASK [创建文件] ******
changed: [ecs-1.aliyun.sz]
# 运行回调:包含任务文件
RUNNING HANDLER [create file handler] ******
included: /prodata/scripts/ansibleLearn/tasks/tasks-demo1-1.yml for ecs-1.aliyun.sz
# 运行回调:执行 create file handler 回调
RUNNING HANDLER [create file handler] ******
ok: [ecs-1.aliyun.sz] => {
"msg": "【2021-10-11 20:30:14】文件创建完成,当前主机:ecs-1.aliyun.sz..."
}
PLAY RECAP ******
ecs-1.aliyun.sz : ok=5 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
第二个思路:listen 监听对应的回调事件
剧本定义
---
- hosts: ecs[0]
gather_facts: no
tasks:
- include_tasks: tasks/tasks-demo1.yml
- name: "创建文件"
file:
path: /tmp/testdir/t3.txt
state: touch
notify: "create file handler"
handlers:
- include_tasks: tasks/tasks-demo1-1.yml
listen: "create file handler"
执行效果
$ ansible-playbook playbook-include_tasks-demo1-2.yml
PLAY [ecs[0]] ******
# 第一个任务:include_tasks 包含 tasks-demo1 文件中的 tasks
TASK [include_tasks] ******
included: /prodata/scripts/ansibleLearn/tasks/tasks-demo1.yml for ecs-1.aliyun.sz
# 第二个任务:执行 tasks-demo1 文件中的 “打印开始信息” 任务
TASK [打印开始信息] ******
ok: [ecs-1.aliyun.sz] => {
"msg": "【2021-10-11 20:34:40】脚本开始执行,当前主机:ecs-1.aliyun.sz..."
}
# 第三个任务:执行 playbook 中的 “创建文件” 任务
TASK [创建文件] ******
changed: [ecs-1.aliyun.sz]
# 运行回调:包含任务文件
RUNNING HANDLER [include_tasks] ******
included: /prodata/scripts/ansibleLearn/tasks/tasks-demo1-1.yml for ecs-1.aliyun.sz
# 运行回调:执行 create file handler 回调
RUNNING HANDLER [create file handler] ******
ok: [ecs-1.aliyun.sz] => {
"msg": "【2021-10-11 20:34:40】文件创建完成,当前主机:ecs-1.aliyun.sz..."
}
PLAY RECAP ******
ecs-1.aliyun.sz : ok=5 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
为了加强理解,我们看下下面的图:
include 关键字回调使用
include_tasks 关键字回调使用
当我们使用 notify 进行通知,由于使用的是 include_tasks 任务的名称,所以 include_tasks 这个任务包含进来的所有 tasks 都会顺序执行一遍
假如,我们只想执行 handler tasks 文件中某些特定任务可以吗?
可以,这就需要用到 tags
功能了~
include_tassk 参数化任务
我们先过下参数化任务,两者使用起来没区别
剧本定义
---
- hosts: ecs[0]
gather_facts: no
tasks:
# 包含引入 task 定义文件
- include_tasks: tasks/tasks-demo1-2.yml
vars:
username: "Da"
gender: "Male"
- name: "创建文件"
file:
path: /tmp/testdir/t3.txt
state: touch
执行效果
$ ansible-playbook playbook-include_tasks-demo1-3.yml
PLAY [ecs[0]] ******
TASK [include_tasks] ******
included: /prodata/scripts/ansibleLearn/tasks/tasks-demo1-2.yml for ecs-1.aliyun.sz
TASK [变量输出] ******
ok: [ecs-1.aliyun.sz] => {
"msg": "【2021-10-12 15:51:47】变量输出,username:Da,gender:Male"
}
TASK [创建文件] ******
changed: [ecs-1.aliyun.sz]
PLAY RECAP ******
ecs-1.aliyun.sz : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
include_tasks 给”包含”打tags
上面我们在使用回调中遇到了一个问题,那就是如何执行 tasks file 中特定的任务,OK,我们现在看下处理方法
任务定义
---
- name: "Tasks-A"
debug:
msg: "【{{ '%Y-%m-%d %H:%M:%S' | strftime }}】Task-A"
tags: tag-a
- name: "Tasks-B"
debug:
msg: "【{{ '%Y-%m-%d %H:%M:%S' | strftime }}】Task-B"
tags: tag-b
剧本定义
---
- hosts: ecs[0]
gather_facts: no
tasks:
- include_tasks: tasks/tasks-demo1-7.yml
tags: tag1
- name: "创建文件"
file:
path: /tmp/testdir/t3.txt
state: touch
notify: "create file handler"
handlers:
- name: "create file handler"
include_tasks: tasks/tasks-demo1-1.yml
# listen: "create file handler"
执行 task file 中的特定任务
假设我们只想执行剧本中所有任务以及 tasks-demo1-7
中 tags 为 tag-a
的任务,可以这么做
$ ansible-playbook --skip-tags=tag-b playbook-include_tasks-demo1-4.yml
PLAY [ecs[0]] ******
TASK [include_tasks] ******
included: /prodata/scripts/ansibleLearn/tasks/tasks-demo1-7.yml for ecs-1.aliyun.sz
TASK [Tasks-A] ******
ok: [ecs-1.aliyun.sz] => {
"msg": "【2021-10-12 16:02:47】Task-A"
}
TASK [创建文件] ******
changed: [ecs-1.aliyun.sz]
RUNNING HANDLER [create file handler] ******
included: /prodata/scripts/ansibleLearn/tasks/tasks-demo1-1.yml for ecs-1.aliyun.sz
RUNNING HANDLER [create file handler] ******
ok: [ecs-1.aliyun.sz] => {
"msg": "【2021-10-12 16:02:48】文件创建完成,当前主机:ecs-1.aliyun.sz..."
}
RUNNING HANDLER [create file handler2] ******
ok: [ecs-1.aliyun.sz] => {
"msg": "【2021-10-12 16:02:48】文件创建完成,当前主机:ecs-1.aliyun.sz..."
}
PLAY RECAP ******
ecs-1.aliyun.sz : ok=6 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
跳过 tag-b
即可
执行 task file 中的所有任务
假若,我们只想运行 task file 中的所有任务,该怎么做呢?
简单,执行 playbook 时不加 tags 参数不就可以了嘛,OK,确实如此…
$ ansible-playbook playbook-include_tasks-demo1-4.yml
PLAY [ecs[0]] ******
TASK [include_tasks] ******
included: /prodata/scripts/ansibleLearn/tasks/tasks-demo1-7.yml for ecs-1.aliyun.sz
###### 开始
# 执行所有包含进来的 task
TASK [Tasks-A] ******
ok: [ecs-1.aliyun.sz] => {
"msg": "【2021-10-12 16:42:27】Task-A"
}
TASK [Tasks-B] ******
ok: [ecs-1.aliyun.sz] => {
"msg": "【2021-10-12 16:42:27】Task-B"
}
###### 结束
TASK [创建文件] ******
changed: [ecs-1.aliyun.sz]
RUNNING HANDLER [create file handler] ******
included: /prodata/scripts/ansibleLearn/tasks/tasks-demo1-1.yml for ecs-1.aliyun.sz
RUNNING HANDLER [create file handler] ******
ok: [ecs-1.aliyun.sz] => {
"msg": "【2021-10-12 16:42:27】文件创建完成,当前主机:ecs-1.aliyun.sz..."
}
PLAY RECAP ******
ecs-1.aliyun.sz : ok=6 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
可是试想下,如果我们使用 t1
标签,可是效果如何呢?
$ ansible-playbook --tags=tag1 playbook-include_tasks-demo1-4.yml
PLAY [ecs[0]] ******
TASK [include_tasks] ******
included: /prodata/scripts/ansibleLearn/tasks/tasks-demo1-7.yml for ecs-1.aliyun.sz
PLAY RECAP ******
ecs-1.aliyun.sz : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
task-a
、task-b
两个任务并没有执行,这是为什么?
其实仔细想下,其中的原因不难理解,还是因为 include_tasks
本身就是一个任务,我们针对这个 task 设置 tag、使用 tag 的作用只会局限在它本身上,并不会附带执行它所 include 包含进来的 task
所以,这里引入一个参数,apply
,它接收两个参数 tags
、become
后者是用来提升权限的,前者才是重头戏,直接看示例:
---
- hosts: ecs[0]
gather_facts: no
tasks:
- include_tasks:
file: tasks/tasks-demo1-7.yml
apply:
tags:
- tag-a
- tag-b
- name: "创建文件"
file:
path: /tmp/testdir/t3.txt
state: touch
notify: "create file handler"
handlers:
- name: "create file handler"
include_tasks: tasks/tasks-demo1-1.yml
# listen: "create file handler"
我们尝试使用 tasks file 中的 标签进行执行
$ ansible-playbook --tags=tag-a,tag-b playbook-include_tasks-demo1-4.yml
PLAY [ecs[0]] ******
PLAY RECAP ******
还是不行,这是为什么?
再回顾下,这张复习导图
当使用 --tags
参数时,只会执行参数内的 task,这意味着 ansible 在执行时只会寻找包含标签 tag-a
、tag-b
的任务
符合条件的任务有吗?有
包含进来了吗?包含…喔不,包含了,但没有完全包含
include_tasks
本身就是一个任务,假如它不本身没有被执行,那么内两个任务当然是没有包含进来啊,所以自然执行不了啊
OK,大致梳理清楚后,我们给 include_tasks
打上 tag
tasks:
- include_tasks:
file: tasks/tasks-demo1-7.yml
apply:
tags:
- tag-a
- tag-b
tags: include-tag
再显示调用尝试下
$ ansible-playbook --tags=include-tag,tag-a,tag-b playbook-include_tasks-demo1-4.yml
PLAY [ecs[0]] ******
# 第一个任务:包含文件中的任务进来
TASK [include_tasks] ******
included: /prodata/scripts/ansibleLearn/tasks/tasks-demo1-7.yml for ecs-1.aliyun.sz
# 第二个任务:执行 Tasks-A
TASK [Tasks-A] ******
ok: [ecs-1.aliyun.sz] => {
"msg": "【2021-10-12 16:30:58】Task-A"
}
# 第三个任务:执行 Tasks-A
TASK [Tasks-B] ******
ok: [ecs-1.aliyun.sz] => {
"msg": "【2021-10-12 16:30:58】Task-B"
}
PLAY RECAP ******
ecs-1.aliyun.sz : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
OK,达到预期效果,执行 tasks file 中所有任务
到目前,我们拎清了一个概念,如果要执行 tasks file 中的任务,那么一定要保证 include_tasks
本身是被执行的,所以,通常 include_tasks
我们都是设置为 always
的,如下所示:
tasks:
- include_tasks:
file: tasks/tasks-demo1-7.yml
apply:
tags:
- tag-a
- tag-b
tags: always
这样,当我们执行时就不需要显式声明了
$ ansible-playbook --tags=tag-a,tag-b playbook-include_tasks-demo1-4.yml
PLAY [ecs[0]] ******
TASK [include_tasks] ******
included: /prodata/scripts/ansibleLearn/tasks/tasks-demo1-7.yml for ecs-1.aliyun.sz
TASK [Tasks-A] ******
ok: [ecs-1.aliyun.sz] => {
"msg": "【2021-10-12 16:34:56】Task-A"
}
TASK [Tasks-B] ******
ok: [ecs-1.aliyun.sz] => {
"msg": "【2021-10-12 16:34:56】Task-B"
}
PLAY RECAP ******
ecs-1.aliyun.sz : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
些许迷思
1. –tag 执行所有包含进来的任务
当我试着使用 --tag=
执行包含特定 tag 的任务时,我发现其他的任务也会跟着执行,示例如下:
任务定义
---
- name: "Tasks-A"
debug:
msg: "【{{ '%Y-%m-%d %H:%M:%S' | strftime }}】Task-A"
tags: tag-a
- name: "Tasks-B"
debug:
msg: "【{{ '%Y-%m-%d %H:%M:%S' | strftime }}】Task-B"
tags: tag-b
剧本定义
---
- hosts: ecs[0]
gather_facts: no
tasks:
- include_tasks:
file: tasks/tasks-demo1-7.yml
apply:
tags:
- tag-a
- tag-b
tags: always
- name: "创建文件"
file:
path: /tmp/testdir/t3.txt
state: touch
notify: "create file handler"
handlers:
- name: "create file handler"
include_tasks: tasks/tasks-demo1-1.yml
# listen: "create file handler"
执行效果
$ ansible-playbook --tags=tag-a playbook-include_tasks-demo1-4.yml
PLAY [ecs[0]] ******
# 任务一
TASK [include_tasks] ******
included: /prodata/scripts/ansibleLearn/tasks/tasks-demo1-7.yml for ecs-1.aliyun.sz
# 任务二
TASK [Tasks-A] ******
ok: [ecs-1.aliyun.sz] => {
"msg": "【2021-10-12 16:52:58】Task-A"
}
# 任务三
TASK [Tasks-B] ******
ok: [ecs-1.aliyun.sz] => {
"msg": "【2021-10-12 16:52:58】Task-B"
}
PLAY RECAP ******
ecs-1.aliyun.sz : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
从执行返回上看,一共执行了三个任务,前两个任务都是如何预期的,include_tasks
标签为 always
所以没的说,Tasks-A
标签为 tag-a
也没的说,可为啥 Tasks-B
也跟着执行了啊?
奇了怪了,难道是因为 apply.tags
参数写了 tag-a、tag-b
吗?那我修改下
- include_tasks:
file: tasks/tasks-demo1-7.yml
apply:
tags:
- tag-a
tags: always
再尝试执行 --tags=tag-a
$ ansible-playbook --tags=tag-a playbook-include_tasks-demo1-4.yml
PLAY [ecs[0]] ******
TASK [include_tasks] ******
included: /prodata/scripts/ansibleLearn/tasks/tasks-demo1-7.yml for ecs-1.aliyun.sz
TASK [Tasks-A] ******
ok: [ecs-1.aliyun.sz] => {
"msg": "【2021-10-12 16:55:50】Task-A"
}
TASK [Tasks-B] ******
ok: [ecs-1.aliyun.sz] => {
"msg": "【2021-10-12 16:55:50】Task-B"
}
PLAY RECAP ******
ecs-1.aliyun.sz : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
效果依旧~ 奇了怪了
更神奇的,假如我此时执行 --tags=tag-b
居然是成功的!!!
$ ansible-playbook --tags=tag-b playbook-include_tasks-demo1-4.yml
PLAY [ecs[0]] ******
TASK [include_tasks] ******
included: /prodata/scripts/ansibleLearn/tasks/tasks-demo1-7.yml for ecs-1.aliyun.sz
TASK [Tasks-B] ******
ok: [ecs-1.aliyun.sz] => {
"msg": "【2021-10-12 17:05:07】Task-B"
}
PLAY RECAP ******
ecs-1.aliyun.sz : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
这里做一个小梳理:
- 当 apply.tags: [tag-a, tag-b],执行
--tags=tag-a
所有包含任务都执行 - 当 apply.tags: [tag-a] ,执行
--tags=tag-a
所有包含任务都执行 - 当 apply.tags: [tag-a] ,执行
--tags=tag-b
只有Tasks-B
任务都执行
2. –skip-tags 跳过所有包含进来的任务
剧本定义
---
- hosts: ecs[0]
gather_facts: no
tasks:
- include_tasks:
file: tasks/tasks-demo1-7.yml
apply:
tags:
- tag-a
- tag-b
tags: always
- name: "创建文件"
file:
path: /tmp/testdir/t3.txt
state: touch
notify: "create file handler"
handlers:
- name: "create file handler"
include_tasks: tasks/tasks-demo1-1.yml
# listen: "create file handler"
执行 --skip-tags=tag-a
$ ansible-playbook --skip-tags=tag-a playbook-include_tasks-demo1-4.yml
PLAY [ecs[0]] ******
TASK [include_tasks] ******
included: /prodata/scripts/ansibleLearn/tasks/tasks-demo1-7.yml for ecs-1.aliyun.sz
TASK [创建文件] ******
changed: [ecs-1.aliyun.sz]
RUNNING HANDLER [create file handler] ******
included: /prodata/scripts/ansibleLearn/tasks/tasks-demo1-1.yml for ecs-1.aliyun.sz
RUNNING HANDLER [create file handler] ******
ok: [ecs-1.aliyun.sz] => {
"msg": "【2021-10-12 16:58:47】文件创建完成,当前主机:ecs-1.aliyun.sz..."
}
PLAY RECAP ******
ecs-1.aliyun.sz : ok=4 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
除非我修改 apply.tags
参数,取消掉 tag-a
标签
- include_tasks:
file: tasks/tasks-demo1-7.yml
apply:
tags:
- tag-b
tags: always
执行 --skip-tags=tag-a
$ ansible-playbook --skip-tags=tag-a playbook-include_tasks-demo1-4.yml
PLAY [ecs[0]] ******
TASK [include_tasks] ******
included: /prodata/scripts/ansibleLearn/tasks/tasks-demo1-7.yml for ecs-1.aliyun.sz
TASK [Tasks-B] ******
ok: [ecs-1.aliyun.sz] => {
"msg": "【2021-10-12 17:02:06】Task-B"
}
TASK [创建文件] ******
changed: [ecs-1.aliyun.sz]
RUNNING HANDLER [create file handler] ******
included: /prodata/scripts/ansibleLearn/tasks/tasks-demo1-1.yml for ecs-1.aliyun.sz
RUNNING HANDLER [create file handler] ******
ok: [ecs-1.aliyun.sz] => {
"msg": "【2021-10-12 17:02:06】文件创建完成,当前主机:ecs-1.aliyun.sz..."
}
PLAY RECAP ******
ecs-1.aliyun.sz : ok=5 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
这里做一个小梳理:
- 当 apply.tags: [tag-a, tag-b],执行
--skip-tags=tag-a
所有包含任务全都不执行 - 当 apply.tags: [tag-b] ,执行
--skip-tags=tag-a
Tasks-A 不执行
记录下当前的版本
$ ansible --version
ansible 2.9.25
config file = /etc/ansible/ansible.cfg
configured module search path = [u'/root/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
ansible python module location = /usr/lib/python2.7/site-packages/ansible
executable location = /usr/bin/ansible
python version = 2.7.5 (default, Nov 16 2020, 22:23:17) [GCC 4.8.5 20150623 (Red Hat 4.8.5-44)]
目前的处理方法
不知道你是否绕晕了,反正我懵了好一阵,在一头雾水中我摸索出了另一种玩法,空列表 []
,示例如下:
剧本定义
---
- hosts: ecs[0]
gather_facts: no
tasks:
- include_tasks:
file: tasks/tasks-demo1-7.yml
apply:
tags: []
tags: always
- name: "创建文件"
file:
path: /tmp/testdir/t3.txt
state: touch
notify: "create file handler"
handlers:
- name: "create file handler"
include_tasks: tasks/tasks-demo1-1.yml
# listen: "create file handler"
执行 任务文件中包含特定标签的的任务(单个)
$ ansible-playbook --tags=tag-a playbook-include_tasks-demo1-4.yml
PLAY [ecs[0]] ******
TASK [include_tasks] ******
included: /prodata/scripts/ansibleLearn/tasks/tasks-demo1-7.yml for ecs-1.aliyun.sz
TASK [Tasks-A] ******
ok: [ecs-1.aliyun.sz] => {
"msg": "【2021-10-12 17:14:54】Task-A"
}
PLAY RECAP ******
ecs-1.aliyun.sz : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
执行 任务文件中包含特定标签的的任务(多个)
$ ansible-playbook --tags=tag-a,tag-b playbook-include_tasks-demo1-4.yml
PLAY [ecs[0]] ******
TASK [include_tasks] ******
included: /prodata/scripts/ansibleLearn/tasks/tasks-demo1-7.yml for ecs-1.aliyun.sz
TASK [Tasks-A] ******
ok: [ecs-1.aliyun.sz] => {
"msg": "【2021-10-12 17:15:03】Task-A"
}
TASK [Tasks-B] ******
ok: [ecs-1.aliyun.sz] => {
"msg": "【2021-10-12 17:15:03】Task-B"
}
PLAY RECAP ******
ecs-1.aliyun.sz : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
跳过 任务文件中包含特定标签的的任务(单个)
$ ansible-playbook --skip-tags=tag-a playbook-include_tasks-demo1-4.yml
PLAY [ecs[0]] ******
TASK [include_tasks] ******
included: /prodata/scripts/ansibleLearn/tasks/tasks-demo1-7.yml for ecs-1.aliyun.sz
TASK [Tasks-B] ******
ok: [ecs-1.aliyun.sz] => {
"msg": "【2021-10-12 17:18:50】Task-B"
}
TASK [创建文件] ******
changed: [ecs-1.aliyun.sz]
RUNNING HANDLER [create file handler] ******
included: /prodata/scripts/ansibleLearn/tasks/tasks-demo1-1.yml for ecs-1.aliyun.sz
RUNNING HANDLER [create file handler] ******
ok: [ecs-1.aliyun.sz] => {
"msg": "【2021-10-12 17:18:50】文件创建完成,当前主机:ecs-1.aliyun.sz..."
}
PLAY RECAP ******
ecs-1.aliyun.sz : ok=5 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
跳过 任务文件中包含特定标签的的任务(多个)
$ ansible-playbook --skip-tags=tag-a,tag-b playbook-include_tasks-demo1-4.yml
PLAY [ecs[0]] ******
TASK [include_tasks] ******
included: /prodata/scripts/ansibleLearn/tasks/tasks-demo1-7.yml for ecs-1.aliyun.sz
TASK [创建文件] ******
changed: [ecs-1.aliyun.sz]
RUNNING HANDLER [create file handler] ******
included: /prodata/scripts/ansibleLearn/tasks/tasks-demo1-1.yml for ecs-1.aliyun.sz
RUNNING HANDLER [create file handler] ******
ok: [ecs-1.aliyun.sz] => {
"msg": "【2021-10-12 17:19:12】文件创建完成,当前主机:ecs-1.aliyun.sz..."
}
PLAY RECAP ******
ecs-1.aliyun.sz : ok=4 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
随着我进一步的尝试与删减,最后与上述效果等同的剧本定义如下:
---
- hosts: ecs[0]
gather_facts: no
tasks:
- include_tasks: tasks/tasks-demo1-7.yml
tags: always
- name: "创建文件"
file:
path: /tmp/testdir/t3.txt
state: touch
notify: "create file handler"
handlers:
- name: "create file handler"
include_tasks: tasks/tasks-demo1-1.yml
# listen: "create file handler"
是的,你没看错,一切都回去了,笑哭…也是醉了
真是摸不透 apply.tags
,还是暂时敬而远之吧~
include_tasks 条件判断
与 include
没啥不同的
剧本定义
---
- hosts: ecs[0]
gather_facts: yes
tasks:
# 包含引入 task 定义文件
- include_tasks: tasks/tasks-demo1.yml
tags: print-start-info
when: ansible_distribution == "CentOS" and ansible_distribution_major_version == "7"
- name: "创建文件"
tags: always
file:
path: /tmp/testdir/t3.txt
state: touch
执行效果
$ ansible-playbook playbook-include_tasks-demo1-5.yml
PLAY [ecs[0]] ******
TASK [Gathering Facts] ******
ok: [ecs-1.aliyun.sz]
TASK [include_tasks] ******
included: /prodata/scripts/ansibleLearn/tasks/tasks-demo1.yml for ecs-1.aliyun.sz
TASK [打印开始信息] ******
ok: [ecs-1.aliyun.sz] => {
"msg": "【2021-10-12 17:41:59】脚本开始执行,当前主机:ecs-1.aliyun.sz..."
}
TASK [创建文件] ******
changed: [ecs-1.aliyun.sz]
PLAY RECAP ******
ecs-1.aliyun.sz : ok=4 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
include_tasks 循环
同样与 include
没啥区别
剧本定义
---
- hosts: ecs[0]
gather_facts: no
tasks:
# 包含引入 task 定义文件
- include_tasks: tasks/tasks-demo1-6.yml
# 迭代列表 [1, 2] 循环包含 include_tasks 默认会将 item 参数传递过去
loop: [outer-1, outer-2]
loop_control:
loop_var: outer_item
执行效果
$ ansible-playbook playbook-include_tasks-demo1-6.yml
PLAY [ecs[0]] ******
TASK [include_tasks] ******
included: /prodata/scripts/ansibleLearn/tasks/tasks-demo1-6.yml for ecs-1.aliyun.sz
included: /prodata/scripts/ansibleLearn/tasks/tasks-demo1-6.yml for ecs-1.aliyun.sz
TASK [Include-Tasks] ******
ok: [ecs-1.aliyun.sz] => (item=inner-a) => {
"msg": "【2021-10-12 17:44:10】变量输出,item:outer-1-inner-a"
}
ok: [ecs-1.aliyun.sz] => (item=inner-b) => {
"msg": "【2021-10-12 17:44:10】变量输出,item:outer-1-inner-b"
}
TASK [Include-Tasks] ******
ok: [ecs-1.aliyun.sz] => (item=inner-a) => {
"msg": "【2021-10-12 17:44:10】变量输出,item:outer-2-inner-a"
}
ok: [ecs-1.aliyun.sz] => (item=inner-b) => {
"msg": "【2021-10-12 17:44:10】变量输出,item:outer-2-inner-b"
}
PLAY RECAP ******
ecs-1.aliyun.sz : ok=4 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
五、import_tasks 关键字
前面我们看过了 include_tasks
,现在我们看下另一个用来 包含(导入) tasks 的 关键字 import_tasks
import_tasks 包含任务
剧本定义
---
- hosts: ecs[0]
gather_facts: no
tasks:
- import_tasks: tasks/tasks-demo1-7.yml
- debug:
msg: "Done."
执行效果
$ ansible-playbook playbook-import_tasks-demo1-1.yml
PLAY [ecs[0]] ******
TASK [Tasks-A] ******
ok: [ecs-1.aliyun.sz] => {
"msg": "【2021-10-12 17:40:04】Task-A"
}
TASK [Tasks-B] ******
ok: [ecs-1.aliyun.sz] => {
"msg": "【2021-10-12 17:40:04】Task-B"
}
TASK [debug] ******
ok: [ecs-1.aliyun.sz] => {
"msg": "Done"
}
PLAY RECAP ******
ecs-1.aliyun.sz : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
OK,可以看到, import_tasks
关键字本身并没有产生 tasks,这一点与 include_tasks
截然不同!
import_tasks handlers 回调
import_tasks
与 includ_tasks
一样,当使用 notify 通知时,要么有同样名称的 handler,要么有 handler 监听特定名称的事件
剧本定义
---
- hosts: ecs[0]
gather_facts: no
tasks:
- import_tasks: tasks/tasks-demo1.yml
- name: "创建文件"
file:
path: /tmp/testdir/t3.txt
state: touch
notify: "create file handler"
handlers:
- name: "create file handler"
include_tasks: tasks/tasks-demo1-1.yml
# listen: "create file handler"
执行效果
$ ansible-playbook playbook-import_tasks-demo1-2.yml
PLAY [ecs[0]] ******
TASK [打印开始信息] ******
ok: [ecs-1.aliyun.sz] => {
"msg": "【2021-10-12 17:46:53】脚本开始执行,当前主机:ecs-1.aliyun.sz..."
}
TASK [创建文件] ******
changed: [ecs-1.aliyun.sz]
RUNNING HANDLER [include_tasks] ******
included: /prodata/scripts/ansibleLearn/tasks/tasks-demo1-1.yml for ecs-1.aliyun.sz
RUNNING HANDLER [create file handler] ******
ok: [ecs-1.aliyun.sz] => {
"msg": "【2021-10-12 17:46:53】文件创建完成,当前主机:ecs-1.aliyun.sz..."
}
PLAY RECAP ******
ecs-1.aliyun.sz : ok=4 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
import_tasks 参数化任务
与 include_tasks 使用方式向相同
剧本定义
---
- hosts: ecs[0]
gather_facts: no
tasks:
# 包含引入 task 定义文件
- import_tasks: tasks/tasks-demo1-2.yml
vars:
username: "Da"
gender: "Male"
- name: "创建文件"
file:
path: /tmp/testdir/t3.txt
state: touch
执行效果
$ ansible-playbook playbook-import_tasks-demo1-3.yml
PLAY [ecs[0]] ******
TASK [变量输出] ******
ok: [ecs-1.aliyun.sz] => {
"msg": "【2021-10-12 17:51:35】变量输出,username:Da,gender:Male"
}
TASK [创建文件] ******
changed: [ecs-1.aliyun.sz]
PLAY RECAP ******
ecs-1.aliyun.sz : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
import_tasks 给”包含”打tags
它与 include_tasks 不同,但与 include 是相同的,如下所示:
---
- hosts: ecs[0]
gather_facts: no
tasks:
# include: tasks/tasks-demo1-7.yml
# include_tasks: tasks/tasks-demo1-7.yml
- import_tasks: tasks/tasks-demo1-7.yml
- debug:
msg: "Done."
首先,假设我们什么标签参数都不加,三个关键字的效果是相同的,唯一的区别就是 include_tasks
会产生一次 task,包含进来的任务都会顺序执行
include
TASK [Tasks-A] ****** ok: [ecs-1.aliyun.sz] => { "msg": "【2021-10-12 18:01:51】Task-A" } TASK [Tasks-B] ****** ok: [ecs-1.aliyun.sz] => { "msg": "【2021-10-12 18:01:51】Task-B" } TASK [debug] ****** ok: [ecs-1.aliyun.sz] => { "msg": "Done." }
include_tasks
TASK [include_tasks] ****** included: /prodata/scripts/ansibleLearn/tasks/tasks-demo1-7.yml for ecs-1.aliyun.sz TASK [Tasks-A] ****** ok: [ecs-1.aliyun.sz] => { "msg": "【2021-10-12 18:03:24】Task-A" } TASK [Tasks-B] ****** ok: [ecs-1.aliyun.sz] => { "msg": "【2021-10-12 18:03:24】Task-B" } TASK [debug] ****** ok: [ecs-1.aliyun.sz] => { "msg": "Done." }
import_tasks
TASK [Tasks-A] ****** ok: [ecs-1.aliyun.sz] => { "msg": "【2021-10-12 18:03:46】Task-A" } TASK [Tasks-B] ****** ok: [ecs-1.aliyun.sz] => { "msg": "【2021-10-12 18:03:46】Task-B" } TASK [debug] ****** ok: [ecs-1.aliyun.sz] => { "msg": "Done." }
OK,假如我们执行指定包含进来的任务:
include
$ ansible-playbook --tags=tag-a playbook-import_tasks-demo1-4.yml PLAY [ecs[0]] ****** TASK [Tasks-A] ****** ok: [ecs-1.aliyun.sz] => { "msg": "【2021-10-12 18:06:18】Task-A" } PLAY RECAP ****** ecs-1.aliyun.sz : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
include_tasks
$ ansible-playbook --tags=tag-a playbook-import_tasks-demo1-4.yml PLAY [ecs[0]] ****** PLAY RECAP ******
import_tasks
$ ansible-playbook --tags=tag-a playbook-import_tasks-demo1-4.yml PLAY [ecs[0]] ****** TASK [Tasks-A] ****** ok: [ecs-1.aliyun.sz] => { "msg": "【2021-10-12 18:07:43】Task-A" } PLAY RECAP ****** ecs-1.aliyun.sz : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
可以看到
include
与import_tasks
是相同的,而include_tasks
因其本身并未被执行,所有没有任何任务包含进来,从而无任务执行
跳过指定包含进来的任务:
include
$ ansible-playbook --skip-tags=tag-a playbook-import_tasks-demo1-4.yml PLAY [ecs[0]] ****** TASK [Tasks-B] ****** ok: [ecs-1.aliyun.sz] => { "msg": "【2021-10-12 18:11:00】Task-B" } TASK [debug] ****** ok: [ecs-1.aliyun.sz] => { "msg": "Done." } PLAY RECAP ****** ecs-1.aliyun.sz : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
include_tasks
$ ansible-playbook --skip-tags=tag-a playbook-import_tasks-demo1-4.yml PLAY [ecs[0]] ****** TASK [include_tasks] ****** included: /prodata/scripts/ansibleLearn/tasks/tasks-demo1-7.yml for ecs-1.aliyun.sz TASK [Tasks-B] ****** ok: [ecs-1.aliyun.sz] => { "msg": "【2021-10-12 18:11:18】Task-B" } TASK [debug] ****** ok: [ecs-1.aliyun.sz] => { "msg": "Done." } PLAY RECAP ****** ecs-1.aliyun.sz : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
import_tasks
$ ansible-playbook --skip-tags=tag-a playbook-import_tasks-demo1-4.yml PLAY [ecs[0]] ****** TASK [Tasks-B] ****** ok: [ecs-1.aliyun.sz] => { "msg": "【2021-10-12 18:11:32】Task-B" } TASK [debug] ****** ok: [ecs-1.aliyun.sz] => { "msg": "Done." } PLAY RECAP ****** ecs-1.aliyun.sz : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
三者效果基本也都相同,唯一差别还是
include_tasks
产生了一次 tasks 执行
import_tasks 条件判断
三者都没啥区别
剧本定义
---
- hosts: ecs[0]
gather_facts: yes
tasks:
# 包含引入 task 定义文件
- import_tasks: tasks/tasks-demo1.yml
tags: print-start-info
when: ansible_distribution == "CentOS" and ansible_distribution_major_version == "7"
- name: "创建文件"
tags: always
file:
path: /tmp/testdir/t3.txt
state: touch
执行效果
$ ansible-playbook playbook-import_tasks-demo1-5.yml
PLAY [ecs[0]] ******
TASK [Gathering Facts] ******
ok: [ecs-1.aliyun.sz]
TASK [打印开始信息] ******
ok: [ecs-1.aliyun.sz] => {
"msg": "【2021-10-12 18:15:02】脚本开始执行,当前主机:ecs-1.aliyun.sz..."
}
TASK [创建文件] ******
changed: [ecs-1.aliyun.sz]
PLAY RECAP ******
ecs-1.aliyun.sz : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
import_tasks 循环
import_tasks 不支持 loop
剧本定义
---
- hosts: ecs[0]
gather_facts: no
tasks:
# 包含引入 task 定义文件
- import_tasks: tasks/tasks-demo1-6.yml
# 迭代列表 [1, 2] 循环包含 include 默认会将 item 参数传递过去
loop: [outer-1, outer-2]
loop_control:
loop_var: outer_item
执行效果
$ ansible-playbook playbook-import_tasks-demo1-6.yml
ERROR! You cannot use loops on 'import_tasks' statements. You should use 'include_tasks' instead.
The error appears to be in '/prodata/scripts/ansibleLearn/playbook-import_tasks-demo1-6.yml': line 6, column 7, but may
be elsewhere in the file depending on the exact syntax problem.
The offending line appears to be:
# 包含引入 task 定义文件
- import_tasks: tasks/tasks-demo1-6.yml
^ here
不过,import_tasks 包含进来的 task 本身是可以执行 loop 的,如下所示:
任务定义
---
- name: "Include-Tasks"
debug:
msg: "【{{ '%Y-%m-%d %H:%M:%S' | strftime }}】变量输出,item:{{outer_item | default('')}}-{{ item }}"
loop: [inner-a, inner-b]
剧本定义
---
- hosts: ecs[0]
gather_facts: no
tasks:
# 包含引入 task 定义文件
- import_tasks: tasks/tasks-demo1-6.yml
执行效果
$ ansible-playbook playbook-import_tasks-demo1-6.yml
PLAY [ecs[0]] ******
TASK [Include-Tasks] ******
ok: [ecs-1.aliyun.sz] => (item=inner-a) => {
"msg": "【2021-10-12 18:20:24】变量输出,item:inner-a"
}
ok: [ecs-1.aliyun.sz] => (item=inner-b) => {
"msg": "【2021-10-12 18:20:24】变量输出,item:inner-b"
}
PLAY RECAP ******
ecs-1.aliyun.sz : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
六、var_files 关键字
详见 Ansible Playbook 变量——var_files
七、import_playbook 关键字
之前 include 关键字也可以,但是,自 2.8 版本以后,这部分功能剥离到 import_playbook
关键字上来,具体使用如下:
剧本定义 playbook-import_playbook-demo1-0.yml
---
- name: "play-1"
hosts: ecs[0]
gather_facts: no
tasks:
- debug:
msg: "我是 play-1,等下我会包含 play-2 进来..."
- import_playbook: playbook-import_playbook-demo1-1.yml
剧本定义 playbook-import_playbook-demo1-1.yml
---
- name: "play-2"
hosts: ecs[0]
gather_facts: no
tasks:
- debug:
msg: "我是 play-2,我被人包含过去了..."
执行效果
$ ansible-playbook playbook-import_playbook-demo1-0.yml
PLAY [play-1] ******
TASK [debug] ******
ok: [ecs-1.aliyun.sz] => {
"msg": "我是 play-1,等下我会包含 play-2 进来..."
}
PLAY [play-2] ******
TASK [debug] ******
ok: [ecs-1.aliyun.sz] => {
"msg": "我是 play-2,我被人包含过去了..."
}
PLAY RECAP ******
ecs-1.aliyun.sz : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
八、include_role
从 ansible 2.4 开始支持通过 include_role
、import_role
两种方式将 Role 角色 内联到其他任务中,我们接下来分别演示下
Role 示例来自于笔记 Ansible Role,具体详情见这里
首先,修改 ansible 配置,设置 role 搜索目录
$ vim /etc/ansible/ansible.cfg
#roles_path = /etc/ansible/roles
roles_path = /etc/ansible/roles
拷贝 Role 到对应目录中
$ tree /etc/ansible/roles
/etc/ansible/roles
└── test-role
├── defaults
│ └── main.yml
├── files
│ ├── index.html
│ └── nginx.conf
├── filter_plugins
│ ├── my_filters.py
│ └── my_filters.pyc
├── group_vars
│ └── all
├── handlers
│ └── main.yml
├── host_vars
│ └── ecs-1.aliyun.sz
├── library
│ └── docker_sh
├── meta
│ ├── __init__.py
│ └── main.yml
├── tasks
│ └── main.yml
├── templates
│ └── test.j2
└── vars
└── main.yml
12 directories, 14 files
模版定义
---
- hosts: ecs[0]
remote_user: root
tasks:
- name: "include_role 引用 Role"
debug:
msg: "通过 include_role 指令引用 Role 角色"
- include_role:
name: test-role
执行命令
$ ansible-playbook playbook-tasks-link-role.yml
PLAY [ecs[0]] ******
TASK [Gathering Facts] ******
ok: [ecs-1.aliyun.sz]
TASK [include_role 引用 Role] ******
ok: [ecs-1.aliyun.sz] => {
"msg": "通过 include_role 指令引用 Role 角色"
}
TASK [include_role : test-role] ******
TASK [test-role : debug] ******
ok: [ecs-1.aliyun.sz] => {
"msg": "hello, Yo!"
}
TASK [test-role : generate config] ******
ok: [ecs-1.aliyun.sz]
TASK [test-role : Copy HTML] ******
ok: [ecs-1.aliyun.sz]
TASK [test-role : Run Container] ******
ok: [ecs-1.aliyun.sz]
TASK [test-role : Custom filter demo1] ******
ok: [ecs-1.aliyun.sz] => {
"msg": "Da | a_filter"
}
TASK [test-role : Custom filter demo2] ******
ok: [ecs-1.aliyun.sz] => {
"msg": "args: ('Yo', 'Yo', 'like', 'Python') --- kwargs: {'username': 'yo', 'gender': 'female'}"
}
PLAY RECAP ******
ecs-1.aliyun.sz : ok=8 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
九、import_role
import_role 与 include_role 在使用上差别不大
模版定义
---
- hosts: ecs[0]
remote_user: root
tasks:
- name: "import_role 引用 Role"
debug:
msg: "通过 import_role 指令引用 Role 角色"
- import_role:
name: test-role
执行命令
$ ansible-playbook playbook-tasks-link-role2.yml
PLAY [ecs[0]] ******
TASK [Gathering Facts] ******
ok: [ecs-1.aliyun.sz]
TASK [import_role 引用 Role] ******
ok: [ecs-1.aliyun.sz] => {
"msg": "通过 import_role 指令引用 Role 角色"
}
TASK [test-role : debug] ******
ok: [ecs-1.aliyun.sz] => {
"msg": "hello, Yo!"
}
TASK [test-role : generate config] ******
ok: [ecs-1.aliyun.sz]
TASK [test-role : Copy HTML] ******
ok: [ecs-1.aliyun.sz]
TASK [test-role : Run Container] ******
ok: [ecs-1.aliyun.sz]
TASK [test-role : Custom filter demo1] ******
ok: [ecs-1.aliyun.sz] => {
"msg": "Da | a_filter"
}
TASK [test-role : Custom filter demo2] ******
ok: [ecs-1.aliyun.sz] => {
"msg": "args: ('Yo', 'Yo', 'like', 'Python') --- kwargs: {'username': 'yo', 'gender': 'female'}"
}
PLAY RECAP ******
ecs-1.aliyun.sz : ok=8 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0