Add vfc catalog save directory
[vfc/nfvo/lcm.git] / lcm / packages / tests / test_nf.py
1 # Copyright 2016-2017 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 import json
15 import mock
16 from rest_framework import status
17 from django.test import TestCase
18 from django.test import Client
19
20 from lcm.pub.utils import restcall
21 from lcm.pub.utils import fileutil
22 from lcm.pub.nfvi.vim.vimadaptor import VimAdaptor
23 from lcm.pub.database.models import NfPackageModel, VnfPackageFileModel, NfInstModel
24 from lcm.pub.database.models import JobStatusModel, JobModel
25 from lcm.packages.nf_package import NfOnBoardingThread, NfPkgDeletePendingThread
26 from lcm.packages.nf_package import NfPkgDeleteThread
27 from lcm.packages import nf_package
28 from lcm.pub.nfvi.vim.const import VIM_OPENSTACK
29
30
31 class TestNfPackage(TestCase):
32     def setUp(self):
33         self.client = Client()
34         NfPackageModel.objects.filter().delete()
35         VnfPackageFileModel.objects.filter().delete()
36         NfInstModel.objects.filter().delete()
37         JobModel.objects.filter().delete()
38         JobStatusModel.objects.filter().delete()
39         self.vnfd_raw_data = {
40             "rawData":{
41                 "instance":{
42                     "metadata":{
43                         "is_shared":False,
44                         "plugin_info":"vbrasplugin_1.0",
45                         "vendor":"zte",
46                         "request_reclassification":False,
47                         "name":"vbras",
48                         "version":1,
49                         "vnf_type":"vbras",
50                         "cross_dc":False,
51                         "vnfd_version":"1.0.0",
52                         "id":"zte_vbras_1.0",
53                         "nsh_aware":True
54                     },
55                     "nodes":[
56                         {
57                             "id":"aaa_dnet_cp_0xu2j5sbigxc8h1ega3if0ld1",
58                             "type_name":"tosca.nodes.nfv.ext.zte.CP",
59                             "template_name":"aaa_dnet_cp",
60                             "properties":{
61                                 "bandwidth":{
62                                     "type_name":"integer",
63                                     "value":0
64                                 },
65                                 "direction":{
66                                     "type_name":"string",
67                                     "value":"bidirectional"
68                                 },
69                                 "vnic_type":{
70                                     "type_name":"string",
71                                     "value":"normal"
72                                 },
73                                 "sfc_encapsulation":{
74                                     "type_name":"string",
75                                     "value":"mac"
76                                 },
77                                 "order":{
78                                     "type_name":"integer",
79                                     "value":2
80                                 }
81                             },
82                             "relationships":[
83                                 {
84                                     "name":"guest_os",
85                                     "source_requirement_index":0,
86                                     "target_node_id":"AAA_image_d8aseebr120nbm7bo1ohkj194",
87                                     "target_capability_name":"feature"
88                                 }
89                             ]
90                         },
91                         {
92                             "id":"LB_Image_oj5l2ay8l2g6vcq6fsswzduha",
93                             "type_name":"tosca.nodes.nfv.ext.ImageFile",
94                             "template_name":"LB_Image",
95                             "properties":{
96                                 "disk_format":{
97                                     "type_name":"string",
98                                     "value":"qcow2"
99                                 },
100                                 "file_url":{
101                                     "type_name":"string",
102                                     "value":"/SoftwareImages/image-lb"
103                                 },
104                                 "name":{
105                                     "type_name":"string",
106                                     "value":"image-lb"
107                                 }
108                             }
109                         }
110                     ]
111                 },
112                 "model":{
113                     "metadata":{
114                         "is_shared":False,
115                         "plugin_info":"vbrasplugin_1.0",
116                         "vendor":"zte",
117                         "request_reclassification":False,
118                         "name":"vbras",
119                         "version":1,
120                         "vnf_type":"vbras",
121                         "cross_dc":False,
122                         "vnfd_version":"1.0.0",
123                         "id":"zte_vbras_1.0",
124                         "nsh_aware":True
125                     },
126                     "node_templates":[
127                         {
128                             "name":"aaa_dnet_cp",
129                             "type_name":"tosca.nodes.nfv.ext.zte.CP",
130                             "default_instances":1,
131                             "min_instances":0,
132                             "properties":{
133                                 "bandwidth":{
134                                     "type_name":"integer",
135                                     "value":0
136                                 }
137                             },
138                             "requirement_templates":[
139                                 {
140                                     "name":"virtualbinding",
141                                     "target_node_template_name":"AAA",
142                                     "target_capability_name":"virtualbinding"
143                                 }
144                             ]
145                         }
146                     ]
147                 }
148             }
149         }
150
151     def tearDown(self):
152         pass
153
154     def assert_job_result(self, job_id, job_progress, job_detail):
155         jobs = JobStatusModel.objects.filter(
156             jobid=job_id,
157             progress=job_progress,
158             descp=job_detail)
159         self.assertEqual(1, len(jobs))
160
161     @mock.patch.object(NfOnBoardingThread, 'run')
162     def test_nf_pkg_on_boarding_normal(self, mock_run):
163         resp = self.client.post("/openoapi/nslcm/v1/vnfpackage", {
164             "csarId": "1",
165             "vimIds": ["1"]
166             }, format='json')
167         self.assertEqual(resp.status_code, status.HTTP_202_ACCEPTED)
168 """
169     @mock.patch.object(restcall, 'call_req')
170     def test_nf_pkg_on_boarding_when_on_boarded(self, mock_call_req):
171         mock_call_req.return_value = [0, json.JSONEncoder().encode({"onBoardState": "onBoarded"}), '200']
172         NfOnBoardingThread(csar_id="1",
173                            vim_ids=["1"],
174                            lab_vim_id="",
175                            job_id="2").run()
176         self.assert_job_result("2", 255, "CSAR(1) already onBoarded.")
177
178     @mock.patch.object(restcall, 'call_req')
179     def test_nf_pkg_on_boarding_when_on_boarding(self, mock_call_req):
180         mock_call_req.return_value = [0, json.JSONEncoder().encode({
181             "onBoardState": "non-onBoarded",
182             "processState": "onBoarding"
183             }), '200']
184         NfOnBoardingThread(csar_id="2",
185                            vim_ids=["1"],
186                            lab_vim_id="",
187                            job_id="3").run()
188         self.assert_job_result("3", 255, "CSAR(2) is onBoarding now.")
189
190     @mock.patch.object(restcall, 'call_req')
191     def test_nf_on_boarding_when_nfd_already_exists(self, mock_call_req):
192         mock_vals = {
193             "/openoapi/catalog/v1/csars/2":
194                 [0, json.JSONEncoder().encode({
195                     "onBoardState": "onBoardFailed", "processState": "deleteFailed"}), '200'],
196             "/openoapi/catalog/v1/servicetemplates/queryingrawdata":
197                 [0, json.JSONEncoder().encode(self.vnfd_raw_data), '200']}
198
199         def side_effect(*args):
200             return mock_vals[args[4]]
201
202         mock_call_req.side_effect = side_effect
203         NfPackageModel(uuid="1", nfpackageid="2", vnfdid="zte_vbras_1.0").save()
204         NfOnBoardingThread(csar_id="2", vim_ids=["1"], lab_vim_id="", job_id="4").run()
205         self.assert_job_result("4", 255, "NFD(zte_vbras_1.0) already exists.")
206
207     @mock.patch.object(restcall, 'call_req')
208     @mock.patch.object(fileutil, 'download_file_from_http')
209     @mock.patch.object(VimAdaptor, '__init__')
210     @mock.patch.object(VimAdaptor, 'create_image')
211     @mock.patch.object(VimAdaptor, 'get_image')
212     def test_nf_on_boarding_when_successfully(self, mock_get_image, mock_create_image,
213                                               mock__init__, mock_download_file_from_http, mock_call_req):
214         mock_download_file_from_http.return_value = True, "/root/package"
215         mock_vals = {
216             "/openoapi/catalog/v1/csars/2":
217                 [0, json.JSONEncoder().encode({
218                     "onBoardState": "onBoardFailed", "processState": "deleteFailed"}), '200'],
219             "/openoapi/catalog/v1/servicetemplates/queryingrawdata":
220                 [0, json.JSONEncoder().encode(self.vnfd_raw_data), '200'],
221             "/openoapi/catalog/v1/csars/2/files?relativePath=/SoftwareImages/image-lb":
222                 [0, json.JSONEncoder().encode({
223                     "csar_file_info": [{"downloadUri": "8"}, {"localPath": "9"}]}), '200'],
224             "/openoapi/extsys/v1/vims":
225                 [0, json.JSONEncoder().encode([{
226                     "vimId": "1", "type": VIM_OPENSTACK,
227                     "url": "/root/package", "userName": "tom",
228                     "password": "tom", "tenant": "10"}]), '200'],
229             "/openoapi/catalog/v1/csars/2?onBoardState=onBoarded": [0, '{}', 200],
230             "/openoapi/catalog/v1/csars/2?operationalState=Enabled": [0, '{}', 200],
231             "/openoapi/catalog/v1/csars/2?processState=normal": [0, '{}', 200]}
232         mock_create_image.return_value = [0, {"id": "30", "name": "jerry", "res_type": 0}]
233         mock__init__.return_value = None
234         mock_get_image.return_value = [0, {"id": "30", "name": "jerry", "size": "60", "status": "active"}]
235
236         def side_effect(*args):
237             return mock_vals[args[4]]
238         mock_call_req.side_effect = side_effect
239
240         NfOnBoardingThread(csar_id="2", vim_ids=["1"], lab_vim_id="", job_id="4").run()
241         self.assert_job_result("4", 100, "CSAR(2) onBoarding successfully.")
242
243     @mock.patch.object(restcall, 'call_req')
244     @mock.patch.object(fileutil, 'download_file_from_http')
245     @mock.patch.object(VimAdaptor, '__init__')
246     @mock.patch.object(VimAdaptor, 'create_image')
247     @mock.patch.object(VimAdaptor, 'get_image')
248     def test_nf_on_boarding_when_timeout(self, mock_get_image, mock_create_image,
249                                          mock__init__, mock_download_file_from_http, mock_call_req):
250         nf_package.MAX_RETRY_TIMES = 2
251         nf_package.SLEEP_INTERVAL_SECONDS = 1
252         mock_download_file_from_http.return_value = True, "/root/package"
253         mock_vals = {
254             "/openoapi/catalog/v1/csars/3":
255             [0, json.JSONEncoder().encode({"onBoardState": "onBoardFailed",
256                                            "processState": "deleteFailed"}), '200'],
257             "/openoapi/catalog/v1/servicetemplates/queryingrawdata":
258                 [0, json.JSONEncoder().encode(self.vnfd_raw_data), '200'],
259             "/openoapi/catalog/v1/csars/3/files?relativePath=/SoftwareImages/image-lb":
260                 [0, json.JSONEncoder().encode({
261                     "csar_file_info": [{"downloadUri": "8"}, {"localPath": "9"}]}), '200'],
262             "/openoapi/catalog/v1/csars/3?processState=onBoardFailed": [0, '{}', 200],
263             "/openoapi/extsys/v1/vims":
264                 [0, json.JSONEncoder().encode([{
265                     "vimId": "1", "type": VIM_OPENSTACK,
266                     "url": "/root/package", "userName": "tom",
267                     "password": "tom", "tenant": "10"}]), 200]}
268         mock_create_image.return_value = [0, {"id": "30", "name": "jerry", "res_type": 0}]
269         mock__init__.return_value = None
270         mock_get_image.return_value = [0, {"id": "30", "name": "jerry", "size": "60", "status": "0"}]
271
272         def side_effect(*args):
273             return mock_vals[args[4]]
274
275         mock_call_req.side_effect = side_effect
276         NfOnBoardingThread(csar_id="3", vim_ids=["1"], lab_vim_id="", job_id="6").run()
277         self.assert_job_result("6", 255, "Failed to create image:timeout(2 seconds.)")
278
279     @mock.patch.object(restcall, 'call_req')
280     @mock.patch.object(fileutil, 'download_file_from_http')
281     @mock.patch.object(VimAdaptor, '__init__')
282     @mock.patch.object(VimAdaptor, 'create_image')
283     def test_nf_on_boarding_when_failed_to_create_image(self, mock_create_image,
284                                                         mock__init__, mock_download_file_from_http, mock_call_req):
285         mock_download_file_from_http.return_value = True, "/root/package"
286         mock_vals = {
287             "/openoapi/catalog/v1/csars/5":
288                 [0, json.JSONEncoder().encode({
289                     "onBoardState": "onBoardFailed", "processState": "deleteFailed"}), '200'],
290             "/openoapi/catalog/v1/servicetemplates/queryingrawdata":
291                 [0, json.JSONEncoder().encode(self.vnfd_raw_data), '200'],
292             "/openoapi/catalog/v1/csars/5/files?relativePath=/SoftwareImages/image-lb":
293                 [0, json.JSONEncoder().encode({
294                     "csar_file_info": [{"downloadUri": "8"}, {"localPath": "9"}]}), '200'],
295             "/openoapi/catalog/v1/csars/5?processState=onBoardFailed": [0, '{}', 200],
296             "/openoapi/extsys/v1/vims":
297                 [0, json.JSONEncoder().encode([{
298                     "vimId": "1", "type": VIM_OPENSTACK,
299                     "url": "/root/package", "userName": "tom",
300                     "password": "tom", "tenant": "10"}]), '200']}
301         mock_create_image.return_value = [1, 'Unsupported image format.']
302         mock__init__.return_value = None
303
304         def side_effect(*args):
305             return mock_vals[args[4]]
306         mock_call_req.side_effect = side_effect
307         NfOnBoardingThread(csar_id="5", vim_ids=["1"], lab_vim_id="", job_id="8").run()
308         self.assert_job_result("8", 255, "Failed to create image:Unsupported image format.")
309
310     #########################################################################
311     @mock.patch.object(restcall, 'call_req')
312     def test_get_csar_successfully(self, mock_call_req):
313         mock_call_req.return_value = [0, json.JSONEncoder().encode({
314             "name": "1", "provider": "2", "version": "3", "operationalState": "4",
315             "usageState": "5", "onBoardState": "6", "processState": "7",
316             "deletionPending": "8", "downloadUri": "9", "createTime": "10",
317             "modifyTime": "11", "format": "12", "size": "13"
318             }), '200']
319         NfPackageModel(uuid="1", vnfdid="001", vendor="vendor",
320                        vnfdversion="1.2.0", vnfversion="1.1.0", nfpackageid="13").save()
321         VnfPackageFileModel(id="1", filename="filename", imageid="00001",
322                             vimid="1", vimuser="001", tenant="12", status="1", vnfpid="13").save()
323         NfInstModel(nfinstid="1", mnfinstid="001", nf_name="name", package_id="13").save()
324         resp = self.client.get("/openoapi/nslcm/v1/vnfpackage/13")
325         self.assertEqual(resp.status_code, status.HTTP_200_OK)
326         expect_data = {
327             "csarId": '13',
328             "packageInfo": {
329                 "vnfdId": "001",
330                 "vnfdProvider": "vendor",
331                 "vnfdVersion": "1.2.0",
332                 "vnfVersion": "1.1.0",
333                 "name": "1",
334                 "provider": "2",
335                 "version": "3",
336                 "operationalState": "4",
337                 "usageState": "5",
338                 "onBoardState": "6",
339                 "processState": "7",
340                 "deletionPending": "8",
341                 "downloadUri": "9",
342                 "createTime": "10",
343                 "modifyTime": "11",
344                 "format": "12",
345                 "size": "13"},
346             "imageInfo": [{
347                 "index": "0",
348                 "fileName": "filename",
349                 "imageId": "00001",
350                 "vimId": "1",
351                 "vimUser": "001",
352                 "tenant": "12",
353                 "status": "1"}],
354             "vnfInstanceInfo": [{
355                 "vnfInstanceId": "1",
356                 "vnfInstanceName": "name"}]}
357         self.assertEqual(expect_data, resp.data)
358
359     #########################################################################
360     @mock.patch.object(restcall, 'call_req')
361     def test_delete_pending_csar_when_successfully(self, mock_call_req):
362         mock_call_req.return_value = [0, json.JSONEncoder().encode({
363             "processState": "deleting"}), "200"]
364         NfPkgDeletePendingThread(csar_id="1", job_id='2').run()
365         self.assert_job_result("2", 100, "Delete pending CSAR(1) successfully.")
366
367     @mock.patch.object(restcall, 'call_req')
368     def test_delete_pending_csar_when_deleting(self, mock_call_req):
369         NfPackageModel(uuid="01", nfpackageid="1").save()
370         mock_call_req.return_value = [0, json.JSONEncoder().encode({
371             "processState": "deleting"}), "200"]
372         NfPkgDeletePendingThread(csar_id="1", job_id='2').run()
373         self.assert_job_result("2", 100, "CSAR(1) is deleting now.")
374
375     @mock.patch.object(restcall, 'call_req')
376     def test_delete_pending_csar_when_not_deletion_pending(self, mock_call_req):
377         NfPackageModel(uuid="01", nfpackageid="1").save()
378         mock_call_req.return_value = [0, json.JSONEncoder().encode({
379             "deletionPending": "false"}), "200"]
380         NfPkgDeletePendingThread(csar_id="1", job_id='2').run()
381         self.assert_job_result("2", 100, "CSAR(1) need not to be deleted.")
382
383     @mock.patch.object(restcall, 'call_req')
384     def test_delete_pending_csar_when_in_using(self, mock_call_req):
385         mock_call_req.return_value = [0, json.JSONEncoder().encode({
386             "processState": "normal"}), "200"]
387         NfPackageModel(uuid="01", nfpackageid="1").save()
388         NfInstModel(nfinstid="01", package_id="1").save()
389         NfPkgDeletePendingThread(csar_id="1", job_id='2').run()
390         self.assert_job_result("2", 100, "CSAR(1) is in using, cannot be deleted.")
391
392     @mock.patch.object(VimAdaptor, '__init__')
393     @mock.patch.object(VimAdaptor, 'delete_image')
394     @mock.patch.object(restcall, 'call_req')
395     def test_delete_csarr_when_exception(self, mock_call_req, mock_delete_image, mock_init_):
396         mock_vals = {
397             ("/openoapi/catalog/v1/csars/1", "DELETE"):
398                 [1, "{}", "400"],
399             ("/openoapi/catalog/v1/csars/1?processState=deleting", "PUT"):
400                 [0, "{}", "200"],
401             ("/openoapi/catalog/v1/csars/1?processState=deleteFailed", "PUT"):
402                 [0, "{}", "200"],
403             ("/openoapi/catalog/v1/csars/1", "GET"):
404                 [0, json.JSONEncoder().encode({"processState": "normal"}), "200"],
405             ("/openoapi/extsys/v1/vims", "GET"):
406                 [0, json.JSONEncoder().encode([{"vimId": "002",
407                                                 "url": "url_test",
408                                                 "userName": "test01",
409                                                 "password": "123456",
410                                                 "tenant": "test"}]), "200"]}
411         mock_delete_image.return_value = [0, "", '200']
412
413         def side_effect(*args):
414             return mock_vals[(args[4], args[5])]
415
416         mock_call_req.side_effect = side_effect
417         mock_init_.return_value = None
418         VnfPackageFileModel(vnfpid="1", imageid="001", vimid="002").save()
419         NfPackageModel(uuid="01", nfpackageid="1").save()
420         NfPkgDeletePendingThread(csar_id="1", job_id='2').run()
421         self.assert_job_result("2", 255, "Failed to delete CSAR(1) from catalog.")
422
423     @mock.patch.object(VimAdaptor, '__init__')
424     @mock.patch.object(VimAdaptor, 'delete_image')
425     @mock.patch.object(restcall, 'call_req')
426     def test_delete_csar_when_successfully(self, mock_call_req, mock_delete_image, mock_init_):
427         mock_vals = {
428             ("/openoapi/catalog/v1/csars/1", "DELETE"):
429                 [0, json.JSONEncoder().encode({"successfully": "successfully"}), "200"],
430             ("/openoapi/catalog/v1/csars/1?processState=deleting", "PUT"):
431                 [0, json.JSONEncoder().encode({"successfully": "successfully"}), "200"],
432             ("/openoapi/catalog/v1/csars/1?processState=deleteFailed", "PUT"):
433                 [0, json.JSONEncoder().encode({"successfully": "successfully"}), "200"],
434             ("/openoapi/catalog/v1/csars/1", "GET"):
435                 [0, json.JSONEncoder().encode({"notProcessState": "notProcessState"}), "200"],
436             ("/openoapi/extsys/v1/vims", "GET"):
437                 [0, json.JSONEncoder().encode([{
438                     "vimId": "002",
439                     "url": "url_test",
440                     "userName": "test01",
441                     "password": "123456",
442                     "tenant": "test"}]), "200"]}
443         mock_delete_image.return_value = [0, json.JSONEncoder().encode({"test": "test"}), '200']
444
445         def side_effect(*args):
446             return mock_vals[(args[4], args[5])]
447
448         mock_call_req.side_effect = side_effect
449         mock_init_.return_value = None
450         VnfPackageFileModel(vnfpid="1", imageid="001", vimid="002").save()
451         NfPackageModel(uuid="01", nfpackageid="1").save()
452         NfPkgDeletePendingThread(csar_id="1", job_id='2').run()
453         self.assert_job_result("2", 100, "Delete CSAR(1) successfully.")
454
455     #########################################################################
456     @mock.patch.object(restcall, 'call_req')
457     def test_delete_nf_pkg_when_deleting(self, mock_call_req):
458         mock_call_req.return_value = [0, json.JSONEncoder().encode({"processState": "deleting"}), '200']
459         NfPkgDeleteThread(csar_id="1", job_id="2").run()
460         self.assert_job_result("2", 100, "CSAR(1) is deleting now.")
461         
462     
463     def test_get_nf_csars_normal(self):
464         NfPackageModel(uuid="01", nfpackageid="1", vnfdid="2").save()
465         resp = self.client.get("/openoapi/nslcm/v1/vnfpackage")
466         self.assertEqual(resp.status_code, status.HTTP_200_OK)
467         self.assertEqual(1, len(resp.data["csars"]))
468         self.assertEqual("1", resp.data["csars"][0]["csarId"])
469         self.assertEqual("2", resp.data["csars"][0]["vnfdId"])
470 """        
471