Ansible – Execute and Delegate Tasks Across Hosts

ansibleansible-playbook

Context:

I have a project with two roles.
I've reduced the number of tasks to the problem ones for better understanding.

Problem:
I run a task from a role1 in server1 and trie to delegate a task to a vmware virtualizer from condition in the first server1 role task.
And have a host fail because it wants to excecute the second role task (Vmware) in the server1.

The error:

fatal: [testhost]: FAILED! => {"reason": "conflicting action statements: hosts, 
gather_facts\n\nThe error appears to be in '/home/ancible/proyects/extend_fs-role/roles/vmwaretaks/tasks/addvmwaredisk.yml': line 2, column 3, 
but may\nbe elsewhere in the file depending on tntax problem.\n\nThe offending line appears to be:\n\n---\n- hosts: localhost\n  ^ here\n"}

Here is the structure:

.
├── collections
│   └── requirements.yml
├── README.md
├── resizefs_hosts.yml
└── roles
    ├── resizefs
    │   ├── defaults
    │   │   └── main.yml
    │   ├── handlers
    │   │   └── main.yml
    │   ├── meta
    │   │   └── main.yml
    │   ├── tasks
    │   │   ├── main.yml
    │   │   ├── findfreedisk.yml
    │   ├── tests
    │   │   ├── inventory
    │   │   └── test.yml
    │   └── vars
    │       └── main.yml
    └── vmwaretaks
        ├── defaults
        │   └── main.yml
        ├── files
        ├── handlers
        │   └── main.yml
        ├── meta
        │   └── main.yml
        ├── README.md
        ├── tasks
        │   ├── main.yml
        │   ├── addvmwaredisk.yml
        ├── templates
        ├── tests
        │   ├── inventory
        │   └── test.yml
        └── vars
            └── main.yml

This is the excecution order in case that not find a free lun in the host:

resizefs_role_hosts.yml -> roles/resizefs/tasks/main.yml -> roles/resizefs/tasks/findfreedisk.yml -> \
roles/vmwaretaks/tasks/main.yml -> roles/vmwaretaks/tasks/addvmwaredisk.yml

This are what the playbooks looks like:

$ cat  resizefs_role_hosts.yml
---
- hosts: testhost
  become: yes
  become_method: sudo
  roles:
    - role: 'roles/resizefs'
$ cat roles/resizefs/tasks/main.yml
---
# tasks file for create_fs-test
- import_tasks: findfreedisk.yml
$ cat roles/resizefs/tasks/findfreedisk.yml

- name: Finding disk with no partitions
  set_fact:
    disks: "/dev/{{outer_item.key}}"
  when:
    - not outer_item.value.partitions
    - not outer_item.value.links.ids
    - outer_item.key is search ("sd")
  with_dict: '{{ansible_devices}}'
  loop_control:
    loop_var: outer_item
  notify:
    - Format_free_disk
  changed_when: true

- name: Print disk name if available
  debug:
    msg:
      - "{{ disks|default('NOT FREE DISK') }} Available"

# If not disk available add new lun from Vmware
- include_role:
    name: vmwaretaks
  when: disks is undefined
$ cat roles/vmwaretaks/tasks/main.yml
---
# tasks file for add-new-vmware-lun
- import_tasks: addvmwaredisk.yml
$ cat roles/vmwaretaks/tasks/addvmwaredisk.yml

---
- hosts: localhost
  gather_facts: true

  vars:
    vcenter_hostname: 'vcenter.labo.local'
    vcenter_username: 'labo.local\ansible'
    vcenter_password: "{{ vault_pass }}"
    target_host: 'TESTHOST'
    vm_uuid: '4217B33E-014D-E056-0719-45AD3AC1861E'
    vm_unit_number: '5'

  tasks:
    - name: Add disks to virtual machine using UUID
      vmware_guest_disk:
        hostname: "{{ vcenter_hostname }}"
        username: "{{ vcenter_username }}"
        password: "{{ vcenter_password }}"
        datacenter: "{{ vcenter_hostname }}"
        uuid: "{{ vm_uuid | lower }}"
        validate_certs: no
        disk:
          - size_gb: 10
            type: 'thick'
            state: 'present'
            autoselect_datastore: yes
            scsi_controller: '0'
            scsi_type: 'paravirtual'
            unit_number: '5'
            disk_mode: 'independent_persistent'
      delegate_to: localhost

I was trying to find the way to tell it that the second role is not executed in the server but in the vmware virtualizer but with not luck.

If I run the addvmwaredisk.yml as a playbook it runs perfect

Hope you can help!

thanks in advance!

Best Answer

hosts and tasks are play keywords, they cannot be used inside a task list. To execute tasks on a different host than the current play host, use delegation; to group related tasks together and apply directives to all of them, use a block.

- delegate_to: localhost
  vars:
    vcenter_hostname: 'vcenter.labo.local'
    vcenter_username: 'labo.local\ansible'
    vcenter_password: "{{ vault_pass }}"
    target_host: 'TESTHOST'
    vm_uuid: '4217B33E-014D-E056-0719-45AD3AC1861E'
    vm_unit_number: '5'
  block:
    - name: Add disks to virtual machine using UUID
      vmware_guest_disk:
        hostname: "{{ vcenter_hostname }}"
        username: "{{ vcenter_username }}"
        password: "{{ vcenter_password }}"
        datacenter: "{{ vcenter_hostname }}"
        uuid: "{{ vm_uuid | lower }}"
        validate_certs: no
        disk:
          - size_gb: 10
            type: 'thick'
            state: 'present'
            autoselect_datastore: yes
            scsi_controller: '0'
            scsi_type: 'paravirtual'
            unit_number: '5'
            disk_mode: 'independent_persistent'