我的目标是拥有一个灵活的Ansible角色,其中变量的值可以按此优先顺序(从最大到最小)提供:
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')
插件)当前实现的限制?
答案 0 :(得分:1)
使用单个变量名称无法做到这一点。
我能想到的唯一解决方法是使用set_fact
:
- set_fact:
location: "{{ lookup('env', 'LOCATION' ) | ternary (lookup('env', 'LOCATION' ), omit) }}"
这样,如果环境变量LOCATION
不存在/为空,则任务不会分配值(omit
),并且将使用角色的默认值(即不会被覆盖)。
您可以在调用角色之前将其放置在pre_tasks
中,也可以放在角色tasks/main.yml
理由:
您带来的整个问题是在整个过程中使用单个变量名称,但是:
vars
部分中定义变量后,它优先于defaults
中定义的变量(即使评估将在以后进行 - 查找插件与问题无关)Ansible处理变量的“优先级链”(在运行任何任务之前),一旦遇到定义,它就会停止。在评估实际值时,执行时没有进一步“返回”。
注:
我已经能够找到一种“解决”这个问题的方法:
[]
现在我在“vars”区域而不是“默认”区域中定义“默认值”。
但你不必。您无需将default_location
变量放入vars
。您可以在defaults
中定义它(该值在执行时使用)。