You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

修复Ansible中Jinja2模板生成CSV时的字符串对象属性错误

问题原因

你遇到的错误核心是变量名冲突:在Build CSV File任务中,你将user_info_results重新定义为{{ user_info_results.results }},和之前任务注册的user_info_results变量重名,导致Ansible解析模板时该变量结构被意外破坏,原本的字典列表被解析为字符串,从而无法访问item属性。

此外还有两个潜在问题:

  1. 第一个任务的awk条件$3 >= 999不符合你要求的UID≥1000,会错误包含UID=999的用户;
  2. Last_Login_Date的default('N/A')不会生效——因为lastlog返回空字符串时变量是已定义状态,default仅对未定义变量生效。

修复现有Playbook的步骤

1. 修正变量名冲突

在Build CSV File任务中更换变量名,避免和注册变量重名:

- name: Build CSV File
  ansible.builtin.template:
    src: "userlist_template.j2"
    dest: "output.csv"
  vars:
    users_passwd_data: "{{ user_info_results.results }}"
    users_sudo_data: "{{ sudo_status_results.results }}"
    users_login_data: "{{ last_login_results.results }}"

2. 对应修改Jinja2模板

调整模板中的变量引用,同时修复空登录日期的显示逻辑:

Hostname;Login;UID;GID;Comments;SUDO Enabled;Last_Login_Date
{% for user_info in users_passwd_data %}
{{ inventory_hostname }};{{ user_info['item'] }};{{ user_info.stdout.split(':')[2] }};{{ user_info.stdout.split(':')[3] }};{{ user_info.stdout.split(':')[4] }};{{ users_sudo_data[loop.index0].stdout }};{% if users_login_data[loop.index0].stdout | trim == '' %}N/A{% else %}{{ users_login_data[loop.index0].stdout }}{% endif %}
{% endfor %}

3. 修正用户筛选条件

将第一个任务的awk条件改为$3 >= 1000,符合需求:

- name: Check User List
  shell:
    cmd: |
       awk -F ':' '{ if ($3 >= 1000 && $7 != "/sbin/nologin") print $1 }' /etc/passwd
  register: user_list_result

4. 确保sudo命令权限

在Check SUDO Privileges任务中添加become: yes,查询其他用户的sudo列表通常需要sudo权限:

- name: Check SUDO Privileges
  ansible.builtin.shell: "sudo -U {{ item.item }} -l | grep -q '(ALL) ALL' && echo 'YES' || echo 'NO'"
  loop: "{{ user_info_results.results }}"
  register: sudo_status_results
  become: yes

更优的Playbook(推荐)

使用Ansible内置的getent模块获取结构化的passwd数据,避免shell命令的字符串解析错误,更可靠且符合最佳实践:

---
- name: Generate user CSV report
  hosts: your_target_hosts
  gather_facts: no

  tasks:
    # 获取结构化的/etc/passwd数据
    - name: Retrieve passwd entries
      ansible.builtin.getent:
        database: passwd
        split: ':'

    # 筛选符合条件的用户(UID≥1000,shell不是/sbin/nologin)
    - name: Filter target users
      ansible.builtin.set_fact:
        target_users: "{{ getent_passwd | dict2items | selectattr('value.2', '>=', 1000) | selectattr('value.6', '!=', '/sbin/nologin') | list }}"

    # 检查sudo权限
    - name: Check sudo privileges
      ansible.builtin.command: "sudo -U {{ item.key }} -l | grep -q '(ALL) ALL' && echo 'YES' || echo 'NO'"
      loop: "{{ target_users }}"
      register: sudo_status
      become: yes

    # 获取最后登录日期
    - name: Get last login date
      ansible.builtin.command: "lastlog -u {{ item.key }} | awk 'NR==2 {print $4}'"
      loop: "{{ target_users }}"
      register: last_login

    # 生成CSV文件
    - name: Build CSV file
      ansible.builtin.template:
        src: userlist_template.j2
        dest: "/tmp/user_report.csv"

对应的Jinja2模板:

Hostname;Login;UID;GID;Comments;SUDO Enabled;Last_Login_Date
{% for user in target_users %}
{{ inventory_hostname }};{{ user.key }};{{ user.value.2 }};{{ user.value.3 }};{{ user.value.4 }};{{ sudo_status.results[loop.index0].stdout }};{% if last_login.results[loop.index0].stdout | trim == '' %}N/A{% else %}{{ last_login.results[loop.index0].stdout }}{% endif %}
{% endfor %}

内容的提问来源于stack exchange,提问作者Mnbaku_AJ

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 06:12:08