zoukankan      html  css  js  c++  java
  • Django实现自动发布(3发布-升级和回退)

    发布实际上就是将服务的某个版本和一台主机关联,我用一张表(MicroServiceInstance)记录了主机id、服务id、版本id,目前一台主机只能部署一个版本,所以主机id和服务id要做联合索引。

    当我们操作某个实例时(升级、回退),为了防止其他人也进行相关操作,要对实例当前的状态就行判断,这里用 locked 标记。

    升级、回退操作类似,都是更新MicroServiceInstance表记录的版本id,可以放在一个视图里实现。

    升级回退页面

    点击页面的版本管理,则弹出对应服务的版本列表页面,在这个页面可以进行发布操作,如下图:
    版本列表

    然后点击某个版本的 升级回退 ,则弹出页面,用户可以选择需要目标版本和相应的主机:
    版本选择

    由于获取主机相关的视图函数还未实现,所以页面显示了数据接口异常

    当打开升级页面时,应该只能选择比当前版本高的版本,即id号大于当前id;同理回退页面则只能选择比当前版本低的版本,即id号小于当前id。而且用户只能选择构建成功的版本进行操作。
    版本升级选择

    版本号下拉框的数据由后端返回:

    class VersionDeployActionApi(generic.View):
        def get(self, request, service_id, action, pk):
            if action not in ('upgrade', 'revert'):
                return JsonResponse({'msg': '仅支持 upgrade/revert', 'code': -1}, status=417)
    
            cur_id = int(pk)
            versions = MicroServiceVersion.objects.filter(
                microservice_id=service_id,
                status=BuildStatus.success.value
            ).order_by('-id')
    
            data = [{
                'id': item.id,
                'version': item.version,
                'enable': item.id > cur_id if action == 'upgrade' else cur_id > item.id,
            } for item in versions]
    
            return JsonResponse({
                'data': data,
                'count': versions.count(),
                'code': 0,
            })
    

    实例

    页面上可供选择的实例,在数据库中体现为当前版本id关联的全部MicroServiceInstance对象,先在数据库中初始化一些对应关系

    python manage.py shell
    
    from microservice.models import *
    MicroServiceInstance.objects.create(microservice_id=1, version_id=2, updated_by_id=1, host_id=1)
    

    然后是返回当前版本下的全部实例:

    class InstanceApi(generic.View):
        def get(self, request, service_id):
            query = request.GET
            version_id = query.get('version_id')
            locked = query.get('locked')
    
            try:
                service = MicroService.objects.get(pk=service_id)
            except MicroService.DoesNotExist:
                return JsonResponse({'msg': '资源不存在'}, status=404)
    
            insts = MicroServiceInstance.objects.filter(microservice=service)
            if version_id:
                insts = insts.filter(version_id=version_id)
    
            insts = insts.select_related('version').select_related('host').select_related('updated_by')
    
            if locked is not None:
                lck = False if locked in ('0', 'false') else True
                insts = insts.filter(locked=lck)
    
            data = [{
                'id': item.id,
                'name': service.name,
                'language': service.language,
                'version': item.version.version,
                'host': ':'.join((item.host.hostname, item.host.ip)),
                'host_id': item.host_id,
                'port': item.port,
                'tag': item.tag,
                'weight': item.weight,
                'description': item.description,
                'status': item.status,
                'status_str': item.get_status_display(),
                'is_maintain': item.is_maintain,
                'updated_by': item.updated_by.username,
                'updated': localtime(item.updated).strftime('%Y-%m-%d %H:%M:%S %Z'),
            } for item in insts]
    
            return JsonResponse({
                'data': data,
                'count': insts.count(),
                'code': 0,
            })
    

    当lock为true时,代表实例正在被操作,前端查询时可以带上参数: lock=1,这样就只返回可进行发布的实例

    执行升级/回退

    页面选好了目标版本和对应的主机后,发送数据到后端,后端判断参数后执行相应的任务。

    web开发有一条规则:永远不要相信用户的输入

    为了保证服务实例数据的正确性、完整性,对用户提交的发布操作参数要进行严格校验:

    • 校验 service
    • 校验 version
    • 校验参数是否合法
    • 校验传入的主机id在数据库中是否有记录
    • 只更新db中存在且lock为false的实例

    相关的代码实现:

    # class VersionDeployActionApi 增加 post 方法
    
        def post(self, request, service_id, action, pk):
            params = request.POST
            q = {}
            q['dest_version'] = params.get('dest_version', '')
            q['host'] = params.get('host', '')
    
            if not q['dest_version']:
                return JsonResponse({'msg': '版本号不能为空'}, status=417)
    
            if not q['host']:
                return JsonResponse({'msg': '主机不能为空'}, status=417)
            else:
                if q['host'] != 'all' and (not re.match(r'[0-9,]', q['host'])):
                    return JsonResponse({'msg': '主机参数错误,请传入 all 或以逗号分隔的id值'}, status=417)
    
            # 先获取服务
            try:
                service = MicroService.objects.get(pk=service_id)
                insts = MicroServiceInstance.objects.select_related('host').select_related('version').filter(version__id=pk)
                dest_ver = MicroServiceVersion.objects.filter(microservice=service).get(pk=q['dest_version'])
            except ObjectDoesNotExist:
                return JsonResponse({'msg': '资源不存在'}, status=404)
    
            db_idset = req_idset = set([x.host_id for x in insts])
            if q['host'] != 'all':
                req_idset = set([int(x) for x in q['host'].split(',') if x])
            # 如果传入的主机id在 db 中不存在
            if req_idset - db_idset:
                return JsonResponse({'msg': '请发送正确的主机id'}, status=404)
    
            # 只更新db中存在 且未锁定 的主机id
            idset = db_idset & req_idset
    
            st = InstanceStatus.upgrading.value if action == 'upgrade' else InstanceStatus.reverting.value
            for inst in insts:
                if inst.host_id in idset and not inst.locked:
                    d = {
                        'updated_by': request.user,
                        'updated': now(),
                        'status': st,
                        'locked': True,
                    }
                    print d
                    MicroServiceInstance.objects.filter(pk=inst.id).update(**d)
    
            # TODO 发起任务
    
            return JsonResponse({})
    

    TODO 可以使用celery发起一个耗时的任务操作,而视图函数可以立即返回。

    页面效果如下:
    版本回退

    升级、回退,相关的代码在 这里

  • 相关阅读:
    《Dotnet9》系列-开源C# WPF控件库强力推荐
    《Dotnet9》系列-开源C# WPF控件库3《HandyControl》强力推荐
    《Dotnet9》系列-开源C# WPF控件库2《Panuon.UI.Silver》强力推荐
    《Dotnet9》系列-开源C# WPF控件库1《MaterialDesignInXAML》强力推荐
    《Dotnet9》系列-FluentValidation在C# WPF中的应用
    《Dotnet9》建站-本站使用的什么主题?
    结对作业——第二次作业
    团队第一次作业——团队展示
    结队项目——第一次作业
    软件工程实践2017第二次作业
  • 原文地址:https://www.cnblogs.com/wbjxxzx/p/12039094.html
Copyright © 2011-2022 走看看