Подключаемые модули сети
Каждый подключаемый модуль подключения к сети имеет набор собственных подключаемых модулей, которые предоставляют спецификацию подключения для определённого набора устройств. Конкретный используемый подключаемый модуль выбирается во время выполнения на основе значения переменной ansible_network_os , присвоенной хосту. Эта переменная должна быть установлена в такое же значение, как имя подключаемого модуля, который необходимо загрузить. Таким образом, ansible_network_os=nxos будет пытаться загрузить подключаемый модуль в файле с именем nxos.py, поэтому важно назвать подключаемый модуль осмысленно для пользователей.
Общедоступные методы этих подключаемых модулей могут вызываться из модуля или module_utils с объектом прокси-подключения, точно так же, как и другие методы подключения. Ниже приведён очень простой пример использования такого вызова в файле module_utils, чтобы его можно было использовать совместно с другими модулями.
from ansible.module_utils.connection import Connection
def get_config(module):
# module is your AnsibleModule instance.
connection = Connection(module._socket_path)
# You can now call any method (that doesn't start with '_') of the connection
# plugin or its platform-specific plugin
return connection.get_config()
- Разработка подключаемых модулей httpapi
- Разработка подключаемых модулей NETCONF
- Разработка подключаемых модулей network_cli
Разработка подключаемых модулей httpapi
httpapi plugins служат адаптерами для различных API HTTP(S) для использования с подключаемым модулем подключения httpapi. Они должны реализовывать минимальный набор удобных методов, настроенных на API, который вы пытаетесь использовать.
В частности, существует несколько методов, которые подключаемый модуль подключения httpapi ожидает найти.
Отправка запросов
Подключаемый модуль подключения httpapi имеет метод send(), но подключаемый модуль httpapi нуждается в методе send_request(self, data, **message_kwargs), как в оболочке более высокого уровня для send(). Этот метод должен подготавливать запросы, добавляя такие фиксированные значения, как общие заголовки или корневые пути URL. Этот метод может выполнять более сложные задачи, такие как преобразование данных в отформатированные полезные данные или определение пути или метода запроса. Затем он может также распаковать ответы, чтобы их проще было обработать вызывающей стороне.
from ansible.module_utils.six.moves.urllib.error import HTTPError
def send_request(self, data, path, method='POST'):
# Fixed headers for requests
headers = {'Content-Type': 'application/json'}
try:
response, response_content = self.connection.send(path, data, method=method, headers=headers)
except HTTPError as exc:
return exc.code, exc.read()
# handle_response (defined separately) will take the format returned by the device
# and transform it into something more suitable for use by modules.
# This may be JSON text to Python dictionaries, for example.
return handle_response(response_content)
Аутентификация
По умолчанию все запросы будут аутентифицироваться с помощью аутентификации HTTP Basic. Если запрос может вернуть какой-либо токен вместо аутентификации HTTP Basic, метод update_auth(self, response, response_text) должен быть реализован для проверки ответов на наличие таких токенов. Если токен предназначен для включения в заголовки каждого запроса, достаточно вернуть словарь, который будет объединён с вычисленными заголовками для каждого запроса. Стандартная реализация этого метода делает именно это для куки. Если токен используется другим способом, например, в строке запроса, вы должны вместо этого сохранить этот токен в переменную экземпляра, где метод send_request() (выше) может добавить его в каждый запрос
def update_auth(self, response, response_text):
cookie = response.info().get('Set-Cookie')
if cookie:
return {'Cookie': cookie}
return None
Если вместо этого требуется явный конечный пункт входа для получения токена аутентификации, метод login(self, username, password) может быть реализован для вызова этого конечного пункта. При наличии реализации этот метод будет вызываться один раз перед запросом любых других ресурсов сервера. По умолчанию он также будет выполняться один раз при получении HTTP 401 от запроса.
def login(self, username, password):
login_path = '/my/login/path'
data = {'user': username, 'password': password}
response = self.send_request(data, path=login_path)
try:
# This is still sent as an HTTP header, so we can set our connection's _auth
# variable manually. If the token is returned to the device in another way,
# you will have to keep track of it another way and make sure that it is sent
# with the rest of the request from send_request()
self.connection._auth = {'X-api-token': response['token']}
except KeyError:
raise AnsibleAuthenticationFailure(message="Failed to acquire login token.")
Аналогично, logout(self) может быть реализован для вызова конечной точки для аннулирования и/или высвобождения текущего токена, если такая конечная точка существует. Это будет автоматически вызываться при закрытии соединения (и, соответственно, при сбросе).
def logout(self):
logout_path = '/my/logout/path'
self.send_request(None, path=logout_path)
# Clean up tokens
self.connection._auth = None
Обработка ошибок
Метод handle_httperror(self, exception) может обрабатывать статусные коды, возвращаемые сервером. Значение возвращаемого значения указывает, как подключаемый модуль будет продолжать запрос:
- Значение
trueозначает, что запрос может быть повторён. Это может использоваться для указания временной ошибки или ошибки, которая была решена. Например, стандартная реализация попытается вызватьlogin()при получении 401 и вернётtrueпри успехе. - Значение
falseозначает, что подключаемый модуль не может восстановиться от этого ответа. Код состояния будет возвращён вызывающему модулю в качестве исключения. Любое другое значение будет рассматриваться как некритический ответ на запрос. Это может быть полезно, если сервер возвращает сообщения об ошибках в теле ответа. Возврат исходного исключения обычно достаточен в этом случае, так как объекты HTTPError имеют тот же интерфейс, что и успешный ответ.
Например, подключаемые модули httpapi см. в исходном коде подключаемых модулей httpapi, включённом в Ansible Core.
Разработка подключаемых модулей NETCONF
Подключаемый модуль подключения netconf предоставляет подключение к удалённым устройствам через подсистему SSH NETCONF. Устройства сети обычно используют этот подключаемый модуль подключения для отправки и получения вызовов RPC через NETCONF.
Подключаемый модуль подключения netconf использует библиотеку Python ncclient в качестве внутренней реализации для инициирования сессии NETCONF с удалённым устройством сети, поддерживающим NETCONF. ncclient также выполняет NETCONF запросы RPC и получает ответы. Вам необходимо установить ncclient на локальном контроллере Ansible.
Чтобы использовать подключаемый модуль подключения netconf для устройств сети, поддерживающих стандартные операции NETCONF (RFC 6241), такие как get, get-config, edit-config, задайте ansible_network_os=default. Вы можете использовать модули netconf_get, netconf_config и netconf_rpc для работы с удалённым хостом, поддерживающим NETCONF.
Как разработчику и пользователю, вы должны иметь возможность использовать все методы в классе NetconfBase, если ваше устройство поддерживает стандартный NETCONF. Вы можете внести вклад в новый подключаемый модуль, если устройство, с которым вы работаете, имеет специфичный для поставщика NETCONF RPC. Чтобы поддержать специфический для поставщика NETCONF RPC, добавьте реализацию в подключаемый модуль NETCONF, специфичный для операционной системы сети.
Например, для Junos:
- См. методы RPC Junos, специфичные для поставщика, реализованные в
plugins/netconf/junos.py. - Установите значение
ansible_network_osна имя файла подключаемого модуля netconf, то естьjunosв этом случае.
Разработка подключаемых модулей network_cli
Тип подключения network_cli использует paramiko_ssh в качестве внутренней реализации, которая создаёт псевдотерминал для отправки команд и получения ответов. network_cli загружает два подключаемых модуля, специфичные для платформы, на основе значения ansible_network_os:
- Подключаемый модуль терминала (например,
plugins/terminal/ios.py) — управляет параметрами, относящимися к терминалу, такими как установка длины и ширины терминала, отключение страниц и повышение привилегий. Также определяет регулярные выражения для идентификации командной строки и сообщений об ошибках. -
Подключаемые модули cliconf (например, ios cliconf) — предоставляет абстракционный уровень для операций отправки и получения низкого уровня. Например, метод
edit_config()гарантирует, что приглашение находится в режимеconfigперед выполнением команд конфигурации.
Чтобы внести вклад в новую операционную систему сети для работы с подключением network_cli, реализуйте подключаемые модули cliconf и terminal для этой операционной системы сети.
Подключаемые модули могут располагаться в:
-
Соседние с playbook в папках
cliconf_plugins/ terminal_plugins/
-
Роли
myrole/cliconf_plugins/ myrole/terminal_plugins/
-
Коллекции
myorg/mycollection/plugins/terminal/ myorg/mycollection/plugins/cliconf/
Пользователь также может установить DEFAULT_CLICONF_PLUGIN_PATH для настройки пути подключаемого модуля cliconf.
После добавления подключаемых модулей cliconf и terminal в ожидаемые расположения пользователи могут:
- Использовать cli_command для запуска произвольной команды на устройстве сети.
- Использовать cli_config для внесения изменений в конфигурацию на удалённых хостах без модулей, специфичных для платформы.
© 2012–2018 Michael DeHaan
© 2018–2019 Red Hat, Inc.
Licensed under the GNU General Public License version 3.
https://docs.ansible.com/ansible/2.9/network/dev_guide/developing_plugins_network.html