diff options
author | tianxing <15210838572@139.com> | 2018-09-21 11:36:45 +0800 |
---|---|---|
committer | Tian Xing <15210838572@139.com> | 2018-10-08 03:22:47 +0000 |
commit | bd77d972c666cf7a57b610bea5b29ba99444de78 (patch) | |
tree | ab05193d5716cbcdcd026ae57f04c6491e7c3b00 | |
parent | 6594edc6160fb2a43685e383f0dd8727f2df667f (diff) |
add function of update
Change-Id: I7d6107d1f7210ed460c82b8f9a76a4d6bf8566d8
Issue-ID: VFC-1139
Signed-off-by: tianxing <15210838572@139.com>
-rw-r--r-- | lcm/ns/biz/ns_update.py | 150 | ||||
-rw-r--r-- | lcm/ns/serializers/update_serializers.py | 2 | ||||
-rw-r--r-- | lcm/ns/urls.py | 5 | ||||
-rw-r--r-- | lcm/ns/views/update_ns_view.py | 57 |
4 files changed, 211 insertions, 3 deletions
diff --git a/lcm/ns/biz/ns_update.py b/lcm/ns/biz/ns_update.py new file mode 100644 index 00000000..cb00ced8 --- /dev/null +++ b/lcm/ns/biz/ns_update.py @@ -0,0 +1,150 @@ +# Copyright (c) 2018, CMCC Technologies Co., Ltd. + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import logging +import threading +import traceback +import datetime +import time + +from lcm.ns.const import NS_INST_STATUS +from lcm.pub.database.models import JobModel, NSInstModel +from lcm.ns_vnfs.biz.update_vnfs import NFOperateService +from lcm.pub.exceptions import NSLCMException +from lcm.pub.utils.jobutil import JobUtil, JOB_MODEL_STATUS +from lcm.pub.utils.values import ignore_case_get +from lcm.pub.utils.enumutil import enum + +JOB_ERROR = 255 +logger = logging.getLogger(__name__) +OPERATIONAL_STATES = enum(STOPPED='STOPPED', STARTED='STARTED') +STOP_TYPE = enum(GRACEFUL='GRACEFUL', FORCEFUL='FORCEFUL') + + +class NSUpdateService(threading.Thread): + def __init__(self, ns_instance_id, request_data, job_id): + super(NSUpdateService, self).__init__() + self.ns_instance_id = ns_instance_id + self.request_data = request_data + self.job_id = job_id + + self.update_type = '' + self.operate_vnf_data = '' + + def run(self): + try: + self.do_biz() + except NSLCMException as e: + logger.error(traceback.format_exc()) + JobUtil.add_job_status(self.job_id, JOB_ERROR, e.message) + except: + logger.error(traceback.format_exc()) + JobUtil.add_job_status(self.job_id, JOB_ERROR, 'ns update fail') + + def do_biz(self): + self.update_job(1, desc='ns update start') + self.get_and_check_params() + self.update_ns_status(NS_INST_STATUS.UPDATING) + self.do_update() + self.update_ns_status(NS_INST_STATUS.ACTIVE) + self.update_job(100, desc='ns update success') + + def get_and_check_params(self): + ns_info = NSInstModel.objects.filter(id=self.ns_instance_id) + if not ns_info: + raise NSLCMException( + 'NS [id=%s] does not exist' % self.ns_instance_id) + + self.update_type = ignore_case_get(self.request_data, "updateType") + if not self.update_type: + raise NSLCMException( + 'UpdateType parameter does not exist or value incorrect.') + + def do_update(self): + if self.update_type == "OPERATE_VNF": + self.operate_vnf_data = ignore_case_get( + self.request_data, "operateVnfData") + if not self.operate_vnf_data: + raise NSLCMException( + 'OperateVnfData does not exist or value is incorrect.') + for vnf_update_data in self.operate_vnf_data: + vnf_update_params = self.prepare_update_params(vnf_update_data) + status = self.do_vnf_update(vnf_update_params, 15) + if status is JOB_MODEL_STATUS.FINISHED: + logger.info( + 'nf[%s] update handle end' % vnf_update_params.get('vnfInstanceId')) + self.update_job(90, + desc='nf[%s] update handle end' + % vnf_update_params.get('vnfInstanceId')) + else: + raise NSLCMException('nf update failed') + else: + raise NSLCMException('Method update.') + + def do_vnf_update(self, vnf_update_params, progress): + vnf_instance_id = vnf_update_params.get('vnfInstanceId') + nf_service = NFOperateService(vnf_instance_id, vnf_update_params) + nf_service.start() + self.update_job(progress, desc='nf[%s] update handle start' % vnf_instance_id) + status = self.wait_job_finish(nf_service.job_id) + return status + + @staticmethod + def prepare_update_params(vnf_data): + vnf_instance_id = ignore_case_get(vnf_data, 'vnfInstanceId') + if not vnf_instance_id: + raise NSLCMException( + 'VnfInstanceId does not exist or value is incorrect.') + + change_state_to = ignore_case_get(vnf_data, 'changeStateTo') + if not change_state_to: + raise NSLCMException( + 'ChangeStateTo does not exist or value is incorrect.') + Stop_Type = '' + graceful_stop_timeout = '' + operational_states = ignore_case_get(change_state_to, 'OperationalStates') + if operational_states == OPERATIONAL_STATES.STOPPED: + stop_type = ignore_case_get(vnf_data, 'stopType') + Stop_Type = ignore_case_get(stop_type, 'StopType') + if Stop_Type == STOP_TYPE.GRACEFUL: + graceful_stop_timeout = ignore_case_get(vnf_data, 'gracefulStopTimeout') + + result = { + "vnfInstanceId": vnf_instance_id, + "changeStateTo": operational_states, + "stopType": Stop_Type, + "gracefulStopTimeout": graceful_stop_timeout + } + return result + + @staticmethod + def wait_job_finish(sub_job_id, timeout=3600): + query_interval = 2 + start_time = end_time = datetime.datetime.now() + while (end_time - start_time).seconds < timeout: + job_result = JobModel.objects.get(jobid=sub_job_id) + time.sleep(query_interval) + end_time = datetime.datetime.now() + if job_result.progress == 100: + return JOB_MODEL_STATUS.FINISHED + elif job_result.progress > 100: + return JOB_MODEL_STATUS.ERROR + else: + continue + return JOB_MODEL_STATUS.TIMEOUT + + def update_job(self, progress, desc=''): + JobUtil.add_job_status(self.job_id, progress, desc) + + def update_ns_status(self, status): + NSInstModel.objects.filter(id=self.ns_instance_id).update(status=status) diff --git a/lcm/ns/serializers/update_serializers.py b/lcm/ns/serializers/update_serializers.py index 80d506ed..fc3b6fb3 100644 --- a/lcm/ns/serializers/update_serializers.py +++ b/lcm/ns/serializers/update_serializers.py @@ -147,7 +147,7 @@ class OperationalStatesSerializer(serializers.Serializer): class StopTypeSerializer(serializers.Serializer): - StopType = serializers.CharField(help_text="Type of stop", choices=["FORCEFUL", "GRACEFUL"]) + StopType = serializers.ChoiceField(help_text="Type of stop", choices=["FORCEFUL", "GRACEFUL"]) class OperateVnfDataSerializer(serializers.Serializer): diff --git a/lcm/ns/urls.py b/lcm/ns/urls.py index 4322d763..53c42498 100644 --- a/lcm/ns/urls.py +++ b/lcm/ns/urls.py @@ -18,6 +18,7 @@ from lcm.ns.views.create_ns_view import CreateNSView from lcm.ns.views.inst_ns_view import NSInstView from lcm.ns.views.term_ns_view import TerminateNSView from lcm.ns.views.heal_ns_view import NSHealView +from lcm.ns.views.update_ns_view import NSUpdateView from lcm.ns.views.get_del_ns_view import NSDetailView from lcm.ns.views.inst_ns_post_deal_view import NSInstPostDealView from lcm.ns.views.scale_ns_views import NSManualScaleView @@ -31,10 +32,10 @@ urlpatterns = [ url(r'^api/nslcm/v1/ns/(?P<ns_instance_id>[0-9a-zA-Z_-]+)$', NSDetailView.as_view()), url(r'^api/nslcm/v1/ns/(?P<ns_instance_id>[0-9a-zA-Z_-]+)/postdeal$', NSInstPostDealView.as_view()), url(r'^api/nslcm/v1/ns/(?P<ns_instance_id>[0-9a-zA-Z_-]+)/scale$', NSManualScaleView.as_view()), - url(r'^api/nslcm/v1/ns/(?P<ns_instance_id>[0-9a-zA-Z_-]+)/heal$', NSHealView.as_view()) + url(r'^api/nslcm/v1/ns/(?P<ns_instance_id>[0-9a-zA-Z_-]+)/heal$', NSHealView.as_view()), # SOL005 URL API definition TODO - + url(r'^api/nslcm/v1/ns/(?P<ns_instance_id>[0-9a-zA-Z_-]+)/update$', NSUpdateView.as_view()) ] urlpatterns = format_suffix_patterns(urlpatterns) diff --git a/lcm/ns/views/update_ns_view.py b/lcm/ns/views/update_ns_view.py new file mode 100644 index 00000000..45aa2735 --- /dev/null +++ b/lcm/ns/views/update_ns_view.py @@ -0,0 +1,57 @@ +# Copyright (c) 2018, CMCC Technologies Co., Ltd. + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import logging + +from rest_framework import status +from rest_framework.response import Response +from rest_framework.views import APIView +from drf_yasg.utils import swagger_auto_schema + +from lcm.ns.biz.ns_update import NSUpdateService +from lcm.ns.serializers.ns_serializers import NsOperateJobSerializer +from lcm.ns.serializers.update_serializers import UpdateNsReqSerializer +from lcm.pub.exceptions import NSLCMException +from lcm.pub.utils.jobutil import JobUtil, JOB_TYPE + +logger = logging.getLogger(__name__) + + +class NSUpdateView(APIView): + @swagger_auto_schema( + request_body=UpdateNsReqSerializer(), + responses={ + status.HTTP_202_ACCEPTED: NsOperateJobSerializer(), + status.HTTP_500_INTERNAL_SERVER_ERROR: "Inner error" + } + ) + def post(self, request, ns_instance_id): + try: + logger.debug("Enter UpdateNSView::post %s, %s", request.data, ns_instance_id) + req_serializer = UpdateNsReqSerializer(data=request.data) + if not req_serializer.is_valid(): + raise NSLCMException(req_serializer.errors) + + job_id = JobUtil.create_job("VNF", JOB_TYPE.HEAL_VNF, ns_instance_id) + NSUpdateService(ns_instance_id, request.data, job_id).start() + + resp_serializer = NsOperateJobSerializer(data={'jobId': job_id}) + if not resp_serializer.is_valid(): + raise NSLCMException(resp_serializer.errors) + + logger.debug("Leave UpdateNSView::post ret=%s", resp_serializer.data) + return Response(data=resp_serializer.data, status=status.HTTP_202_ACCEPTED) + except Exception as e: + logger.error("Exception in UpdateNSView: %s", e.message) + return Response(data={'error': e.message}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) |