2025-02-21 разни openfest-овски

February 21st, 2025 by Vasil Kolev

Още се освестявам от FOSDEM, но вече можем да движим някакви неща около OpenFest – имаме си дати (17-18 октомври), имаме разни забавни идеи и малко по малко време да ги правим.

Едното нещо е, че си сменяме системата за submit-ване на лекции към pretalx. След като дълги години изборът беше pentabarf (чиито сайт даже вече го няма) или да си пишем нещо (както имахме clarion за OpenFest), сега вече има нормално работеща система, която CCC и FOSDEM са проходили доста добре, и успява да свърши работа. Тази година ползвах pretalx-а на FOSDEM и бях приятно изненадан колко човешко е като интерфейс и функционалност.

Та, ако на някой му е скучно, сме започнали превод в translate.pretalx.com. Има 1500 неща за превод, от които в последните дни сме превели около 150.
(а няма начин да пуснем системата за самия фест без български без да бъда линчуван)

Има и разни интересни нововъведения за CfP-то и програмата, но тях ще ги разкажа като ги случим :)

FOSDEM 2025 – на български

February 11th, 2025 by Vasil Kolev

Случихме FOSDEM 2025.

Мисля, че това беше събитието, в което наляхме най-много усилия много хора. Получи се много добре (така де, с по-малко проблеми от очакваното)

Нещата започнаха още на предишното издание, където в NOC-а дойде да ни види Martijn Braam и да ни каже “беше ми скучно по едно време и тука си направих аудио миксер със сравнително проста платка и едно Teensy 4 за контролер”…
(пак от при него, нашата версия на миксера и ethernet switch-а)

И се започна нов дизайн на кутията (неофициално версия 2.5). Версия 2 беше една 4-портова мрежова карта на USB със switch в нея, една capture карта, базирана на MS2131 чип (с вграден loop-out) и един USB hub, на който да се закачат. Всичко останало се вършеше от един лаптоп, който ползвахме за encoder, да показва статус и всякакви такива неща.

Планът за новия дизайн беше:
– да махнем лаптопа
– да сложим екран на кутията
– да си спестим всякакъв друг хардуер, съответно
– да си вградим аудио миксер
– да имаме начин да си зареждаме батериите на микрофоните в движение
– (съвсем нагло, не успяхме) да вградим приемник за микрофоните в миксера

Съответно, Martijn и Ангел от наша страна се заеха с дизайн на платки.
(около това аз осъзнах колко мразя хардуера)

Не знам дали мога да разкажа всичко случило се в рамките на годината. Най-лесно е е да се види history-то на video repo-то.

Малко интересни моменти:
cursor.c, нещо малко, което като се preload-не, прави всяко ползване на SDL да крие курсора. Защото иначе ако човек прави с ffmpeg изход към HDMI порта на компютъра, поне в Debian остава един курсор в горния ляв ъгъл (написването и тестването на цялото нещо отне по-малко време от rebuild на ffmpeg, та за това е в такъв вид);
Инструкции за сглобяване, заедно с план за поточна линия/workshop за сглобяване на много кутии от много хора;

Martijn направи много хубаво видео за кутията, и с Ангел я представиха в една от лекциите на FOSDEM, записът вече е качен.

За основен компютър вътре в кутията избрахме Radxa x4. Изискванията ни бяха да е x86-64, да има Intel-ско GPU (защото за тях има mainline support за хардуерен encoding), и да е достъпна/налична. Има един много полезен сайт на Martijn, hackerboards.com, в който човек може да търси каквото компютърче му трябва. Първоначално тествахме с Raxda X2L, но заемаше доста място, и имаше проблем със захранването (оправен в по-новите версии, но все пак). В крайна сметка се оказа, че за подобни пари можем да вземем 110 X4-ки, с вграден eMMC flash и всякакви екстри (вкл. bluetooth/wifi, които не ползвахме), и се спряхме на тях.

Ще отделя малко повече време на историята на вентилаторите, понеже имаше много въпроси защо звучат така. Без да изпадам в подробности, които не разбирам, ситуацията е следната:
– на power board-а си имаме чип, който може да контролира вентилаторите, по документация или със стойност на PWM, или на база обороти;
– контролът на база обороти не работи. След като написах една реализация, която следваше дословно datasheet-а и не свърши никаква работа, отидох да видя source за същото нещо в linux kernel, и се оказа, че и там не го ползват на база обороти;
– поради някакви неща с навързването, чипът може и да поддържа един байт за PWM, но на практика има разлика само при 3-4, при всички останали или спира, или е на максимална скорост;
– Въпреки, че сме купили еднакви, хубави вентилатори, различните стойности на PWM-а имат различен ефект върху тях. Също така, различна температура/влажност в стаята, фаза на луната и т.н. също влияят различно. Което води до това, че понякога вентилаторите спират и трябва да им се вдигне стойността да развъртят, което води до виене;
– Което виене вероятно се чува на прилична част от лекциите;
– Понеже на дъното на кутията имаме 2 мм метална пластина, която го покрива цялото и я ползваме за радиатор, имаше разговор дали да не ги спрем изобщо (понеже по време на тестовете не успяхме да го прегреем), но не ни се рискуваше.

За съжаление, в много от лекциите ще се чува звукът на тези вентилатори. Ако някой измисли филтър да го махнем, да пише…

Металната пластина на дъното се оказа невероятно добра идея. Всичко дойде от там, че ако бяхме следвали стария принцип на закрепяне, трябваше да проектираме и 3d-принтираме много много различни и дребни части, които някакси да закрепим за малкото дупки на кутията многото платки. Идеята да направим една голяма платка отпадна много бързо, понеже две от платките изобщо не бяха правени от нас (Radxa x4 и HDMI capture картата), и щеше да затрудни много процеса на дебъгване и правене на нови ревизии. В един момент си казахме “а защо не просто едно желязо и да завиваме в него”, което почти като страничен ефект се оказа невероятно ефективен радиатор (преди него Radxa x4-ката прегряваше и забиваше в рамките на 10 минути, а Radxa X2L си смъкваше процесора на 500MHz, и обмисляхме всякакви варианти за охлаждане).

Октомври и ноември около други неща бяхме поприключили дизайна, и започна поръчването на всички части. Добрите хора от МиНоЛаб ни услужиха с място, където да струпаме всичко, да можем лесно да товарим и разтоварваме и да сглобяваме. Събрахме части за 70 кутии и организирахме sweatshop по Коледа, в който да ги сглобим, с допълнителна стъпка малко след нова година да инсталираме екраните.
(първоначалният план беше да сглобяваме в initLab, но щеше да ни е трудно да се съберем, и съвсем не ми се мисли как щяхме да носим кашоните с неща нагоре-надолу по ония стълби. За това в initLab беше повечето тестване и разни други разработнически дейности)

Не знам дали мога да обясня какво невероятно преживяване беше сглобяването. 10-15 човека, в дните между Коледа и нова година и после първия weekend на януари, от купчина части и джунджурии направихме 70 работещи, инсталирани и тествани кутии, с които преценихме, че може да се случи FOSDEM (60 за залите и 10 резервни). Ако се бяхме забавили с още една седмица, можеше да направим още, но твърде много приближаваше събитието, и щеше да е сложно да ползваме мястото за сглобяване.

В крайна сметка на 7ми януари успяхме да изпратим всичко към Белгия, и то стигна там след една седмица.
Това беше много на ръба, и бяхме на път да активираме резервния план (който беше да наемем камион и да си го караме ние сами до там, като за крайни случаи можеше да досглобяваме някакви от кутиите в по пътя)

За да се справим изобщо, махнахме следните функционалности:
– loop-out през портовете на Radxa-та, вместо през capture картата. Така щяхме и да можем да показваме нещо различно на екрана, докато няма нищо включено. Основната причина да го няма беше, че не можахме да намерим 110 бр. къси microHDMI-HDMI кабели;
– Да избегнем един кабел и да носим аудиото между двете кутии по мрежата. Подкарах един proof of concept с AES67, но не остана време да го направя production ready;
– Горното беше спряно и от това, че поради някакъв синхронизационен проблем audio mixer-a crash-ва, ако му ползваме USB audio-то. Има няколко идеи за как да го оправим, но сравнително късно намерихме, че причината е една промяна, която го прави да работи на 48KHz вместо на 44.1KHz, и води до разсинхронизация на USB-то и четене на грешна памет;
– Пак заради липса на един кабел и време не довършихме функционалността да може да се пуска звук от презентацията на лектора. В някои зали няма озвучаване, та това нямаше да е полезно, но за други щеше да е, а все повече лектори искат да пускат звук;
– Единият ни USB порт на кутията трябваше да ходи директно в Radxa-та, за да можем да правим разни интересни неща. И за него нямахме подходящ кабел, но и донякъде по-добре, понеже това си е жив backdoor в кутията и не сме доизмислили как някой да не пъхне клавиатура и да почне да прави мизерии…

Но, имахме цялата функционалност от предишни години, заедно с аудио миксер, който беше вграден (едно нещо по-малко за носене), и чиито нива можеше да следим в реално време и да променяме, когато се налага (без да трябва да пращаме някой на място). Като допълнителен бонус, не можеше random хора да променят настройките по звука, понеже кутията копчета няма :). Изобщо, аудио миксера и нещата около него заслужават отделен post, който Алберт (който написа повечето код) написа :)

В последната седмица успях да оправя още няколко неща, като да имаме и 480p stream (не само за хората на гаден DSL, но за хората на Wi-Fi в самия университет, които не успяваха да влязат в залите).

И така, започнахме FOSDEM 2025 с хардуер, приготвен преди 3 седмици, с известни проблеми и не-достатъчно-тестван. Ако имахме толкова проблеми, колкото очаквах, щях да използвам цялата тая история като пример за децата ми какво да не правят.
Отидохме около 30 човека от България, и бяхме голямата част на видео екипа. Въпреки всичките ми планове да съберем доброволци от други места, не ми се получи – успях да направя един online инструктаж точно една седмица преди FOSDEM, а нямах как по-рано (поради приключването на сглобяването в началото на януари, след което се разболях така, че все още кашлям). Надеждата ми е, след като сглобим останалите кутии, да видим дали разни hackerspace-ове няма да им харесат (щото с тях може да се правят доста интересни неща) и така да съберем още желаещи.

Имахме учудващо малко проблеми.

Основният ни проблем дойде от известния проблем с memory leak-овете на Voctomix – бяхме планирали да мигрираме към Voc2mix, който беше release-нат лятото, но не ни остана време да го преборим (той щеше да ни даде и още възможности, като например повече от 2 аудио канала и съответно начин да носим backup аудио). Това доведе до дупки в някои лекции, и за догодина има няколко идеи как да се оправи.

Другият по-често срещан проблем (3-4 пъти) беше, че определен входен сигнал в capture картата успява да я ошашка, и да и спре loop out-а. Не е ясно защо е, нямаме source на firmware и не можем да намерим документация на чипа (Macrosilicon MS2131, ако на някой му се намира, няма да откажа).
(има предположение, че определени macbook M1-та го правят това с побъркването на capture картата, накрая ще вземем да ги забраним)

Иначе ни отказаха една-две платки, спря тока в една зала, нищо не се наводни, въпреки забавяния заради вдигането на мрежата в петък бяхме готови в сравнително нормално време, та да си легнем навреме, и разглобяването приключи също достатъчно спокойно, че да може всички да хапнат нормално.

Успяхме дори да пренапишем начина за визуализация на нивата на звука (разделихме двата канала), с изнасяне на цялото смятане на нивата в отделна машина и база (за да освободим процесорно време на видео миксерите).

А аз направих грешката в събота вечер да ида на едната вечеря, която доста се проточи и заедно с умората от всичко останало доведе до там, че трябваше да седна и подремна някъде неделя следобед. Или съм изгубил форма, или просто не успях да се възстановя от боледуването…

Накрая дадохме назаем 2 кутии и един mixing laptop на FOSSASIA, има шанс да ги ползват скоро :)

От новите неща тази година – наслагахме стационарни телефони по VOC-овете и на разни други места, да видим как ще се получи. Закачихме и малко мобилни телефони на SIP към същата централа, за който желаеше. Експериментът беше успешен, ползваха се прилично (и вече има желаещи да има на още места). Може дори донякъде да заместят walkie-talkie-тата (дето още не мога да ги заобичам).

За самия FOSDEM не мога да кажа много – пак беше голяма лудница и пълно с хора, доколкото знам тази година доста по-добре са поддържали залите да не се препълнят. За мен най-интересното беше отделният “junior” track, за деца да ходят на workshop-и и да им разказват полезни неща. Това е нещо, което при нас май в момента го няма (едно време hackconf беше ориентиран към ученици, ама вече го няма), и би било хубаво да се появи.

И да завърша с една голяма благодарност към всички доброволци, които помогнаха и не ме удушиха (понеже цялото упражнение никак не беше леко) – без вас това нямаше шанс да се случи, та много много много благодаря. И ще се радвам да се включите пак догодина :)

FOSDEM 2025 – in English

February 11th, 2025 by Vasil Kolev

We did FOSDEM 2025.

I think this was the event where we put the most effort into by the most people. It went very well (or, well, with less problems than expected)

Things started at the previous edition, where Martijn Braam came to see us at the NOC and said “I was bored at one point and I made an audio mixer with a relatively simple board and a Teensy 4 as a controller”…

(also from his blog, our version of the mixer and the Ethernet switch)

So a new design of the box began (unofficially version 2.5). Version 2 was a 4-port USB network card with a switch in it, a capture card based on the MS2131 chip (with built-in loop-out) and a USB hub to hook them up to. Everything else was done from a laptop that we used as an encoder, to show status and all that sort of stuff.

The plan for the new design was:
– to remove the laptop
– to put a screen on the box
– to save on any other hardware, respectively
– to build an audio mixer
– to have a way to charge the microphone batteries on the go
– (quite brazenly, bit it failed) to build a receiver for the microphones in the mixer

Accordingly, Martijn and Angel from our side started designing the boards.
(this is where I realized how much I hate hardware)

I don’t know if I can tell you everything that happened within the year. The easiest way is to look at the history of the video repo.

A few interesting points:
cursor.c, a small thing that, when preloaded, makes every use of SDL hide the cursor. Because otherwise, if you output to the HDMI port of the computer with ffmpeg, at least in Debian there is a cursor in the upper left corner (writing and testing the whole thing took less time than rebuilding ffmpeg, so that’s why it’s like this);
Assembly instructions, along with a plan for a production line/workshop for assembling many boxes by many people;

Martijn made a very nice video about the box, and with Angel they presented it in one of the FOSDEM talks, the recording is already uploaded.

For the main computer inside the box we chose a Radxa x4. Our requirements were that it be x86-64, have an Intel GPU (because they have mainline support for hardware encoding), and be affordable/available. There is a very useful site by Martijn, hackerboards.com, where you can search for any computer you need. Initially we tested with Raxda X2L, but it took up a lot of space, and there was a problem with the power supply (fixed in newer versions, but still). In the end, it turned out that for a similar amount of money we could get 110 X4s, with built-in eMMC flash and all sorts of extras (including bluetooth/wifi, which we didn’t use), and we settled on them.

I’ll spend a little more time on the history of the fans, because there were a lot of questions about why they sound like that. Without going into details that I don’t understand, the situation is as follows:
– on the power board we have a chip that can control the fans, according to the documentation either with a PWM value or based on RPM;
– the RPM-based control doesn’t work. After I wrote an implementation that followed the datasheet verbatim and didn’t do anything, I went to see the source for the same thing in the Linux kernel, and it turned out that they don’t use it based on RPM there either;
– due to some details with the wiring, the chip can support one byte for PWM, but in practice there is only a difference at 3-4, with all the others it either stalls or is at maximum speed;
– Although we bought the same, nice fans, different PWM values have different effects on them. Also, different temperature/humidity in the room, moon phase, etc. also have different effects. Which leads to the fact that sometimes the fans stop and their value has to be increased to spin, which leads to whining;
– Which whine is probably heard in a decent part of the lectures;
– Since we have a 2 mm metal plate on the bottom of the case that covers the whole case and we use it as a radiator, there was a discussion about whether to stop them altogether (because during the tests we were not able to overheat it), but we didn’t feel like taking the risk.

Unfortunately, the sound of these fans will be heard in many of the lectures. If someone comes up with a filter to remove it, please send it to us…

The metal plate on the bottom turned out to be an incredibly good idea. It all came from the fact that if we had followed the old principle of fastening, we would have had to design many different and small parts to be 3D-printed, which we can somehow attach to the few holes of the case so they can hold all the boards. The idea of making one big board was dropped very quickly, because two of the boards were not made by us at all (Radxa x4 and HDMI capture card), and it would have made the process of debugging and making new revisions very difficult. At one point we said to ourselves “why not just make one piece of iron and screw it in”, which almost as a side effect turned out to be an incredibly effective radiator (before that, the Radxa x4 would overheat and crash within 10 minutes, and the Radxa X2L would throttle its processor to 500MHz, and we were considering all sorts of cooling options).

In October and November, we had finished the design and started ordering all the parts. The good people at MinoLab provided us with a place to get all the pieces, so we could easily load and unload and assemble. We built 70 boxes out of parts we had by organizing a sweatshop at Christmas to assemble them, with an additional step shortly after the new year to install the screens.
(the original plan was to assemble at initLab, but it would have been difficult for us to fit there, and I can’t imagine how we would have carried the boxes of stuff up and down those stairs. That’s why most of the testing and various other development activities were at initLab)

I don’t know if I can explain what an incredible experience the assembly was. In the days between Christmas and New Year and then the first weekend of January, 10-15 people made 70 working, installed and tested boxes from a pile of parts and gadgets we had. We estimated that FOSDEM could happen with that many (60 for the rooms and 10 spare). If we had delayed another week, we could have built more, but the event was getting too close, and it would have been complicated to use the assembly site.

In the end, on January 7th we managed to send everything to Belgium, and it arrived there a week later.
This was very much on the verge, and we were about to activate the backup plan (which was to rent a truck and drive it there ourselves, and in extreme cases we could assemble some of the boxes on the way, in the back of the truck)

To be able to have something working, we removed the following functionalities:
– loop-out through the Radxa HDMI ports, instead of through the capture card. This way we could show something different on the screen while nothing was on. The main reason it wasn’t there was that we couldn’t find 110 pcs of short microHDMI-HDMI cables;
– To avoid one cable and carry the audio between the two boxes over the network. I ran a proof of concept with AES67, but there was no time left to make it production ready;
– The above was also stopped by the fact that due to some synchronization problem the audio mixer crashes if we use USB audio on it. There are several ideas on how to fix it, but relatively late we found that the cause was a change that makes it work at 48KHz instead of 44.1KHz, and that leads to USB desynchronization and reading the wrong memory;
– Again due to the lack of one cable and time we didn’t finish the functionality to be able to play sound from the lecturer’s presentation. Some rooms don’t have sound, so this wouldn’t be useful, but for others it would be, and more and more lecturers want to play sound these days;
– One of the USB ports on the box had to go directly to the Radxa, so we could do some interesting things. We didn’t have a suitable cable for it, but it was the better thing to do, because this is a live backdoor into the box and we haven’t figured out how to prevent someone from sticking a keyboard in and starting to make trouble…

But, we had all the functionality from previous years, along with an audio mixer that was built in (one less thing to carry), and whose levels we could monitor in real time and change when necessary (without having to send someone in the room). As an added bonus, random people couldn’t change the sound settings, because the box doesn’t have any controls :). In general, the audio mixer and things around it deserve a separate post, which Albert (who wrote most of the code) wrote :)

In the last week I managed to fix a few more things, like having a 480p stream (not only for people on crappy DSL, but for people on Wi-Fi at the university itself, who couldn’t get into the rooms).

So, we started FOSDEM 2025 with hardware that was prepared 3 weeks ago, with some problems and not-tested-enough. If we had as many problems as I expected, I would use this whole story as an example for my children of what not to do.
About 30 of us went from Bulgaria, and we were the majority of the video team. Despite all my plans to gather volunteers from other places, it didn’t work out – I managed to do an online briefing exactly one week before FOSDEM, and I couldn’t do it any earlier (due to the assembly finishing in early January, after which I got so sick that I’m still coughing). My hope is that after we assemble the rest of the boxes, we can see if various hackerspaces won’t like them (because you can do some interesting things with them) and that way we would gather more people who want to play with them and help at FOSDEM.

We had surprisingly few problems.

Our main problem came from the famous problem with Voctomix memory leaks – we had planned to migrate to Voc2mix, which was released in the summer, but we didn’t have time to test and integrate it (it would have given us more options, such as more than 2 audio channels and a way to carry backup audio). This led to holes in some lectures, and for next year there are a few ideas on how to fix it.

The other more common problem (3-4 times) was that a certain input signal in the capture card manages to screw it up and stop its loop out. It’s not clear why, we don’t have the firmware source and we can’t find documentation for the chip (Macrosilicon MS2131, if anyone has it, I won’t refuse).
(there is an assumption that certain macbook M1s do this with the capture card going crazy, eventually we will ban them)

Otherwise, a couple of boards died, the power went out in one room, nothing flooded, despite delays due to the network being deployed on Friday, we were ready at a relatively normal time, so we could go to bed on time, and the tear-down was also completed calmly enough so that everyone could eat normally.

We even managed to rewrite the way to visualize the sound levels (we separated the two channels), by moving the entire calculation of the levels to a separate machine and database (to free up processor time for the video mixers).

And I made the mistake on Saturday night of going to the staff dinner, which dragged on for a long time and, together with the fatigue from everything else, led to the fact that I had to sit down and take a nap somewhere on Sunday afternoon. Either I’ve lost my form, or I just haven’t been able to recover from my illness…

We also lent 2 boxes and a mixing laptop to FOSSASIA, there’s a chance they’ll use them soon :)

Some of the new things this year – we’ve been putting fixed phones on the VOCs and in various other places, to see if they’d help. We also hooked up some SIP mobile phones to the same PBX, for those who wanted them. The experiment was a success, they were used quite a bit (and there are already people who want them in more places). They might even replace walkie-talkies to some extent (which I still can’t get used to).

I can’t say much about FOSDEM itself – it was still very large and full of people, but as far as I know this year they’ve kept the rooms from getting crowded much better. For me, the most interesting thing was the separate “junior” track, for kids to go to workshops and be shown useful things. This is something that seems to be missing here in Bulgaria (hackconf used to be student-oriented, but it’s gone now), and it would be nice if it re-appeared.

And to end with a big thank you to all the volunteers who helped and didn’t strangle me (because the whole exercise wasn’t easy at all) – without you this wouldn’t have had a chance to happen, so thank you very much. And I’d be happy if you joined again next year :)

2024-12-30 равносметъчно

December 30th, 2024 by Vasil Kolev

Равносметъчно…

(гледайки архива, съм нямал очаквания за тая година. Изглежда е било правилно, щото нямаше шанс да позная доста от нещата…)

– Децата, as usual, продължават да растат. Понеже гледането на деца в София е леко екстремно преживяване, започнаха училище в Бургас (където им намерихме едно много добро такова);
– Успяхме да случим FOSDEM 2024. Така и не написах нещо по темата, но вероятно ще напиша за следващия, понеже
– По-голямата част от годината се занимаваме да направим следващия revision на video-box-а на FOSDEM. Което води до много занимавания с хардуер и последно три дни сглобяване, на който му е интересно може да разгледа в repo-то. Ще гледам да го разпиша по-подробно като сме готови;
– Случи се OpenFest 2024, в който нямах участие, и в който някаква прилична част от екипа се разпадна. В момента съм се върнал и подреждам нещата (има събран core, говорено с малко спонсори, и даже дати – 18 и 19 октомври в техпарка). Знаех в какво се забърквам, знам, че не е ясно дали трябваше да си го причинявам и не можах да оставя така нещата;
– Това с OpenFest беше половината причина да напиша лекция тая година, този път за екипи. Ще ми се следващата ми лекция да е за нещо техническо, че имам поне 3 идеи;
– Работата си е интересна и много (както обикновено). Тази година успях да си напълня екипа и сега си правим малка реорганизация;
– И последното, chervarium почина по-миналата седмица. Мислим на 8ми януари на ИББ да го полеем прощално…

Да видим 2025.

2024-12-20 почивай в мир, chervarium

December 20th, 2024 by Vasil Kolev

Снощи е починал Атанас Бъчваров (който повечето хора познават като chervarium).

Още нямам информация за кога ще бъде погребението и какво са плановете там, ако е ок, ще пиша тук.

И бих искал да напиша още нещо по темата, но ще изчака…

Update: погребението е в неделя, 22.12, от 13:30 в Ямбол (на гробищата)

2024-11-03 лекция “Екипи” на OpenFest 2024

November 3rd, 2024 by Vasil Kolev


Преди известно време NSA разсекретиха лекция, която (по това време капитан, после адмирал) Grace Hopper изнесла при тях през 1982 година. В тази лекция има много интересни неща и я препоръчвам на всички да я изгледат, но една част от нея ме побутна да направя моята.
(всички, които гледат лекцията почват да искат да имат баба като нея)

(ако някой не знае коя е Grace Hopper, силно препоръчвам да се се зарови)

Явно се сблъска в главата ми с много други неща, свързани с “мениджмънт”, “човешки ресурси”, “модерно робство” (за мен термина “човешки ресурси” е наследство от времената, когато робството е било нормално. Честно казано, даже очаквах да намеря някой римски термин като “Homo subjecto” (човекопредметност), на който да е наследство).

Та поне аз имам нужда да разкажа какво знам за правенето на екипи, поддръжката им, работата с тях. Вижда ми се много по-важно от всякаква техническа тема, на която бих могъл да говоря в момента, и съм зарязал поне три такива полунаписани лекции, за да направя тази.

Нещата толкова се бяха събрали в главата ми, че една вечер, след като спешно трябваше да стана да оправя нещо, вместо пак да си легна отделих един час и написах подробен план на лекцията. Това, което ще разказвам, не се отклонява особено от него.

Тази лекция събира опита ми от последните двайсетина години с някакво количество книги, изчетени по темата. Опитът ми е от различни фирми (последната е StorPool), и доброволчески организации като OpenFest, FOSDEM, IT турнето и разни други.

Този въпрос го има и накрая.

Въпреки, че много повече предпочитам да се занимавам със сървъри, мрежи и машини, никога не съм успявал да се измъкна от човешкия елемент. И колкото да ми е уморителен, с годините съм приел, че е сравнимо важен с всичко останало, което правят.

Едно от нещата, които ми е липсваше в университета (и което се стараех по някакви начини да вкарвам в преподаването си там) бяха екипни проекти. Възможно е това, че аз съм бил три години втори курс да ме е спряло да открия, че всъщност се преподава екипност, но и на разглеждане на конспекта такива неща няма – всички изпити, контролни и други подобни забавления са индивидуални. Единственото отборно нещо, в което съм участвал беше едно състезание по програмиране.

HR отделите това им е част от работата, но в повечето случаи не им се получава. Всички екипи, които съм виждал са супер подозрително настроени към всякакви подобни инициативи.

Също така, много ще се радвам, ако след лекцията хората ми кажат, че това са неща, дето се знаят и съм и загубил времето.

Малко spoiler alert за какво ще говоря – за как се събира екип, за какви хора бихте искали и каква култура, как може да работи, и как се поддържа.

Този слайд го има основно, за да си изяснят хората дали ще им е интересна лекцията, и да ходят да пият/пушат отвън, ако не :)

Малко източници, на които съм се базирал.

Астронавтите и изобщо космическите пътувания са много добър пример за начин на работа на малки и големи екипи с критични системи. Информацията е публична, намира се лесно, и чак е трудно да избягаш от нея.

Военните организации са друг интересен пример. Теорията им съществуват от много отдавна, и при тях доста от лошите идеи са отмрели (понякога съвсем буквално). Доста от техните идеи са неприложими извън тяхната сфера (например принципите им за team building са незаконни), но има и много полезни неща.

За системите от хора (т.е. организации) има също написано много, ще се появява на разни места из лекцията.

И накрая, художествената литература. Правил съм цяла отделна лекция за това колко е полезна, тук само ще отбележа, че популярната такава показва какво хората очакват и би им се харесало в реалния свят. Описанията на добрите лидери, с които сме свикнали от малки идват основно от там – те ни дават очакванията към лидерие и границите, до които могат да се нарушат.

Да започнем с това как се събират правилните хора.

Виждал съм и познавам хора, които са или водещи екип, или важна част от него, но отказват да се занимават с взимането на хора в него. Считат го за скучна, второстепенна или направо ненужна част. Има и фирми, в които самите екипи почти нямат право на глас кой влиза в тях.
И двете не са правилни, съответно силно ги препоръчвам на всичките ни конкуренти.

Хората, с които работите определят дали ще си свършвате работата, дали ще ви харесва, или сутрин ще трябва да си разреждате кафето с нещо по-спиртно, за да може да понесете деня.
(Личен съвет – ако откриете, че започвате да си сипвате алкохол от сутринта, за да може да си вършите работата, е време да напуснете. Както и ако в понеделник сутрин ви става лошо при мисълта, че трябва да ходите на работа)

На повечето места, на които съм работил съм имал участие в процеса на наемане, а в последните няколко и изрично съм държал да участвам. Вече не ми се налага да пия сутрин :)

Ще базирам тази част основно на какво правим в StorPool, но доста неща са подобни и при търсенето на доброволци, и твърдя, че са приложими за повечето IT специалности.

В StorPool ни отне време да изгладим процеса (и сигурно има неща, които допълнително можем да подобрим). Това не стана без да направим едно количество грешки.

Първия път пуснахме обява по нормалния начин, видяхме 20-30 CV-та, от тях избрахме 10 по някакъв начин, и ги поканихме на интервюта.
След като приключихме с тях (отне около седмица), седнахме, поговорихме и си казахме “NEVER AGAIN”. Обърнахме процеса, като сега първо пращаме на кандидата задачи, и след и ако реши някаква част от тях, каним на интервю.

CV-тата на хората дават идея за какво да си говориш с тях. От там нататък стойността им не е особено голяма – хората лъжат, доста често ненарочно, и разликата между двама човека със същото CV може да е от земята до небето. А интервю с грешния вид човек е изпитание и уморително упражнение, което спокойно може да се пропусне.

Единствения човек, който се радваше на този тип интервюта беше жена ми, която много се забавляваше на историите от тях. Или, както е казал народът, на чужд гръб и сто интервюта са малко.

Та, един ден седнах и насъбрах задачи. Спомних си някакво количество проблеми, с които съм се борил и които са ми останали в главата, малкото код или други неща около тях, и сглобих нещо, което лесно да даваме на хората да решават.
Това, че съм ги запомнил има и друго предимство – че вероятно са интересни. Ако карам някого да ми отдели някакво време, е добре да не е с нещо скучно :)

Важно е задачите да са реални. Това има допълнителния момент, че кандидатът може да разпознае неща, с които се е борил и да разбере, че не е сам :)

И разбира се, трябва някакво разнообразие, не може да дадем същата задача 5 пъти с различни параметри. Най-малко никъде работата няма такова нещо.

Задачите са прекрасен филтър.
Има хора, които изобщо отказват да обърнат внимание, защото смятат, че са над такива неща. Има хора, които не намират подобни неща за интересни. Има такива, които не могат да решат нищо от тях. И наскоро дори имаше случай “не смятам, че някога в реалната работа ще ми се наложи да правят A и B (неща от задачите).

Последният не е прав, а всичките други групи са хора, които не бих искал в екипа си.

Кратко отклонение за типа хора, с които искам да работя, понеже идеята със задачите е много дискриминираща спрямо останалите.

Смятам, че човек трябва да се занимава с неща, които му харесват. Може би не всички детайли, но основната част от работата, генералната цел и каквото се постига, трябва да са нещо, което ти харесва. Животът е твърде кратък, за да се занимаваш с глупости.

Това, освен че прави целия процес на работа по-приятен, води и до това, че се работи с по-кадърни хора. Колкото повече ти харесва нещо, толкова повече влагаш усилия и се занимаваш с него и ставаш по-добър (всички сме чували за 10те хиляди часа).

И разбира се, ако хората им харесва, няма да искат да си тръгнат. Достатъчно често попадам на случаи, в които хората искат да напуснат и да идат някъде дори на по-ниска заплата. От друга страна пък, никога няма да забравя как се опитвахме да подмамим при нас Боби Станимиров. Бяхме го завели на обяд в едно много приятно заведение, говорехме си, обяснявахме колко интересни неща правим, и той в един момент каза “Да, вашето е интересно. Ама при нас лекуваме рак.”
(той тогава беше във viewray, те правят комбинация от ядрено-магнитен резонанс и гама-нож, т.е. докторите могат да гледат докато режат с гама ножа)

Да си харесваш работата всъщност не е толкова рядко, а хората харесват какви ли не работи. Може би най-простия пример, който имам е как хора ходят, учат във ФМИ и вместо да след това да работят за много пари в IT-то, стават учители – професия, която (да цитирам един мой любим сериал) комбинира стреса на неврохируг със заплащането на продавач в магазин.
Шапка им свалям на тези хора, аз не бих могъл.

(или всички доктори)

Слайдът, разбира се, може да се чете като “отклонение е да си харесвате работата”. И такива отклонения трябват :)

Благодаря, че ми намериха този графит, който беше написан едно време, мисля на ул. “Париж”, и който е донякъде крайната фаза на харесването на работата и мотивираността. Поне според мен, човек трябва да може сутрин да си отговаря на този въпрос или с “да”, или с “ще направя нещо, че отговорът да е ‘да'”.
(предполагам не е полезно да мислиш за умиране всяка сутрин, та може да бъде разредено кога се преосмисля, но принципът си остава :) )

Чудил съм се понякога колко е наемът на един билборд на Орлов мост, за да сложим този надпис да постои там известно време.

Човек и добре да живее, трябва да си говори с други хора. Процес на наемане без интервюта няма как да се направи.

Виждал съм различни варианти на интервюта. Може би най-любимото ми беше в google, където им бях на гости за един ден, сложиха ме в една стая и различни екипни lead-ове ме разпитваха в продължение на около 5-6 часа.
(може би заради това Дъблин ми стана другия любим град след София)

Това идва тежко за доста хора, и е отделяне на много време с неясно каква полезност. При нас базовото техническо интервю е едно, с двама-трима човека от наша страна. Имаме няколко области, в които задаваме въпроси, като цяло съвсем стандартно.
Различното е, че цялото интервю започва с обясняване кои сме ние, какво правим и каква е работата. През целия процес на интервюто идеята е не само ние да научим нещо (за кандидата, или като цяло), но това да се случи и за отсрещната страна. Всяко интервю трябва да е полезно и за двете страни, и да помогне за отговора дали наистина искат да работят заедно.

После срещаме човека с целия екип, с който ще работи. Всеки има право да знае в какво се забърква, а и помага да видиш, че ще работиш в компания на сродни души (или ужасни изроди и по-добре да бягаш надалеч).
След срещата на целия екип въпросът, който си задаваме е “Кажете нещо лошо за човека”. Ще го спомена по-долу, но да почна от тук, решението за нов човек се взема с консенсус – всички от екипа участват във взимането на решението и трябва да са съгласи за новия член. Тези интервюта са едно от много малкото неща, за които занимаваме хора, излезли в отпуска.

И има едно “човешко” интервю (все ми се карат, като го наричам така, та приетия термин е “не-техническо”). Целта му е да хване проблеми с човека, които ние не сме видели.

Всички преди изпитателния срок е филтър, който да намали хората, провалящи се в него. А самият изпитателен срок е правилният показател дали може да се работи с някого.

Един от любимите ми процеси за интервюиране беше в Automattic – там имаше едно-две интервюта, и после директно едномесечен договор, в рамките на който ти дават достъп, правиш задачи с разни хора за разни цели (истински задачи, има шанс едно от нещата дето правих да са го ползвали прилично време) и двете страни могат да видят как изглежда работата и вписването на новия човек. Завиждам на фирмите с достатъчно ресурс, които могат да го правят.

Учудващо, разликите в доброволческите организации са основно в реда на случващото се. Много често доброволците директно почват с един изпитателен срок, преди да навлязат повече в организацията :)

Практически обаче, има горе-долу същите стъпки и действия, за да стане някой част от доброволческа организация – да свърши нещо, да се срещене с някакви основни хора, и после с всички, и да работи с тях известно време. На практика много от доброволците минават като първа стъпка нещото със “задачите”, понеже идват един ден и някой им казва “свърши това” :)

Това е като продължение на частта с типа хора, който искаш.

За да работи един екип, трябва да съществува в добра среда. Среда, която насърчава правилните неща, не толерира вредните, и дава възможност на хората да се развиват и да работят.

Културата е нещо, което съществува в екипа, но трябва да е подкрепено на всяко едно ниво.

И понеже това е някакво вятърничаво като обяснение, ето конкретни примери.

Един пример, който ще дам, е FOSDEM и open-source решенията. Видеото на FOSDEM винаги е било с open-source решения, доколкото е възможно, и когато е имало възможност да се направи още нещо отворено, като например смяната на един capture device с друг, това винаги е било подкрепяно от цялата организация, въпреки отражението върху бюджета на събитието. Това винаги е важало и за всичко, което се ползва – ако има възможност, се прави с open-source софтуер, ако ще и самата организация да си го напише, без възражения от типа “не можем ли да ползваме онова готовото и да не се занимаваме”.

Друг пример – за нещо, което не осъзнавах, че е добре да се формализира – е т.нар. blameless postmortem. Идеята е следната – ако се случи грешка, която да доведе до сериозни последствия (в нашия случай – downtime), се пише postmortem документ, който описва как се е случило събитието, какво е довело до него, и какво може да се направи, за да не се случва пак.
Blameless частта е, че вместо да кажем “Пешо пипна там и то се счупи, та ще му хвърлим един бой”, се прави по-трудното – изяснява се процеса, грешката и как да не се стигне пак до там. Така се правят по-малко грешки, и не се стига до там, че хората не смеят да правят нищо, за да не пострадат.
(и това е обратно на културата на твърде много места, които съм виждал)

Свързано с това по-горе, културата трябва да приема, че грешките са нещо възможно, и че са някаква част от learning процеса. Щом това успяват да го приемат в области като медицината и воденето на война (USMC имат изрично записано, че “there must be no ‘zero defects’ mentality”), където заради грешки умират хора, не мисля, че и в IT-то не може да се приложи.

Също така, одобено доброволческите организации трябва и осигуряват възможности за развитие, да можеш да смениш екипа, да видиш нещо от друга гледна точка, и да можеш да разнообразиш. [да се допише]

Това си мисля, че е познато на всички. Ще се връщам към него, но просто ще кажа, че всеки в един екип трябва да може да е Бай Иван, без значение позицията.

Съвсем дискриминационно ще кажа, че има правилни и неправилни хора, с които да работиш.

Правилните хора не ги е страх от работата. Както отбелязах, тя трябва да им харесва, да ги забавлява, да не им е лошо сутрин като трябва да ходят на работа и т.н.. И когато има да се свърши нещо, да могат да хванат лопатата.

Има много изписано и изговорено на темата как се мотивират хора. Преди години един колега беше попаднал на статия, която възприехме, и която казваше, че ако хората не се мотивират сами, то насила няма как да се получи добър резултат.
(“насила админ не става”)

Аз не мисля, че мога да мотивирам някой, който не би могъл да се мотивира сам (и определено не искам). Мога да покажа работата, да обясня какво е интересното, какви неща никъде другаде не правят (или в случая на доброволчеството – какво постигаме), но всичко това е безсмислено, ако човекът не е достатъчно self-driven, за да може сам да се мотивира и да се движи напред.

И да натъртя още веднъж идеята, ще дам пример за едно обяснение към студенти, как по партита като се забиват с някой от подходящия пол, преди секс да не търсят “consent”, а “entusiasm”.

При доброволците има важен момент, който следва от предното. За да си харесваш работата и да си достатъчно желаещ да се занимаваш с нея (особено за без пари), трябва да го припознаеш като нещо свое. И това е едно от най-важните неща в подобни организации – да събере хора с обща цел, които приемат целите на организацията за свои.

Това води до друго важно нещо, възможността за изграждане на автономност в хората. Ако всички знаят целта и насоката, ако са запознати с цялостната работа на организацията, то те могат да вършат повечето си работа без да занимават някой друг, и да направят организацията много по-ефективна.

Така и обратната връзка не се приема като нещо лошо, а като нещо, което помага да се движите напред. Екипът не трябва да има страх да каже на някой “моткаш се” или “това е грешно”, какото и всеки в екипа трябва да е ок с подобен feedback. Ако сме се подбрали правилно, нищо от това не е с цел да тормози другия, а с цел да си свършим работата.

Та може би поговоркара за сговорната дружина може да е “дружина с обща осъзната цел планина повдига”, понеже съм го виждал в действие :)

Крис Хадфийлд, който първо ми беше познат от една глава на “How to” (на темата “как да приземим космическата совалка на различни странни места”) има една глава в книгата си “An astornaut’s guide to life on Earth”, в която обяснява какво е правилното нещо, към което да се стремиш да си в един екип. Отговорът му е, че винаги поне трябва да си на нула, т.е. да поддържаш нивото на работа на екипа.

Това е нещо, което е трудно за разбиране. Много хора смятат, че могат от първия ден да направят промени, които да подобрят екипа, работата, да им помогнат да се изтъкнат и т.н. После бързо се обезкуражават след сблъсъка с реалността – понеже за всяко нещо в една организация си има причини, и те трябва да бъдат адресирани, преди да се направи някаква (може би голяма) промяна в начина на работа.
(това не променя факта, че е важно да се проявява инициатива и да се подобрява работата на всички)

Това е и истинската дефиниция на “екипен” човек за мен. Като пример как не се прави, ще дам скорошната случка, в която maintainer-а на Rust за linux kernel-а се отказа да се занимава, защото му било омръзнало да го занимават с “нетехнически” проблеми. Което показва колко заблуден е бил, щом е очаквал, че проблемите му ще са само такива – цялото това нещо, което се опитва да направи е като да накара ламята Спаска да танцува балет. И колкото да обяснява колко гениален е тоя балет, има много други подробности, преди това да има шанс да се случи.

Изобщо по темата за убеждаването на хората и прокарването на идеи, препоръчвам лекцията на Грейс Хопър, която споменах в началото. Тя обяснява за добри начини за постигане на промени в подобни обстоятелства (тя все пак е работела за department of defense и други подобни гигантски структури).

Иначе, имало е доста странни въпроси по интервюта, които са ми помогнали да изчистя моето очакване за какво е екипност и какво всъщност очакват хората. Най-странния въпрос, който са ми задавали беше дали сме повече adversarial или cooperative – което за мен беше невероятно, понеже никога не съм бил/очаквал някой такъв екип да е adversarial и хората да се състезават, вместо да си помагат. Предполагам, някъде има приложение, но поне за мен не е в рамките на една организация, която се опитва да върши работа.

Понеже до тук говорих за общите неща в хората, извън тях, останалото няма значение. В разните екипи, в които съм бил и са били ефективни е имало хора от всякаквите възможни части на обществото, по всякакви признаци, и това определено помага да се избегне groupthink-а (или поне да се намали). Дори в текущия ми екип, който на практика е само системни администратори, има следните под-видове хора: бивши военни, тонрежисьори, готвачи, заварчици и т.н.. Ако попаднем на необитаем остров, няма да ни е скучно, няма да умрем от глад и сигурно ще намерим начин да се измъкнем…

А последния link – ако не сте го чели, отделете му 20 минути. Той обяснява колко бързо свикват хората с глупостите в една организация. Заради него ние правим едно post-onboarding интервю с всеки нов човек, горе-долу на втория месец, в което сядаме и започваме да задаваме въпроси от типа “сега, докато още не си свикнал с нашите глупости, кажи какво не ти се вижда вярно”. Силно препоръчвам и като четиво и като практика.
(в началото имаше доста моменти в тези разговори, в които си казвах “а, ама и аз имах проблем с това, и то все още не е правилно”)

И така, имаме правилните хора, как да работим с тях? Има някои важни неща, особено в подобен екип, които трябва да бъдат взимани предвид, за да може да се работи гладко и най-вече – правилно.

Едно от нещата, които се откриват по трудния начин е какъв е работещия начин за взимане на решения в един екип и каква е ролята на водещия екипа в тях.

Има една идея (срещана и в много вицове), че решенията идват отгоре и толкова. Това е грешно по две причини – губи се полезния опит на членовете на екипа (които сме ги избирали да са умни хора), и защото така има приличен шанс екипът да няма желание да ги изпълнява – понеже не може да ги разбере, не мога да види, че водят до нещо смислено и може би просто от инат.

Това, което работи най-добре е да се изговори даден проблем и да се стигне до консенсус. За някои неща това е единственото правилно решение (например наемането на нови хора в екипа), въпреки времето, което може да отнеме. Понякога има подобен вариант с rough consensus (който го има разписан в IETF документите), който казва, че в общи линии сме съгласни с някакви резервации, но да действаме е по-добрия вариант, отколкото да продължим да го дъвчем.

И ролята на водещия екипа в такива дискусии (освен нормалното участие) е да сумаризира и да отпушва дискусията, когато забие в някоя ненужна посока. Формално накрая може да произнесе решението и да носи отговорност за него, но то на практика трябва да идва от екипа.

Понякога консенсус не се получава – опциите са много, мненията са различни, има нужда да си подредим по предпочитаност някакви опции. В такива случаи може да се прибегне до някакво гласуване, като обаче е важно да сме наясно с изборите, и как точно избираме. Темата за системите за гласуване е много обширна и няма да се спирам на нея, но препоръчвам на всички да се запознаят с модифицирания Condorcet метод, който се ползва в Debian проекта.

А в някои случаи (по-често срещани в доброволческите организации), под-група казва “това ние можем да го случим и поемаме отговорност”, и това е решението. Това пак помага на организацията да се движи напред и да си върши работата, вместо само да отлага и да не прави нищо.

За да може да се случи последното, трябва правилната култура, за която ще говоря надолу.

Между другото, учудващо е колко голяма част от тези два слайда се среща по книгите за военни организации и колко важно е да се изслушат/събере информация от всички (от които е възможно във времевите ограничения). Повечето очаквания от такива организации е, че всичко се спуска отгоре, но практиката (и текущата литература по въпроса) говори друго.

Нещо важно, което се пропуска (и което продължава да ми е проблем при мен самия) е, че понякога има връщане към стар проблем, и опит да разберем защо сме взели дадено решение и дали не трябва сега да вземем различно. Съответно, е добре да има някъде записани старите доводи.

Ако нямате стенографиращ екип, и не сте водили дискусията по mail, то на практика се разчита само на паметта на хората. Паметта на хората е нещо ужасно (който не го вярва, да прочете “Невидимата горила”). За това всяка организация би трябвало има писмена институционна памет (не само хора, дето помнят някакви неща), за да може да се обръща към нея в такива моменти.

Би трябвало всички тук да са имали момента, в който се ровят в стар код, чудят се защо и кой го е написал, и откриват, че са те.

Документирането никак не е лесно, но се изплаща многократно.

И тук някъде идва разговорът за воденето на екипа.

По принцип екипите си имат lead в някакъв вид. Дали се води директор, мениджър или какъвто-там-е-термина, в организацията ролята е да бъде интерфейс между екипа и останалата част от организацията.

Това има различни варианти да се направи. Чувал съм, че често е някой, дето да назначават и да размахва камшика без идея какво правят хората “под” него.

В това има няколко проблема, като тръгнем от това, че тези хора не трябва да са “под”, а “при” него. За мен един lead е част от екипа, може да е смислена част от него и може да е “бай Иван”.

Това е един списък, дето написах още в началото, докато си правех плана на лекцията. За мен е сравнително очевиден, но сам по себе си не е особено интересен. Може да се намери в някакъв вид в много книги, включително в голяма част от всичката военна фантастика :)

За мен по-важно е в екипа всяко едно от тези неща да може да го прави всеки, и да има увереността, че може да го прави – може би не от първия ден, не максимално ефективно, но в един момент всеки трябва да може да поема отговорност, и всички да могат да застанат зад него, когато се наложи.

И ако се върнем към културата, важни за един екип са възможността, способността и желанието да се поеме отговорност. Без тях нищо не може да се случи.

Не е задължително да има един lead. Виждал съм (и съм участвал в такива) екипи, където има трима lead-ове, с различни профили. Те донякъде могат да се покриват, но са специализирани достатъчно, и са достатъчно автономни, че да могат да движат нещата без постоянно да трябва да се разбират за някакви неща. Като един пример, това беше OpenFest през повечето време, през което се занимавах с него.

Да има резервен човек, който може да поеме такъв тип задачи е направо животоспасяващо. Това може да е формализирано, а може и просто когато се наложи, да излизат хора от екипа, които да поемат тези функции. Та е важно (както споменах и по-горе) да има една резервна лидерска скамейка, на която има хора, можещи да поемат отговорност.

А може просто да няма формализиран lead, и ролята да се мести, или просто да се случва сама. Това също е работещ вариант при правилните хора, и е просто една голяма “резервна скамейка”, от която някой става, когато е нужно.

Такива примери имам много, от всякакви организации, но най-лесния за илюстриране и един от от любимите ми (даже се оказа, че съм го ползвал в друга моя лекция :) ). Това се случва в петък вечер преди OpenFest 2018. Аз съм се прибрал да си гледам жената и детето (тогава само едно), и нещо се счупва с интернета и сървъра. И няколко човека, които всъщност не са настройвали тая част, щото са били заети с други неща сядат и го оправят (с малко обаждане по телефона да ме питат нещо).

Да си призная, тези хора ми бяха от любимите екипи :)

Почистването на екип е от нещата, с които съм се занимавал най-малко. Старая се основно да не се налага, понеже това губи време и изтормозва всички.

Виждал съм най-различни случаи на проблемни хора. За тях има различни решения, като тръгнем от корекция на конфликти, разделение на отговорности (ако някакви хора не могат да се траят, но трябва да работят в близки екипи), до директно раздяла с някого. Важното при всички такива решения е да са ясни защо се случват и да се случват.

Това по принцип е една от най-тежките задачи, и във фирмите даже си има хора за тая работа, да играят лошия, когато ни дойде желание да избягаме от отговорност…

А трябва ли да се занимваме с това? Да сме в екип, да го поддържаме, да работим заедно?

За някои хора не. Има достатъчно неща, за които може да си one-man show и да сработят, и познавам хора, които правят точно това – гледат да са единствените, които се занимават с дадено нещо и да си го организират така, че да не им е проблем.

За мен си заслужава и винаги си е заслужавало. Правил съм неща сравнително сам, и съм наясно какво мога да постигна. Постигал съм повече в различни екипи, и определено си е заслужавало. Препоръчвам на всички :) В някои отношения е по-трудно от работата с компютри, в някои е по-лесно, но съм се убедил, че е важно.

И ако се огледаме около себе си, огромна част от света, в който живеем се е случил и развил заради групи от хора с определена цел.

Оставям един slide с малко допълнителни ресурси, има ли някакви въпроси?

2024-10-19 “Self-hosting workshop” в initLab

October 20th, 2024 by Vasil Kolev

В initLab се случват доста събития, но рядко има записи (или не се откриват, трябва да проуча малко).

Вчера с Благо направихме self-hosting workshop, и има запис. Ще се постарая да намерим начин останалите неща, дето се случват там да се записват и да ходят във видео архива.

2024-09-23 гласуване за лекции на OpenFest

September 23rd, 2024 by Vasil Kolev

vote.openfest.org, както винаги. Гласуването помага за подреждането на лекциите и понякога за избора им.

(има и моя там, но понеже аз държах на това да не се виждат кои са лекторите, за да се избират лекции на база материала в тях, няма да кажа коя)
(както и че ще я правя тестово в събота в initLab)

2024-08-31 Лекция на Grace Hopper

August 31st, 2024 by Vasil Kolev

По принцип видеото ми е един от най-бавните и неудобни начини да приемам информация (това въпреки всичкото време, което съм отделил за записване и stream-ване на конференции). Та рядко гледам такива неща, и много често предпочитам да си прочета за нещо, вместо да седя и да слушам.

Тия дни обаче попаднах на запис на лекция на Grace Hopper в NSA, който наскоро са разсекретили (и в който няма нищо особено секретно или тайно). За лекция, която е изнесена преди 30-40 години, нещата са доста интересни и на място, доста от проблемите от тогава съществуват и сега, а самият разказ и начинът на разказване са едни от най-добрите, дето съм виждал.

Та, препоръчвам.

2024-08-11 initLab рожден ден

August 11th, 2024 by Vasil Kolev

initLab стана на 14 години.

Отпразнувахме го подобаващо, с разни занимания, включващи пиене, свирене и бордови игри. Имаше хора, които са членове отдавна, имаше хора, които идваха за пръв път, та си беше весело.

Хубаво е, че лабът съществува толкова години. Това е едно от малкото места, на които хора могат да се съберат и да свършат нещо интересно, в почти произволна посока, без някакви особени ограничения и задължения, просто за удоволствието и знанията. През годините са организирани толкова събития, че ми е трудно да ги изброя (във времената, когато бях в управителния съвет си спомням колко дълъг ставаше отчетът за дейността, просто защото целогодишно се случват някакви неща). Без initLab щеше да е доста по-трудна организацията на OpenFest, на доброволците, които ходим на FOSDEM, study групите за Rails Girls, както и на много знайни и незнайни други проекти.

Около свиренето си припомних, че в лаба има един много забавен ефект (така де, любимо звучащия ми дисторжън на тоя свят), и в събота отидох да подрънча малко. Резултатите са (средно зле), нещо с полка ритъм и частта от нещото без distortion, която за някои хора може да е по-слушаема.
(частта без distortion е от края и е по-зле, понеже вече малко ме боляха ръцете, поотвикнал съм)

(също обмислям да проходя някакви лекции в лаба в следващите месеци, понеже имам три започнати и трите не ми харесват изобщо, и се чудя дали ако ги изговоря с някакви други хора може да се получат)

Празнуването на sysadminday 2024

July 11th, 2024 by Vasil Kolev

Има запазени 2-3 маси в “Дондуковъ” (където се провежда и ИББ), за 26.07 (петък), 19:00, на мое име.

Ще има и във Варна, ще update-на за там като ми кажат къде ще е.

Update: За Варна – “Черната овца” до ЖП гарата, на името на Тодор Петков, пак от 19:00, пак 26.07.

Update: За Велико Търново – “Тихият кът” от 20:00, пак 26.07.

2024-06-16 празнуване на sysadminday

June 16th, 2024 by Vasil Kolev

По традиция деня на системния администратор е последния петък на юли.

Дали за тази година има желаещи да го празнуваме в София? Нещо като Маймунарника, или някоя кръчма по центъра, някой би ли дошъл?:)

2024-04-06 нова marla, нов tyler, миграции

April 6th, 2024 by Vasil Kolev

И дойде време за подмяна на хардуера.

marla.ludost.net последно е подменяна през 2016, и имаше нужда от refresh.

За разлика от предишните, новата е 1U. Сега е AMD EPYC 7303P, 128 GiB RAM, и три броя 7.68TB NVMe-та в RAID5. В сравнение с предишната направо лети.

Хардуерната част беше по-лесната. Машината беше още на Debian 9, с купчина ръчно компилирани неща, с разни стари услуги и какви ли не странности. За миграцията имах 40тина неща за подготвяне, и план за самата миграция план от 45 точки какво има да се пусне/спре/мигрира и т.н.. От по-забавните:

– Не ми се занимаваше да мигрирам до maiman3, така че си build-нах пакет за mailman2, с python2 и всичко останало. Тва ще живее в миналото, докато не събера желание да пренеса миграцията до нещо по-модерно. Също, никак не ме радва идеята разни пакети да мислят, че да се счупи миграцията от версия 2 към версия 3 е добра идея, и обвинявам Python-а, че даде лош пример на света.
– Трябваше да си build-на ircd-то и services с моите patch-ове за UTF-8 support и подобни неща. В момента ircd-ratbox го няма никъде в debian и трябва да помисля за миграция към някой от наследниците.
– Ползвам packetbl за филтриране на пакети на база на RBL, та му направих по-нормален начин за пускане и пакетиране за текущата ситуация.
– И разбира се купчини сайтове, PHP-та, бази и какво ли не още.

Подготовката беше няколко седмици, от които може би 2 дни бяха rsync на всички данни през интернетите, за да пренеса повечето информация, разни дебели видео архиви и подобни работи. После едни колеги пренесоха желязото физически до 3dc, пъхнаха го в rack-а, и аз след ден-два направих самия switch, в рамките на няколко часа. Помогна и monitoring-а, да покаже какво не е светнало и какво има да се досветне.

Имаше няколко fail-а, които се оправяха в последствие, но като цяло нещата минаха добре, и в момента желязото си клати краката, щото предишния load изобщо не може да се сравни с какво може. Следва да се качи още натоварване :)

И това беше лесната част. Като допълнение, исках да махна стария tyler (който е по-предната marla, купувана 2010та), и да го пренеса на старата marla. Което щеше да е доста по-проста задача, ако не беше това:

u0    RAID-5    DEGRADED       -       -       64K     2793.94   RiW    ON    
VPort Status         Unit Size      Type  Phy Encl-Slot    Model
------------------------------------------------------------------------------
p0    OK             u0   1.82 TB   SATA  0   -            ST2000DM008-2UB102 
p1    OK             u0   1.82 TB   SATA  1   -            ST2000DM008-2UB102 
p2    DEGRADED       u0   1.82 TB   SATA  2   -            ST2000DM008-2UB102 
p3    ECC-ERROR      u0   1.82 TB   SATA  3   -            ST2000DM008-2UB102 

Това е RAID5 масив с един изпаднал диск и един, който дава грешки, или в човешка терминология, “life sucks and then you die”. Открих го, когато започнах да планирам миграцията, и се наложи да го планирам малко по-форсмажорно. Файловите системи вече даваха грешки, така че в общи линии една нощ преточвах каквото можеше, и в една ранна сутрин с dd през netcat преточих root partition-а на другото желязо и boot-нах.

Най-голямото упражнение беше да го направя без ходене на място, понеже да се boot-не нещо на желязо с толкова стар IPMI се оказа забавно, и загубих 4-5 часа да се опитвам да намеря java, която да може да направи закачането на block device отсреща (в което се провалих изцяло). Накрая (понеже все пак имах ipmi) написах едно sysrescuecd на един partition на диска и просто boot-нах от него, за да мога спокойно да overwrite-вам root-а.
(след което имаше разни други проблеми с разлики в GRUB версии и т.н., като цяло в GRUB prompt не бях изкарвал толкова време доста отдавна)

Доста неща са пострадали. Спасих си netbox-а, но kenny.ludost.net е със заминала база, там няма спасение, та който е имал account, ще трябва да си прави пак. Jabber сървъра също е пострадал, и ще видя там какво мога да направя в следващите дни.

Цялата работа ми показа основно колко ме е разглезил StorPool с тия виртуални машини, snapshot-и, end-to-end checksum-и, live миграции… Ако събера бюджет, някой ден ще си вдигна нещо подобно. От друга страна, човек определено трябва да си припомня как се правят по-криви неща от време на време :)

2024-03-05 The failed live migration case

March 5th, 2024 by Vasil Kolev

There’s a purpose in everyone’s life. Some days, it seems like mine is to show people what not to do.

I’ve written this explanation to show my mistakes and that, hopefully, other people don’t (there’s no hope for me). What follows is most of my debugging process, and it could be helpful to other people to see it (and point out what is wrong with it).

This happens in a StorPool deployment for a customer who runs a public cloud service. We provide the shared storage via some drivers of our own, and the customer uses OpenNebula to control Linux/KVM hypervisors. It’s all integrated very nicely and is used for our internal clouds.

KVM VMs are a qemu process in the Linux userspace with multiple threads.

The case started with a customer complaining that after an update we did to the storage software, the live migrations of his VMs started failing (the VMs would fail to move but would continue working on the original host). The problem was narrowed down to VMs started before a specific date (when we did the update mentioned above), and initially, it seemed to be contained to VMs that had QEMU CPU set (i.e., the least performant one).

At this point, I asked – can’t they restart all such VMs? This CPU type is mainly contributing to global warming anyway.
The reply was, “Are you insane? These are 900 VMs. We’ll reboot them, but we really don’t want to do that now”.
Fair point.

Then, some further tests showed that any VMs, not just the ones with the QEMU CPU, were failing the migration. Finally, someone looked into the (not easy to find) logs of qemu and found the following:

2024-02-20T09:46:41.938285Z qemu-kvm-one: qemu_savevm_state_complete_precopy_non_iterable: bdrv_inactivate_all() failed (-1)

(seriously. Trying to trace anything via the logs in OpenNebula/libvirt/qemu feels like interrogating prisoners who don’t speak your language.)

Two mistakes above that would’ve saved a day or two – I should’ve looked into the issue immediately myself instead of relying on hearsay and building the wrong picture (based on assumptions) in my head. I did not expect that the (routine) update we did could have any such effect.

I specifically checked if the same problem existed in our labs and test environments, where we had done the same routine update, and it didn’t exist.

Now, this was weird. The only mention of the above error was in https://bugzilla.redhat.com/show_bug.cgi?id=2058982 when the storage device on the originating side was broken. This was not the case here.

My first step was to get permission to use one VM at the customer for tests, and after I had that, I ran strace on it while migrating.

What I was able to see in the thread that performed the migration was:

prctl(PR_SET_NAME, "live_migration")    = 0
…
sendmsg(99, {msg_name=NULL, msg_namelen=0, msg_iov=[{iov_base="..."..., iov_len=32768}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 32768
sendmsg(99, {msg_name=NULL, msg_namelen=0, msg_iov=[{iov_base="..."..., iov_len=32768}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 32768
write(2, "2024-02-15T07:00:23.057678Z ", 28) = 28
write(2, "qemu-kvm-one:", 13)           = 13
write(2, " ", 1)                        = 1
write(2, "qemu_savevm_state_complete_precopy_non_iterable: bdrv_inactivate_all() failed (-1)", 82) = 82
write(2, "\n", 1)                       = 1
futex(0x55586af89640, FUTEX_WAKE_PRIVATE, 1) = 1
sendmsg(20, {msg_name=NULL, msg_namelen=0, msg_iov=[{iov_base="{\"timestamp\": {\"seconds\": 1707980423, \"microseconds\": 57880}, \"event\": \"MIGRATION\", \"data\": {\"status\": \"failed\"}}\r\n", iov_len=115}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 115
futex(0x55586af89640, FUTEX_WAIT_PRIVATE, 2, NULL) = -1 EAGAIN (Resource temporarily unavailable)
sendmsg(20, {msg_name=NULL, msg_namelen=0, msg_iov=[{iov_base="{\"timestamp\": {\"seconds\": 1707980423, \"microseconds\": 58133}, \"event\": \"RESUME\"}\r\n", iov_len=82}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 82

Some digging showed that 99 was the file descriptor with the connection to the remote qemu. This was the memory transfer, followed almost immediately by writing out the error and nothing in between.

So, being somewhat lost, I looked up debug symbols for qemu to see if I could trace this further. The usual tooling told me there weren’t:

[root@somewhere str3]# gdb /usr/libexec/qemu-kvm
GNU gdb (GDB) Rocky Linux 8.2-20.el8.0.1
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from /usr/libexec/qemu-kvm...Reading symbols from .gnu_debugdata for /usr/libexec/qemu-kvm...(no debugging symbols found)...done.
(no debugging symbols found)...done.
Missing separate debuginfos, use: yum debuginfo-install qemu-kvm-core-6.2.0-33.module+el8.8.0+1454+0b2cbfb8.x86_64
(gdb) quit

[root@somewhere str3]# yum debuginfo-install qemu-kvm-core-6.2.0-33.module+el8.8.0+1454+0b2cbfb8.x86_64
Repository storpool-contrib is listed more than once in the configuration
enabling epel-debuginfo repository
Extra Packages for Enterprise Linux 8 - x86_64 - Debug                                                                                                                                                                                            4.0 MB/s | 6.1 MB     00:01    
Last metadata expiration check: 0:00:02 ago on Thu Feb 15 16:26:34 2024.
Could not find debuginfo package for the following installed packages: qemu-kvm-core-15:6.2.0-33.module+el8.8.0+1454+0b2cbfb8.x86_64
Could not find debugsource package for the following installed packages: qemu-kvm-core-15:6.2.0-33.module+el8.8.0+1454+0b2cbfb8.x86_64
Dependencies resolved.
Nothing to do.
Complete!

(I can already hear people saying, “You’re an idiot”; someone had to point that out to me)

Then, the colleague in communication with the customer said, “BTW, do you remember that at that time we did the other update, to migrate from one-type-of-volume-name to the-other-type-of-volume-name”? Of course, I didn’t. We ran the same migration in our lab, and the issue was reproduced immediately.

The mistake was that I did not collect all available information (or even most of it), still relying on assumptions.

I could deploy the latest qemu for AlmaLinux (almost the same as what the customer was using), download debug symbols, and start digging. Yay.

On strace, the issue looked the same – lots of sending to the socket and then just the error. So, I started digging with gdb by attaching, adding a breakpoint, continuing the process, and then running a live migration to see how the situation looked like at different points of the program. I had something like this primed and pasted when I ran gdb -p xxxx (some comments added to explain what these are):

set print pretty			# the usual gdb print is hard to read
set pagination off			# pagination is annoying in this regard, my terminal can scroll
handle SIGUSR1 nostop pass		# qemu uses SIGUSR1 a lot
break block/block-backend.c:253		# stop here
cont					# continue execution
bt full					# print me a full backtrace with local variables when stopped

It took some time to read through the relevant code and ensure there wasn’t something obvious (which took many wrong turns). The issue looked like that bdrv_inactivate_recurse() was trying to remove write permissions from the devices and was failing for some reason.

6523     /* Inactivate this node */
6524     if (bs->drv->bdrv_inactivate) {
6525         ret = bs->drv->bdrv_inactivate(bs);
6526         if (ret < 0) {
6527             return ret;
6528         }
6529     }
6530 
6531     QLIST_FOREACH(parent, &bs->parents, next_parent) {
6532         if (parent->klass->inactivate) {
6533             ret = parent->klass->inactivate(parent);
6534             if (ret < 0) {
6535                 return ret;
6536             }
6537         }
6538     }
6539 
6540     bdrv_get_cumulative_perm(bs, &cumulative_perms,
6541                              &cumulative_shared_perms);
6542     if (cumulative_perms & (BLK_PERM_WRITE | BLK_PERM_WRITE_UNCHANGED)) {
6543         /* Our inactive parents still need write access. Inactivation failed. */
6544         return -EPERM;
6545     }

This is the code in question, and in bdrv_get_cumulative_perms(), there were some devices that still had r/w set even after the stuff between lines 6531 and 6533 had passed:

bdrv_inactivate_recurse (bs=0x556e00221530) at ../block.c:6534
6534                if (ret < 0) {
(gdb) 
6531        QLIST_FOREACH(parent, &bs->parents, next_parent) {
(gdb) 
6540        bdrv_get_cumulative_perm(bs, &cumulative_perms,
(gdb) 
6542        if (cumulative_perms & (BLK_PERM_WRITE | BLK_PERM_WRITE_UNCHANGED)) {
(gdb) 
bdrv_inactivate_all () at ../block.c:6591
6591            if (ret < 0) {
(gdb) 
6592                bdrv_next_cleanup(&it);
(gdb) 

The inactivate() function above was in block/block-backend.c and looks like this:

 250 static int blk_root_inactivate(BdrvChild *child)
 251 {
 252     BlockBackend *blk = child->opaque;
 253 
 254     if (blk->disable_perm) {
 255         return 0;
 256     }
 257 
 258     if (!blk_can_inactivate(blk)) {
 259         return -EPERM;
 260     }
 261 
 262     blk->disable_perm = true;
 263     if (blk->root) {
 264         bdrv_child_try_set_perm(blk->root, 0, BLK_PERM_ALL, &error_abort);
 265     }
 266 
 267     return 0;
 268 }

and what was happening was:

258         if (!blk_can_inactivate(blk)) {
(gdb) 
262         blk->disable_perm = true;
(gdb) 
263         if (blk->root) {
(gdb) 
264             bdrv_child_try_set_perm(blk->root, 0, BLK_PERM_ALL, &error_abort);
(gdb) 
bdrv_inactivate_recurse (bs=0x556e00221530) at ../block.c:6534

So qemu is calling it, and that was all OK.

Here, a few times, I had missed what this was trying to do. Here’s bdrv_child_try_set_perm():

2517 
2518 int bdrv_child_try_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared,
2519                             Error **errp)
2520 {
2521     Error *local_err = NULL;
2522     Transaction *tran = tran_new();
2523     int ret;
2524 
2525     bdrv_child_set_perm(c, perm, shared, tran);
2526 
2527     ret = bdrv_refresh_perms(c->bs, &local_err);
2528 
2529     tran_finalize(tran, ret);
2530 
2531     if (ret < 0) {
2532         if ((perm & ~c->perm) || (c->shared_perm & ~shared)) {
2533             /* tighten permissions */
2534             error_propagate(errp, local_err);
2535         } else {
2536             /*
2537              * Our caller may intend to only loosen restrictions and
2538              * does not expect this function to fail.  Errors are not
2539              * fatal in such a case, so we can just hide them from our
2540              * caller.
2541              */
2542             error_free(local_err);
2543             ret = 0;
2544         }
2545     }
2546 
2547     return ret;
2548 }

So that 0 being passed is “remove all permissions”, but at some time late in the day, you can’t see it…

And now, I break into that one and try to see what happens:

(gdb) n
2197        *s = (BdrvChildSetPermState) {
(gdb) print *(local_err)
No symbol "local_err" in current context.
(gdb) 
No symbol "local_err" in current context.
(gdb) n
2203        c->perm = perm;
(gdb) print *(local_err)
No symbol "local_err" in current context.
(gdb) n
2204        c->shared_perm = shared;
(gdb) print *(local_err)
No symbol "local_err" in current context.
(gdb) n
2206        tran_add(tran, &bdrv_child_set_pem_drv, s);
(gdb) n
bdrv_child_try_set_perm (c=0x556e002e1730, perm=perm@entry=0, shared=shared@entry=31, errp=0x556dfeb99258 <error_abort>) at ../block.c:2527
2527        ret = bdrv_refresh_perms(c->bs, &local_err);
(gdb) print *(local_err)
Cannot access memory at address 0x0
(gdb) n
2529        tran_finalize(tran, ret);
(gdb) print *(local_err)
$1 = {
  msg = 0x7f25a4041b70 "Could not open '/var/lib/one//datastores/0/310/disk.0': No such file or directory", 
  err_class = ERROR_CLASS_GENERIC_ERROR, 
  src = 0x556dfe63ca2a "../util/osdep.c", 
  func = 0x556dfe63cbc0 <__func__.26488> "qemu_open_internal", 
  line = 359, 
  hint = 0x0
}
(gdb) q

Now, I see it going through the function, and I’m trying to look at that local_err if there’s something in it. Finally, I get the actual error; it has happened somewhere and is not propagated – but qemu has tried opening a file, and that doesn’t exist.

Two things here:
– This file does exist (it’s a symlink to a symlink to a block device, and I can access it with the permissions of the process);
– Why isn’t this error logged or propagated? I should probably send a patch for that…
– This was not in what strace showed, so what the hell.

So, I break at util/osdep.c in qemu_open_internal(), to see what happens. I pass through that a few times, trying to see where that error comes from, because I still think there is no syscall there, and glibc is screwing with me. This goes to show that you shouldn’t debug when tired because glibc returning ENOENT on its own is a lot less likely than strace missing one syscall.

I’m going to leave out a lot of unsuccessful attempts and show you how I got to the next clue in one large gdb session (commends with #):

(gdb) break util/osdep.c:312
Breakpoint 1 at 0x556dfe2c5c71: file ../util/osdep.c, line 312.
(gdb) handle SIGUSR1 nostop pass
Signal        Stop      Print   Pass to program Description
SIGUSR1       No        Yes     Yes             User defined signal 1
(gdb) set print pretty
(gdb) set pagination off
(gdb) cont
Continuing.
[New Thread 0x7f259c9ba700 (LWP 1798462)]
[New Thread 0x7f259c1b9700 (LWP 1798463)]

Thread 5 "CPU 0/KVM" received signal SIGUSR1, User defined signal 1.

Thread 5 "CPU 0/KVM" received signal SIGUSR1, User defined signal 1.

Thread 5 "CPU 0/KVM" received signal SIGUSR1, User defined signal 1.
[Switching to Thread 0x7f259c1b9700 (LWP 1798463)]

Thread 8 "live_migration" hit Breakpoint 1, qemu_open_internal (name=name@entry=0x556e0021b241 "/var/lib/one//datastores/0/310/disk.0", flags=16384, mode=mode@entry=0, errp=errp@entry=0x7f259c1b85e0) at ../util/osdep.c:318
318         if (strstart(name, "/dev/fdset/", &fdset_id_str)) {
(gdb) bt full# nothing interesting in the backtrace
(gdb) disassemble 
Dump of assembler code for function qemu_open_internal:
   0x0000556dfe2c5c40 <+0>:     push   %r15
   0x0000556dfe2c5c42 <+2>:     push   %r14
   0x0000556dfe2c5c44 <+4>:     mov    %rcx,%r14
   0x0000556dfe2c5c47 <+7>:     push   %r13
   0x0000556dfe2c5c49 <+9>:     mov    %edx,%r13d
   0x0000556dfe2c5c4c <+12>:    push   %r12
   0x0000556dfe2c5c4e <+14>:    mov    %esi,%r12d
   0x0000556dfe2c5c51 <+17>:    lea    0x376dad(%rip),%rsi        # 0x556dfe63ca05
   0x0000556dfe2c5c58 <+24>:    push   %rbp
   0x0000556dfe2c5c59 <+25>:    mov    %rdi,%rbp
   0x0000556dfe2c5c5c <+28>:    push   %rbx
   0x0000556dfe2c5c5d <+29>:    sub    $0x28,%rsp
   0x0000556dfe2c5c61 <+33>:    mov    %fs:0x28,%rax
   0x0000556dfe2c5c6a <+42>:    mov    %rax,0x18(%rsp)
   0x0000556dfe2c5c6f <+47>:    xor    %eax,%eax
=> 0x0000556dfe2c5c71 <+49>:    lea    0x10(%rsp),%rdx
   0x0000556dfe2c5c76 <+54>:    callq  0x556dfe2c6a30 <strstart>
   0x0000556dfe2c5c7b <+59>:    test   %eax,%eax
   0x0000556dfe2c5c7d <+61>:    je     0x556dfe2c5cd8 <qemu_open_internal+152>
   0x0000556dfe2c5c7f <+63>:    mov    0x10(%rsp),%rdi
   0x0000556dfe2c5c84 <+68>:    callq  0x556dfe2c79b0 <qemu_parse_fd>
   0x0000556dfe2c5c89 <+73>:    movslq %eax,%rdi
   0x0000556dfe2c5c8c <+76>:    mov    %rdi,%rbx
   0x0000556dfe2c5c8f <+79>:    cmp    $0xffffffffffffffff,%rdi
   0x0000556dfe2c5c93 <+83>:    je     0x556dfe2c5d7c <qemu_open_internal+316>
   0x0000556dfe2c5c99 <+89>:    mov    %r12d,%esi
   0x0000556dfe2c5c9c <+92>:    callq  0x556dfe101b60 <monitor_fdset_dup_fd_add>
   0x0000556dfe2c5ca1 <+97>:    mov    %eax,%ebx
   0x0000556dfe2c5ca3 <+99>:    cmp    $0xffffffff,%eax
   0x0000556dfe2c5ca6 <+102>:   je     0x556dfe2c5db3 <qemu_open_internal+371>
   0x0000556dfe2c5cac <+108>:   mov    0x18(%rsp),%rcx
   0x0000556dfe2c5cb1 <+113>:   xor    %fs:0x28,%rcx
   0x0000556dfe2c5cba <+122>:   mov    %ebx,%eax
   0x0000556dfe2c5cbc <+124>:   jne    0x556dfe2c5dd3 <qemu_open_internal+403>
   0x0000556dfe2c5cc2 <+130>:   add    $0x28,%rsp
   0x0000556dfe2c5cc6 <+134>:   pop    %rbx
   0x0000556dfe2c5cc7 <+135>:   pop    %rbp
   0x0000556dfe2c5cc8 <+136>:   pop    %r12
   0x0000556dfe2c5cca <+138>:   pop    %r13
   0x0000556dfe2c5ccc <+140>:   pop    %r14
   0x0000556dfe2c5cce <+142>:   pop    %r15
   0x0000556dfe2c5cd0 <+144>:   retq   
   0x0000556dfe2c5cd1 <+145>:   nopl   0x0(%rax)
   0x0000556dfe2c5cd8 <+152>:   mov    %r12d,%esi
   0x0000556dfe2c5cdb <+155>:   mov    %r13d,%edx
   0x0000556dfe2c5cde <+158>:   mov    %rbp,%rdi
   0x0000556dfe2c5ce1 <+161>:   xor    %eax,%eax
   0x0000556dfe2c5ce3 <+163>:   or     $0x80000,%esi
   0x0000556dfe2c5ce9 <+169>:   callq  0x556dfdf0f190 <open64@plt>

…

I am not good at reading assembly, so if I’m doing this, I’m desperate (the colleague talking to the client was sitting next to me and asking why I was digging in the assembly). I see that it should call open64@plt, which looks like the syscall open to me.

I spend some time stepping instruction by instruction and trying to understand (and failing) what /usr/include/bits/fcntl2.h is doing with the macros there, but instruction by instruction I get to this:

(gdb) si
__libc_open64 (file=file@entry=0x556e0021b241 "/var/lib/one//datastores/0/310/disk.0", oflag=oflag@entry=540672) at ../sysdeps/unix/sysv/linux/open64.c:37
37      {
(gdb) si
0x00007f25d7a401d4      37      {
(gdb) si
0x00007f25d7a401d8      37      {
(gdb) disassemble 
Dump of assembler code for function __libc_open64:
   0x00007f25d7a401d0 <+0>:     endbr64 
   0x00007f25d7a401d4 <+4>:     sub    $0x68,%rsp
=> 0x00007f25d7a401d8 <+8>:     mov    %esi,%r10d
   0x00007f25d7a401db <+11>:    mov    %rdx,0x40(%rsp)
   0x00007f25d7a401e0 <+16>:    mov    %fs:0x28,%rax
   0x00007f25d7a401e9 <+25>:    mov    %rax,0x28(%rsp)
   0x00007f25d7a401ee <+30>:    xor    %eax,%eax
   0x00007f25d7a401f0 <+32>:    and    $0x40,%r10d
   0x00007f25d7a401f4 <+36>:    jne    0x7f25d7a40248 <__libc_open64+120>
   0x00007f25d7a401f6 <+38>:    mov    %esi,%eax
   0x00007f25d7a401f8 <+40>:    and    $0x410000,%eax
   0x00007f25d7a401fd <+45>:    cmp    $0x410000,%eax
   0x00007f25d7a40202 <+50>:    je     0x7f25d7a40248 <__libc_open64+120>
   0x00007f25d7a40204 <+52>:    mov    0x20d236(%rip),%eax        # 0x7f25d7c4d440 <__pthread_multiple_threads>
   0x00007f25d7a4020a <+58>:    test   %eax,%eax
   0x00007f25d7a4020c <+60>:    jne    0x7f25d7a40273 <__libc_open64+163>
   0x00007f25d7a4020e <+62>:    mov    %esi,%edx
   0x00007f25d7a40210 <+64>:    mov    $0x101,%eax
   0x00007f25d7a40215 <+69>:    mov    %rdi,%rsi
   0x00007f25d7a40218 <+72>:    mov    $0xffffff9c,%edi
   0x00007f25d7a4021d <+77>:    syscall 
   0x00007f25d7a4021f <+79>:    cmp    $0xfffffffffffff000,%rax
   0x00007f25d7a40225 <+85>:    ja     0x7f25d7a402c8 <__libc_open64+248>
   0x00007f25d7a4022b <+91>:    mov    0x28(%rsp),%rcx
   0x00007f25d7a40230 <+96>:    xor    %fs:0x28,%rcx
   0x00007f25d7a40239 <+105>:   jne    0x7f25d7a402f1 <__libc_open64+289>
   0x00007f25d7a4023f <+111>:   add    $0x68,%rsp

And that, at 0x00007f25d7a4021d <+77>: is obviously the entry point to the kernel (the syscall). So…

(gdb) si
0x00007f25d7a40289      48        return SYSCALL_CANCEL (openat, AT_FDCWD, file, oflag | EXTRA_OPEN_FLAGS,
(gdb) si
0x00007f25d7a4028d      48        return SYSCALL_CANCEL (openat, AT_FDCWD, file, oflag | EXTRA_OPEN_FLAGS,
(gdb) si
0x00007f25d7a40290      48        return SYSCALL_CANCEL (openat, AT_FDCWD, file, oflag | EXTRA_OPEN_FLAGS,
(gdb) si
0x00007f25d7a40295      48        return SYSCALL_CANCEL (openat, AT_FDCWD, file, oflag | EXTRA_OPEN_FLAGS,
(gdb) si
0x00007f25d7a4029a      48        return SYSCALL_CANCEL (openat, AT_FDCWD, file, oflag | EXTRA_OPEN_FLAGS,
(gdb) si
0x00007f25d7a4029c      48        return SYSCALL_CANCEL (openat, AT_FDCWD, file, oflag | EXTRA_OPEN_FLAGS,
(gdb) si
0x00007f25d7a4029f      48        return SYSCALL_CANCEL (openat, AT_FDCWD, file, oflag | EXTRA_OPEN_FLAGS,
(gdb) si
0x00007f25d7a402a4      48        return SYSCALL_CANCEL (openat, AT_FDCWD, file, oflag | EXTRA_OPEN_FLAGS,
(gdb) si
0x00007f25d7a402a6      48        return SYSCALL_CANCEL (openat, AT_FDCWD, file, oflag | EXTRA_OPEN_FLAGS,
(gdb) disassemble 
Dump of assembler code for function __libc_open64:
… 			# omitted
   0x00007f25d7a40285 <+181>:   mov    0xc(%rsp),%esi
   0x00007f25d7a40289 <+185>:   mov    (%rsp),%rdi
   0x00007f25d7a4028d <+189>:   mov    %eax,%r8d
   0x00007f25d7a40290 <+192>:   mov    0x8(%rsp),%r10d
   0x00007f25d7a40295 <+197>:   mov    $0x101,%eax
   0x00007f25d7a4029a <+202>:   mov    %esi,%edx
   0x00007f25d7a4029c <+204>:   mov    %rdi,%rsi
   0x00007f25d7a4029f <+207>:   mov    $0xffffff9c,%edi
   0x00007f25d7a402a4 <+212>:   syscall 
=> 0x00007f25d7a402a6 <+214>:   cmp    $0xfffffffffffff000,%rax
   0x00007f25d7a402ac <+220>:   ja     0x7f25d7a402de <__libc_open64+270>

Maybe not the one I expected, but by stepping instruction by instruction, I obviously called a syscall here. So qemu asks the kernel about the file, and the kernel says it’s not there.

So for the hell of it I run strace -e trace=open,openat -p PIDFILE, and

[root@a8onekvm1 ~]# strace -f -p 1463232 -o dbg.open -s 255 -e trace=open,openat
strace: Process 1463232 attached with 6 threads
strace: Process 1832488 attached
strace: Process 1832489 attached
^Cstrace: Process 1463232 detached
strace: Process 1463236 detached
strace: Process 1463237 detached
strace: Process 1463240 detached
strace: Process 1463242 detached
strace: Process 1463245 detached

[root@a8onekvm1 ~]# grep open dbg.open 
1832489 openat(AT_FDCWD, "/var/lib/one//datastores/0/310/disk.0", O_RDONLY|O_DIRECT|O_CLOEXEC) = -1 ENOENT (No such file or directory)

So, now strace sees it, but otherwise doesn’t?

Cue 5 minutes of me, yelling about strace betraying me, then checking that the file exists, writing a small C program to execute the exact same syscall with the permissions of the process, and (being late Friday afternoon and being tired) complaining to other people. And someone says, “this is most probably mount namespaces issue”.

And what do you know, it is:

[root@a8onekvm1 1463232]# nsenter -m -t 1463232 ls -l /var/lib/one//datastores/0/310/disk.0
lrwxrwxrwx 1 oneadmin oneadmin 28 Feb 16 11:02 /var/lib/one//datastores/0/310/disk.0 -> /dev/storpool-byid/fir.b.f2g
[root@a8onekvm1 1463232]# nsenter -m -t 1463232 ls -l /dev/storpool-byid
ls: cannot access '/dev/storpool-byid': No such file or directory

Sooo… what we have done is replace the symlink from pointing to /dev/storpool/XXX to /dev/storpool-byid/YYY. The namespace for qemu doesn’t have the second directory, it was not in use when the process was started, and we have just screwed it by moving the symlink.

So, happy with that, on Monday I wrote a lousy script to recreate the links, which one of my colleagues made into a good script that people won’t be ashamed to show, for example, replacing

virsh dumpxml one-316 |grep 'source dev.*datastores' | cut -d ' ' -f 2

with

xmlstarlet sel -t -m '//devices/disk/source' -v '@dev' -n "${DOMXML}" 2>/dev/null

Then, we apply this to the live environment to one VM, and happily tell the customer to try a live migration.

It fails with the same error.
(cut some time for swearing at the world and all broken software)

So I’m back to square one, as I try strace-ing the process in the live environment with -e trace=open,openat, and there is no such call. I also tried ltrace, but the only difference was that it was slower and didn’t show anything more.

Then, a colleague says, “You know, these debuginfo packages should exist, they’re not that old”, goes looking in the mirrors, and FINDS THEM. For some reason, google doesn’t index that part, and I could not find them the lazy way.

Here’s the obvious error that you should look for yourself. It would’ve been even easier if I logged in to the local mirror we have for Rocky Linux and ran a find for myself.

Armed with debug symbols, I get the test VM again, attach to it, add a breakpoint at qemu_internal_open(), and nothing happens. It doesn’t get hit. It looks like strace wasn’t lying here.

I go back to the blk_root_inactivate() function and I notice:

Thread 8 "live_migration" hit Breakpoint 1, blk_root_inactivate (child=0x55586bf47c00) at ../block/block-backend.c:252
252         BlockBackend *blk = child->opaque;
(gdb) bt
#0  blk_root_inactivate (child=0x55586bf47c00) at ../block/block-backend.c:252
#1  0x000055586a5e8162 in bdrv_inactivate_recurse (bs=0x55586b297760) at ../block.c:6533
#2  0x000055586a5e963f in bdrv_inactivate_all () at ../block.c:6590
#3  0x000055586a37b535 in qemu_savevm_state_complete_precopy_non_iterable (f=0x55586c05d500, in_postcopy=<optimized out>, inactivate_disks=</optimized><optimized out>) at ../migration/savevm.c:1441
#4  0x000055586a37b622 in qemu_savevm_state_complete_precopy (f=0x55586c05d500, iterable_only=iterable_only@entry=false, inactivate_disks=inactivate_disks@entry=true) at ../migration/savevm.c:1493
#5  0x000055586a374236 in migration_completion (s=0x55586b207000) at ../migration/migration.c:3260
#6  migration_iteration_run (s=0x55586b207000) at ../migration/migration.c:3672
#7  migration_thread (opaque=0x55586b207000) at ../migration/migration.c:3908
#8  0x000055586a6d9dc4 in qemu_thread_start (args=0x55586c0ee6c0) at ../util/qemu-thread-posix.c:585
#9  0x00007f4a951d11ca in start_thread () from target:/lib64/libpthread.so.0
#10 0x00007f4a94e3de73 in clone () from target:/lib64/libc.so.6
(gdb) n
254         if (blk->disable_perm) {
(gdb) n
bdrv_inactivate_recurse (bs=0x55586b297760) at ../block.c:6534

blk->disable_perm is already set, so it looks like in this version of qemu (a bit older than what I initially used), when the live migration fails, this flag doesn’t get reset. I made a diff between the two versions, and that part has enough changes to warrant this idea. So, VMs that didn’t fail the migration would be fine.

Now, what about this one and a few more? They seem to be in a corrupt state. I read a bit more code, then bite the bullet and change the variable live:

Thread 7 "live_migration" hit Breakpoint 1, blk_root_inactivate (child=0x55586bf47c00) at ../block/block-backend.c:254
254         if (blk->disable_perm) {
(gdb) bt
#0  blk_root_inactivate (child=0x55586bf47c00) at ../block/block-backend.c:254
#1  0x000055586a5e8162 in bdrv_inactivate_recurse (bs=0x55586b297760) at ../block.c:6533
#2  0x000055586a5e963f in bdrv_inactivate_all () at ../block.c:6590
#3  0x000055586a37b535 in qemu_savevm_state_complete_precopy_non_iterable (f=0x55586c05d500, in_postcopy=</optimized><optimized out>, inactivate_disks=</optimized><optimized out>) at ../migration/savevm.c:1441
#4  0x000055586a37b622 in qemu_savevm_state_complete_precopy (f=0x55586c05d500, iterable_only=iterable_only@entry=false, inactivate_disks=inactivate_disks@entry=true) at ../migration/savevm.c:1493
#5  0x000055586a374236 in migration_completion (s=0x55586b207000) at ../migration/migration.c:3260
#6  migration_iteration_run (s=0x55586b207000) at ../migration/migration.c:3672
#7  migration_thread (opaque=0x55586b207000) at ../migration/migration.c:3908
#8  0x000055586a6d9dc4 in qemu_thread_start (args=0x55586c2325e0) at ../util/qemu-thread-posix.c:585
#9  0x00007f4a951d11ca in start_thread () from target:/lib64/libpthread.so.0
#10 0x00007f4a94e3de73 in clone () from target:/lib64/libc.so.6
(gdb) print ( (BlockBackend *) (child->opaque))->disable_perm
$1 = true
(gdb) print ( (BlockBackend *) (child->opaque))->perm
$2 = 3
(gdb) set: variable ( (BlockBackend *) (child->opaque))->disable_perm = false
No symbol "false" in current context.	# arghhhh
(gdb) set variable ( (BlockBackend *) (child->opaque))->disable_perm = 0
(gdb) cont
Continuing.

Thread 7 "live_migration" hit Breakpoint 1, blk_root_inactivate (child=0x55586bf51850) at ../block/block-backend.c:254
254         if (blk->disable_perm) {
(gdb) print ( (BlockBackend *) (child->opaque))->disable_perm
$3 = false
(gdb) print ( (BlockBackend *) (child->opaque))->perm
$4 = 1
(gdb) cont
Continuing.
[Thread 0x7f4999ffb700 (LWP 144024) exited]
[Thread 0x7f499a7fc700 (LWP 144025) exited]

Thread 1 "qemu-kvm-one" received signal SIGTERM, Terminated.	# oops?
[Switching to Thread 0x7f4a985a6e40 (LWP 3460894)]
0x00007f4a94f28036 in ppoll () from target:/lib64/libc.so.6
(gdb) q

(imagine this being done live and as quickly as possible, as the VM is hanging. You also see two devices, OpenNebula adds a context image to all VMs, and it’s a CD-ROM device that the migration didn’t get to corrupt)

Then I see SIGTERM and think, “crap, I killed it”. Then I look at the logs, and it has actually migrated successfully.

So, finally, with some pointers (“the command in gdb is command” :) ) I write the following:

set print pretty
set pagination off
handle SIGUSR1 nostop pass
handle SIGTERM nostop pass
break block/block-backend.c:253
commands
print ( (BlockBackend *) (child->opaque))->disable_perm
print ( (BlockBackend *) (child->opaque))->perm
set variable ( (BlockBackend *) (child->opaque))->disable_perm = 0
cont
end
cont

and it works like a charm on the 10-or-something VMs with a corrupt state.

A list of errors and lessons learned:

– Don’t assume that because there’s something not right, it’s the cause of the problem you’re looking at (QEMU processor for the VMs);
– Collect all relevant information (and maybe even irrelevant) – I keep telling people that it’s easier to work with too much information than with not enough. I should listen to myself one of these days;
– strace can hide syscalls and shouldn’t be fully trusted;
– If you’re searching for debuginfo (or anything like that), do your legwork, and don’t trust a single search engine;
– testing the wrong software version can reveal only a part of the problem (or a different one).

2023-12-25 равносметъчно

December 25th, 2023 by Vasil Kolev

– Децата са добре. Проведохме даже експеримент – големия ходи с майка си за 2 седмици до Ню Йорк, и ние с малкия си изкарахме много добре, типично по ергенски, с печене на пържоли и други такива;
– Успял съм да напиша 7 blog post-а през годината (без този). Има какво да се желае още, определено;
– FOSDEM 2023 се случи, направихме видео за последна година със стария хардуер, и се получи добре;
– Продължаваме да борим новия setup за FOSDEM 2024, пълно е с “интересни” проблеми;
– OpenFest 2023 се случи без мен. Догодина предавам фондацията, и ще съм приключил;
– Опитите ми за баланс на колко се натоварвам не са от най-успешните, въпреки махането на някакви задачи, трябва да се постарая малко повече за догодина.

Мисля да последвам традицията от миналата година и да не си правя планове за идващата.

2023-12-09 OpenFest 2023

December 9th, 2023 by Vasil Kolev

Голяма лудница ми е, та все не стигам да напиша тия няколко реда (и щяха да останат за равносметката), но държа да кажа:

OpenFest 2023 се случи без мен.

Правих някакви дребни неща, но не съм бил в организацията, нещата се случиха някакси, аз бях там само за да си тествам setup-а за FOSDEM. Да съм честен, най-трудното ми беше да не давам нареждания, щото навикът е страшна работа…

Та, по някое време догодина като направим събрание на фондацията да я предам, ще съм приключил с тая си част от живота. Екип се намира да движи нещата, та съм спокоен :)

п.с. по предишната тема за junior администраторите ще пиша отделно.

2023-11-11 откъде започват в наши дни junior администраторите?

November 11th, 2023 by Vasil Kolev

От време на време задавам тоя въпрос (и си мислех, че вече съм го блогвал, ама не откривам къде) – в наши дни, откъде започват junior системните администратори? Говорим за съвсем начинаещи, първа работа, горе-долу знаят как се държи клавиатура, и имат желание…

Едно време се започваше от support в близкото ISP. Там имаше всякакви мрежови и клиентски проблеми, човек научаваше, че user-ите лъжат (особено като ги питаш “нещо променяно ли е”), и малко по малко се попиваше от по-старшите и админите, така че да може да се научи къде да рови, какво да очаква и как да оправя разни по-дълбоки проблеми. Понеже работата никога не беше малко, почваха да се дават на човека по-сложни и по-сложни задачи, и така.
(“наградата за добре свършената работа е още работа” не е нещо лошо :) )

Също имаше достатъчно места (малки фирмички на някой роднина/познат на роднини), дето имаше нужда някой да им поддържа компютрите и където имаше достатъчно потребители, на чиито гръб да се научиш.

В наши дни май не е така, или поне аз не знам. Има от време на време някакви junior обяви, но като съм имал някакви такива интервюта и разговори, не мога да кажа на хората къде е добре за тях да отидат, ако нямат предишен опит.
(support-а в isp-тата в наши дни са хора, дето четат сценарий стъпка по стъпка и ако не беше толкова модерно заменянето на хора с AI, щяха да са ги заменили със shell script)

Една идея, която давам на хората, е да правят неща сами вкъщи. Може би аз съм в някаква изкривена среда, но повечето ми колеги имат нещо вкъщи, с което си играят, едно-две-три съвърчета, малка мрежа, собственоръчно правен rack… Това дава доста възможности да се научат някакви неща, основно на собствен гръб (или на хората, живеещи с човека).
От друга страна, не всички имат възможност, и не всички могат съвсем самостоятелно да започнат. До някакъв момент си мислех, че всички хора са/трябва да са такива, но с годините се поразубедих (и няма как да очаквам, че всички биха били като мен).

Липсва ми и това, че при мен няма такъв вариант. Естеството на работата за момента изглежда такова, че няма как да учим някой от нулата – няма капацитет и подходяща работа. От нещата, които искам да променя е, само дето още не съм измислил как…

Та, откъде в наши дни могат да почнат junior администраторите, дайте идея.

2023-09-25 гласуване за лекции за OpenFest

September 25th, 2023 by Vasil Kolev

Както обикновено, гласуването за лекции за OpenFest може да се намери на vote.openfest.org. Аз лекция тая година нямам, та няма да давам идеи :)

(“за бога братя, гласувайте”)

2023-09-21

September 21st, 2023 by Vasil Kolev

Има дни, които започват с намирането, ремонтирането и report-ването на бъг в мобилното приложение на rocketchat, минават през срещи и гасене на 3 пожара паралелно, и завършват с


MariaDB [opennebula]> update vm_pool set short_body=replace(short_body,'80','33') where oid=39;
Query OK, 1 row affected (0.002 sec)
Rows matched: 1 Changed: 1 Warnings: 0

Един ден трябва да направя лекция за opennebula и за кандидатурата им за най-невъзможна за докарване в консистентно състояние база данни на тоя свят. Онова по-горе (редактиране на XML в базата със string операции, което теорията твърди, че е идиотщина, и аз съм съгласен) се налага, понеже има същите данни в 2 различни полета на същата таблица, с малка редакция, и понякога не са синхронизирани.

Имам чувството, че съм почнал да гледам на целия свят като някакъв проблем за дебъгване.

2023-06-02 Взимане на решения в екип

June 2nd, 2023 by Vasil Kolev

От няколко места виждам вариации на темата, та ми се стори уместно да напиша нещо.

Ще започна с нещо от Камил Галеев, който на моменти има много добри обяснения. Важният момент в това е, че хората, които са на власт/в позиция да взимат решения/вършат нещо, не могат да имат крайни позиции. Вършенето на работа в екип с някого изисква компромиси, и е далеч по-лесно да работиш с хора, които са съгласни с теб и с които може да си сглобиш обща цел, отколкото с такива, които трябва да бъдат насилвани.

От това има няколко посоки на изводите:

Първо, хората/организациите с крайни позиции са такива, които никога не са стигали до свършване на нещо реално. Неспособността да направиш някакъв компромис и да се промениш/пренасочиш, за да се справиш с някаква промяна в обстановката води до това да си по-зле от тези, които намират вариант и да “отпаднеш” по някакъв начин.
(тук има огромна скоба и малко примери, понеже може да се разбира по грешния начин…

Опциите за компромис и промяна на посоката винаги са повече от една. Първи пример, някой на база на горното може да каже “Това значи ли, че Украйна трябва да направи компромис с Русия?” и отговорът там е, че те са направили много компромиси със западния свят/ЕС, за да могат да продължат да се бият. Дали тези ще са им достатъчни, е отделен въпрос.

Друг пример, на скоро обяснявах нуждата от “черна каса” и бях гледан с огромно учудване, че това се налага в наши дни. Моето твърдение е, че на практика няма организация, в която да няма нещо подобно, просто защото има неща, които не могат да се случат без подобен фонд за плащания, които нямат насрещен документ. Имам някакво количество примери от моята практика, за които по очевидни причини няма да разкажа, и само ще отбележа, че всяка достатъчно голяма организация от едно ниво нагоре има нещо подобно, известно като “discretionary фондове”, с които определени хора разполагат по собствено усмотрение за благото на организацията. С тях се злоупотребява, но ползите от тях надминават загубите.
Чувал съм твърдение, че има организации без такива, но тогава тези неща се случват, като определени хора поемат тези разходи от собствения си джоб. В повечето НПО-та е така и за това в счетоводството на доста от тях може да се намери “и за <нещоси> на тоя член му платихме толкова пари”, като нещото е от типа на “да стои и да изглежда добре”
край на скобата)

Второ, съвсем нормално и здравословно в една организация е да има някакво количество спорове и да се достига до решение с дискусия. Мисля си, че сме супер повредени от много години на “един спасител, който знае всичко”, но очакването да има един-единствен диктатор/ръководител/авторитет и той да е прав за всичко е идиотщина и като цяло сбъркано. Смислените лидери (думата не ми харесва, но не ми хрумва по-добра) не взимат решенията ей-така, без да се консултират, и дори в повечето случаи работата им не е да вземат решението, а например да решат кога има някакъв приблизителен консенсус или достатъчно голямо мнозинство за някакво решение, и да прекратят дискусията.
Много полезна е идеята за rough consensus, дошла от IETF. Може да се каже дори, че организации работещи на еквивалента за тях на “rough consensus and running code” (щото не всички живеят на код) са по-здрави и работещи от тези, които не го правят.

За това и аз лично много се зарадвах на записа от заседанието на ПП, на което обсъждат правителството с ГЕРБ – понеже е пример за всичките неща по-горе и за смислен процес по взимане на решение (въпреки че чисто практически изтичането на записа има неприятни последици). Може би след някакво количество години подобни записи ще се използват за обучителни материали :)

(изобщо, може да не съм от ПП, но от време на време Кирил Петков свършва нещо, с което ми се издига в очите, което като цяло е огромна рядкост за български политик)