LINUX.ORG.RU

Сообщения vbr

 

А вы пытаетесь соблюдать FHS в контейнерах?

Почему-то коробит, когда делают контейнеры с /data, /app и прочим бредом. Всегда делаю контейнеры с /home/build, /opt/app, /srv/data, /mnt/host и тд, пытаясь хоть как-то в FHS. Для меня создавать рандомный каталог в корне это какое-то кощунство. Вполне могу себе представить, что с таким подходом кто-нибудь смонтирует что-нибудь в /dev, типа среда разработки.

А вы как думаете? Есть в этом смысл?

 

vbr
()

Помогите улучшить хук usePromise

Пытаюсь подружить реакт с промисами. React Query и прочую муть не предлагать.

Пока родился такой вариант. Думаю, из сигнатур очевидно, как оно должно работать. Не нравится то, что reducer получился «не чистый». Вызывает abortController.abort(). Хотя и идемпотентный но кажется это всё равно не по феншую.

Как сделать нормально - я не придумал. Хотя думал много и это далеко не первая итерация. Буду благодарен помощи от гуру, если у кого будет хорошая идея.

import { DependencyList, useEffect, useReducer } from "react";

type PromiseFunction<T> = (signal: AbortSignal) => Promise<T>;

type Result<T> =
  | { status: "pending" }
  | { status: "fulfilled"; value: T }
  | { status: "rejected"; reason: unknown };

type State<T> =
  | { status: "uninitialized" }
  | { status: "pending"; id: number; abortController: AbortController }
  | { status: "fulfilled"; value: T }
  | { status: "rejected"; reason: unknown };

type Action<T> =
  | { type: "init"; id: number; abortController: AbortController }
  | { type: "resolve"; id: number; value: T }
  | { type: "reject"; id: number; reason: unknown }
  | { type: "clean" };

function reducer<T>(state: State<T>, action: Action<T>): State<T> {
  switch (action.type) {
    case "init":
      switch (state.status) {
        case "uninitialized":
          return {
            status: "pending",
            id: action.id,
            abortController: action.abortController,
          };
      }
      break;

    case "resolve":
      switch (state.status) {
        case "uninitialized":
          return state;
        case "pending":
          if (action.id < state.id) {
            return state;
          }
          if (action.id == state.id) {
            return { status: "fulfilled", value: action.value };
          }
          break;
      }
      break;

    case "reject":
      switch (state.status) {
        case "uninitialized":
          return state;
        case "pending":
          if (action.id < state.id) {
            return state;
          }
          if (action.id == state.id) {
            return { status: "rejected", reason: action.reason };
          }
          break;
      }
      break;

    case "clean":
      switch (state.status) {
        case "pending":
          state.abortController.abort();
          return { status: "uninitialized" };
        case "fulfilled":
        case "rejected":
          return { status: "uninitialized" };
      }
      break;
  }

  console.error("Unexpected state", state, action);
  return state;
}

function loggingReducer<S, A>(
  reducer: (state: S, action: A) => S,
): (state: S, action: A) => S {
  return (state, action) => {
    try {
      const nextState = reducer(state, action);
      console.log(state, action, nextState);
      return nextState;
    } catch (e) {
      console.log(state, action, e);
      throw e;
    }
  };
}

let nextId = 1;

export default function usePromise<T>(
  promiseFunction: PromiseFunction<T>,
  deps: DependencyList,
): Result<T> {
  const [state, dispatch] = useReducer(loggingReducer(reducer<T>), {
    status: "uninitialized",
  });

  useEffect(() => {
    const id = nextId++;
    const abortController = new AbortController();

    dispatch({ type: "init", id, abortController });

    promiseFunction(abortController.signal).then(
      (value) => dispatch({ type: "resolve", id, value }),
      (reason) => dispatch({ type: "reject", id, reason }),
    );

    return () => dispatch({ type: "clean" });
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, deps);

  switch (state.status) {
    case "uninitialized":
    case "pending":
      return { status: "pending" };

    case "fulfilled":
      return { status: "fulfilled", value: state.value };

    case "rejected":
      return { status: "rejected", reason: state.reason };
  }
}

 

vbr
()

prometheus, whitelisting всего

Хочу начать освоение прометеуса с малого.

К примеру есть адрес someserver.com/metrics

Он выплёвывает кучу всего. Мне из всего этого нужно только одна метрика:

base_gc_time_total_seconds{name="G1 Old Generation"} 0.0
base_gc_time_total_seconds{name="G1 Young Generation"} 0.303

Причём вот этот label мне не нужен, я хочу его убрать. Чтобы в базе лежало только одно значение - сумма этих двух значений.

Как убирать лишние метрики я вроде понял:

    metric_relabel_configs:
      - source_labels: [ __name__ ]
        regex: base_gc_time_total_seconds
        action: keep

А вот как убрать лишние label-ы - я не понял. Можно использовать labeldrop, но кажется это не то, он не будет комбинировать получившиеся метрики, а получится какая-то смесь.

То, что можно сумму посчитать в запросе потом это понятно, я в принципе не хочу хранить эту метрику в двух экземплярах.

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

В общем по сути хочу включать метрики потихоньку добавляя нужные мне метрики и label-ы, а не всё скопом. Типа добавил base_gc_time_total_seconds, а все label-ы у него убрал. Потом разобрался - что мне нужна более тонкая статистика и добавил этот name конкретно к этой метрике.

 

vbr
()

Как проверить oom killer?

Завис сервер. Я рассчитывал, что он отвиснет, когда oom killer что-нибудь прибьёт, а он не отвисает до сих пор. Подожду до завтра, но явно ситуация не нормальная. Поэтому на соседнем сервере пытаюсь разобраться.

Сам я ничего не настраивал специально, свопа у системы нет. Система установлена из облачного образа debian.

Почему создал тему - в интернете на каждом сайте пишут, что оно контролируется через sysctl vm.oom-kill. Но у меня такого нет:

debian@worker-d-3:~$ /usr/sbin/sysctl vm.oom-kill
sysctl: cannot stat /proc/sys/vm/oom-kill: No such file or directory
debian@worker-d-3:~$ ls /proc/sys/vm
admin_reserve_kbytes         dirty_ratio                max_map_count              nr_hugepages              overcommit_ratio          user_reserve_kbytes
block_dump                   dirty_writeback_centisecs  memory_failure_early_kill  nr_hugepages_mempolicy    page-cluster              vfs_cache_pressure
compact_memory               dirtytime_expire_seconds   memory_failure_recovery    nr_overcommit_hugepages   page_lock_unfairness      watermark_boost_factor
compact_unevictable_allowed  drop_caches                min_free_kbytes            numa_stat                 panic_on_oom              watermark_scale_factor
compaction_proactiveness     extfrag_threshold          min_slab_ratio             numa_zonelist_order       percpu_pagelist_fraction  zone_reclaim_mode
dirty_background_bytes       hugetlb_shm_group          min_unmapped_ratio         oom_dump_tasks            stat_interval
dirty_background_ratio       laptop_mode                mmap_min_addr              oom_kill_allocating_task  stat_refresh
dirty_bytes                  legacy_va_layout           mmap_rnd_bits              overcommit_kbytes         swappiness
dirty_expire_centisecs       lowmem_reserve_ratio       mmap_rnd_compat_bits       overcommit_memory         unprivileged_userfaultfd

Видимо гайды устарели. Как правильно проверить? Ядро 5.10.0-20-amd64

В /usr/lib/systemd/ бинарника systemd-oomd тоже нет и сервиса соответствующего тоже нет, если что.

 ,

vbr
()

Файловая система для SD-карт

Есть смысл смотреть на что-то вроде F2FS или сейчас нормальные карты от SSD не отличаются и сами балансируют записи по блокам, то бишь стандартный Ext4 будет предпочтительней?

Помимо прочего крайне необходимо, чтобы не было порчи ФС при выключении питания. Данные хранятся в sqlite, поэтому важно, чтобы sqlite оставалась в работоспособном состоянии.

 , , , ,

vbr
()

raspberry, buildroot, wayland

Хочу сделать на raspberry киоск с веб-интерфейсом (чтобы после загрузки открывался браузер на весь экран с HTML с диска).

Как я понял, свой линукс надо собирать через buildroot, вместо electron надо использовать wpewebkit и сейчас графика работает через wayland.

Но ничего у меня в итоге не получилось и не работает.

Минимальный образ buildroot-ом с помощью make raspberrypi4_defconfig я собрал, он грузится, консоль есть, залогиниться можно. buildroot 2022.02.8

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

Toolchain
 Enable WCHAR support
Target packages
 Graphic libraries and applications (graphic/text)
  mesa3d
   Gallium vc4 driver
   OpenGL ES
 Libraries
  Graphics
   wpewebkit
 Graphic libraries and applications (graphic/text)
  cog
   Wayland backend
Filesystem images
 ext2/3/4 root filesystem
  exact size: 180M

cog это, как я понимаю, браузер на этом wpewebkit, т.е. видимо то, что и должно показать мою HTML-ку и то, что я должен буду настроить на автозапуск.

В итоге cog этот не запускается. Пишу cog (от рута), он начинает в цикле писать (сокращаю, т.к. перепечатываю)

error: XDG_RUNTIME_DIR not set in the environment.
WARNING Your application does not implement g_application_activate() and has no handlers connected to the activate signal. It should do one of these.
libEGL warning: MESA-LOADER: failed to open swrast: File not found (search paths /usr/lib/dri, suffix _dri)

EGLDisplay initialization failed: EGL_NOT_INITIALIZED

Cog Core WARNING THe rendered process crashed.

XDG_RUNTIME_DIR ставил, эта ошибка ушла, толку не было.

Что за libEGL warning я не понял. В /usr/lib/dri файла swrast_dri.so нет. Есть файл vc4_dri.so. Как я предполагаю, swrast это софтовый растеризатор, а vc4 это хардварный. Как этому libEGL сказать, чтобы он использовал vc4, я пока не понял, гугл не очень помогает.

Пробовал добавить weston, пришлось для этого udev ставить, но ничего не изменилось, weston тоже не запускается.

Пробовал запускать cog --platform=wl, пишет preferred modulewlnot supported, cannot create platformm: could not find an usable platform module. could not load the impl library. Is there any backend installed? File not foudn.

Может я вообще не в том направлении двигаюсь? raspi в целом это больше прототип, потом надо будет это на i.mx8 делать, поэтому хочу через buildroot сделать.

Также пробовал включать v3d драйвер, не помогло.

 , ,

vbr
()

Почему не работает suid бит

Хочу взломать свой компьютер через докер.

Запустил в конейнере линукс, подмонтировал туда локальную папку. В неё предварительно скопировал sh. Сделал chmod u+s sh из докера. Вышел из докера - suid бит остался. Запускаю этот sh ожидая, что suid бит его запустит под рутом - но не получается.

vbr@13049:~/test$ ls -la
total 132
drwxr-xr-x 2 vbr vbr   4096 Dec  4 05:51 .
drwxr-xr-x 8 vbr vbr   4096 Dec  4 05:47 ..
-rwsr-xr-x 1 root      root      125560 Dec  4 05:47 sh
vbr@13049:~/test$ stat sh
  File: sh
  Size: 125560    	Blocks: 248        IO Block: 4096   regular file
Device: 801h/2049d	Inode: 3951222     Links: 1
Access: (4755/-rwsr-xr-x)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2022-12-04 05:52:33.620839091 +0600
Modify: 2022-12-04 05:47:48.758333113 +0600
Change: 2022-12-04 05:52:24.856885055 +0600
 Birth: 2022-12-04 05:47:48.758333113 +0600
vbr@13049:~/test$ ./sh 
$ id
uid=1001(vbr) gid=1001(vbr) groups=1001(vbr),997(docker)
$ ls /root
ls: cannot open directory '/root': Permission denied

Никаких маунтов с nosuid нет.

 

vbr
()

self hosted github runner в публичном репозитории

Имеется организация в github на бесплатном тарифе.

Имеется несколько закрытых репозиториев.

Хочется иметь reusable workflow, который можно вызывать из этих закрытых репозиториев. Хранить его нужно в публичном репозитории, т.к. на бесплатном тарифе нельзя вызывать reusable workflow из закрытых репозиториев.

К этой организации прикреплены self hosted runners. Они должны использоваться для этого workflow.

В документации написано:

We recommend that you only use self-hosted runners with private repositories. This is because forks of your public repository can potentially run dangerous code on your self-hosted runner machine by creating a pull request that executes the code in a workflow.

В самом публичном репозитории с reusable workflows ничего кроме них самих и какой-нибудь документации ничего не будет.

Хочется понять, как правильно и безопасно это всё организовать.

 ,

vbr
()

.gitignore: всё в secrets/ кроме *.example.*

Есть каталог some/path/secrets/ в нём есть два файла: name.env и name.example.env. Нужно заигнорить первый и разигнорить второй. Таких каталогов и файлов много, нужно универсальное правило.

Логичный вариант (в корне) не сработал

secrets/
!secrets/*.example.*

он всё игнорит в итоге. Пробовал некоторые вариации, не получилось.

Как правильно?

 

vbr
()

Как вычитать http запрос?

Хочу вычитать входящий запрос по протоколу HTTP 1.0 или 1.1 и послать ответ, в котором будет текст запроса.

Я так понимаю, простой алгоритм вида «читать, пока клиент не закрыл соединение» не сработает, т.к. современные клиенты пытаются в http keepalive и соединение надо закрывать самому со стороны сервера. Но чтобы закрыть соединение, мне нужно вычитать весь запрос.

Выходит, придётся парсить запрос.

Я так понимаю, есть три алгоритма:

transfer-encoding не указан и content-length не указан. Тогда читаем до закрытия соединения.

content-length указан. Тогда читаем указанное число байтов (ну или до закрытия соединения, что будет странно).

указан transfer-encoding и в нём присутствует chunked. Тогда читаем чанки, пока не придёт чанк нулевой длины, что сигнализирует конец запроса.

Пока не понял, что делать, если указан и chunked и content-length, но я прочитаю.

Можно ли считать, что этого хватит для любых разумных и неразумных (но в рамках протокола) запросов?

 

vbr
()

Альтернативы keycloak

Ищу легковесную альтернативу Keycloak.

Хотелки:

  • Всякие oauth штуки. Тут нужна достаточно продвинутая поддержка - маппинг групп, audience.
  • Своя база юзеров с паролями.
  • Страница логина. Регистрация не нужна.
  • Функционал сброса пароля путём отправки ссылки на почту через SMTP-сервер с авторизацией.
  • Sqlite база или что-то подобное.
  • Админка для просмотра, добавления и редактирования пользователей.
  • Настройки realm-а и прочих oauth штук через конфиги, а не как в keycloak в базе/UI. Чтобы можно было конфиг поменять и запустить с изменённым конфигом, а не тыкаться там по менюшкам.

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

В кейклоке не устраивает:

  • Долгий старт, несколько минут. Они предлагают собирать свой образ. Это неудобно.
  • Жрёт под половину гигабайта на пустой базе.
  • Конфиг в базе хранится. Нет удобного способа делать что-то, похожее на gitops. На terraform можно сделать, но это бред какой-то.
  • Работает на взрослой базе вроде постгреса. У меня нагрузка смешная, мне это не надо, гемор по поддержке полноценной базы не хочу.

 

vbr
()

Решето

Sudo 1.8.0 through 1.9.12, with the crypt() password backend, contains a plugins/sudoers/auth/passwd.c array-out-of-bounds error that can result in a heap-based buffer over-read. This can be triggered by arbitrary local users with access to Sudo by entering a password of seven characters or fewer. The impact could vary depending on the compiler and processor architecture.

 ,

vbr
()

Без чего вы не обходитесь на андроиде?

По случаю санкций решил пересесть с айфона на андроид. Зонд это хорошо, но когда у тебя отбирают двагис, это плохо. Купил пиксель 7, вроде говорят, что у гугла самые приятные ощущения.

Про андроид знаю больше как программист, но в повседневной жизни его почти не использовал.

Пока на аосп/ф-дроид переезжать не планирую, но держу этот вариант в уме на всякий случай.

Собственно что вы бы поставили себе на телефон из неочевидных приложений? Может лаунчер какой маст хэв или файловый менеджер. И почему. Что не хватает в стандартном?

 

vbr
()

ZeroSSL существует

У letsencrypt есть неприятная особенность. У него стоит ограничение на 5 сертификатов в неделю для определенного имени. То бишь можно выпустить ровно 5 сертификатов для www.linux.org.ru, к примеру. Если этот лимит превышен, можно запросить сертификат для двух доменов вроде www.linux.org.ru, www1.linux.org.ru и он его успешно выпустит ещё 5 раз и тд.

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

Тут внезапно узнал про сабж. Работает по протоколу ACME, то бишь вообще ничего менять не нужно кроме URL сервера. И вроде как у него вообще нет никаких ограничений на число сертификатов и тд. Конечно бесплатен.

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

 , ,

vbr
()

Запускать докер удаленно с пробросом портов

Я использую сервер, на котором запущен докер. Локально у меня установлен только клиент-бинарник. Соединение настроено через docker context поверх ssh.

Я могу выполнять локально нужные команды, всё выполняется на сервере. Но есть одна проблема - если я запускаю контейнер и выставляю порты, то они выставляются не на моей локальной машине, а на том сервере. В итоге мне, чтобы запустить что-то, надо ещё отдельно пробрасывать порты через ssh -L.

Нет ли тут какого-то более удобного решения? Также должно работать с docker-compose. Теоретически я это вижу, как некоторый демон, который запускается локально, а также мониторит запущенные докер-контейнеры на удаленном хосте. И при появлении новых контейнеров с выставленными портами он будет автоматически пробрасывать эти порты на локальный компьютер.

На всякий случай приведу команды, чтобы стало понятней.

$ s=someserver.com
$ docker run -d --rm --name nginx -p 127.0.0.1:8080:80 nginx
$ ssh $s curl -i --head -sS http://127.0.0.1:8080/
HTTP/1.1 200 OK
$ curl -i --head -sS http://127.0.0.1:8080/
curl: (7) Failed to connect to 127.0.0.1 port 8080 after 10 ms: Connection refused
$ ssh -L 127.0.0.1:8080:127.0.0.1:8080 -N $s
$ curl -i --head -sS http://127.0.0.1:8080/
HTTP/1.1 200 OK

Вот чтобы ssh -L не нужно было запускать, мне хочется.

 ,

vbr
()

Где почитать про разработку драйверов?

Надо написать небольшой драйвер. Какие-то отрывочные знания по устройству ОС с университета есть, но драйверы никогда не писал. Драйвер взаимодействует с устройством через общую память. Прям глубоко в тему вникать мне не нужно. Посоветуйте, с чего начать. В идеале книжку, я книжки уважаю.

 

vbr
()

Генерация PDF с векторным изображением

Нужно генерировать PDF-документ, в котором вставлено сложное векторное изображение.

Сейчас процесс выглядит так: генерируется SVG, растеризуется в PNG, генерируется HTML, в нём вставлено это PNG изображение и результат преобразуется в PDF.

Что не нравится:

  1. PDF получается больше, чем, как кажется, должна была бы быть. Ну собственно 99% её размера это эта картинка.

  2. PDF в теории это векторный формат, хотелось бы для пущего качества оставлять исходный вектор.

Но общий подход нравится, т.к. каждый этап легко отлаживать, поэтому сам процесс хотелось бы оставить (SVG, HTML).

Собственно в идеале нужен инструмент, которому на вход подаётся HTML в котором какой-то текст, разметка и тд, а также ссылка на SVG. А на выходе получается PDF, в котором SVG преобразован в PS или чего там внутри.

Пробовал такую схему просто печатать в гугль-хроме, в теории получается то, что надо (PDF с векторной картинкой), но размер там дикий и открывается оно с дикими тормозами.

Есть утилита rsvg-convert которая умеет конвертировать SVG в PDF, у неё PDF получается хороший, и размер небольшой и вектор остаётся. Но как этот PDF встроить в HTML и потом сгенерировать следующий PDF - не понятно.

 , ,

vbr
()

Какой стек для react сегодня надо использовать?

Последний раз плотно этим занимался несколько лет назад, по меркам фронтэнда мои знания полностью устарели. Тогда использовал react с классами, состояние в redux хранил, кучу каких-то библиотек натягивал чтобы с редуксом не так больно было работать. Билд вроде через webpack делал.

Сейчас нужно написать небольшой фронт. Проект - типичная опердень, тупо кучка табличек, формочек, CRUD в общем, с псевдо-REST бэкэндом.

Брать планирую реакт, ибо я его знаю. Понятно, что уже с функциями, я примерно в курсе как там что работает в плане базового реакта.

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

Вопрос с тем - что сейчас правильно брать:

  1. Для сборки. webpack была жутко муторная ерунда. Слыхал, сейчас esbuild используют, хороший вариант? Я так понял, он typescript компилирует не пойми как, без проверок типов и тд, мне надо с проверками, как это правильно организовать?

  2. Для хранения состояния что посоветуете? redux для форм мне тогда показался плохо приспособлен. Да и в целом странная библиотека, вроде концептуально всё просто и понятно, но когда на практике начинаешь использовать, там подтягиваешь 500 библиотек со всякими сагами и внезапно всё становится сложно и непонятно. Не понравилось по итогу. Хотя подозреваю, что сейчас с этим должно быть получше. Гуглится какой-то redux toolkit.

Слыхал, что react-query какая-то волшебная библиотека, которой даже каким-то макаром можно заменить state (а что нельзя - просто в компонентах пускай лежит, без всяких выпендрёжей).

 ,

vbr
()

По какому принципу формируются ежемесячные Debian Cloud образы?

Есть такой сайт: https://cloud.debian.org/images/cloud/bullseye/

Я так понимаю, это официальные образы от Debian для облачных провайдеров.

По указанному URL новый образ появляется примерно раз в месяц.

По адресу https://cloud.debian.org/images/cloud/bullseye/daily/ образы обновляются ежедневно.

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

Какой-то документации по этим образам я тоже не нашёл, ну или я искать не умею.

 ,

vbr
()

Как обработать код возврата с set -e

Использую set -e для упрощения обработки ошибок в shell-скрипте. Но в одном месте нужна более сложная обработка. Т.е. я вызываю определённую команду и после этого мне нужно получить код ошибки.

Для иллюстрации покажу следующий пример:

#!/bin/sh

set -e

(exit 2)
rv=$?
echo "rv=$rv"

В данном случае мне нужно продолжить выполнение после того, как subshell вернул ошибку. И обработать конкретное значение этой ошибки.

Понятно, что можно сделать set +e в нужном месте. Но может быть есть какой-то более изящный трюк?

 

vbr
()

RSS подписка на новые темы