Unable to get stat of existing directory in Ansible due to variable formatting issue

159 Views Asked by At

I'm trying to get the owner of the first directory passed to Ansible variable source_files.

We do not have control over the content of Ansible variable source_files as it is constructed through some OLAM API. I have hard coded it for this example.

Both the files of source_files variable exists as seen below:

[wluser@mylocalhost ~]$ ls -ltr '/tmp/my  private.txt' /tmp/files.sh  
-rw-r--r-- 1 wluser mygrp 0 Nov 12 21:52 /tmp/files.sh    
-rw-r--r-- 1 wluser mygrp 0 Nov 12 21:52 /tmp/my  private.txt

Playbook [wluser@mylocalhost ~]$ cat formatstring.yml

---
- name: "Play 1-Find the details here"

  hosts: localhost
  any_errors_fatal: True
  gather_facts: no

  tasks:

   - name: Set source_files variable
     set_fact:
       source_files: "'/tmp/my  private.txt','/tmp/files.sh'"
 
   - name: Print source_files
     debug:
       msg: "source_files: {{ source_files }}"
     
   - name: Loop Print source_files
     debug:
       msg: "{{ item }}"
     loop: "{{ source_files.split(',') }}"

   - name: Single Print source_files
     debug:
       msg: "{{ source_files.split(',')[0] }}"
   
   - name: Get directory owner
     ansible.builtin.stat:
       path: "{{ tomcat_home_item }}"
     register: dir_stat
     vars:
       tomcat_home_item: "{{ source_files.split(',')[0] | trim }}"

   - name: Store directory owner's UID in a variable
     set_fact:
       owner_uid: "{{ dir_stat.stat.pw_name | default('baduser') }}"

   - debug:
       msg: "Detected user is: {{ owner_uid }}"

   - name: Get directory owner
     ansible.builtin.stat:
       path: "{{ tomcat_home_item | regex_replace('^\\s*'|'\\s*$', '') }}"
     register: dir_stat
     vars:
       tomcat_home_item: "{{ source_files.split(',')[0] | trim }}"

   - name: Store directory owner's UID in a variable
     set_fact:
       owner_uid: "{{ dir_stat.stat.pw_name | default('baduser') }}"
 
   - debug:
       msg: "Detected user is: {{ owner_uid }}"

Output

[wluser@mylocalhost ~]$ ansible-playbook formatstring.yml -vvv
ansible-playbook 2.8.4
  config file = /etc/ansible/ansible.cfg
PLAYBOOK: formatstring.yml ****************************************************************************************************
1 plays in formatstring.yml

PLAY [Play 1-Find the details here] *******************************************************************************************
META: ran handlers

TASK [Set source_files variable] **********************************************************************************************
task path: /home/wluser/formatstring.yml:10
Sunday 12 November 2023  22:02:56 -0600 (0:00:00.044)       0:00:00.044 *******
ok: [localhost] => {
    "ansible_facts": {
        "source_files": "'/tmp/my  private.txt','/tmp/files.sh'"
    },
    "changed": false
}

TASK [Print source_files] *****************************************************************************************************
task path: /home/wluser/formatstring.yml:15
Sunday 12 November 2023  22:02:56 -0600 (0:00:00.018)       0:00:00.062 *******
ok: [localhost] => {
    "msg": "source_files: '/tmp/my  private.txt','/tmp/files.sh'"
}

TASK [Loop Print source_files] ************************************************************************************************
task path: /home/wluser/formatstring.yml:19
Sunday 12 November 2023  22:02:56 -0600 (0:00:00.017)       0:00:00.080 *******
ok: [localhost] => (item='/tmp/my  private.txt') => {
    "msg": "'/tmp/my  private.txt'"
}
ok: [localhost] => (item='/tmp/files.sh') => {
    "msg": "'/tmp/files.sh'"
}

TASK [Single Print source_files] **********************************************************************************************
task path: /home/wluser/formatstring.yml:24
Sunday 12 November 2023  22:02:56 -0600 (0:00:00.033)       0:00:00.114 *******
ok: [localhost] => {
    "msg": "'/tmp/my  private.txt'"
}

TASK [Get directory owner] ****************************************************************************************************
task path: /home/wluser/formatstring.yml:29
Sunday 12 November 2023  22:02:56 -0600 (0:00:00.023)       0:00:00.137 *******
<127.0.0.1> ESTABLISH LOCAL CONNECTION FOR USER: wluser
ok: [localhost] => {
    "changed": false,
    "invocation": {
        "module_args": {
            "checksum_algorithm": "sha1",
            "follow": false,
            "get_attributes": true,
            "get_checksum": true,
            "get_md5": null,
            "get_mime": true,
            "path": "'/tmp/my  private.txt'"
        }
    },
    "stat": {
        "exists": false
    }
}

TASK [Store directory owner's UID in a variable] ******************************************************************************
task path: /home/wluser/formatstring.yml:36
Sunday 12 November 2023  22:02:57 -0600 (0:00:00.352)       0:00:00.489 *******
ok: [localhost] => {
    "ansible_facts": {
        "owner_uid": "baduser"
    },
    "changed": false
}

TASK [debug] ******************************************************************************************************************
task path: /home/wluser/formatstring.yml:40
Sunday 12 November 2023  22:02:57 -0600 (0:00:00.020)       0:00:00.510 *******
ok: [localhost] => {
    "msg": "Detected user is: baduser"
}

TASK [Get directory owner] ****************************************************************************************************
task path: /home/wluser/formatstring.yml:43
Sunday 12 November 2023  22:02:57 -0600 (0:00:00.019)       0:00:00.529 *******
fatal: [localhost]: FAILED! => {
    "msg": "template error while templating string: expected token 'name', got 'string'. String: {{ tomcat_home_item | regex_replace('^\\\\s*'|'\\\\s*$', '') }}"
}

NO MORE HOSTS LEFT ************************************************************************************************************
PLAY RECAP ********************************************************************************************************************
localhost                  : ok=7    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0

As you can see, I'm getting baduser instead of correct user wluser due to quoting/formatting issues with variable source_files.

I then attempted to remove the quotes but that got me runtime error.

Can you please suggest how can i get the stats to the file considering the formatting of source_files mentioned initially in the playbook cannot be changed.

1

There are 1 best solutions below

2
U880D On BEST ANSWER

How can I get the stats to the file considering the formatting of source_files

Assuming the output of the ls -ltr command is correct, as well the content of source_files. For files

~/test$ ls -ltr 'test file' 'test path' 'test path/test file'
-rw-r--r--. 1 ansible_user users 0 Nov 13 08:00 test file
-rw-r--r--. 1 ansible_user users 0 Nov 13 08:00 test path/test file

test path:
total 0
-rw-r--r--. 1 ansible_user users 0 Nov 13 08:00 test file

a minimal example playbook


```---
- hosts: localhost
  become: false
  gather_facts: false

  vars:

    FILE: 'test file'
    PATH: 'test path'

  tasks:

  - set_fact:
      SOURCE_FILES: "'test file','test path/test file'"

  - stat:
      path: 'test file'
    register: result

  - debug:
      msg: "{{ result.stat.path }}"

  - stat:
      path: "{{ FILE }}"
    register: result

  - debug:
      msg: "{{ result.stat.path }}"

  - stat:
      path: "{{ PATH }}/{{ FILE }}"
    register: result

  - debug:
      msg: "{{ result.stat.path }}"

  - debug:
      msg:
        - "Content: {{ SOURCE_FILES }}"
        - "Type: {{ SOURCE_FILES | type_debug }}"
        - "List of files: {{ SOURCE_FILES | split(',') }}"

  - stat:
      path: "{{ SOURCE_FILES | split(',') | first | replace(\"'\",'') }}"
    register: result

  - debug:
      msg: "{{ result.stat.path }}"

  - stat:
      path: "{{ SOURCE_FILES | split(',') | last | replace(\"'\",'') }}"
    register: result

  - debug:
      msg: "{{ result.stat.path }}"

will result into an output of

TASK [stat] ******************************************************
ok: [localhost]

TASK [debug] *****************************************************
ok: [localhost] =>
  msg: test file

TASK [stat] ******************************************************
ok: [localhost]

TASK [debug] *****************************************************
ok: [localhost] =>
  msg: test file

TASK [stat] ******************************************************
ok: [localhost]

TASK [debug] *****************************************************
ok: [localhost] =>
  msg: test path/test file

TASK [debug] *****************************************************
ok: [localhost] =>
  msg:
  - 'Content: ''test file'',''test path/test file'''
  - 'Type: AnsibleUnicode'
  - 'List of files: [u"''test file''", u"''test path/test file''"]'

TASK [stat] ******************************************************
ok: [localhost]

TASK [debug] *****************************************************
ok: [localhost] =>
  msg: test file

TASK [stat] ******************************************************
ok: [localhost]

TASK [debug] *****************************************************
ok: [localhost] =>
  msg: test path/test file

If the content of source_files is a Comma Separated Value (CSV) string with explicit quoted values and quote character single quote (') (... annot: which it makes non-RFC conform then), to make a list of file names out of it again

  • Split on delimiter comma (,) via split(',')
  • Remove the explicit quote character single quote (') for all values via replace(\"'\",'')

Please take not that files can not contain single quote anymore as that would run into an error again. It would fail in example for

~/test$ touch "andrew's.file"
~/test$ ls -al and*
-rw-r--r--. 1 ansible_user users 0 Nov 13 09:30 andrew's.file
-rw-r--r--. 1 ansible_user users 0 Nov 13 09:30 and.yml

Thanks To