Doppelte geschweifte Klammern in Ansible


76

Wie entkomme ich doppelten geschweiften Klammern in Ansible 1.9.2?

Wie kann ich beispielsweise im folgenden Shell-Befehl doppelte geschweifte Klammern umgehen?

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

BEARBEITEN: fügte die Ansible-Version hinzu, die ich benutze
Davide Guerri

Hinweis: Das Problem hierbei ist, dass der inspectDocker-Client-Befehl eine go-Vorlage eingibt, die die doppelten geschweiften Klammern als jinja2 verwendet. Ich brauche einen Weg, um die geschweiften Klammern zum letzten Befehl zu bringen, den Ansile auf den Zielservern ausführt. Siehe docs.docker.com/reference/commandline/inspect -
Davide Guerri

Antworten:


121

Wenn Sie Probleme mit widersprüchlichen Zeichen in Ansible haben, gilt als Faustregel, diese als Zeichenfolge in einem Jinja-Ausdruck auszugeben.

Also anstatt {{du würdest verwenden {{ '{{' }}:

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

Thema "Escaping" in den Jinja2-Dokumenten.


1
Ich kann es nicht zum Laufen bringen. Ich fange an zu denken, dass mir etwas fehlt ... Ich 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": []}
verstehe

Das Schließen von geschweiften Klammern ist nicht erforderlich
Nelson G.

1
Das funktioniert nicht. Ich weiß nicht, warum es so viele Upvotes gibt - das funktioniert nur für eine Ebene. Wenn Sie eine Variable erstellen raw_var: '{{ '{{' }}something{{ '}}' }}' und an anderer Stelle referenzieren, erhalten command: "{{ raw_var }}"Sie Error: something is undefined.
Megakoresh

1
raw_var: "{{ '{{' }}something{{ '}}' }}"?
Udondan

Danke, einfach und klug.
Josh

52

Dies:

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

Sollte arbeiten

Eine andere Möglichkeit ist die Verwendung von Backslashes wie \{\{ .NetworkSettings.IPAddress \}\}

Ich hoffe es hilft


2
Danke Filippe, aber ich habe bereits beide ausprobiert und sie funktionieren nicht :(
Davide Guerri

Welche Version von Ansible verwenden Sie?
Filipe

6
Ich habe dies gerade in 1.9.2 getestet und { raw }...{% endraw %}arbeite für mich. Flucht funktioniert allerdings nicht. Es wird in\\{\\{ .NetworkSettings.IPAddress \\}\\}
udondan

1
Und als Bonus ist es nicht einmal möglich, die Ausgabe des vorherigen Schritts zu debuggen! :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
kann mit diesem Trick debuggt werden:- 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

Versucht mit ansible 2.1.1.0

Der Block {% raw%} ... {% endraw%} scheint der klare Weg zu sein

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

Muss nur dem führenden '{{' entkommen

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

Kein Schaden, dem Tailing '}}' zu entkommen, außer schwieriger zu lesen.

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

Backslash '\' scheint nicht zu funktionieren


8

Neu in Ansible 2.0 ist die Möglichkeit, einen Wert mit dem !unsafeTag als unsicher zu deklarieren .

In Ihrem Beispiel könnten Sie Folgendes tun:

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

Einzelheiten finden Sie in den Dokumenten .


1
Warum 2.5? ... 2.0
Konstantin Suworow

2
Shh, ich sagte 2.0
Ben

Es funktioniert unter 2.4.6 und ich habe die Lösung in den Dokumenten gefunden, damit ich sie bestätigen kann.
Einarc

Austausch von einfachen Anführungszeichen und doppelten Anführungszeichen sieht eher nach Linux aus !unsafe 'docker inspect --format "{{ .NetworkSettings.IPAddress }}" instance1'
Timmy Chiu

Persönlich möchte ich alle Jinja-Vorlagen in doppelten Anführungszeichen halten, um jedem, der den Code liest, einen Hinweis zu geben. Die meisten Sprachen mit String-Interpolation behandeln einfache Anführungszeichen als Literale und doppelte Anführungszeichen als Vorlagen. Ich versuche, diese in ansible zu replizieren (obwohl dies nicht erforderlich ist). Wenn Sie das Argument im Shell-Skript in einfache Anführungszeichen setzen, wird die Anzahl der Zeichen, die interpretiert werden können, auf "'" und "\" reduziert, wodurch möglicherweise Probleme vermieden werden, wenn die Variable ein "$" enthält. Beide Zitierweisen funktionieren jedoch
Ben

5

Ich habe ein ähnliches Problem: Ich muss ein JSON-Dokument veröffentlichen, das aus einer jinja2-Vorlage erstellt wurde, die einige Variablen für go-Vorlagen enthält (ja, ich weiß :-P), z

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

Der Versuch, diesen Teil der Vorlage zwischenzäunen

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

hat nicht funktioniert, weil es in ansible eine Art Magie gibt, die die Vorlage und die variable Substitution zweimal ausführt (da bin ich mir nicht sicher, aber es sieht definitiv so aus).

Sie erhalten "undefinierte Variable service_name", wenn Sie versuchen, die Vorlage zu verwenden ...

Also habe ich eine Kombination aus !unsafeund verwendet {% raw %} ... {% endraw %}, um eine Tatsache zu definieren, die später in der Vorlage verwendet wird.

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

Die Vorlage enthält Folgendes:

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

und die Ausgabe ist in Ordnung:

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

Das ist so unglücklich, aber es scheint, dass Ansible manchmal seltsame Dinge tut und solche doppelt entkommenden Konstrukte die einzige Möglichkeit sind, damit umzugehen ...
WindyFields

4

Hier ist eine kürzere Alternative zu Udondans Antwort . Umgeben Sie die gesamte Zeichenfolge mit doppelten Klammern:

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

3

Ich habe es geschafft, mein Problem mit einem kleinen Skript zu umgehen:

#!/usr/bin/env bash

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

Und das folgende Ansible-Spiel

- 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

Trotzdem ist es sehr überraschend, dass Ansible es nicht zulässt, doppelten geschweiften Klammern zu entkommen!


2

Die Lösung mit rawwurde bereits erwähnt, aber der Befehl in der Antwort zuvor hat bei mir leider nicht funktioniert.

Ohne Ansible:

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

Mit 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

Ich konnte @ Bens Antwort nicht zur Arbeit bringen ( shell: !unsafe ...)

Was hier folgt, ist eine vollständige (und funktionierende!) Antwort auf die Frage des OP, die für Ansible> 2.0 aktualisiert wurde

---
# 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                                                                                                          

Ausgänge: ([WARNHINWEISE] entfernt)

# 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

Hier ist eine meist saubere und Ansible native Problemumgehung, die nicht von docker --inspectgeschweiften Klammern abhängt. Wir gehen davon aus, dass wir zuvor nur einen Container mit dem Docker-Modul Ansible referenziert haben :

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

Sie haben jetzt die IP des Docker-Containers in der Variablen _container_ip. Ich habe diese Problemumgehung auch in meinem Artikel Die Ehe von Ansible mit Docker veröffentlicht .

[Update 03.11.2015] Leerzeichen aus dem Standard der Containerabfrage entfernt.

[Update 2015-11-04] Übrigens gab es im offiziellen Ansible-Repository zwei Pull-Anforderungen, die diese Problemumgehung unnötig machten, indem die vom Docker-Modul zurückgegebenen Fakten wiederhergestellt wurden. So können Sie über auf die IP eines Docker-Containers zugreifen docker_containers[0].NetworkSettings.IPAddress. Bitte stimmen Sie für diese Pull-Anfragen ab:


Sehr schön. Diese Antwort funktioniert sofort mit der aktuellen Docker-Implementierung. In meinem Fall muss ich einige Verarbeitungsschritte hinzufügen, da ich auf einem Container eine zusätzliche Schnittstelle hinzufüge. Trotzdem ist dieser Ansatz wirklich minimalistisch und sauber. Vielen Dank!
Davide Guerri

Der Vollständigkeit halber füge ich in einigen Containern mehrere Schnittstellen hinzu: virtuelle Brücken und Veths. Das Projekt, über das ich spreche, ist hier: github.com/dguerri/dockerstack
Davide Guerri

9
Dies beantwortet nicht die Frage "Wie kann ich in Ansible 1.9.2 doppelten geschweiften Klammern entkommen?"
August

3
Abgestuft, da diese Antwort für 99% der Anwendungsfälle überhaupt nicht hilfreich ist. Praktikable Antwort: Curly Drucken über jinja tpl: stackoverflow.com/a/32283447/293064
Jay Taylor
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.