How to parallelize loops with an inculde in ansible












0














Recently I came across a bottleneck in our ansible playbooks' code. We were deploying our clusters (e.g. a mongoDB Replica Set) sequentially - i.e. one VM after another, each waiting for the previous to be up and running.



This slowed down the whole cluster deploy time by a factor of the members on it.



To solve this, I started digging on ansible's async actions and pooling and found out a few examples on parallel loops and "fire-and-forget" strategies for scenarios like ours.



The particular thing is, we have defined our own "customize the VM and spawn it" ansible task (create_instance.yml) that gets included and receives the different customization variables from the playbook and abstracts the whole process by running different KVM/shell commands.



Using "Parallel task execution in Ansible" as reference, I ended up having something like:



- name: Generate VMs for DB
hosts: hypervisor_fe
tags: platform,mongodb
tasks:
- include: tasks/create_instance.yml
vars:
vm: "{{ item }}"
with_items: "{{ mongodb.vms }}"
register: mongo_instances
async: 7200
poll: 0

- name: Wait for instance creation to complete
async_status: jid={{ item.ansible_job_id }}
register: mongo_jobs
until: mongo_jobs.finished
retries: 300
with_items: "{{ mongo_instances.results }}"


However, this setup does seem to ignore all the new async code and keeps the old, sequential behavior. I'm guessing this has to do with the no. and granularity of plays inside the imported task. If I instead replace the include for a single, explicit long-running task - let's say, e.g.



- name: Test async operation
shell: ping -c1 {{ item.hostname }} && sleep 20


This does seem to work just fine, running one ping to each item and then moving on to the next action.



Is this assumption right? Does someone has experience with include and async loops in ansible? Do I need to move the async declaration to a single play inside the imported code?










share|improve this question
























  • Based on what I read in stackoverflow.com/a/39207589/2172072 by @konstantin-suvorov: "include can't use async keyword" - thus, this seems not to be an option right now. Digging on ansible's GH found out this FR: github.com/ansible/ansible/issues/22716
    – Alfageme
    Nov 12 '18 at 16:00
















0














Recently I came across a bottleneck in our ansible playbooks' code. We were deploying our clusters (e.g. a mongoDB Replica Set) sequentially - i.e. one VM after another, each waiting for the previous to be up and running.



This slowed down the whole cluster deploy time by a factor of the members on it.



To solve this, I started digging on ansible's async actions and pooling and found out a few examples on parallel loops and "fire-and-forget" strategies for scenarios like ours.



The particular thing is, we have defined our own "customize the VM and spawn it" ansible task (create_instance.yml) that gets included and receives the different customization variables from the playbook and abstracts the whole process by running different KVM/shell commands.



Using "Parallel task execution in Ansible" as reference, I ended up having something like:



- name: Generate VMs for DB
hosts: hypervisor_fe
tags: platform,mongodb
tasks:
- include: tasks/create_instance.yml
vars:
vm: "{{ item }}"
with_items: "{{ mongodb.vms }}"
register: mongo_instances
async: 7200
poll: 0

- name: Wait for instance creation to complete
async_status: jid={{ item.ansible_job_id }}
register: mongo_jobs
until: mongo_jobs.finished
retries: 300
with_items: "{{ mongo_instances.results }}"


However, this setup does seem to ignore all the new async code and keeps the old, sequential behavior. I'm guessing this has to do with the no. and granularity of plays inside the imported task. If I instead replace the include for a single, explicit long-running task - let's say, e.g.



- name: Test async operation
shell: ping -c1 {{ item.hostname }} && sleep 20


This does seem to work just fine, running one ping to each item and then moving on to the next action.



Is this assumption right? Does someone has experience with include and async loops in ansible? Do I need to move the async declaration to a single play inside the imported code?










share|improve this question
























  • Based on what I read in stackoverflow.com/a/39207589/2172072 by @konstantin-suvorov: "include can't use async keyword" - thus, this seems not to be an option right now. Digging on ansible's GH found out this FR: github.com/ansible/ansible/issues/22716
    – Alfageme
    Nov 12 '18 at 16:00














0












0








0







Recently I came across a bottleneck in our ansible playbooks' code. We were deploying our clusters (e.g. a mongoDB Replica Set) sequentially - i.e. one VM after another, each waiting for the previous to be up and running.



This slowed down the whole cluster deploy time by a factor of the members on it.



To solve this, I started digging on ansible's async actions and pooling and found out a few examples on parallel loops and "fire-and-forget" strategies for scenarios like ours.



The particular thing is, we have defined our own "customize the VM and spawn it" ansible task (create_instance.yml) that gets included and receives the different customization variables from the playbook and abstracts the whole process by running different KVM/shell commands.



Using "Parallel task execution in Ansible" as reference, I ended up having something like:



- name: Generate VMs for DB
hosts: hypervisor_fe
tags: platform,mongodb
tasks:
- include: tasks/create_instance.yml
vars:
vm: "{{ item }}"
with_items: "{{ mongodb.vms }}"
register: mongo_instances
async: 7200
poll: 0

- name: Wait for instance creation to complete
async_status: jid={{ item.ansible_job_id }}
register: mongo_jobs
until: mongo_jobs.finished
retries: 300
with_items: "{{ mongo_instances.results }}"


However, this setup does seem to ignore all the new async code and keeps the old, sequential behavior. I'm guessing this has to do with the no. and granularity of plays inside the imported task. If I instead replace the include for a single, explicit long-running task - let's say, e.g.



- name: Test async operation
shell: ping -c1 {{ item.hostname }} && sleep 20


This does seem to work just fine, running one ping to each item and then moving on to the next action.



Is this assumption right? Does someone has experience with include and async loops in ansible? Do I need to move the async declaration to a single play inside the imported code?










share|improve this question















Recently I came across a bottleneck in our ansible playbooks' code. We were deploying our clusters (e.g. a mongoDB Replica Set) sequentially - i.e. one VM after another, each waiting for the previous to be up and running.



This slowed down the whole cluster deploy time by a factor of the members on it.



To solve this, I started digging on ansible's async actions and pooling and found out a few examples on parallel loops and "fire-and-forget" strategies for scenarios like ours.



The particular thing is, we have defined our own "customize the VM and spawn it" ansible task (create_instance.yml) that gets included and receives the different customization variables from the playbook and abstracts the whole process by running different KVM/shell commands.



Using "Parallel task execution in Ansible" as reference, I ended up having something like:



- name: Generate VMs for DB
hosts: hypervisor_fe
tags: platform,mongodb
tasks:
- include: tasks/create_instance.yml
vars:
vm: "{{ item }}"
with_items: "{{ mongodb.vms }}"
register: mongo_instances
async: 7200
poll: 0

- name: Wait for instance creation to complete
async_status: jid={{ item.ansible_job_id }}
register: mongo_jobs
until: mongo_jobs.finished
retries: 300
with_items: "{{ mongo_instances.results }}"


However, this setup does seem to ignore all the new async code and keeps the old, sequential behavior. I'm guessing this has to do with the no. and granularity of plays inside the imported task. If I instead replace the include for a single, explicit long-running task - let's say, e.g.



- name: Test async operation
shell: ping -c1 {{ item.hostname }} && sleep 20


This does seem to work just fine, running one ping to each item and then moving on to the next action.



Is this assumption right? Does someone has experience with include and async loops in ansible? Do I need to move the async declaration to a single play inside the imported code?







asynchronous ansible






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 12 '18 at 14:56

























asked Nov 12 '18 at 14:22









Alfageme

1,24011120




1,24011120












  • Based on what I read in stackoverflow.com/a/39207589/2172072 by @konstantin-suvorov: "include can't use async keyword" - thus, this seems not to be an option right now. Digging on ansible's GH found out this FR: github.com/ansible/ansible/issues/22716
    – Alfageme
    Nov 12 '18 at 16:00


















  • Based on what I read in stackoverflow.com/a/39207589/2172072 by @konstantin-suvorov: "include can't use async keyword" - thus, this seems not to be an option right now. Digging on ansible's GH found out this FR: github.com/ansible/ansible/issues/22716
    – Alfageme
    Nov 12 '18 at 16:00
















Based on what I read in stackoverflow.com/a/39207589/2172072 by @konstantin-suvorov: "include can't use async keyword" - thus, this seems not to be an option right now. Digging on ansible's GH found out this FR: github.com/ansible/ansible/issues/22716
– Alfageme
Nov 12 '18 at 16:00




Based on what I read in stackoverflow.com/a/39207589/2172072 by @konstantin-suvorov: "include can't use async keyword" - thus, this seems not to be an option right now. Digging on ansible's GH found out this FR: github.com/ansible/ansible/issues/22716
– Alfageme
Nov 12 '18 at 16:00












1 Answer
1






active

oldest

votes


















1














I advice you to rethink your playbook design in the following way:



- hosts: localhost
tasks:
- add_host:
name: "{{ item.name }}"
groups: new_vms
vm: "{{ item }}"
with_items: "{{ mongodb.vms }}"

- hosts: new_vms
tasks:
- include: create_instance.yml


And inside create_instance.yml use delegate_to: hypervisor_fe.



This gives you native Ansible host loop for every vm with concurrent execution of each task.






share|improve this answer





















  • Won't this fail with "unreachable" when trying to gather the facts of new_vms (not yet created)? Is there a way to apply the delegate_to to all tasks on the include? (~30)
    – Alfageme
    Nov 13 '18 at 10:33






  • 1




    You can disable it with gather_facts: no and collect them later with setup module. You can apply delegate_to: localhost to include statement or add block into your task file and apply delegate_to to the block.
    – Konstantin Suvorov
    Nov 13 '18 at 10:41











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53264168%2fhow-to-parallelize-loops-with-an-inculde-in-ansible%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes









1














I advice you to rethink your playbook design in the following way:



- hosts: localhost
tasks:
- add_host:
name: "{{ item.name }}"
groups: new_vms
vm: "{{ item }}"
with_items: "{{ mongodb.vms }}"

- hosts: new_vms
tasks:
- include: create_instance.yml


And inside create_instance.yml use delegate_to: hypervisor_fe.



This gives you native Ansible host loop for every vm with concurrent execution of each task.






share|improve this answer





















  • Won't this fail with "unreachable" when trying to gather the facts of new_vms (not yet created)? Is there a way to apply the delegate_to to all tasks on the include? (~30)
    – Alfageme
    Nov 13 '18 at 10:33






  • 1




    You can disable it with gather_facts: no and collect them later with setup module. You can apply delegate_to: localhost to include statement or add block into your task file and apply delegate_to to the block.
    – Konstantin Suvorov
    Nov 13 '18 at 10:41
















1














I advice you to rethink your playbook design in the following way:



- hosts: localhost
tasks:
- add_host:
name: "{{ item.name }}"
groups: new_vms
vm: "{{ item }}"
with_items: "{{ mongodb.vms }}"

- hosts: new_vms
tasks:
- include: create_instance.yml


And inside create_instance.yml use delegate_to: hypervisor_fe.



This gives you native Ansible host loop for every vm with concurrent execution of each task.






share|improve this answer





















  • Won't this fail with "unreachable" when trying to gather the facts of new_vms (not yet created)? Is there a way to apply the delegate_to to all tasks on the include? (~30)
    – Alfageme
    Nov 13 '18 at 10:33






  • 1




    You can disable it with gather_facts: no and collect them later with setup module. You can apply delegate_to: localhost to include statement or add block into your task file and apply delegate_to to the block.
    – Konstantin Suvorov
    Nov 13 '18 at 10:41














1












1








1






I advice you to rethink your playbook design in the following way:



- hosts: localhost
tasks:
- add_host:
name: "{{ item.name }}"
groups: new_vms
vm: "{{ item }}"
with_items: "{{ mongodb.vms }}"

- hosts: new_vms
tasks:
- include: create_instance.yml


And inside create_instance.yml use delegate_to: hypervisor_fe.



This gives you native Ansible host loop for every vm with concurrent execution of each task.






share|improve this answer












I advice you to rethink your playbook design in the following way:



- hosts: localhost
tasks:
- add_host:
name: "{{ item.name }}"
groups: new_vms
vm: "{{ item }}"
with_items: "{{ mongodb.vms }}"

- hosts: new_vms
tasks:
- include: create_instance.yml


And inside create_instance.yml use delegate_to: hypervisor_fe.



This gives you native Ansible host loop for every vm with concurrent execution of each task.







share|improve this answer












share|improve this answer



share|improve this answer










answered Nov 12 '18 at 19:38









Konstantin Suvorov

36.1k44081




36.1k44081












  • Won't this fail with "unreachable" when trying to gather the facts of new_vms (not yet created)? Is there a way to apply the delegate_to to all tasks on the include? (~30)
    – Alfageme
    Nov 13 '18 at 10:33






  • 1




    You can disable it with gather_facts: no and collect them later with setup module. You can apply delegate_to: localhost to include statement or add block into your task file and apply delegate_to to the block.
    – Konstantin Suvorov
    Nov 13 '18 at 10:41


















  • Won't this fail with "unreachable" when trying to gather the facts of new_vms (not yet created)? Is there a way to apply the delegate_to to all tasks on the include? (~30)
    – Alfageme
    Nov 13 '18 at 10:33






  • 1




    You can disable it with gather_facts: no and collect them later with setup module. You can apply delegate_to: localhost to include statement or add block into your task file and apply delegate_to to the block.
    – Konstantin Suvorov
    Nov 13 '18 at 10:41
















Won't this fail with "unreachable" when trying to gather the facts of new_vms (not yet created)? Is there a way to apply the delegate_to to all tasks on the include? (~30)
– Alfageme
Nov 13 '18 at 10:33




Won't this fail with "unreachable" when trying to gather the facts of new_vms (not yet created)? Is there a way to apply the delegate_to to all tasks on the include? (~30)
– Alfageme
Nov 13 '18 at 10:33




1




1




You can disable it with gather_facts: no and collect them later with setup module. You can apply delegate_to: localhost to include statement or add block into your task file and apply delegate_to to the block.
– Konstantin Suvorov
Nov 13 '18 at 10:41




You can disable it with gather_facts: no and collect them later with setup module. You can apply delegate_to: localhost to include statement or add block into your task file and apply delegate_to to the block.
– Konstantin Suvorov
Nov 13 '18 at 10:41


















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.





Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


Please pay close attention to the following guidance:


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53264168%2fhow-to-parallelize-loops-with-an-inculde-in-ansible%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







這個網誌中的熱門文章

Academy of Television Arts & Sciences

L'Équipe

1995 France bombings