aboutsummaryrefslogtreecommitdiffstats
path: root/lcm/ns/biz/ns_update.py
blob: eba18c681773c02d522fee1501155993f6622044 (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
# 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.')
        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')
            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 if graceful_stop_timeout else 0
        }
        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)