简体   繁体   中英

Ansible user deployment task with loop

I have started an ansible role for user deployment and created some variables in defaults/main.yml:

bootstrap_users:
 - name: test1
   comment: "test user 1"
   shell: "/bin/bash"
   password: "<hashed password>"
   groups: []
   sshpubkey: "<public ssh key"
   home: "/home/test1"
   create_home: yes
 - name: test2
   comment: "test user 2"
   shell: "/bin/bash"
   password: "<hashed password>"
   groups: []
   sshpubkey: "<public ssh key"
   home: "/home/test2"
   create_home: yes

in tasks/main.yml to create users in loop.

- name: "Create users"
  user:
    name: "{{ item.name }}"
    comment: "{{ item.comment|default('test user') }}"
    shell: "{{ item.shell|default('/bin/bash') }}"
    password: "{{ item.password|default('1234') }}"
    groups: "{{ ','.join(item.groups|default([])) }}"
    state: present
    update_password: on_create
    create_home: "{{ item.create_home|default(yes) }}"
    home: "{{ item.home|default('/home/{{ item.name }}') }}"
  loop: "{{ bootstrap_users|default([]) }}"
  loop_control:
    label: "{{ item.name }}"

I want to copy some files to the newly created user homes like .bashrc or profile.

Is there a way to crate a inner and outer loop to copy those files to any newly created user

Update: I've created the task like this:

- name: "Copy user shell settings files"
  copy:
    src: "{{ item[1].src }}"
    dest: "{{ item[0].home | default('/home/' ~ item[0].name) }}/{{ item[1].dest }}"
    owner: "{{ item[0].name }}"
    group: "{{ (item[0].name }}"
    mode: "{{ item[1].mode | default('0600') }}"
  loop: "{{ [ bootstrap_users|default([]), bash_files|default([]) ] }}"
  loop_control:
    label: "{{ item[0].name }}/{{ item[1].name }}"
  vars:
    bash_files:
      - name: bashrc
        src: "bash/bashrc"
        dest: ".bashrc"
        mode: "0600"
      - name: profile
        src: "bash/profile"
        dest: ".profile"
        mode: "0600"
      - name: bash_aliases
        src: "bash/bash_aliases"
        dest: ".bash/bash_aliases"
        mode: "0600"
      - name: bash_functions
        src: "bash/bash_functions"
        dest: ".bash/bash_functions"
        mode: "0600"

But when I run the task I got this error:

TASK [base_role : Copy user shell settings files] ****************************************************************
fatal: [172.20.2.4]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'dict object' has no attribute 'src'\n\nThe error appears to be in '/home/andre/Dokumente/Ansible Development/Ansible-BaseRole/roles/base_role/tasks/system_setup/os-settings-user_deployment.yml': line 96, column 3, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n- name: \"Copy user shell settings files\"\n  ^ here\n"}

You could use a nested loop [1], something like:

- name: Install users configuration
  copy:
    dest: "{{ item[0].home | default('/home/' ~ item[0].name) }}/{{ item[1].path }}"
    group: "{{ (item[0].groups|default([]))[0] | default(item[0].name) }}"
    mode: "{{ item[1].mode | default('u=rw') }}"
    owner: "{{ item[0].name }}"
    src: "{{ item[1].name }}"
  loop: "{{ (bootstrap_users|default([])) | product(bash_files|default([])) | list }}"
  loop_control:
    label: "{{ item[0].name }}/{{ item[1].name }}"

Or using a simple loop to include_tasks , while the included task file has its own loop [2] :

#main.yaml
- include_tasks: install-config.yaml
  loop: "{{ bootstrap_users|default([]) }}"
  loop_control:
    loop_var: "{{ userentry }}"

#install-config
- name: Install users configuration
  copy:
    dest: "{{ userentry.home | default('/home/' ~ userentry.name) }}/{{ item.path }}"
    group: "{{ (userentry.groups|default([]))[0] | default(userentry.name) }}"
    mode: "{{ item.mode | default('u=rw') }}"
    owner: "{{ userentry.name }}"
    src: "{{ item.name }}"
  loop: "{{ files_to_install|default([]) }}"
  loop_control:
    label: "{{ item.name }}"

[1] https://docs.ansible.com/ansible/latest/user_guide/playbooks_loops.html#iterating-over-nested-lists

[2] https://docs.ansible.com/ansible/latest/user_guide/playbooks_loops.html#defining-inner-and-outer-variable-names-with-loop-var

I believe you want a nested loop. You can use jinja2 expression to merge lists and iterate over them with product() filter .

There is also older syntax with nested loop with with_nested , but product() is preferred. For example, with_nested looks the following:

- name: "Testing, testing..."
  debug:
    msg: "echo MARK {{ item[0].name }} {{ item[1].file }}"
  with_nested:
    - "{{ bootstrap_users }}" 
    - "{{ filedest }}"
  delegate_to: localhost
  vars:
    bootstrap_users:
     - name: test1
     - name: test2
    filedest:
      - file: a/b
      - file: e/f

outputs:

$ ansible .... | grep MARK
TASK [Testing, testing... msg=echo MARK {{ item[0].name }} {{ item[1].file }}] ***
echo MARK test1 a/b
echo MARK test1 e/f
echo MARK test2 a/b
echo MARK test2 e/f
echo MARK test1 a/b
echo MARK test1 e/f
echo MARK test2 a/b
echo MARK test2 e/f

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM