<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>bisko.be - Разработка</title><description>Технологии, разработка, хардуер и експерименти.</description><link>https://bisko.be/bg/posts/dev/</link><language>bg</language><item><title>Стартиране на Ollama със стари видеокарти на CachyOS</title><link>https://bisko.be/bg/posts/dev/running-ollama-with-older-gpus-on-cachyos/</link><guid isPermaLink="true">https://bisko.be/bg/posts/dev/running-ollama-with-older-gpus-on-cachyos/</guid><description>Днес мигрирах Windows 11 виртуалната си машина към Linux, за да имам по-голяма гъвкавост със сървисите, които върват на нея, и се сблъсках с проблем – Ollama не можеше да работи на старите ми видеокарти – GTX1070 и GTX970</description><pubDate>Sat, 28 Feb 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3 id=&quot;tldr&quot;&gt;TL;DR;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;ollama-cuda&lt;/code&gt; на CachyOS идва (към момента) с поддръжка само за &lt;code&gt;compute &gt;= 7.5&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Ако имате по-стари видеокарти с по-ранен &lt;code&gt;compute&lt;/code&gt;, ТРЯБВА да направите едно от 2 неща:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Да компилирате &lt;code&gt;ollama-cuda&lt;/code&gt; от сорс кода, с поддръжка за по-старите compute цели&lt;/li&gt;
&lt;li&gt;Да инсталирате &lt;code&gt;ollama-vulkan&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Аз избрах &lt;code&gt;ollama-vulkan&lt;/code&gt; и работи чудесно!&lt;/p&gt;
&lt;h3 id=&quot;време-за-история&quot;&gt;Време за история&lt;/h3&gt;
&lt;p&gt;Днес ме споходи вдъхновението най-накрая да изключа Windows 11 виртуалната си машина и да я мигрирам към Linux.&lt;/p&gt;
&lt;p&gt;Изискванията бяха да мога да пускам:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ollama - за магия с локални модели&lt;/li&gt;
&lt;li&gt;Docker - за отдалечена разработка&lt;/li&gt;
&lt;li&gt;Steam - за игра на игри&lt;/li&gt;
&lt;li&gt;Jellyfin - за архива с домашни видеа&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Сега ще се фокусирам само върху Ollama, защото беше интересно преживяване и ме накара да се замисля защо нещата не са по-очевидни.&lt;/p&gt;
&lt;p&gt;В машината има 2 видеокарти:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;GTX 1070 - 8GB&lt;/li&gt;
&lt;li&gt;GTX 970 - 4GB&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Исках да пусна Ollama на тях, за да си поиграя с локални модели и да видя как мога да го интегрирам в някои проекти. Например - анонимизиране на данни локално, неразрушителна имплементация на OpenClaw, която пасва на моите случаи на употреба, локален OCR за документи, които сканирам с телефона си, автоматизиране на някои неща в ежедневното управление на дома.&lt;/p&gt;
&lt;p&gt;Така че естествено инсталирах &lt;code&gt;ollama&lt;/code&gt; и &lt;code&gt;ollama-cuda&lt;/code&gt;, тъй като имам 2 Nvidia видеокарти, очаквайки, че ще работи без проблем, защото само преди няколко минути работеше на Windows.&lt;/p&gt;
&lt;p&gt;Стартирах Ollama, заредих &lt;code&gt;qwen3:8b&lt;/code&gt; за бърз експеримент и… работеше на процесора 🤔&lt;/p&gt;
&lt;p&gt;Видеокартите бяха напълно способни да го удържат във VRAM, но по някаква причина Ollama избираше да го върти на процесора.&lt;/p&gt;
&lt;p&gt;След като се опитах да разбера от логовете, помолих Claude да ми помогне малко и той стигна до доста обезкуражаващото откритие:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;The&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; logs&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; tell&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; the&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; story&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; clearly.&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; Both&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; your&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; GPUs&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; are&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; detected&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; but&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; then&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; filtered&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; out&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; because&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; they&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; fail&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; CUDA&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; initialization:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  &quot;filtering device which didn&apos;t fully initialize&quot;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; id=GPU-eb132a13-b9f4-40e3-d85d-60f211dfd21e&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; ...&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; library=CUDA&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  &quot;filtering device which didn&apos;t fully initialize&quot;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; id=GPU-550263c8-37e2-2a25-c0b6-10cc7511ed20&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; ...&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; library=CUDA&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  The&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; reason&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; is&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; the&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; CUDA&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; library&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; bundled&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; with&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; Ollama&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 0.17.4&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; was&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; compiled&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; for&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; these&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; architectures&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; only:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  CUDA.0.ARCHS&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;=750,800,860,870,880,890,900,1000,1030,1100,1200,1210&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  The&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; minimum&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; supported&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; compute&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; capability&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; is&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 7.5&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (Turing &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; RTX&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; 20xx&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; series&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;). Your GPUs are older than that:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  ┌──────────┬────────────────────┬──────────────┐&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  │&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;   GPU&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;    │&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; Compute&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; Capability&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; │&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; Architecture&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; │&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  ├──────────┼────────────────────┼──────────────┤&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  │&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; GTX&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1070&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; │&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 6.1&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;                │&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; Pascal&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;       │&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  ├──────────┼────────────────────┼──────────────┤&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  │&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; GTX&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 970&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;  │&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 5.2&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;                │&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; Maxwell&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;      │&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  └──────────┴────────────────────┴──────────────┘&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  Neither&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; is&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; the&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; supported&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; list,&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; so&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; CUDA&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; initialization&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; fails&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; for&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; both,&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; and&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; Ollama&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; falls&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; back&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; to&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; CPU-only&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; inference.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  Your&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; options:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  1.&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; Downgrade&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; Ollama&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; to&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; an&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; older&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; version&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; that&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; still&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; included&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; Pascal/Maxwell&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; support&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (pre-0.6.x &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;era&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; had&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; broader&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; arch&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; coverage,&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; but&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; check&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; release&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; notes&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; for&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; specifics&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;).&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  2.&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; Build&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; Ollama&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; from&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; source&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; with&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; CUDA_ARCHITECTURES=&quot;52;61;75;80;86&quot;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; to&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; include&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; your&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; GPU&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; architectures.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  3.&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; Upgrade&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; GPUs&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; to&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; at&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; least&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; an&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; RTX&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 2060&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; or&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; newer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (compute &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;7.5+&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;).&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Това малко ме разочарова, защото искам да използвам видеокартите максимално, преди да мина на нова.&lt;/p&gt;
&lt;p&gt;Не исках наистина да компилирам Ollama от сорс кода, тъй като трябва да поддържа нещата от кутията, и бях много объркан защо не го прави, при положение че на Windows инсталацията поддържаше тези архитектури.&lt;/p&gt;
&lt;p&gt;Тези карти дори бяха показани като поддържани на сайта на Ollama!&lt;/p&gt;
&lt;p&gt;За да скъся дългата история с ровене в Google:&lt;/p&gt;
&lt;p&gt;Оказва се, че &lt;code&gt;ollama-cuda&lt;/code&gt; идва точно с изискванията, изброени по-горе… а съветът беше да се инсталира &lt;code&gt;ollama-vulkan&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;След като го направих, всичко заработи много гладко!&lt;/p&gt;</content:encoded><category>linux</category><category>llm</category><category>ollama</category><category>cachyos</category><category>vulcan</category><category>cuda</category></item><item><title>[Linux] Възстановяване на прекъсната сесия на `apt dist-upgrade`</title><link>https://bisko.be/bg/posts/dev/linux-recovering-a-disconnected-apt-dist-upgrade-session/</link><guid isPermaLink="true">https://bisko.be/bg/posts/dev/linux-recovering-a-disconnected-apt-dist-upgrade-session/</guid><description>Днес обновявах инсталацията си на Proxmox отдалечено през вградената конзола, но забравих какво правя и затворих таба по средата. Това доведе до това да не мога да се свържа отново, защото пакетите вече се обновяваха на заден план, а обновяването беше задало въпрос за замяна на файл и чакаше отговор</description><pubDate>Wed, 23 Oct 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Днес обновявах инсталацията си на Proxmox отдалечено през вградената конзола, но забравих какво правя и затворих таба по средата.&lt;/p&gt;
&lt;p&gt;Това доведе до това да не мога да се свържа отново, защото пакетите вече се обновяваха на заден план, а обновяването беше задало въпрос за замяна на файл и чакаше моя отговор.&lt;/p&gt;
&lt;p&gt;Така че можех да вляза през SSH, но не можех да направя нищо, понеже процесът все още чакаше отговор в конзола, към която не можех да се свържа, тъй като интерфейсът не се отваряше.&lt;/p&gt;
&lt;p&gt;След кратко ровене попаднах на &lt;a href=&quot;https://serverfault.com/questions/19634/how-to-reconnect-to-a-disconnected-ssh-session&quot;&gt;тема в Serverfault&lt;/a&gt;, в която се споменаваше използването на &lt;code&gt;reptyr&lt;/code&gt;, за да поемеш терминална сесия през SSH.&lt;/p&gt;
&lt;p&gt;Описвам тук какво точно направих, за да си върна сесията и да завърша обновяването:&lt;/p&gt;
&lt;p&gt;От &lt;a href=&quot;https://serverfault.com/questions/19634/how-to-reconnect-to-a-disconnected-ssh-session#comment1506308_979180&quot;&gt;този коментар&lt;/a&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; clone&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; https://github.com/nelhage/reptyr&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; reptyr&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;make&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; install&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Това инсталира &lt;code&gt;reptyr&lt;/code&gt; на машината.&lt;/p&gt;
&lt;p&gt;После потърсих всички отворени сесии с &lt;code&gt;ps ax | grep pts&lt;/code&gt;, за да намеря процеса, който ми трябваше.&lt;/p&gt;
&lt;p&gt;След това намерих най-горния родителски процес в дървото на извикванията, на който е зададен &lt;code&gt;pts&lt;/code&gt;, и се закачих за него чрез неговия PID:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;reptyr&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -T&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1390511&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;И така успях да завърша обновяването! 🎉&lt;/p&gt;</content:encoded><category>Uncategorized</category></item><item><title>[Linux] Syncthing – файлова система само за четене при стартиране като услуга</title><link>https://bisko.be/bg/posts/dev/linux-syncthing-read-only-file-system-when-running-as-service/</link><guid isPermaLink="true">https://bisko.be/bg/posts/dev/linux-syncthing-read-only-file-system-when-running-as-service/</guid><description>От няколко месеца използвам Syncthing, за да синхронизирам работното си копие с локален dev сървър. В началото го стартирах ръчно през CLI след логване. Работеше добре, така че не се замислих, когато реших да го пусна като услуга.</description><pubDate>Wed, 06 Apr 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;От няколко месеца използвам &lt;a href=&quot;https://syncthing.net/&quot;&gt;Syncthing&lt;/a&gt;, за да синхронизирам работното си копие с локален dev сървър.&lt;/p&gt;
&lt;p&gt;В началото го стартирах ръчно през CLI след логване. Работеше добре, така че не се замислих, когато реших да го пусна като услуга. Стартира, синхронизира малко данни, всичко беше наред.&lt;/p&gt;
&lt;p&gt;Докато не спря да бъде, разбира се! 🙂&lt;/p&gt;
&lt;p&gt;Оказва се, че не съм забелязал куп грешки в логовете, които споменават, че файловата система на dev сървъра е само за четене и това кара Syncthing да не синхронизира нищо.&lt;/p&gt;
&lt;p&gt;Мислех, че е бъг и просто показва &lt;code&gt;Out of Sync&lt;/code&gt; за папките, но всъщност си синхронизираше. Е, грешах.&lt;/p&gt;
&lt;p&gt;След няколко часа дебъгване и без никакви следи във форумите след няколко търсения в Google, попаднах на &lt;a href=&quot;https://wiki.archlinux.org/title/syncthing#read-only_file_system_error_on_/etc_although_run_as_root&quot;&gt;статия за Syncthing в ArchWiki&lt;/a&gt;, която описваше точно моя случай:&lt;/p&gt;
&lt;p&gt;read-only file system error on /etc although run as root&lt;/p&gt;
&lt;p&gt;Това беше точно моят случай, с тази разлика, че проблемната папка не беше &lt;code&gt;/etc&lt;/code&gt;, а &lt;code&gt;/usr/local/src&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Е, след като прочетох какво пише, излезе, че ако стартираш Syncthing (или каквото и да е) през &lt;code&gt;systemd&lt;/code&gt; и имаш зададено &lt;code&gt;ProtectSystem&lt;/code&gt; на &lt;code&gt;full&lt;/code&gt; за услугата, някои директории стават само за четене по подразбиране. &lt;code&gt;/usr&lt;/code&gt; е една от тези директории.&lt;/p&gt;
&lt;p&gt;За да го поправиш, трябва да добавиш нов ред в конфигурацията на услугата и да я рестартираш (и да изпълниш &lt;code&gt;daemon-reload&lt;/code&gt;):&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ReadWritePaths=/usr/local/src&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;След това Syncthing би трябвало да работи нормално.&lt;/p&gt;</content:encoded><category>Homelab</category><category>linux</category><category>permissions</category><category>read-only</category><category>syncthing</category><category>systemd</category></item><item><title>[Linux] Изпълнение на множество команди на множество сървъри паралелно</title><link>https://bisko.be/bg/posts/dev/linux-running-multiple-commands-on-multiple-servers-in-parallel/</link><guid isPermaLink="true">https://bisko.be/bg/posts/dev/linux-running-multiple-commands-on-multiple-servers-in-parallel/</guid><description>Имам клъстер от Raspberry Pi-та вкъщи, на които върви Docker Swarm. За да ги държа в крак, те използват една и съща конфигурация – потребители, версии на Docker и т.н. Понякога някои от обновленията изискват да се изпълни едно и също нещо на всички възли в клъстера – например – създаване на нова Docker macvlan мрежа. За да</description><pubDate>Mon, 19 Apr 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Имам клъстер от Raspberry Pi-та вкъщи, на които върви Docker Swarm. За да ги държа в крак, те използват една и съща конфигурация – потребители, версии на Docker и т.н.&lt;/p&gt;
&lt;p&gt;Понякога някои от обновленията изискват да се изпълни едно и също нещо на всички възли в клъстера – например – създаване на нова Docker macvlan мрежа.&lt;/p&gt;
&lt;p&gt;За да стане това, човек трябва или да изпълни ръчно едни и същи команди на всички възли, като влиза с &lt;strong&gt;ssh&lt;/strong&gt; във всеки един от тях, изпълнява командите и преминава към следващия.&lt;/p&gt;
&lt;p&gt;Тъй като се опитвам в дългосрочен план да си намалям работата и да направя нещата възможно най-подредени, започнах да търся начини да изпълнявам команди на всички възли едновременно.&lt;/p&gt;
&lt;h3 id=&quot;итерация-1-собствен-python-скрипт&quot;&gt;Итерация 1: Собствен Python скрипт&lt;/h3&gt;
&lt;p&gt;Първата ми идея беше да напиша собствен Python скрипт. От една страна, така щях да науча Python малко по-добре, а от друга – не можах да намеря добър начин да изпълнявам команди по по-„роден“ начин.&lt;/p&gt;
&lt;p&gt;Както може да се очаква (хей, все още имам малко опит с езика 🙂 ), много бързо се превърна в раздут хаос и беше много податлив на счупвания.&lt;/p&gt;
&lt;p&gt;Трябваше да намеря друг начин, без да се налага да си припомням наново какво съм направил преди 3 седмици и какво се е счупило миналия път.&lt;/p&gt;
&lt;h3 id=&quot;итерация-2-pssh&quot;&gt;Итерация 2: &lt;code&gt;pssh&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Ровейки в Google, попаднах на &lt;code&gt;[pssh](https://linux.die.net/man/1/pssh)&lt;/code&gt;, който може да изпълнява неща паралелно през SSH.&lt;/p&gt;
&lt;p&gt;Като цяло беше доста лесно да го пусна и да проработи.&lt;/p&gt;
&lt;p&gt;Проблемът беше, че за част от нещата, които исках да правя, ми трябваше &lt;code&gt;sudo&lt;/code&gt;. Подаването на пароли насам-натам не беше най-доброто решение, така че пак трябваше да потърся как да изпратя &lt;code&gt;sudo&lt;/code&gt; паролата, когато отдалеченият сървър я поиска.&lt;/p&gt;
&lt;p&gt;Оказва се, че е доста лесно, ако попаднеш на правилния &lt;a href=&quot;https://unix.stackexchange.com/a/487558/134974&quot;&gt;коментар в StackOverflow&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;кратката-версия-е&quot;&gt;Кратката версия е:&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;stty&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -echo&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;printf&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;Password: &quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;read&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; PASS&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;stty&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; echo&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;${&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;PASS&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;}&quot;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;pssh&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -h&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;HOSTFIL&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;E&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -o&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; /tmp/output&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -t&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -I&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;`&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;cat&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; ./commands.sh`&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Частта &lt;code&gt;-I &quot;`cat ./commands.sh`&quot;&lt;/code&gt; трябва да се напише точно така (заобиколена с кавички и обратни кавички), иначе командите не се изпълняват правилно. Паролата ще бъде изпратена като отделна команда, а не като вход към &lt;strong&gt;sudo&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Другата уловка е, че заради начина, по който е направено всичко това, &lt;code&gt;sudo&lt;/code&gt; трябва да се изпълнява с параметъра &lt;code&gt;-S&lt;/code&gt;, за да приеме правилно паролата от входа.&lt;/p&gt;</content:encoded><category>Uncategorized</category></item><item><title>Разгадаване на числова парола на ZIP файл само с команднолинейни инструменти</title><link>https://bisko.be/bg/posts/dev/guessing-a-numeric-zip-file-password-only-with-command-line-utilities/</link><guid isPermaLink="true">https://bisko.be/bg/posts/dev/guessing-a-numeric-zip-file-password-only-with-command-line-utilities/</guid><description>Днес получих месечната си фактура от доставчика ми на интернет и нещо ми се стори странно. Фактурата, съдържаща се в писмото, беше в ZIP файл с парола. Да не говорим колко странно беше да се получи прикачен файл като ZIP в наши дни (спам, зловреден софтуер, фишинг и т.н.), паролата</description><pubDate>Mon, 14 Sep 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Днес получих месечната си фактура от доставчика ми на интернет и нещо ми се стори странно.&lt;/p&gt;
&lt;p&gt;Фактурата, съдържаща се в писмото, беше в ZIP файл с парола.&lt;/p&gt;
&lt;p&gt;Да не говорим колко странно беше да се получи прикачен файл като ZIP в наши дни (спам, зловреден софтуер, фишинг и т.н.), паролата, която бяха избрали, ми се стори много слаба.&lt;/p&gt;
&lt;p&gt;Това е рожденият ден на титуляря на сметката във формат &lt;code&gt;YYMMDD&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Направих едно много грубо изчисление наум, докато бях на фитнес, и се оказа, че възможните комбинации са много малко. След като използвах онлайн инструмент за изчисляване на колко дни са минали (тъй като не всички комбинации биха довели до валидна дата) от 1900-01-01, се оказа, че комбинациите са само 44 075 (до 2020-09-14).&lt;/p&gt;
&lt;p&gt;Знаейки, че оптимизирани инструменти, използващи GPU мощност за разбиване на хешове, могат да правят догадки в милиони на секунда, исках да видя колко бързо може да се разгадае паролата без да ги използвам, а само с помощта на Linux/macOS CLI (тъй като имах достъп единствено до VPS във фитнеса).&lt;/p&gt;
&lt;p&gt;Измислих следния код, който работи на macOS:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;echo {1..44000} | xargs -P 16 -n 1 -I{} date -v &quot;-{}d&quot; +&quot;%y%m%d&quot; | xargs -P 16 -I{} sh -c &apos;unzip -qqoP &quot;{}&quot; 0417160508.zip &amp;#x26;&amp;#x26; echo &quot;{}&quot; &amp;#x26;&amp;#x26; exit 255&apos;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Командата е доста проста в работата си, въпреки че изглежда сложна.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;echo {1..44000}&lt;/code&gt; генерира числата от 1 до 44 000 и ги предава на следващата стъпка.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;xargs -P 16 -n 1 -I{} date -v &quot;-{}d&quot; +&quot;%y%m%d&quot;&lt;/code&gt; – взема входа от първата стъпка и генерира дати във формат &lt;code&gt;YYMMDD&lt;/code&gt;, като използва функционалността на &lt;code&gt;date&lt;/code&gt; да „добавя“ към дата определено количество. В случая това би извадило X дни от текущата дата. Където X е числото, генерирано в първата стъпка. По този начин можем да генерираме дати от днес назад до 1900-те.&lt;/p&gt;
&lt;p&gt;Третата стъпка е по-интересната, затова ще я разделя на две части:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;xargs -P 16 -I{} sh -c &apos;...&apos;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Това взема генерираните дати от стъпка 2 и изпълнява команда за всяка от тези дати. &lt;code&gt;-P 16&lt;/code&gt; тук означава, че това ще се изпълнява в 16 паралелни процеса, за да се ускори пресяването на данните. Същият трик е приложен и в стъпка 2, за да се ускори генерирането на дати.&lt;/p&gt;
&lt;p&gt;Втората част е мястото, където се случват догадките:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;unzip -qqoP &quot;{}&quot; 0417160508.zip &amp;#x26;&amp;#x26; echo &quot;{}&quot; &amp;#x26;&amp;#x26; exit 255&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Това, което прави, е първо да се опита да декомпресира zip файла, използвайки паролата, генерирана в стъпка 2. Ако е успешно, то ще отпечата (&lt;code&gt;echo&lt;/code&gt;) познатата парола и след това &lt;code&gt;exit 255&lt;/code&gt; принуждава &lt;code&gt;xargs&lt;/code&gt; да спре изпълнението. Не искаме да продължаваме да гадаем, ако паролата вече е намерена.&lt;/p&gt;
&lt;p&gt;Като цяло, беше доста лошо решение да се избере това за парола на файла, защото изпълнението на горната команда отнема само около 10 секунди, за да се разгадае правилната парола за моята фактура. Не много повече за когото и да било друг.&lt;/p&gt;</content:encoded><category>Uncategorized</category></item><item><title>Как да се справим със спагети код в PHP: използване на анонимни функции за извличане на парчета шаблонен код</title><link>https://bisko.be/bg/posts/dev/dealing-with-spaghetti-code-in-php-using-anonymous-functions-to-extract-pieces-of-template-code/</link><guid isPermaLink="true">https://bisko.be/bg/posts/dev/dealing-with-spaghetti-code-in-php-using-anonymous-functions-to-extract-pieces-of-template-code/</guid><description>Напоследък помагам на един приятел да разбере някакъв код и как да го промени, за да работи добре с асинхронни заявки към бекенда. Бонус би било да може да се напише по-модулно и преизползваемо. Кодът е WordPress плъгин, който беше написан</description><pubDate>Sat, 08 Aug 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Напоследък помагам на един приятел да разбере някакъв код и как да го промени, за да работи добре с асинхронни заявки към бекенда. Бонус би било да може да се напише по-модулно и преизползваемо.&lt;/p&gt;
&lt;p&gt;Кодът е WordPress плъгин, написан с много наследен (legacy) подход – бизнес и фронтенд логиката са смесени на едно място. Манипулации на данни, правени по средата на шаблонния код и подобни неща.&lt;/p&gt;
&lt;p&gt;Всъщност това е горе-долу онова, което сте виждали в PHP сайтовете от началото на 2000-те, преди всички страхотни ООП допълнения към езика и купчината зрели фреймуърци.&lt;/p&gt;
&lt;p&gt;Случаят, по който работих днес, беше следният – имаш таблица, която показва куп записи. Трябваше да добавим няколко филтъра към таблицата и да я накараме да работи през AJAX, за да се обновява бързо интерфейсът, без да се презарежда цялата страница на WordPress Admin.&lt;/p&gt;
&lt;p&gt;Филтрирането на данните беше лесно – един бърз inline &lt;code&gt;array_filter&lt;/code&gt;, който да филтрира данните, преди да бъдат подадени към шаблонния код (за да запазим същия стил на кода, и това беше в шаблонния файл 😇).&lt;/p&gt;
&lt;p&gt;Проблемът дойде, когато започнахме да работим по това таблицата да може да се рендерира през AJAX.&lt;/p&gt;
&lt;p&gt;Тя е по средата на куп друг шаблонен и бизнес код. Ако искахме през AJAX да връщаме само таблицата, имахме съвсем малко начини да го постигнем.&lt;/p&gt;
&lt;p&gt;Първият начин би бил да обвием HTML-а преди и след таблицата в ОГРОМНИ &lt;code&gt;if&lt;/code&gt; конструкции, за да сме сигурни, че той не се рендерира.&lt;/p&gt;
&lt;p&gt;Друг начин би бил да извадим шаблона в отделен файл и да го включим в AJAX action-а, който бихме дефинирали в кода на плъгина.&lt;/p&gt;
&lt;p&gt;Анонимните функции на помощ!&lt;/p&gt;
&lt;p&gt;Мислейки как да се справя с това по най-лесния възможен начин, опитах да дефинирам нормална PHP функция, която да съдържа кода на таблицата, но имаше проблем.&lt;/p&gt;
&lt;p&gt;Кодът се изпълнява в метод на клас. В шаблона на таблицата има препратки към &lt;code&gt;$this&lt;/code&gt;. Ако не искаме да променяме кода много, трябва да подадем &lt;code&gt;$this&lt;/code&gt; като аргумент на функцията. Е, това не работи, защото не можеш да подадеш &lt;code&gt;$this&lt;/code&gt; като параметър 🤷‍♂️.&lt;/p&gt;
&lt;p&gt;Бях малко разочарован, че ще трябва да пренапишем доста неща в шаблона, а имаше доста препратки, за които трябваше да внимаваме, за да продължи всичко да работи.&lt;/p&gt;
&lt;p&gt;Тогава си спомних, че сайтът не работи на PHP 5.2, а на PHP 7, така че анонимните функции се поддържат.&lt;/p&gt;
&lt;p&gt;А те имат полезна възможност да определиш кои променливи от извикващия обхват да бъдат подадени на функцията, когато тя бъде извикана. Например:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;php&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;$table_function &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; function&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;use&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ( $pages, $current_page, $items ) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    // ... Table render code&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Това ще ти позволи директно да използваш &lt;code&gt;$pages&lt;/code&gt; или &lt;code&gt;$items&lt;/code&gt; в тялото на функцията.&lt;/p&gt;
&lt;p&gt;Страхотното тук е, че можеш да подадеш и &lt;code&gt;$this&lt;/code&gt; като променлива в обхвата на функцията!&lt;/p&gt;
&lt;p&gt;Така успяхме напълно да извадим кода за рендериране на таблицата в отделна функция, която можем да извикаме изолирано по време на AJAX заявката!&lt;/p&gt;
&lt;p&gt;Разбира се, човек трябва да внимава много с променливите, използвани в тялото на функцията, защото те трябва да са дефинирани, така че внимавай откъде може да бъде извикана AJAX функцията.&lt;/p&gt;
&lt;p&gt;За нас това означава, че ще добавим малък action в основния клас, който пак ще include-ва файла, но ще имаме повече контрол върху спирането на всички останали изходи, които иначе ще се случат.&lt;/p&gt;</content:encoded><category>Snippets</category><category>lambda-functions</category><category>php</category><category>WordPress</category></item><item><title>Arduino/ESP32: Изключване на task watchdog-а</title><link>https://bisko.be/bg/posts/dev/arduino-esp32-disabling-the-task-watchdog/</link><guid isPermaLink="true">https://bisko.be/bg/posts/dev/arduino-esp32-disabling-the-task-watchdog/</guid><description>Напоследък си играя с многоядрените възможности на ESP32 и закрепването на задачи към конкретни ядра. Използвах AutoConnect, за да поддържам WiFi връзка без да съхранявам паролите в кода и за OTA ъпдейти през уеб интерфейса. Това беше за проект, който щеше да управлява няколко 4-пинови CPU PWM вентилатора, които са в</description><pubDate>Wed, 29 Apr 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Напоследък си играя с многоядрените възможности на ESP32 и закрепването на задачи към конкретни ядра.&lt;/p&gt;
&lt;p&gt;Използвах &lt;a href=&quot;https://github.com/Hieromon/AutoConnect&quot;&gt;AutoConnect&lt;/a&gt;, за да поддържам WiFi връзка без да съхранявам паролите в кода и да предоставя OTA ъпдейти през уеб интерфейса.&lt;/p&gt;
&lt;p&gt;Това беше за проект, който щеше да управлява няколко 4-пинови CPU PWM вентилатора, които са в сървърния ми шкаф, за да охлаждат въздуха вътре. За целта исках да разделя логиката на две задачи.&lt;/p&gt;
&lt;p&gt;Едната задача да се занимава с API-та, четене на сензори, ъпдейти, WiFi и т.н., а другата да обработва прекъсването и PWM управлението на вентилаторите.&lt;/p&gt;
&lt;p&gt;Всичко беше наред, задачите бяха създадени, но когато пуснах кода и ESP32 влезеше в режима, в който трябва да се свържеш с него, за да му кажеш към коя WiFi мрежа да се свърже, започна да се държи странно – рестартираше контролера на всеки няколко секунди и не успявах да накарам връзката да работи.&lt;/p&gt;
&lt;p&gt;Това беше досадно, защото трябваше да демонтирам контролера от мястото му и да го свържа по USB, за да кача нов фърмуер.&lt;/p&gt;
&lt;p&gt;След като направих всичко това, забелязах, че грешката идва от watchdog-а:&lt;/p&gt;
&lt;p&gt;Task watchdog got triggered. The following tasks did not feed the watchdog in time:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;IDLE (CPU 1)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Tasks currently running:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;CPU 0: ManageTask&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;CPU 1: ControllerTask&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Поразрових се и излиза, че това се задейства от Task Watchdog-а на ESP32, който се грижи всички задачи да получават своя ред за изпълнение на процесора.&lt;/p&gt;
&lt;p&gt;Изглежда също, че AutoConnect не е особено гъвкав, когато работи в контекста на задача, в сравнение с изпълнение извън такава, директно с всичкия останал код и функционалност.&lt;/p&gt;
&lt;p&gt;След известно ровене и пробване на различни неща, излиза, че най-лесният начин да се измъкнеш от тази ситуация е просто да изключиш watchdog-а и да се надяваш нещата да се изпълнят навреме 🙂 Задачата не е критична, така че е нормално да се изчака повече, докато приключи с това, което прави.&lt;/p&gt;
&lt;p&gt;За да изключите watchdog-а, трябва да направите две неща:&lt;/p&gt;
&lt;p&gt;Първо, включете хедъра &lt;code&gt;esp_task_wdt.h&lt;/code&gt;. За целта добавете &lt;code&gt;#include &amp;#x3C;esp_task_wdt.h&gt;&lt;/code&gt; към секцията с include-ите си.&lt;/p&gt;
&lt;p&gt;Второ, накарайте watchdog-а да не рестартира контролера и да чака по-дълго. За целта трябва да добавите &lt;code&gt;esp_task_wdt_init(30, false);&lt;/code&gt; в началото на кода на вашата задача.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;cpp&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; manage_core_task&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;pv_parameters&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    esp_task_wdt_init&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;30&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    // .... rest of the code ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Това ще зададе timeout на watchdog-а на 30 &lt;strong&gt;СЕКУНДИ&lt;/strong&gt; и ще изключи рестартирането на контролера, ако се задейства.&lt;/p&gt;
&lt;p&gt;Ако искате контролерът все пак да се рестартира след задействане на watchdog-а, сменете втория параметър на извикването на функцията от &lt;code&gt;false&lt;/code&gt; на &lt;code&gt;true&lt;/code&gt;.&lt;/p&gt;</content:encoded><category>Uncategorized</category><category>arduino</category><category>code</category><category>esp32</category><category>espressif</category><category>multi-core</category><category>multi-threading</category></item><item><title>Настройване на YubiKey за подписване на Git комити</title><link>https://bisko.be/bg/posts/dev/setting-up-a-yubikey-for-git-commit-signing/</link><guid isPermaLink="true">https://bisko.be/bg/posts/dev/setting-up-a-yubikey-for-git-commit-signing/</guid><description>Използвам YubiKey като ключ за двуфакторна автентикация и за подписване на Git комитите си. До преди няколко дни използвах YubiKey 4. Тъй като текущият ми компютър няма никакви USB-A портове, мъкнех из раницата си USB-A към USB-C адаптери и използването на ключа беше досадно неудобство за</description><pubDate>Wed, 08 Jan 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Използвам YubiKey като ключ за &lt;a href=&quot;https://en.wikipedia.org/wiki/Multi-factor_authentication&quot;&gt;двуфакторна автентикация&lt;/a&gt; и за подписване на Git комитите си. До преди няколко дни използвах YubiKey 4. Тъй като текущият ми компютър няма никакви USB-A портове, последната година мъкнех из раницата си USB-A към USB-C адаптери и използването на ключа беше пълна мъка. Затова реших, че е време да мина на „новия“ си YubiKey 5C и да не жонглирам повече с тези адаптери.&lt;/p&gt;
&lt;p&gt;Всъщност ключът си стои у мен от доста време – поръчах го заедно със заместващ YubiKey 4, който получих заради проблема с &lt;a href=&quot;https://www.yubico.com/2017/10/infineon-rsa-key-generation-issue/&quot;&gt;Infineon TPM&lt;/a&gt;, който са открили, но чак сега реших, че е време да премина на новия ключ.&lt;/p&gt;
&lt;p&gt;Другата причина да го направя точно сега е, че старите ми GPG ключове изтекоха и трябваше да ги издам наново, така че мога да използвам ключа за подписване на Git комитите си.&lt;/p&gt;
&lt;h3 id=&quot;gpg-лудницата&quot;&gt;GPG лудницата&lt;/h3&gt;
&lt;p&gt;Ако си се занимавал с GPG ключове в миналото (или се занимаваш в момента), знаеш, че може да е доста трудно да го накараш да работи както трябва и безопасно, ако никога не си го правил. Пазене на главните ключове офлайн, местене на публични ключове, преиздаване на ключове след изтичането им, евентуално подписването им с предишни ключове за верификация, отнемане на ключове… Не е лесно да следваш най-добрите практики дори на теория. Когато стане дума за практиката, нещата стават изключително сложни.&lt;/p&gt;
&lt;p&gt;Повечето уроци в мрежата препоръчват да използваш командния ред за генериране на ключовете, да навигираш из менюта с необичаен дизайн и общо взето е болка да ги накараш да заработят. Повечето казват да използваш офлайн машина, например Raspberry PI, и/или да генерираш главните ключове и подключовете офлайн и да държиш главния ключ далеч от компютъра си.&lt;/p&gt;
&lt;p&gt;🤯&lt;/p&gt;
&lt;p&gt;Занимавам се с това всеки януари вече почти 4 години. Страхувам се от момента, в който получа следната грешка, която ми показва, че подписващите ми ключове са изтекли.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;error: gpg failed to sign the data&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;fatal: failed to write commit object&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Тази година реших, че е време да направя процеса много по-лесен и да използвам вграденото генериране на сертификати, за да избегна цялата тази каша с генерирането на GPG ключове и подобни.&lt;/p&gt;
&lt;h3 id=&quot;генериране-на-ключове-директно-върху-yubikey&quot;&gt;Генериране на ключове директно върху YubiKey&lt;/h3&gt;
&lt;p&gt;Пак ще трябва да ползваме интерфейса в командния ред, но е малко по-ясен, защото има по-малко стъпки.&lt;/p&gt;
&lt;p&gt;Първо трябва да настроим картата/устройството.&lt;/p&gt;
&lt;h3 id=&quot;настройка-на-картатаустройството&quot;&gt;Настройка на картата/устройството&lt;/h3&gt;
&lt;p&gt;Изпълни &lt;code&gt;gpg --card-status&lt;/code&gt; в терминала и трябва да видиш нещо такова:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Reader ………..: Yubico Yubikey 4 OTP U2F CCID&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Application ID …: &amp;#x3C;Serial number&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Version ……….: 2.1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Manufacturer …..: Yubico&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Serial number ….: &amp;#x3C;Device serial number&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Name of cardholder: unspecified&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Language prefs …: en&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Sex …………..: unspecified&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;URL of public key : \[not set\]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Login data …….: &amp;#x3C;e-mail or nothing&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Signature PIN ….: not forced&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Key attributes …: rsa4096 rsa4096 rsa4096&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Max. PIN lengths .: 127 127 127&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;PIN retry counter : 3 0 3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Signature counter : 9&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ако виждаш нещо подобно и няма грешки, можеш спокойно да продължиш.&lt;/p&gt;
&lt;p&gt;Изпълни &lt;code&gt;gpg --card-edit&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Ще се озовеш в интерфейс в командния ред, който показва същата информация в началото, а най-отдолу има команден промпт &lt;code&gt;gpg/card&gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Напиши &lt;code&gt;admin&lt;/code&gt; и натисни Enter.&lt;/p&gt;
&lt;p&gt;Сега можеш да напишеш &lt;code&gt;help&lt;/code&gt;, за да разбереш как да промениш информацията за собственика и PIN кодовете на картата.&lt;/p&gt;
&lt;p&gt;Нещо, което &lt;strong&gt;&lt;em&gt;ЗАДЪЛЖИТЕЛНО&lt;/em&gt;&lt;/strong&gt; трябва да направиш, е да смениш PIN кодовете по подразбиране на картата. Те са два. Първият е PIN кодът, с който достъпваш ключовете на картата. Вторият е „Admin“ PIN или PUK (Personal Unblocking Code).&lt;/p&gt;
&lt;p&gt;За целта напиши &lt;code&gt;passwd&lt;/code&gt; и ще видиш меню:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;gpg/card&gt; passwd  &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;gpg: OpenPGP card no. &amp;#x3C;Serial number&gt; detected&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;1 - change PIN  &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;2 - unblock PIN  &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;3 - change Admin PIN  &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;4 - set the Reset Code  &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Q - quit&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Напиши &lt;code&gt;1&lt;/code&gt; и следвай указанията, за да смениш PIN кода. PIN кодът по подразбиране е &lt;code&gt;123456&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;След като приключиш с това, избери &lt;code&gt;3&lt;/code&gt;, за да смениш Admin PIN. По подразбиране е &lt;code&gt;12345678&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;След като смениш и двата кода, върни се в главното меню, за да довършиш обновяването на информацията за ключа.&lt;/p&gt;
&lt;p&gt;Командите, които можеш да използваш, са:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;name&lt;/code&gt; – за смяна на името на собственика на картата&lt;/li&gt;
&lt;li&gt;&lt;code&gt;login&lt;/code&gt; – за смяна на имейл адреса или логина на собственика на картата&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;След това можем да преминем към същинското генериране на ключове.&lt;/p&gt;
&lt;h3 id=&quot;генериране-на-ключове&quot;&gt;Генериране на ключове&lt;/h3&gt;
&lt;p&gt;Сега е време наистина да генерираме ключовете.&lt;/p&gt;
&lt;p&gt;За целта напиши &lt;code&gt;generate&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Ще бъдеш попитан &lt;code&gt;Make off-card backup of encryption key? (Y/n)&lt;/code&gt;, но както се споменава в документацията на YubiKey, това е само бекъп „на парче“ и няма да създаде пълен бекъп на тайните ключове, така че няма значение дали ще отговориш &lt;code&gt;Yes&lt;/code&gt;, или &lt;code&gt;No&lt;/code&gt;. Аз отговарям с &lt;code&gt;No(n)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Ако на картата вече има запазени ключове, ще бъдеш попитан дали искаш да ги замениш:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;gpg: Note: keys are already stored on the card!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Replace existing keys? (y/N)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Увери се, че няма да заменяш нещо важно, от което нямаш бекъп, и продължи с &lt;code&gt;Y&lt;/code&gt;. Ако има нещо важно, по-добре прекъсни целия процес с &lt;code&gt;Ctrl+C&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Ще бъдеш попитан за PIN кода на картата, който зададе по-рано.&lt;/p&gt;
&lt;p&gt;После трябва да избереш за колко време ще са валидни ключовете:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Please specify how long the key should be valid.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        0 = key does not expire&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &amp;#x3C;n&gt; = key expires in n days&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;     &amp;#x3C;n&gt;w = key expires in n weeks&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;     &amp;#x3C;n&gt;m = key expires in n months&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;     &amp;#x3C;n&gt;y = key expires in n years&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; Key is valid for? (0)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ако искаш ключовете да са валидни само 1 година, напиши &lt;code&gt;1y&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Ще бъдеш помолен да потвърдиш датата на изтичане. Провери дали всичко е правилно и потвърди.&lt;/p&gt;
&lt;p&gt;След това ще трябва да въведеш информация за собственика на ключа:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Is this correct? (y/N) y&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;GnuPG needs to construct a user ID to identify your key.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Real name: &amp;#x3C;Your name&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Email address: &amp;#x3C;Your e-mail&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Comment: &amp;#x3C;Comment is optional&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; You selected this USER-ID:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;     &quot;&amp;#x3C;Your name&gt; &amp;#x3C;comment&gt; &amp;#x3C;your e-mail&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit?&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Type `O` to confirm if everything seems correct.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;След това ще бъдеш попитан за Admin PIN или PUK. Това е необходимо, защото ще се извърши запис върху картата.&lt;/p&gt;
&lt;p&gt;После, ако всичко е наред, YubiKey ще започне да мига и ще продължи да го прави известно време (при мен отнема към пет минути).&lt;/p&gt;
&lt;p&gt;Когато приключи, ще видиш следното съобщение:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;gpg: key &amp;#x3C;Short ID&gt; marked as ultimately trusted&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;gpg: revocation certificate stored as &apos;/Users/bisko/.gnupg/openpgp-revocs.d/&amp;#x3C;LONG ID&gt;.rev&apos; public and secret key created and signed.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Запиши си &lt;code&gt;&amp;#x3C;Short ID&gt;&lt;/code&gt;, защото ще ни трябва по-късно.&lt;/p&gt;
&lt;p&gt;В този момент можеш да излезеш от GPG промпта с &lt;code&gt;quit&lt;/code&gt; или &lt;code&gt;Ctrl+C&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Сега е време да запазим публичния ключ, за да можем да го използваме на друг компютър.&lt;/p&gt;
&lt;p&gt;За целта изпълни следната команда:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;gpg&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; --armor&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; --export&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;Short&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; I&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;D&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; &gt;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;Short&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; I&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;D&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;.asc&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Това ще експортира публичния ключ във файл с име &lt;code&gt;&amp;#x3C;Short ID&gt;.asc&lt;/code&gt;. Той ще ти трябва в бъдеще, ако искаш да използваш YubiKey на друг компютър или ако изгубиш GPG конфигурацията си.&lt;/p&gt;
&lt;p&gt;За да възстановиш публичния ключ във връзката си с ключове (keyring), направи следното:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;gpg&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; --import&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;Short&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; I&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;D&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;.asc&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;gpg:&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; key&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;Short&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; I&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;D&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; public&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; key&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;Your Name &amp;#x3C;your@email&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; imported&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;gpg:&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; Total&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; number&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; processed:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;gpg:&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; imported:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;Много важна забележка.&lt;/em&gt;&lt;/strong&gt; Ако това е нова инсталация на GPG или друг компютър, GPG няма сам да разпознае ключовете на картата. Трябва да изпълниш &lt;code&gt;gpg --card-status&lt;/code&gt;, за да може да прочете картата и да засече ключовете върху нея.&lt;/p&gt;
&lt;h3 id=&quot;настройка-на-git-за-подписване&quot;&gt;Настройка на Git за подписване&lt;/h3&gt;
&lt;p&gt;За да настроиш Git да подписва комитите ти, трябва да добавиш следното в &lt;code&gt;~/.gitconfig&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;В секцията &lt;code&gt;[user]&lt;/code&gt; трябва да добавиш (или обновиш) следния ред:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;signingkey = 0x&amp;#x3C;Short ID&gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;После, ако искаш да подписваш всичките си комити, добави следното в края на файла:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;ini&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;[gpg]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  program&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; = /usr/local/bin/gpg&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;[commit]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  gpgsign&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; = true&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Така Git ще подписва всички твои комити.&lt;/p&gt;
&lt;p&gt;За да настроиш GitHub, трябва да добавиш публичния си ключ към профила си. За целта отиди на &lt;code&gt;GitHub -&gt; Settings -&gt; SSH and GPG keys -&gt; New GPG key&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Ще видиш текстово поле, в което трябва да поставиш цялото съдържание на файла &lt;code&gt;&amp;#x3C;Short ID&gt;.asc&lt;/code&gt;, който генерирахме по-горе.&lt;/p&gt;
&lt;p&gt;Ако искаш да копираш съдържанието на файла (на macOS), можеш да направиш така:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;cat &amp;#x3C;Short ID&gt;.asc | pbcopy&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Това ще копира съдържанието на целия файл в клипборда.&lt;/p&gt;
&lt;p&gt;Постави го в текстовото поле в GitHub и натисни бутона &lt;code&gt;Add GPG key&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;След това можеш да пробваш да направиш комит и push към GitHub и трябва да видиш симпатичния етикет &lt;code&gt;Verified&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;дебъгване&quot;&gt;Дебъгване&lt;/h3&gt;
&lt;p&gt;Понякога нещата не работят от раз. За да съберем повече информация, можем да опитаме следното:&lt;/p&gt;
&lt;h3 id=&quot;подписване-с-gpg&quot;&gt;Подписване с GPG&lt;/h3&gt;
&lt;p&gt;Първо опитай да подпишеш нещо с ключа:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;gpg -s &amp;#x3C;file&gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Ако това не успее, опитай да разбереш защо, аз не съм експерт, за да помогна с това.&lt;/p&gt;
&lt;p&gt;Погледни изхода на GitGIT_TRACE=1 git commit -am “test”&lt;/p&gt;
&lt;p&gt;Това ще ти покаже точно какво прави Git, докато се опитва да направи комита и да го подпише. Ще ти даде насока защо подписването може да се проваля.&lt;/p&gt;
&lt;p&gt;От него можеш да видиш и че Git изпълнява следната команда:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;/usr/local/bin/gpg&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; --status-fd=2&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -bsau&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;Key&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; I&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;D&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Можеш да опиташ да я изпълниш ръчно, за да видиш дали ще ти даде по-добра грешка.&lt;/p&gt;</content:encoded><category>Snippets</category><category>Technology</category><category>git</category><category>github</category><category>gpg</category><category>key</category><category>public-key</category><category>secrets</category><category>sign</category><category>yubikey</category></item><item><title>e1000e eth0: Detected Hardware Unit Hang</title><link>https://bisko.be/bg/posts/dev/e1000e-device-id-eth0-detected-hardware-unit-hang/</link><guid isPermaLink="true">https://bisko.be/bg/posts/dev/e1000e-device-id-eth0-detected-hardware-unit-hang/</guid><description>Напоследък домашният ми сървър и VM хост на случаен принцип започна да губи мрежова свързаност. Отвън изглежда, че още работи, но не можех да го достъпя по никакъв отдалечен начин. Ethernet адаптерът изглеждаше включен според суича, така че проблемът трябваше да е някъде в софтуера. Нямаше да е</description><pubDate>Wed, 18 Dec 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Напоследък домашният ми сървър и VM хост на случаен принцип започна да губи мрежова свързаност. Отвън изглежда, че още работи, но не можех да го достъпя по никакъв отдалечен начин. Ethernet адаптерът изглеждаше включен според суича, така че проблемът трябваше да е някъде в софтуера.&lt;/p&gt;
&lt;p&gt;Нямаше да е първият път, в който драйвер причинява зависване на мрежовата връзка. В миналото съм се опарвал от бъгави WiFi драйвери както на Linux, така и на Windows компютри.&lt;/p&gt;
&lt;p&gt;След като поразрових малко системните логове, се натъкнах на следното:&lt;/p&gt;
&lt;p&gt;vmhost kernel: e1000e 0000:00:1f.6 eth0: Detected Hardware Unit Hang:&lt;br&gt;
vmhost kernel:   TDH                  &amp;#x3C;0&gt;&lt;br&gt;
vmhost kernel:   TDT                  &amp;#x3C;1&gt;&lt;br&gt;
vmhost kernel:   next_to_use          &amp;#x3C;1&gt;&lt;br&gt;
vmhost kernel:   next_to_clean        &amp;#x3C;0&gt;&lt;br&gt;
vmhost kernel: buffer_info[next_to_clean]:&lt;br&gt;
vmhost kernel:   time_stamp           &amp;#x3C;10fbc2f81&gt;&lt;br&gt;
vmhost kernel:   next_to_watch        &amp;#x3C;0&gt;&lt;br&gt;
vmhost kernel:   jiffies              &amp;#x3C;10fbc3871&gt;&lt;br&gt;
vmhost kernel:   next_to_watch.status &amp;#x3C;0&gt;&lt;br&gt;
vmhost kernel: MAC Status             &amp;#x3C;40080083&gt;&lt;br&gt;
vmhost kernel: PHY Status             &amp;#x3C;796d&gt;&lt;br&gt;
vmhost kernel: PHY 1000BASE-T Status  &amp;#x3C;7800&gt;&lt;br&gt;
vmhost kernel: PHY Extended Status    &amp;#x3C;3000&gt;&lt;br&gt;
vmhost kernel: PCI Status             &amp;#x3C;10&gt;&lt;br&gt;
vmhost kernel: e1000e 0000:00:1f.6 eth0: Reset adapter unexpectedly&lt;br&gt;
vmhost kernel: vmbr0: port 1(eth0) entered disabled state&lt;/p&gt;
&lt;p&gt;След това ресетваше мрежовия адаптер и малко по-късно го правеше пак, докато машината накрая изобщо не излезе офлайн.&lt;/p&gt;
&lt;p&gt;Търсейки отговори онлайн, попаднах на &lt;a href=&quot;https://serverfault.com/questions/616485/e1000e-reset-adapter-unexpectedly-detected-hardware-unit-hang&quot;&gt;тази тема в ServerFault&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Причина&lt;/p&gt;
&lt;p&gt;От различни източници и списъци с бъг репорти излиза, че най-лесният начин да се възпроизведе проблемът е ситуация с висока честотна лента на устройството, т.е. поточно пренасяне на големи количества данни, които насищат интерфейса.&lt;/p&gt;
&lt;p&gt;При мен това обикновено се случваше, когато стриймвам медия от локалния Plex сървър към някое устройство. Заради начина, по който е изградена мрежата, Windows VM-ът, на който върви Plex, трябва да вземе медийния файл от NFS мрежов дял на отделно устройство, да го транскодира във VM-а и после да го изпрати към устройството за възпроизвеждане.&lt;/p&gt;
&lt;p&gt;Това се натрупва до много мрежов трафик, обикновено ~40-100 mbit/s, в зависимост от устройството, което пуска файла, и от качеството на оригиналния файл.&lt;/p&gt;
&lt;p&gt;Същият проблем се появи и при стриймване на игри през Steam Link към нашия Apple TV. Връзката е кабелна, но не е необичайно мрежата да прекъсне. Мисля, че е свързано със същия проблем, но ще държа под око дали ще се повтори в бъдеще след поправката.&lt;/p&gt;
&lt;p&gt;Възможна поправка&lt;/p&gt;
&lt;p&gt;Изглежда, че възможна поправка е да се изключат &lt;strong&gt;GSO&lt;/strong&gt; &lt;em&gt;(Generic Segmentation Offload)&lt;/em&gt;, &lt;strong&gt;TSO&lt;/strong&gt; &lt;em&gt;(TCP Segmentation Offload)&lt;/em&gt; и &lt;strong&gt;GRO&lt;/strong&gt; &lt;em&gt;(Generic Receive Offload)&lt;/em&gt; на мрежовия интерфейс*:&lt;/p&gt;
&lt;p&gt;ethtool -K eth0 gso off gro off tso off&lt;/p&gt;
&lt;p&gt;Приложих това при себе си и чакам да видя дали наистина ще реши проблема в дългосрочен план.&lt;/p&gt;
&lt;p&gt;Бележки под линия&lt;/p&gt;
&lt;p&gt;* Тези опции са свързани с прехвърлянето на сегментирането на пакети към мрежовия контролер, за да се намали натоварването на процесора на машината. Повече подробности може да намерите в &lt;a href=&quot;https://en.wikipedia.org/wiki/Large_send_offload&quot;&gt;тази статия в Уикипедия&lt;/a&gt;.&lt;/p&gt;</content:encoded><category>Homelab</category><category>bandwidth</category><category>bug</category><category>network</category><category>nic</category><category>plex</category><category>proxmox</category><category>steam</category><category>streaming</category></item><item><title>Бележки: Стартиране на локален/частен swarm регистър за Docker образи</title><link>https://bisko.be/bg/posts/dev/snippets-running-a-local-private-swarm-docker-image-registry/</link><guid isPermaLink="true">https://bisko.be/bg/posts/dev/snippets-running-a-local-private-swarm-docker-image-registry/</guid><description>Днес се опитвах да генерирам Docker образ от Node.js проект и исках да го разположа на моя локален тестов swarm. За съжаление, ако човек създаде локален Docker образ, той се съхранява и е достъпен само на възела, на който е създаден, а останалите възли в swarm не могат да го достъпят. Начинът</description><pubDate>Fri, 11 Oct 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Днес се опитвах да генерирам Docker образ от Node.js проект и исках да го разположа на моя локален тестов swarm.&lt;/p&gt;
&lt;p&gt;За съжаление, ако човек създаде локален Docker образ, той се съхранява и е достъпен само на възела, на който е създаден, а останалите възли в swarm не могат да го достъпят.&lt;/p&gt;
&lt;p&gt;Решението е образът да се качи (push) в Docker регистър, от който всички възли в swarm могат да го изтеглят (pull).&lt;/p&gt;
&lt;p&gt;Създаване на регистъра&lt;/p&gt;
&lt;p&gt;За да стартирате регистър услуга в swarm, изпълнете:&lt;/p&gt;
&lt;p&gt;docker service create —name registry —publish 5000:5000 registry:latest&lt;/p&gt;
&lt;p&gt;Това ще създаде услугата registry и ще я стартира в swarm, като я направи достъпна за всички възли в swarm.&lt;/p&gt;
&lt;p&gt;Качване на образ в регистъра&lt;/p&gt;
&lt;p&gt;За да качите образ в регистъра, трябва да направите две неща – да го тагнете и след това да го push-нете.&lt;/p&gt;
&lt;p&gt;Ето пример как да build-нете и тагнете образа наведнъж:&lt;/p&gt;
&lt;p&gt;docker build . -t localhost.localdomain:5000/&lt;image-name&gt;:latest&lt;/image-name&gt;&lt;/p&gt;
&lt;p&gt;И как да го качите в регистъра:&lt;/p&gt;
&lt;p&gt;docker push localhost.localdomain:5000/&lt;image-name&gt;:latestИзползване на образа в услуга/контейнер/и т.н.&lt;/image-name&gt;&lt;/p&gt;
&lt;p&gt;За да използвате образа в услуга или контейнер, посочвате пълния път от по-горе, т.е. &lt;code&gt;localhost.localdomain:5000/&amp;#x3C;image-name&gt;:latest&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Възлите в swarm ще имат достъп до образа и ще могат да го изтеглят и стартират.&lt;/p&gt;
&lt;p&gt;Важна забележка относно адреса на регистъра&lt;/p&gt;
&lt;p&gt;В повечето уроци онлайн адресът на регистъра е даден като &lt;code&gt;localhost:5000&lt;/code&gt;. За съжаление това не работи и обикновено изтича времето за изчакване, когато се опитате да го ползвате. Ако го смените с &lt;code&gt;localhost.localdomain&lt;/code&gt;, ще заработи!&lt;/p&gt;
&lt;p&gt;Не знам защо се случва това, при положение че и &lt;code&gt;localhost&lt;/code&gt;, и &lt;code&gt;localhost.localdomain&lt;/code&gt; се разрешават до &lt;code&gt;127.0.0.1&lt;/code&gt;.&lt;/p&gt;</content:encoded><category>Homelab</category><category>Snippets</category><category>Technology</category><category>docker</category><category>docker-swarm</category><category>registry</category><category>swarm</category></item><item><title>Снипети: Преместване на клавиша Section sign на Apple клавиатурите към back quote ( § към ` )</title><link>https://bisko.be/bg/posts/dev/snippets-map-apple-keyboard-section-sign-key-to-back-quote-%C2%A7-to/</link><guid isPermaLink="true">https://bisko.be/bg/posts/dev/snippets-map-apple-keyboard-section-sign-key-to-back-quote-%C2%A7-to/</guid><description>Използвам клавиатури на Apple от доста време, но когато живееш в Европа, не е лесно да се сдобиеш с американската подредба, на която съм свикнал. На macOS има „лесен“ начин да пренастроиш клавиатурата само с една команда в терминала: watch -n1 -x hidutil property -m ‘{“ProductID”:592, “VendorID”:1452}’ –set ‘{“UserKeyMapping”:[{“HIDKeyboardModifierMappingSrc”:0x700000035,”HIDKeyboardModifierMappingDst”:0x700000064}]}’ Какво прави това</description><pubDate>Wed, 31 Jul 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Използвам клавиатури на Apple от доста време, но когато живееш в Европа, не е лесно да се сдобиеш с американската подредба, на която съм свикнал.&lt;/p&gt;
&lt;p&gt;На macOS има „лесен“ начин да пренастроиш клавиатурата само с една команда в терминала:&lt;/p&gt;
&lt;p&gt;watch -n1 -x hidutil property -m ’{“ProductID”:592, “VendorID”:1452}’ —set ’{“UserKeyMapping”:[{“HIDKeyboardModifierMappingSrc”:0x700000035,“HIDKeyboardModifierMappingDst”:0x700000064}]}’&lt;/p&gt;
&lt;p&gt;Това парче код променя картографирането на клавиша Section ( § ), така че да изписва клавиша backquote/tilde ( &lt;code&gt;`/ ~&lt;/code&gt; ).&lt;/p&gt;
&lt;p&gt;Частта &lt;code&gt;watch -n1 -x&lt;/code&gt; го изпълнява всяка секунда, защото понякога macOS обича да губи настройката, обикновено когато компютърът заспи или когато клавиатурата бъде изключена и включена отново.&lt;/p&gt;
&lt;p&gt;Имай предвид, че на някои версии на macOS инструментът &lt;code&gt;watch&lt;/code&gt; не е инсталиран и трябва да се инсталира чрез нещо като &lt;a href=&quot;https://brew.sh/&quot;&gt;Homebrew&lt;/a&gt; или &lt;a href=&quot;https://www.macports.org/&quot;&gt;MacPorts&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Горният код работи с външната клавиатура на Apple с USB и европейска подредба с български букви. Може да се наложи лека корекция на шестнадесетичните стойности на клавишите за други видове клавиатури.&lt;/p&gt;
&lt;p&gt;Вариант на командата работи добре за същия тип клавиатура на самия MacBook Pro. Просто трябва да размените местата на стойностите &lt;code&gt;0x700000035&lt;/code&gt; и &lt;code&gt;0x700000064&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Мислех да напиша инструмент, който да го прави автоматично вместо мен, но в момента смятам, че е по-разумно да инвестирам в нова клавиатура с правилната подредба 🙂&lt;/p&gt;</content:encoded><category>Uncategorized</category></item><item><title>Ресетиране/рестартиране на дистанционното на Apple TV</title><link>https://bisko.be/bg/posts/dev/resetting-restarting-apple-tv-remote/</link><guid isPermaLink="true">https://bisko.be/bg/posts/dev/resetting-restarting-apple-tv-remote/</guid><description>Снощи, докато имахме гости, успях да потопя дистанционното на нашето Apple TV във вода. Липсата на сън и нестабилните чаши водят до инциденти. Дистанционното работеше чудесно снощи, но днес спря. Не реагира на нищо. Опитах да го тропам в дланта си и да изтръскам водата от него. Изобщо не помогна.</description><pubDate>Sun, 17 Feb 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Снощи, докато имахме гости, успях да потопя дистанционното на нашето Apple TV във вода. Липсата на сън и нестабилните чаши водят до инциденти.&lt;/p&gt;
&lt;p&gt;Дистанционното работеше чудесно снощи, но днес спря. Не реагира на никакви действия. Опитах да го тропам в дланта си и да изтръскам водата от него. Изобщо не помогна.&lt;/p&gt;
&lt;p&gt;Решихме, че е свършено, и започнахме да търсим пакета с ориз по шкафовете.&lt;/p&gt;
&lt;p&gt;Влязох в интернет най-вече на шега, за да видя дали мога да опитам да го „рестартирам”.&lt;/p&gt;
&lt;p&gt;Един полезен наръчник ме насочи да натисна и задържа бутоните за увеличаване на звука (Volume Up) и Menu за 2-3 секунди, за да ресетирам дистанционното и да го вкарам в режим на сдвояване.&lt;/p&gt;
&lt;p&gt;Бях наистина изненадан, когато &lt;strong&gt;всъщност проработи&lt;/strong&gt;!&lt;/p&gt;
&lt;p&gt;Така че, ако нещо изглежда съмнително, първо опитайте да ресетирате дистанционното. Ако не помогне, тогава можете да пробвате с ориза и хардуерна интервенция.&lt;/p&gt;
&lt;p&gt;TL;DR;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Задръжте Menu + Volume Up за 2-3 секунди&lt;/li&gt;
&lt;li&gt;Изчакайте няколко секунди&lt;/li&gt;
&lt;li&gt;Опитайте да взаимодействате с Apple TV&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>Apple</category><category>Technology</category><category>AppleTV</category><category>Have you tried turning it off and on again?</category><category>remote</category><category>reset</category><category>restart</category></item></channel></rss>