如何创建一个键值对项目的字典列表并将其附加到Ansible中的原始列表?

huangapple go评论73阅读模式
英文:

How to create a dictionary list of key: value items and append it to the original list in Ansible?

问题

It appears that you're working with Ansible and trying to manipulate a list of user data based on their "ClassType" to add a "path" value to each user. However, there are some issues in your playbook, and you want to achieve a specific output format.

Here's the corrected playbook snippet to achieve the desired output:

- name: If class is full time
  set_fact:
    path: "OU=fulltime,OU=Test OU,DC=localdemo,DC=local"
  when: item.ClassType == "Full Time"
  loop: "{{ data_list }}"

- name: If employment type is part time
  set_fact:
    path: "OU=parttime,OU=Test OU,DC=localdemo,DC=local"
  when: item.ClassType == "Part Time"
  loop: "{{ data_list }}"

- name: If employment type is flexi
  set_fact:
    path: "OU=flexi,OU=Test OU,DC=localdemo,DC=local"
  when: item.ClassType == "Flexi"
  loop: "{{ data_list }}"

- name: Append to original userdata list
  set_fact:
    userdata: "{{ userdata + [{'ClassType': item.ClassType, 'FirstName': item.FirstName, 'LastName': item.LastName, 'path': path}] }}"
  loop: "{{ data_list }}"

This playbook will correctly set the "path" value based on "ClassType" and append the modified user data to the "userdata" list in the desired format.

英文:

I want to create a new dictionary list, 'path: value' to be looped for each user and appended under each item in the user list. The end result would look something like below:

        "userdata": [
            {
                "ClassType": "Full Time",
                "FirstName": "Grace",
                "LastName": "Higgins",
                "path": "OU=fulltime,OU=Test OU,DC=localdemo,DC=local"
            },
            {
                "ClassType": "Part Time",
                "FirstName": "Robert",
                "LastName": "Miller",
                "path": "OU=parttime,OU=Test OU,DC=localdemo,DC=local"
            },
            {
                "ClassType": "Flexi",
                "FirstName": "Jeffrey",
                "LastName": "Keller",
                "path": "OU=flexi,OU=Test OU,DC=localdemo,DC=local"
            }
        ]

The values for path is dependent on the value of the ClassType.

However, when I tried to append the new path: value dictionary list to the original userdata list, the 'path: item.path' is in the wrong layout and also has the wrong value:

TASK [Read_csv_creation : Append to original userdata list] *******************************************************************************************
ok: [localhost] => (item={'FirstName': '}) => {
    "ansible_facts": {
        "userdata": [
            {
                "ClassType": "Full Time",
                "FirstName": "Grace",
                "LastName": "Higgins"
            },
            {
                "ClassType": "Part Time",
                "FirstName": "Robert",
                "LastName": "Miller"
            },
            {
                "ClassType": "Flexi",
                "FirstName": "Jeffrey",
                "LastName": "Keller"
            },
            "path: item.path"
        ]
    },

How can I get the final output as shown below?

        "userdata": [
            {
                "ClassType": "Full Time",
                "FirstName": "Grace",
                "LastName": "Higgins",
                "path": "OU=fulltime,OU=Test OU,DC=localdemo,DC=local"
            },
            {
                "ClassType": "Part Time",
                "FirstName": "Robert",
                "LastName": "Miller",
                "path": "OU=parttime,OU=Test OU,DC=localdemo,DC=local"
            },
            {
                "ClassType": "Flexi",
                "FirstName": "Jeffrey",
                "LastName": "Keller",
                "path": "OU=flexi,OU=Test OU,DC=localdemo,DC=local"
            }
        ]

Below is my tasks file. The variable 'data_list' would be my original list.

    - name: Read input file
      read_csv:
        path: /var/lib/awx/projects/file/creation.csv
        key: FirstName 
        fieldnames: FirstName,LastName,ClassType
        delimiter: ','
      register: userdata

    - name: Initialise data list
      set_fact:
        data_list: []

    - name: Extract the list
      set_fact:
        data_list: "{{ data_list + [{ 'FirstName': item.FirstName, 'LastName': item.LastName, 'ClassType': item.ClassType }] }}"
      loop: "{{ userdata | community.general.json_query('dict.[*][0]') }}"

    - name: Set fact for data_list
      set_fact: 
        data_list: "{{ data_list[1:] }}"

    - name: If class is full time
      set_fact:
        path: "OU=fulltime,OU=Test OU,DC=localdemo,DC=local"
      when: item.ClassType == "Full Time"  
      loop: "{{ data_list  }}"   

    - name: If employment type is part time
      set_fact:
        path: "OU=parttime,OU=Test OU,DC=localdemo,DC=local"
      when: item.ClassType == "Part Time"  
      loop: "{{ data_list  }}"   

    - name: If employment type is flexi
      set_fact:
        path: "OU=flexi,OU=Test OU,DC=localdemo,DC=local"
      when: item.ClassType == "Flexi"  
      loop: "{{ data_list  }}"   

    - name: Append to original userdata list
      set_fact:
        userdata: "{{ data_list + ['path: item.path'] }}"
      loop: "{{ data_list  }}" 

The job run output is as below. I have omitted some of it as it is very lengthy:

TASK [Read_csv_creation : Initialise data list] *******************************************************************************************************
ok: [localhost] => {
    "ansible_facts": {
        "data_list": []
    },
    "changed": false
}

TASK [Read_csv_creation : Read input file] ************************************************************************************************************
ok: [localhost] => {
    "changed": false,
    "dict": {
        " FirstName ": {
            "ClassType": " Employment Type ",
            "FirstName": " FirstName ",
            "LastName": " Last Name "
        },
        "Grace": {
            "ClassType": "Sub Contract",
            "FirstName": "Grace",
            "LastName": "Higgins"
        },
        "Robert": {
            "ClassType": "Contract",
            "FirstName": "Robert",
            "LastName": "Miller"
        },
        "Jeffrey": {
            "ClassType": "Full Time",
            "FirstName": "Jeffrey",
            "LastName": "Keller"
        }
    },
    "invocation": {
        "module_args": {
            "delimiter": ",",
            "dialect": "excel",
            "fieldnames": [
                "FirstName",
                "LastName",
                "ClassType"
            ],
            "key": "FirstName",
            "path": "/var/lib/awx/projects/file/creation.csv",
            "skipinitialspace": null,
            "strict": null,
            "unique": true
        }
    },
    "list": []
}

TASK [Read_csv_creation : Extract the list] ***********************************************************************************************************
ok: [localhost] => (item={'FirstName': ' FirstName ', 'LastName': ' Last Name ', 'ClassType': ' Class Type '}) => {
    "ansible_facts": {
        "data_list": [
            {
                "ClassType": " Class Type ",
                "FirstName": " FirstName ",
                "LastName": " Last Name "
            }
        ]
    },
    "ansible_loop_var": "item",
    "changed": false,
    "item": {
        "ClassType": " Class Type ",
        "FirstName": " FirstName ",
        "LastName": " Last Name ",
    }
}
ok: [localhost] => (item={'FirstName': '}) => {
    "ansible_facts": {
        "data_list": [
            {
                "ClassType": " Class Type ",
                "FirstName": " FirstName ",
                "LastName": " Last Name ",

            }
        ]
    },
    "ansible_loop_var": "item",
    "changed": false,
    "item": {
        "ClassType": "Class Time",
        "FirstName": "Grace",
        "LastName": "Higgins"
    }
}


TASK [Read_csv_creation : Set fact for data_list] *****************************************************************************************************
ok: [localhost] => {
    "ansible_facts": {
        "data_list": [
            {
                "ClassType": "Full Time",
                "FirstName": "Grace",
                "LastName": "Higgins"
            },
            {
                "ClassType": "Part Time",
                "FirstName": "Robert",
                "LastName": "Miller"
            },
            {
                "EmploymentType": "Flexi",
                "FirstName": "Jeffrey",
                "LastName": "Keller"
            }
        ]
    },
    "changed": false
}


TASK [Read_csv_creation : If class type is full time] *******************************************************************************************
ok: [localhost] => (item={'FirstName': 'Grace', 'LastName': 'Higgins', 'ClassType': 'Full Time'}) => {
    "ansible_facts": {
        "path": "OU=fulltime,OU=Test OU,DC=localdemo,DC=local"
    },
    "ansible_loop_var": "item",
    "changed": false,
    "item": {
        "ClassType": "Full Time",
        "FirstName": "Grace",
        "LastName": "Higgins"
    }
}
skipping: [localhost] => (item={'FirstName': 'Robert', 'LastName': 'Miller', 'ClassType': 'Part Time'})  => {
    "ansible_loop_var": "item",
    "changed": false,
    "item": {
        "EmploymentType": "Contract",
        "FirstName": "Robert",
        "LastName": "Miller"
    },
    "skip_reason": "Conditional result was False"
}
skipping: [localhost] => (item={'FirstName': .....
    "ansible_loop_var": "item",
    "changed": false,
    "item": {
        .......
        "ClassType": "Flexi"
    },
    "skip_reason": "Conditional result was False"
}

答案1

得分: 1

给定用于测试的文件 mre

shell> cat /tmp/creation.csv 
Grace,Higgins,Full Time
Robert,Miller,Part Time
Jeffrey,Keller,Flexi

读取 CSV 文件

    - read_csv:
        path: /tmp/creation.csv
        # key: FirstName 
        fieldnames: FirstName,LastName,ClassType
        delimiter: ','
      register: userdata

当你省略参数 key 时,你会得到列表而不会'提取'

  userdata.list:
  - ClassType: Full Time
    FirstName: Grace
    LastName: Higgins
  - ClassType: Part Time
    FirstName: Robert
    LastName: Miller
  - ClassType: Flexi
    FirstName: Jeffrey
    LastName: Keller

要添加属性 path,创建字典 class_path

  class_path:
    Full Time: "OU=fulltime,OU=Test OU,DC=localdemo,DC=local"
    Part Time: "OU=parttime,OU=Test OU,DC=localdemo,DC=local"
    Flexi: "OU=flexi,OU=Test OU,DC=localdemo,DC=local"

从列表 map 属性 ClassType提取 path,并创建哈希列表

  path: "{{ userdata.list|map(attribute='ClassType')|
                          map('extract', class_path)|
                          map('community.general.dict_kv', 'path') }}"

得到

  path:
  - path: OU=fulltime,OU=Test OU,DC=localdemo,DC=local
  - path: OU=parttime,OU=Test OU,DC=localdemo,DC=local
  - path: OU=flexi,OU=Test OU,DC=localdemo,DC=local

zip 列表并 combine 项目。你必须使用 set_facts 因为变量 userdata 已经在 registered vars 中使用过了

    - set_fact:
        userdata: "{{ userdata.list|zip(path)|map('combine') }}"

得到你想要的结果

  userdata:
  - ClassType: Full Time
    FirstName: Grace
    LastName: Higgins
    path: OU=fulltime,OU=Test OU,DC=localdemo,DC=local
  - ClassType: Part Time
    FirstName: Robert
    LastName: Miller
    path: OU=parttime,OU=Test OU,DC=localdemo,DC=local
  - ClassType: Flexi
    FirstName: Jeffrey
    LastName: Keller
    path: OU=flexi,OU=Test OU,DC=localdemo,DC=local

用于测试的完整 playbook 示例

- hosts: localhost

  vars:

    class_path:
      Full Time: "OU=fulltime,OU=Test OU,DC=localdemo,DC=local"
      Part Time: "OU=parttime,OU=Test OU,DC=localdemo,DC=local"
      Flexi: "OU=flexi,OU=Test OU,DC=localdemo,DC=local"

    path: "{{ userdata.list|map(attribute='ClassType')|
                            map('extract', class_path)|
                            map('community.general.dict_kv', 'path') }}"

  tasks:

    - read_csv:
        path: /tmp/creation.csv
        # key: FirstName 
        fieldnames: FirstName,LastName,ClassType
        delimiter: ','
      register: userdata

    - debug:
        var: userdata.list
    - debug:
        var: path

    - set_fact:
        userdata: "{{ userdata.list|zip(path)|map('combine') }}"
    - debug:
        var: userdata

英文:

Given the file for mre testing

shell> cat /tmp/creation.csv 
Grace,Higgins,Full Time
Robert,Miller,Part Time
Jeffrey,Keller,Flexi

read the CSV file

    - read_csv:
        path: /tmp/creation.csv
        # key: FirstName 
        fieldnames: FirstName,LastName,ClassType
        delimiter: ','
      register: userdata

When you omit the parameter key you get the list without 'extracting'

  userdata.list:
  - ClassType: Full Time
    FirstName: Grace
    LastName: Higgins
  - ClassType: Part Time
    FirstName: Robert
    LastName: Miller
  - ClassType: Flexi
    FirstName: Jeffrey
    LastName: Keller

To add the attribute path create the dictionary class_path

  class_path:
    Full Time: "OU=fulltime,OU=Test OU,DC=localdemo,DC=local"
    Part Time: "OU=parttime,OU=Test OU,DC=localdemo,DC=local"
    Flexi: "OU=flexi,OU=Test OU,DC=localdemo,DC=local"

From the list map the attribute ClassType, extract the path, and create the list of the hashes

  path: "{{ userdata.list|map(attribute='ClassType')|
                          map('extract', class_path)|
                          map('community.general.dict_kv', 'path') }}"

gives

  path:
  - path: OU=fulltime,OU=Test OU,DC=localdemo,DC=local
  - path: OU=parttime,OU=Test OU,DC=localdemo,DC=local
  - path: OU=flexi,OU=Test OU,DC=localdemo,DC=local

zip the lists and combine the items. You have to use set_facts because the variable userdata has already been used in registered vars

    - set_fact:
        userdata: "{{ userdata.list|zip(path)|map('combine') }}"

gives what you want

  userdata:
  - ClassType: Full Time
    FirstName: Grace
    LastName: Higgins
    path: OU=fulltime,OU=Test OU,DC=localdemo,DC=local
  - ClassType: Part Time
    FirstName: Robert
    LastName: Miller
    path: OU=parttime,OU=Test OU,DC=localdemo,DC=local
  - ClassType: Flexi
    FirstName: Jeffrey
    LastName: Keller
    path: OU=flexi,OU=Test OU,DC=localdemo,DC=local

<hr>

<sup>

Example of a complete playbook for testing

- hosts: localhost

  vars:

    class_path:
      Full Time: &quot;OU=fulltime,OU=Test OU,DC=localdemo,DC=local&quot;
      Part Time: &quot;OU=parttime,OU=Test OU,DC=localdemo,DC=local&quot;
      Flexi: &quot;OU=flexi,OU=Test OU,DC=localdemo,DC=local&quot;

    path: &quot;{{ userdata.list|map(attribute=&#39;ClassType&#39;)|
                            map(&#39;extract&#39;, class_path)|
                            map(&#39;community.general.dict_kv&#39;, &#39;path&#39;) }}&quot;

  tasks:

    - read_csv:
        path: /tmp/creation.csv
        # key: FirstName 
        fieldnames: FirstName,LastName,ClassType
        delimiter: &#39;,&#39;
      register: userdata

    - debug:
        var: userdata.list
    - debug:
        var: path

    - set_fact:
        userdata: &quot;{{ userdata.list|zip(path)|map(&#39;combine&#39;) }}&quot;
    - debug:
        var: userdata

</sup>

huangapple
  • 本文由 发表于 2023年6月8日 02:26:53
  • 转载请务必保留本文链接:https://go.coder-hub.com/76426128.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定