我正在尝试使用以下模板生成 CSV 输出文件: 主机名;登录;UID;GID;评论;SUDO 启用;Last_Login_Date
此任务必须根据 /etc/passwd 中的信息检查 UID >= 1000 的每个用户的此信息。注释与 /etc/passwd 中的注释字段相同。如果用户具有 SUDO 权限,则必须仅显示 YES 或 NO。对于 Last_Login_Date,如果用户从未登录过该系统,则应显示 N/A。
对于此任务,我提供了 Ansible playbook 解决方案,但我不知道如何在创建 CSV 文件时修复以下错误。
剧本:
tasks:
- name: Check User List
shell:
cmd: |
awk -F ':' '{ if ($3 >= 999 && $7 != "/sbin/nologin") print $1 }' /etc/passwd
register: user_list_result
- name: Get info on /etc/passwd
ansible.builtin.shell: "grep ^{{ item }}: /etc/passwd"
loop: "{{ user_list_result.stdout_lines }}"
register: user_info_results
- 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
- name: Check Last Login Date
ansible.builtin.shell: "lastlog -u {{ item.item }} | awk 'NR==2 { print $4 }'"
loop: "{{ user_info_results.results }}"
register: last_login_results
- name: Build CSV File
ansible.builtin.template:
src: "userlist_template.j2"
dest: "output.csv"
vars:
user_info_results: "{{ user_info_results.results }}"
sudo_status_results: "{{ sudo_status_results.results }}"
last_login_results: "{{ last_login_results.results }}"
我来到了这个 Jinja2 模板:
Hostname;Login;UID;GID;Comments;SUDO Enabled;Last_Login_Date
{% for user_info in user_info_results %}
{{ inventory_hostname }};{{ user_info['item'] }};{{ user_info.stdout.split(':')[2] }};{{ user_info.stdout.split(':')[3] }};{{ user_info.stdout.split(':')[4] }};{{ sudo_status_results[loop.index0].stdout }};{{ last_login_results[loop.index0].stdout | default('N/A') }}
{% endfor %}
但是当我运行此剧本时,出现以下错误:
The error was: ansible.errors.AnsibleUndefinedVariable: 'str object' has no attribute 'item'
Ansible 似乎正在检查字符串对象,但它是一个 dict 对象。我怎样才能实现建议的文件?
getent
模块而不是手动解析文件。
现在介绍模板结构。如果我们出于调试目的对其进行简化,我们会发现
user_info_results
变量似乎没有您期望的结构:
Hostname;Login;UID;GID;Comments;SUDO Enabled;Last_Login_Date
{% for user_info in user_info_results %}
{{ inventory_hostname }};{{ user_info }}
{% endfor %}
Hostname;Login;UID;GID;Comments;SUDO Enabled;Last_Login_Date
localhost;results;
localhost;skipped;
localhost;changed;
localhost;msg;
因此,使用变量的嵌套
results
对象可以修复模板:
Hostname;Login;UID;GID;Comments;SUDO Enabled;Last_Login_Date
{% for user_info in user_info_results.results %}
{{ inventory_hostname }};{{ user_info['item'] }};{{ user_info.stdout.split(':')[2] }};{{ user_info.stdout.split(':')[3] }};{{ user_info.stdout.split(':')[4] }};{{ sudo_status_results.results[loop.index0].stdout }};{{ last_login_results.results[loop.index0].stdout | default('N/A') }}
{% endfor %}
我将 UID 减少到 280 进行测试,因为我本地没有任何 UID >= 1000:
Hostname;Login;UID;GID;Comments;SUDO Enabled;Last_Login_Date
localhost;_coreml;280;280;CoreML Services;NO;
localhost;_sntpd;281;281;SNTP Server Daemon;NO;
localhost;_trustd;282;282;trustd;NO;
localhost;_darwindaemon;284;284;Darwin Daemon;NO;
localhost;_notification_proxy;285;285;Notification Proxy;NO;
localhost;_oahd;441;441;OAH Daemon;NO;
为什么会发生这种情况?虽然看起来有点令人惊讶,但有记录: 注册变量的优先级高于任务变量。