Появилась необходимость сменить основной домен компании в G Suite с .ru на .com с сохранением всех данных, календарей, псевдонимов и доступов на сторонние ресурсы. Информации о переезде в интернете не очень много, а точнее, кроме справки самого Google, вообще ничего не нашлось, что и стало причиной создания этого how-to. Будет полезно, если кто-то решит повторить подобное.
Дело в том, что изначально в компании использовался домен pixonic.ru. Затем был добавлен псевдоним pixonic.com, но везде по умолчанию стояла почта в зоне .ru. А так как многие сотрудники компании ведут переписку с зарубежными коллегами и клиентами, было желание использовать международный формат. Для этого им приходилось заходить в настройки аккаунта, самостоятельно менять основной почтовый адрес и приводить подпись в соответствие с корпоративным шаблоном. Не все это делали (или делали, но через раз) и можно представить, какой беспорядок и путаница творились в ветках сообщений. Для внешних партнеров это выглядело еще менее презентабельно из-за разных подписей.
В общем, настал момент, когда было решено — вся переписка должна вестись с использованием почты pixonic.com. Задача упала на нас — системных администраторов.
В конце статьи есть ссылка на весь скрипт, поэтому в тексте будут лишь его куски.
Мы используем Google для бизнеса, поэтому и почта располагается на том же сервисе. Итак, что имелось:
- Домен pixonic.ru.
- Псевдонимы pixonic.com и pixonic.org.
- ~200 учетных записей и ~80 групп рассылок.
- Куча псевдонимов у некоторых учетных записей.
- Календари, в том числе общие для компании.
- Подключена Google-аналитика.
- Десятки терабайтов важной информации на Google Drive.
- Сторонние сервисы Jira, Slack и другие, в которых авторизация происходила с помощью учетной записи Google.
Что планировалось:
- Сделать pixonic.com основным доменом, а pixonic.ru и pixonic.org — его псевдонимами.
- Переезд всех учетных записей в pixonic.com с сохранением всей корреспонденции и информации на Google Drive.
- Переезд почтовых групп с сохранением состава и прав ее участников.
- Сохранение всех псевдонимов пользователей.
- Сохранение доступов ко всем расшаренным файлам в Google Диск для учетных записей.
- Сохранение календарей, чтобы не потерялась информация о запланированных встречах и мероприятиях.
- Сохранение доступов в Jira и Slack.
- По максимуму избежать потери почты.
Конечно, первым делом написали в техподдержку с просьбой поменять нам основной домен. Получили ответ — сделать они этого не могут и, вообще, посоветовали так никогда не рисковать.
Ладно. Перенастраивать аккаунт каждого пользователя вручную — перспектива так себе. Да еще подобную процедуру приходилось бы делать для каждого нового сотрудника отдельно. Можно еще попробовать сделать через API, но опять же — это не решит всех проблем, т.к. многие пользуются сторонними почтовыми клиентами со старыми настройками. Да и проблема с новыми сотрудниками никуда не денется.
В справке по переезду от самого Google пять пунктов:
- Добавьте дополнительный домен и настройте записи MX.
- Сделайте новый домен основным.
- Переименуйте пользователей в соответствии с новым основным доменом.
- Переименуйте группы в соответствии с новым основным доменом.
- Удалите прежний основной домен (необязательно).
Выглядит не сложно, надо пробовать.
Что точно останется, а что может потеряться в результате подобных действий — не указывалось. Поэтому мы сделали тестовое окружение, купили еще один G Suit и добавили к нему тестовых доменов.
Потом обозначили требования для переезда: сохранение информации, прав и доступов пользователей. Т.е. единственная проблема, с которой должен был столкнуться конечный пользователь — это необходимость заново зайти в свой новый аккаунт на всех устройствах.
И начали тесты.
Тестирование возможных сценариев и проверка заняли у нас почти месяц. Результаты тестов были очень обнадеживающими, поэтому мы решились повторить все на рабочем окружении.
Алгоритм действий
Все, что можно было сделать не руками — сделано скриптом на Python 3.6. Из сторонних модулей нам потребуется google-api-python-client, oauth2client,httplib2, apiclient и pyopenssl. Без проблем устанавливаются с помощью pip.
Чтобы воспользоваться Google API, надо создать сервисный аккаунт в консоли разработчика. Для этого создаем проект (либо используем имеющийся), выбираем «Учетные данные > Создать учетные данные > Ключ сервисного аккаунта».
Выбираем «Новый сервисный аккаунт», именуем его, назначаем роль «Владелец», выбираем ключ P12 (по поводу ключа не очень принципиально, но во время тестов у меня с JSON получилось авторизоваться только с явной выдачей разрешений от конкретного пользователя, от имени которого производились операции, что в данном случае не подходит).
Авторизовать сервисный аккаунт в консоли администратора в разделе «Безопасность > Расширенные настройки > Управлять доступом клиента API».
API может работать только в той области, в которой его авторизовали (описание всех областей можно прочитать здесь). Я использовал следующие:
- Email (Read/Write/Send) mail.google.com
- www.googleapis.com/auth/activity
- View and manage the provisioning of groups on your domain www.googleapis.com/auth/admin.directory.group
- View and manage the provisioning of users on your domain www.googleapis.com/auth/admin.directory.user
- www.googleapis.com/auth/drive.metadata.readonly
- www.googleapis.com/auth/gmail.settings.basic
- www.googleapis.com/auth/gmail.settings.sharing
После того, как API проверено, можно приступать к самим работам по переносу.
Основа всего скрипта — это получение прав и делегирование их на какого-либо пользователя в зависимости от требуемых действий. Т.е. если вам нужно поменять подпись кого-либо в почте, то делегирование нужно производить на эту же учетную запись; если получить список пользователей — то на аккаунт администратора и т.п.
Так это выглядит у меня:
def get_credentials(email):
# Авторизация и делегирование прав на e-mail
credentials = ServiceAccountCredentials.from_p12_keyfile(
SERVICE_ACCOUNT_EMAIL,
SERVICE_ACCOUNT_PKCS12_FILE_PATH,
'notasecret',
scopes=['https://www.googleapis.com/auth/admin.directory.user',
'https://www.googleapis.com/auth/gmail.settings.sharing',
'https://www.googleapis.com/auth/gmail.settings.basic', 'https://mail.google.com/',
'https://www.googleapis.com/auth/activity',
'https://www.googleapis.com/auth/drive.metadata.readonly',
'https://www.googleapis.com/auth/admin.directory.group'])
delegate_credentials = credentials.create_delegated(email)
return delegate_credentials.authorize(httplib2.Http())
По сути мы вызываем эту функцию перед каждым действием, затем выбираем приложение, в котором нужно произвести манипуляции, и запускаем API. Выполнение API возвращает либо результат выполнения, либо данные, которые запрашивались.
http = get_credentials(adminEmail)
service = build('admin', 'directory_v1', http=http)
data = service.users().aliases().list(userKey=usermail).execute()
print(data)
Начало работ обозначаем созданием бэкапа всего, что нам может потребоваться, а именно: информации о пользователях, группах, составе групп, псевдонимов пользователей и псевдонимов групп.
Тут все просто: запрашиваем инфу, записываем в файл, благо Google предоставляет всю информация в JSON-формате и с ней удобно работать.
def backUpInfo(filename=''):
path = os.path.expanduser('~/Documents/backup/')
prefix = path+'backup'
if not (filename == ''):
prefix = path + filename
#backupUsers
with open(prefix + 'Users.json', 'w') as file:
userInfo = getAllInfoUsers()
file.write(json.dumps(userInfo, indent=4))
print(prefix + 'Users.json done')
#backupGroups
with open(prefix + 'Groups.json', 'w') as file:
groupInfo = getAllInfoGroups()
file.write(json.dumps(groupInfo, indent=4))
print(prefix + 'Groups.json done')
#backupUsersInGroups
with open(prefix + 'UsersInGroups.json', 'w') as file:
groupInfo = getAllUsersInGroups()
file.write(json.dumps(groupInfo, indent=4))
print(prefix + 'UsersInGroups.json done')
#backupUsersAliases
with open(prefix + 'UsersAliases.json', 'w') as file:
info = getUsersAliases()
file.write(json.dumps(info, indent=4))
print(prefix + 'UsersAliases.json done')
#backupGroupsAliases
with open(prefix + 'GroupsAliases.json', 'w') as file:
info = getGroupAliases()
file.write(json.dumps(info, indent=4))
print(prefix + 'GroupsAliases.json done')
Следующий шаг — это удаление псевдонима com и добавление его как домена. Эти действия производятся в консоли администрирования > Домены > Добавление/удаление доменов.
При добавлении домена надо указывать MX-записи и сервису необходимо некоторое время, чтобы их проверить (в нашем случае это заняло пару минут). В принципе, окончания проверки можно не дожидаться и продолжать работы.
После добавления домена появится возможность сделать его основным, что мы и делаем (такой возможности нет в триальной версии G suit, появляется только в платной версии и не сразу после оплаты, а только после истечения пробного периода, что странно).
Потом у нас идет перенос пользователей и групп в новый домен. Алгоритм следующий:
- делегируем права на учетную запись администратора;
- выгружаем весь список пользователей;
- проходимся по каждому пользователю, кроме учетной записи администратора, под которым работаем;
- и изменяем поле primaryEmail через API функцию users().update().
Т.е. перенос пользователя через API заключается в изменении домена в основном почтовом адресе с .ru на .com. Выглядит это так:
def moveUsers(domain):
# Получаем список всех пользователей
users = getUsers()
# Переименовываем всех пользователей, кроме adminEmail
for a in users:
if adminEmail in a[0]: continue
try:
renameUser(a[0], domain)
print('Done: ' + a[0])
except Exception as e:
print(sys.exc_info()[0], ":", e)
print('Failed: ' + a[0])
print("Users done!!!")
Функция users().update() очень полезна, так как позволяет изменить любую информация в профиле пользователя. Ей в параметрах передается логин пользователя и изменяемые параметры в JSON-формате.
def renameUser(email, domain):
patch = {'primaryEmail': changeMailDomain(email=email, domain=domain)}
http = get_credentials(adminEmail)
service = build('admin', 'directory_v1', http=http)
service.users().update(userKey=email, body=patch).execute()
Аналогичным образом можно добавлять информацию в профиль, например: аккаунт Skype, дополнительную должность и все, что угодно, на ваш вкус.
Подобную операцию проводим для групп.
Переносим свой аккаунт в новый домен. После этого необходимо зайти в ваш новый аккаунт и заново произвести авторизацию сервисной учетной записи. Менять в ней ничего не требуется, просто берете ее имя из графы «Авторизованные клиенты API», а список нужных областей из второй колонны.
Сейчас в нашем старом домене никого не должно быть. Поэтому заходим в список доменов в консоли администратора и удаляем его. А после добавляем его на место, но уже как псевдоним (если вам вообще нужен старый домен).
Остался последний штрих. После того как мы в начале удалили псевдоним «com», все алиасы пользователей и групп тоже удалились, поэтому нам надо восстановить их из резервной копии, которую мы сделали в самом начале. При этом имеет смысл изменить во всех алиасах домен на наш новый, т.к. на все вспомогательные домены псевдонимы появятся автоматически. Для этого загружаем информацию из бэкапа, проходимся по каждому пользователю и восстанавливаем все псевдонимы, если они есть в наличии при помощи users().aliases().insert(userKey=email, body=body).
Аналогичную операцию производим для групп.
Ну всё, переехали.
Ссылка на Github.
P.S. Некоторые изменения видны не сразу. Например, после удаления старого домена и добавления его как псевдонима, если зайти в админке в чей-либо аккаунт, то там будут видны его псевдонимы, которых на самом деле уже нет. Их в любом случае придется восстанавливать.
Что в итоге?
Мы переехали с минимумом потерь. Работы с момента создания резервной копии, до момента восстановления псевдонимов заняли ~20 минут.
Доступы не пропали, состав почтовых групп не изменился. Нам никто не пожаловался о каких-либо проблема с учетной записью, мол, не могу зайти в аккаунт или прочитать какой-либо файл. Общие календари остались целы, запланированные события не пропали.
Со сторонними сервисами не все так радостно, хотя приемлемо. Авторизация в них не слетела, но кто регистрировался на старую почту, под ней же и должны заходить, поэтому там нельзя выбрать вход через Google+. Нас это особо не коснулось, т.к. все пользователи были предупреждены об этом до начала и после окончания работ. В случае со Slack проблему тоже можно решить через API, изменив адреса пользователей. В облачной Jira, увы, так не получится, но если вы используете локальный сервер, то проблема решаема.
Бонусом мы получили хороший инструмент для создания пользователей с уже готовыми подписями, сделанными по корпоративному шаблону. И в случае необходимости подпись легко обновить без участия пользователя. Кроме того, с помощью API удобно обновлять информацию в профиле сотрудника или же наоборот, получать.
Комментарии (11)
VecH
21.02.2018 19:29А у меня не дает сменить с домена site-old.ru на new-domain.ru а старом аккаунте где еще лимит пользователейбыл = 100 (точно не помню)
aleshkashell Автор
21.02.2018 19:34В каком моменте проблема? Не дает сделать new-domain.ru основным? У нас такое ограничение было на тестовом аккаунте, пока не закончился триальный период. Так же google не даст удалить домен, если он не пустой.
VecH
21.02.2018 21:08У меня старый аккаунт на котором можно создать 100 пользователей (использую только 5) по подписке Google Apps, боюсь переходить на G-Suite, не знаю что потеряю
Тестовый домен добавил, но кнопки назначения его основным не появляетсяaleshkashell Автор
21.02.2018 22:12Не знаю с чем связано такое ограничение, разве что может быть у вас бесплатный аккаунт, но возможно подойдет способ, описанный в этой статье habrahabr.ru/post/304636
Oval
21.02.2018 19:33А я вот удалил свой G Suite акаунт переехав на бесплатный яндекс, а гугл до сих пор снимает с карточки оплату. Самое смешное я ничего не могу сделать — даже для обращения в поддержку нужно зайти в действующий акаунт G Suite.
fedorro
22.02.2018 12:09Попробовать написать на емаил, или зарегистрировать тестовый аккаунт и с него написать. Ну или карту перевыпустить. А ещё можно в банк написать, что снимают за неоказанную услугу — может и вернуть что то получится.
НУ или можно считать себя спонсором Гугла)
divanikus
А чего GAM не заюзали? Не подошел совсем?
aleshkashell Автор
Мы не рассматривали этот вариант. Помимо работы с учетными данными, пользователей была потребность работать с Google Spreadsheets, а производить операции с данными все-таки проще на Python. Плюс, для понимания работы, так же пришлось бы ознакамливаться с api.
В общем, если бы задача заключалась в простом переименовании пользователей, то да этим инструментом вполне можно было бы обойтись, не вдаваясь подробности работы самого сервиса.