Search code examples
ansible

Pass variable between plays on same hosts with different user


I have an inventory with hosts where some process are running from other users unknown in my inventory.

My ssh key is already copied for the main ansible user as for these other users

I need to build a playbook where I will get the username running some process in one play and in an other play connect to same server with this username and make some changes using ENV of obtained user

For security reasons I can't configure become_user: "{{ process_username }}" and run my tasks with the same main ansible user as it can't escalate privileges.

This is what I've tried so far:

- name: Get process username with default ansible_user 
  hosts: all
  tasks:
    - name: Get process username
      shell: ps -eo uname:20,cmd | grep process_name | grep -v grep | head -1 | awk '{print $1}'
      register: process_user

- name: Make some changes as process_user.stdout user
  hosts: all
  remote_user: "{{ hostvars[inventory_hostname].process_user.stdout }}"
  tasks:
    - name: Make changes
      lineinfile:
        src: somefile
        dst: "{{ansible_env.HOME}}/process_name/somefile"

Unfortunately, ansible fires an error telling me {{ hostvars[inventory_hostname].process_user.stdout }} is undefined in the second play as my remote_user.

Any suggestions?


Solution

  • remote_user is a keyword, not a variable. When used at play level, its content will be evaluated before the actual play starts looping on the hosts. So at that point inventory_hostname is unset.

    You need to either:

    • use the remote_user keyword at task level. This is ok if you only have one or a few tasks in your second play (else you'll have to repeat it many times):
      - name: Make some changes
        hosts: all
        tasks:
          - name: Add a line to a file as process_user.stdout user
            remote_user: "{{ hostvars[inventory_hostname].process_user.stdout }}"
            ansible.builtin.lineinfile:
              line: Some line to add
              path: "{{ ansible_env.HOME }}/process_name/somefile"
      
    • Use the ansible_user variable instead. This has the same effect but in your specific case, that var will be evaluated every time it is used hence for each task in your play for the corresponding host. This is much more convenient if you have many tasks:
      - name: Make some changes as process_user.stdout user
        hosts: all
        vars:
          ansible_user: "{{ hostvars[inventory_hostname].process_user.stdout }}"
        tasks:
          - name: Add a line to a file
            ansible.builtin.lineinfile:
              line: Some line to add
              path: "{{ ansible_env.HOME }}/process_name/somefile"
          - name: Create a new directory
            ansible.builtin.file:
              path: "{{ ansible_env.HOME }}/process_name/somedir"
              state: directory
      

    As pointed out by @U880D in the comments, you can find a good discussion on the difference between the remote_user keyword and the ansible_user variable in this other answer