applying sudo_user to a list of tasks

Hello,

My playbook is run with sudo: yes
Inside this playbook, I would like to run a task list several times. Each time it would be for a different user.

for simplification, the task list could be:

tasks:

  • ping:
  • ping:
  • ping

I managed to write the task list as

tasks:

  • ping:
    sudo_user: {{ u }}
  • ping:
    sudo_user: {{ u }}
  • ping

sudo_user: {{ u }}

and reuse this task list. But this does not seem right. I wish I could parametrize the sudo_user outside of the task list.

the “include” directive does not seem to accept a sudo_user parameter.

of course, the sudo_user can be set at the play level

  • hosts: all
    sudo: yes
    sudo_user: john
    roles:
  • developer

but is there any way i can “loop” over a play ; something in the order of :

  • hosts: all
    sudo: yes
    sudo_user: {{ item }}
    roles:
  • developer

with_items:

  • john
  • dave

thank you very much for your insight !
Jerome

No, you can’t do this.

You should do any looping inside of the task files.

Also, stuff like sudo_user: {{ item}} needs to be quoted, like so, sudo_user: “{{ item }}” since YAML will think the “{” is starting a hash.

ok thank you I will try that.

it seems to me that in this case, each task will have to change the sudo user in a loop. It sounds like a lot of sudo user switching ( Number of task * Number of users in the loop) but why not.

what is the rationale behind your sentence “you should do any looping inside of the task files” ? is that a strong design decision to protect something else in the architecture or could it evolve at some point ?

thanks
Jerome

I’m not really sure why you need to ping as a sudo user from 3 different accounts, can you explain the use case before we start to figure out how to model it? :slight_smile:

Hello,
no :wink: the 3 pings where just for a simplified example of what I was trying to achieve. I confirm they are useless !

given a list of users (john, dave, …) I want to setup several configs / applications in their /home dir.
I have 2 options :

  • install everything with sudo=yes and then try to correctly change all the ownership modes so that it appears as if the user had actually set up the environment
  • install everything with sudo=yes and sudo_user=item, so that the configuration / installation takes place under the correct user and all the ownership modes are immediatly correct

for example i want each user to start with its own installation of nvm with a pre-installed set of node.js versions

I hope this clarifies my use case. Maybe there are other ways to do this ?

I think this is ultimately about being able to pass sudo_user to a role and have it automatically apply that to all tasks in the role that don’t have the “sudo_user” set.

Can’t do that now, but then you could just have:

roles:

  • { role: install_things, user: bob, sudo_user: bob }
  • { role: install_things, user: sam, sudo_user: sam }

Hello,

yes, sudo_user at the role level could be a solution. Are you open for a patch on something like that ?

however, is there a way to iterate over the addition of roles in a play ? something like

roles:

  • { role: install_things, user: “{{item}}”, sudo_user: “{{item}}” }
    with_items: userlist

in order to avoid repeating the same line with N users ?

Thank you
Jerome

Totally fine with sudo_user being acceptable as a role parameter and doing the right thing.

Include + with_items was a patch we got a long time ago that caused a lot of user questions because everybody wanted to use it with inventory variables, and tasks must exist prior to inventory being parsed, so no, I’m not ok with with_items being applied to roles like that. The solution is to either list all the items out flat, or do the looping inside the tasks files.

ok thank you for the clarification
I will try to understand how the roles are implemented.

I appreciate that you are totally fine with a patch as long as it does the right thing :wink:

thanks a lot for creating ansible and nurturing a great community btw !
Jerome

Hello,

I had a look at the code in order to see how we could add the sudo & sudo_user options at the role level just like so :

roles:

  • { role: install_things, user: bob, sudo_user: bob }
  • { role: install_things, user: sam, sudo_user: sam }

extract from the code:

if os.path.isfile(task):
nt = dict(include=task, vars=has_dict)
if when:
nt[‘when’] = when
if with_items:
nt[‘with_items’] = with_items
new_tasks.append(nt)

The problem I see is that the tasks of the role are injected in the play as an “include” task. So basically if we add the sudo/sudo_user at the role level, we would currently need to add it also at the “include” level in order for it to work.

Since you seemed to be against adding sudo/sudo_user at the include level, I prefer asking you what you think about this (and maybe I am wrong with my understanding of how the code actually works)

Thank you
Jerome

Yes!

Hello,

I understood the “Yes!” as a “go for it !”.

Here is a pull request for the implementation of sudo/sudo_user at the role level (and and include level because roles are implemented as include tasks)

https://github.com/ansible/ansible/pull/3579

Usage is pretty straight forward :

  • include: myfile.yml
    sudo: yes
    sudo_user: tom

or

  • hosts: all
    roles:
  • { role: myrole, sudo: yes, sudo_user: jerry }

As explained in the pull request comment, “the deepest setting encountered in the hierarchy of playbook/play/role/include/tasks is kept for any task below.” which is I think the intuitive expectation.

I hope I didn’t break anything.
Existing playbooks should be pretty safe since sudo/sudo_user were failing at the “include” level, and not extracted from the dict at the “role” level.

Best regards,
Jerome

Nice!

I’ve wanted this for a while!

Thanks!

Mark

Merging a ton of bits and doing a lot of bug fixing on things this weekend, so hope to get to this soon.

Thanks!

+1, me too. Looking forward to this new functionality.

Lorin