Процедура миграции доменов¶
Старт миграции (вьюшка MigrationStartView
).¶
По POST она дёргает PddDomainMigration.create_migration_task
и отдаёт её результат, как id миграции.
По GET она отдаёт статус миграции по её id.
При создании задания на миграцию¶
Выбирается шард для организации.
Создаётся запись в таблице migrations со статусом
check
,only_check_conditions=False
и рандомнымid
.При этом, в
settings
прописывается словарь с входными параметрами метода:settings = { 'admin': admin, 'domain': domain, 'deproot': deproot, 'orgname': orgname, 'tld': tld, }
Дальше в дело вступают воркеры.
Worker condition_check¶
Этот воркер перебирает все записи из migrations
, у которых
status=='check'
.
Для каждого из них он берёт
lock
.Проверяет, возможна ли миграция. На этом этапе функция проверки
migration_status_and_data
может вернуть разные ошибки, в том числе иin_progress
. И этотin_progress
будет означать, что в метабазе уже есть запись про организацию с таким жеlabel
, как для этого домена иready=False
.В этом случае воркер ищет уже идущую миграцию, и прописывает её id, как в поле
migration_id
атрибутаdata
у текущей миграции.Если миграция разрешена, то её статус переводится в
setup
.
По итогу, миграция переходит в состояние setup
, если всё хорошо,
in_progress
, если уже идёт миграция этого домена или в какую-то
ошибку, если дальнейшее продолжение миграции невозможно.
Worker setup_migration¶
Этот воркер обрабатывает все записи из migration, что в состоянии
setup
.
На каждую запись берётся лок.
Запускается
PddDomainMigration.setup_migration
.При подготовке миграции проходят следующие шаги:
Сначала проверяется, что свободен аккаунт заданный в переменной
deproot
, если нет, то возвращается исключениеroot_maillist_exists
.Дальше получаем список ящиков и рассылок на домене, а так же информацию об админе из паспорта.
Заводим запись про организацию в метабазе и основной базе.
Создаём рассылку для корневого отдела.
Сохраняем алиасы домена из ПДД в Директорию.
Создаём саппортного робота для Ямба.
Если всё проходит хорошо, то миграция переводится в состояние
migration
Если случилось исключение, то в
rollback
сcode: unknown
.
Есть странный коммент. Я его не понимаю. Зачем табличку migrations обновлять дважды:
MigrationModel(main_connection).update_one(
migration_id=task_id,
status=status,
data=data
)
# запомним ид заготовки организации
MigrationModel(main_connection).update(
update_data={'org_id': migrator.org_id},
filter_data={'id': task_id},
)
Update. Выяснили с Наилем, что особого смысла в этом нет, можно было бы одним update обойтись.
Worker migrate_worker¶
Этот занимается тем, что мигрирует один ящик.
Он достаёт из таблички первую запись, у которой
migrated is NULL
.Берёт лок на её id
Запускает PddDomainMigrationEmail.migrate_email.
Тот в свою очередь, достаёт данные по id из таблицы migrate_email и создаёт по ним пользователя в Директории.
Подписывает пользователя на корневой отдел.
Синхронно активирует для него b2b диск.
В конце - создаёт в migrate_log две записи, про то, что пользователя создали и про то, что подписали его на корневую рассылку.
Если в процессе случается PddException, то ошибка логгируется в migrate_log.
Note
Прочие ошибки в migrate_log не попадают, однако всё равно вызывают откат миграции. Надо это поправить!
Воркер migrate_finalizer¶
Этот воркер выбирает все записи со статусом migration
. Потом считает все
migrate_email, относящиеся к этой организации. Если у них у всех поле
migrated=True
, то воркер создаёт лок по id организации. Дальше:
В табличке migrations для миграции проставляется статус
finalization
.Вызывается
PddDomainMigration.finalize_migration
, который:по
domain_id
проставляет в паспорте признак воркспейсности, через указание для доменаorganization_name
.дёргает ручку
ws_update
в ПДД.
Если случается ошибка, то миграция переводится в статус
rollback
, а для всех записей в таблицеmigrate_email
, проставляется флагmigrated=False
.Если ошибки не было, то:
организации в метабазе проставляется признак
ready=True
;все записи в
migrate_email
, относящиеся к организации, удаляются;генерится действие
organization_migration
;отправляется письмо админу организации;
отправляются письма всем пользователям организации;
Note
воркер меняет состояние миграции в секции finalize
, уже после
всех остальных действий. Так что если в ходе except
или
else
произошла ошибка, то состояние миграции не
изменится. А поскольку раньше у нас воркеры запускались не в
транзакции, то здесь могла возникнуть неконсистентность.
Воркер migrate_rollback¶
Этот воркер вынимает из таблицы migrations все записи со статусом
rollback
. И для каждой из них поочереди берёт лок, и дальше делает
следующее:
Если org_id в записи нет, то сразу проставляется статус
rollback_completed
.Если к организации привязаны записи в табличке migrate_email, то на каждую такую запись берётся лок по id и если хотя бы для одной лок взять не получилось, то решаем, что всё ещё идёт миграция (что странно, ведь миграция в статусе
rollback
) и просто делаем выход из процедурыmigrate_rollback
.Note
При этом откат других организаций перестаёт обрабатываться до тех пор, пока не откатится эта странная организация у которой всё ещё мигрируют ящики.
В целом, попытка брать локи - весьма стрёмный способ определить, что миграция всё ещё идёт.
Если на все записи из
migrate_email
удалось взять лок, или их уже нет, то пробуем достать из базы Директорииmaster_domain
. Если его почему-то нет, то делаемcontinue
и откат миграции зависает. Возможно именно это произошло с 45 организациями, у которых сейчасready=False
.Если все предыдущие пункты прошли, то запускаем
PddDomainMigrationRollback.rollback
:Удаляются рассылки, созданные для Отделов.
Деактивируются b2b пользователи в Диске.
Удаляется признак воркспейсности домена в паспорте (через сброс organization_name).
Дожидаемся, пока у всех пользователей пропадёт атрибут 1011.
Делаем downgrade домена в ПДД.
Дёргаем ручку Abook
workspace/rollback
для отката общей адресной книги.Записываем действие
organization_delete
.Удаляем пользователей из мета-базы Директории.
Сбрасываем руководителей отделов и авторов Команд в None.
Удаляем через ПДД аккаунт каждого робота, созданного для сервисов.
Чистим RobotServiceModel.
Удаляем всех пользователей, отделы и команды, а так же записи про домены, действия, события, migrate_email, ресурсы с так далее.
Note
но кстати, почему-то
migrate_log
табличка не очищается.В довершение всего, удаляются записи про организацию из обычной и мета баз.
Если метод
rollback
отработал корректно, то миграции проставляется статусrollback_completed
. Если произошло исключениеPddException
, то статусerror
и вdata
пишется код из исключения. В случае любого другого исключения типа Exception, просто в статусerror
переходит миграция.
Переходы статусов¶
check
|- in_progress, если уже есть параллельная такая же миграция (здесь
| возможна ошибка, потому что получается две записи в таблице migration).
|- error, или другие ошибки если миграция не возможна
|- setup
|- ???
|- rollback
|- rollback_completed
|- error