Ansible: utilizza il valore predefinito se una variabile non è definita


101

Sto personalizzando la userscreazione di Linux all'interno del mio ruolo. Ho bisogno di consentire agli utenti di personalizzare il mio ruolo home_directory, group_name, name,password .

Mi chiedevo se esiste un modo più flessibile per gestire i valori predefiniti.

So che il codice qui sotto è possibile:

- name: Create default
  user:
    name: "default_name"
  when: my_variable is not defined

 - name: Create custom
  user:
    name: "{{my_variable}}"
  when: my_variable is defined

Ma come ho detto, ci sono molte variabili opzionali e questo crea molte possibilità.

C'è qualcosa di simile al codice sopra?

user:
  name: "default_name", "{{my_variable}}"

Il codice dovrebbe essere impostato name="default_name"quando my_variablenon è definito.

Potrei impostare tutte le variabili defaults/main.ymle creare l'utente in questo modo:

- name: Create user
  user:
    name: "{{my_variable}}"

Ma quelle variabili sono all'interno di un hash davvero grande e ci sono alcuni hash all'interno di quell'hash che non possono essere un valore predefinito.


Risposte:


193

Puoi usare Jinja default:

- name: Create user
  user:
    name: "{{ my_variable | default('default_value') }}"

10
E se la variabile predefinita dipende da un'altra variabile. Ad esempio default('/home/' {{ anothervar }}), c'è un modo per concatenare quei valori?
Bernardo Vale

8
Basta rimuovere il 'intorno al default_valuee userebbe una variabile chiamata default_value
dagonza

7
Non funziona se la variabile è annidata come {{ dict.key | default(5) }}. Fallirà se dictnon è definito.
Jordan Stewart

1
Cordiali saluti, questo ora genererà un errore:[WARNING]: when statements should not include jinja2 templating delimiters such as {{ }} or {% %}.
bryan kennedy

1
@JordanStewart Ho avuto lo stesso caso - con variabili nidificate. Ho pubblicato una risposta con le possibili soluzioni di seguito.
Roman Kruglov

11

Non totalmente correlato, ma puoi anche controllare entrambe le variabili undefinedAND empty(ad esempio my_variable:). (NOTA: funziona solo con la versione ansible> 1.9, vedi: link )

- name: Create user
  user:
    name: "{{ ((my_variable == None) | ternary('default_value', my_variable)) \
    if my_variable is defined else 'default_value' }}"

2
È fantastico, molto utile.
eagle33322

5

Se qualcuno sta cercando un'opzione che gestisca le variabili annidate, ci sono molte di queste opzioni in questo problema di GitHub .

In breve, è necessario utilizzare il filtro "predefinito" per ogni livello di variabili annidate. Per una variabile "a.nested.var" sarebbe simile a:

- hosts: 'localhost'
  tasks:
    - debug:
        msg: "{{ ((a | default({})).nested | default({}) ).var | default('bar') }}"

oppure puoi impostare valori predefiniti di dict vuoti per ogni livello di variabili, magari usando il filtro "combina". Oppure usa il filtro "json_query". Ma l'opzione che ho scelto mi sembra più semplice se hai un solo livello di nidificazione.


4

Se hai una singola riproduzione che desideri riprodurre in loop sugli elementi, definisci quell'elenco in group_vars / all o da qualche altra parte che abbia senso:

all_items:
  - first
  - second
  - third
  - fourth

Quindi il tuo compito può assomigliare a questo:

  - name: List items or default list
    debug:
      var: item
    with_items: "{{ varlist | default(all_items) }}"

Passa nella lista variabili come array JSON:

ansible-playbook <playbook_name> --extra-vars='{"varlist": [first,third]}'

Prima di ciò, potresti anche volere un'attività che controlli che ogni elemento nella lista variabili sia anche in all_items :

  - name: Ensure passed variables are in all_items
    fail:
      msg: "{{ item }} not  in all_items list"
    when: item not in all_items
    with_items: "{{ varlist | default(all_items) }}"

3

Nel caso in cui utilizzi la ricerca per impostare la lettura predefinita dall'ambiente, hai anche impostato il secondo parametro di default su true:

- set_facts:
    ansible_ssh_user: "{{ lookup('env', 'SSH_USER') | default('foo', true) }}"

È inoltre possibile concatenare più definizioni predefinite:

- set_facts:
    ansible_ssh_user: "{{ some_var.split('-')[1] | default(lookup('env','USER'), true) | default('foo') }}"

1

La domanda è piuttosto vecchia, ma per quanto riguarda:

- hosts: 'localhost'
  tasks:
    - debug:
        msg: "{{ ( a | default({})).get('nested', {}).get('var','bar') }}"

Mi sembra meno ingombrante ...


1

Se stai assegnando un valore predefinito per i fatti booleani, assicurati che non vengano utilizzate virgolette all'interno di default ().

- name: create bool default
  set_fact:
    name: "{{ my_bool | default(true) }}"

Per le altre variabili è stato utilizzato lo stesso metodo fornito nella risposta verificata.

- name: Create user
  user:
    name: "{{ my_variable | default('default_value') }}"
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.