带循环的 Ansible 用户部署任务

Ansible user deployment task with loop

我已经启动了一个用于用户部署的 ansible 角色,并在 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

在 tasks/main.yml 中循环创建用户。

- 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 }}"

我想将一些文件复制到新创建的用户主目录,例如 .bashrc 或配置文件。

有没有办法创建一个内循环和外循环来将这些文件复制到任何新创建的用户

更新: 我创建了这样的任务:

- 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"

但是当我 运行 任务时我得到了这个错误:

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"}

您可以使用嵌套循环 [1],例如:

- 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 }}"

或者使用一个简单的循环 include_tasks,而包含的任务文件有自己的循环 [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

我相信你想要一个嵌套循环。您可以使用 jinja2 expression to merge lists and iterate over them with product() filter.

nested loop with with_nested 也有较旧的语法,但首选 product()。例如,with_nested 看起来如下:

- 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

输出:

$ 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