Накладываем швы на ActiveRecord::SchemaDumper

March 28, 2017

В рейлс primary key - желательно делать id, формально конечно можно поставить что-то другое, но гарантия заканчивается очень быстро. У нас в одном проекте сделали ключом uuid и конечно же сломался дамп схемы. Где сломался дамп схемы, там сломались тесты и вообще не хорошо все это.

Иногда получается вставить аккуратный монкей-патч, но тут нужно было фиксить увесистый приватый метод ActiveRecord::SchemaDumper#table. Обычно я делаю так:

  1. Добавляю файл в config/initializers, обычно это достаточно удачное время
  2. Копирую подопытный метод целиком, по возможности с условиями: if defined?(ActiveRecord::SchemaDumper) ...
  3. Обязательно ставлю ассерт на текущую версию рейлс raise "review and update this patch for Rails upgrade" if Rails.version != "4.2.8"
  4. Каждое вмешательство оформляю ярко, примерно так:
  ##### [BEGIN PATCH 2]
  # # original code
  # next if column.name == pk
  # @connection.column_spec(column, @types)

  # # patched code
  if column.name == pk
    if pk == "uuid"
      @connection.column_spec(column, @types).merge(primary: "primary: true")
    else
      next
    end
  else
    @connection.column_spec(column, @types)
  end
  ##### [END PATCH 2]

В данном случае удалось обойтись тремя швами и схема как новенькая.

Глубоководные работы

March 27, 2017

Недавно друг сказал в беседе полностью серьезно: "эпоха ботов, конечно уже прошла, месяцев 8 назад ..." Я не очень помню, что дальше было, но эта фраза очень позабавила. И действительно боты очень ярко сверкали на каждом ресурсе совсем недавно, а сейчас стали где-то рабочим инструментом, где-то не стали, но шума однозначно производят сильно меньше.

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

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

Осилив одну глубину, вторая дается гораздо легче, а радует также. Из свеженького, в одной задумке мне пригодится утилита script, ей 100500 лет, но конечно я про нее никогда до этого не слышал. Знаете такую? Если идея выгорит - расскажу.

Цифровой бардак, здравствуй, это я

March 24, 2017

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

Прозрение, что мир бардака окончательно поглотил человечество, наступило сегодня, когда решил упорядочить контакты. Вообще контакты от гугла весьма странная программа, она подтягивает какой-то шлак из гугл плюса (WTF, почему это еще живо), плохо находит дубли и из настроек можно выбрать только сортировку по имени или фамилии. И вдруг понял, что в современном мире не надо и невозможно держать единый список контактов. Всегда без проблем можно найти человека в телеграмме, вотсаппе, фейсбуке или твиттере, а может быть по профилю гитхаба, в слеке или еще где.

Современный цифровой мир - ад для перфекциониста старой школы, любителя каталогизации и систематизации. Но я вылечился. Раз так, значит так. Буду смотреть, как дальше пойдет.

Black Black Rsync Magic

March 23, 2017

На днях переносил террабайт пдфок с одного сервера на другой. Генетическая память подсказывала, что rsync -avP --del неплохой выбор. Решил для надежности посмотреть хелп:

$ rsync --help | grep -- '-a'
 -a, --archive     archive mode; equals -rlptgoD (no -H,-A,-X)

Я люблю консоль, но иногда, конечно, с изысканности утилит мне становится очень смешно. rlptgoD вам, no HAX, братишки! А мы еще даже не разобрались с комбинаторикой слешей в путях :scream_cat:, IDDQD.

Маленькая гениальная штучка в прометее

March 22, 2017

При настройке прометея через сервис дискавери консула поле __meta_consul_tags состоит из тегов, перечисленных через запятую. Внимание, с дополнительными запятыми в начале и в конце строки! :scream_cat: То есть массив тегов [job-A, job-B] превращается в строку ,job-A,job-B,.

Это нужно для более легкой настройки релейбелинга, когда вхождение тега мы можем искать по простому регекспу .*,job-A,.*, не отвлекаясь на отсутствие запятой вначале или в конце строки, как было бы в случае простого join(",").

Про эту штуку узнал из статьи Little Things Matter и испытал огромное эстетическое удовольствие. И да, мы это используем в продакшене.

Хероку

March 21, 2017

Мне хорошо запомнилась цитата из группы ror2ru, что Хероку - для олигархов. Я себя никогда не чувствовал и не чувствую принадлежащим к этой группе людей, поэтому мне потребовались весьма значительные усилия, чтобы решить держать там наши первые продакшены.

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

В цифрах, я бы сказал, что если прайс меньше 1000$ в месяц, нагрузки меньше 100 запросов в секунду, база не больше 50Гб, а также нет требований о персоналке, то Хероку - идеален.

docker run -p A:B vs git - 1:1

March 20, 2017

Запускать докер контейнеры я учился из интернета, в 99% статей это выглядит как-то так docker run -p 80:80 nginx, поэтому часто путал какой порт отвечает за хост, а какой за контейнер. Когда они отличались, то решал задачу так же, как флешка вставляется в USB-порт, суперпозицией поворотов.

Запомнить очень просто: 80:80 - это сокращенная запись hostIP:hostPort:containerPort, то есть если я хочу повесить рейлс контейнер на 8080-й порт для интерфейса 192.168.12.27, то так и пишу:

docker run -p 192.168.12.27:8080:3000

либо, если интерфейс не важен, то команда - docker run -p 8080:3000. Теперь не путаюсь.

PS. жуткая команда для удаления ветки git push origin :branch становится понятной, когда узнаешь, что git push origin branchA:branchB, отправляет локальную branchA в branchB на сервере, и если отправить "пустоту" в серверную ветку branch, то это будет равносильно удалению branch на сервере.

Скрипт целостности

March 17, 2017

На конференции я обещал выложить скрипт, который сравнивает DNSimple, Селектел и состояния терраформов. Это не один скрипт, а несколько. Конечно они без комментариев и повышенной ламповости. Я вырезал кое-что, но вот этот набор скриптов в целом должен работать, по крайней мере на наших данных запускается:

Идея в том, что есть backup_* скрипты, которые дампят в текстовом виде разные параметры системы. Мы эти файлы храним в приватном репозитарии и я даже иногда поглядываю на изменения, кто там что поменял. Далее запускается скрипт check, вывод которого выглядит примерно так:

То есть с днс-записями на картинке порядок, а вот состояние-терраформа кто-то не сдал.

У нас таких backup-* скриптов больше, но остальные решают еще более частные задачи. Например, там есть проверка того, что ночные бэкапы собрались и всякие другие штуки. Вот этот набор скриптов нам очень-очень помогает, но я не знаю как их правильно обернуть, чтобы они помогли еще кому-нибудь. Если у вас есть идеи - буду рад обсудить!

Коллеги, я удалил сервер с VPN

March 16, 2017

Недавно замечательным терраформом грохнул несколько серверов, дело было так. В файле var.tf лежала переменная с ID-образа убунты примерно так UBUNTU_IMAGE_ID = 'cde3892-...'. Я решил обновить образ на свежий и не прочитал, что написал terraform plan, а зря. Терраформ, когда у диска меняется переменная image_id, пересоздает диск. Поэтому сервер на новом образе я конечно создал, но еще заодно обновил старые сервера. Хорошо, что базы были на другом образе, а так бы веселья было чуть больше.

Сейчас мы страхуемся тем, что в каждый диск копипастим конкретное значение в image_id, Ctrl-C Ctrl-V - рулят.

Ansible Variables

March 15, 2017

В ансибл круто сделано, что можно передать переменную в очень многих слоях, как минимум в roles/vars, roles/default, group_vars и тд. И даже можно передать через командную строку. Как-то захотел передать false, попробовал так:

ansible-playbook system.yml --tags vpn --e vpn_fetch=false
ansible-playbook system.yml --tags vpn --e vpn_fetch=False
ansible-playbook system.yml --tags vpn --e vpn_fetch=no

но сработал только вариант с JSON:

ansible-playbook system.yml --tags vpn --e '{"vpn_fetch":false}'

Далее этот флажок обрабатывается в роли привычным образом:

- include: fetch.yml
  when: not vpn_fetch