我在下面的剧本中有多个剧本.如果不满足某些条件,我想忽略所有其他播放.
因此对于下面的示例-如果在Play1中找不到任何新文件,那么我根本就不想执行Play2和Play3(应该跳过它).我该怎么办?
我在Play1中有end_play,但它只跳过了Play1,它仍然执行Play2和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/更新:
所以块模块解决方案看起来不起作用,因为您不能像这样那样在块中使用嵌套播放.
解决方案有两种方法可以解决您的问题:
使用委托
剧中的任何任务都可以委派给另一位主持人.这非常简单,只需在任务中使用一个额外的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,因为如果将任务委派给另一台主机,则无需这样做,也就是说,如果主机组中有十台主机,则运行十次
这是一个有关此的小例子
--- - 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..."在哪里可以看到,当我在上一步的主机组中拥有三台主机中的两台时,我通过结束播放跳过了最后一条调试消息.
该剧本的输出:
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在输出中,您可以轻松地发现委托,就像输出
changed: [host1 -> localhost]当未委派的任务刚开始时
changed: [host1]使用hostvars
我要说的是,这种方法比现有技术要少一些,但是如果您想委托边缘案例,它可能会派上用场.我以前使用过它,所以这并不是说不可能以正确的解决方案结束它.
这里是例子
--- - 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您可以看到,在主机的每个新任务组的开头,我只是运行meta以结束播放,这是基于find结果中注册的变量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=0I have multiple plays in below playbook. I want to ignore all other plays if some condition is not met.
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?
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/Update:
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:
Using delegation
Any task in the play can be delegated to another host. This is quite simple to do and would just use one extra delegate_to options on your task:
- name: Delegate a find to localhost find: path: /test file_type: any register: localhost_find delegate_to: localhost run_once: trueWhen 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.
Output of that playbook:
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=0In 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.
Here is the example
--- - 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 happenWhere 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
Here is the output for this one
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
更多推荐
如果不满足某些条件,如何跳过ansible剧本中的所有其他剧本?
发布评论