Fabric: v2-совместимые "роли" или аналогичные

Созданный на 22 апр. 2017  ·  7Комментарии  ·  Источник: fabric/fabric

Синопсис

На момент написания в ветке v2 есть класс Group который должен быть способен служить в качестве единиц, ранее известных как «роли», иначе говоря, «группа хостов, с помощью которых и с / на которых можно что-то делать».

Однако пока не существует определенного способа организации или маркировки объектов Group ; этого достаточно для случая использования чистого API продвинутыми пользователями, которые хотят использовать свой собственный способ их создания, но не хватает чего-либо для пользователей, ориентированных на CLI, или промежуточных людей, которые хотят построить что-то каркасное.

Другими словами, если вы не работаете исключительно с API, наличие объектов Group, лежащих где-то поблизости, бесполезно, если CLI или биты вызова задач не имеют возможности их найти!

Фон

В v1 роли фактически представляли собой единое плоское пространство имен, сопоставляющее простые строковые метки с тем, что было бы группами в v2, и они могли быть выбраны в CLI во время выполнения ( fab --roles=web,db ) и / или зарегистрированы как цели по умолчанию для задач ( @task('db') \n def migrate(): ), как и хосты.

Пользователи определили их в env.roledefs , простом слове; любые промежуточные и расширенные функциональные возможности связаны с их изменением, обычно во время выполнения (с помощью предварительной задачи или подпрограммы), иногда во время загрузки модуля.

Конкретные варианты использования / потребности / дополнительные функции

  • Базовое, наивное сопоставление для использования / ссылки в любом другом месте системы: введите имя, верните несколько итераций из Group s и / или Connection s.

    • Часто псевдонимы хотят присоединиться к этому, поэтому, например, Lexicon вместо dict .

    • Даже более глубокие конструкции, такие как «связывание», например, у вас есть прямые сопоставления с именами db , web , lb , но затем имя второго уровня называется prod который всегда является объединением трех других. Я забыл, добавил ли я это в Lexicon . Возможно, есть другие подклассы карт, которые уже делают это.

    • Вдобавок / альтернативно, такие вещи, как подстановка символов или другие строковые синтаксисы, хотя я лично предпочел бы использовать тот факт, что Python не "строго типизирован" ...

  • Полезное «обратное сопоставление», позволяющее определить, к каким группам принадлежит данное соединение.

    • Проблема: поскольку в настоящее время нет глобального общего состояния, наивный ответ на этот вопрос - использование идентификатора - падает, потому что вы можете технически создать несколько идентичных объектов Connection.

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

    • Однако, учитывая это ограничение отсутствия глобального состояния, я не вижу очевидных проблем с использованием вместо этого тестирования равенства, поэтому это должно быть выполнимо, например, if cxn in group будет работать, даже если cxn - отдельный объект от равного члена внутри group .

    • Единственное, что приходит на ум, - это наличие сильных, отслеживающих состояние ссылок от Соединения к Группе (должны быть группы, во множественном числе), которые удерживают его, а не наоборот, но я не вижу веских причин для этого навскидку.

  • Сильно связано с предыдущим: способность проверять / отображать, что такое «текущая роль» (что-то, чего люди давно хотели в v1, что было нетривиальным из-за его дизайна)

    • Основная проблема заключается в том, что на самом деле это два полуразличных вопроса: «какая роль (роли) является текущей частью хоста, вообще говоря» (в основном, предыдущий вариант использования обратного поиска), но также «какая роль (роли) была машина исполнения специально просила противостоять ".

    • Другими словами, данный хост 'foo', принадлежащий ролям A, B и C: в рамках данной задачи, контекст которой равен 'foo', но которая была запущена из-за запроса на выполнение роли A, является пользователем, ищущим ответ «A, B и C» (в целом роли «foo») или просто «A» (текущая исполняющая роль)?

    • Это действительно похоже на два разных вызова API, хотя запросы функций, которые я помню, объединяют их.

  • Выбор цели в интерфейсе командной строки, глобально и / или для каждой задачи

    • Расширение системы CLI Invoke для учета «флагов, которые все задачи получают поверх того, что они определяют», может быть полезным или необходимым для этого. Фактически, это точно относится к территории pyinvoke / invoke # 205, так что это только что получило более высокий приоритет, чем был (который был довольно высоким).

  • То же самое по умолчанию на уровне задачи

    • Хотя целевые значения по умолчанию на уровне задачи действительно хотят быть одним из следующих: соединение, соединения, групповые объекты, групповые объекты или имя, оценивающее _to_ групповые объекты (возможно, это единственное, что имеет непосредственное отношение к этому билету)

  • То же самое по умолчанию на уровне коллекции (НОВИНКА в версии 2!)

    • Т.е. "все задачи в подмодуле $ по умолчанию выполняются с ролью db "

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

  • Есть ли что-нибудь еще новое и захватывающее, связанное с объектно-ориентированным подходом, которое действительно хочет пойти вместе с этим? Помните, что упор следует делать на строительных блоках и предоставлении возможностей для продвинутых пользователей, а не на, например, полностью изобретать системы, такие как Chef или Ansible.

Идеи / проблемы по реализации

  • Если мы использовали конфигурационную систему в качестве основного вектора хранилища, значения «хотят» быть примитивами, чтобы их можно было хранить в yaml, json и т. Д., Но это баня червей, заканчивающаяся на «хранить все группы / подключения kwarg в большом ol» list-o-dicts "и др.
  • Если мы ожидаем, что определения будут в основном на Python, мы можем просто сказать «создать экземпляры групповых объектов», а затем у нас есть возможность объединить эти данные в систему конфигурации или как-то оставить ее автономной.

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

  • Более глубокие конструкции, такие как псевдоним и объединение, добавляют сложности и проблемы с упорядочением (т.е. представьте себе тривиальную настройку псевдонима, где значение key1 является группой, а значение key2 - key1; теперь вам нужно дважды сканировать структуру, чтобы разрешить или проверить key2)

    • хотя, если мы пойдем в основном на подход «сделай это в питоне», он станет во многом похожим на API системы конфигурации, где вы можете начать с декларативной структуры, но после этой начальной настройки вызовами методов разрешается что-то еще. Не думаю, что это ужасно? РЕДАКТИРОВАТЬ: и я думаю, что именно так работает Lexicon.

  • Независимо от формата, мы должны выяснить, как опытные пользователи захотят генерировать его «на лету» из внешних источников или аналогичных; это плюс проблемы с псевдонимом и тому подобное, подразумевает, что мы, возможно, не хотим, чтобы это было в наивной структуре, «хранящейся» где-то, а как API для некоторого объекта или объектов, который вызывается для его генерации.

    • Я подозреваю, что мы можем захотеть работать «вниз» от выбора ролей / групп, придя к тому, что API самого высокого уровня предназначено для «превращения того, что пользователь предоставил, в действенную единицу целей», потому что наиболее продвинутые пользователи обязательно захотят иметь полный контроль над реализацией этого вызова API. Тогда мы, как всегда, можем предложить то, что кажется полезным общим случаем, но которое четко обозначено как «только один способ сделать это».

    • У @RedKrieg есть отличная идея в этих строках, где у нас есть @group например @task , а функции не являются исполняемыми единицами работы, а вместо этого выдают объекты Group.

    • Этот подход изначально повторно использует иерархию задач (Коллекция), что практично (зачем изобретать колесо) и элегантно (потому что в реальных случаях определения ролей / групп часто очень точно соответствуют задачам, использующим их!)



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



    • Мне неясно, лучше ли это возвращать одну группу из каждой функции, или нам нужна возможность создавать несколько групп (или соединений), или лучше всего делать это вообще не как декорированные функции, а просто как вызовы API. Коллекция (например, как хранятся конфигурации уровня коллекции).

    • Например, вариант использования, когда данные группы / роли являются динамическими и находятся вне Fabric, все еще требует решения (вот почему ранее я отмечал, что мы сначала должны идентифицировать API самого высокого уровня для этого пространства; затем нам нужно увидеть, как это связано с этой идеей среднего уровня.)

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

Привет, я не знаю, что случилось с этим программным обеспечением через много лет, но мне очень не хватало концепции «ролей» в [email protected] , особенно при запуске $ fab -R dev

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

Из списка рассылки:

Мы внедрили наш собственный внутренний REST API, который динамически заполняет env.roledefs в зависимости от развертываемого проекта и сильно полагается на то, что не встраивает строки хоста в fabfile проекта или не указывает их в CLI.

Наши варианты использования:

  1. Кодовая база, свободная от окружающей среды https://12factor.net/config. Среды (роли) и соответствующие им строки хоста хранятся в централизованной базе данных. В каждом файле fabfile.py есть что-то вроде этого (он заполняет env.roledefs при импорте файла):
EnvironmentDatabaseAPIClient(
    'https://rest.api.url/schema/',
    env.service_name,
).apply_env()
  1. Количество серверных сред - несколько сред тестирования (некоторые из них частные, некоторые общедоступные) и несколько производственных сред (для разных клиентов). Каждая среда состоит из одного или нескольких хостов и сопоставлена ​​роли фабрики.

  2. Каждая служба ( env.service_name в приведенном выше примере) имеет разный набор сред.

  3. Также у нас есть мета-роли (группы ролей). Они имеют префикс group- : group-production , group-test , group-external , group-internal , group-all . Это позволяет нам выполнять развертывание на нескольких ролях сервера, не указывая их одну за другой, например group-all развертывается для всех ролей, как производственных, так и тестовых.

  4. У нас есть специальные задачи фабрики для печати информации о группах ролей, ролях и хостах.

  5. Мы также сильно полагаемся на обратное сопоставление строк хоста с именами ролей (строки хостов уникальны для каждого service_name). Это используется для ведения журнала развертывания и уведомлений. По сути, мы регистрируем развертывание службы на каждом хосте и отправляем уведомление Slack, когда служба была развернута на всех хостах в роли. За это отвечает сервер EnvironmentDatabaseAPI (он ведет журналы и состояние развертывания). Это делается путем украшения задач фабрики декоратором, который отправляет env.host , env.port и env.service_name (плюс информацию о фиксации) обратно на сервер API.

  6. Мы планируем добавить аутентификацию развертывания в будущем, также очень вероятно, что будет извлекать больше переменных env с сервера, чтобы сделать их доступными в контексте задачи.

Спасибо @ max-arnold! Я узнал многие из них из моих собственных примеров использования в прошлом. В частности, бит обратного сопоставления, как я помню, несколько раз появлялся в v1, поэтому я добавил его в список.

Чтобы Fabric v2 стала для меня полезной, мне понадобится способ указать fab каком наборе хостов выполнять задачу.

Раньше я определял роли, а затем запускал fab -R ... . (На самом деле роли были определены программно с использованием диапазона IP-адресов, но это не является обязательным требованием, и статический список внутри файла YAML подойдет.)

Мне не удалось найти эквивалент в Fabric v2, и мне также не удалось эмулировать эту функцию, используя:

  • файл конфигурации fabric.yaml содержащий
active_hostset: null
hostsets:
  myhostset:
  - ...
  • active_hostset = config["hostsets"][config["active_hostset"]] в fabfile.py
  • env INVOKE_ACTIVE_HOSTSET=myhostset fab ...

Вместо ожидаемого списка хостов я получаю KeyError: 'active_hostset' .

Мы сопоставляем разные наборы хостов каждой роли для каждой из наших сред в фабрике v1, и среда устанавливается путем выполнения задачи role.environment:staging чтобы указать ее. Таким образом, эта задача влияет на хосты, используемые следующими задачами.

В версии 2 мы пытались использовать настраиваемую задачу, но проблема в том, что Executor.expand_calls запускается до запуска нашей задачи role.environment и поэтому ни одна из следующих задач не знает среды, чтобы динамически создавать списки своих хостов.

Создание генератора Executor.expand_calls позволяет выполнению задачи влиять на выполнение последующих задач. Итак, мой пример выше работает, когда у нас есть пользовательский Task который должен знать свою среду, чтобы должным образом расширять роли для хостов. например, fab role.environment dev deploy.app - задача role.environment теперь запускается до того, как deploy.app раскрывается, и поэтому deploy.app знает среду и может настраивать ее хосты, а затем расширяется в правильный набор задач.

Я прототипировал это в своих вилках:
https://github.com/pyinvoke/invoke/compare/master...rectalogic : генератор расширения
https://github.com/fabric/fabric/compare/master...rectalogic : генератор расширений

Привет, я не знаю, что случилось с этим программным обеспечением через много лет, но мне очень не хватало концепции «ролей» в [email protected] , особенно при запуске $ fab -R dev

Мы также используем роли для представления одного и того же набора операций в разных средах. Возможно, было бы полезно разделить концепцию именованной роли и именованной среды? Например, веб-роль в среде разработки.

Была ли эта страница полезной?
0 / 5 - 0 рейтинги