在Ansible中转义双花括号


77

如何在Ansible 1.9.2中转义双花括号?

例如,如何在以下shell命令中转义大括号?

- name: Test 
  shell: "docker inspect --format '{{ .NetworkSettings.IPAddress }}' instance1"

编辑:添加了我正在使用的Ansible版本
Davide Guerri

注意:这里的问题是inspectdocker client命令输入了go模板的输入,该模板使用双花括号作为jinja2。我需要一种将花括号添加到目标服务器上运行的最终命令Ansile的方法。参见docs.docker.com/reference/commandline/inspect
Davide Guerri 2015年

Answers:


122

每当您在Ansible中遇到字符冲突时,经验法则就是在Jinja表达式中将它们作为字符串输出。

因此,{{您可以使用{{ '{{' }}

- debug: msg="docker inspect --format '{{ '{{' }} .NetworkSettings.IPAddress {{ '}}' }}' instance1"

Jinja2文档中的主题“转义”。


1
我无法正常工作。我开始认为我正在丢失某些东西...我明白了:changed: [docker-server.local] => {"changed": true, "cmd": "docker inspect --format '{# .NetworkSettings.IPAddress #}' glance-api.os-in-a-box", "delta": "0:00:00.029344", "end": "2015-08-29 17:36:37.962143", "rc": 0, "start": "2015-08-29 17:36:37.932799", "stderr": "", "stdout": "172.17.1.6", "warnings": []}
Davide Guerri

不需要关闭大括号
Nelson G.

1
这行不通。我不知道为什么会有这么多的投票-这仅适用于一个级别。如果创建变量raw_var: '{{ '{{' }}something{{ '}}' }}' 并在其他位置引用它command: "{{ raw_var }}",则会得到Error: something is undefined
Megakoresh

2
raw_var: "{{ '{{' }}something{{ '}}' }}"
udondan

谢谢,简单聪明。
乔什

53

这个:

- name: Test 
  shell: "docker inspect --format {% raw %}'{{ .NetworkSettings.IPAddress }}' {% endraw %} instance1"

应该管用

另一种方法是使用反斜杠 \{\{ .NetworkSettings.IPAddress \}\}

希望能帮助到你


2
谢谢菲利普(Filippe),但我已经尝试过这两种方法,但它们都没用:(
Davide Guerri 2015年

您正在使用哪个版本的ansible?
菲利普

6
我刚刚在1.9.2中对此进行了测试并{ raw }...{% endraw %}为我工作。转义虽然确实不起作用。这将导致\\{\\{ .NetworkSettings.IPAddress \\}\\}
udondan

1
而且,作为奖励,甚至不可能调试上一步的输出!:fatal: [docker-server.local] => Failed to template {{test}}: Failed to template docker inspect --format '{{ .NetworkSettings.IPAddress }}' glance-api.os-in-a-box: template error while templating string: unexpected '.'
Davide Guerri

1
可以使用以下技巧进行调试:- name: Find ipv6 of of some-host shell: docker inspect -f "{% raw %} {{ .NetworkSettings.GlobalIPv6Address }} {% endraw %}" {{some.host}} > tmp.txt - command: cat tmp.txt register: result - debug: msg="{{ result.stdout }}"
lanwen

25

尝试使用ansible 2.1.1.0

{%raw%} ... {%endraw%}块似乎是清晰的方法

- name: list container images and name date on the server
  shell: docker ps --format {%raw%}"{{.Image}} {{.Names}}"{%endraw%}

只需要转义前导'{{'

tasks:
- name: list container images and names
  shell: docker ps --format "{{'{{'}}.Image}} {{'{{'}}.Names}}"

转义尾部的'}}'无害,但更难阅读。

tasks:
- name: list container images and names
  shell: docker ps --format "{{'{{'}}.Image{{'}}'}} {{'{{'}}.Names{{'}}'}}"

反斜杠“ \”似乎不起作用


8

Ansible 2.0的新功能是可以使用!unsafe标记将值声明为不安全。

在您的示例中,您可以执行以下操作:

- name: Test 
  shell: !unsafe "docker inspect --format '{{ .NetworkSettings.IPAddress }}' instance1"

有关详细信息,请参阅文档


1
为什么是2.5?... 2.0
Konstantin Suvorov

2
嘘,我说2.0

它适用于2.4.6,并且我在文档中找到了解决方案,因此可以确认。
einarc

单引号和双引号的互换看起来更多linux-途 !unsafe 'docker inspect --format "{{ .NetworkSettings.IPAddress }}" instance1'
Timmy Chiu

就个人而言,我喜欢将所有Jinja模板都放在双引号中,以提示任何阅读该代码的人。大多数具有字符串插值的语言都将单引号视为文字,将双引号视为可模板化,我尝试将其复制为ansible(即使不是必需的)。另外,用单引号将参数包装在shell脚本中会减少可以解释为“'”和“ \”的字符数,如果变量中包含“ $”,则有可能防止出现问题。不管哪种引用方式都有效
Ben

5

我有一个类似的问题:我需要发布一个由jinja2模板制成的JSON文档,其中包含一些go模板变量(是的,我知道:-P),例如

"NAME_TEMPLATE": %{{service_name}}.%{{stack_name}}.%{{environment_name}}

试图将模板的这部分围起来

{% raw %} ... {% endraw %}

没用,是因为ansible中有某种魔术会运行两次模板和变量替换(我不确定,但是肯定是这样)

service_name尝试使用模板时,您最终得到“未定义的变量”。

所以,我最终使用的组合!unsafe{% raw %} ... {% endraw %}定义后来在模板中使用的事实。

- set_fact:
   __rancher_init_root_domain: "{{ rancher_root_domain }}"
   #!unsafe: try to trick ansible into not doing substitutions in that string, then use %raw% so the value won't substituted another time
   __rancher_init_name_template: !unsafe "{%raw%}%{{service_name}}.%{{stack_name}}.%{{environment_name}}{%endraw%}"

- name: build a template for a project
  set_fact:
    __rancher_init_template_doc: "{{ lookup('template', 'templates/project_template.json.j2') }}"

模板包含以下内容:

    "ROOT_DOMAIN":"{{__rancher_init_root_domain}}",
    "ROUTE53_ZONE_ID":"",
    "NAME_TEMPLATE":"{{__rancher_init_name_template }}",
    "HEALTH_CHECK":"10000",

并且输出正常:

"NAME_TEMPLATE": "%{{service_name}}.%{{stack_name}}.%{{environment_name}}",

这太不幸了,但是似乎有时Ansible会做一些奇怪的事情,而这种双重转义的构造是处理它的唯一方法……
WindyFields

4

这是乌冬丹答案的更短的选择;用双括号将整个字符串括起来:

shell: "docker inspect --format {{ '{{ .NetworkSettings.IPAddress }}' }} instance1"

3

我设法使用一个小脚本解决了我的问题:

#!/usr/bin/env bash

docker inspect --format '{{ .NetworkSettings.IPAddress }}' "$1"

和下面的Ansible玩

- copy:
    src: files/get_docker_ip.sh
    dest: /usr/local/bin/get_docker_ip.sh
    owner: root
    group: root
    mode: 0770

- shell: "/usr/local/bin/get_docker_ip.sh {{ SWIFT_ACCOUNT_HOSTNAME }}"
  register: swift_account_info

然而,令人惊讶的是Ansible不允许转义双花括号!


2

raw已经提到了使用解决方案,但不幸的是,答案中的命令对我不起作用。

没有ansible:

docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' docker_instance_name

与ansible:

- name: Get ip of db container
  shell: "{% raw %}docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' docker_instance_name{% endraw %}"
  register: db_ip_addr
- debug:
  var: db_ip_addr.stdout

1

我无法获得@Ben的工作答案(shell: !unsafe ...

接下来是对OP问题的完整解答(正在运行!),并针对Ansible> 2.0进行了更新。

---
# file: play.yml

- hosts: localhost
  connection: local
  gather_facts: no
  vars:
    # regarding !unsafe, please see:
    # https://docs.ansible.com/ansible/latest/user_guide/playbooks_advanced_syntax.html
    #
    - NetworkSettings_IPAddress: !unsafe "{{.NetworkSettings.IPAddress}}"
  tasks:
    - shell: "docker inspect --format '{{NetworkSettings_IPAddress}}' instance1"
      register: out
    - debug: var="{{item}}"                                                                                                   
      with_items:                                                                                                             
        - out.cmd                                                                                                             
        - out.stdout                                                                                                          

输出:([警告]已删除)

# ansible-playbook play.yml
PLAY [localhost] ***************************************************************

TASK [shell] *******************************************************************
changed: [localhost]

TASK [debug] *******************************************************************
ok: [localhost] => (item=out.cmd) => {
    "item": "out.cmd", 
    "out.cmd": "docker inspect --format '{{.NetworkSettings.IPAddress}}' instance1"
}
ok: [localhost] => (item=out.stdout) => {
    "item": "out.stdout", 
    "out.stdout": "172.17.0.2"
}

PLAY RECAP *********************************************************************
localhost                  : ok=2    changed=1    unreachable=0    failed=0   

# ansible --version | head -1
ansible 2.6.1

-7

这是一个非常干净和Ansible的本机解决方法,不依赖于docker --inspect花括号。我们假设之前我们刚刚使用Ansible docker模块引用了一个容器:

- name: query IP of client container
  shell: "docker exec {{ docker_containers[0].Id }} hostname -I"
  register: _container_query

- name: get IP of query result
  set_fact:
    _container_ip: "{{ _container_query.stdout | regex_replace('\\s','') }}"

现在,在Variable中具有Docker容器的IP _container_ip。我还在我的文章《与Docker的Ansible的婚姻》中发布了此变通办法。

[更新2015-11-03]删除了容器查询标准输出的空格。

[Update 2015-11-04]顺便说一句,官方的Ansible存储库中有两个pull请求,通过恢复Docker模块返回的事实,该解决方案变得不必要。因此,您可以通过来访问Docker容器的IP docker_containers[0].NetworkSettings.IPAddress。因此,请为这些拉取请求投票:


非常好。这个答案与当前的docker实现开箱即用。就我而言,我将不得不添加一些处理,因为我要在某个容器上添加一个附加接口。然而,这种方法确实是极简主义和简洁的。谢谢!
Davide Guerri

为了完整性,我在某些容器中添加了多个接口:虚拟网桥和veth。我正在谈论的项目在这里:github.com/dguerri/dockerstack
Davide Guerri 2015年

9
这没有回答问题“如何在Ansible 1.9.2中转义双花括号?”
augurar

3
不赞成投票,因为此答案对于99%的用例完全没有帮助。可行的答案:通过jinja tpl进行卷曲打印:stackoverflow.com/a/32283447/293064
Jay Taylor
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.