Gebruik van item en loop_var in Ansible-loops

Gebruik item als de standaard loop-variabele. Reserveer loop_control.loop_var voor gevallen waarin item zou botsen over loop-grenzen, zoals geneste loops en include_tasks.

Probleem

De standaard loop-variabele item is handig en bekend, en in de meeste gevallen de beste keuze. Problemen ontstaan wanneer item hergebruikt wordt over loop-grenzen, bijvoorbeeld wanneer include_tasks loop-data doorgeeft aan een ander bestand of wanneer loops genest zijn.

In een gevalideerde test met ansible-core 2.21.4 geeft Ansible een waarschuwing wanneer een included task een nieuwe loop start die ook item gebruikt:

[WARNING]: The variable 'item' is already in use.
You should set the `loop_var` value in the `loop_control` option for the task to
something else to avoid variable collisions and unexpected behavior.

Een aangepaste loop-variabele overal gebruiken voegt ook ruis toe. Als een naam zoals apache_vhost geen echte ambiguïteit oplost, maakt het de taak alleen maar langer.

Context

In Ansible is item de standaard variabelenaam voor loop en with_items. Die standaard is meestal de beste keuze voor korte en lokale loops, inclusief loops over dictionaries en andere objecten.

Een aangepaste loop_control.loop_var is alleen nuttig wanneer het ambiguïteit voorkomt. Dit komt vooral voor in herbruikbare Ansible-rollen, included task-bestanden en geneste loops. Alleen itereren over een object is op zichzelf geen reden om item niet te gebruiken.

Wanneer een aangepaste loop-variabele naar een ander task-bestand wordt doorgegeven en anders te veel op een ondersteunde publieke rolvariabele lijkt, kan de interne __...-vorm duidelijker zijn dan een gesingulariseerde naam.

Voor veldtoegang is consistentie belangrijker dan persoonlijke afkortingen. De Ansible-documentatie toont vaak dot-notatie zoals item.name en item.value.role, terwijl Jinja zowel foo.bar als foo['bar'] als geldige syntax documenteert. In C2 Platform-code wordt bracket-notatie al veel vaker gebruikt dan dot-notatie, daarom prefereert deze richtlijn bracket-notatie voor looped objecten om de codebase consistent te houden.

Oplossing

  1. Gebruik loop in plaats van with_items voor nieuwe code.
  2. Gebruik item als standaard.
  3. Introduceer geen aangepaste loop_var als dit geen duidelijke meerwaarde heeft.
  4. Gebruik loop_control.loop_var wanneer item ambigu wordt, vooral bij geneste loops en include_tasks-patronen.
  5. Wanneer je een aangepaste loop-variabele introduceert, gebruik deze consistent in label, when en alle expressies binnen de taak.
  6. Gebruik voor looped dictionaries en objecten consistent bracket-notatie, zoals item['servername'], in plaats van bracket- en dot-notatie te mengen.
  7. Wanneer een aangepaste loop-variabele alleen een interne helper is die over een include_tasks-grens gaat, overweeg dan de interne __...-vorm als die het bereik duidelijker maakt.

Voordelen

  • Houdt eenvoudige taken kort en in lijn met de normale Ansible-stijl.
  • Voorkomt verwarring in included task-bestanden en geneste loop-scenario’s.
  • Vermijdt onnodige aangepaste namen die ruis toevoegen zonder de code te verbeteren.
  • Verkleint de kans op typefouten tussen vergelijkbaar benoemde variabelen zoals role_cars en role_car.

Alternatieven (optioneel)

Een aangepaste loop_var voor elke loop gebruiken creëert onnodige breedsprakigheid en wordt niet aanbevolen. item voor elke loop gebruiken is ook niet aanbevolen, omdat het in herbruikbare of complexere code kan verbergen wat de loop-waarde vertegenwoordigt.

Voorbeelden en implementatie

Gebruik item voor eenvoudige waarden

Gebruik item wanneer de taak lokaal en duidelijk is.

- name: Install packages
  ansible.builtin.package:
    name: "{{ item }}"
    state: present
  loop:
    - git
    - curl
    - jq

Gebruik loop_var voor herbruikbare include-patronen

Een aangepaste loop-variabele heeft de voorkeur wanneer de loop-waarde in een ander task-bestand wordt gebruikt.

- name: Restore
  ansible.builtin.include_tasks: restore.yml
  loop: "{{ oracle_database_restores }}"
  loop_control:
    loop_var: oracle_database_restore
    label: "{{ oracle_database_restore['archive'] }}"
  when: oracle_database_restore_enabled

Dit voorkomt item-botsingen over bestandsgrenzen.

Als het included task-bestand de loop-variabele gebruikt als interne helper en de gewone enkelvoudsvorm te veel op een publieke rolvariabele lijkt, heeft de interne vorm de voorkeur:

- name: Configureer IIS web application pools
  ansible.builtin.include_tasks: web_app_pool.yml
  loop: "{{ iis_web_app_pools }}"
  loop_control:
    loop_var: __iis_web_app_pool
    label: "{{ __iis_web_app_pool['name'] }}"
# web_app_pool.yml
- name: Zorg dat IIS web application pool bestaat
  microsoft.iis.web_app_pool:
    name: "{{ __iis_web_app_pool['name'] }}"
    state: "{{ __iis_web_app_pool['state'] | default(omit) }}"

Hier maakt __iis_web_app_pool duidelijker dat de waarde geen publieke rolparameter is. Zie ook Variabelen prefixen en woorden scheiden in Ansible .

Gebruik item voor objectdata wanneer er geen botsing is

Wanneer de loop over dictionaries of objecten itereert, is item nog steeds prima als er geen ambiguïteit is.

- name: Configure Apache vhosts
  ansible.builtin.debug:
    msg: "{{ item['servername'] }} -> {{ item['documentroot'] }}"
  loop: "{{ apache_vhosts }}"

Hier zijn item['servername'] en item['documentroot'] al duidelijk genoeg. apache_vhost introduceren voegt weinig waarde toe en vergroot de kans op typefouten.

Vermijd aangepaste namen die geen waarde toevoegen

Voor korte en duidelijke taken voegt een aangepaste loop-variabele alleen maar ruis toe.

- name: Configure Apache vhosts
  ansible.builtin.debug:
    msg: "{{ apache_vhost['servername'] }} -> {{ apache_vhost['documentroot'] }}"
  loop: "{{ apache_vhosts }}"
  loop_control:
    loop_var: apache_vhost

Hier verschilt de aangepaste naam alleen in enkelvoud/meervoud van apache_vhosts, wat review en onderhoud lastiger maakt zonder een echt probleem op te lossen.

Aanvullende informatie