Втеча з подвійних фігурних дужок в Ansible


78

Як уникнути подвійних фігурних дужок в Ansible 1.9.2?

Наприклад, як я можу уникнути подвійних фігурних дужок у такій команді оболонки?

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

EDIT: додано версію Ansible, яку я використовую
Davide Guerri

Примітка: Проблема тут полягає в тому, що inspectкоманда клієнта docker бере на введення шаблон go, який використовує подвійні фігурні дужки як jinja2. Мені потрібен спосіб отримати фігурні дужки до останньої команди Ansile, запущеної на цільових серверах. Див. Docs.docker.com/reference/commandline/inspect -
Давіде Геррі,

Відповіді:


125

Кожного разу, коли у вас виникають проблеми з конфліктуючими символами в 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": []}
Давіде Геррі

Закривати фігурні дужки не потрібно
Нельсон Г.

1
Це не працює. Не знаю, чому так багато голосів - це працює лише для одного рівня. Якщо ви створите змінну raw_var: '{{ '{{' }}something{{ '}}' }}' та посилаєтесь на неї в іншому місці, command: "{{ raw_var }}"ви отримаєте Error: something is undefined.
Мегакореш

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

Дякую, простий та кмітливий.
Джош

54

Це:

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

Має працювати

Інший спосіб зробити це - використовувати зворотні скісні риски типу \{\{ .NetworkSettings.IPAddress \}\}

Сподіваюся, це допоможе


2
Дякую Філіппе, але я вже спробував обидва, і вони не працюють :(
Давіде Геррі,

Яку версію 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 '.'
Давіде Геррі

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 }}"
налагодити за

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
Костянтин Суворов

2
Тсс, я сказав 2.0
Бен,

Це працює на 2.4.6, і я знайшов рішення в документації, тому можу підтвердити.
einarc

обмін одинарними та подвійними лапками виглядає більш по- !unsafe 'docker inspect --format "{{ .NetworkSettings.IPAddress }}" instance1'
лінуксу

Особисто мені подобається зберігати всі шаблони Jinja у подвійних лапках як підказку кожному, хто читає код. Більшість мов, які мають рядкову інтерполяцію, розглядають одинарні лапки як літерали, а подвійні лапки - як шаблонні, я намагаюся відтворити це в ansible (хоча це і не потрібно). Крім того, обгортання аргументу в скрипт оболонки одинарними лапками зменшує кількість символів, які можна інтерпретувати як "'" та "\", потенційно запобігаючи виникненню проблем, якщо у змінній є "$". Хоча будь-який спосіб цитування працює
Бен,

5

У мене схожа проблема: мені потрібно опублікувати документ JSON, зроблений із шаблону jinja2, що містить деякі змінні шаблонів 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вже було згадано, але команда у відповіді раніше, на жаль, не спрацювала для мене.

Без ансамблю:

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

З ансиблем:

- 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

Ось переважно чисте та відповідне місцеве рішення, не залежно від docker --inspectфігурних дужок. Припускаємо, що ми щойно посилалися на один контейнер з модулем докерів Ansible :

- 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','') }}"

Тепер у вас є IP-адреса контейнера Docker у змінній _container_ip. Я також опублікував цей обхідний шлях у своїй статті "Шлюб Ансібеля з Докером" .

[Оновлення 03.11.2015] Видалено пробіли stdout запиту контейнера.

[Оновлення 04.11.2015] До речі, в офіційному сховищі Ansible було два запити на витяг, що зробило б цей спосіб непотрібним, відновлюючи факти, повернуті модулем Docker. Таким чином, ви можете отримати доступ до IP контейнера докера через docker_containers[0].NetworkSettings.IPAddress. Тож, будь ласка, проголосуйте за ці запити на витяг:


Дуже мило. Ця відповідь працює нестандартно з поточною реалізацією докера. У моєму випадку мені доведеться додати деяку обробку, оскільки я додаю додатковий інтерфейс на якомусь контейнері. Тим не менше, такий підхід дійсно мінімалістичний і чистий. Дякую!
Давіде Геррі,

Заради повноти, в якийсь контейнер я додаю кілька інтерфейсів: віртуальні мости та версії. Проект, про який я говорю, тут: github.com/dguerri/dockerstack
Давіде Геррі

9
Це не відповідає на питання "Як я можу уникнути подвійних фігурних дужок в Ansible 1.9.2?"
серпень

3
Проголосували проти, оскільки ця відповідь абсолютно не корисна для 99% випадків використання. Працездатна відповідь: Кучерявий друк через jinja tpl: stackoverflow.com/a/32283447/293064
Джей Тейлор,
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.