Руководство по переносу Ansible 2.0
В этом разделе обсуждаются изменения в поведении между Ansible 1.x и Ansible 2.0.
Он предназначен для помощи в обновлении ваших playbooks, плагинов и других частей вашей инфраструктуры Ansible, чтобы они работали с этой версией Ansible.
Мы рекомендуем вам прочитать эту страницу вместе с Журналом изменений Ansible для версии 2.0, чтобы понять, какие обновления вам могут потребоваться.
Этот документ является частью коллекции по переносу. Полный список руководств по переносу можно найти на странице руководства по переносу.
Playbook
В этом разделе обсуждаются возможные изменения, которые вам могут потребоваться внести в ваши playbooks.
# Syntax in 1.9.x
- debug:
msg: "{{ 'test1_junk 1\\\\3' | regex_replace('(.*)_junk (.*)', '\\\\1 \\\\2') }}"
# Syntax in 2.0.x
- debug:
msg: "{{ 'test1_junk 1\\3' | regex_replace('(.*)_junk (.*)', '\\1 \\2') }}"
# Output:
"msg": "test1 1\\3"
Чтобы создать экранированную строку, которая будет работать во всех версиях, у вас есть два варианта:
- debug: msg="{{ 'test1_junk 1\\3' | regex_replace('(.*)_junk (.*)', '\\1 \\2') }}"
использует экранирование key=value, которое не изменилось. Другой вариант — проверить версию ansible:
"{{ (ansible_version|version_compare('2.0', 'ge'))|ternary( 'test1_junk 1\\3' | regex_replace('(.*)_junk (.*)', '\\1 \\2') , 'test1_junk 1\\\\3' | regex_replace('(.*)_junk (.*)', '\\\\1 \\\\2') ) }}"
-
Конец строки При указании строки с концом строки в playbook в формате словаря YAML, конец строки удалялся. При указании в формате key=value, концы строк сохранялись. В версии 2 оба способа сохраняют концы строк. Если вы полагались на удаление конца строки, вы можете изменить свой playbook, используя следующий пример:
# Syntax in 1.9.x vars: message: > Testing some things tasks: - debug: msg: "{{ message }}" # Syntax in 2.0.x vars: old_message: > Testing some things message: "{{ old_messsage[:-1] }}" - debug: msg: "{{ message }}" # Output "msg": "Testing some things" -
Изменение поведения шаблонизации текстовых файлов типа DOS в Ansible v2.
Ошибка в Ansible v1 приводит к тому, что текстовые файлы типа DOS (использующие возврат каретки и новую строку) шаблонизируются в текстовые файлы типа Unix (использующие только новую строку). В Ansible v2 эта давняя ошибка, наконец, была исправлена, и текстовые файлы типа DOS сохраняются правильно. Это может сбить с толку, когда вы ожидаете, что ваш playbook не покажет никаких различий при миграции на Ansible v2, в то время как на самом деле вы увидите, что каждый файл типа DOS полностью заменяется (с тем же самым содержимым).
-
При указании сложных аргументов в качестве переменной, переменная должна использовать полный синтаксис Jinja2 (
`{{var_name}}`) — простые имена переменных больше не принимаются. Фактически, даже указание аргументов с переменными устарело и в будущих версиях не будет разрешено:--- - hosts: localhost connection: local gather_facts: false vars: my_dirs: - { path: /tmp/3a, state: directory, mode: 0755 } - { path: /tmp/3b, state: directory, mode: 0700 } tasks: - file: args: "{{item}}" # <- args here uses the full variable syntax with_items: "{{my_dirs}}" - перенос задачи включает
- Более динамичный. Случаи форматов, которые не должны были работать, теперь не работают, как ожидалось.
- переменные, определенные в формате YAML https://github.com/ansible/ansible/issues/13324
- шаблонизация (переменные в playbooks и поиски шаблонов) улучшилась, сохраняя исходный формат вместо преобразования всего в строку. Если вам нужен старый формат, заключите значение в кавычки, чтобы передать его в виде строки.
- Пустые переменные и переменные, установленные в null в формате YAML, больше не преобразуются в пустые строки. Они сохраняют значение
None. Вы можете переопределитьnull_representationзначение на пустую строку в вашем конфигурационном файле, задав переменную средыANSIBLE_NULL_REPRESENTATION. - Плагины дополнений должны быть включены в ansible.cfg. Копирование больше не требуется, но их нужно включить в ansible.cfg.
- Модуль dnf был переписан. Могут наблюдаться незначительные изменения в поведении.
- win_updates был переписан и теперь работает как ожидалось.
- Начиная с версии 2.0.1, неявная задача setup из gather_facts теперь правильно наследует все из play, но это может вызвать проблемы для тех, кто настраивает
environmentна уровне play и зависит от существованияansible_env. Раньше это игнорировалось, но теперь может вызывать ошибку «Undefined».
Устаревшие элементы
Хотя все перечисленные элементы будут показывать предупреждение об устаревании, они все еще работают так же, как и в 1.9.x. Обратите внимание, что они будут удалены в версии 2.2 (Ansible всегда ожидает два основных выпуска, чтобы удалить устаревшую функцию).
- Простые переменные в циклах
with_следует заменить на синтаксис"{{ var }}", который помогает устранить неоднозначность. - Файл требований в формате ansible-galaxy. Пользователи должны использовать формат YAML для требований вместо этого.
- Неопределенные переменные внутри списка цикла
with_в настоящее время не прерывают цикл, но выдают предупреждение; в будущем они будут вызывать ошибку. -
Использование переменных словарей для установки всех параметров задачи небезопасно и будет удалено в будущей версии. Например:
- hosts: localhost gather_facts: no vars: debug_params: msg: "hello there" tasks: # These are both deprecated: - debug: "{{debug_params}}" - debug: args: "{{debug_params}}" # Use this instead: - debug: msg: "{{debug_params['msg']}}" - Образцы хостов должны использовать запятую (,) или двоеточие (:) вместо точки с запятой (;), чтобы разделить хосты/группы в шаблоне.
- Диапазоны, указанные в образцах хостов, должны использовать синтаксис [x:y], а не [x-y].
- Playbooks, использующие повышение привилегий, должны всегда использовать опции «become*» вместо старых опций su*/sudo*.
-
«Короткий» формат для vars_prompt больше не поддерживается. Например:
vars_prompt: variable_name: "Prompt string" -
Указание переменных на верхнем уровне инструкции включения задачи больше не поддерживается. Например:
- include_tasks: foo.yml a: 1
Теперь должно быть:
- include_tasks: foo.yml
vars:
a: 1
- Установка any_errors_fatal в задаче больше не поддерживается. Это должно быть установлено только на уровне play.
- Простые переменные в словаре
environment(для play/задач и т.д.) больше не поддерживаются. Переменные, указанные там, должны использовать полный синтаксис переменных: ‘{{foo}}’. -
Теги (или любая директива) больше не должны указываться вместе с другими параметрами в инструкции включения задачи. Вместо этого они должны быть указаны в качестве опции в задаче. Например:
- include_tasks: foo.yml tags=a,b,c
Должно быть:
- include_tasks: foo.yml tags: [a, b, c]
- Опция first_available_file в задачах устарела. Пользователи должны использовать опцию with_first_found или плагин поиска (‘first_found’, …).
Другие особенности
Вот некоторые частные случаи, с которыми вы столкнулись при обновлении. Они в основном вызваны более строгим валидатором парсера и обработкой ошибок, которые ранее игнорировались.
-
Неправильное составление переменных:
with_items: myvar_{{rest_of_name}}Это работало «случайно», так как ошибки были повторно шаблонизированы и привели к разрешению переменной, но никогда не предполагалось, что это действительный синтаксис, и теперь он правильно возвращает ошибку. Используйте следующее вместо этого.:
hostvars[inventory_hostname]['myvar_' + rest_of_name]
-
Неправильно написанные директивы:
- task: dostuf becom: yes
Задача всегда запускалась без повышения привилегий (для этого требуется
become), но также молча игнорировалась, поэтому play «запускался», хотя этого не должно было быть. Теперь это ошибка парсинга. -
Повторные директивы:
- task: dostuf when: True when: False
Первая
whenбыла проигнорирована, и использовалась только вторая, так как play запускался без предупреждения, что одна из директив игнорируется. Теперь это ошибка парсинга. -
Смешение переменных и директив:
- role: {name=rosy, port=435 } # in tasks/main.yml - wait_for: port={{port}}Переменная
portзарезервирована как директива play/задачи для переопределения порта подключения. В предыдущих версиях она смешивалась с переменной, названнойport, и использовалась позже в play. Это создавало проблемы, если хост пытался подключиться снова или использовал некэшированное подключение. Теперь она будет правильно распознана как директива, и переменнаяportбудет отображаться как неопределенная. Это теперь заставляет использовать неконфликтные имена и устраняет неоднозначность при добавлении настроек и переменных к вызову роли. -
Простые операции над
with_:with_items: var1 + var2
Проблема с функциями «простых переменных», которые должны были шаблонизировать только одну переменную без необходимости фигурных скобок ({{ )}}, в некоторых версиях Ansible шаблонизировали полные выражения. Теперь вам нужно использовать правильную шаблонизацию и фигурные скобки для всех выражений, за исключением условных выражений (
when):with_items: "{{var1 + var2}}"Сама функция «простых переменных» устарела, так как неопределенная переменная неотличима от строки, что затрудняет вывод правильной ошибки.
Перенос плагинов
В ansible-1.9.x, как правило, копировался существующий плагин для создания нового. Простое реализация методов и атрибутов, ожидаемых вызывающим плагин, делало его плагином этого типа. В ansible-2.0 большинство плагинов реализуются путем наследования базового класса для каждого типа плагина. Таким образом, пользовательский плагин не должен содержать методы, которые не настроены.
Плагины поиска
- плагины поиска; версия импорта
Плагины подключения
- плагины подключения
Плагины действий
- плагины действий
Плагины обратной связи
Хотя Ansible 2.0 предоставляет новый API обратной связи, старый API продолжает работать для большинства плагинов обратной связи. Однако, если ваш плагин обратной связи использует self.playbook, self.play или self.task, вам придется хранить значения для этих параметров самостоятельно, так как Ansible больше не автоматически заполняет плагин обратной связи этими значениями. Вот небольшой фрагмент, который показывает, как это сделать:
import os
from ansible.plugins.callback import CallbackBase
class CallbackModule(CallbackBase):
def __init__(self):
self.playbook = None
self.playbook_name = None
self.play = None
self.task = None
def v2_playbook_on_start(self, playbook):
self.playbook = playbook
self.playbook_name = os.path.basename(self.playbook._file_name)
def v2_playbook_on_play_start(self, play):
self.play = play
def v2_playbook_on_task_start(self, task, is_conditional):
self.task = task
def v2_on_any(self, *args, **kwargs):
self._display.display('%s: %s: %s' % (self.playbook_name,
self.play.name, self.task))
Плагины подключения
- плагины подключения
Гибридные плагины
В некоторых случаях вам может потребоваться плагин, который поддерживает как ansible-1.9.x, так и ansible-2.0. Подобно портированию плагинов с версии v1 на v2, необходимо понять, как работают плагины в каждой версии, и обеспечить поддержку обоих требований.
Поскольку система плагинов ansible-2.0 более продвинутая, проще адаптировать ваш плагин для предоставления аналогичных элементов (подклассы, методы) для ansible-1.9.x, как ожидается ansible-2.0. Таким образом, ваш код будет выглядеть намного чище.
Следующие советы могут быть полезны:
- Проверьте, доступны ли классы ansible-2.0, и если они отсутствуют (ansible-1.9.x), имитируйте их с необходимыми методами (например,
__init__) - Когда импортируются модули python ansible-2.0, и они терпят неудачу (ansible-1.9.x), перехватывайте исключение
ImportErrorи выполняйте эквивалентные импорты для ansible-1.9.x. С возможными переводами (например, импортирование определенных методов). - Используйте наличие этих методов в качестве квалификатора для версии Ansible, которую вы используете. Поэтому вместо использования проверок версии можно использовать проверки возможностей. (См. примеры ниже)
- Документируйте каждый случай if-then-else, для какой версии необходим каждый блок. Это поможет другим понять, как нужно адаптировать свои плагины, но также поможет вам удалить поддержку более старых ansible-1.9.x, когда она устареет.
- При разработке плагинов очень полезно иметь метод
warning()во время разработки, но также важно выводить предупреждения об тупиковых ситуациях (случаях, которые, как вы ожидаете, никогда не будут вызваны) или граничных случаях (например, случаях, где вы ожидаете неправильной конфигурации). - Полезно посмотреть на другие плагины в ansible-1.9.x и ansible-2.0, чтобы понять, как работает API и какие модули, классы и методы доступны.
Плагины поиска
В качестве простого примера мы создадим гибридный fileglob плагин поиска.
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
import os
import glob
try:
# ansible-2.0
from ansible.plugins.lookup import LookupBase
except ImportError:
# ansible-1.9.x
class LookupBase(object):
def __init__(self, basedir=None, runner=None, **kwargs):
self.runner = runner
self.basedir = self.runner.basedir
def get_basedir(self, variables):
return self.basedir
try:
# ansible-1.9.x
from ansible.utils import (listify_lookup_plugin_terms, path_dwim, warning)
except ImportError:
# ansible-2.0
from ansible.utils.display import Display
warning = Display().warning
class LookupModule(LookupBase):
# For ansible-1.9.x, we added inject=None as valid argument
def run(self, terms, inject=None, variables=None, **kwargs):
# ansible-2.0, but we made this work for ansible-1.9.x too !
basedir = self.get_basedir(variables)
# ansible-1.9.x
if 'listify_lookup_plugin_terms' in globals():
terms = listify_lookup_plugin_terms(terms, basedir, inject)
ret = []
for term in terms:
term_file = os.path.basename(term)
# For ansible-1.9.x, we imported path_dwim() from ansible.utils
if 'path_dwim' in globals():
# ansible-1.9.x
dwimmed_path = path_dwim(basedir, os.path.dirname(term))
else:
# ansible-2.0
dwimmed_path = self._loader.path_dwim_relative(basedir, 'files', os.path.dirname(term))
globbed = glob.glob(os.path.join(dwimmed_path, term_file))
ret.extend(g for g in globbed if os.path.isfile(g))
return ret
Примечание
В приведенном выше примере мы не использовали метод warning(), поскольку для него не было прямого использования в окончательной версии. Однако мы оставили этот код, чтобы люди могли использовать эту часть во время разработки/портирования/использования.
Плагины подключения
- плагины подключения
Плагины действий
- плагины действий
Плагины обратной связи
- плагины обратной связи
Плагины подключения
- плагины подключения
Портирование пользовательских скриптов
Пользовательские скрипты, которые использовали API ansible.runner.Runner в версии 1.x, должны быть перенесены в версию 2.x. Обратитесь к: API Python
© 2012–2018 Michael DeHaan
© 2018–2021 Red Hat, Inc.
Licensed under the GNU General Public License version 3.
https://docs.ansible.com/ansible/2.11/porting_guides/porting_guide_2.0.html