0

Having a playbook that contains 2 plays,

  • one that will run a command through the shell module and save the output to a result file on the Control Node (localhost) for all the hosts in the inventory
  • and another one that will only run on the Control Node and that is meant to change the ownership permissions to that result file,

like this:

---
 - name: Run and save shell command - 1st play
   hosts: all
   gather_facts: False
   serial: 10
   become_flags: -i
   become: yes

   vars:
    res: "/home/myuser/test"

   tasks:
     - name: run shell command
       shell: 'pwd'
       register: myshellout

     - name: save output
       shell: echo -e "{{ inventory_hostname }}{{ myshellout.stdout }}\n" >> "{{ res }}"
       delegate_to: localhost

 - name: change ownership - 2nd play
   hosts: localhost
   gather_facts: no
   tasks:
     - name: change ownership task
       file:
         path: "{{ res }}"
         owner: myuser
         group: myuser
      #  delegate_to: localhost
      #  run_once: true

Please note that I run the Ansible playbook like this:

ansible-playbook -i myinventory -e 'res=/home/myuser/mycustomfile' --limit 'host1,host2,host3' myansibleplaybook.yml

so it's not all the hosts in the inventory.

Why do I get the skipping: no hosts matched comment for the 2nd play and how can I execute the change of ownership task only once, at the end of the play?

U880D
  • 8,601
  • 6
  • 24
  • 40
Cat Hariss
  • 123
  • 10
  • 3
    `localhost` is not part of your `--limit` hence there are no hosts available to run a play against target `localhost` – Zeitounator Feb 25 '23 at 17:27
  • Please take note that with your given example you are hitting the same write concurrency issue as in [Ansible module `lineinfile` ... write all the output](https://stackoverflow.com/a/74221921/6771046). – U880D Feb 26 '23 at 11:51
  • @U880D I have found that by using echo rather than lineinfile it never skipped a result so the write concurrency is not present anymore – Cat Hariss Feb 27 '23 at 04:24

1 Answers1

1

This have been said over and over again on the tag: do not use Ansible as a wrapper for shell commands over SSH. By doing so, you fail to benefit most of the feature Ansible is providing you and you create yourself more trouble than necessary.

In order to save something from one machine to the controller, what you can do is to use the blockinfile, which have the parameters owner and group available already, and delegate this task to localhost.

And if your goal running pwd is to get the home of the user, you could use the fact ansible_env.HOME of your hosts.

So, with a serial approach in mind, this should do the trick, and is an idempotent task:

- hosts: all
  gather_subset: min
  serial: 10
  become: true

  tasks:
    - blockinfile:
        block: |
          {% for host in ansible_play_batch %}
            {{- host }}{{ hostvars[host].ansible_env.HOME }}
          {% endfor %}
        path: /home/myuser/test
        marker: >-
          # {mark} {{ ansible_play_batch | join('/') }} ANSIBLE MANAGED BLOCK
        owner: myuser
        group: myuser
        create: true
      delegate_to: localhost
      run_once: true

Which will generate a file containing something like:

# BEGIN host3/host2/host1 ANSIBLE MANAGED BLOCK
host3/root
host2/root
host1/root
# END host3/host2/host1 ANSIBLE MANAGED BLOCK
β.εηοιτ.βε
  • 33,893
  • 13
  • 69
  • 83
  • No, my goal was not to run pwd to get the home of the user but a more complex command that could not be replaced by any of the ansible facts – Cat Hariss Feb 27 '23 at 04:29
  • Then the answer still apply, `register` whatever task or command you need, then: `{{- host }}{{ hostvars[host].myshellout }}` in the loop. – β.εηοιτ.βε Feb 27 '23 at 09:22
  • 1
    Just like to note that if your "_goal was **not to run `pwd`** to get the home of the user but a more complex command that could not be replaced by any of the ansible facts_" then that should be in the initial description together with a minimal reproducible example as over-simplifying or over-generalization will lead to wrong assumptions and incorrect solutions. It might be better to describe your actual use case and what you try to achieve rather than how do you try to resolve the not specified further. – U880D Feb 28 '23 at 06:59