通过 Google Workspace Admin SDK 用户数据迁移删除实践

背景介绍

谷歌企业账户能不能通过相应的API管理了?如何实现账户回收及数据迁移了?
谷歌提供了一套名为 Workspace Admin SDK 的API管理接口,笔者使用的python,下面一起来看看如何通过这个接口实现账户回收及数据迁移吧。

SCOPES授权请参照此篇文章:https://zhuanlan.zhihu.com/p/567568321

系统环境

  • WIN11
  • Python 3.10

库安装

pip install google-api-python-client google-auth-httplib2 google-auth-oauthlib

代码部分

用户管理

class UserManageApiRequest(object):  
    def __init__(self): 
	    # 此处为密钥文件路径
        SERVICE_ACCOUNT_FILE = "****.json"  
        # 鉴权地址,根据操作定义
        SCOPES = ['https://www.googleapis.com/auth/admin.directory.user']  
        try:  
            # 授权空间(scope)和授权秘钥  
            self.credential = service_account.Credentials.from_service_account_file(SERVICE_ACCOUNT_FILE, scopes=SCOPES)  
            # 授权的账户
            self.credentials = self.credential.with_subject('accountapi@gmail.com') 
            # 接口权限目录 
            self.service = build("admin", "directory_v1", credentials=self.credentials)  
            self.result = True  
  
        except Exception as err:  
            self.result = err  
  
    def get_user_data(self, user_email: str) -> dict:  
        results = dict()  
        try:  
            results[user_email] = self.service.users().get(userKey=user_email).execute()  
        except Exception as err:  
            results[user_email] = err  
  
        return results  
  
    def delete_user(self, user_email: str):  
        try:  
            results = self.service.users().delete(userKey=user_email).execute()  
  
        except Exception as err:  
            print('{} 删除失败'.format(user_email))  
            raise err  
        else:  
            return results  
  

用户数据管理

class UserDataManage(object):  
    def __init__(self):  
        SERVICE_ACCOUNT_FILE = "****.json"  
        SCOPES = ['https://www.googleapis.com/auth/admin.datatransfer']  
        try:   
            self.credential = service_account.Credentials.from_service_account_file(SERVICE_ACCOUNT_FILE, scopes=SCOPES)  
            self.credentials = self.credential.with_subject('accountapi@gmail.com')  
            self.service = build('admin', 'datatransfer_v1', credentials=self.credentials)  
            self.result = True  
  
        except Exception as err:  
            print(err)  
            self.result = err  
  
    def get_applications_info(self) -> dict:  
        try:  
            results = self.service.applications().list().execute()  
            self.service.close()  
        except Exception as err:  
            raise err  
        else:  
            return results  
  
    def user_data_migration(self, new_user_id: str, old_user_id: str, operation: str) -> dict:  
        try:  
            Drive_and_Docs = {  
                "applicationDataTransfers": [  
                    {  
                        "applicationId": '55656082996',  
                        "applicationTransferParams": [  
                            {  
                                "key": "PRIVACY_LEVEL",  
                                "value": ['PRIVATE', 'SHARED'],  
                            },  
                        ],  
                    },  
                ],  
                "kind": "admin#datatransfer#DataTransfer",  
                "newOwnerUserId": new_user_id,  
                "oldOwnerUserId": old_user_id,  
            }  
  
            Currents = {  
                "applicationDataTransfers": [  
                    {  
                        "applicationId": '553547912911',  
                        "applicationTransferParams": [],  
                    }  
                ],  
                "kind": "admin#datatransfer#DataTransfer",  
                "newOwnerUserId": new_user_id,  
                "oldOwnerUserId": old_user_id,  
            }  
  
            Google_Data_Studio = {  
                "applicationDataTransfers": [  
                    {  
                        "applicationId": '810260081642',  
                        "applicationTransferParams": [  
                            {  
                                "key": "PRIVACY_LEVEL",  
                                "value": ['PRIVATE', 'SHARED'],  
                            },  
                        ],  
                    },  
                ],  
                "kind": "admin#datatransfer#DataTransfer",  
                "newOwnerUserId": new_user_id,  
                "oldOwnerUserId": old_user_id,  
            }  
  
            Calendar = {  
                "applicationDataTransfers": [  
                    {  
                        "applicationId": '435070579839',  
                        "applicationTransferParams": [  
                            {  
                                'key': 'RELEASE_RESOURCES',  
                                'value': ['TRUE'],  
                            },  
                        ],  
                    },  
                ],  
                "kind": "admin#datatransfer#DataTransfer",  
                "newOwnerUserId": new_user_id,  
                "oldOwnerUserId": old_user_id,  
            }  
  
            if operation == 'migration_Drive_and_Docs':  
                results = self.service.transfers().insert(body=Drive_and_Docs).execute()  
            elif operation == 'migration_Currents':  
                results = self.service.transfers().insert(body=Currents).execute()  
            elif operation == 'migration_Google_Data_Studio':  
                results = self.service.transfers().insert(body=Google_Data_Studio).execute()  
            elif operation == 'migration_Calendar':  
                results = self.service.transfers().insert(body=Calendar).execute()  
            else:  
                results = 'operation is migration_Drive_and_Docs migration_Currents migration_Google_Data_Studio ' \  
                          'migration_Calendar'  
  
        except Exception as err:  
            print(err)  
            raise err  
  
        else:  
            return results  
  
    def query_user_data_migration_statu(self, user_migration_id: str) -> dict:  
        try:  
            results = self.service.transfers().get(dataTransferId=user_migration_id).execute()  
        except Exception as err:  
            raise err  
        else:  
            return results

applicationDataTransfers 中的 applicationId 的值可以通过 UserDataManage().get_applications_info 方法获取所有的应用ID,部分回显示如下:

注:用户同事只能迁移一个应用数据,需要等到上个应用数据迁移完成后才能执行后续操作否则回报错,所以引入后续数据迁移状态查询函数。

查询用户数据迁移状态

def check_migration_statu(operation_statu: str, statu_info: str, user_info: str) -> dict:  
    i = 2  
    # 判断迁移状态,数据迁移完成后跳出循环,最多等待58秒。  
    try:  
        for times in range(5):  
            time.sleep(i)  
            operation_result = UserDataManage().query_user_data_migration_statu(statu_info)  
            operation_StatusCode = operation_result['overallTransferStatusCode']  
            if operation_StatusCode == 'completed':  
                print('用户邮箱是:{}  {}数据迁移完成'.format(user_info, operation_statu))  
                return {'statu': 'completed', 'info': 'no err'}  
            else:  
                print('用户邮箱是:{}  操作是:{}, 当前状态是:{}'.format(user_info, operation_statu, operation_StatusCode))  
                i += 5  
  
        return {'statu': 'err', 'info': '58秒内未完成数据迁移'}  
  
    except Exception as err:  
        print(err)  
        return {'statu': 'err', 'info': err}  
  

关联函数操作

def main(user_email: str, receive_user_id: str) -> dict:  
    operations = ['migration_Currents', 'migration_Google_Data_Studio', 'migration_Calendar',  
                  'migration_Drive_and_Docs']  
  
    # 获取发送数据用户ID  
    try:  
        user_id = UserManageApiRequest().get_user_data(user_email)[user_email]['id']  
  
    except Exception as error:  
        with open('user_get_id_error.txt', 'a+', encoding='utf-8') as r:  
            r.write('用户邮箱:{},获取用户ID失败,错误信息:{} \n'.format(user_email, error))  
        return {'statu': 'error', 'info': '获取用户ID失败,详情见user_get_id_error.txt文件信息'}  
  
    # 对数据逐个迁移  
    for one_operation in operations:  
        try:  
            operation_result = UserDataManage().user_data_migration(new_user_id=receive_user_id, old_user_id=user_id,  
                                                                    operation=one_operation)  
            migration_statu_id = operation_result['id']  
            check_result = check_migration_statu(one_operation, migration_statu_id, user_email)  
  
            if check_result['statu'] != 'completed':  
                err_info = '用户邮箱:{} 数据迁移状态检测失败,原因是:{}'.format(user_email, check_result['info'])  
                return {'statu': 'check_migration_statu_err', 'info': err_info}  
  
        except Exception as err:  
            err_info = ('用户邮箱:{} 数据迁移失败,原因是 {}'.format(user_email, err))  
            return {'statu': 'migration_data_err', 'info': err_info}  
  
    return {'statu': 'ok', 'info': 'no err'}

启动脚本

if __name__ == "__main__":  
    err_infos = list()  
    new_time = time.time()  
    # 发送数据邮箱,用户邮箱从文本中获取,每行一个邮箱账户。
    all_user = open('userinfo.txt').read().split('\n') 
    
    # 用户从列表中获取 
    # all_user = ['456@gmail.com']
    
    #  接受数据邮箱 
    receive_email = '123@gmail.com'  
  
    try:  
	    # 获取用户ID,数据传输时使用的是用户ID
        get_receive_email_id = UserManageApiRequest().get_user_data(receive_email)[receive_email]['id']  
  
        # 开始迁移用户数据。  
        for one_email in all_user:  
            new_time = time.time()  
            result = main(one_email, get_receive_email_id)  
            if result['statu'] == 'ok':  
                # 数据迁移完成后删除用户。  
                try:  
                    UserManageApiRequest().delete_user(user_email=one_email)  
                    print('用户邮箱:{} 数据迁移完成并已删除耗时:{} \n'.format(one_email, time.time() - new_time))  
                except Exception as delete_error:  
                    err_infos.append({'email': one_email, 'info': '用户删除失败,错误信息是{}'.format(delete_error)})  
                    print('用户邮箱:{},用户删除失败,错误信息是{} \n'.format(one_email, delete_error))  
            else:  
                err_infos.append({'email': one_email, 'info': result['info']})  
  
    except Exception as e:  
        print('获取接受用户ID失败,错误原因是{}'.format(e))  
  
    if err_infos:  
	    # 将错误日志写入文本文件
        print(err_infos)  
        with open('user_migration_error_log.txt', 'a+', encoding='utf-8') as user_log:  
            for one_error_log in err_infos:  
                user_log.write(str(one_error_log) + '\n')

部分运行结果截图

参考文档

https://developers.google.com/workspace
https://googleapis.github.io/google-api-python-client/docs/dyn/admin_directory_v1.users.html

友情链接

推荐三位老师 网络工程师 python入门指南
王印老师:https://zhuanlan.zhihu.com/p/486260131
九净老师:https://www.zhihu.com/column/feifeiflight
朱嘉盛老师:https://zhuanlan.zhihu.com/p/370526806

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值