Merge "Refine code for OOF-VFC interaction"
[vfc/nfvo/lcm.git] / lcm / ns_vnfs / biz / grant_vnf.py
1 # Copyright 2018 ZTE Corporation.
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 #         http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 import json
16 import logging
17 import uuid
18 import time
19 from lcm.pub.database.models import NfInstModel, OOFDataModel
20 from lcm.pub.exceptions import NSLCMException
21 from lcm.pub.msapi.sdc_run_catalog import query_vnfpackage_by_id
22 from lcm.pub.utils.values import ignore_case_get
23 from lcm.pub.msapi import resmgr
24
25 logger = logging.getLogger(__name__)
26
27
28 class GrantVnf(object):
29     def __init__(self, grant_data):
30         self.data = grant_data
31
32     def exec_grant(self):
33         logger.debug("grant data from vnfm:%s", self.data)
34         if isinstance(self.data, (unicode, str)):
35             self.data = json.JSONDecoder().decode(self.data)
36         has_res_tpl = False
37         grant_type = None
38         action_type = ignore_case_get(self.data, "operation")
39         vimConnections = []
40         if ignore_case_get(self.data, "addResources"):
41             grant_type = "addResources"
42         elif ignore_case_get(self.data, "removeResources"):
43             grant_type = "removeResources"
44         else:
45             has_res_tpl = True
46
47         for res in ignore_case_get(self.data, grant_type):
48             if "resourceTemplate" in res:
49                 has_res_tpl = True
50                 break
51
52         if not has_res_tpl:
53             m_vnf_inst_id = ignore_case_get(self.data, "vnfInstanceId")
54             additional_param = ignore_case_get(self.data, "additionalparams")
55             vnfm_inst_id = ignore_case_get(additional_param, "vnfmid")
56             vim_id = ignore_case_get(additional_param, "vimid")
57             if vnfm_inst_id and vnfm_inst_id != "":
58                 vnfinsts = NfInstModel.objects.filter(
59                     mnfinstid=m_vnf_inst_id, vnfm_inst_id=vnfm_inst_id)
60             else:
61                 vnfinsts = NfInstModel.objects.filter(
62                     mnfinstid=m_vnf_inst_id)
63             if not vnfinsts:
64                 raise NSLCMException("Vnfinst(%s) is not found in vnfm(%s)" % (
65                     m_vnf_inst_id, vnfm_inst_id))
66
67             vnf_pkg_id = vnfinsts[0].package_id
68             nfpackage_info = query_vnfpackage_by_id(vnf_pkg_id)
69             vnf_pkg = nfpackage_info["packageInfo"]
70             vnfd = json.JSONDecoder().decode(vnf_pkg["vnfdModel"])
71
72             req_param = {
73                 "vnfInstanceId": m_vnf_inst_id,
74                 "vimId": vim_id,
75                 "vnfLcmOpOccId": ignore_case_get(self.data, "vnfLcmOpOccId"),
76                 "additionalParams": additional_param,
77                 grant_type: []
78             }
79             for res in ignore_case_get(self.data, grant_type):
80                 vdu_name = ignore_case_get(res, "vdu")
81                 grant_res = {
82                     "resourceDefinitionId": ignore_case_get(res, "resourceDefinitionId"),
83                     "type": ignore_case_get(res, "type"),
84                     "vdu": vdu_name
85                 }
86                 for vdu in vnfd["vdus"]:
87                     if vdu_name in (vdu["vdu_id"], vdu["properties"].get("name", "")):
88                         grant_res["resourceTemplate"] = self.get_res_tpl(vdu, vnfd)
89                         break
90                 req_param[grant_type].append(grant_res)
91             self.data = req_param
92         tmp = resmgr.grant_vnf(self.data)
93         vimConnections.append(
94             {
95                 "id": tmp["vim"]["vimId"],
96                 "vimId": tmp["vim"]["vimId"],
97                 "vimType": None,
98                 "interfaceInfo": None,
99                 "accessInfo": tmp["vim"]["accessInfo"],
100                 "extra": None
101             }
102         )
103
104         grant_resp = {
105             "id": str(uuid.uuid4()),
106             "vnfInstanceId": ignore_case_get(self.data, 'vnfInstanceId'),
107             "vnfLcmOpOccId": ignore_case_get(self.data, "vnfLcmOpOccId"),
108             "vimConnections": vimConnections
109         }
110
111         logger.debug("action_type=%s" % action_type)
112         if action_type == 'INSTANTIATE':
113             for i in range(18):
114                 offs = OOFDataModel.objects.filter(service_resource_id=ignore_case_get(self.data, "vnfInstanceId"))
115                 if not (offs.exists() and offs[0].vdu_info):
116                     logger.debug("Cannot find oof data, retry%s" % (i + 1))
117                     time.sleep(5)
118                     continue
119                 vdu_info = json.loads(offs[0].vdu_info)
120                 grant_resp['vimAssets'] = {'computeResourceFlavours': []}
121                 for vdu in vdu_info:
122                     grant_resp['vimAssets']['computeResourceFlavours'].append({
123                         'vimConnectionId': offs[0].vim_id,
124                         'resourceProviderId': vdu.get("vduName"),
125                         'vnfdVirtualComputeDescId': None,  # TODO: required
126                         'vimFlavourId': vdu.get("flavorName")
127                     })
128                     # grant_resp['additionalparams'][off.vim_id] = off.directive
129                 break
130
131         logger.debug("grant_resp=%s", grant_resp)
132         return grant_resp
133
134     def get_res_tpl(self, vdu, vnfd):
135         storage_size = 0
136         for storage_id in vdu["local_storages"]:
137             storage_size = storage_size + self.get_storage_size(storage_id, vnfd)
138         resourceTemplate = {
139             "virtualComputeDescriptor": {
140                 "virtualCpu": {
141                     "numVirtualCpu": int(vdu["virtual_compute"]["virtual_cpu"]["num_virtual_cpu"])
142                 },
143                 "virtualMemory": {
144                     "virtualMemSize": parse_unit(vdu["virtual_compute"]["virtual_memory"]["virtual_mem_size"], "MB")
145                 }
146             },
147             "virtualStorageDescriptor": {
148                 "typeOfStorage": "",
149                 "sizeOfStorage": storage_size,
150                 "swImageDescriptor": ""
151             }
152         }
153         return resourceTemplate
154
155     def get_storage_size(self, storage_id, vnfd):
156         for storage in vnfd["local_storages"]:
157             if storage_id == storage["local_storage_id"]:
158                 return parse_unit(storage["properties"]["size"], "GB")
159         return 0
160
161
162 def parse_unit(val, base_unit):
163     recognized_units = ["B", "kB", "KiB", "MB", "MiB", "GB", "GiB", "TB", "TiB"]
164     units_rate = [1, 1000, 1024, 1000000, 1048576, 1000000000, 1073741824, 1000000000000, 1099511627776]
165     unit_rate_map = {unit.upper(): rate for unit, rate in zip(recognized_units, units_rate)}
166     num_unit = val.strip().split(" ")
167     if len(num_unit) != 2:
168         return val.strip()
169     num, unit = num_unit[0], num_unit[1]
170     return int(num) * unit_rate_map[unit.upper()] / unit_rate_map[base_unit.upper()]