在 Ansible 中转义双花括号
Escaping double curly braces in Ansible
如何在 Ansible 1.9.2 中转义双花括号?
例如,如何在下面的 shell 命令中转义双花括号?
- name: Test
shell: "docker inspect --format '{{ .NetworkSettings.IPAddress }}' instance1"
这个:
- name: Test
shell: "docker inspect --format {% raw %}'{{ .NetworkSettings.IPAddress }}' {% endraw %} instance1"
应该可以
另一种方法是使用像 \{\{ .NetworkSettings.IPAddress \}\}
这样的反斜杠
希望对您有所帮助
我设法使用一个小脚本解决了我的问题:
#!/usr/bin/env bash
docker inspect --format '{{ .NetworkSettings.IPAddress }}' ""
以及下面的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 不允许转义双花括号!
每当您在 Ansible 中遇到字符冲突问题时,经验法则就是将它们输出为 Jinja 表达式中的字符串。
所以您可以使用 {{ '{{' }}
:
而不是 {{
- debug: msg="docker inspect --format '{{ '{{' }} .NetworkSettings.IPAddress {{ '}}' }}' instance1"
这是一个基本干净且 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','') }}"
您现在在变量 _container_ip
中有了 Docker 容器的 IP。我还在我的文章 The Marriage of Ansible with Docker.
中发布了这个解决方法
[2015-11-03 更新] 删除了容器查询标准输出的空格。
[更新 2015-11-04] 顺便说一句,官方 Ansible 存储库中有两个拉取请求,通过恢复 Docker 模块返回的事实,可以使这个解决方法变得不必要。所以你可以通过 docker_containers[0].NetworkSettings.IPAddress
访问 docker 容器的 IP。因此,请为这些拉取请求投票:
试用 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{{'}}'}}"
反斜杠“\”似乎不起作用
Ansible 2.0 中的新功能是能够使用 !unsafe
标记将值声明为不安全。
在您的示例中,您可以这样做:
- name: Test
shell: !unsafe "docker inspect --format '{{ .NetworkSettings.IPAddress }}' instance1"
See the docs 了解详情。
我有一个类似的问题:我需要 post 一个由包含一些 go 模板变量的 jinja2 模板制作的 JSON 文档(是的,我知道 :-P),例如
"NAME_TEMPLATE": %{{service_name}}.%{{stack_name}}.%{{environment_name}}
试图在
之间围栏这部分模板
{% raw %} ... {% endraw %}
没有用,因为 ansible 中有某种魔法会 运行 模板和变量替换两次(我不确定,但它确实看起来像这样)
您在尝试使用模板时得到 "undefined variable 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}}",
这是 的更短替代方案;用双括号将整个字符串括起来:
shell: "docker inspect --format {{ '{{ .NetworkSettings.IPAddress }}' }} instance1"
我无法得到@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
已经提到了使用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
如何在 Ansible 1.9.2 中转义双花括号?
例如,如何在下面的 shell 命令中转义双花括号?
- name: Test
shell: "docker inspect --format '{{ .NetworkSettings.IPAddress }}' instance1"
这个:
- name: Test
shell: "docker inspect --format {% raw %}'{{ .NetworkSettings.IPAddress }}' {% endraw %} instance1"
应该可以
另一种方法是使用像 \{\{ .NetworkSettings.IPAddress \}\}
希望对您有所帮助
我设法使用一个小脚本解决了我的问题:
#!/usr/bin/env bash
docker inspect --format '{{ .NetworkSettings.IPAddress }}' ""
以及下面的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 不允许转义双花括号!
每当您在 Ansible 中遇到字符冲突问题时,经验法则就是将它们输出为 Jinja 表达式中的字符串。
所以您可以使用 {{ '{{' }}
:
{{
- debug: msg="docker inspect --format '{{ '{{' }} .NetworkSettings.IPAddress {{ '}}' }}' instance1"
这是一个基本干净且 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','') }}"
您现在在变量 _container_ip
中有了 Docker 容器的 IP。我还在我的文章 The Marriage of Ansible with Docker.
[2015-11-03 更新] 删除了容器查询标准输出的空格。
[更新 2015-11-04] 顺便说一句,官方 Ansible 存储库中有两个拉取请求,通过恢复 Docker 模块返回的事实,可以使这个解决方法变得不必要。所以你可以通过 docker_containers[0].NetworkSettings.IPAddress
访问 docker 容器的 IP。因此,请为这些拉取请求投票:
试用 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{{'}}'}}"
反斜杠“\”似乎不起作用
Ansible 2.0 中的新功能是能够使用 !unsafe
标记将值声明为不安全。
在您的示例中,您可以这样做:
- name: Test
shell: !unsafe "docker inspect --format '{{ .NetworkSettings.IPAddress }}' instance1"
See the docs 了解详情。
我有一个类似的问题:我需要 post 一个由包含一些 go 模板变量的 jinja2 模板制作的 JSON 文档(是的,我知道 :-P),例如
"NAME_TEMPLATE": %{{service_name}}.%{{stack_name}}.%{{environment_name}}
试图在
之间围栏这部分模板{% raw %} ... {% endraw %}
没有用,因为 ansible 中有某种魔法会 运行 模板和变量替换两次(我不确定,但它确实看起来像这样)
您在尝试使用模板时得到 "undefined variable 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}}",
这是
shell: "docker inspect --format {{ '{{ .NetworkSettings.IPAddress }}' }} instance1"
我无法得到@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
已经提到了使用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