如果不满足某些条件,如何跳过 ansible 剧本中的所有其他剧本?
我在下面的剧本中有多个剧本.如果不满足某些条件,我想忽略所有其他播放.
I have multiple plays in below playbook. I want to ignore all other plays if some condition is not met.
所以对于下面的例子 - 如果我在 Play1
中找不到任何新文件,那么我不想执行 Play2
和 Play3
在全部(它应该跳过它).我该怎么做?
So for below example - If I cannot find any new file in Play1
then I don't want to execute Play2
and Play3
at all (it should skip it). How can I do that?
我在 Play1 中有 end_play
但它只跳过 Play1
而它仍然执行 Play2
和 Play3
>
I have end_play
in Play1 but it only skips Play1
and it still executes Play2
and Play3
---
- name: Play 1
hosts: 127.0.0.1
tasks:
- name: find the latest file
find: paths=/var/lib/jenkins/jobs/process/workspace/files
file_type=file
age=-1m
age_stamp=mtime
register: files
- meta: end_play
when: files.files|count == 0
- name: Copy file, if found
copy:
src: "some stuff here"
dest: "some other stuff here"
when: files.files|count > 0
- name: Play 2
hosts: all
serial: 5
tasks:
- name: copy latest file
copy: src=data_init/goldy.init.qa dest=/data01/admin/files/goldy.init.qa owner=golden group=golden
- name: copy latest file
copy: src=data_init/goldy.init.qa dest=/data02/admin/files/goldy.init.qa owner=golden group=golden
- name: Play 3
hosts: 127.0.0.1
tasks:
- name: execute command
shell: ./data_init --init_file ./goldy.init.qa
args:
chdir: /var/lib/jenkins/jobs/process/workspace/data_init/
更新:
所以块模块解决方案看起来不起作用,因为你不能像那样在块中使用嵌套播放..
So block module solution doesn't work looks like because you cannot use nested play in block like that..
有两种方法可以解决您的问题:
There are two ways to approach your issue:
- 尽管您尝试定义一个
hosts: localhost
来在控制器上运行一些任务是可以理解的,但您实际上并不需要它.使用delegate_to: localhost
和run_once: true
在控制器上运行的步骤是一个更好的方法. - 如果你真的想走这条路(使用
hosts: localhost
),出于某种原因,那么你需要保存你的find
的返回,用set_fact
按顺序在全局hostvars
- Although it is understandable that you tried defining a
hosts: localhost
to run some tasks on the controller, you don't really need this. Usingdelegate_to: localhost
andrun_once: true
on the steps you want to run on your controller is a far better approach. - If you really want to go this way (using
hosts: localhost
), for some reason, then you'll need to save the return of yourfind
, withset_fact
in order to reuse it in other hosts with the help of the globalhostvars
使用委托
剧中的任何任务都可以委托给其他主持人.这很简单,只需在您的任务中使用一个额外的 delegate_to
选项:
- name: Delegate a find to localhost
find:
path: /test
file_type: any
register: localhost_find
delegate_to: localhost
run_once: true
这样做时,我建议您也使用 run_once: true
,因为如果您将任务委托给另一个主机,则没有必要,假设您运行十次您的主机组中有十个主机.
When doing so, I would advice you to also use run_once: true
, because, if you delegate the task to another host, there is no need to, let's say run it ten times if you have ten hosts in your host group.
这里有一个关于这个的小例子
Here is a little example about that
---
- hosts: hosts
become: true
gather_facts: false
tasks:
- name: Delegate directory creation to localhost
file:
path: /test
state: directory
delegate_to: localhost
run_once: true
- name: Create directory on hosts
file:
path: /test
state: directory
- name: Delegate file creation to localhost
file:
path: /test/localhost.txt
state: touch
delegate_to: localhost
run_once: true
- name: Create file on hosts
file:
path: /test/host.txt
state: touch
- name: Delegate a find to localhost
find:
path: /test
file_type: any
register: localhost_find
delegate_to: localhost
run_once: true
- name: Find in the hosts for comparison
find:
path: /test
file_type: any
register: host_find
- name: List /test of localhost
debug:
msg: "{{ localhost_find.files | map(attribute='path') | list }}"
- name: List /test of host
debug:
msg: "{{ host_find.files | map(attribute='path') | list }}"
- name: Remove /test folder on localhost
file:
path: /test
state: absent
delegate_to: localhost
run_once: true
- name: Delegate an empty find to localhost
find:
path: /test
file_type: any
register: empty_find
delegate_to: localhost
run_once: true
- name: Here are our hostnames from the inventory
debug:
msg: "{{ inventory_hostname }}"
- name: I am the evil host killer
meta: end_host
when: empty_find.files | count == 0 and inventory_hostname != 'host1'
- debug:
msg: "I am a sad message, because I will never display :'( But hopefully host1 likes me :')"
- name: I am the evil playbook killer
meta: end_play
when: empty_find.files | count == 0
- debug:
msg: "I am a sad message, because I will never display :'( No one likes me..."
你可以看到,当我结束前一步主机组中的三个主机中的两个时,我通过结束播放跳过了最后一条调试消息.
Where you can see, that, I am skipping the very last debug message by ending the play, when I ended two out of the three hosts I have in my hosts group on the step before.
该剧本的输出:
PLAY [hosts] **************************************************************************************************************************
TASK [Delegate directory creation to localhost] ***************************************************************************************
ok: [host1 -> localhost]
TASK [Create directory on hosts] ****************************************************************************************************
ok: [host3]
ok: [host2]
ok: [host1]
TASK [Delegate file creation to localhost] ********************************************************************************************
changed: [host1 -> localhost]
TASK [Create file on hosts] ****************************************************************************************************
changed: [host2]
changed: [host1]
changed: [host3]
TASK [Delegate a find to localhost] ***************************************************************************************************
ok: [host1 -> localhost]
TASK [Find in the host for comparison] ************************************************************************************************
ok: [host1]
ok: [host3]
ok: [host2]
TASK [List /test of localhost] ********************************************************************************************************
ok: [host1] => {
"msg": [
"/test/localhost.txt"
]
}
ok: [host2] => {
"msg": [
"/test/localhost.txt"
]
}
ok: [host3] => {
"msg": [
"/test/localhost.txt"
]
}
TASK [List /test of host] *************************************************************************************************************
ok: [host1] => {
"msg": [
"/test/host.txt"
]
}
ok: [host2] => {
"msg": [
"/test/host.txt"
]
}
ok: [host3] => {
"msg": [
"/test/host.txt"
]
}
TASK [Remove /test folder on localhost] ***********************************************************************************************
changed: [host1 -> localhost]
TASK [Delegate an empty find to localhost] ********************************************************************************************
ok: [host1 -> localhost]
TASK [Here are our hostnames from the inventory] **************************************************************************************
ok: [host1] => {
"msg": "host1"
}
ok: [host2] => {
"msg": "host2"
}
ok: [host3] => {
"msg": "host3"
}
TASK [debug] **************************************************************************************************************************
ok: [host1] => {
"msg": "I am a sad message, because I will never display :'( But hopefully host1 likes me :')"
}
PLAY RECAP ****************************************************************************************************************************
host1 : ok=12 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
host2 : ok=6 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
host3 : ok=6 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
在输出中,您可以很容易地发现委托,就像输出一样
In the output, you can easily spot the delegation, as is will output
changed: [host1 -> localhost]
当一个非委派的任务会去时
When a non-delegated task would just go
changed: [host1]
使用主机变量
我想说这种方法不太先进,但如果您想委托处理边缘情况,可能会很方便.我以前用过它,所以它并不是没有最终无法解决的情况.
Using hostvars
I would say the approach is a little bit less state of the art, but could become handy if you would like to delegate on edge cases. I have used it before, so it is not like there is no situation where it could not end up has being the right solution.
这是例子
---
- hosts: localhost
gather_facts: false
tasks:
- name: Find in localhost
find:
path: /not/existing/folder
file_type: any
register: find
- name: This will register the list under find.files as a variable on the host, making it accessible via hostvars
set_fact:
find_result: "{{ find.files }}"
- meta: end_play
when: find.files | count == 0
- debug:
msg: I am the sanity check message, proving the end_play did happen
- hosts: hosts
gather_facts: false
tasks:
- name: Just to show we are not cheating with an empty host group, we display the hosts names
debug:
msg: "{{ inventory_hostname }}"
- name: To show it is really our empty list and not an empty string or a null variable
debug:
msg: "{{ hostvars['localhost']['find_result'] }}"
- meta: end_play
when: "hostvars['localhost']['find_result'] | count == 0"
- debug:
msg: I am a first sanity check message, proving the end_play did happen
- debug:
msg: I am a second sanity check message, proving the end_play did happen
- hosts: localhost
gather_facts: false
tasks:
- name: To show it is really our empty list and not an empty string or a null variable
debug:
msg: "{{ hostvars['localhost']['find_result'] }}"
- meta: end_play
when: "hostvars['localhost']['find_result'] | count == 0"
- debug:
msg: I am a first sanity check message, proving the end_play did happen
- debug:
msg: I am a second sanity check message, proving the end_play did happen
您可以看到,在主机的每个新任务组开始时,我只是根据变量 find_result
运行 meta
来结束播放注册出find
结果
Where you can see that, at the beginning of each new tasks group for a host, I just run the meta
to end the play, based on the variable find_result
registered out of the find
result
这是这个的输出
PLAY [localhost] **********************************************************************************************************************
TASK [Find in localhost] **************************************************************************************************************
ok: [localhost]
TASK [This will register the list under find.files as a variable on the host, making it accessible via hostvars] *********************
ok: [localhost]
PLAY [hosts] **************************************************************************************************************************
TASK [Just to show we are not cheating with an empty host group, we display the hosts names] ******************************************
ok: [host1] => {
"msg": "host1"
}
ok: [host2] => {
"msg": "host2"
}
ok: [host3] => {
"msg": "host3"
}
TASK [To show it is really our empty list and not an empty string or a null variable] ************************************************
ok: [host1] => {
"msg": []
}
ok: [host2] => {
"msg": []
}
ok: [host3] => {
"msg": []
}
PLAY [localhost] **********************************************************************************************************************
TASK [To show it is really our empty list and not an empty string or a null variable] ************************************************
ok: [localhost] => {
"msg": []
}
PLAY RECAP ****************************************************************************************************************************
host1 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
host2 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
host3 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
localhost : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0