1
votes

Mauvais résultat lors de l'évaluation d'une instruction booléenne multiligne dans un fichier yaml Ansible

En utilisant ansible 2.7.5, j'essaie de créer un paramètre booléen multiligne.

J'ai d'abord vérifié qu'il fonctionne comme prévu en tant que ligne avec:

ok: [localhost] => {
    "msg": "FOOD is apple where IS_FRUIT False"
}

puis une tâche:

FOOD: apple

IS_FRUIT: |
 {% if FOOD == "carrot" %}false
 {% elif FOOD == "apple" or FOOD == "banana" %}true
 {% endif %}

qui imprime:

ok: [localhost] => {
    "msg": "FOOD is apple where IS_FRUIT [ False ]"
}

comme prévu lors de l'exécution.

Basé sur:

En YAML, comment couper une chaîne sur plusieurs lignes?

J'ai ensuite essayé:

IS_FRUIT: >-
 {% if FOOD == "carrot" %}false
 {% elif FOOD == "apple" or FOOD == "banana" %}true
 {% endif %}

mais cela affiche:

ok: [localhost] => {
    "msg": "FOOD is apple where IS_FRUIT [ True ]"
}

ce qui est faux. J'ai trouvé cet article décrivant un problème similaire: https://github.com/ansible/ansible/issues/18142 p >

mais cela ne fournit pas vraiment de solution. Une suggestion sur la façon de créer des variables booléennes multilignes dans Ansible?

D'après la réponse ci-dessous, j'ai également essayé:

- name: "FOOD is: {{ FOOD }}" 
  debug: msg="FOOD is {{ FOOD }} where IS_FRUIT {{ IS_FRUIT | bool }}"

mais quand je l'exécute avec la même tâche ci-dessus, j'obtiens toujours:

FOOD: apple
IS_FRUIT: '{% if FOOD == "carrot" %}false{% elif FOOD == "apple" or FOOD == "banana" %}true{% endif %}'

ce qui est faux.


2 commentaires

Je ne sais pas si cela est pertinent, mais vous devriez supprimer les ' s environnants dans la version > - car ils feraient partie du contenu.


Pour le cas le plus simple - ajouter simplement une nouvelle ligne - qui a corrigé l'erreur. Mais pour plusieurs lignes - voir l'exemple mis à jour ci-dessus, cela échoue toujours.


3 Réponses :


-1
votes

Cela fonctionne pour moi:

IS_FRUIT: |
 {% if FOOD == "carrot" %}false
 {% elif FOOD == "apple" or FOOD == "banana" %}true
 {% endif %}

(changer pour le symbole | pour utiliser un comportement multiligne littéral)


2 commentaires

J'ai également essayé - voir l'article mis à jour - mais même mauvais résultat.


Ouais désolé. J'ai mal lu la subtilité de la question. Vous avez une excellente réponse de @flyx, donc j'espère que votre problème est résolu.



4
votes

Explication ennuyeuse sur ce qui se passe

IS_FRUIT: >-
 {% if FOOD == "carrot" %}false{% elif FOOD == "apple" or FOOD == "banana" %}true{% endif %}

Notez que dans YAML, un scalaire bloc plié (commençant par > ) remplace les sauts de ligne simples par des espaces (et plusieurs sauts de ligne avec un saut de ligne en moins). Donc, le code ci-dessus est équivalent à

IS_FRUIT: >-
 {% if FOOD == "carrot" %}false
 {%- elif FOOD == "apple" or FOOD == "banana" %}true
 {%- endif %}

Donc, après le traitement Jinja, vous obtiendrez soit false soit true avec un espace de fin . YAML ne mappera pas ces scalaires avec des valeurs booléennes à cause de cet espace de fin.

Maintenant, je suppose qu'Ansible voit qu'il obtient une valeur non booléenne, et il mappe cette valeur non booléenne valeur à un booléen d'une certaine manière. Et donc votre scalaire évalue à False même s'il est true avec un espace de fin (le markdown ne me permet pas de rendre cela correctement).


Partie importante sur la façon de résoudre ce problème

Vous pouvez utiliser un bloc littéral scalaire à la place (basé sur la suggestion de clockworknet ):

IS_FRUIT: |-
 {% if FOOD == "carrot" %}false
 {% elif FOOD == "apple" or FOOD == "banana" %}true
 {% endif %}

Cela fonctionne car maintenant les nouvelles lignes ne seront plus transformées en espaces, mais resteront à la place des nouvelles lignes. Après le traitement Jinja, il ne reste qu'une seule ligne et le dernier caractère de nouvelle ligne sera supprimé par le - dans |- .

Cependant, c'est le cas ne vous aide pas si vous avez des expressions plus complexes dans lesquelles vous souhaitez réellement diviser le contenu sur plusieurs lignes. Il existe une meilleure solution qui est Contrôle des espaces blancs Jinja : p>

IS_FRUIT: >-
 {% if FOOD == "carrot" %}false {% elif FOOD == "apple" or FOOD == "banana" %}true {% endif %}

Le - sur les balises Jinja indique à Jinja de supprimer tous les espaces avant cette balise, donc c'est fondamentalement équivalent à

IS_FRUIT: >-
 {% if FOOD == "carrot" %}false
 {% elif FOOD == "apple" or FOOD == "banana" %}true
 {% endif %}

Vous pouvez également l'utiliser comme ceci -%} pour supprimer tous les espaces après une balise. Cependant, méfiez-vous: le traitement Jinja a lieu avant le traitement YAML, il peut donc gâcher votre indentation YAML soigneusement écrite! Par exemple, n'utilisez pas {% - sur la première balise Jinja dans le bloc scalaire, car Jinja placerait alors le texte sur la même ligne que | - qui n'est pas valide YAML! Il en va de même pour la dernière balise et -%}.


0 commentaires

1
votes

Belle explication de ce qui se passe par @flyx.

Je recommanderais d'éviter d'utiliser les déclarations Jinja dans vos playbooks en faveur des expressions Jinja.
Les instructions fixes sont OK dans les modèles de fichiers.

Vous pouvez écrire votre définition de vars comme suit:

IS_FRUIT: >-
  {{ false if FOOD == 'carrot'
     else
     (
       true if FOOD in ['apple', 'banana']
       else 'unknown'
     )
  }}

Dans ce cas, nous ne nous soucions que du dernier saut de ligne qui est supprimé avec >-.


0 commentaires