Пишемо консольний двопанельний менеджер на Linux shell
Привіт, мене звати Сергій, я працюю DevOps інженером в компанії Luxoft. Хочу розповісти, як лінь допомогла мені написати непоганий, як мені здається, «велосипед».
Багато хто з розробників недооцінює або некоректно ставиться до Linux Shell, порівнюючи його з іншими мовами програмування. Але не треба забувати, що найважливіше в Linux Shell — саме слово shell, тобто це не просто мова програмування для написання програм.
Це — оболонка операційної системи, що була написана системними інженерами для системних інженерів, і вона досить потужна та універсальна, щоб автоматизувати та спростити майже всі рутинні операції без застосування зайвих мов програмування.
Вона оперує не бібліотеками, а програмами (безліч GNU tools та все, що ви можете знайти та написати самостійно — легко інтегрується з оболонкою). Також вона слідує у першу чергу не за стандартами мови програмування, а за стандартами операційної системи. Тому навіть базові знання про те, як працює операційна система, покращать ваше володіння Linux Shell.
Про сертифікати
З того моменту, як HTTPS почав наступ на інтернет, майже у кожному проекті використовуються сертифікати. Зазвичай, їх є кілька видів:
- ті, які кожен може згенерувати сам;
- ті, які видав корпоративний CA;
- безкоштовний публічний сертифікат від Let’s Encrypt;
- або комерційний сертифікат від IdenTrust чи DigiCert та інших центрів сертифікації, що представляють додаткові функції, наприклад перевірку компанії, або державну акредитацію...
Також це може бути сертифікат для утворення tls/ssl каналу, або для авторизації на сторонньому сервісі, або сертифікат для створення двостороннього tls/ssl...
Якщо у вас багато сертифікатів, скоріше за все, ви користуєтесь сховищами — keystore, такими як JKS (Java keystore, що набув статус legacy з виходом дев’ятої версії Java) або PKCS12. Останній використовується майже 20 років, і не дивлячись на критику, є одним з найпопулярніших надійних відкритих форматів, що мають повністю витіснити JKS у недалекому майбутньому.
Я багато працював у проектах, де основною мовою програмування була Java, тому в мене основний інструмент для роботи з JKS — keytool, що йде разом із JDK.
Звісно, в мене є і невеличка шпаргалка з командами, такими як:
1. Вивести список сертифікатів
keytool -list -v -keystore "файл.jks" -storepass "пароль"|grep -P '(Alias name:|Entry type:|Serial number:|Owner:|Valid from:)'
2. Скопіювати сертифікат із одного keystore в другий keystore
keytool -importkeystore -srckeystore "KEYSTORE_FROM.jks" -srcstorepass "SOURCE_PASSWORD" -destkeystore "KEYSTORE_TO.jks" -deststorepass "DESTINATION_PASSWORD" -srcalias "CERT_ALIAS" [ -destalias "NEW_CERT_ALIAS" ]
3. Завантажити сертифікат в keystore із PEM файла
keytool -import -file "FILE_FROM.pem" -keystore "KEYSTORE_TO.jks" -storepass "KEYSTORE_PASSWORD" -noprompt -alias "CERT_ALIAS"
4. Вивантажити сертифікат із keystore в файл
keytool -exportcert -v -alias "CERT_ALIAS" -keystore "KEYSTORE_FROM.jks" -storepass "KEYSTORE_PASSWORD" -rfc -file "FILE_TO.cer"
Одного разу я працював у проекті, де було кілька десятків мікросервісів, безліч віртуалок у тестових середовищах, на яких розробники руками правили сховища сертифікатів і не було ніякого централізованого контролю. Тільки щоб розібрати все це та привести у якийсь системний вид, треба було все прискіпливо перебрати, порівняти, домовитись із розробниками на перехід до якихось стандартів.
Звісно, немає такого, що було б неможливо зробити, але сертифікати оновлювались не дуже часто, тому ніхто не збирався ставити це завдання у беклог — при необхідності, сертифікати поновлювали вручну до наступного разу.
Мені, як інфраструктурному інженеру, це не дуже подобалось, але обсяг початкової рутини та низький пріоритет змушував мене ходити колами та займатися іншими, більш важливими завданнями.
Час від часу я намагався знайти якесь магічне рішення, навіть ознайомився із графічною утилитою, але потрібного функціоналу там не було, та й політика компанії не дозволяла використовувати на десктопі програми без аудиту безпеки, що міг розтягнутись на рік.
Можливо, я б зібрався та за тиждень зробив би все однострічніками + блокнот + excel, але зненацька в мене сталась відпустка через хворобу, а коли температура дозволила сидіти за монітором, але ще не виходити на роботу, я згадав, що я ж мислю себе спецом на bash.
Тому зустрічайте: консольний двопанельний менеджер на Linux shell.
~35 кілобайт POSIX-сумісного Linux Shell.
Для роботи треба:
- не дуже старий шелл (ksh, bash, zsh)
- sed, grep
- keytool, що йде у поставці із JDK
Що вміє менеджер коротко можна наочно побачити на скриншотах, також працює справка по F1 або «H»
В одно-панельному режимі:
У двох-панельному режимі:
Для шанувальників панельних менеджерів (наприклад я жити не можу без FAR), таких як NC, VC, MC, FAR та ін., функціональні клавіші та навігація повинні бути інтуїтивно зрозумілими.
Що було найцікавіше під час розробки?
Спочатку я написав простенький скрипт на bash, вже із навігацією та першим функціоналом, але в якийсь момент в мене щось не запустилось на ksh. Я зрозумів свою помилку та переписав усе на користь POSIX-сумісності.
Код став виглядати більш громіздким, зате скрипт перевірено працює в bash/ksh/dash (навіть у git-bash, але із тормозами). Якщо щось пропустив — напишіть в коментарях.
Автоматичне налаштування панелей під висоту / ширину екрану
Так як екран у мене повністю оновлюється майже з кожним натисканням, то змінити розмір вікна (наприклад якщо сидіти через графічний ssh клієнт) можна в будь який час — після першого ж натискання будь-якої клавіші все адаптується. Пару вечорів пішло на опції відображення/приховування стовпців — потрібно було порахувати й налагодити адаптацію для одно-панельного і дво-панельного режиму, плюс заголовки і текст обчислюються різними формулами. Ось шматочок для визначення наскільки треба обрізати Certificate Alias, якщо екран занадто вузький і потім приклад виведення заголовка:
WindowWidth="$(tput cols)" if [ -n "$RFILE" ]; then # two-panel used=24 [ -n "$SHOW_TYPE" ] && used=$(( $used+34 )) localWidth=$(( ( $WindowWidth - $used ) / 2 - 1 )) if [ $localWidth -ne $aliasWidth ]; then aliasWidth=$localWidth [ $aliasWidth -lt 1 ] && aliasWidth=1 clear fi ..................................................................... headerWidth=$(( $aliasWidth + 5 )) [ -n "$SHOW_TYPE" ] && headerWidth=$(( $headerWidth + 17 )) printf " store: ${blue}%-$(( $headerWidth ))s${rst}" "$LFILE" printf "| store: ${blue}%-$(( $headerWidth -1 ))s${rst}\n" "$RFILE" printf " %-10s" "Valid to" [ -n "$SHOW_TYPE" ] && printf " %-16s" "Storetype" printf " %-${aliasWidth}s |" "Alias" printf " %-10s" "Valid to" [ -n "$SHOW_TYPE" ] && printf " %-16s" "Storetype" printf " %-${aliasWidth}s\n" "Alias"
Визначення натискання функціональних клавіш (updated)
Деякі спеціальні клавіші можуть мати довжину декiльца символів, тому просто через read було зробити непросто — він не дозволяє варіативно змінювати довжину строки, але після пошуку та експериментiв я визначив, що команда read розуміє що таке мілісекунда. І після експериментів, ця частина виглядає так:
# Special keypress could take variable amount of characters keypress="" read -rsN1 keytap while [ -n "$keytap" ]; do keypress="${keypress}${keytap}" read -sN1 -t 0.01 keytap done
Тепер можна порівнювати значення $keypress із комбінаціями типу:
F1_KEY=$’\e[11~’
F10_KEY=$’\e[21~’
UP_KEY=$’\e[A’
DOWN_KEY=$’\e[B’
TAB_KEY=$’\t’
DEL_KEY=$’\e[3~’
Я не зовсім впевнений, що мій варіант буде працювати скрізь ідеально — тому про всяк випадок більшість hot keys продубльована літерами.
У спрощеному вигляді подібну навігацію я вже використовую в інших скриптах — в деяких випадках це набагато зручніше ніж стандартний select завдяки можливості робити хоткеї та можливості зручно виводити списки.
Дуже важливим плюсом я вважаю те, що jks_mgr.sh — це просто скрипт одним текстовим файлом.
Ніяких обсфукацій, код максимально простий — перевірити на відсутність закладок може в принципі будь-який джуніор.
Тобто, якщо ви працюєте у проекті, де кожна програма потребує перегляду службою безпеки, перевірки на ліцензію, або на цільовій машині просто недостатньо прав — цей скрипт може бути стати вам в нагоді. Його не потрібно встановлювати, потрібен лише доступний шелл, keytool, sed та grep.
Та є й «печалька»: звичка роботи з Java змусила мене виконувати всю роботу зі сховищами саме через keytool, який повинен бути доступний в PATH (а можливо варто було б розібратися та зробити все через openssl? — напишіть у коментарях).
На поточний момент всі найважливіші для мене функції втілені і я взяв перепочинок, та власне й сам скрипт я почав писати, щоб отримати трохи практики з tput - і навігацією, але захопився — tput вже викiнув iз скрипта, користуюсь stty щоб дiзнатись розмiр термiналу, та напряму вивожу контрольнi коди.
Підсумок
Наприкінці потрібно написати щось важливе/мудре. Ну хай так: хочеш отримати від навчання/практики задоволення — придумай таке, щоб результат був корисний для тебе.
Хочеш отримати від навчання/практики подвійне задоволення — придумай таке, щоб результат був корисний для тебе і для когось ще.
Зараз моїм скриптом користується невелика кількість людей в компанії. А те, що я, не розробник, зміг написати щось корисне і потрібне, мене дуже радує.
P.S. Про всяк випадок (чули про nginx та Wargaming?), хочу заявити, що jks_mgr.sh був написаний ВИКЛЮЧНО в неробочий час, на приватному комп’ютері.
50 коментарів
Додати коментар Підписатись на коментаріВідписатись від коментарів