使用数组样式检查主机属性时出现 Ansible 错误

Rob*_*ert 0 ansible ansible-playbook

我有一个 site.yml 剧本,当我使用这个配置时:

- hosts: target
  tags:
    - setup_target
  tasks:
    - name: See some data
      debug: msg={{ hostvars[inventory_hostname][ansible_lsb].codename }}
Run Code Online (Sandbox Code Playgroud)

Ansible 报告我一个错误:

PLAY [target] ***************************************************************** 

GATHERING FACTS *************************************************************** 
ok: [target]

TASK: [See some data] ********************************************************* 
fatal: [target] => One or more undefined variables: dict object has no element {u'release': u'14.04', u'major_release': u'14', u'codename': u'trusty', u'id': u'Ubuntu', u'description': u'Ubuntu 14.04.1 LTS'}

FATAL: all hosts have already failed -- aborting

PLAY RECAP ******************************************************************** 
           to retry, use: --limit @/home/robe/site.retry

target                     : ok=1    changed=0    unreachable=1    failed=0  
Run Code Online (Sandbox Code Playgroud)

但是如果我使用点样式,就像这样:

---
# The main playbook to deploy

# setup our database
- hosts: target
  tags:
    - setup_target
  tasks:
    - name: See some data
      debug: msg={{ hostvars[inventory_hostname].ansible_lsb.codename }}
Run Code Online (Sandbox Code Playgroud)

输出没问题:

PLAY [target] ***************************************************************** 

GATHERING FACTS *************************************************************** 
ok: [target]

TASK: [See some data] ********************************************************* 
ok: [target] => {
    "msg": "trusty"
}

PLAY RECAP ******************************************************************** 
target                     : ok=2    changed=0    unreachable=0    failed=0 
Run Code Online (Sandbox Code Playgroud)

那么,有什么不同呢?对我来说,两者是平等的吗?

ted*_*r42 5

那么,有什么不同呢?对我来说,两者是平等的吗?

这归结为 dicts/hashes 在 Python 中的工作方式,以及它们在 jinja2 和 Ansible 中的工作方式。

如果你有一个 dict 调用data并且你想要foo元素的值,你可以像这样访问它:

data["foo"]
Run Code Online (Sandbox Code Playgroud)

如果省略引号,则需要有一个名为 foo 的变量。

data[foo] # does not work (so far)
Run Code Online (Sandbox Code Playgroud)

jinja2 还允许您使用点样式:

data.foo
Run Code Online (Sandbox Code Playgroud)

让我们假设“foo”元素的值是数字 42。这些都是真的:

data["foo"] = 42
data[foo] # does not work
data.foo = 42
Run Code Online (Sandbox Code Playgroud)

现在,如果您有一个名为 foo 的变量怎么办?在下面的示例中,我们将考虑键 'foo' 的值仍然是 42,而 'bar' 将是 13。

foo = "bar"
data["foo"] = 42
data[bar] = 13
data.foo = 42
Run Code Online (Sandbox Code Playgroud)

要将其转换为您的原始案例,请记住inventory_hostnameansible_lsb都是variables,而不是strings。更令人困惑的是, ansible_lsb 是一本字典。这意味着您原来的括号样式扩展如下:

hostvars["inventory_hostname"][{u'release': u'14.04', u'major_release': u'14', u'codename': u'trusty', u'id': u'Ubuntu', u'description': u'Ubuntu 14.04.1 LTS'}]["codename"]
Run Code Online (Sandbox Code Playgroud)

哎呀。一个 dict 作为一个 dict 的键进入递归自相残杀的海龟。

这就是你的“虚线”风格。

hostvars["inventory_hostname"]["ansible_lsb"]["codename"]
Run Code Online (Sandbox Code Playgroud)

那个也可以稍微翻译一下,让它更清楚一点:

lsb = hostvars["inventory_hostname"]["ansible_lsb"]
lsb["codename"]
Run Code Online (Sandbox Code Playgroud)

这显然是你的意图。