引用循环项时使用 jinja2 定界符的替代方法

Alternatives to using jinja2 delimiters when referencing loop item

此处为新手 Ansible 用户。所以我试图自动更改密码,并在播放中的循环中添加了一个条件,以便仅当用户存在于系统上时才更改密码。

我让剧本检索了所有用户的列表,然后在 运行 循环之前将其与 when 语句一起使用。

---
- hosts: localhost
  become: yes
  gather_facts: no
  vars_files:
    - /etc/ansible/userlist.yaml

  tasks:
    - name: definepass
      ansible.builtin.shell: tail -1 passlist.yaml
      register: newpassword

    - name: get data
      shell: "getent passwd | cut -d: -f1"
      register: allusers

    - name: change password
      user:
        name: "{{ item }}"
        update_password: always
        password: "{{ 'newpassword'|password_hash('sha256') }}"
      loop: "{{ uservar }}"
      when: '"item" in allusers'
- uservar:
    - 'testuser' # real user on system
    - 'testuser2' # also a real user on system
    - 'fakeuser' # fake username, does not yet exist on system
- user: 'testuser'

(作为参考,当我在正常的 shell window 中执行 getent passwd | cut -d: -f1 时,我得到了我应该得到的:一长串用户名以及我想要的用户名。 )

系统似乎不理解这种情况,因为它跳过了所有用户。


TASK [definepass] *********************************************************************************************************************************************
changed: [localhost]

TASK [get data] ***********************************************************************************************************************************************
changed: [localhost]

TASK [change password] ****************************************************************************************************************************************
skipping: [localhost] => (item=testuser) 
skipping: [localhost] => (item=testuser2) 
skipping: [localhost] => (item=fakeuser) 

PLAY RECAP ****************************************************************************************************************************************************
localhost                  : ok=2    changed=2    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0 

(新密码本应更改为无效。)

抱歉,如果修复很简单,但我不确定如何最好地解决这个问题。

问:"条件跳过所有用户。"

A:命令的标准输出存储在已注册字典 allusers 的属性 stdout 中。在您的情况下,属性 stdout_lines 更有用。看看变量

    - name: get data
      shell: "getent passwd | cut -d: -f1"
      register: allusers
    - debug:
        var: allusers

但是,在这种情况下,您应该使用 Ansible 模块 getent 而不是模块 shell。数据将自动存储在变量getent_passwd中,例如

    - name: get data
      getent:
        database: passed
    - debug:
        var: getent_passwd

那么,就可以使用条件中的数据了

    - debug:
        msg: "{{ item }} exists on the system."
      loop: "{{ uservar }}"
      when: item in getent_passwd
      vars:
        uservar:
          - 'testuser'  # real user on system
          - 'testuser2' # also a real user on system
          - 'fakeuser'  # fake username, does not yet exist on system
          - admin

举个例子

skipping: [localhost] => (item=testuser) 
skipping: [localhost] => (item=testuser2) 
skipping: [localhost] => (item=fakeuser) 
ok: [localhost] => (item=admin) => 
  msg: admin exists on the system.

您可能想知道条件是如何工作的。 getent_passwd 是一个字典,测试 in 需要一个列表(Jinja 术语中的序列)。当用作列表时,字典会转换为其键的列表。


当您保留命令的注册输出时,条件的正确形式是

      when: item in allusers.stdout_lines