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

Ansible读取CSV加密密码写入文件报错:'dict'无'stdout'属性

问题分析与解决方案

这个错误的核心原因是你在第二个任务中使用loop注册的output变量结构和第三个任务中调用的方式不匹配:

当任务使用loop并注册变量时,Ansible会返回一个包含results数组的对象,每个数组元素对应一次循环的执行结果(里面才包含stdout字段)。而你在第三个任务中直接调用output.stdout,但output本身并没有这个属性——它只有output.results,所以Ansible报错说dict object has no attribute 'stdout'。

同时,第三个任务的loop是独立遍历routers.list的,和第二个任务的循环没有直接关联,无法直接映射到对应的加密结果。

下面提供几种可靠的解决方案:

方案一:用循环索引关联结果(简单直接)

如果你的CSV文件顺序不会变化,可以通过循环的索引来匹配output.results中的对应项:

- name: Read csv file
  read_csv:
    path: files/ww.csv
    fieldnames: ip,password
    delimiter: ','
  register: routers
  delegate_to: localhost

- name: encrypt password
  command: "ansible-vault encrypt_string --vault-password-file password '{{ router.password }}' --name 'password'"
  loop: "{{ routers.list }}"
  loop_control: loop_var: router
  register: output
  delegate_to: localhost

- name: write file
  copy:
    content: "{{ output.results[index].stdout }}"
    dest: "/tmp/{{ router.ip }}.yaml"
  loop: "{{ routers.list }}"
  loop_control:
    loop_var: router
    index_var: index  # 获取当前循环的索引
  delegate_to: localhost

这里通过index_var拿到当前循环的索引,用它去output.results里找到对应位置的加密结果,前提是两个循环的顺序完全一致。

方案二:将加密结果整理为字典(更可靠)

如果担心顺序变化或者需要更清晰的映射关系,可以把加密结果整理成一个以IP为键的字典,之后直接通过IP查找对应加密内容:

- name: Read csv file
  read_csv:
    path: files/ww.csv
    fieldnames: ip,password
    delimiter: ','
  register: routers
  delegate_to: localhost

- name: encrypt password
  command: "ansible-vault encrypt_string --vault-password-file password '{{ router.password }}' --name 'password'"
  loop: "{{ routers.list }}"
  loop_control: loop_var: router
  register: output
  delegate_to: localhost

# 新增:把加密结果整理为 {IP: 加密后的内容} 的字典
- name: Organize encrypted passwords into a dictionary
  set_fact:
    encrypted_passwords: >-
      {{
        encrypted_passwords | default({}) | combine({
          item.item.ip: item.stdout
        })
      }}
  loop: "{{ output.results }}"

- name: write file
  copy:
    content: "{{ encrypted_passwords[router.ip] }}"
    dest: "/tmp/{{ router.ip }}.yaml"
  loop: "{{ routers.list }}"
  loop_control: loop_var: router
  delegate_to: localhost

这里item.item是因为output.results中的每个元素的item字段就是原来循环中的router对象,我们从中取出IP作为键,把加密后的stdout作为值存入字典,后续直接通过IP取值即可,完全不用依赖循环顺序。

方案三:合并加密与写入任务(结构更简洁)

你也可以把加密和写入操作放到同一个循环里,避免两次循环的关联问题:

- name: Read csv file
  read_csv:
    path: files/ww.csv
    fieldnames: ip,password
    delimiter: ','
  register: routers
  delegate_to: localhost

- name: Encrypt password and write to file
  block:
    - name: encrypt password
      command: "ansible-vault encrypt_string --vault-password-file password '{{ router.password }}' --name 'password'"
      register: encrypted_result
      delegate_to: localhost

    - name: write file
      copy:
        content: "{{ encrypted_result.stdout }}"
        dest: "/tmp/{{ router.ip }}.yaml"
      delegate_to: localhost
  loop: "{{ routers.list }}"
  loop_control: loop_var: router

这个方案中,每个路由器的加密和写入操作在同一个循环迭代中完成,逻辑更连贯,也不会出现变量关联的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 08:21:40