amarao: (Default)
Отлаживаю почему ассерты медленные.

import_playbook стоит 100мс. Кадждый. То есть три плейбуки раздельно на 240мс быстрее, чем плейбука, которая в конце делает импорт двух остальных.

Сами ассерты - это какой-то ппц. Математика на группах 130мс (математика: assert that group.foo|d( [] ) intersect groups.bar |d ()). 130мс. На процессоре с частотой 4ГГц. Это 500 миллионов инструкций, чтобы обработать пересечение групп с ~50 строк в худшем случае. Ассерт на каждый хост при 50 хостах - 50*0.1 = 5с потерянного времени. Ассерт перед каждым приложением - 5*50 = 250с. Да, алгоритмически это квадрат, или даже куб, но мы говорим про 50 штук. 50**3 = 125000. Сколько нужно времени современному процессору, чтобы чихнуть 125 тысяч раз?

... Но не в ансибле. И я решаю не микрооптимизацию рендеринга кадра на 144Гц, а конкретные лишние несколько минут в пайплайне.

(и нет, митоген замедляет ассерты, это известный феномен).
amarao: (Default)
Я вызываю shell: ansible-inventory из плейбуки на ансибле, меняя `ANSIBLE_INVENTORY` (jinja поверх lookup/env) для того, чтобы динамически сформировать инвентори для ансибла на удалённом сервере, потому что так быстрее.

/facepalm, /selfawe, /sadness
amarao: (Default)
Я очень долго искал замену молекуле, но не нашёл.

Наша проблема: у нас тяжёлый converge, тяжёлый create (и иногда тяжёлый prepare). Мы не можем плодить по сценарию на каждый чих.

Однако, у нас большой и сложный сценарий тестирования: сделай то, проверь то, сделай это, проверь это и т.д. 10-20-30 этапов - запросто. Сами этапы простейшие, и ради них городить полный цикл глупо.

Один этап легко ложится на side effect, но нам надо много.

Перепробовав всё, я сел за потрохи молекулы.
https://github.com/amarao/molecule/commit/e0d9f188809634ff240a08fda447794e106c0927

идея: к стадиям side-effect и verify добавить поддержку параметра, указывающего что именно side-effect, и какие именно тесты запускать.

Примерно так:

test_sequence:
  - create
  - prepare
  - converge
  - verify
  - side_effect good_foo.yaml
  - verify good_foo_tests/
  - side_effect second_foo.yaml
  - verify two_foo_tests/
  - side_effect bar.yaml
  - verify bar_tests/
  - idempotence
  - cleanup
  - destroy


Пока что я расковырял самую мякотку (куда писать) и ещё обдумываю детали реализации. Но я полон решимости, даже если в апстрим не примут.
amarao: (Default)

Добавил режим state=query.

Теперь можно сделать так:

    - name: Get ip information from agge interface
      amarao.ip.ip_address:
        name: agge
        state: query
      register: addr
    - debug: var=addr

и получить вот так:

"addr": {
    "addresses_v4": [
        "173.237.37.20/29"
    ],
    "addresses_v6": [
        "2600:9c00:3:2::/64",
        "2600:9c00:999::54/125",
        "fe80::b696:91ff:fe5d:a126/64"
    ],
    "changed": false,
    "failed": false
}

Прям с маской, чего нельзя в ansible_ipv6_addresses.

https://galaxy.ansible.com/amarao/ip

amarao: (Default)

А вот я хочу продолжить думать умное про ансибл, ci/cd и прочую рабочую фигню между гитом и сервером.

Классическое программирование стремится абстрагироваться от ввода-вывода. Идеалом программы (имплементации алгоритма) является полностью определённая функция, которая для заданных входных значений выдаёт определённые выходные. При этом такая программа работает в полностью определённой среде (мы знаем список доступных состояний машины Тьюринга, либо используем только хорошо нам известные функции, если работаем в функциональной модели).

Теперь посмотрим на "best practice для Ansible". Всё, что происходит - это сайд-эффекты. Некоторые из них предсказуемы, некоторые условно предсказуемы, некоторые не совсем предсказуемы. Часть сайд-эффектов имеют в качестве зависимости внешний мир (т.е. могут фейлиться по каким-то внешним причинам не связанным с нашим кодом).

В программировании существует модель описания этого, посредством интерейсов. Мол, у нас неконтролируемое "нечто" снаружи, консистентность внутри, и есть код, задача которого описать "нечто снаружи" в терминах, которые устраивают модель внутри. Если мир расходится с моделью, это это EnvironmentError, который мы можем пытаться описывать в терминах нашей модели (и может, даже, исправлять).

Но у такого подхода есть фатальная проблема: она не следует за реальностью. В момент разработки модели кто-то должен придумать модель, которая достаточно хорошо описывает реальность. Если количество "отклонений" станет слишком большим, то (пусть и консистентная) модель внутри будет неактуальной будет всё портить (или просто не работать).

И вот тут вот появляется парадигма, условно, админская. Девопс, ансибл, iaac, называйте как хотите. Это форма компьютерного экзестенциализима, которая принимает систему "as is", без чрезмерной строгости. Модель стремится к уменьшению и упрощению, и чем проще модель, тем меньше она отличается от реальности. От модели оставляют только то, что минимально необходимо для решения задачи. Интерпретация происходящего предельно близка к утиной типизации (если у нас получилось сделать то, что нужно, то это хорошо, а что это именно - уже не совсем важно).

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

Почему это упрощение неизбежно?

Потому что сисадминский код взаимодействует с необъятно сложными системами. Каждый второй модуль того же Ансибла, за собой тащит необъятную сложность. Вот, предположим, мы поднимаем виртуалку с постгрес и настраиваем в ней пользователя.

Сначала мы общаемся с пакетным менеджером. Модель пактного менеджера - это граф зависимостей, который разрешается в непротиворечивую комбинацию пакетов, либо оставляет систему в broken state. Взаимодействие с пакетным менеджером в общем случае должно предусматривать графы как структуры данных. Это очень много. Пакетный менеджер так же зависит от системы доверия ключам, которая в свою очередь зависит от даты, установленных ключей и чужих серверов. Ещё у нас могут быть transient проблемы: например, блокировка доступа к пакетному менеджеру из-за параллельного процесса (cloud-init, unattended updates, etc).

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

Где-то тут же у нас есть модель файловой системы, поскольку образ будущей VM куда-то положен в файловой системе.

Потом мы погружаемся в мир XML для libvirt'а с одной стороны (надо правильно расставлять атрибуты и ноды внутри xml tree), и в мир устройства виртуальных машин с другой.

Виртуальные машины в свою очередь имеют несколько domain specific областей - концепцию "машины", внутри которой есть PCI-шина (ещё одно дерево с крайне запутанной и сложной логикой), сети (которая включает в себя целые пласты знаний про бриджи, раутинг, macvtap, pci passthrough, nat, etc).

Потом мы оказываемся в опять с пакетным менеджером.

Потом с нами здоровается мануал по postgres, где для правильного описания прав пользователя нужно знать какие базы данных, схемы, таблицы и т.д. нужно давать. И всё это весьма и весьма нетривиально.

Заметим, это всё находится поверх сетевой абстракции хоста, и транспортной абстракции ssh, через (очень хорошо работающий) слой абстрации по запуску питона через ssh внутри ansiballZ.

Это не сложно, это необъятно сложно. Любая попытка "сделать правильно" (т.е. формировать XML как осмысленное дерево, конструирование дерева PCI-устройств, поддержка полной модели прав пользователей postgres или графа зависимостей в apt) приведёт к одному или комбинации нескольких результатов: * Непозводительно медленная разработка (десятки тысяч строк кода), закончившаяся ничем. * Ошибки в описании предметной области, которые критичеки нарушают точность модели (не всё предусмотрено). * Перегрузка получившегося кода излишними понятиями, которые не нужны для достижения результата.

Таким образом, "реализовать правильно" (т.е. реализовать честный интерфейс из предметной области в модель) мы не можем из-за слишком высокой сложности и разнообразности предметной области.

Какие альтернативы? Начать реализовывать правильно и не дореализовать (см список последствий выше). Или... Не реализовывать вообще, а использовать компьютерный экзестенцианализм в чистом виде. Что нас, на самом деле, и приводит к best practices Ансибла: * Список пакетов для установки с retries для защиты от локов. * Хардкоженный список элементов для image builder'а. * template из XML, в котором мы руками пишем львиную долю, заменяя минимальное количество элементов для интерполяции. * Минимальный по сложности код заведения пользователя в postgres, возможно, не обладающий максимальной точностью по правам (если нет такой потребности).

Такой поверхностный подход позволяет сделать быстро и всё, что нужно. При этом он всегда страдает неполнотой и неожиданностями (теперь к transient ошибкам добавляются ошибки ожиданий, потому что мы делаем, например, не xml, а текстовый файл похожий на xml).

Что делать для повышения надёжности? Вместо уточнения и усложнения модели (что приведёт нас в трясину, описанную выше), мы просто стараемся покрыть тестами наши простые сценарии использования, зафиксировать зависимости.

Это всё работает не до конца, потому что IRL может оказываться отличным от наших ожиданий в момент тестов. В конце там ещё один комплект тестов, на этот раз инфраструктурных, которые проверяют, что сделанное одним образом соответствует ожиданиям, проверенным другим образом (поставили postgres apt'ом, проверили, что порт слушает).

Таким образом, философия сайд-эффектов кардинально отличается от философии программирования (как полу-математической дисциплины). Принятие этого факта позволяет избежать довольно распространённого феномена "программировать на ансибле", который бывает двух видов: принятие решений и попытка "понять" предметную область. Есть борьба с принятием решений в ансибле - это героический подвиг во имя улучшения сопровождения (всё время подвиги и не всегда успех), то отказ от "понимания" предметной области (на самом деле - трансляции предметной области в структуры данных), это философская максима, которую легко реализовать, для которой легко заметить отклонения, и в целом, реализуемая задача.

APython

Mar. 9th, 2021 01:38 pm
amarao: (Default)
troll mode:

Специальный интерпретатор питона, написанный на ансибле с помощью конечного автомата на хэндлерах. В начале делается set_fact для code с содержимым желаемого python-файла, а дальше он парсится с помощью набора when и рекурсивных include, потом исполняется посредством хэндлеров от include_role, которые делают notify/listen друг другу, разумеется, вместе с when. В некоторых случаях приходится делать в качестве таски для хэндлера include_role (так, например, всё IO делается).

В принципе, внутри кода можно написать import remote_pdb; remote_pdb.set_trace() и тогда ансибл в хэндлерах будет поллить сокеты и давать repr-шелл внутрь этого питона.

Enjoy your debugging.

Для слабых духом можно предложить транспайлер из питона в ансибл py2ansible - всё то же самое, но уже транспилированное в плейбуки. Вот тогда можно будет программировать на ансибле.

Profile

amarao: (Default)
amarao

August 2025

S M T W T F S
     12
3456789
10111213141516
17181920212223
24252627282930
31      

Syndicate

RSS Atom

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated Aug. 6th, 2025 05:43 am
Powered by Dreamwidth Studios