Category: it

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

404

Rust soundness

Каждый раз, когда я сталкиваюсь с маленькими "но" в Rust'е, это ощущение тщательной продуманности. Например, простейшие fold-функции для итераторов: sum, min, max, any. Например, что должен вернуть max для пустого списка?

В питоне? Enjoy your ValueError exception.

В Rust'е? Max возвращает Some с результатом. Или None (который вариант от Option, а не абстрактный синглтон None).
404

still_ntp

В ходе локального мозгового штурма у меня родилась суперидея. Надо написать ntp сервер, который может отдавать указанную дату. Т.е. сказали при запуске сервиса "1990-01-01 12:00:00", он отвечает на ntp-запросы 1990-01-01 12:00:00. И через час всё равно отвечает "1990-01-01 12:00:00".

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

Кажется, я придумал себе хорошее упражнение для rust'а.
404

Rust-строковое

А вот строки в Rust'е неожиданно сложны. Например, такая простая вещь, как strstr() (поиск начала подстроки в строке) с каждой итераций раздумий всё сложнее и сложнее. Особенно, если делать эффективно.

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

Итератор chars не очень хороший, потому что он из любого символа (даже 1-байтового) делает 4 байта. Это значит, что для поиска подстроки в гигабайтной строке нам нужно будет перемолотить 4 ГБ в режиме записи (вероятнее всего, в регистр, но всё равно...)

Т.е. первая задача, которая у нас будет, это реализация считающего Window поверх String/str без копирования. Внутри это указатель на первый символ и байтовая длина (при том, что количество символов в window фиксировано, байтовый размер будет прыгать очень неровно).

Основываться она должна на str-итераторе по символам. Такой итератор получает &str, после чего начинает возвращать &str в один символ (in-place, без копирования!). Т.е. ещё уровнем ниже, это fat pointer на байты строки, который указывает на начало символа и содержит в себе его длину, кроме того, он содержит в себе (для удобства, видимо), адрес начала строки, и её оригинальный размер.

Перед тем, как изобретать всё своё с нуля, надо ещё раз перечитать что String и str умеют из коробки (игнорируя существование find и matches, разумеется).

Чем глубже я в это погружаюсь, тем тоньшее все нюансы становятся. Я чувствую, что пока что я сделаю очень грубо, с использованием Vec.

.. Сделал. Получил заслуженные 40мс (нижние 27% всех решений). Нырять в устройства fat pointers я пока не готов.

pub fn str_str(haystack: String, needle: String) -> i32 {
    if needle.len() == 0 {return 0};
    let haystack_vec: Vec<char> = haystack.chars().collect();
    let needle_vec: Vec<char> = needle.chars().collect();
    let mut pos = 0;
    for candidate in haystack_vec.windows(needle_vec.len()){
        if candidate == needle_vec.as_slice(){
            return pos as i32;
        }
        pos += 1;
    }
    -1
}
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, которым это всё собралось.