Changing of ownership is not working

Here, in this code, I’m trying to change the ownership from root:root to user:user. It is failing to do so!
Due to this ownership issue, it is giving error at next step.

Logs of error:

TASK [Change ownership of output_dir directory to "user"] **********************************************************************************************
changed: [ip]

TASK [Download Output File Locally] ************************************************************************************************************************
fatal: [ip]: FAILED! => {"msg": "Unable to create local directories(/tmp/log/dir1/dir2): [Errno 13] Permission denied: b'/tmp/log/dir1/dir2'"}

This code is not even giving any error.

  • my code!
  hosts: "{{ profile }}"
  remote_user: "{{ user }}"
  vars:
    code_name: xenial
    user: "{{ user }}"
    output_dir: "{{ output_dir }}"
  tasks:
    - name: Create Template OS Version file
      shell: echo "" > /home/{{ user }}/os-version.txt
    - name: Run the shell command to get raw OS data
      shell: |
        cat /etc/*release > os-version.txt
	- name: Change ownership of output_dir directory to "user"
      file:
        path: "{{ output_dir }}"
        owner: "{{ new_owner }}"
        state: directory
      become: yes
    - name: Download Output File Locally
      fetch:
        src: /home/{{ user }}/os-version.txt
        dest: "{{ output_dir }}os-version.txt"
        flat: yes
      become: yes
      become_user: root
    - name: Clean up footprints
      shell: |
        rm /home/{{ user }}/os-version.txt

You have a few problems. I was able to get your playbook to run - and fail - depending on what extra variables I put on the command line. For the record, I used this:

$ ansible-playbook copyfetch.yml -vv -e '{"profile":"cloister","user":"utoddl","output_dir":"/tmp/log/dir1/dir2","new_owner":"utoddl"}' -K -i cloister,

Starting at the top: Setting hosts: to a variable is a bit of an anti-pattern. But if you’re going to do it, you should at least include a default, even if it’s

  hosts: "{{ profile | default('none') }}"

so that you can run ansible-lint on your playbook. (Otherwise ansible-lint stops at that point. Or at least it did at the version I’m running.)

Why are you setting the variables user and output_dir to their own values? If they don’t already have those values, those initializations won’t work. Or maybe that’s the point: to ensure they are passed in from outside? If so, I recommend you add an ansible.builtin.assert step with appropriate messages and assertions.

The whitespace before “- name: Change ownership of output_dir directory to "user"” is a tab, not spaces. (Speaking of whitespace, a blank line between tasks would be welcome by some of us.)

Your “Change ownership of output_dir directory to "user"” task is creating a possibly nested directory on the remote, not on the Ansible control node. You probably want a “delegate_to: localhost” on that task. Also, the task name claims to change the owner to "user", when in fact it changes it to {{ new_owner }}.

I was not able to reproduce the exact error you showed, but the expression

        dest: "{{ output_dir }}os-version.txt"

depends on the value of {{ output_dir }} ending with a “/”. You really should spell that

        dest: "{{ output_dir }}/os-version.txt"

so the dest: will work regardless of whether {{ output_dir }} ends with a slash.

I suspect your error has to do with something already existing at some level along the path /tmp/log/dir1/dir2/os-version.txt, particularly since the prior step which was supposed to prepare that path did so on the wrong host. It could also be that the version of ansible.builtin.fetch you are running cannot create the necessary parent directories. (Mine does, so the prior step’s prep on the wrong host was irrelevant in my tests.)

I hope something in here helps. Good luck.

2 Likes