moiseenko.online

local в bash подавляет ошибки

Писать скрипты на баше — это весёлое занятие. Никогда не знаешь, когда выползет рояль в кустах.

Сейчас, например, наткнулся на рояль, о котором, слава богу, был заранее предупреждён в «Bite Size Bash»

Давайте возьмём такую тестовую функцию, которая задаёт недопустимый режим вращения кулеров на платформе Supermicro. Режима 0x05 нет, поэтому ждём ошибку.

test_fan() {
    local _result
    if _result=$(ipmitool raw 0x30 0x45 0x01 0x05)
    then
        return 1
    fi
    echo "YES"
}

A=$(test_fan)
echo $?
echo "$A"

Как вы думаете, что произойдёт в результате выполнения этого скрипта?

Здравый смысл подсказывает, что:

  • ipmitool свалится с ошибкой, плюнет ее в STDERR, и поднимет ненулевое значение в $?
  • дальше мы провалимся внутрь условия и вывалимся из функции с ошибкой
  • после вызова функции в $? мы поймаем 1, а значение $A вовсе будет пусто.

Как бы не так:

# ./test_fan_control
Unable to send RAW command (channel=0x0 netfn=0x30 lun=0x0 cmd=0x45 rsp=0xcc): Invalid data field in request
0
YES

А всё потому что в баше почему-то local подавляет все ошибки.

Уберём его и получим ожидаемое поведение:

# ./test_fan_control
Unable to send RAW command (channel=0x0 netfn=0x30 lun=0x0 cmd=0x45 rsp=0xcc): Invalid data field in request
1

11 цитат из «Идеального программиста»

Это будет немного читерский пост, поскольку он почти целиком состоит из цитат. Но это очень важные цитаты.

Все они — из книги «Идеальный программист» Роберта Мартина (Дядюшки Боба).

Прочитав эту книгу, я проглотил также и «Чистый код», затем «Чистый Agile», а сейчас читаю «Чистую архитектуру». Меня зацепило дерзкое сочетание профессионализма и безапелляционности суждений. Роберт Мартин стал для меня главным авторитетом в мире разработки.

Я хотел бы поделиться с вами любимыми цитатами, которые я выбрал потому что:

  1. Я искренне верю в сказанное Дядюшкой Бобом. Хотя во многих случаях мне потребовалось время, чтобы принять это. В половине случаев это были набитые мной шишки. Эх, если бы я прочитал эту книгу раньше.
  2. Кто-то может счесть эти мысли Мартина спорными.

Не буду скрывать, что смысл этого поста — заинтересовать вас. Если вы в итоге купите и прочитаете хотя бы «Идеального программиста», то это будет прекрасным результатом. Ну, конечно, только если вы до сих пор не прочитали эту замечательную книгу ;)

Про покрытие тестами

Скажете, я предлагаю 100% тестовое покрытие кода? Ничего подобного. Я не предлагаю, а требую. Каждая написанная вами строка кода должна быть протестирована. Точка.

Про рефакторинг

Когда следует вносить такие изменения? Всегда! Каждый раз при работе с модулем следует понемногу совершенствовать его структуру. Каждое чтение кода должно приводить к доработке структуры.

Эта идеология иногда называется безжалостным рефакторингом. Я называю этот принцип «правилом бойскаута»: всегда оставляйте модуль чище, чем до вашего прихода.

Про карьеру

За свою карьеру отвечаете вы сами. Ваш работодатель не обязан заботиться о вашей востребованности на рынке труда. Он не обязан обучать вас, отправлять вас на конференции или покупать книги. Всем этим должны заниматься вы сами. Горе тому разработчику, который доверит свою карьеру работодателю.

Про состояние потока

О сверхпроизводительном состоянии, называемом «потоком» (flow) написано много литературы. Некоторые программисты называют его «зоной». Как бы оно ни называлось, вероятно, вам знакомо это ощущение предельной концентрации сознания, в которое может войти программист при написании кода. (...) Избегайте Зоны.

Про обучение

(...) ответственность за обучение менее квалифицированных программистов возлагается на их опытных коллег. Учебных курсов недостаточно. Книг недостаточно. Ничто не приведёт молодого разработчика к высокой производительности быстрее, чем его собственное желание в сочетании с эффективным обучением со стороны старших товарищей.

Про TDD

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

Про критерии готовности

У профессиональных разработчиков есть только одно определение: выполнено — значит выполнено. Сделано — значит, что весь код написан, все тесты пройдены, служба контроля качества и ключевые участники приняли результат. Сделано.

Про присутствие на встречах

Вы не обязаны посещать каждую встречу, на которую вас приглашают. Более того, посещать слишком много встреч непрофессионально. (...) За годы я выработал простое правило: если на встрече стало скучно — уходите.

Про сотрудничество

Быть одиночкой, или отшельником в группе непрофессионально.

О принадлежности кода

Один из худших признаков неправильно функционирующей команды — когда каждый программист возводит стену вокруг своего кода и запрещает другим программистам прикасаться к нему

Про парное программирование

Скажу одно — профессионалы работают в парах. Почему? Потому что по крайней мере для некоторых задач эта методология наиболее эффективна. Впрочем это не единственная причина.
Профессионалы также объединяются в пары, потому что это лучший способ обмена знаниями. (...)
Профессионалы объединяются в пары, потому что это лучший способ рецензирования кода.

Советы тем, кто пишет на bash.

Используйте shellcheck

shellcheck — потрясающий инструмент. Если вы пишете скрипты на bash, но до сих пор не используете его — начните делать это прямо сейчас.

Он прекрасно устанавливается в любой оси, интегрируется с вашими любимыми IDE, его можно заставить проверять ваши скрипты в CI/CD.

Каждый скрипт должен проходить проверку шеллчеком. Точка.

Примите свой стайлгайд

Обсудите и примите в вашей команде свой стиль написания кода. Не надо думать, что bash — это не python, или golang, а какая-то несерьёзная фигня, поэтому и писать на нём можно как угодно.

Да и не драться же, в конце концов, из-за использования табуляций или размера отступов? :)

Начать можно с ознакомления с чужими стайлгайдами, например, за основу можно взять гугловский:

Никто не обязывает всецело следовать ему, но чужие стайлгайды — это прекрасный источник вдохновения.

Красивые отступы в HEREDOC

HEREDOC — это клёвая штука. Обязательно изучите все её возможности. В этом поможет Advanced Bash-Scripting Guide

Однако, с HEREDOC есть одна боль, которую я пока не знаю как решить: они ломают отступы. В процитированном документе есть работающее решение, где все красиво:

#!/bin/bash

ugly_func() {

    cat << ENDOFMESSAGE
This is line 1 of the message.
This is line 2 of the message.
This is line 3 of the message.
This is line 4 of the message.
This is the last line of the message.
ENDOFMESSAGE
}

pretty_func() {

    #  The - option to a here document <<-
    #+ suppresses leading tabs in the body of the document,
    #+ but *not* spaces.

    cat <<-ENDOFMESSAGE
    This is line 1 of the message.
    This is line 2 of the message.
    This is line 3 of the message.
    This is line 4 of the message.
    This is the last line of the message.
    ENDOFMESSAGE
}

Однако, оно «сжёвывает» только символы табуляций и не сработает, если вы практикуете отступы пробелами.

Очень жаль, ведь отступы табуляциями — зашквар и прошлый век.

Используйте ${...}

Вы еще не используете мощный механизм раскрытия параметров? Значит ещё не читали стрипы от замечательной Джулии Эванс

Мой любимый жизненный пример — получение аргументов запуска программы из окружения с использованием значений по умолчанию, например:

#!/bin/bash

PACKER_BIN=/usr/bin/packer
MANIFESTS_DIR=${MANIFESTS_DIR:-/mnt/ssd/packer/manifests}
TARGET_DIR=${TARGET_DIR:-/mnt/ssd/ostemplates/data}
...

В баше есть регулярки

Да, в баше есть регулярки и ничто не мешает вам использовать их, например, для валидации данных:

[[ $distro =~ ^(centos|debian|ubuntu)-[0-9.]+$ ]] \
|| error "Incorrect distro \"$distro\": validation failed"

Чтение входных данных

Давайте рассмотрим классический пример:

$ cat example.txt
word1
word2 word3
word4

$ for line in $(cat example.txt); do echo $line; done
word1
word2
word3
word4

Об этой коварной особенности нам нужно помнить. Как это обойти?

Ну, например, встречается такой распространённый совет:

$ cat example.txt | while read -r line; do echo $line; done
word1
word2 word3
word4

Вроде бы задачу выполняет, но есть нюанс. Вся эта конструкция с пайпом на while read порождает сабшелл. Про сабшеллы с их вытекающими плюсами и минусами я расскажу дальше.

Как быть? Если вас устраивает сабшелл — используйте вариант выше, он красивый. А нет — можно использовать переменную IFS:

$ IFS=
$ for line in $(cat example.txt); do echo $line; done
word1
word2 word3
word4

Главное — не забудьте потом её вернуть к исходному состоянию:

$ unset IFS
$ for line in $(cat example.txt); do echo $line; done
word1
word2
word3
word4

Помните про сабшеллы

Сабшелл — это всё, что запускается в отдельном унаследованном процессе bash. Иногда — это необходимость, иногда — это полезный трюк. Например, мы можем временно перемещаться в рамках какой-то подзадачи в другую директорию. Такой паттерн я часто использую при сборке чего-либо:

(
        cd "$MANIFESTS_DIR" \
        && rm -rfv "$artifacts_dir" \
        && $PACKER_BIN \
        build \
        -var-file "$distro_var_file" \
        manifest.json \
        >  >(tee -a stdout.log) \
        2> >(tee -a stderr.log >&2)
    ) || error "BUILD FAILED"

Сабшелл работает в дочернем процессе, поэтому не меняет ничего в родительском. Этот побочный эффект в примере выше является полезным. В сабшелле мы перемещаемся в другую директорию, что-то там собираем, но когда возвращаемся из сабшелла, то остаёмся в исходной директории.

Но в других кейсах сабшеллы могут запутать вас.

Как вы думаете что выведет данный скрипт?

#!/bin/bash

declare -a numbers

seq 1 5 | while read -r num;
do
  numbers["${num}"]=1
done

echo "${!numbers[@]}"

Правильно — ничего. Ассоциативный массив будет заполняться в сабшелле, а команда echo будет выполняться в родительском процессе. Учитывайте это при работе с сабшеллами.

А как можно обойти проблему? Например, так:

#!/bin/bash

declare -a numbers

while read -r num;
do
  numbers["${num}"]=1
done < <(seq 1 5)

echo "${!numbers[@]}"

Мощная инструкция set

До этого года я не подозревал о том удобстве, которое предоставляет инструкция set, хотя иногда встречал её в «серьёзных скриптах».

Просто изучите варианты её использования и будете приятно удивлены. А для начала попробуйте в начало любого вашего скрипта добавить инструкцию set -x и посмотреть что получится в итоге.

Отладка скриптов если и не стала удовольствием, но уж точно перестала быть адом.

Bite Size Bash

В обязательном порядке рекомендую к прочтению Bite Size Bash Джулии Эванс. Не забывайте про региональную скидку. Например, россиянам этот журнальчик обойдётся на 70% дешевле.

Oh Shit, Git!?!

Мне очень нравится творчество Джулии Эванс. Она структурирует знания по системному администрированию и программированию и делает из них одностраничные комиксы, которые потом объединяет в формате минижурналов, которые можно самому напечатать на обычных листах A4, сложить пополам и прошить.

Попозже я обязательно порекомендую вам мои любимые её творения, но сегодня я хочу остановиться на её коллаборации с Кэти Сайлор-Миллер

Это небольшое и необычное руководство по гиту. Здесь нет попытки создать какое-то исчерпывающее руководство. Вместо этого разбираются частые засады :)

То есть ситуации в которых мы с вами, работая в гите, оказываемся и хотим их исправить.

Вот их список:

  • хочу поправить текст последнего коммита;
  • сделал коммит, но хочу внести небольшую правку;
  • случайно закоммитил в другую ветку (обожаю этот кейс!);
  • закоммитил что-то в мастер, а хотел в отдельную новую ветку;
  • делаю diff, но не вижу никаких правок;
  • у меня мердж-конфликт;
  • в мой коммит попал файл, который должен был быть проигнорирован;
  • сделал rebase и теперь у меня 100500 конфликтов;
  • хочу разбить свой коммит на два;
  • хочу откатиться аж на 5 коммитов назад;
  • я сделал что-то совсем ужасное и мне нужна машина времени.

Интересно? Купить журнальчик можно тут: https://wizardzines.com/zines/oh-shit-git/

И пусть вас не пугает цена в $10, для России действует специальная скидка в 70%. Для жителей Украины и Беларуси, кажется тоже.

Установка VPN-сервера для доступа к LinkedIn (видео-версия)

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

Почему нельзя выбрать бесплатные VPN-сервисы?

Используя бесплатные VPN-сервисы, вы подвергаете свои данные угрозе.

Пожалуйста, никогда не пользуйтесь бесплатными VPN-сервисами.

Выбираем ПО

В этой статье я остановлю свой выбор на OpenVPN Access Server:

  • он очень просто устанавлявается
  • с ним удобно работать при подключении клиентов
  • он скромный в потреблении ресурсов

Выбираем хостинг и тариф

Я рекомендую минимальный тариф START-0 на облачных серверах REG.RU. Этого тарифа хватит, чтобы развернуть OpenVPN Access Server. Я использую его лично.

Чтобы начать работать с облачными серверами REG.RU, нажмите на ссылку

Ограничения со стороны хостера

Вы можете использовать облачный сервер, чтобы настроить VPN для доступа к такому сайту как Linkedin. Всё будет хорошо до тех пор, пока вы не начнёте генерировать большие объёмы трафика, например, использовать VPN для обхода блокировок серверов потокового вещания, или для скачивания торрентов.

Ограничения со стороны ПО

OpenVPN Access Server без платной лицензии будет ограничен двумя одновременными соединениями, что нас в данной задаче полностью устраивает

When the OpenVPN Access Server is installed without a license key it goes into a sort of demonstration mode. There is no time limit or functionality limit on this mode. The only difference between a licensed Access Server and an unlicensed one is the amount of simultaneous OpenVPN tunnel connections the Access Server allows. An unlicensed server will only ever allow 2 simultaneous connections and that’s it. To unlock more connections you can purchase a license key to unlock more connections. We suggest you read the licensing frequently asked questions page and the pricing overview page to learn more.

Устанавливаем VPN-сервер

Я подготовил ролик, где наглядно показал как поставить OpenVPN Access Server.

Несколько поясненений:

  • Минимального тарифа REG.RU с 512 MB RAM как я и говорил — достаточно
  • В данном руководстве не рассматривается как выпустить SSL-сертификат, об этом я напишу позже
  • В процессе вы установите первоначальный пароль с помощью команды passwd openvpn, но повторный запуск этой команды никакого влияния на пароль в веб-интерфейсе не окажет.

Подключаемся к VPN-серверу

У OpenVPN Access будет два разных интерфейса: администраторский и пользовательский. В пользовательском интерфейсе вам дадут скачать конфиг, который можно будет импортировать в OpenVPN-клиент. В этом и будет заключаться вся настройка VPN.

Добавляем домен и сертификат

Вся эта часть опциональна. Наш VPN-сервер будет работать и с самоподписным сертификатом.

У меня есть домен, размещённый на DNS-серверах REG.RU, поэтому я могу использовать его для своего VPN-сервера. В том числе и для того, чтобы подключить SSL-сертификат.

Мой домен moiseenko.online, а для VPN-сервера я выберу поддомен vpn.moiseenko.online.

Сперва я пропишу A-запись в DNS для того, чтобы поддомен vpn.moiseenko.online смотрел на мой виртуальный сервер.

Теперь нужно подождать немного, пока запись не появится на DNS-серверах REG.RU и поддомен не заработает. Это нужно для того, чтобы letsencrypt смог пройти проверку и заказать сертификат. Я рекомендую сделать перерыв в 15 минут на чаёк-кофеёк, но на самом деле в REG.RU новые записи на DNS-серверах для существующего домена появляются намного быстрее.

Когда поддомен заработает всё просто — мы ставим certbot, заказываем сертификат и подменяем сертификаты «из коробки» ссылками на только что выпущенный с помощью let’s encrypt сертификат: