通过 csv 文件元素的 Ansible 循环

问题描述 投票:0回答:2

sample.csv:

table_name,column_name,prefix
segment_100,test1:null:string,x:y/1:z/1
segment_100,test2_name:null:string,p:q/1
segment_101,test3_name:null:string,foo

Ansible 剧本:

- hosts: localhost

  tasks:

 - name: Read CSV file
   read_csv:
     path: sample.csv
   register: vms

 - debug:
     msg: "{{vms.list}}"

 - name: Run shell command for each prefix
   debug:
     msg: "Running shell command for table -> {{item.0.table_name}} in column -> {{item.0.column_name}} for prefix -> {{item.1}}"
   with_nested:
     - "{{vms.list}}"
     - "{{vms.list[0].prefix.split(':')}}"

注意: 我目前正在使用

"{{vms.list[0].prefix.split(':')"
加载列表中的第一项只是为了描述场景,但理想情况下它应该是每个表和列的循环。

输出:

TASK [Read CSV file] ******************************************************************************************************************************************************************************************
ok: [localhost]

TASK [debug] **************************************************************************************************************************************************************************************************
ok: [localhost] => {
    "msg": [
        {
            "column_name": "test1:null:string",
            "prefix": "x:y/1:z/1",
            "table_name": "segment_100"
        },
        {
            "column_name": "test2_name:null:string",
            "prefix": "p:q/1",
            "table_name": "segment_100"
        },
        {
            "column_name": "test3_name:null:string",
            "prefix": "foo",
            "table_name": "segment_101"
        }
    ]
}

TASK [Run shell command for each prefix] **********************************************************************************************************************************************************************
ok: [localhost] => (item=[{u'prefix': u'x:y/1:z/1', u'table_name': u'segment_100', u'column_name': u'test1:null:string'}, u'x']) => {
    "msg": "Running shell command for table -> segment_100 in column -> test1:null:string for prefix -> x"
}
ok: [localhost] => (item=[{u'prefix': u'x:y/1:z/1', u'table_name': u'segment_100', u'column_name': u'test1:null:string'}, u'y/1']) => {
    "msg": "Running shell command for table -> segment_100 in column -> test1:null:string for prefix -> y/1"
}
ok: [localhost] => (item=[{u'prefix': u'x:y/1:z/1', u'table_name': u'segment_100', u'column_name': u'test1:null:string'}, u'z/1']) => {
    "msg": "Running shell command for table -> segment_100 in column -> test1:null:string for prefix -> z/1"
}
ok: [localhost] => (item=[{u'prefix': u'p:q/1', u'table_name': u'segment_100', u'column_name': u'test2_name:null:string'}, u'x']) => {
    "msg": "Running shell command for table -> segment_100 in column -> test2_name:null:string for prefix -> x"
}
ok: [localhost] => (item=[{u'prefix': u'p:q/1', u'table_name': u'segment_100', u'column_name': u'test2_name:null:string'}, u'y/1']) => {
    "msg": "Running shell command for table -> segment_100 in column -> test2_name:null:string for prefix -> y/1"
}
ok: [localhost] => (item=[{u'prefix': u'p:q/1', u'table_name': u'segment_100', u'column_name': u'test2_name:null:string'}, u'z/1']) => {
    "msg": "Running shell command for table -> segment_100 in column -> test2_name:null:string for prefix -> z/1"
}
ok: [localhost] => (item=[{u'prefix': u'foo', u'table_name': u'segment_101', u'column_name': u'test3_name:null:string'}, u'x']) => {
    "msg": "Running shell command for table -> segment_101 in column -> test3_name:null:string for prefix -> x"
}
ok: [localhost] => (item=[{u'prefix': u'foo', u'table_name': u'segment_101', u'column_name': u'test3_name:null:string'}, u'y/1']) => {
    "msg": "Running shell command for table -> segment_101 in column -> test3_name:null:string for prefix -> y/1"
}
ok: [localhost] => (item=[{u'prefix': u'foo', u'table_name': u'segment_101', u'column_name': u'test3_name:null:string'}, u'z/1']) => {
    "msg": "Running shell command for table -> segment_101 in column -> test3_name:null:string for prefix -> z/1"
}

场景:

我需要为每个“前缀”值(用冒号分隔)运行一个shell脚本对应于每个“table_name”“column_name”

期望的输出:

TASK [Run shell command for each prefix] **********************************************************************************************************************************************************************
ok: [localhost] => (item=[{u'prefix': u'x:y/1:z/1', u'table_name': u'segment_100', u'column_name': u'test1:null:string'}, u'x']) => {
    "msg": "Running shell command for table -> segment_100 in column -> test1:null:string for prefix -> x"
}
ok: [localhost] => (item=[{u'prefix': u'x:y/1:z/1', u'table_name': u'segment_100', u'column_name': u'test1:null:string'}, u'y/1']) => {
    "msg": "Running shell command for table -> segment_100 in column -> test1:null:string for prefix -> y/1"
}
ok: [localhost] => (item=[{u'prefix': u'x:y/1:z/1', u'table_name': u'segment_100', u'column_name': u'test1:null:string'}, u'z/1']) => {
    "msg": "Running shell command for table -> segment_100 in column -> test1:null:string for prefix -> z/1"
}
ok: [localhost] => (item=[{u'prefix': u'p:q/1', u'table_name': u'segment_100', u'column_name': u'test2_name:null:string'}, u'p']) => {
    "msg": "Running shell command for table -> segment_100 in column -> test2_name:null:string for prefix -> p"
}
ok: [localhost] => (item=[{u'prefix': u'p:q/1', u'table_name': u'segment_100', u'column_name': u'test2_name:null:string'}, u'q/1']) => {
    "msg": "Running shell command for table -> segment_100 in column -> test2_name:null:string for prefix -> q/1"
}
ok: [localhost] => (item=[{u'prefix': u'foo', u'table_name': u'segment_101', u'column_name': u'test3_name:null:string'}, u'foo']) => {
    "msg": "Running shell command for table -> segment_101 in column -> test3_name:null:string for prefix -> foo"
}

基本上,我希望为 CSV 的每个行项目的每个 prefix 字符串(以冒号分隔)运行 shell 脚本。

注意:我目前使用的是以下Ansible版本

$ ansible --version
  ansible 2.9.9
   config file = /etc/ansible/ansible.cfg
   configured module search path = [u'/xyz/users/test/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
   ansible python module location = /usr/lib/python2.7/site-packages/ansible
   executable location = /usr/bin/ansible
   python version = 2.7.5 (default, May 27 2022, 11:27:32)
ansible ansible-2.x ansible-facts
2个回答
2
投票

前注:您使用的是过时且不受支持的 Ansible 版本,需要尽快升级。请参阅支持矩阵。我在下面给出的解决方案适用于最新版本的 ansible。我在这篇文章的底部给出了 ansible 2.9 的解决方法。


将冒号分隔的前缀转换为列表:

prefixes: "{{ ['prefix: '] | ansible.builtin.product(vms.list | map(attribute='prefix') | map('split', ':')) | map('join') | map('from_yaml') }}"

给予:

{
    "prefixes": [
        {
            "prefix": [
                "x",
                "y/1",
                "z/1"
            ]
        },
        {
            "prefix": [
                "p",
                "q/1"
            ]
        },
        {
            "prefix": [
                "foo"
            ]
        }
    ]
}

将它们与来自 csv 的初始列表相结合:

vms_data: "{{ vms.list | zip(prefixes) | map('combine') }}"

给:

{
    "vms_data": [
        {
            "column_name": "test1:null:string",
            "prefix": [
                "x",
                "y/1",
                "z/1"
            ],
            "table_name": "segment_100"
        },
        {
            "column_name": "test2_name:null:string",
            "prefix": [
                "p",
                "q/1"
            ],
            "table_name": "segment_100"
        },
        {
            "column_name": "test3_name:null:string",
            "prefix": [
                "foo"
            ],
            "table_name": "segment_101"
        }
    ]
}

使用

subelements
过滤器在该数据结构上循环。这是一个完整的剧本来测试:

---
- hosts: localhost
  gather_facts: false

  vars:
    prefixes: "{{ ['prefix: '] | ansible.builtin.product(vms.list | map(attribute='prefix') | map('split', ':')) | map('join') | map('from_yaml') }}"
    vms_data: "{{ vms.list | zip(prefixes) | map('combine') }}"
    

  tasks:

    - name: Read CSV file
      ansible.builtin.read_csv:
        path: sample.csv
      register: vms

    - name: Run shell command for each prefix
      ansible.builtin.debug:
        msg: "Running shell command for table -> {{ item.0.table_name }} in column -> {{ item.0.column_name }} for prefix -> {{ item.1 }}"
      loop: "{{ vms_data | subelements('prefix') }}"

给出:

$ ansible-playbook csv_loop.yml 

PLAY [localhost] ******************************************************************************************************************************************************************************************

TASK [Read CSV file] **************************************************************************************************************************************************************************************
ok: [localhost]

TASK [Run shell command for each prefix] ******************************************************************************************************************************************************************
ok: [localhost] => (item=[{'table_name': 'segment_100', 'column_name': 'test1:null:string', 'prefix': ['x', 'y/1', 'z/1']}, 'x']) => {
    "msg": "Running shell command for table -> segment_100 in column -> test1:null:string for prefix -> x"
}
ok: [localhost] => (item=[{'table_name': 'segment_100', 'column_name': 'test1:null:string', 'prefix': ['x', 'y/1', 'z/1']}, 'y/1']) => {
    "msg": "Running shell command for table -> segment_100 in column -> test1:null:string for prefix -> y/1"
}
ok: [localhost] => (item=[{'table_name': 'segment_100', 'column_name': 'test1:null:string', 'prefix': ['x', 'y/1', 'z/1']}, 'z/1']) => {
    "msg": "Running shell command for table -> segment_100 in column -> test1:null:string for prefix -> z/1"
}
ok: [localhost] => (item=[{'table_name': 'segment_100', 'column_name': 'test2_name:null:string', 'prefix': ['p', 'q/1']}, 'p']) => {
    "msg": "Running shell command for table -> segment_100 in column -> test2_name:null:string for prefix -> p"
}
ok: [localhost] => (item=[{'table_name': 'segment_100', 'column_name': 'test2_name:null:string', 'prefix': ['p', 'q/1']}, 'q/1']) => {
    "msg": "Running shell command for table -> segment_100 in column -> test2_name:null:string for prefix -> q/1"
}
ok: [localhost] => (item=[{'table_name': 'segment_101', 'column_name': 'test3_name:null:string', 'prefix': ['foo']}, 'foo']) => {
    "msg": "Running shell command for table -> segment_101 in column -> test3_name:null:string for prefix -> foo"
}

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

过时 Ansible 版本的解决方法,其中过滤器

split
不存在,其中
list
是强制性的以从
map
中获取列表并且可能不完全支持 FQCN(完全限定的集合名称)<= Please upgrade to a 尽快支持的版本

---
- hosts: localhost
  gather_facts: false

  tasks:

    - name: Read CSV file
      read_csv:
        path: sample.csv
      register: vms

    - name: Compute prefixes to perform combination
      set_fact:
        vms_data: >-
          {{
            vms_data | d([])
            +
            [item | combine({'prefix': item.prefix.split(':')})]
          }}
      loop: "{{ vms.list }}"

    - name: Run shell command for each prefix
      debug:
        msg: "Running shell command for table -> {{ item.0.table_name }} in column -> {{ item.0.column_name }} for prefix -> {{ item.1 }}"
      loop: "{{ vms_data | subelements('prefix') }}"
 

0
投票

简化前缀列表

    - debug:
        msg: "{{ item.0.table_name }} {{ '%-22s' % (item.0.column_name) }} {{ item.1 }}"
      with_subelements:
        - "{{ vms.list|zip(prefixes)|map('combine') }}"
        - prefix
      vars:
        prefixes: "{{ vms.list|
                      map(attribute='prefix')|
                      map('split', ':')|
                      map('community.general.dict_kv', 'prefix') }}"

给予

  msg: segment_100 test1:null:string      x
  msg: segment_100 test1:null:string      y/1
  msg: segment_100 test1:null:string      z/1
  msg: segment_100 test2_name:null:string p
  msg: segment_100 test2_name:null:string q/1
  msg: segment_101 test3_name:null:string foo

完整的测试剧本示例

- hosts: localhost

  tasks:

    - read_csv:
        path: /tmp/sample.csv
      register: vms

    - debug:
        msg: "{{ item.0.table_name }} {{ '%-22s' % (item.0.column_name) }} {{ item.1 }}"
      with_subelements:
        - "{{ vms.list|zip(prefixes)|map('combine') }}"
        - prefix
      vars:
        prefixes: "{{ vms.list|
                      map(attribute='prefix')|
                      map('split', ':')|
                      map('community.general.dict_kv', 'prefix') }}"
© www.soinside.com 2019 - 2024. All rights reserved.