【问题标题】:Is it possible to set a fact of a list in Ansible?是否可以在 Ansible 中设置列​​表的事实?
【发布时间】:2014-05-07 02:16:18
【问题描述】:

是否可以使用set_fact 在 Ansible 中设置包含列表的事实?它的正确语法是什么?

【问题讨论】:

    标签: ansible


    【解决方案1】:

    是的,这是可能的。如另一个答案中所述,您可以使用双引号设置数组,如下所示:

    - name: set foo fact to a list
      set_fact: 
        foo: "[ 'one', 'two', 'three' ]"
    

    但是,我想我会创建另一个答案来表明它也可以添加到现有数组中,如下所示:

    - name: add items to foo list fact
      set_fact: 
        foo: "{{foo}} + [ 'four' ]"
    

    结合这些并将调试添加为剧本(我称之为facts.yml),如下所示:

    ---
    - name: test playbook
      gather_facts: false
      hosts: localhost
      tasks:
        - name: set foo fact to an array
          set_fact: 
            foo: "[ 'one', 'two', 'three' ]"
        - debug: 
            var: foo
        - name: add items to foo array fact
          set_fact: 
            foo: "{{foo}} + [ 'four' ]"
        - debug: 
            var: foo
    

    产生(通过ansible-playbook facts.yml)以下内容:

    PLAY [test playbook] ******************************************************** 
    
    TASK: [set foo fact to an array] ********************************************
    ok: [localhost]
    
    TASK: [debug var=foo] *******************************************************
    ok: [localhost] => {
        "foo": [
            "one", 
            "two", 
            "three"
        ]
    }
    
    TASK: [add items to foo array fact] *****************************************
    ok: [localhost]
    
    TASK: [debug var=foo] *******************************************************
    ok: [localhost] => {
        "foo": [
            "one", 
            "two", 
            "three", 
            "four"
        ]
    }
    
    PLAY RECAP ****************************************************************** 
    localhost                  : ok=4    changed=0    unreachable=0    failed=0   
    

    【讨论】:

    • 很好的答案......不过有一个问题 - !!?!?我们应该知道这件事吗?我在文档中没有看到类似的内容
    • 将项目附加到事实确实很有价值,一直在寻找一段时间才能找到这个
    • 如果我们以foo=[] 开头然后附加一个模板字符串而不是'four',这将如何工作?例如,我将在下面提供一个“答案”来解释这个问题。
    【解决方案2】:

    确实如此。不过,您需要引用整个列表:

    - name: set fact
      set_fact: foo="[ 'one', 'two', 'three' ]"
    
    - name: debug
      debug: msg={{ item }}
      with_items: foo
    

    上述任务应生成以下输出:

    TASK: [set fact] **************************************************************
    ok: [localhost]
    
    TASK: [debug] *****************************************************************
    ok: [localhost] => (item=one) => {
        "item": "one",
        "msg": "one"
    }
    ok: [localhost] => (item=two) => {
        "item": "two",
        "msg": "two"
    }
    ok: [localhost] => (item=three) => {
        "item": "three",
        "msg": "three"
    }
    

    【讨论】:

      【解决方案3】:

      除了已经给出的答案之外,我想向您展示一种不同的方式 使用常规 YAML 语法而不是使用 set_fact 定义列表 Ansible 核心人员喜欢在他们的文档中使用的自定义格式。这 像这种情况下的自定义格式已显示会导致混淆。

      考虑这个例子:

      - name: 'Set the foo variable to a static list using the YAML syntax'
        set_fact:
          foo:
            - 'one'
            - 'two'
            - 'three'
      

      直截了当,对吧?就像您在任何普通的 YAML 文档中所做的一样。所以 为什么不在 Ansible YAML 任务文件中使用它呢?

      关于@lindes-hw 提到的列表组合。不止一个 方法来做到这一点。以下示例使用 Jinja2 语法定义列表:

      - name: 'Set the foo variable to a combined static list using the Jinja2 syntax'
        set_fact:
          foo: '{{ [ "one" ] + [ "two", "three" ] }}'
      
      - name: 'Set the foo variable to a combined static list using the Jinja2 syntax and Jinja2 filters'
        set_fact:
          foo: '{{ [ "one" ] | union([ "two", "three" ]) }}'
      

      第二个示例使用union 过滤器。参考set theory filters in the Ansible docs

      【讨论】:

      • +1 保持简单。 Ansible 的主要卖点之一是您可以使用易于阅读(和编写)的 YAML 语法,所以总是让我感到困惑,为什么许多 Ansible 示例代码无缘无故地令人费解。
      【解决方案4】:

      我有一个类似的要求,即根据 IP 地址列表创建服务器对象列表。

      vars:
        server_ips: one,two,three
      tasks:
        - name: build items list
          set_fact: 
            foo: "{{foo|default([]) + [{'ip': {'addr': item, 'type': 'V4'}}] }}"
          with_items: "{{server_ips.split(',')}}"
        - debug:
            msg: "{{ foo }}"
      

      给出以下输出

      TASK [setup] *******************************************************************
      ok: [localhost]
      
      TASK [build items list] ********************************************************
      ok: [localhost] => (item=one)
      ok: [localhost] => (item=two)
      ok: [localhost] => (item=three)
      
      TASK [debug] *******************************************************************
      ok: [localhost] => {
          "msg": [
              {
                  "ip": {
                      "addr": "one", 
                      "type": "V4"
                  }
              }, 
              {
                  "ip": {
                      "addr": "two", 
                      "type": "V4"
                  }
              }, 
              {
                  "ip": {
                      "addr": "three", 
                      "type": "V4"
                  }
              }
          ]
      }
      

      【讨论】:

      • 为什么不把你的事实放在 vars 下而不是使用默认值?
      • 在 set_fact 循环中构建一个数组很好,很干净,虽然不是 OP 的答案,但这正是我想要的。
      【解决方案5】:

      我不知道功能是否发生了变化——它可能在 2.5 中发生了——但在我看来就像这段代码

      with_items: foo
      

      在示例中不再起作用,您必须使用

      with_items: "{{ foo }}"
      

      我正在使用 Ansible 2.5.2。我得到了这个(不正确的)输出:

      ok:[localhost] => (item=None) => {
          "msg":"foo"
      }
      

      我在此处的文档中找到了更新的语法:
      https://docs.ansible.com/ansible/latest/user_guide/playbooks_loops.html#with-items

      【讨论】:

        【解决方案6】:

        喜欢这个

        - hosts: all
          tasks:
          - set_fact:
              redis_list: |
                {%- set list = [] -%}
                {%- for index in range(1, 5 ) -%}
                  {{ list.append(index)  }}
                {%- endfor -%}
                {{ list }}
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2015-10-30
          • 1970-01-01
          • 2016-08-14
          • 2011-12-07
          • 1970-01-01
          • 2012-05-11
          • 2011-07-09
          相关资源
          最近更新 更多