-1
votes

Format Ansible / YAML incohérent pour les listes?

J'ai besoin d'aide pour comprendre pourquoi, lorsque je crée un fichier YAML pour un playbook Ansible qui reflète exactement ce qui est spécifié dans la documentation du module, les listes et list_items ne sont pas analysés correctement lorsque le YAML est lu par Python.

Je crois comprendre que lors de la lecture de la documentation sur les modules Ansible sur Github, les éléments sont affichés dans des colonnes pour indiquer leur relation par rapport aux éléments au-dessus et en dessous d'eux. De plus, si un élément est défini comme " liste / éléments = dictionnaire ", cela signifie ce qui suit:

  1. La saisie de l'élément doit être terminée en ajoutant un deux-points et un espace (cela définit les éléments "dictionnaire")

  2. La ligne suivante / suivante doit commencer au même niveau d'indentation (ou plus) et commencer par un tiret et un espace (cela désigne un élément de «liste»)

  3. L'ordre des éléments dans une liste doit être suivi exactement.

  4. Les éléments de liste suivants doivent être au même niveau d'indentation que le premier élément de la liste

  5. Si un sous-élément donné de la liste est lui-même un autre élément " liste / éléments = dictionnaire ", répétez l'étape 2 à nouveau.

(EXEMPLE: extrait du module cisco.ios.ios_ospfv2 ) Donc, si l'élément principal de " processus " est un " liste / éléments = dictionnaire " composé des éléments suivants:

  1. zones (également une "liste / éléments = dictionnaire")
  2. réseau (également une "liste / éléments = dictionnaire")
  3. process_id (entier)

Ensuite, la syntaxe YAML correcte pour ce qui précède serait:

processes: 
- process_id: 1
  areas: 
  - area_id: '0'
    authentication: 
      message_digest: true
  network: 
    address: 0.0.0.0
    area: 0
    wildcard_bits: 255.255.255.255

Cependant, même si je n'obtiens aucune erreur YAML lorsque je démarre mon Playbook, j'obtiens un tas de traces obscures de Python. Mais si je change mon code en CECI (voir ci-dessous), cela fonctionne!

processes: 
- areas: 
  - area_id: 0 ##dictionary_item
  - authentication: ##dictionary_item
      message_digest: true ##boolean
- network: 
  - address: '10.1.1.0' ##string
  - area: '0' ##string
  - wildcard_bits: 0.0.0.255. ##integer
- process_id: 1

Mes questions:

  1. Si l'ordre de list_items est important, pourquoi mon fichier n'a-t-il PAS fonctionné lorsque j'ai suivi l'ordre spécifié dans la documentation du module ... mais il fonctionne lorsque cet ordre est ignoré ("process_id" ne doit PAS être le premier selon la documentation pour cela module)?
  2. Je comprends que TOUTES les éléments de la liste ne doivent pas être précédés d'un tiret-espace. Mais j'ai pensé que le PREMIER list_item l'exigeait. Alors pourquoi (dans mon premier exemple) mon playbook échoue-t-il lorsque je désigne les sous-éléments sous «réseau» avec des tirets ... mais lorsque je supprime TOUS les tirets de cette liste, cela fonctionne-t-il? Cependant, il faut un trait d'union pour le premier élément de la liste sous "zones" ??

Erreurs Python

(désolé pour le long post ... je ne savais pas comment le condenser plus loin)


3 commentaires

Quelle structure de données connaissez-vous? Quel est votre langage de codage principal? Cela vous aiderait-il si nous traduisions cela dans la langue à laquelle vous êtes «habitué»?


La plupart des gens qui "implémentent" yaml comme format de configuration n'ont aucune idée de ce qu'ils implémentent réellement. C'est un format de données si fondamentalement cassé que sa popularité défie ma compréhension. Protégez tous ceux qui pensent que yaml est une bonne idée: faites des recherches, examinez les cas secondaires, voyez dans quoi vous faites vraiment entrer vos utilisateurs: / J'utilise beaucoup trop Ansible à un moment donné, et pendant ce que vous décrivez peut ne pas être nécessairement un bogue, cela tue la convivialité de la chose si vous voulez faire quelque chose qui n'est pas trivial et couvert dans des tutoriels. Par pour le cours ici.


@UnslanderMonica TBH, je comprends partiellement l'aversion de YAML, vous n'êtes pas la première personne que je vois soulever cela. Cela dit, c'est un peu comme n'importe quel langage utilisant {} pour indiquer des blocs par rapport à Python utilisant l'indentation pour indiquer des blocs. Donc, les gens préfèrent JSON à YAML, mais c'est comme la plupart des choses: une question de goûts. Il y a cependant des bizarreries dans YAML, mais cette question ne fait pas partie de ces cas.


3 Réponses :


0
votes

Voici une explication générale de ce YAML:

- foo: bar
  bar: foo

- baz: qux
  qux: baz
  • processes : vous pouvez avoir 1 à N processus, donc c'est une liste, et dans ce cas, une liste de dictionnaire. Vous devriez vous attendre à quelque chose comme:
    - 
      foo: bar
      bar: foo
    - 
      baz: qux
      qux: baz
    
  • process_id : est un int, vous devriez vous attendre:
    the:
      jump: over
      red: fox
    
    Donc c'est exactement le même YAML
    the:
      red: fox
      jump: over
    
  • areas : est une liste de 1 à N zones, sous les areas clés d'un dictionnaire, imbriquées dans une liste, de processes clés
    - the:
        red: fox
        jump: over
    - the:
        lazy: dog
    
  • network : est un dictionnaire dans un dictionnaire
    fruits:
      - banana
      - apple
      - pear
      - peach
    

Donc, en général, faites attention à la façon dont Ansible vous donne également des indices ici: les areas sont pluralisées pour une bonne raison: parce que c'est une liste de zones. Il en va de même pour les processes . Alors que le network est un singulier, donc, comme prévu, ce sera un dictionnaire et non une liste.


list / elements = dictionnaire

Signifie que les processus doivent être une liste où chaque élément est un dictionnaire.

En YAML, c'est un dictionnaire:

foo:
  some: bar
  property: bar
  of: bar
  the: bar
  dictionary: bar
  of: bar
  key: bar
  foo: bar

Et voici une liste:

processes:
  - process_id: 1
    areas:
      - area_id: '0'
        authentication: 
          message_digest: true
      - area_id: '1'
        authentication: 
          message_digest: true
  - process_id: 2
    areas:
      - area_id: '0'
        authentication: 
          message_digest: true 
    network: 
      address: 0.0.0.0
      area: 0
      wildcard_bits: 255.255.255.255

Ensuite, une liste de dictionnaires serait:

processes:
  - process_id: 1
    areas:
      - area_id: '0'
        authentication: 
          message_digest: true
      - area_id: '1'
        authentication: 
          message_digest: true
  - process_id: 2
    areas:
      - area_id: '0'
        authentication: 
          message_digest: true 

Notez que, puisqu'il s'agit d'une liste, la même clé peut être reproduite dans les différents éléments de la liste mais ne peut pas être vue deux fois dans le même dictionnaire.


Donc, pour répondre à votre deuxième question, vous avez raison de dire que dans un dictionnaire, l'ordre des touches n'a pas d'importance:

processes:
  - process_id: 1
    # since you are in a dictionary, 
    # process_id can be anywhere in the dictionary, 
    # as the first, last, or anywhere in between key  
    foo: bar
    baz: qux
  - process_id: 2
    # since you are in a dictionary, 
    # process_id can be anywhere in the dictionary, 
    # as the first, last, or anywhere in between key 
    foo: some
    baz: thing 

Est en effet exactement le même dictionnaire que

processes:
  - foo: bar
    baz: qux
    # since you are in a dictionary, 
    # process_id can be anywhere in the dictionary, 
    # as the first, last, or anywhere in between key 
    process_id: 1 
  - foo: some
    baz: thing
    # since you are in a dictionary, 
    # process_id can be anywhere in the dictionary, 
    # as the first, last, or anywhere in between key 
    process_id: 2

Mais puisque vous faites ici une liste de ce que devrait être un dictionnaire, c'est là que réside votre problème.


Une petite note sur le trait d'union ( - ) aussi, car cela semble vous déranger:

Si vous le préférez, écrivez vos listes comme ceci:

processes:
  - foo: bar
    baz: qux
  - foo: some
    baz: thing

C'est strictement équivalent à:

processes: 
- process_id: 1
  areas: 
  - area_id: '0'
    authentication: 
      message_digest: true
  network: 
    address: 0.0.0.0
    area: 0
    wildcard_bits: 255.255.255.255

Cela vous aiderait à voir que le trait d'union délimite simplement le fait qu'un nouvel élément de la liste commence là, maintenant vous pouvez le "condenser" et avoir une clé de votre dictionnaire sur la même ligne que le délimiteur "nouvel élément de la liste" ( - ), mais vous n'y êtes pas obligé.


Peut-être pour un langage de programmation orienté objet parallèle, si cela peut vous être utile, vous devriez penser

  • un dictionnaire est comme un objet, il a plusieurs propriétés, mais toutes les propriétés définissent en fait le même objet
  • une liste est une collection de choses, elle peut être une liste d'objets, d'entiers ou même d'objets.

Ainsi, lorsque la documentation dit liste / éléments = dictionnaire, ils veulent en fait que vous construisiez une liste (ou une collection) où tous les éléments seraient des dictionnaires (ou des objets).


Peut-être que la mise en page sur la page de documentation elle - même est plus facile à lire que le tableau sur GitHub.
Mais là, vous pouvez clairement voir que le dictionnaire de config contient une liste de processes qui, elle-même, contient beaucoup de dictionnaires différents, parmi lesquels address_family , adjacency , ..., areas , network , ...

table de paramètres dans le module ios_ospfv2


4 commentaires

Merci β.εηοιτ.βε. Cependant, ce qui me trouble ici, c'est que ni les «zones» ni les «réseaux» ne sont purement des dictionnaires. Ils (comme les "processus") sont de type "liste / éléments = dictionnaire". Et étant donné qu'ils sont tous les deux au même niveau (sous processus) et tous les deux du même type ... pourquoi est-ce qu'un trait d'union avant "zones" est acceptable mais PAS acceptable avant "réseau"? C'est presque comme si la documentation déclarait que "réseau" est une "liste / éléments = dictionnaire" alors qu'en réalité c'est purement un dictionnaire. Alors, cherchons-nous un bug de documentation ici?


Parce qu'ils sont censés être listés sous l'un des éléments des processus de liste


Faites attention à la façon dont Ansible vous donne également des indices ici: les areas sont pluralisées pour une bonne raison, car il s'agit d'une liste de area . Il en va de même pour les processes . Alors que le réseau est un singulier, donc, comme prévu, ce sera un dictionnaire et non une liste.


@KeithBogart J'ai ajouté une petite note sur le trait d'union, qui pourrait répondre à l'idée fausse à laquelle vous faites face ici



0
votes

Merci à tous pour vos idées. J'ai discuté avec d'autres et je pense que c'est un problème d'erreur de documentation pour ce module. L'élément de "réseau" est documenté comme étant "liste / éléments = dictionnaire".

En réalité, le code Python sous-jacent s'attend à le voir comme un dictionnaire (pas une liste). Lorsqu'il est ajouté en tant que dictionnaire, cela fonctionne très bien. S'il vous plaît voir mon lien dans lequel je fournit une capture d'écran de la documentation (incorrecte) ainsi que l'erreur Python qui se produit lorsque "réseau" est configuré en tant que "liste / éléments = dictionnaire". entrez la description de l'image ici


0 commentaires

0
votes

Mise à jour: J'utilisais auparavant la collection Ansible cisco.ios version 1.1.0 (qui nécessite que le paramètre "network" soit entré comme dictionnaire dans le code python du module, "ios_ospfv2").

Lors de la mise à niveau vers la version 1.2.0 de la collection cisco.ios, le paramètre "réseau" ne fonctionnait plus comme un dictionnaire et devait être changé en une liste (qui correspond à la documentation de ce module).

Donc, apparemment, la version d'Ansible Collection que l'on utilise peut changer la façon dont les paramètres sont définis dans les modules. Morale de l'histoire? Assurez-vous d'utiliser la dernière version de la collection dont vous avez besoin. Déterminer la version la plus récente de la collection


0 commentaires