Ansible: [ВНИМАНИЕ]: операторы when не должны включать разделители шаблонов jinja2, такие как {{}} или {%%}.

Созданный на 8 мар. 2017  ·  31Комментарии  ·  Источник: ansible/ansible

ТИП ПРОБЛЕМЫ

  • Сообщение об ошибке
КОМПОНЕНТ НАЗВАНИЕ
ДОСТУПНАЯ ВЕРСИЯ
$ ansible --version
ansible 2.3.0 (devel a8910e78ca) last updated 2017/03/08 02:46:53 (GMT -500)
  config file =
  configured module search path = Default w/o overrides
  python version = 2.7.10 (default, Jul 30 2016, 19:40:32) [GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.34)]
КОНФИГУРАЦИЯ


Сток ansible.cfg

ОС / СРЕДА


Хост управления macOS 10.12.3

РЕЗЮМЕ


Задача, которую я использую более 7 месяцев, начала выдавать предупреждение.

ДЕЙСТВИЯ ПО ВОСПРОИЗВЕДЕНИЮ

- name: install powershell
  win_chocolatey:
    name: '{{ item }}'
    state: 'present'
    upgrade: True
  with_items:
    - "powershell"
  register: check_powershell5
  when: "{{ ansible_PSVersionTable.Major|int < 5 }}"
  tags: win_powershell
ОЖИДАЕМЫЕ РЕЗУЛЬТАТЫ


Задача будет выполняться без предупреждения

ФАКТИЧЕСКИЕ РЕЗУЛЬТАТЫ

TASK [win_powershell : install powershell] *************************************
 [WARNING]: when statements should not include jinja2 templating delimiters
such as {{ }} or {% %}. Found: {{ ansible_PSVersionTable.Major|int < 5 }}
affects_2.3 bug

Самый полезный комментарий

Честно говоря, я не понимаю, как можно написать содержательный сценарий игры, не вызвав это новое предупреждающее сообщение. Весь смысл Ansible в том, что вещи можно разделить на роли. Если вы хотите, чтобы это предупреждение не срабатывало, у вас нет шансов, если вы не пишете плоские playbook с уродливыми выражениями when.

Примеры, которые, казалось бы, невозможно обойти:

значения по умолчанию

auth_service       : none
auth_service_aws   : aws
auth_service_is_aws: '{{ (auth_service == auth_service_aws) | bool }}'

мета

dependencies:

  - { role: apollo/auth/aws, when: auth_service_is_aws }

выдает предупреждения ....

И наконец (это действительно сложно обойти!)

Родительская роль - по умолчанию

bootstrap_ping : true

Родительская роль - мета

dependencies:

  - { role: apollo/platform/ping, ping: '{{ bootstrap_ping }}' }

Дочерняя роль - задачи

- name: execute

  when: ping

  win_ping:

Я серьезно надеюсь, что поступаю глупо и упускаю что-то простое, либо это изменение будет отменено в следующем выпуске.

Все 31 Комментарий

Это ожидаемо. Предупреждение было специально добавлено в выпуск 2.3.

Как указано в предупреждении, вы не должны использовать разделители jinja2 в выражении when. Вместо этого следует читать:

when: ansible_PSVersionTable.Major|int < 5

Если у вас есть дополнительные вопросы, воспользуйтесь списком рассылки.

Как обойти это предупреждение, если выражение when хранится в переменной (по какой-либо причине, например, из-за того, что оно использовалось несколько раз в разных играх).

например: mycondition: ansible_PSVersionTable.Major|int < 5 для использования как when: mycondition .
-> Это не работает, потому что mycondition не оценивается / расширяется и рассматривается как строка.

Что работает, так это объявить mycondition: "{{ ansible_PSVersionTable.Major|int < 5 }}" или when: "{{ mycondition }}" но оба результата приведут к вышеупомянутому ПРЕДУПРЕЖДЕНИЮ.

Это работает для меня

  when: "(ansible_PSVersionTable.Major|int < 5) and ('Microsoft Windows 7' in ansible_distribution)"

с участием

$ ansible --version
ansible 2.4.0 (devel 53c52cf65f) last updated 2017/03/30 07:29:39 (GMT -500)
  config file =
  configured module search path = [u'/Users/tanner/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  python version = 2.7.10 (default, Jul 30 2016, 19:40:32) [GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.34)]

Для меня это тоже работает. Но теперь переместите условие в переменную и попробуйте вместо нее использовать переменную.

ansible_PSVersionTable - это переменная из настраиваемого факта, который я установил на всех компьютерах с Windows.

Попробуйте следующее, и я предполагаю, что это не сработает (при условии, что условие равно true ):

mycond: "(ansible_PSVersionTable.Major|int < 5) and ('Microsoft Windows 7' in ansible_distribution)"
...
when: mycond

В этом случае вам понадобится "{{...}}" - это только условие "когда", где, я думаю, подразумевается "{{....}}".

также может захотеть использовать | bool, чтобы гарантировать, что var хранится как логическое значение.

Вот что я говорю ... вам понадобится либо "{{...}}" в объявлении переменной, либо условие when, иначе оно не будет работать (правильно). И тогда вы получите указанное ПРЕДУПРЕЖДЕНИЕ.

Вы можете использовать что-то вроде:

- set_fact: content1="{{ var1.stdout }}" content2="{{ var2.stdout }}" и сравните это.

возможно дублирование # 23578

Меня это тоже немного смущает. Я понимаю, что теперь мы можем использовать myvar вместо "{{ myvar }}" или {{ myvar }} но в некоторых случаях использования этого все еще недостаточно. Например

when: myvar.stdout != ansible_date_time.date

^ Это НЕ вернет текущую дату (ГГГГ-ММ-ДД). В этом случае у меня нет возможности использовать что-либо еще, кроме разделителей jinja2 с чем-то вроде:

- set_fact:
    ansible_date: "{{ ansible_date_time.date }}"

Другой вариант использования, например,

- name: "TEST: The files directory should have correct ownership"
  shell: stat -c %U:%G {{ files_dir }}
  register: styles_dir_ownership
  changed_when: styles_dir_ownership.stdout != "{{ user }}:{{ apache_user }}"
  failed_when: styles_dir_ownership.stdout != "{{ user }}:{{ apache_user }}"

У меня нет возможности просто сделать user:apache_user потому что мне нужно передать двоеточие и, следовательно, прибегнуть, например, к

- set_fact:
    expected_ownership: "{{ user }}:{{ apache_user }}"

Итак, мой вопрос: как я могу учесть эти 2 варианта использования, если разделители jinja2 устарели, начиная с Ansible 2.3? set_fact теперь предпочтительный вариант?

Добавление еще одного варианта использования:

рассмотрим следующую переменную:

to_be_removed_users:
  - name: 'adm'
    remove: False 
  - name: 'ftp'
    remove: True
  - name: 'games'
    remove: False  
  - name: 'gopher'
    remove: True
  - name: 'operator'
    remove: False
  - name: 'uucp'
    remove: True

то следующие задачи генерируют предупреждение. Не уверен, как этого избежать, поскольку item.name является результатом итерации в списке

``
name: Получить список пользователей
getent:
база данных: passwd
теги:
- userdel

  • имя: Убедитесь, что следующие пользователи удалены
    пользователь:
    имя: "{{item.name}}"
    состояние: отсутствует
    удалить: "{{item.remove}}"
    with_items: '{{to_be_removed_users}}'
    когда: getent_passwd. {{item.name}} определено
    теги:

    • юзердел

      ``

@PhilEv , вы можете сделать что-то вроде этого, чтобы избежать этой проблемы (обратите внимание, что вам не нужна настоящая проверка):

`` ---

  • хосты:

    • localhost

      задания:

    • set_fact:

      ЦВЕТА:

      КРАСНЫЙ: Правда

      СИНИЙ: верно

      ЖЕЛТЫЙ: ложь.

- name: Favourite colours!
  command: echo "I like {{ item }}"
  # when: COLOURS.{{item}} is defined and COLOURS.{{item}}
  when: item in COLOURS and COLOURS[item]
  with_items:
    - "GREEN"
    - "BLUE"
    - "PURPLE"
    - "YELLOW"```

Мы также видим эти предупреждения, и удаление разделителей jinja из when похоже, нарушает это:

- name: Check if redis is installed
  shell: redis-server --version || /bin/true
  register: redis_is_installed

- include: redis_build.yml
  when: "redis_is_installed.stdout.find('v={{ redis_version }}') == -1"

Есть предложения по альтернативному способу написания этого?

@jsuter

when: "redis_is_installed.stdout.find('v=' ~ redis_version) == -1"

@sivel Отлично, спасибо. Что конкретно делает тильда в этом случае? Я не могу найти по нему документы и хотел бы прочитать.

@jsuter http://jinja.pocoo.org/docs/dev/templates/#other -operators

~
Преобразует все операнды в строки и объединяет их.

{{"Привет" ~ имя ~ "!" }} вернет (при условии, что имя установлено на 'John') Hello John !.

Спасибо @streetster, как опубликовано в группе ansible (спасибо

when: getent_passwd[item['name']] is defined
все было хорошо в моем случае

Честно говоря, я не понимаю, как можно написать содержательный сценарий игры, не вызвав это новое предупреждающее сообщение. Весь смысл Ansible в том, что вещи можно разделить на роли. Если вы хотите, чтобы это предупреждение не срабатывало, у вас нет шансов, если вы не пишете плоские playbook с уродливыми выражениями when.

Примеры, которые, казалось бы, невозможно обойти:

значения по умолчанию

auth_service       : none
auth_service_aws   : aws
auth_service_is_aws: '{{ (auth_service == auth_service_aws) | bool }}'

мета

dependencies:

  - { role: apollo/auth/aws, when: auth_service_is_aws }

выдает предупреждения ....

И наконец (это действительно сложно обойти!)

Родительская роль - по умолчанию

bootstrap_ping : true

Родительская роль - мета

dependencies:

  - { role: apollo/platform/ping, ping: '{{ bootstrap_ping }}' }

Дочерняя роль - задачи

- name: execute

  when: ping

  win_ping:

Я серьезно надеюсь, что поступаю глупо и упускаю что-то простое, либо это изменение будет отменено в следующем выпуске.

Цвет меня тоже смутил. Все остальное в Ansible, насколько я понимаю, использует разделители Jinja. В чем разница между "changed_when" и остальными? Говоря как человек, изучающий Ansible, это усложняет понимание.

См. Выше PR. Я, вероятно, получу довольно сильный удар по рыбе, но если это затрагивает достаточно людей, пожалуйста, покажите свою поддержку, и, возможно, предупреждения будут удалены (так или иначе).

https://github.com/ansible/ansible/pull/24974

Вместо того, чтобы говорить, чего не следует делать, следует сказать, ЧТО ДЕЛАТЬ! Мы не волшебники. Благодарю.

Теперь я получаю это предупреждение повсюду. У меня есть общая роль, которая «расширяется» в специализированных ролях путем указания некоторых переменных при определении этой общей роли как такой зависимости в meta/main.yml :

dependencies:
  - role: generic_role
    _configuration_needed: "{{custom_configuration_needed}}"

custom_configuration_needed тогда используется по умолчанию или может быть переопределено для каждого хоста или группы при включении специализированной роли.

Затем в общей роли у меня есть такие шаги:

- name: "configure package if necessary"
  include: configure.yml
  when: _configuration_needed

Однако теперь я на каждом шаге в configure.yml в 'базовой' общей роли, выполняемой для этой специализированной роли, получаю такие предупреждения:

   [WARNING]: when statements should not include jinja2 templating delimiters such as {{ }} or {% %}. Found: {{custom_configuration_needed}}
 ```

This is due to the implicit 'when' clause that's added to every step in that included file, but I'm not sure how to solve this-one. The `_configuration_needed` isn't the only case, it's just the one spamming most warnings right now. Now for this `_configuration_needed` I tried defining the dependency like this:

зависимости:

  • роль: generic_role
    _configuration_needed: custom_configuration_needed
    ``

Однако это не работает, поскольку, когда я отлаживаю печать этой переменной _configuration_needed, я вижу эту «custom_configuration_needed» как (непустую) строку, которая всегда принимает значение «True». Это, конечно, нежелательное или нежелательное поведение, и я не знаю, как удалить эти предупреждения.

Если есть рабочее решение для предотвращения появления этих предупреждений в этом случае, которое также имеет ожидаемое поведение, пожалуйста, поделитесь - но прямо сейчас я не могу найти способ сделать это.

Кроме того, для ansible 3, пожалуйста, подумайте о том, чтобы сделать шаблоны jinja единообразными по всем направлениям. Везде или нигде {{}} , но это просто глупо.

Я не могу выделить динамическую переменную без {{}} , я не могу получить эту работу без фигурных скобок:

vars:
    host_name: ['foo', 'bar']
    foo_wwn_2: "This exist"

  tasks:
    - debug:
        var: "{{item.1}}_wwn_{{item.0}}"
     when: ({{item.1 + '_wwn_' + item.0}}) is defined
      with_nested:
        - ['1', '2']
        - "{{host_name}}"

Без скобок это просто строка, которая будет оценена как ИСТИНА.

Очень досадно видеть, что вы хотите удалить единственный способ оценки переменной в when .

@bartmeuris в вашем примере, это предупреждение больше не будет отображаться в ansible v2.4, который скоро будет выпущен

@MichalTaratuta, вы должны вместо этого использовать следующее:

when: vars[item.1 ~ '_wnn_' ~ item.0] is defined

Тот факт, что ваш пример работал раньше, был непреднамеренным и не является лучшей практикой для создания имени переменной для проверки.

А как насчет проверки на наличие строки, часть которой содержит переменную?

vars:
  acct:
    name: example_name

tasks:
  - name: Emergency Account | Gather list of usernames
    ios_command:
      commands: show run | i ^username
    register: ios_usernames

  - name: Emergency Account | Remove non-emergency account users
    ios_config:
      lines:
        - no {{ item }}
    with_flattened:
      - "{{ ios_usernames.stdout_lines }}"
    when: '"username {{ acct.name }} privilege 0 secret" not in item'
    no_log: True

Вполне возможно, что мне просто не хватает лучшего или более подходящего способа написать это, но пока что единственный работающий метод, похоже, использует скобки в цитируемой строке.

РЕДАКТИРОВАТЬ
Извините за загромождение темы. После перечитывания нескольких примеров и дальнейшего тестирования он смог заставить его работать, разбив цитату на части и используя конкатенацию. Делает это немного дольше, но выполняет свою работу.

  when: '"username " ~ localauth.emergency.name ~ " privilege 0 secret" not in item'

Я вижу, что предупреждение полезно, но можно, например, написать более длинные выражения, подобные следующему, без каких-либо шаблонных разделителей:

  when: |-
      {%- set certs = {'sync': False} -%}
      {% if gen_node_certs[inventory_hostname] or
        (not etcdcert_node.results[0].stat.exists|default(False)) or
          (not etcdcert_node.results[1].stat.exists|default(False)) or
            (etcdcert_node.results[1].stat.checksum|default('') != etcdcert_master.files|selectattr("path", "equalto", etcdcert_node.results[1].stat.path)|map(attribute="checksum")|first|default('')) -%}
              {%- set _ = certs.update({'sync': True}) -%}
      {% endif %}
      {{ certs.sync }}

Это может помочь новым людям,
Мы не можем использовать переменные внутри условия when, потому что оно имеет некоторые ограничения, и ниже будет отображаться предупреждение
ПРЕДУПРЕЖДЕНИЕ: операторы

поэтому, чтобы избежать таких вещей при проверке условия путем передачи переменной, сначала нам нужно зарегистрировать эту конкретную переменную, а затем использовать ее. Ниже приведен небольшой пример

ВЕРСИЯ уже определена или передана явно при запуске книги воспроизведения

- name: Check the java version
   shell: java -version 2>&1 | grep version | awk '{print $3}' | sed 's/"//g' | cut -d "_" -f1
   register: java_versios
 - name: testing senario
   shell: echo '{{ VERSION }}'
   register: r
- name: testing
   file:
     path: /root/Karthik/JAVATEST
     state: directory
     owner: root
     group: root
     mode: 0755
     recurse: yes
   when: java_version.stdout >= r.stdout

Здравствуйте,

Как насчет случая, когда я передаю имя группы инвентаря на основе предопределенной переменной?
В этом сценарии, основанном на переменной «sync_source», я вызываю группу инвентаризации, которая передается как переменная пользователем.

    - debug:
        msg:
          - "source instance: {{ inventory_hostname }}"
          - "{{ dir }} size is {{ result_dir_size }} GB"
      when: "inventory_hostname in groups.{{ sync_source }}"

@linlinas

when: "inventory_hostname in groups[sync_source]"
Была ли эта страница полезной?
0 / 5 - 0 рейтинги