blog.

Almost there.

  • Lab 3.0 – The Downsizening

    Lab 3.0 – The Downsizening

    Много неща се промениха, откакто писах за последно по тази тема преди 5 години.

    В един момент купих още един DL380e Gen8 с 32GB памет, повече ядра (два броя E5-2420) и място за големи дискове, но без caddy-та. Известно време бях с ESXi cluster, но не намерих много смисъл за моите нужди. Готино е да си местиш виртуалните машини от сървър на сървър, но бързо ми омръзна. След това вторият сървър стана Proxmox хост и си играх да уча и това. Имаше период, в който на Proxmox-а работеха Plex и много свързани с него неща. Само че липсата на дискретна видеокарта се оказа проблем, когато няколко пъти се наложи да се прекодират видеа заради невъзможността на клиента да гледа стрийма с пълна резолюция, та и това се пенсионира. Минах през толкова много софтуер, че няма шанс да си спомня всичко. Интересното е, че най-накрая флашнах iLO-тата на сървърите и мога да контролирам скоростта на вентилаторите. Това се оказа важно, след като се наложи да ги изместя в стаята, в която работя. Всички знаят, че излитащите изтребители звучат като HP сървър с вентилатори на 30%. Разбира се, ниските обороти доведоха до нуждата да лепя вентилатори по радиаторите на дисковите контролери. Няколко пъти получих и изключване, защото RAID картата на единия сървър скочи на над 100 градуса.

    Старият QNAP (TS-459) изгоря по чуден начин през 2021-а. Един ден един от предпазителите беше паднал без видима причина. Вдигнах го и забравих за случая. Малко след това получих нотификация, че единият Nextcloud не работи. Нотификацията беше стандартното “Мишо, това не работи!”.

    Машината, която хоства Nextcloud-а, беше пълна с логове за грешки по файловата система. Конкретният проблемен диск беше върху datastore, който беше mount-нат по NFS в ESXi. Беше забавно проследяване на проблема. Оказа се, че NAS-ът не отговаря на ping. Отидох при него и беше изключен. След като не реагира на натискането на копчето за включване, изтръпнах леко. В него бяха ~12TB неща, на които единствения бекъп към онзи момент беше RAID-а.

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

    В крайна сметка не загубих данни. Намерих приличен QNAP T-453A втора ръка, който и до момента работи (и е с външно захранване!). Новият NAS е и с 16GB RAM, което ми дава още място за игра. За миграцията използвах втория сървър, който към онзи момент си беше чист cold spare. Пуснах RAID контролера в HBA режим, сложих му Ubuntu и малко по малко изместих 12TB върху него. После ги местих към новия NAS. Всичко по гигабитова мрежа и терабитов стрес.

    Сега

    Основната промяна, поне в контекста на lab-а, е, че си купих къща, която довършвах сам в продължние на няколко години. Това ми даде възможност да направя много неща, които исках, точно както ги искам. Едно от тези неща беше да прекарам кабели за 10 гигабита мрежа навсякъде. Дори телевизорът в спалнята ми е с cat. 6a (flex, flex, но работи по WiFi).

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

    Rack

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

    12U
    Шкафът, след като е напълнен с основните устройства.
    Кога ще е по-подреден? По-подреден вече беше.
    (След снимката подредих кабелите. Честно!)

    Монтирането беше приключение. Монтирах го сам. В един момент го държах на глава, докато бях върху стълбата. Не паднах. Мерих всичко точно много пъти и въпреки това се наложи да пиля малко от гърба, защото свредлото хвана леко накриво и дюбелът не можеше да влезе в предвидения за това отвор. Дори да бях пробил права дупка, пак щеше да се наложи да пиля, защото дюбелите са 10 или 12mm, а отворите на шкафа са по-малки.

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

    Вдясно се вижда кутия за предпазители (не бушони). В нея има един 24A, след който сложих Shelly Pro 4PM. Това Shelly засега служи само за следене на потреблението на мрежата. Останалите три канала са предвидени за автоматизация на осветлението навън. Отгоре се вижда стария UPS, който ползвах временно, докато намеря как да събера APC-то вътре. Вляво висят двете влакна оптика, по които идва интернетът. Първоначалната идея беше да използвам двете връзки, за да е по-бързо, но и само едната ми е достатъчна.

    В момента в рака има следното, от долу нагоре: UPS, NAS, Raspberry Pi 4, мониторинг, суич, инжектор за едното AP, PDU, разклонител, рафт за ненужни неща, NVR, първия ми истински рутер (MikroTIk RB4011iGS+5HacQ2HnnD (накратко)), малко cable management, patch panel, много нетерминирани кабели, умен вентилатор и прах.

    Не предполагах, че нещо ще ми хареса повече от pfSense, но MikroTik-ът ме впечатли много. Основно с това колко много имам да уча и колко много възможности ми дава за това. Върху него пуснах WireGuard, който замени OpenVPN-а от предния път. Настроил съм и NAT към Raspberry-то, което е входната точка отвън.

    Raspberry-то върши най-важната работа след рутера. Върху него се търкалят: Home Assistant, AdGuard, HAProxy и fail2ban. През HAProxy изкарвам всичко, което искам да е изкарано и го ползвам за SSL termination на всички сървиси, за които имам домейни. В момента има дефинирани около 20 backend-а, голяма част от които сочат към Apache с виртуални хостове или Nginx, който също сервира различни услуги според домейна, source IP-то или URL-а.

    Home Assistant

    Друго важно нещо, което е свързано към pi-чето е Zigbee dongle-а. Така изглежда Zigbee мрежата преди да съм сложил всички неща, които подготвих за слагане:

    В един момент реших, че колкото и да ми харесва да си правя устройствата с ESPHome, трудно ще бия леснотата, която дават готовите Zigbee играчки. Това, разбира се, не означава, че спрях да си правя такива. Последното, което започнах, е RFID управление за врата. Остава ми само да взема електронна брава, която да управлявам. За Zigbee устройствата използвам Zigbee2MQTT, което е един от малкото софтуери, които работят безпроблемно (след като имах мъки при подкарването).

    Споменах умен вентилатор. Умен е, защото се управлява от едно ESP8266, което е програмирано с ESPHome. Така мога да го виждам в Home Assistant и да правя автоматизации според температурата в рака или да го управлявам ръчно:

    Мониторингът в рака използва един от модулите, които правих за умната шамандура, а именно този с BPM180 и DHT11. Към тях добавих и вече споменатия Dallas DS18B20, който следи температурата навън. Тези сензори са свързани към друго ESP8266, което също е програмирано с ESPHome. Сложих му и един 7-сегментен дисплей, на който се въртят температурата и влажността в рака.

    Home Assistant е безкрайна тема. Толкова ми харесва, че избирам уредите според това дали мога да ги интегрирам лесно. Използвам го за всичко, което може да се автоматизира. Като се комбинират готовите Zigbee решения с елементарното правене на автоматизации, решаването на “проблеми” става изключително лесно. Може би най-простия пример е лампата в пералното – просто качих един Sonoff SNZB-03 на вратата, сложих едно ZBMINIL2 в ключа и автоматизирането отне няколко клика. Вече няма как да забравя лампата в пералното светната ¯\_(ツ)_/¯.

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

    Тъй като мога да пиша прекалено много за Home Assistant, ще спра тук. Набира доста популярност последните години, та няма да кажа нищо нечувано. Може би ще пиша пак по въпроса, ако реша да споделя някоя custom интеграция.

    Сървъри

    Големите сървъри вече спят и са пенсионирани. Работата им пое стария десктоп (i7-4790k, 32GB RAM), на който сложих Proxmox и мигрирах виртуалните машини от ESXi. Миграцията се оказа лесна и с минимални драми.

    Оставих три виртуални машини, които ми покриват всички нужди. На едната са всевъзможни сървъри (PostgreSQL, Redis, Rabbit, etc.), на другата работят NextCloud и transmission-daemon (за Linux ISO-та). Третата е просто docker host, който използвам за тестване на контейнери. Най-важното там е docker registry-то, което използвам за CI/CD на някои лични проекти.

    Пенсионирах Jenkins и k8s. Вероятно скоро пак ще вдигна k8s cluster, защото имам идеи за нови играчки.

    Използването на обикновен десктоп има доста плюсове, като по-малкото потребление на ток и по-малкото шум, но и странни минуси като липса на iLO. Засега нямам проблеми с consumer hardware-а, но все пак настроих бекъпи на нещата, които са ми важни. В някой бъдещ момент вероятно ще му сложа 10GbE карта, за да мога най-накрая да си ползвам бързата мрежа вкъщи. Друго, което смятам да сложа, е и дискретна видеокарта, която да ползвам за прекодиране на видео.

    Блог

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

    Единствената причина да продължавам да се боря със споделени хостинги беше, че ми дават имейл без да се налага да го поддържам аз. Тъй като да поддържаш собствен мейл сървър е специална форма на мазохизъм, дълго време беше оправдано. След като Голяма Хостинг Компания Х купи хостинг провайдъра, който ползвах и започна да вкарва “добрите” си практики, реших, че е време да се мигрирам. Проблемът с имейла го реших с Google.

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


  • GeoStuff-1.2

    GeoStuff-1.2

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

    Оказа се, че е полезна на много хора и вече 11 години след първата си версия продължава да се тегли и използва сравнително често.

    Снощи пуснах нова версия за първи път от 2016-а с разни малки подобрения по интерфейса, с които ми се струва, че ще е малко по-удобно:

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

    Имам започнати още няколко неща за десктоп и Android версиите, но винаги имам нещо по-спешно и не остава време да ги донапиша.

    Повече информация има на страницата на програмата: тук.


  • Да отида ли на работа днес?

    Да отида ли на работа днес?

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

    Преди 5-6 години написах страница с таймер до 18:00, която се хареса на доста колеги. След това ѝ добавих и таймер до деня в месеца, в който обикновено идват заплатите.

    Преди няколко дни реших да инвестирам $2.40 в .eu домейн (имам проблем с купуването на домейни) и така се роди идеята за “Да отида ли на работа?“.

    Изборът на .eu бе продиктуван единствено от цената. По-евтин беше само .xyz, но с .eu ми харесва повече.
    Купуването на домейна оказа интересно приключение. Тъй като .eu се смята за ccTLD, трябваше да докажа, че наистина живея в ЕС. Това го разбрах, след като 24 след купуването на домейна, все още не се бяха опреснили DNS записите.

    Така научих за EURid, където домейнът ми излизаше със статус “Server Hold”. След писане до съпорта на регистрара ми, разбрах, че трябва да пиша на WHOIS accuracy отела на EURid.
    След няколко часа имейли и пращане на личната ми карта до тях ми казаха, че не могат да намерят адреса ми. Стана ми интересно как така адресът ми не се намира – дали в данните, които регистрарът ми праща към тях или нещо друго. Явно и на тях им писна да се занимават и да губят време с това, защото ми звъннаха (от доста скрит номер) да се разберем.

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

    В крайна сметка заради опитът ми за глупава шега няколко души от EURid са ровили в Google Maps да ми търсят адреса по лична карта (който си е странен, но съвсем реален).

    За този проект използвам Nuxt и Vuetify. Изключително приятни са ми за работа – с Nuxt избягвам голяма част от безумията на JavaScript*, а с Vuetify не пиша CSS. В последно време ги използвам за всичко, на което ми трябва бързо да има фронтенд.

    Засега deploy-ването се случва чрез npm run build && scp -r dist/* аз@хост:/ей/там.

    От 09.01 до днес има около 600 уникални посещения. Това е най-успешният ми проект за тази година (също и първия завършен за този период).

     

    Update: Преди да умре интереса имах около 2000 посещения на ден. Все още е най-успешния ми проект за 2020 🙂


  • Lab 2.0

    Lab 2.0

    Не очаквах нещата да се развият толкова бързо. Мрежата вкъщи се разрасна с няколко нови попълнения, като двете основни са HP ProLiant DL380e Gen8 и QNAP TS-459 Pro II.

    Малко след като се оплаках, че старият сървър ми струва излишно много пари за ток, попаднах на добра оферта в eBay и в момента основният ми сървър изглежда така:

    CPU 2*Intel(R) Xeon(R) E5-2407 @ 2.20GHz
    RAM 120 GB DDR3 (non-ECC)
    RAID 0 Самотно 960GB A-data SSD
    RAID 5 3*480GB Kingston SSD в RAID 5

    So much room for activities!

    Хардуерът е малко по-нов и мога да използвам ESXi 6.0 (HPE Image, Update 3). Засега не усещам особени разлики от 5.5, освен че мога да избера Debian 8 като най-нова дистрибуция при създаването на виртуална машина.

    След всички “подобрения” мрежата изглежда долу-горе така:

    Новите джаджи са: суич с пасивно охлаждане за “сървърното”, access point от Ubiquiti и, разбира се, двата нови сървъра. На диаграмата по-горе липсват виртуалните машини и VPN-а към droplet-а в DigitalOcean и хостинга в SiteGround.

    HP

    Забавата започна още с пристигането на сървъра. Не знам дали по време на транспорта или преди това му се е случило нещо, но единият му край е изкривен. За щастие е този със серийния порт и не ми пука особено много за това. Ще го мисля, когато стане време да го вкарвам в истински шкаф.

    Като изключим това изкривяване, всичко друго работи идеално.

    Знаех, че 2U машините са шумни, но не очаквах да е толкова шумно. Прекарах близо 8 часа първия ден да разбера защо всички вентилатори са постоянно на 20%. След всевъзможни ъпдейти, флашвания и версии на ESXi се оказа, че е заради 4-портовата LAN карта, която седи на единия PCI riser. Разкарах я и вентилаторите се оправиха.

    Научих, че това с вентилаторите е основен мотив в работата с HP сървъри – ако нещо не му харесва, получаваш излитащ реактивен самолет. Хубавото е, че не винаги можеш да разбереш какво не му се харесва. В крайна сметка нещата се нормализираха и вентилаторите работят между 7 и 19%, което го прави по-тихо от настолния ми компютър. Ако не ми писне да си играя с истински машини, смятам, че следващият ми сървър ще е някой стар Dell. При тях поне вентилаторите могат да се регулират през IPMI.

    Миграция

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

    Преди да дойде QNAP-а, важните ми данни бяха на една от виртуалните машини, която ги сервираше през Samba и NFS. Върху един (чисто нов) диск в RAID 0, който често казваше това:
    Без да имам бекъп.

    Подозирам, че диска се дънеше заради моя грешка. На NAS виртуалната машина бях заделил 800GB виртуален диск, но “thin provisioned”. Всичко е хубаво, докато не стигнем момента, в който на един datastore има много машини с thin provisioned дискове и започнат да се карат, защото сумарно обещаният им капацитет е невъзможен. Все още само подозирам, защото не ми се губи време и енергия в репродуциране на проблеми с данни, които са ми важни. Освен това се случваше само при последователно четене и писане на няколкостотин гигабайта.

    В момента тази виртуална машина държи основно NextCloud и transmission. Чакам момента, в който ще си допиша скрипта за правилно копиране на данните по правилните места, за да не местя на ръка, каквото ми трябва. Най-вероятно този момент ще дойде, след като диска се предаде изцяло.

    Най-хубавото на новата машина (освен 120-те GB RAM) е, че дърпа между 75 и 95W от контакта (според Ubiquiti mPower). Това е при 10-11 работещи виртуални машини със средна натовареност. За сравнение – предният дърпаше 256, докато не прави нищо. Relevant Grafana:

    Преди и след

    Подобрих и скрипта за scrape-ване на цената на тока. Все още тормози сайта на енергото постоянно, но поне вади точна цена.

    Друго интересно нещо за този сървър е и това, че съм принуден да държа един SAS диск в него иначе вентилаторите пак скачат на 20%. Без този диск потреблението му пада и под 69W. Причината за това е, че някой не може да прочете правилно температурата на не-HP дисковете и се паникьосва. Оставяме спорът за proprietary lock-in темите за друг път.

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

    Услуги

    С многото памет идва и много място за игра. Към момента има 12 виртуални машини, като постоянно работят 11 от тях, а 8 са сложени с autostart. Сред по-интересните нови услуги, които пуснах са: Home Assistant, UniFi Controller, Kubernetes и Portainer.

    В Home Assistant засега само следя кой колко ток дърпа.

    Разклонителят, на който са вързани сървърите и AP-то, праща статистики към Home Assistant по MQTT.

    Само бях чувал колко са удобни нещата на Ubiquiti. Инсталацията на контролера и adopt-ването на AP-то са елементарни. Работи толкова стабилно, че забравям за съществуването му. За разлика от предишното решение за WiFi, при което трябваше да рестартирам рутерите през ден.

    Подкарването на Kubernetes cluster-а се оказа по-трудно, отколкото очаквах. Кой да предположи, че четенето на документация ще помогне. Крайният резултат е, че имам работещ cluster с един master и 4 node-а.

    Целта е някои задачи в Jenkins-а спокойно да си пакетират image-ите и ги деплойват върху Kubernetes. За това пуснах машина с Portainer, на която върви контейнер с Docker Registry, където се намират няколко проекта, които трябваше да са пробни, но вече над месец са продукционни. Контейнери върху контейнери, върху контейнери…

    Недостатъкът в момента е, че за всяко приложение добавям правилата в HAProxy ръчно вместо да го пусна като ingress controller. Някой ден може и до това да стигна.

    Покрай цялата работа с много машини и контейнери, върху които трябва да се изпълняват едни и същи команди, започнах да си играя с Ansible. Така правенето и развалянето на клъстера се свеждаше до викане на няколко Ansible ad-hoc команди вместо да се логвам на 4 машини и да пиша едно и също. Наложи ми се да създавам клъстера (поне) 6 пъти преди да разбера какво правя грешно и да стигна до работещо решение.

    Шкаф

    Наложи се да сглобя “шкаф” за всичката техника, защото нещата започнаха да изглеждат много зле и чистенето на прах беше зор.

    Преди

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

    В SOLIDWORKS изглеждаше лесно – 12U шкаф с масивни стени, добро охлаждане и т.н.

    Реалността е малко по-различна

    Отзад има какво още да се желае

    QNAP

    Всичко е прилежно подредено!

    За QNAP-а нямам много за казване. Също като продуктите на Ubiquiti, това просто работи и забравям, че го има. Взех му 4 диска по 4 TB, за да съм сигурен, че ще имам сигурно място за важни неща още известно време. Дисковете са в RAID 5, а не 6, защото съм лаком за място. Така 4 диска по 4 TB ми дават малко над 10 TB използваемо място. След преместването на всичко от стария сървър и старата “NAS” машина, от 10-те терабайта останаха 8.59 TB. Надявам се да изкара няколко години преди да ми се наложи да го сменям, защото максимумът на volume, който може да се направи на тази машина е 16TB, което означава, че текущата конфигурация е максимумът, който мога да имам в RAID 5 без да правя компромиси. На теория можеше да сложа и 4 8-терабайтови диска, но тогава излизам от официално поддържаните конфигурации и ще е трудно да правя промени по масива.

    Докато чаках да дойдат големите дискове, бях сложил един 2 TB и вместо да копирам всичко, реших да опитам да мигрирам от RAID 0 към RAID 5 с няколко 4 TB диска, след  което да махна малкия и да мигрирам към RAID 5 с пълния капацитет на дисковете. Това се оказа изцяло ненужно упражнение, защото беше бавно (ден и половина) и в крайна сметка направих всичко наново. Онлайн RAID миграцията също е интересно нещо.

     

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


  • Amazon

    Amazon

    В края на миналия месец бях на onsite интервю в Amazon за позицията Software Development Engineer, която щеше да ме закара в офиса им във Ванкувър. Ставаше въпрос за екипа в AWS, който работи по Step Functions.

    Не ме харесаха.

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

    Интервютата в Amazon са много интересно преживяване. Общо взето минават така:

    1. Някаква комуникация с рекрутър, инициирана от една от двете страни,
    2. Онлайн оценяване,
    3. Телефонен разговор с рекрутър,
    4. Onsite интервю.

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

    На едната задача покрих само 10 от 16 теста, но въпреки това минах напред към телефонния разговор. Там мина добре и с рекрутърката си говорихме много странични неща. След разговора започна организирането на onsite интервюто.

    Прекарах около месец в почти денонощно учене на всевъзможни неща от компютърните науки. Започнах от основните структури от данни и алгоритми и реших доста примерни задачи от интервюта в Google, Microsoft и Amazon. Освен основите се очаква и познание по системен и архитектурен дизайн. За това наблегнах на примери като “как скалирахме Dropbox” и “как се оправяме с хилядите (буквално) microservice-и в Uber”. Това че вкъщи имам Kubernetes клъстър и си играя с истински сървъри също помогна много.

    Bit manipulation в самолета към Виена

    Onsite интервюто беше в Будапеща. За тези интервюта пише всевъзможни страшни истории, но моето беше приятно и с много по-лесни въпроси, отколкото очаквах. Цялото нещо представлява 4 интервюта от по час. Всички са едно след друго и има малка почивка, ако си поискаш.

    Хората бяха интересни, приветливи и с удоволствие ми обясняваха подробности за работата в Amazon.  Заради NDA-а не мога да споделя по-конкретни детайли.

    Едно интервю протича основно в три части:

    1. Интервюиращият се представя (не винаги) и задава въпроси за поведение, които се базират на Amazon-ските лидерски принципи. “Кажи ми за случай, в който си получил отрицателна оценка в работата си”, “случай, в който си постигнал добри резултати за кратко време” и всякакви такива. Очакват отговорите да са структурирани по определен начин и да покриват възможно най-много от принципите,
    2. Задача за програмиране върху бяла дъска (моето беше на лист хартия). Тук освен стандартните алгоритмични задачи има и едно интервю за системен дизайн,
    3. Въпроси към интервюиращия. Питах почти всички дали им харесва да работят в Amazon. Не питах само този, който е там от 16 години. Отговорите бяха различни варианти на “Сериозно ли?” и “Ти как мислиш?”. Някои питах как спят спокойно, знаейки че ако нещо се счупи, ще влезе в новините. От това научих много за начина им на работа и всички failsafe-ове, които имат.

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

    Последното ми интервю беше с hiring manager-а (този, който има най-много тежест в решението за наемане). С него си говорихме много странични неща и се смяхме доста. Не знам колко е добре това, защото всички интервюиращи си водят обилни записки, които сравняват после и на база тях се взема решение за наемане. Този по едно време си затвори лаптопа и започнахме да обсъждаме дизайна, който му рисувам. Накрая ми каза, че ме е харесал и е почти сигурен, че ще си говорим пак. Явно това е заучена фраза, за да не се шашкат кандидатите.

    Особеното при Amazon е, че много държат на познаването и прилагането на техните си Leadership Principles. Разликата с други компании, които имат големи твърдения е, че тези наистина спазват нещата, които говорят. Поне по моите наблюдения и разкази от хора, които работят там.

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

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

    Представите на Amazon за начин на разработване на софтуер са много близки до моите и ще ми е много интересно някой ден да успея да играя с големите деца. Дотогава – return; return; и ще решавам задачи в LeetCode от време на време.


  • Нова версия на приложението за чистене на линкове

    Може да е малко нарцистично, но приложението ми за махане на глупости от URL-и ми влиза в употреба постоянно и му се радвам много. Когато не ми се налага да разкарвам tracking параметрите ръчно, споделянето става по-лесно, което пък увеличава честотата на спама, който пръскам насам-натам. Win-win.

    Малко след като пуснах първата версия, в приложението на Instagram (поне при мен) за известно време изчезна опцията за share и остана само “Copy Link”. Оттогава искам да направя нещо по въпроса, но поради една или друга причина това все оставаше на заден план.

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

    От Android 6.0 в менюто за избран текст може да се добавят елементи, които да работят с него по някакъв начин. Това става, когато някое Activity дефинира intent filter за PROCESS_TEXT.

    Long story short, направих го да ми е по-удобно и вече мога да правя така:

    И така:

    В зависимост от това дали избраният текст е read-only (EXTRA_PROCESS_TEXT_READONLY) разбирам какво да се покаже при Unwrap менюто (видеото отгоре).

    Освен промените по интерфейса оправих и глупав бъг в backend-а на приложението, заради който share-ването на текст от Twitter водеше до MalformedURLException.

    Засега ми върши идеална работа, но по-нататък ще го пипна малко. В момента след “unwrap” остава само първият URL. Другият текст изчезва. Освен това се работи и само с първия адрес от избрания текст. За момента не виждам смисъл да си усложнявам живота с обикаляне на неограничен брой адреси, които могат да имат (почти) неограничен брой redirect-и зад себе си.

    Друг потенциален проблем е, че няма дискриминация на избрания текст и двете ми менюта (Clean и Unwrap) се показват във всички случаи. Менюто, което само разкарва ненужните параметри и замества текста, е безсмислено в уеб страници, но засега не виждам умен начин да го махна. Потенциално решение е да оставя само едно меню и да добавя опция в настройките, според която да се избира дали само ще се почиства или ще се “разгъва” избраният текст. Засега не ми се усложнява толкова.

    И като край – приложенията ми в момента имат между 300 и 500 активни инсталации. Без нито един crash или ANR, откакто са пуснати 🙂


  • Lab

    Lab

    Update: Lab 2.0

    Както писах преди, от доста време искам да имам физически сървър вкъщи, който да си администрирам и гавря, както реша. В началото на годината по щастливо стечение на обстоятелствата това се случи и в момента се радвам на един HP ProLiant ML350 G5.

    Това се оказа несвършващ проект и от януари не съм спирал да си играя и да уча нови неща. От по-важните услуги, които се търкалят засега, са: OpenVPN, HAProxy, Let’s Encrypt, Pi-hole, FreeNAS, Jenkins, Graylog, Transmission и NextCloud.

    Сървър

    Първо спецификациите на сървъра в текущото му състояние:

    CPU Един Intel Xeon E5440 @ 2.83GHz
    RAM 32GB FBDIMM ECC (8 по 4GB)
    RAID 5 3*250GB
    RAID 0 1*2TB

    За момента RAID конфигурацията е такава, защото: а) не съм купил дискове за повече и б) нямам caddy-та за останалите два слота. Предстои ми доста интересно приключение, когато реша да разширявам storage-а. Нямам търпение rebuild-а на някой масив да гръмне. Най-вероятно ще трябва да купя още един RAID контролер и да присадя drive cage на мястото на CD-то, за да има къде да сложа всичките дискове, които искам. Шест 4-терабайтови диска в RAID 6 биха били достатъчни за известно време.

    На RAID 5 масива се намира ESXi 5.5 (HPE image) заедно с datastore-а за някои виртуални машини. На самотния 2TB диск е storage-а на NAS-а, където има разни важни файлове.

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

    Малко след като нарисувах горната графика, lime2 се пенсионира и вече не е backup OpenVPN. Намира се в процес на прехвърляне на всички неща от стария OwnCloud и backup partition към NAS-а. Тази малка машинка беше цялата ми инфраструктура допреди няколко месеца.

    Чувството всички (важни) машини да са свързани през гигабитова връзка е прекрасно! Мога да редактирам видео файлове в Premiere Pro, които се намират върху FreeNAS-а, който работи върху една от виртуалните машини, без да усетя някакво забавяне. Няколко клиента спокойно стриймват видео файлове през SMB, nfs и каквото още дойде, без да има никакви проблеми*.

    Най-накрая подкарах и Grafana, която да ми харесва и върши работа, а не да е просто eye candy. Повечето данни идват от Telegraf, който ги събира по SNMP и ги пази в InfluxDB.

    По-интересните неща, като цената на тока и данните от ESXi, идват от един Python скрипт, който използва SDK-то за ESXi (pyVmomi). Оказа се значително по-лесно така, отколкото с Java SDK-то, което работи директно със SOAP-а на ESXi. Така и не можах да го подкарам.

    Цялата работа на скрипта е да се върже за VMware-а, да вземе данните, да scrape-не текущата цена на тока от сайта на Енерго-ПРО и да запише всичко в InfluxDB.

    Тъй като го писах с идеята да го оправя “някой ден”, сега при всяко изпълнение се обръща до сайта на Енерго-ПРО. Това води до интереснa статистикa за последните 24 часа в Pi-hole:

     

    Поиграх си доста и с ILO-то. Толкова е старо, че мога да го отворя само през Internet Explorer, защото само този браузър все още поддържа несигурни и стари SSL сертификати.

    Когато инсталирах втората партида от 16GB RAM, се сблъсках с друго интересно нещо. Заради изгоряла плочка прекарах няколко часа в дебъгване на проблема. В NVRAM-а на дъното се беше записало, че в дадения слот има изгоряла плочка и докато не го изтрих няколко пъти, не се събуди дори само със здравите плочки.

    Мрежа

    За основен рутер използвам pfSense, който работи върху един HP thin client. Тънкият клиент се оказа напълно адекватен избор за това.

    Външната връзка и WAN интерфейсът на рутера са сами на един VLAN, а на друг VLAN са всички останали устройства.

    За първи път настройвах суич през конзолен кабел с истинска цел, а не за упражнение. Прекарах няколко вечери до 3-4 сутринта, докато се стабилизира мрежата. Добре че имаше кой да ми даде акъл.

    Някога ще разделя клиентите на VLAN-и според предназначението им. Освен това ще е хубаво и да взема втори управляем суич с пасивно охлаждане. В момента в стаята ми е Zyxel-а, а вторият суич е истински, rack-mountable, 1U. Чувам го през две врати.

    За безжичните устройства ползвам два обикновени consumer рутера, които работят в режим AP. Доскоро работеха с едно SSID, за да покрия нявсякъде. Имаха проблеми с някои клиенти с по-стари wi-fi модули и ги разделих на две SSID-та. Някога ще бъдат смемени с UniFi AP-та.

    Първият ми тест на мрежата беше да копирам файл от основния компютър към NAS-а. Започваше със 100MB/s и почти веднага падаше на 1-2MB/s и надолу. След недоспиването от борбата с мрежите, вече бях напът да режа кабели, но пък netperf показваше, че мрежата успява да се запълни спокойно до гигабит.

    Така пак научих, че върху RAID контролерите съществува кеш (в случая – с неработеща батерия), който при неправилна настройка на read/write съотношението прави писането бавно (изненада!). След като го оправих, нещата се нормализираха и вече bottleneck-а при писане върху NAS-а е само скоростта на дисковете. Тук също се радвам, че имаше кой да ми даде светлина. В момента съотношението е 5/95 за четене/запис.

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

    Услуги

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

    Имах много време да мисля какво искам да използвам за NAS софтуер и накрая се спрях на FreeNAS. Минах през всевъзможни варианти много преди да имам физически съврър и FreeNAS върху виртуална машина ми пасна най-добре. Разбира се, има и някои недостатъци на виртуализирането, но досега не съм се сблъсквал със сериозни проблеми.

    Ако не друго, то поне охлаждането на процесора е адекватно. Все пак малко хора могат да се похвалят с процесори, които работят на температура под абсолютната нула.

    Върху FreeNAS-а работят няколко jail-а. Основните са Transmission и NextCloud. Благодарение на Transmission имам една директория в share-а на NAS-а, която се следи за torrent файлове, които автоматично се добавят за теглене. Изтеглените неща се намират в друга директория, достъпна от всички устройства в мрежата. Така пиратстването свободното споделяне на медия с уредени авторски права е значително по-лесно.

     

    NextCloud-а ми служи основно за синхронизиране на файловете от телефона и разни маловажни неща между компютрите. Първо ползвах OwnCloud, който се хостваше върху малкото OLinuXino (Lime2). Доскоро за off-site backup ползвах NextCloud върху единия droplet в DigitalOcean, където добавих 50GB Volume, върху който трябваше да са само най-важните неща. След известни проблеми с rsync реших, че Google Photos ми е достатъчен за off-site въпреки компресирането.

     

    pfSense е доста полезен инструмент. Освен стандартните услуги, които трябва да предоставя един рутер (DHCP, DNS, etc.), в момента върху него работят доста неща, като по-интересните са: HAProxy, OpenVPN и plugin, който се грижи за Let’s Encrypt сертификатите.

    OpenVPN-ът ми върши идеална работа. Няма много за писане откъм конфигурация, защото интерфейсът на pfSense е достатъчно прост и цялата работа се свежда до нацелване на разни стойности. Предишният VPN, който бях подкарал върху OLinuXino-то, беше по-интересен, защото цялата инсталация беше на ръка с всичките генерирания на сертификати за сървъра и клиента, както и настройването на рутирането и firewall-а. В pfSense всичко е графични интерфейси.

    Сега мога да се закача за мрежата вкъщи, където и да съм, и с едно mount nas.miskin.in:/mnt/whatever /mnt/nas/ имам достъп до NAS-а.

    Не бях работил с HAProxy преди това. Засега имам 20 frontend-а и 13 backend-а. Фронтендите са разделени под два основни за услугите с и без SSL. В общия случай са огледални – вместо да се реже достъпа без SSL, има frontend, който прави 301 redirect към същия адрес, но с “https://”.

    20-те фронтенда могат да се свият до два, но засега така ми изглежда по-подредено и лесно за поддръжка. Бекендите са толкова малко, защото на Apache-тата отзад са конфигурирани виртуални хостове и е достатъчно да закарам заявката до правилната машина. След това уеб сървърът се дооправя с рутирането.

    Както казах, повечето услуги работят през https. Това става благодарение на Let’s Encrypt. Оказа се малко по-интересна заигравка с HAProxy, за да мога да отговарям правилно на challenge-ите, които идват от Let’s Encrypt при издаване и подновяване на сертификати.

     

    Ако не си личи, мразя рекламите с яростта на 1337 слънца. Благодарение на това всички компютри, до които имам достъп, веднага биват снабдени с някакъв AdBlock софтуер. С телефоните това се оказва излишно сложно и неудобно – не искам да ползвам друг браузър, не искам да root-вам телефона и т.н. За спирането на поне част от рекламите върху устройствата в мрежата използвам  Pi-hole. Тъй като все още нямам Raspberry Pi, се наложи да инсталирам Pi-hole върху старото OLinuXino (a.k.a sexy). Не му пречеше особено, че прекара няколко години затворено в кутия и в момента всички DHCP клиенти в мрежата (дори някои от тези с резервирани адреси) го ползват като главен DNS. Получи се доста добре и не усещам никакво забавяне, където и да е. Не помня всички проблеми, които излязоха по време на “инсталацията”. Помня само, че ми се наложи да ровя из инсталационния скрипт, защото имаше допуснати разни предположения за системата, които може и да са верни за Raspberry Pi, но при OLinuXino седят по различен начин. Намерих и полезен скрипт, който събира статистика от Pi-hole в InfluxDB (pi-hole-influx) за ползване в Grafana.

     

    Друга основна услуга, която ползвам редовно, е Jenkins. Инсталирането и конфигурирането са тривиални. Забавата тук е при конфигурирането на job-овете.

    Разделил съм ги на основно два типа – backend и frontend. Backend job-овете се отнасят до Spring Boot проекти, а другите – Node JS базирани (най-често Vue). Всеки един job се задейства при push в конкретен бранч на конкретен проект. Това става с прост hook в GitLab. Тук идва едно от многото удобства на HAProxy – понеже не исках Jenkins да се вижда извън локалната мрежа, настроих Jenkins frontend-а да приема заявки отвън само от GitLab.

    Общо взето за всички проекти правя build и deploy по сходен начин. Java проектите се компилират и пакетират с Gradle. Преди build-а Jenkins се закача за сървърa, на който ще се деплойва, и затрива старите jar-ове. След това се нагласят конфигурационните файлове, с които трябва да работи Docker Image-а (cp log4j2_docker.xml log4j2.xml например) и се започва с Gradle-а. При успешен build готовия jar се копира на целевия сървър и се trigger-ва job-а за redeploy (ако за конкретния проект ми трябва автоматичен redeploy).

    Redeploy job-овете са изключително прости. През SSH се закачам към сървъра, където ще се деплойва, правя Docker Image от jar-а, спирам, изтривам и стартирам наново контейнера, в който работи приложението.

    При неуспешен build си пращам имейл, за да знам, че нещо се е омазало.

    За фронтенд проектите е аналогично. Разликата е основно в това, че вместо gradle build се извикват npm install и npm run build.

     

    Споменах, че за Spring приложенията се налага използване на различна конфигурация. Причината за това е, че някои от страничните проекти заживяха интересен живот и се наложи да са достъпни публично. Така приложението се налага да може да работи на три среди – local, dev и prod. Очевидно е какво е local. Dev средата се използва при изпълнение на тестовете по време на Jenkins build-а, а prod е това, което се вижда, когато проектът се достъпи публично.

    Засега използвам Graylog за събиране на логовете от всички приложения. Това, обаче, ми излиза скъпо, защото на една машина вървят ElasticSearch, MongoDB и Graylog. На практика излиза, че 10GB RAM са недостатъчни, когато идват над 20 съобщения в секунда и се усеща забавяне. Излиза ми скъпо, защото потреблението на ток на сървъра скача осезаемо, когато се върши някаква работа с Graylog и се хабят изчислителни ресурси нещо, което може да се реши по по-лесен начин.

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

     

    Освен всичко описано дотук, по разните виртуални машини вървят всевъзможни други услуги: MySQL, PostgreSQL, RabbitMQ, Redis и още, и още. Все още успявам да се справя с поддръжката на всичко сам и ми е все по-интересно. По-горе писах, че използвам GitLab. Смятам скоро да си пусна една инстанция при мен, за да видя дали все още е толкова лаком за ресурси.

    Проблеми

    Основният ми проблем със сървъра е, че като сравнително стара enterprise машина, не е обърнато много внимание на ефективността на потреблението и във всеки един момент дърпа около 256W. Това е при включено само едно от двете 1000W захранвания. При две idle потреблението скача до около 280W. Грубата сметка идва около 40лв. на месец (без ДДС и всички такси: за пренос, загуба, “да има” и др.). Не е най-скъпото удоволствие на света, имайки предвид колко много неща мога да уча благодарение на него, но като знам, че мога да ги постигна с по-малко похабена енергия, ме човърка.

    Друг проблем е шумът от вентилаторите. С качването на температурата през последните седмици, все по-често заварвам следната гледка:
    Интересно е, че при по-ниска температура навън паметта достига 75-76 градуса без да вдигне осезаемо скоростта на вентилаторите. Въпреки това, суичът си остава по-шумен.

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


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

    След включването на всичко, изненадващо, имах само един малък проблем – конфигурацията на суича не се беше запазила и SNMP-то му беше спряно, заради което в Grafana-та не излизаха статистиките за него. Всичко друго заработи без да се оплаква.

    Оттук нататък приоритет ми е събирането на дискове за разширяване на storage-а, тъй като той ми умалява най-бързо. Може би и втори процесор, за да няма празни дупки.

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

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


    *Ако не броим нестабилността на sshfs и nfs mount-овете на лаптопа, които решават да потрошат всичко, когато го приспя и събудя. Някой ден ще дойде и неговия ред.


  • Използване на Java Reflection API за мързелива “документация” на response кодове

    В единия от страничните проекти използваме REST за комуникация между фронтенда (Vue) и бекенда (Spring Boot). Приложението е сравнително просто и пиша бекенда сам и за документация на REST-а използвам Swagger. Това значително услеснява имплементацията на фронтенда откъм информация за endpoint-и и кой какво може да очаква като заявка/отговор.

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

    Механизмът, на който се спрях за връщане на грешките към потребителския интерфейс, е сравнително прост и не е нищо ново – при грешка в бекенда към клиента се връща DTO с цифров код и пояснителен текст. Пояснителният текст служи само за улеснение на пишещия фронтенда. Локализацията на грешките, ако се наложи да има такава, ще се случва във Vue приложението според цифровия код.

    В Spring това се имплементира изключително лесно. При неправилно действие (няма достъп, липсва задължително поле и т.н.) се хвърля Exception (в случая – ErrorResponseException), който се прихваща от @ExceptionHandler и към клиента се връща DTO-то с нужния код и текст. За имплементацията на този механизъм са нужни няколко основни неща:

    • Номенклатура на кодовете на грешки и клас, описващ формата на отговора, който очаква Vue приложението,
    • Някой да прихване Exception-а,
    • Exception за прихващане.

    Номенклатурата е обикновено POJO със статични методи за всяка грешка:

    import lombok.Data;
    
    @Data
    @AllArgsConstructor
    public class ErrorResponseDTO {
    
        private Integer code;
        private String message;
    
        // 500
        public static ErrorResponseDTO generalError(Throwable t) {
            return new ErrorResponseDTO(500, "I can't even: " + t.getMessage());
        }
    
        // 1401 - JWT token expired
        public static ErrorResponseDTO tokenExpired() {
            return new ErrorResponseDTO(1401, "Token expired");
        }
    
        // 1402 - Invalid JWT token
        public static ErrorResponseDTO invalidToken() {
            return new ErrorResponseDTO(1402, "Invalid token");
        }
    
        // ...
     
        // 1409 - User is not active
        public static ErrorResponseDTO userIsNotActive() {
            return new ErrorResponseDTO(1409, "User is not active");
        }
    
        // ...
        // Още много статични методи, описващи останалите грешки
        // ...
    }

    Горното може да се реализира по много начини. Засега това ме устройва. Не смятам, че проектът ще стане достатъчно сложен, за да оправдае разделянето на тази номенклатура от DTO-то или категоризиране на грешките в отделни класове, пакети, Exception-и и т.н.

    Прихващането на Exception-а става с @ControllerAdvice и @ExceptionHandler:

    @ControllerAdvice
    public class RestExceptionHandler {
        // ...
        @ExceptionHandler(ErrorResponseException.class)
        @ResponseStatus(HttpStatus.PRECONDITION_FAILED)
        @ResponseBody
        public ErrorResponseDTO processErrorResponseException(ErrorResponseException 
    e) {
            return e.getErrorResponseDTO();
        }
        // ...
        // Други handler-и за други exception-и
        // ...
    }

    Exception-ът е обикновен наследник на RuntimeException, който съдържа в себе си DTO-то:

    public class ErrorResponseException extends RuntimeException {
    
        private ErrorResponseDTO errorResponseDTO;
    
        public ErrorResponseException(ErrorResponseDTO errorResponseDTO) {
            this.errorResponseDTO = errorResponseDTO;
        }
    
        public ErrorResponseDTO getErrorResponseDTO() {
            return errorResponseDTO;
        }
    }

    С описаното дотук връщането на грешка става просто. Например, в Service-а за генериране на JWT токен има простата проверка дали конкретният потребител е активен. Ако не е, няма смисъл да му генерирам токен:

    if (userData.getUserStatus() != UserStatus.ACTIVE) {
        throw new ErrorResponseException(ErrorResponseDTO.userIsNotActive());
    }

    Така при неактивен потребител към извикващия клиент се връща този JSON:

    {
        "code": 1409,
        "message": "User is not active"
    }

    Логиката за потребителския интерфейс е изцяло в клиентското приложението. Дали ще се покаже директно върнатият текст или според кода на грешката ще се случи нещо, няма значение. Целта е пълно отделяне на логиката по обработване на грешката (ако така се превежда decoupling). Няма значение дали клиентът е Vue, Android или Swing приложение – отговорността е негова.

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

    Можеше вместо рефлексия да използвам анотациите, предоставени от Swagger за този случай (@ApiResponses и @ApiResponse) върху всеки метод на всеки контролер в приложението.

    Понеже рефлексията ми е интересна, се спрях на вариант с endpoint, който връща JSON с всички възможни грешки, които могат да се върнат към REST клиента. Тъй като всички грешки са дефинирани като статични методи на класа, който ги описва, алгоритъмът е тривиален:

    1. Вземам всички статични методи, декларирани в този клас,
    2. Викам ги един по един,
    3. Записвам резултатите в списък,
    4. Връщам списъка.
    @RestController
    @Slf4j
    public class ErrorListController {
    
        @GetMapping(path = "/errors-list")
        public List<ErrorResponseDTO> getErrorsList() {
            List<ErrorResponseDTO> result = new ArrayList<>();
            
            // Взимаме всички методи
            Method[] methods = ErrorResponseDTO.class.getMethods();
            for (Method method : methods) {
                try {
                    // Искаме само статичните методи
                    if (Modifier.isStatic(method.getModifiers())) {
                        Method declaredMethod = ErrorResponseDTO.class.getDeclaredMethod(method.getName());
    
                        // Викаме метода
                        ErrorResponseDTO invoke = (ErrorResponseDTO) declaredMethod.invoke(null);
    
                        // Добавяме резултата към отговора
                        result.add(invoke);
                    }
                } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
                    log.debug("Ignoring exception \"{}\": {}", e.getMessage(), e);
                }
            }
    
            return result;
        }
    }
    

    Адресът на този контролер (/errors-list) е разрешен в WebSecurityConfigurerAdapter-а само при определени условия и не се вижда в “продукционната” среда. Отговорът изглежда долу-горе така:

    [
      {
        "code": 1401,
        "message": "Token expired"
      },
      {
        "code": 1402,
        "message": "Invalid token"
      },
      {
        "code": ...,
        "message": "..."
      },
      {
        "code": 1409,
        "message": "User is not active"
      }
    ]

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


  • 2018

    2018

    Най-накрая свърши и тази. Изобщо не беше скучно.

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

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

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

    Какво друго се прави преди да сложиш новите гуми?

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

    Лигавщините с рязко спиране и “трениране” на екстремни ситуации по празни паркинги ме отърваваха от всякакви глупави ситуации. След като донякъде свикнах загубата на сцепление да не ме паникьосва, започнах малко по-спокойно да избягвам хората, които не зачитат предимството.  Последно влачих гума с наклонен мотор, за да не се кача върху капака на джип, който реши, че знакът STOP означава “Излез възможно най-бързо в кръстовището и спри в средата, за да се огледаш”.

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

    https://i.imgur.com/4JsNsW5.gifv

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

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

    ***

    Направих най-дългото си каране досега с двама души на мотора. Тръгнахме от Варна към Видин и се върнахме по различен път. Сумарно пътуването беше около 1300 километра, като първия ден карахме около 10 часа.

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

    Тази година обикалях значително повече и видях много интересни места. За първи път бях в Румъния. Беше интересно преживяване, докато не спуках гума по малоумен начин. Хората в Букурещ карат доста по-зле от троглодитите тук.

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

    ***

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

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

    За първи път бях при доктор, който е завършил през този век.

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

    След първата операция настояваха да ме карат с носилка на колела към стаята. Понеже съм алтернативно лек се наложи малко да се издърпам на излизане от асансьора.

    Беше интересно преживяване. 0/10, не препоръчвам.

    ***

    От миналата година ми е тръгнало приключване на 6-годишни неща. Къде по мое желание, къде – не. Тази година след малко над 6 години на първата ми работа напуснах и започнах на ново място. 12 години, след като започнах да уча Java, вече официално съм джавар. Забавно е и уча много нови неща. Още не мога да реша колко умно е да сменя голяма компания с тепърва развиваща се, но не съжалявам.

    ***

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

    ***

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


  • NAS

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

    Преди десетина години вкъщи се появиха няколко едва работещи компютъра. От тях си харесах единия за “сървър” и му закачих всичките работещи дискове, които намерих. Беше с някакъв Debian, където бях инсталирал стандартните неща, с които си играех тогава – Apache, lighthttpd, MySQL, WordPress и разни други такива. Тогава още нямах рутер и се налагаше нормалният компютър да споделя връзката към другите в къщата. Заради това ми се наложи да науча много неща за мрежи, ReverseProxy-та, красоти около iptables и как да си говорят няколко машини без да се карат. Веднъж отнякъде се появи и работещ RAID контролер – някакъв Adaptec. Не помня дали поддържаше SATA, но дисковете със сигурност бяха вързани с PATA (IDE) кабели. Нямах идея как се работи с това, но пък бях чувал, че е добре да има RAID, затова директно вързах всички дискове към него и създадох масив. Кой да предположи, че това ще затрие всичко по дисковете…

    Оттогава започнах да чета и да чакам момента, в който ще си купя някоe 4U съкровище с поне два Xeon-а и няколкостотин гигабайта RAM, ще му сложа ESXi и ще забравя как изглежда светът през деня. През последните години не съм спирал да уча и да се интересувам от админски неща. В един момент бях стигнал до извода, че 40U rack може и да ми стигне, ако махна това-онова. Гледането на /r/homelab, /r/sysadmin и /r/datahoarder изобщо не помага.

    Проблемите ми с enterprise сървърите са основно цената и шума. Донякъде и потреблението на ток за определени модели.

    Съвременните неща ми идват неоправдано скъпи за играчка.  Миналата година начатках това от сайта на Supermicro:

    Едно такова за Коледа, моля

    Близо $50 000 чисто щастие – 44 ядра с hyperthreading (т.е. 88 “логически” ядра), 512 GB RAM, 10Gb мрежа и много storage.

    Винаги се намират стари сървъри из ebay или olx, но често идват без поддръжка и незнайно колко оставащ живот в тях. Сред най-известните стари и евтини сървъри, които намирам, е PowerEdge R710 на Dell. Звучи така при излитане. При пълен товар не е особено тих.

    Друг вариант са работните станции на Dell и Lenovo.

    Преди да сглобя текущия си десктоп за малко бях с един T7400 на Dell. Взех го, защото ми хареса колко модулно е всичко вътре, как има два сокета, тунел за охлаждането на процесорите, ECC и други красоти. Преглътнах, че е с DDR2, но това, че рамта работи на 60 градуса без товар, ми дойде в повече и го върнах.

    Последното ми решение да имам много storage и виртуализация вкъщи е да оставя текущия ми desktop с някакъв hypervisor или с FreeNAS и да сглобя нов. Към момента се радвам на i7-4790K с 32GB памет и няколко TB дискове. С пуснати няколко виртуални машини, търкалящи всевъзможни неща, не се впечатлява особено. Затова смятам, че ще му е добре да се преквалифицира като хост на FreeNAS или Proxmox. 

    За целта започнах да събирам чаркове за новата машина, която ще страда като desktop. Планът беше да е с i7-8086K, но започнах да се колебая дали да не е нещо с Ryzen. И без това има много време, докато стигна до купуване на части за нов компютър, защото идеята ми е да напълня 6-те SATA порта на дъното на стария и да използвам вградения RAID controller за RAID 5. Тъй като не бързам, купувам частите през месец-два. Вероятно е скоро да не сглобя нищо, но поне се движа натам.

    След като реша дали ще е с Proxmox или FreeNAS, мисля да пусна всякакви шаренийки. Първо ще преместя transmission-а, който работи върху едно OLinuXino със закачен диск на него, защото е напът да си отиде. След това идва реда на Plex, Nextcloud, Sickrage или Couchpotato и всякакви такива. Ще му пусна и нещо подобно на pi-hole, за да имам ad block на ниво DNS на всички устройства, които се вържат за мрежата тук. Разбира се, всичко това ще трябва да е достъпно по сигурен начин, ще трябва да си играя с потребители, сертификати и една камара други глупости. 

    Нямам търпение да видя какви проблеми ще ми създаде това начинание 🙂