【问题标题】:Try to dynamically generate array Jinja2尝试动态生成数组 Jinja2
【发布时间】:2019-11-08 21:12:51
【问题描述】:

我尝试根据给定的类型动态构建一个数组(我初始化为空的 fe_components)——这些类型来自现实生活中的配置文件。

每个给定类型的数组也来自配置文件。

为了简化我的考试,我把所有的变量都写在一个剧本里。

我遍历类型并建立相应数组的名称,我想将其内容捆绑在一起。

- hosts : all

  vars:

     # types and fe_components_XX come in real life from different config files
     types:
       - rs
       - gg


     fe_components_gg:
         - gg_frontend'

     fe_components_rs:
         - rs_frontend_1
         - rs_frontend_2
         - storybook

     # init empty array to dynamically fill in
     fe_components: []

  tasks:

   # This is what I want to get (written in a static statement)
   - debug: msg="{{ fe_components_rs + fe_components_gg }}"

   # My dynamic approach fails:
   # try to dynamically build up the array for given types
   - set_fact:
       my_dyn_var: >-
          {% for item in types -%}
             {% set varname = 'fe_components_' ~ item -%}
             {{  fe_components + varname  }}
          {% endfor -%}


   - name: test it
     debug:
          msg: " {{ my_dyn_var }}"

当我运行它时,我的连接以 “只能将列表(而不是 \"unicode\")连接到列表” 消息结束 .

fatal: [frank-lap]: FAILED! => {"msg": "Unexpected templating type error occurred on ({% for item in types -%}\n   {% set varname = 'fe_components_' ~ item -%}\n   {{  fe_components + varname  }}\n{% endfor -%}): can only concatenate list (not \"unicode\") to list"}

我做错了什么?

【问题讨论】:

    标签: ansible jinja2


    【解决方案1】:

    以下满足您的要求。要点:

    • 如果可以使用标准 ansible 循环、过滤器和模块来分配变量,请不要使用冗长的 jinja2 模板来分配变量
    • 不需要初始化空变量,可以使用default filter
    • 动态构造 var 名称时,必须使用 array notationvars lookup 来获取它。

    我们开始吧:

    ---
    - name: My test play
      hosts : localhost
      gather_facts: false
    
      vars:
         types:
           - rs
           - gg
           - notexists
    
         fe_components_gg:
             - gg_frontend
    
         fe_components_rs:
             - rs_frontend_1
             - rs_frontend_2
             - storybook
    
      tasks:
    
        - name: Static demo of what we are looking for
          debug:
            msg: "{{ fe_components_rs + fe_components_gg }}"
    
        - name: Build my list dynamically from typed list
          vars:
            list_name: "fe_components_{{ item }}"
          set_fact:
            my_dyn_var : "{{ my_dyn_var | default([]) + lookup('vars', list_name, default=[]) }}"
          loop: "{{ types }}"
          loop_control:
            label: "{{ list_name }}"
    
        - name: Show my dynamic var
          debug:
            var: my_dyn_var
    

    结果:

    PLAY [My test play] *****************************************************************************************************************************************************************************************************************************************************
    
    TASK [Static demo of what we are looking for] ***************************************************************************************************************************************************************************************************************************
    ok: [localhost] => {
        "msg": [
            "rs_frontend_1",
            "rs_frontend_2",
            "storybook",
            "gg_frontend"
        ]
    }
    
    TASK [Build my list dynamically from typed list] ************************************************************************************************************************************************************************************************************************
    ok: [localhost] => (item=fe_components_rs)
    ok: [localhost] => (item=fe_components_gg)
    ok: [localhost] => (item=fe_components_notexist)
    
    TASK [Show my dynamic var] **********************************************************************************************************************************************************************************************************************************************
    ok: [localhost] => {
        "my_dyn_var": [
            "rs_frontend_1",
            "rs_frontend_2",
            "storybook",
            "gg_frontend"
        ]
    }
    
    PLAY RECAP **************************************************************************************************************************************************************************************************************************************************************
    localhost                  : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0  
    

    【讨论】:

    • 酷,tnx @Zeitounator
    • 由于您是 SO 新手,请花点时间阅读What should I do when someone answers my question。您应该避免“谢谢”会稀释网站上的信息的 cmets。感谢 SO 上的人们的方式是支持并接受他们的答案,并自己对其他问题给出好的答案。
    • @901Franco:我刚刚拒绝了您对我的回答的修改。那个属于评论或对您自己的问题进行编辑。请花一些时间浏览帮助部分并熟悉该站点的功能。同时,我遇到了您的问题,并且正在编辑答案以解决它。请在您自己的问题中添加某些类型列表可能未定义的信息。
    • @901Franco:已编辑答案并修复了您的问题(您仍然需要通过编辑您的问题而不是我的答案来添加)。
    【解决方案2】:

    我刚刚升级到V2.9.0的ansible版本确实有问题,现在输出就像Zeitounator的一样。

    我知道我的情况也有效:

      - name: Build my list dynamically from typed list
          vars:
            list_name: "fe_components_{{ item }}"
          set_fact:
            my_dyn_var : "{{ my_dyn_var | default([]) + lookup('vars', list_name) }}"
          loop: "{{ types }}"
          loop_control:
            label: "{{ list_name }}"
          when: vars[list_name] is defined
    
    
    TASK [Build my list dynamically from typed list] ***********************************************************************************************************************************************
    ok: [localhost] => (item=fe_components_rs)
    ok: [localhost] => (item=fe_components_gg)
    skipping: [localhost] => (item=fe_components_notexists) 
    
    
    

    【讨论】:

    • 请阅读我的答案下方的 cmets 并编辑您的问题以添加必要的信息(即可能未定义类型列表并且在这种情况下您会收到错误),否则没有人会理解为什么会这样实际上是一个中肯的答案。此外,如果一个答案解决了您的问题,您应该接受它,让每个人都没有解决方案。
    【解决方案3】:

    在我的第一个示例中,我从组合数组开始,上面的解决方案(使用查找变量)效果很好。 在继续我的项目时,我还需要组合类型化字典的子元素。

    - name: My test play
      hosts : localhost
      gather_facts: false
    
      vars:
         types:
           - rs
           - gg
           - notexists
    
         # backend
         be_components: {}
         solr_cores: {}
    
         backend_config_rs:
            be_components :
              rs-document:   { dbaccess: True,  version: latest,  mvn_id: rs-document }
              rs-attachments:{ dbaccess: True,  version: latest,  mvn_id: rs-attachments }
            cores:
              rs: { name: rs_core, dir:  /var/solr/data/jurisdict }       
    
    
         backend_config_gg:
            be_components :
              gg-document:   { dbaccess: True,  version: latest,  mvn_id: gg-document }
              gg-importer:   { dbaccess: True,  version: latest,  mvn_id: gg-importer }
            cores:
              rs: { name: gg_core, dir:  /var/solr/data/law }      
    
      tasks:
    
      # Static demo of what I currently do
      - name: "dyn-config | combine backend variables with RS backend config"
        set_fact: 
           be_components: "{{ be_components | combine ( backend_config_rs.be_components ) }}"
           solr_cores:    "{{ solr_cores | combine ( backend_config_rs.cores ) }}"
        when: "backend_config_rs is defined"
    
      - name: "dyn-config | combine backend variables with GG backend config"
        set_fact: 
           be_components: "{{ be_components | combine ( backend_config_gg.be_components ) }}"
           solr_cores:    "{{ solr_cores | combine ( backend_config_gg.cores ) }}"
        when: "backend_config_gg is defined"
    
      - debug: var=be_components
      - debug: var=solr_cores
    
    

    但后来我尝试以动态方式执行此操作,我发现查找 vars 访问不会返回 dicts 的子元素。

      - name: "try with lookup"
        vars:
            listname:   "backend_config_{{ item }}"    
        set_fact:
           be_components: "{{ be_components | combine (lookup('vars', listname.components)) }}"
        loop: "{{ types }}"
        loop_control:
            label: "{{ listname }}"       
        when: vars[listname] is defined       
    
    

    我明白了

    FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'ansible.utils.unsafe_proxy.AnsibleUnsafeText object' has no attribute 'components'\n
    

    有没有办法通过查找变量访问字典的子元素?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-01-15
      • 2015-04-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-15
      • 2021-03-03
      相关资源
      最近更新 更多