Руководство по переносу Ansible 2.0
В этом разделе обсуждаются изменения поведения между Ansible 1.x и Ansible 2.0.
Он предназначен для помощи в обновлении ваших playbooks, плагинов и других частей вашей инфраструктуры Ansible, чтобы они работали с этой версией Ansible.
Мы рекомендуем вам прочитать эту страницу вместе с Журналом изменений Ansible, чтобы понять, какие обновления вам могут потребоваться.
Этот документ является частью коллекции руководств по переносу. Полный список руководств по переносу можно найти по адресу руководствам по переносу.
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. - Плагины обратного вызова extras должны быть внесены в белый список в ansible.cfg. Копирование больше не требуется, но внесение в белый список в ansible.cfg необходимо выполнить.
- Модуль dnf был переписан. Могут наблюдаться незначительные изменения в поведении.
- win_updates был переписан и теперь работает как ожидается.
- начиная с версии 2.0.1, неявная задача setup из gather_facts теперь правильно наследует все от play, но это может вызвать проблемы для тех, кто устанавливает
environmentна уровне play и зависит отansible_env.
Устаревшие элементы
Хотя все перечисленные элементы будут показывать предупреждение об устаревании, они по-прежнему работают так же, как и в версии 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 не поддерживается. Например:
- include_tasks: foo.yml a: 1
Должно быть:
- include_tasks: foo.yml
vars:
a: 1
- Указание any_errors_fatal в задаче больше не поддерживается. Это должно быть установлено только на уровне play.
- Голые переменные в словаре
environment(для play/задач и т. д.) больше не поддерживаются. Переменные, указанные там, должны использовать полный синтаксис переменных: «{{foo}}». -
Теги (или любые директивы) больше не должны указываться с другими параметрами в задаче include. Вместо этого они должны быть указаны как опция задачи. Например:
- include_tasks: foo.yml tags=a,b,c
Должно быть:
- include_tasks: foo.yml tags: [a, b, c]
- Опция first_available_file в задачах устарела. Пользователи должны использовать опцию with_first_found или плагин lookup (‘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 большинство плагинов реализуются путем наследования базового класса для каждого типа плагина. Таким образом, пользовательский плагин не должен содержать методы, которые не настраиваются.
Плагины lookup
- плагины lookup; версия импорта
Плагины соединения
- плагины соединения
Плагины действий
- плагины действий
Плагины обратного вызова
Хотя 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. Подобно переносу плагинов из версии 1 в версию 2, вам нужно понять, как плагины работают в каждой версии, и поддерживать оба требования.
Поскольку система плагинов 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 __main__ 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. См.: Python API
© 2012–2018 Michael DeHaan
© 2018–2019 Red Hat, Inc.
Licensed under the GNU General Public License version 3.
https://docs.ansible.com/ansible/2.5/porting_guides/porting_guide_2.0.html