Django automatic release (3 release - upgrade and rollback)

Actually released a version and a host associated with the service, I (MicroServiceInstance) records the host id, service id, version id with a table, currently a host can only deploy one version, the host id and Services id do joint index.

When we operate an instance (upgrade, rollback), in order to prevent other people also do that, to the current state of the instance on the line judge, here locked marks.

Similarly upgrade, rollback operation, it is an updated version of id MicroServiceInstance table records, can be placed in a view to achieve.

Upgrade rollback page

Click on the page version management , the pop-up version of the corresponding service list page, you can publish operation in this page, as shown below:
Version List

Then click on a version of the upgrade or rollback , the pop-up page, the user can select the desired target version and the corresponding host:
Select versions

Because to get the host associated view function has not been achieved, so the page shows the abnormal data interface

When you open the upgrade page, you should only choose higher than the current version of the version number that is greater than the current id id; Similarly rollback page you can select only version lower than the current version, that is less than the current number id id. And the user can select the version of building a successful operation.
Version Upgrade Option

The version number drop-down box data returned by the backend:

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,
        })

Examples

On page alternative example, reflected in the database for all MicroServiceInstance object id associated with the current version, some of the first correspondence relationship in the database initialization

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

Then return all instances in the current version:

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,
        })

When the lock is true, the representative example being operated, can bring the front end query parameters: lock = 1, so that only return an instance may be released

Perform the upgrade / rollback

After the selected page and the target version corresponding host transmit data to the back end, the rear end of the respective task performed after judgment parameters.

web developers have a rule: Never trust user input .

In order to ensure service instance data accuracy, completeness, posted operating parameters for user-submitted to rigorous verification:

  • Check service
  • Check version
  • Check the legality of parameters
  • Check whether there is incoming host id record in the database
  • Update instance only exists in db and the lock is false

Implement the relevant code:

# 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 can be used to initiate operation of a time-consuming task, and view function can return immediately.

Page effect is as follows:
Version rollback

Upgrade, rollback, the relevant code here

Guess you like

Origin www.cnblogs.com/wbjxxzx/p/12039094.html
Recommended