История одного факапа
Послушал тут предпоследний 769-й выпуск подкаста Radio-T, в котором обсуждение технических ошибок напомнило мне примерно аналогичный случай из моей практики.
Давным давно, когда я ещё работал в xsolla, которая ещё в то время носила название 2pay, у нас по большому счёту был всего один основной сервер в Московском датацентре, на котором крутился весь мир. Передо мной стояла задача написать скрипт, который зачищает старые логи, временные файлы и прочее, что может занимать много места.
К этой задаче как я помню, я приступил уже под 3 часа ночи, ибо работы было как всегда - много, а времени как всегда - мало. Очень хотелось спать, но количество оставшегося свободного на продакшен хосте места неумолимо уменьшалось, что заставляло действовать в темпе. Я уж не помню, что спровоцировало рост логов - может быть кто-то из разработчиков не отключил какой-то внутренний дебаг при последнем деплое или это были попытки перебора - теперь уже не важно. Одним словом, ближе к половине пятого утра скрипт был готов и я решил его протестировать сначала в dry-run режиме. Выхлоп в логах оказался вполне ожидаемым и верным и я уже с квадратным мозгом и глазами цвета знамени советского союза запустил его на продакшен хосте. Всё прошло прекрасно, ощущение того, что вот прямо сейчас можно будет отрубиться и проспать хотя бы 4-5 часов вызывало нечто сродни ментальному оргазму. Но надо ведь было дёрнуть этот скрипт ещё раз.
И тут я увидел то, что наверное боится увидеть любой DevOPS/системный администратор - как удаляется от корня весь рабочий хост, как быстро пролетели логи удаления /bin, как закончился /etc и началось удаление /dev... В этот момент тебя приподнимает над стулом на сантиметр, потому что волосы становятся дыбом аж на заднице. Непередаваемые ощущения. Сочетание Ctrl+C нажималось со скоростью пулемётной очереди, процесс удалось остановить. Мысль первая - писец, я уволен. Мысль вторая - что делать? Мысль третья - почему так произошло?
Собственно, ошибка была просто хрестоматийная - в коде скрипта собирался список найденных директорий и файлов с тем, что можно было почистить, после чего пути для зачистки передавались в качестве переменной окружения команде rm -rfv /${src}. В первый раз всё отработало прекрасно, потому что было, что удалять. А вот во второй несколько файлов нашлись, а директория из одной секции - нет и ${src} оказался пуст, а привычки по умолчанию ставить set euxo в начале скрипта у меня тогда ещё не выработалось. Вот и запустился rm -rfv / в полный рост.
Начал судорожно разбираться. На сервере я работал в сессии тмукса, в котором в одной из вкладок нашёлся открытый midnight commander. Поднял на своей локальной машине виртуалку, на которой раскрутил нужную версию FreeBSD, соответствующую той, на которой бежал боевой сервер, поставил nginx, php нужных версий и минимальный стек необходимых пакетов, чтобы было подобие прода. Разворачивать бекап времени не было. Я понимал, что если потеряю этот коннект, то это будет катастрофа. Реверс туннелем через ssh вывесил порт до ближайшего хоста с белым адресом, через mc на проде подцепился по ssh уже к FS виртуалки и начал перетаскивать руками bin, etc и всё прочее, что могло зацепить. Параллельно вытаскивал большой и тяжёлый монолитный бекап, из которого потом нужно было добыть уже боевые конфигурационные файлы, скрипты и прочее.
Позвонил начальнику ближе к началу шестого, прямо по телефону через красноречивое молчание ощущалось, как меняется выражение его лица, пока я рассказывал, что натворил. Потом сразу перешёл к части о том, каким образом я решал проблему, какое рассчётное время решения и т.п.. Начальник спросил меня, какие выводы я могу сделать из сложившейся ситуации, я ответил, что похоже нам просто нужно больше людей и что я бы с радостью предпочёл решать текущую проблему в нормальном состоянии днём, а не ночью, но ситуация сложилась именно таким образом, что выбора у меня особого не было. Ну и если бы было время, то каждый тип логов можно было бы чистить с использованием sudo -u $USER.
К половине девятого утра сервер был как новенький и мало кому бы в голову пришло, что над ним совершили такое непотребство. Все конфиги лежали на своих местах, все права на все файлы были выставлены где вручную, где в полуавтоматическом режиме, скрипт был дописан, в хранилище лились новые актуальные бекапы. В общем, всё обошлось, хотя я морально и был готов к тому, что меня уволят, но этого не случилось.
После этого я написал обёртку над rm, которая при запуске переименовывала /usr/bin/rm (или иной путь, который получала от which rm) в /usr/bin/.rm, копировала себя на место бывшего rm и аккуратно передавала все входящие параметры .rm, но если в параметрах был путь, в котором пользователь пытался удалить какой-нибудь корневой каталог, скажем, /bin, обёртка выдавала в консоль "A ne otorvat' li tebe yaitsa, %username%" и отправляла по почте сообщение об инцеденте. Саму обёртку я быстро не найду в закромах родины, ибо лет 10, как её не использовал. С тех пор я уже давно сменил место работы и не одно, но несколько лет назад, уже после моего ухода из xsolla мне написал один мой хороший товарищ с жалобой на то, что он написал какой-то скрипт для разворачивания кажется, рабочих окружений на виртуалках для пользователей, но при попытке его запустить столкнулся с десятками сообщений с угрозами отрыва яиц. У меня на душе прямо потеплело - прошло столько лет, а яйцеотрывательный скрипт всё ещё исправно работал. :) Как выяснилось, в корне виртуалки создавался некий временный файл, который затем были попытки удалить.
К чему я решил обо всём этом рассказать? Ко мне сейчас приходят люди на собеседование - и разработчики и DevOPS'ы. Все они довольно охотно рассказывают о своём положительном опыте, о том, чем они гордятся, о том, чего им удалось достичь. Но при этом практически никто не рассказывает об опыте отрицательном, по крайней мере по своей инициативе, а когда спрашиваешь, то зачастую так же делятся подобными вещами крайне неохотно. А ведь отрицательный опыт в нашем деле зачастую оказывается куда важнее, нежели положительный. Я помню, как изменилось тогда моё отношение к работе под рутом, к использованию неинициализированных переменных в скриптах, к команде RM в принципе. И с куда большей охотой я бы принял на работу человека, который уже накосячил и прочувствовал на своей шкуре, что это такое, а в идеале - смог исправить ситуацию с минимальными потерями. Нет людей, которые получили богатый жизненный и профессиональный опыт, не совершая ошибок, в конце-концов не ошибается тот, кто ничего не делает. Но очень хотелось бы, чтобы и работодатели и работники имели возможность более открыто об этом общаться друг с другом.
P.S.: Не отрицаю, есть люди, которые встают по нескольку раз на одни и те же грабли, но они обычно в IT не задерживаются долго.