Category: it

Category was added automatically. Read all entries about "it".

404

CI без сервера

А вот у меня есть такой запрос: я хочу иметь CI-подобный инструмент (задачи/автоматически вычисляемые зависимости порядка выполнения, параметры, matrix и т.д.), но без сервера. Чтобы не было веб-морды и сервера, а было что-то вида

`ci-run ci.yaml` (в чём эта штука выполняется - следующий вопрос). И чтобы из ci.yaml автоматически вытекало всё остальное. Логи на экран, что выполнять, статусы, зависимости, cleanup и т.д.

Разумеется, opensource. Что-то мне в голову ничего не приходит.
404

Проблемы от ipv6

Всех интересует, какие проблемы от него.

И вот я накопал. Ничего существенного, но то, что есть, раздражает и усложняет.

1. В половине софта обращение по ipv6 требует использования квадратных скобок. А в половине - нет. Т.е. если у вас server_fqdn был 192.168.0.1, то вам это прокатывало как для ping, так и для curl. А если server_fqdn fdcd:ba4a:a9b::2, то в ping оно должно быть as is, а в curl - [fdcd:ba4a:a9b::2]. И в ssh.

Да, если будете страдать, то ssh -L 127.0.0.1:5000:[fdcd:ba4a:a9b::2]:5000 user@fdcd:ba4a:a9b::2

2. leading zeroes. fdcd:ba4a:a9b::2 или fdcd:ba4a:0a9b::2? Оказывается, для testinfra это важно. А ещё в куче мест, где есть assert строковому равенству, или хранится и показывается "как записали", что в свою очередь приводит к строковому равенству.

Вся эта чехарда с leadning zeroes настолько неприятная, что я для себя сделал зарубку - никаких трёхзнаков в адресах. Проще будет.
404

А вот вам пост об исторической нелогичности

Вот есть у меня файл /etc/default/grub.d/unified.cfg для включения unified cgroups для systemd.

А вот вопрос (ответ на который я хорошо знаю, но существование которого всё равно показывает проблему): почему этот конфиг лежит в /etc/default, а не /etc/grub.d/?

И ведь на каждом шаге решение было логичным, вроде бы. Но что-то пошло не так.

Например, являются ли файлами конфигурации /etc/grub.d?

Я утверждаю, что нет. Потому что там (в 00_header) прямо написано

# grub-mkconfig helper script.
# Copyright (C) 2006,2007,2008,2009,2010  Free Software Foundation, Inc.


А если это технический скрипт, то почему он не лежит в /usr/lib? Инерция сознания. Ведь это "конфиги граба". Хотя на самом деле истинные конфиги граба лежат в /boot/grub/grub.cfg, но это не истинное место для редактирования настроек.

А истинное - в /etc/default, которое, традиционно, было микропомоечкой для параметров sysv-init скриптов, которые админы могли изменить. ..Потому что /etc/rc* тоже не были конфигами, а были скриптами, к которым нужны были параметры.

Так что параметры grub'а лежат в /etc/default, потому что его скрипты лежат в /etc/grub. Логично? Логично. Не логично.

Сравните с это с волевым решением systemd, у которого _НЕ_ конфиги лежат в /lib/systemd/system. А вот _КОНФИГИ_ (практические такие же, как и не-конфиги) лежат в /etc/systemd.

Т.е. Поттеринга можно сильно не любить за его стиль общения, но оцените степень продуманности и волю к реализации. Сломать вот эту вот говнистую дуальность "конфиг-но-не-конфиг", которая десятилетиями обиталась в /etc, и заявить, что некоторые, формально, конфиги, это не конфиги, а куски софта. А конфиги - это то, что админы пишут руками или софтом для конфигурации.

А пока у людей такой воли нет, им приходится плодить .d (!!!!) в /etc/default.
404

Назревает большая революция

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

Но... Стоит только на секунду задуматься об их изменении, как архаичный autotools ждёт вас. Причём, он ждёт вас почти всюду. От binutils до cpython.

Моё чувство прекрасного страдает при виде m4. При виде поддержки достандартного С (и макросов вокруг этого). При виде невероятного объёма хаков, написанных с софте, у которого модель garbage in - garbage out, и поверх которого пытаются "сохранить инварианты" в более приличном софте.

У меня ощущение, что это революционная ситуация.

Если раньше у нас не было критической массы софта, который бы решал те, низкоуровневые проблемы, которые раньше решал C (т.е. хочешь системно - вот тебе, падаван, m4, automake, и шуруй воевать с ./configure), и особо вариантов не было, то теперь я вижу альтернативы с более адекватным lore. Это и go, и rust, и (может быть?) swift. Хотя ладно, кого я обманываю. Rust. Его красота - не в "borrow-checker'е", как любят описывать неофиты. Его красота в разумности базовых предположений до самого низа. Спускаясь с красот "асинхронного веб-сервера с job-stealing многозадачностью" до скучных вопросов "каким образом бинарник знает какой номер у сисколла для записи в fd" (если вы этот путь проделаете на условной node, вам будет очень печально), так вот, проделав этот путь, не ощущаешь острого диссонанса от "ненадлежащих средств". (Если что, там снизу libc, так что финальный слой у Rust такой же как у всех, но всё над ним - весьма добротно).

Так вот, революция начнёт происходить из-за awk-дисфории при соприкосновении с внутренностями существующих программ.

Я не знаю, сможет ли сообщество выдержать высочайший уровень инженерной продуманности Rust, но пока что от знакомства с его потрошками (и потрошками всего, что рядом) нет того же ощущения, как от доисторического Си.
404

mac @ python

У меня тут случайно состоялся сеанс показа величия питона (testinfra) рубисту. На маке.

Как с этим вообще живут? Т.е. простого virtualenv нет. gcc появляется на свет в каких-то адских мучениях (xcode?) Какая-то ядрёная смесь компиляции и бинарников, причём с совершенно непонятным поведением, затрагивающим как систему, так и среду пользователя.

На фоне этого обычное линуксовое
apt install python3-virtualenv
virtualenv .venv
source .venv/bin/activate
pip install -r requirements.txt

выглядит детским лепетом.

(Я утрирую, конечно, но -dev пакеты в линуксе всё равно проще образуются, чем в маке, более того, хорошо понятно, где именно).

https://xkcd.com/1987/
404

ещё, интересное из философии сайд-эффектов

Вот, предположим, у нас есть идемпотентный код, который умеет делать state=present/absent для сущности. Я специально абстрагируюсь от кокретных реализаций и пишу "псевдокодом".

Например, мы можем установить субд (утрируя, database-server state=present), а можем удалить (state=absent)
Мы можем создать базу данных в СУБД (database state=present) или удалить.
Мы можем создать пользователя в СУБД (user state=present) или удалить.
Мы можем дать пользователю доступ к базе или отнять (access user--database state=present)

Процесс создания сервера прост:
database-server state=present
database state=present
user state=present
access user--database state=present

Теперь мы хотим сделать обратное. Удалить его.

Мы пишем в обратном порядке:
access user--database state=absent
user state=absent
database state=absent
database-server state=absent


Каждая операция полностью идемпотентная. Но! Теперь попробуем "обратное" запустить второй раз. У нас есть сервер, на котором нет: базы данных; пользователя; СУБД.


Мы говорим access user--database state=absent.

И что должно случиться?
Практически, в любых системах мы получим ошибку, потому что у нас нет database-server, который бы нам эту операцию мог подтвердить или выполнить.

И мы не можем полагаться на "отсутствие СУБД" как доказательство удаления (not changed), потому что СУБД может быть в down state по независимой причине.

Фашистско-декларативный подход должен сказать, что "если чего-то нет, то мы его сделаем" - поставим СУБД, добавим базу, добавим пользователя и подтвердим (not changed) что у пользователя нет доступа в базу.

Но это во-первых абсурдно, во-вторых делает гигантские side effects в условиях not changed, что противоречит идее not changed.

Другими словами, утверждает ли декларативное утверждение "f(A, Б) = ложь", что A и Б существуют?

На практике это часто выливается даже в более сложное "f(первый элемент А, последний элемент Б) = ложь". Можем ли мы рассуждать про первый элемент А если А не существует?
404

Systemic approach

У меня на работе на на почти все задачи обычно делаю шаг назад или на два и говорю "не, вместо вот этого "тут и сейчас" мы будем делать что-то общее". Иногда даже на ровном месте говорю "всё, задолбало, давайте общий код делать". И к этому общему коду требуется ещё общий код, и вообще, всё по https://xkcd.com/1629/. И иногда есть ощущение, что я бегаю от задач и придумываю себе удобные задачи.

Однако, сейчас я получил порцию допамина доказательство того, что подход работает. Надо было поднять сервера для нового проекта. Всё с нуля. Пользователи, пакеты, sudo, мониторинг, всякая ерунда в районе mlfa и т.д. Главное - с нуля.

У меня ушло на это меньше часа. Через час (включая опечатки и линтиг и забытый ansible.cfg для CI'я) у меня был сервер с полным комплектом всего - дашборды, пачка нужных экспортёров, алерты, правильно учитывающие "есть там рейд или нет", "есть бонды на сетевых интерфейсах или нет", готовность включить эскалации (как только станет продакшеном), целевой софт, пользователи и их права, и т.д. Причём у сервера был готовый CI, который его настраивает по мержам в мастер. Это реально кратный рост личной производительности.

2000ый. Настройка сервера - это его установка, и поехали. Неделя или две работы на настройку тяжёлого сервера (субд/почтовый сервер и т.д.) - норма.
2010ый. День на сервер - успех.
2021ый. Час на сервер (плюс ещё минут пять на каждый следующий в группе). Стейджинг в этом конкретном проекте не нужен (т.к. своего кода там пока что нет), но если потребуется - ещё пол-часа возни.

Причём это нифига не "чпок и сервер из шаблона/образа". Это куча двигающихся деталей, нюансов и вариантов.

На самом деле, вовсе не факт, что в другой ситуации у меня будет такая же производительность. Это, так сказать, "здесь и сейчас круто получилось".

Но вот к такому code reuse я интуитивно и стремлюсь.

Причём, ключевым тут является не то, что у меня все кусочки были готовыми под руками, а что все всё инструментировано. Начиная с того, что весь код ансибла был прикрыт (уже протестирован) интеграционными тестами, и заканчивая git vendor, которым это всё собралось.
404

ансибло-философия

А вот я хочу продолжить думать умное про ансибл, 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'ом, проверили, что порт слушает).

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

404

фреймворк моей мечты

Ну чем не ZX-Spectrum? Это целиком весь main.rs, который мигает разноцветным экраном. Обратите внимание на отсутствие event loop'а и прочей ерунды.

use lib::EasyScreen;

fn main(){
    let screen = EasyScreen::new();
    let mut c = 0;
    loop{
        c+=1;
        screen.fill(c);
    }
}


https://github.com/amarao/equart/blob/switching_to_sdl/src/main.rs

Рисование я начну писать после того, как доделаю всякие put_pixel и т.д. Алсо, не реализовать ли мне спектрумовский circle, который умел рисовать муары при углах больше 3 радиан?