Deal with nfPackage
[vfc/nfvo/catalog.git] / catalog / packages / biz / vnf_package.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 os
18 import sys
19 import threading
20 import traceback
21 import urllib2
22 import uuid
23
24 from rest_framework import status
25 from django.http import FileResponse, StreamingHttpResponse
26 from catalog.pub.config.config import CATALOG_ROOT_PATH
27 from catalog.pub.database.models import VnfPackageModel
28 from catalog.pub.exceptions import CatalogException
29 from catalog.pub.utils.values import ignore_case_get
30 from catalog.pub.utils import fileutil, toscaparser
31
32
33 logger = logging.getLogger(__name__)
34
35
36 def create_vnf_pkg(data):
37     user_defined_data = ignore_case_get(data, "userDefinedData")
38     vnf_pkg_id = str(uuid.uuid4())
39     VnfPackageModel.objects.create(
40         vnfPackageId=vnf_pkg_id,
41         onboardingState="CREATED",
42         operationalState="DISABLED",
43         usageState="NOT_IN_USE",
44         userDefinedData=user_defined_data
45     )
46     data = {
47         "id": vnf_pkg_id,
48         "onboardingState": "CREATED",
49         "operationalState": "DISABLED",
50         "usageState": "NOT_IN_USE",
51         "userDefinedData": user_defined_data,
52         "_links": None
53     }
54     return data
55
56
57 def query_multiple():
58     pkgs_info = []
59     nf_pkgs = VnfPackageModel.objects.filter()
60     if not nf_pkgs.exists():
61         raise CatalogException('VNF packages do not exist.')
62     for nf_pkg in nf_pkgs:
63         ret = fill_response_data(nf_pkg)
64         pkgs_info.append(ret)
65     return pkgs_info
66
67
68 def query_single(vnf_pkg_id):
69     nf_pkg = VnfPackageModel.objects.filter(vnfPackageId=vnf_pkg_id)
70     if not nf_pkg.exists():
71         raise CatalogException('VNF package(%s) does not exist.' % vnf_pkg_id)
72     return fill_response_data(nf_pkg[0])
73
74
75 def delete_vnf_pkg(vnf_pkg_id):
76     vnf_pkg = VnfPackageModel.objects.filter(vnfPackageId=vnf_pkg_id)
77     if not vnf_pkg.exists():
78         logger.debug('VNF package(%s) is deleted.' % vnf_pkg_id)
79         return
80     if vnf_pkg[0].onboardingState != "CREATED":
81         raise CatalogException("The VNF package (%s) is not on-boarded" % vnf_pkg_id)
82     if vnf_pkg[0].operationalState != "DISABLED":
83         raise CatalogException("The VNF package (%s) is not disabled" % vnf_pkg_id)
84     if vnf_pkg[0].usageState != "NOT_IN_USE":
85         raise CatalogException("The VNF package (%s) is in use" % vnf_pkg_id)
86     vnf_pkg.delete()
87     vnf_pkg_path = os.path.join(CATALOG_ROOT_PATH, vnf_pkg_id)
88     fileutil.delete_dirs(vnf_pkg_path)
89
90
91 def parse_vnfd_and_save(vnf_pkg_id, vnf_pkg_path):
92     vnfd_json = toscaparser.parse_vnfd(vnf_pkg_path)
93     vnfd = json.JSONDecoder().decode(vnfd_json)
94
95     vnfd_id = vnfd["metadata"]["id"]
96     if VnfPackageModel.objects.filter(vnfdId=vnfd_id):
97         raise CatalogException("VNFD(%s) already exists." % vnfd_id)
98
99     vnfd_ver = vnfd["metadata"].get("vnfd_version")
100     if not vnfd_ver:
101         vnfd_ver = vnfd["metadata"].get("vnfdVersion", "undefined")
102     VnfPackageModel(
103         vnfPackageId=vnf_pkg_id,
104         vnfdId=vnfd_id,
105         vnfVendor=vnfd["metadata"].get("vendor", "undefined"),
106         vnfdVersion=vnfd_ver,
107         vnfSoftwareVersion=vnfd["metadata"].get("version", "undefined"),
108         vnfdModel=vnfd_json,
109         onboardingState="ONBOARDED",
110         operationalState="ENABLED",
111         usageState="NOT_IN_USE",
112         localFilePath=vnf_pkg_path
113     ).save()
114
115
116 class VnfPkgUploadThread(threading.Thread):
117     def __init__(self, data, vnf_pkg_id):
118         threading.Thread.__init__(self)
119         self.vnf_pkg_id = vnf_pkg_id
120         self.data = data
121         self.upload_file_name = None
122
123     def run(self):
124         try:
125             self.upload_vnf_pkg_from_uri()
126             parse_vnfd_and_save(self.vnf_pkg_id, self.upload_file_name)
127         except CatalogException as e:
128             logger.error(e.message)
129         except Exception as e:
130             logger.error(e.message)
131             logger.error(traceback.format_exc())
132             logger.error(str(sys.exc_info()))
133
134     def upload_vnf_pkg_from_uri(self):
135         logger.debug("UploadVnf %s" % self.vnf_pkg_id)
136         vnf_pkg = VnfPackageModel.objects.filter(vnfPackageId=self.vnf_pkg_id)
137         if vnf_pkg[0].onboardingState != "CREATED":
138             raise CatalogException("VNF package (%s) is not created" % self.vnf_pkg_id)
139         uri = ignore_case_get(self.data, "addressInformation")
140         upload_path = os.path.join(CATALOG_ROOT_PATH, self.vnf_pkg_id)
141         if not os.path.exists(upload_path):
142             os.makedirs(upload_path, 0o777)
143         r = urllib2.Request(uri)
144         req = urllib2.urlopen(r)
145
146         self.upload_file_name = os.path.join(upload_path, os.path.basename(uri))
147         save_file = open(self.upload_file_name, "wb")
148         save_file.write(req.read())
149         save_file.close()
150         req.close()
151
152
153 def fill_response_data(nf_pkg):
154     pkg_info = {}
155     pkg_info["id"] = nf_pkg.vnfPackageId
156     pkg_info["vnfdId"] = nf_pkg.vnfdId
157     pkg_info["vnfProductName"] = nf_pkg.vnfdProductName
158     pkg_info["vnfSoftwareVersion"] = nf_pkg.vnfSoftwareVersion
159     pkg_info["vnfdVersion"] = nf_pkg.vnfdVersion
160     if nf_pkg.checksum:
161         pkg_info["checksum"] = json.JSONDecoder().decode(nf_pkg.checksum)
162     pkg_info["softwareImages"] = None  # TODO
163     pkg_info["additionalArtifacts"] = None  # TODO
164     pkg_info["onboardingState"] = nf_pkg.onboardingState
165     pkg_info["operationalState"] = nf_pkg.operationalState
166     pkg_info["usageState"] = nf_pkg.usageState
167     if nf_pkg.userDefinedData:
168         pkg_info["userDefinedData"] = json.JSONDecoder().decode(nf_pkg.userDefinedData)
169     pkg_info["_links"] = None  # TODO
170     return pkg_info
171
172
173 def fetch_vnf_pkg(request, vnf_pkg_id):
174     nf_pkg = VnfPackageModel.objects.filter(vnfPackageId=vnf_pkg_id)
175     if not nf_pkg.exists():
176         raise CatalogException("VNF package (%s) does not exist" % vnf_pkg_id)
177     if nf_pkg[0].onboardingState != "ONBOARDED":
178         raise CatalogException("VNF package (%s) is not on-boarded" % vnf_pkg_id)
179     file_path = nf_pkg[0].localFilePath
180     file_name = file_path.split('/')[-1]
181     file_name = file_name.split('\\')[-1]
182     file_range = request.META.get('RANGE')
183     if file_range:
184         start_end = file_range.split('-')
185         start = int(start_end[0])
186         end = int(start_end[1])
187         f = open(file_path, "rb")
188         f.seek(start, 0)
189         fs = f.read(end - start + 1)
190         response = StreamingHttpResponse(fs, status=status.HTTP_200_OK)
191         response['Content-Type'] = 'application/octet-stream'
192         response['Content-Range'] = file_range
193     else:
194         response = FileResponse(open(file_path, 'rb'), status=status.HTTP_200_OK)
195     response['Content-Disposition'] = 'attachment; filename=%s' % file_name.encode('utf-8')
196     return response