Ansible - Use o padrão se uma variável não for definida

98

Estou personalizando a userscriação do Linux dentro da minha função. Eu preciso permitir que os usuários de meu papel personaliza home_directory, group_name, name, password.

Eu queria saber se existe uma maneira mais flexível de lidar com os valores padrão.

Eu sei que o código abaixo é possível:

- 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

Mas, como mencionei, há muitas variáveis ​​opcionais e isso cria muitas possibilidades.

Existe algo como o código acima?

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

O código deve ser definido name="default_name"quando my_variablenão estiver definido.

Eu poderia definir todas as variáveis defaults/main.ymle criar o usuário assim:

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

Mas essas variáveis ​​estão dentro de um hash muito grande e há alguns hashes dentro desse hash que não podem ser um padrão.

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

Respostas:

190

Você pode usar o de Jinja default:

- name: Create user
  user:
    name: "{{ my_variable | default('default_value') }}"
tedder42
fonte
10
E se a variável padrão depende de outra variável. Por exemplo default('/home/' {{ anothervar }}), existe uma maneira de concatenar esses valores?
Bernardo Vale
8
Basta remover o 'em torno de default_valuee ele usaria uma variável chamada default_value
dagonza
7
Não funciona se a variável estiver aninhada como {{ dict.key | default(5) }}. Ele falhará se dictfor indefinido.
Jordan Stewart
1
Para sua informação, isso agora gerará um erro:[WARNING]: when statements should not include jinja2 templating delimiters such as {{ }} or {% %}.
bryan kennedy
1
@JordanStewart Eu tive o mesmo caso - com variáveis ​​aninhadas. Postei uma resposta com as possíveis soluções abaixo.
Roman Kruglov
11

Não totalmente relacionado, mas você também pode verificar as variáveis undefinedAND empty(por exemplo my_variable:). (NOTA: só funciona com a versão ansible> 1.9, ver: link )

- name: Create user
  user:
    name: "{{ ((my_variable == None) | ternary('default_value', my_variable)) \
    if my_variable is defined else 'default_value' }}"
Tommy Nguyen
fonte
2
Isso é ótimo, muito útil.
eagle33322
5

Se alguém estiver procurando por uma opção que lida com variáveis ​​aninhadas, existem várias dessas opções neste problema do github .

Resumindo, você precisa usar o filtro "padrão" para cada nível de vars aninhados. Para uma variável "a.nested.var" seria assim:

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

ou você pode definir valores padrão de dicts vazios para cada nível de vars, talvez usando o filtro "combine". Ou use o filtro "json_query". Mas a opção que escolhi parece mais simples para mim se você tiver apenas um nível de aninhamento.

Roman Kruglov
fonte
4

Se você tem uma única reprodução que deseja repetir sobre os itens, defina essa lista em group_vars / all ou em outro lugar que faça sentido:

all_items:
  - first
  - second
  - third
  - fourth

Então, sua tarefa pode ser assim:

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

Passe em varlist como uma matriz JSON:

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

Antes disso, você também pode querer uma tarefa que verifique se cada item em varlist também está em 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
fonte
3

No caso de você usar lookup para definir a leitura padrão do ambiente, você também definiu o segundo parâmetro do padrão como verdadeiro:

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

Você também pode concatenar várias definições padrão:

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

A questão é bastante antiga, mas e quanto a:

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

Parece menos complicado para mim ...

pshunter
fonte
1

Se você estiver atribuindo um valor padrão para o fato booleano, certifique-se de que nenhuma aspa seja usada dentro de default ().

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

Para outras variáveis, use o mesmo método dado na resposta verificada.

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