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:
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:
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.
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:
Upgrade, rollback, the relevant code here