Ansible接受什么格式将其模板化的字符串变量转换为列表,dicts等?

时间:2017-05-31 11:33:55

标签: python json ansible jinja2

t: ['u']

t_copy_repr: "{{ t }}"

t_copy_yaml: "{{ t | to_yaml() }}"

t_copy_json: "{{ t | to_json() }}"

t_copy_repr是Ansible中的成语,对吧?

但他们是Jinja2模板,we're not supposed to rely on repr in Jinja2

t_copy_yamlt的行为不同。它会产生字符串值'[u]'(即它缺少引号,而不是['u'])。

t_copy_json似乎与t的行为相同。

我在vars文件中开发以下代码时注意到了这一点:

test_servers__admins: 
  "{{ 
    users
      | selectattr('admin', 'defined')
      | selectattr('admin', 'equalto', True)
      | map(attribute='name')
      | list()
      | to_json()
  }}"

我发现| list()是必要的,以避免像'<generator object do_map at 0x7ff2ef210320>'这样的结果。

此处使用类似| to_json()的内容符合Jinja2最佳做法。我认为它还应该有助于检查我的列表中是否包含具有无法进行往返的表示的对象,例如生成器,并复制到另一个变量中。

问题

正确在这种情况下使用| to_json()吗? ansible实际上在模板化变量中接受哪些格式?是否有| to_json()的可能输出,其中ansible不会接受/解释与JSON相同的条款?

Jinja2字符串/ unicode和int / float类型的所有repr()结果都是有效的JSON吗? (如果ansible接受比JSON更窄的东西,则对ansible有效。)。

2 个答案:

答案 0 :(得分:0)

如果my_list变量定义如下:

my_list: ['u']

然后它是Ansible中的列表

  1. 不,每当你想迭代my_list元素时,你不应该使用my_list | list(顺便提一下,如果没有参数,你可以省略空括号),例如{{ my_list | join(',') }}。 /> 您必须使用| list投标,这是真的(如with_items "{{ my_list | map('upper') | list }}") 通常Ansible在内部处理变量作为Python类型。

  2. 不,每次都不需要拨打| to_json,Ansible可以很好地处理类型。

  3. 如果您想尝试使用类型并查看Ansible何时使用哪种类型,您可以使用这个方便的自定义过滤器插件:

    def get_type(src):
        return type(src)
    
    class FilterModule(object):
    
        def filters(self):
            return {
                'get_type': get_type
            }
    

    将其放在您的剧本./filter_plugins/get_type.py附近并使用如下:

    - debug:
        msg: "{{ my_list | get_type }}"
    

答案 1 :(得分:0)

  

对于Jinja2字符串/ unicode和int / float类型的所有repr()结果是否都是有效的JSON?

没有。 Jinja2使用的repr()将返回无效结果,如

python2> print repr("'")
u'\\\\'

u'都不是有效的JSON。

  

(如果ansible接受比JSON更窄的东西,则对ansible有效。)

Ansible似乎接受了python。

# vars file
t: '[__name__]'

# tasks file
- debug:
    var: t

# output from ansible 2.3.0.0 (on python2):
ok: [fedora-25] => {
    "changed": false, 
    "t": [
        "__builtin__"
    ]
}

Ansible似乎也使用泡菜,这有其他限制。

# vars
t: '[__builtins__]'

# debug output
Traceback (most recent call last):
  File "/usr/lib64/python2.7/multiprocessing/queues.py", line 268, in _feed
    send(obj)
TypeError: can't pickle ellipsis objects
# (and hangs)  

Google指出Python 不是是JSON的超集,因为True,False和None的文字不同:

# vars
t: '{{ True | to_json() }}'

# debug output shows t as a string
ok: [fedora-25] => {
    "changed": false, 
    "t": "true"
}

然而,ansible实现确实为列表和dicts的表示解决了这个问题。我不认为它很难为JSON中使用的三个标识符提供绑定(true,false,null)。

# vars
t: "[True, true, None, null, u'\\', 'True', 'true']"

# debug output
ok: [fedora-25] => {
    "changed": false, 
    "t": [
        true, 
        true, 
        null,
        null,
        "\\", 
        "True", 
        "true"
    ]
}

答案

出于某种原因,Ansible努力在字符串值中解析JSON。在查看JSON的语法之后,我相信Ansible正确编辑了这个:除了"\/"to_json不生成)。

但是,它也保证解析Jinja2提供的repr()输出。

因此,为了Ansible的利益,没有必要使用| to_json()。我不希望使用它会导致错误。但是,您的代码读者会感到困惑。他们会预期您的代码正在与Ansible之外的某些软件进行通信。特别是因为Ansible实际上并不在字符串变量中解析JSON。