Ansible - użyj wartości domyślnej, jeśli zmienna nie jest zdefiniowana

101

Dostosowuję userstworzenie Linuksa w ramach mojej roli. Muszę pozwolić użytkownikom moja rola Dostosuj home_directory, group_name, name, password.

Zastanawiałem się, czy istnieje bardziej elastyczny sposób radzenia sobie z wartościami domyślnymi.

Wiem, że poniższy kod jest możliwy:

- 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

Ale jak wspomniałem, istnieje wiele opcjonalnych zmiennych, a to stwarza wiele możliwości.

Czy jest coś takiego jak powyższy kod?

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

Kod powinien być ustawiony, name="default_name"gdy my_variablenie jest zdefiniowany.

Mógłbym włączyć wszystkie zmienne defaults/main.ymli stworzyć takiego użytkownika:

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

Ale te zmienne znajdują się w naprawdę dużym skrócie, a wewnątrz tego skrótu jest kilka skrótów, które nie mogą być wartością domyślną.

Bernardo Vale
źródło
related: stackoverflow.com/questions/19614027/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Odpowiedzi:

192

Możesz użyć Jinja default:

- name: Create user
  user:
    name: "{{ my_variable | default('default_value') }}"
przetrząsacz 42
źródło
10
A jeśli zmienna domyślna zależy od innej zmiennej. Na przykład default('/home/' {{ anothervar }}), czy istnieje sposób na konkatenację tych wartości?
Bernardo Vale
8
Po prostu usuń 'wokół default_valuei użyje zmiennej o nazwie default_value
dagonza
7
Nie działa, jeśli zmienna jest zagnieżdżona jak {{ dict.key | default(5) }}. Nie powiedzie się, jeśli dictjest niezdefiniowane.
Jordan Stewart,
1
FYI, teraz pojawi się błąd:[WARNING]: when statements should not include jinja2 templating delimiters such as {{ }} or {% %}.
bryan kennedy
1
@JordanStewart Miałem ten sam przypadek - ze zmiennymi zagnieżdżonymi. Poniżej zamieściłem odpowiedź z możliwymi rozwiązaniami.
Roman Kruglov
11

Niezupełnie powiązane, ale możesz również sprawdzić obie zmienne undefinedORAZ empty(np. my_variable:). (UWAGA: działa tylko z wersją ansible> 1.9, patrz: link )

- name: Create user
  user:
    name: "{{ ((my_variable == None) | ternary('default_value', my_variable)) \
    if my_variable is defined else 'default_value' }}"
Tommy Nguyen
źródło
2
To jest świetne, bardzo przydatne.
eagle33322
5

Jeśli ktoś szuka opcji, która obsługuje zagnieżdżone zmienne, w tym wydaniu na githubie jest kilka takich opcji .

Krótko mówiąc, musisz użyć „domyślnego” filtru dla każdego poziomu zagnieżdżonych zmiennych. Dla zmiennej „a.nested.var” wyglądałoby to następująco:

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

lub możesz ustawić domyślne wartości pustych dykt dla każdego poziomu zmiennych, być może używając filtru „połącz”. Lub użyj filtru „json_query”. Ale opcja, którą wybrałem, wydaje mi się prostsza, jeśli masz tylko jeden poziom zagnieżdżenia.

Roman Kruglov
źródło
4

Jeśli masz pojedyncze odtworzenie, które chcesz zapętlić nad elementami, zdefiniuj tę listę w group_vars / all lub w innym miejscu, które ma sens:

all_items:
  - first
  - second
  - third
  - fourth

Wtedy Twoje zadanie może wyglądać następująco:

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

Przekaż varlistę jako tablicę JSON:

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

Wcześniej możesz również potrzebować zadania, które sprawdza, czy każdy element w varlist znajduje się również w 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) }}"
Jacek
źródło
3

Jeśli używasz wyszukiwania do ustawienia domyślnego odczytu ze środowiska, ustaw również drugi parametr default na true:

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

Możesz także połączyć wiele domyślnych definicji:

- set_facts:
    ansible_ssh_user: "{{ some_var.split('-')[1] | default(lookup('env','USER'), true) | default('foo') }}"
panticz
źródło
1

Pytanie jest dość stare, ale co z:

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

Wydaje mi się to mniej kłopotliwe ...

pshunter
źródło
1

Jeśli przypisujesz wartość domyślną dla faktów logicznych, upewnij się, że wewnątrz default () nie są używane cudzysłowy.

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

W przypadku innych zmiennych zastosowano tę samą metodę podaną w zweryfikowanej odpowiedzi.

- name: Create user
  user:
    name: "{{ my_variable | default('default_value') }}"
Samselvaprabu
źródło