当环境变量不存在时,如何分配默认的Ansible值?

时间:2017-12-12 22:03:24

标签: ansible environment-variables

我的目标是拥有一个灵活的Ansible角色,其中变量的值可以按此优先顺序(从最大到最小)提供:

  1. 从命令行使用' - extra-vars'
  2. 来自环境变量
  3. 来自角色的默认值
  4. 1& 3匹配Ansible变量(http://docs.ansible.com/ansible/latest/playbooks_variables.html#variable-precedence-where-should-i-put-a-variable)记录的优先顺序,因此我将注意力集中在环境变量上。使用lookup('env',...)插件,我能够读取vars/main.yml中的环境变量,并且优先顺序正是我想要的。

    但是,如果未定义环境变量,lookup插件将返回一个空字符串。这意味着为变量分配空字符串而不是保持未定义,以便可以分配默认值。

    Playbook(var-exp.yml)

    - name: Variable experiment
      hosts: all
    
      tasks:
      - import_role:
          name: ansible-role-variable-experiment
    

    角色(ansible-role-variable-experiment)

    任务/ main.yml

    - name: Display value of 'location'
      debug:
        msg: 'location is {{ location }}'
    

    默认/ main.yml

    location: from-defaults-main-yml
    

    乏/ main.yml

    # If used, this will override the value in defaults/main.yml, as expected
    # location: from-vars-main-yml
    
    # Since lookup returns '' when the environment variable doesn't exist,
    # location gets set to '' instead of being left undefined so that the
    # default can be used:
    # location: "{{ lookup('env', 'LOCATION' ) }}"  # -> location == ''
    
    # When the environment variable does not exist, all of these options generate 
    # some value assigned to location so that the default cannot be assigned:
    # location: "{{ lookup('env', 'LOCATION' ) | default(None, true) }}"  # -> location == ''
    # location: "{{ lookup('env', 'LOCATION' ) | default(omit, true) }}"  # -> location == __omit_place_holder__3e8bdbb6cebc653a758afca99607fcf9ec1f99f4
    # location: "{{ lookup('env', 'LOCATION' ) | default('undefined') }}"  # -> location == ''
    # location: "{{ lookup('env', 'LOCATION' ) | reject('undefined') }}"  # -> location == <generator object select_or_reject at 0x10caaef00>
    
    # When the environment variable does not exist, these generate a recursive 
    # loop that crashes the play:
    # location: "{{ lookup('env', 'LOCATION' ) | default(location) }}"
    # location: "{{ lookup('env', 'LOCATION' ) | default(location, true) }}"
    

    执行示例

    使用环境变量:

    LOCATION=from-env-variable ansible-playbook ./var-exp.yml
    

    没有环境变量:

    ansible-playbook ./var-exp.yml
    

    我无法确定实现目标的干净方法。我已经能够找到一种方法来解决问题&#34;这样:

    乏/ main.yml

    default_location: from-default-array-in-vars-main-yml
    
    location: "{{ lookup('env', 'LOCATION' ) | default(default_location, true) }}"
    

    虽然这似乎完成了我想要的,但现在我正在定义&#34;默认&#34;在&#34; vars&#34;区域而不是&#34;默认值&#34;区域。

    Ansible文档说的类似于&#34;如果你做的事情似乎过于复杂,那可能就是。&#34;

    所以,我的问题是: 有没有更简单/更好/更正的方法来实现这一目标?或者,我是否遇到了Ansible 2.4.2(或lookup('env')插件)当前实现的限制?

1 个答案:

答案 0 :(得分:1)

使用单个变量名称无法做到这一点。

我能想到的唯一解决方法是使用set_fact

- set_fact:
    location: "{{ lookup('env', 'LOCATION' ) | ternary (lookup('env', 'LOCATION' ), omit) }}"

这样,如果环境变量LOCATION不存在/为空,则任务不会分配值(omit),并且将使用角色的默认值(即不会被覆盖)。

您可以在调用角色之前将其放置在pre_tasks中,也可以放在角色tasks/main.yml

的顶部

理由:

您带来的整个问题是在整个过程中使用单个变量名称,但是:

  • Ansible中的变量是惰性评估的
  • vars部分中定义变量后,它优先于defaults中定义的变量(即使评估将在以后进行 - 查找插件与问题无关)
  • 无法在Ansible
  • 中取消定义变量

Ansible处理变量的“优先级链”(在运行任何任务之前),一旦遇到定义,它就会停止。在评估实际值时,执行时没有进一步“返回”。

注:

  

我已经能够找到一种“解决”这个问题的方法:

     

[]

     

现在我在“vars”区域而不是“默认”区域中定义“默认值”。

但你不必。您无需将default_location变量放入vars。您可以在defaults中定义它(该值在执行时使用)。