aboutsummaryrefslogtreecommitdiffstats
path: root/lcm/ns/biz/ns_manual_scale.py
blob: d3f5eebe4b8a56bb442fb72dd14e9cd6f1a49385 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
# Copyright 2017 ZTE Corporation.
#
# 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 datetime
import logging
import threading
import time
import traceback

from lcm.ns.biz.scale_aspect import get_scale_vnf_data_info_list
from lcm.ns.enum import NS_INST_STATUS
from lcm.pub.database.models import JobModel, NSInstModel
from lcm.pub.exceptions import NSLCMException
from lcm.pub.utils.jobutil import JobUtil
from lcm.jobs.enum import JOB_MODEL_STATUS, JOB_PROGRESS
from lcm.pub.utils.values import ignore_case_get
from lcm.ns_vnfs.biz.scale_vnfs import NFManualScaleService
from lcm.ns.biz.ns_lcm_op_occ import NsLcmOpOcc

JOB_ERROR = 255
SCALE_TYPE = ("SCALE_NS", "SCALE_VNF")
logger = logging.getLogger(__name__)


class NSManualScaleService(threading.Thread):
    """
    Scale the NS instance
    """

    def __init__(self, ns_instance_id, request_data, job_id):
        super(NSManualScaleService, self).__init__()
        self.ns_instance_id = ns_instance_id
        self.request_data = request_data
        self.job_id = job_id
        self.occ_id = NsLcmOpOcc.create(ns_instance_id, "SCALE", "PROCESSING", False, request_data)
        self.scale_vnf_data = ''

    def run(self):
        try:
            self.do_biz()
        except NSLCMException as e:
            JobUtil.add_job_status(self.job_id, JOB_PROGRESS.ERROR, e.args[0])
            NsLcmOpOcc.update(self.occ_id, operationState="FAILED", error=e.args[0])
        except Exception as e:
            logger.error(e.args[0])
            logger.error(traceback.format_exc())
            JobUtil.add_job_status(self.job_id, JOB_PROGRESS.ERROR, 'ns scale fail')
            NsLcmOpOcc.update(self.occ_id, operationState="FAILED", error=e.args[0])
        finally:
            self.update_ns_status(NS_INST_STATUS.ACTIVE)

    def do_biz(self):
        self.update_job(JOB_PROGRESS.STARTED, desc='ns scale start')
        self.update_ns_status(NS_INST_STATUS.SCALING)
        self.check_and_set_params()
        self.do_vnfs_scale()
        self.update_job(JOB_PROGRESS.FINISHED, desc='ns scale success')
        NsLcmOpOcc.update(self.occ_id, "COMPLETED")

    def check_and_set_params(self):
        scale_type = ignore_case_get(self.request_data, 'scaleType')
        if scale_type != SCALE_TYPE[0]:
            raise NSLCMException('scaleType should be SCALE_NS.')

        scale_ns_data = ignore_case_get(self.request_data, 'scaleNsData')
        self.scale_vnf_data = get_scale_vnf_data_info_list(
            scale_ns_data, self.ns_instance_id)
        logger.debug('scale_vnf_data = %s' % self.scale_vnf_data)
        if not self.scale_vnf_data:
            raise NSLCMException('Failed to get scaleVnfData parameter')

    def do_vnfs_scale(self):
        """
        Scale VNF instance
        :return:
        """
        for i in range(len(self.scale_vnf_data)):
            vnf_scale_params = self.prepare_vnf_scale_params(
                self.scale_vnf_data[i])
            count = len(self.scale_vnf_data)
            progress_range = [11 + 80 / count * i, 10 + 80 / count * (i + 1)]
            status = self.do_vnf_scale(vnf_scale_params, progress_range)
            if status is JOB_MODEL_STATUS.FINISHED:
                logger.info(
                    'nf[%s] scale handle end' %
                    vnf_scale_params.get('vnfInstanceId'))
                self.update_job(
                    progress_range[1],
                    desc='nf[%s] scale handle end' %
                         vnf_scale_params.get('vnfInstanceId'))
            else:
                raise NSLCMException('VNF scale failed')

    def prepare_vnf_scale_params(self, vnf_data):
        """
        Prepare parameters for VNF instance scale
        :param vnf_data:
        :return:
        """
        return {
            "vnfInstanceId": ignore_case_get(vnf_data, 'vnfInstanceId'),
            "scaleVnfData": ignore_case_get(vnf_data, 'scaleByStepData'),
            "nsInstanceId": self.ns_instance_id
        }

    def do_vnf_scale(self, vnf_scale_params, progress_range):
        """
        Scale VNF instance
        :param vnf_scale_params:
        :param progress_range:
        :return:
        """
        nf_inst_id = vnf_scale_params.get('vnfInstanceId')
        nf_service = NFManualScaleService(nf_inst_id, vnf_scale_params)
        nf_service.start()
        self.update_job(
            progress_range[0],
            desc='nf[%s] scale handle start' %
                 nf_inst_id)
        status = self.wait_job_finish(nf_service.job_id)
        return status

    @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 == JOB_PROGRESS.FINISHED:
                return JOB_MODEL_STATUS.FINISHED
            if job_result.progress > JOB_PROGRESS.FINISHED:
                return JOB_MODEL_STATUS.ERROR
        return JOB_MODEL_STATUS.TIMEOUT

    def update_job(self, progress, desc=''):
        """
        Update the information of job
        :param progress:
        :param desc:
        :return:
        """
        JobUtil.add_job_status(self.job_id, progress, desc)

    def update_ns_status(self, status):
        """
        Update NS instance status
        :param status:
        :return:
        """
        NSInstModel.objects.filter(
            id=self.ns_instance_id).update(
            status=status)