Ansible: use el valor predeterminado si una variable no está definida

98

Estoy personalizando la userscreación de Linux dentro de mi función. Necesito para que los usuarios de mi papel modifique para requisitos particulares home_directory, group_name, name, password.

Me preguntaba si hay una forma más flexible de hacer frente a los valores predeterminados.

Sé que el siguiente código es posible:

- 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

Pero como mencioné, hay muchas variables opcionales y esto crea muchas posibilidades.

¿Hay algo como el código anterior?

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

El código debe establecerse name="default_name"cuando my_variableno está definido.

Podría configurar todas las variables defaults/main.ymly crear el usuario así:

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

Pero esas variables están dentro de un hash realmente grande y hay algunos hash dentro de ese hash que no pueden ser predeterminados.

Bernardo Vale
fuente
relacionado: stackoverflow.com/questions/19614027/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Respuestas:

190

Puedes usar Jinja's default:

- name: Create user
  user:
    name: "{{ my_variable | default('default_value') }}"
tedder42
fuente
10
Y si la variable predeterminada depende de otra variable. Por ejemplo default('/home/' {{ anothervar }}), ¿hay alguna forma de concatenar esos valores?
Bernardo Vale
8
Simplemente elimine el 'alrededor del default_valuey usaría una variable llamada
valor_predeterminado
7
No funciona si la variable está anidada como {{ dict.key | default(5) }}. Fallará si no dictestá definido.
Jordan Stewart
1
Para su información, esto ahora arrojará un error:[WARNING]: when statements should not include jinja2 templating delimiters such as {{ }} or {% %}.
bryan kennedy
1
@JordanStewart Tuve el mismo caso, con variables anidadas. Publiqué una respuesta con posibles soluciones a continuación.
Roman Kruglov
11

No está totalmente relacionado, pero también puede verificar la variable undefinedAND empty(por ejemplo my_variable:). (NOTA: solo funciona con la versión ansible> 1.9, ver: enlace )

- name: Create user
  user:
    name: "{{ ((my_variable == None) | ternary('default_value', my_variable)) \
    if my_variable is defined else 'default_value' }}"
Tommy Nguyen
fuente
2
Esto es genial, muy útil.
eagle33322
5

Si alguien está buscando una opción que maneje variables anidadas, existen varias de estas opciones en este problema de github .

En resumen, debe utilizar el filtro "predeterminado" para cada nivel de vars anidadas. Para una variable "a.nested.var" se vería así:

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

o puede establecer valores predeterminados de dictados vacíos para cada nivel de vars, tal vez usando el filtro "combinar". O use el filtro "json_query". Pero la opción que elegí me parece más simple si solo tiene un nivel de anidación.

Roman Kruglov
fuente
4

Si tiene una sola jugada en la que desea recorrer los elementos, defina esa lista en group_vars / all o en otro lugar que tenga sentido:

all_items:
  - first
  - second
  - third
  - fourth

Entonces su tarea puede verse así:

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

Pase varlist como una matriz JSON:

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

Antes de eso, es posible que también desee una tarea que verifique que cada elemento en varlist también esté en 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) }}"
Jack
fuente
3

En caso de que utilice la búsqueda para establecer la lectura predeterminada del entorno, también ha establecido el segundo parámetro predeterminado en verdadero:

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

También puede concatenar varias definiciones predeterminadas:

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

La pregunta es bastante antigua, pero ¿qué pasa con:

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

Me parece menos engorroso ...

pshunter
fuente
1

Si está asignando un valor predeterminado para un hecho booleano, asegúrese de que no se utilicen comillas dentro de default ().

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

Para otras variables se utilizó el mismo método dado en respuesta verificada.

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