skip to Main Content

I have a playbook with 2 plays, I would like to for them to run in parallel, currently they are running in series. Any advice?

Here is what the playbook currently looks like:

---
- name: Install windows_hosts
  hosts: win
  tasks:
    # Windows specific tasks

- name: Install ubuntu_hosts
  hosts: ubu
  tasks:
    # Ubuntu specific tasks
  become: true

win and ubu have exactly 1 host in it, see hosts file below:

win:
  hosts:
    win-host:
      ansible_host: <IP>
  vars:
    ansible_connection: winrm
    ansible_winrm_transport: certificate
    ansible_winrm_user: ansible
    ansible_winrm_cert_pem: <CERT-PATH>
    ansible_winrm_cert_key_pem: <CERT-KEY-PATH>
    ansible_port: <PORT>
    ansible_winrm_scheme: https
    ansible_gather_timeout: 300
    ansible_winrm_read_timeout_sec: 60
ubu:
  hosts:
    ubu-host:
      ansible_host: <IP>
  vars:
    ansible_ssh_common_args: '-o StrictHostKeyChecking=no'

I expect the 2 plays to run at the same time but it runs through all of the windows before it starts on ubuntu.

2

Answers


  1. Ansible runs tasks on hosts in parallel within a play, but the plays are always running subsequently.

    So, generally the rules are as follows:

    • you can run the same tasks in parallel within the same play;
    • you can’t run different tasks in parallel within the same play;
    • you can’t run plays in parallel, so you can’t run any tasks in parallel within different plays.

    If the tasks you want to run are supported on both Windows and Linux, you can just unite the groups like hosts: win,ubu and you’re good – you don’t need a second play.

    If you’re invoking some roles, the difference in target hosts operating systems may be processed in the role code using when condition – and you can do the same for your tasks, too. If you have lots of them, you can group them in a block so you have only two when conditions.

    Also, there’s a couple more tricks you could apply. They make use of free play execution strategy, asynchronous task execution, and conditionals. I recommend to check out my answers to this and especially this questions cause they are highly related in terms of possible solutions.

    Remember that Ansible processes up to 5 hosts in parallel by default. You can change this behavior anytime via ansible.cfg file or the corresponding environment variable.

    Login or Signup to reply.
  2. There are more options:

    1. Split the playbook into 2 playbooks and run them in parallel.

    2. Put the OS-specific tasks into files and import them conditionally. For example,

    shell> cat win.yml 
    - debug:
        msg: Windows specific tasks
    
    shell> cat ubu.yml 
    - debug:
        msg: Ubuntu specific tasks
    
    shell> cat pb.yml 
    - hosts: all
    
      tasks:
    
        - import_tasks: win.yml
          when: inventory_hostname in groups.win
    
        - import_tasks: ubu.yml
          when: inventory_hostname in groups.ubu
    
    1. The play will be simpler if you can use include_tasks. See Including and Importing
    • If the first 3 characters of the inventory hostnames are the OS acronyms
    - hosts: all
    
      tasks:
    
        - include_tasks: "{{ inventory_hostname[:3] }}.yml"
    
    • If the names of the inventory groups are the OS acronyms and the hosts are not members of multiple groups. See the special variable group_names
    - hosts: all
      
      tasks:
    
        - include_tasks: "{{ group_names.0 }}.yml"
    
    • Create your mapping of tasks
    - hosts: all
    
      vars:
    
        os_tasks:
          win: win-tasks.yml
          ubu: ubu-tasks.yml
    
      tasks:
    
        - include_tasks: "{{ os_tasks[group_names.0] }}"
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search