5951ce876bb207be17feadc368e5503451b9ee04
[osm/SO.git] / rwlaunchpad / ra / pytest / ns / test_onboard.py
1 #!/usr/bin/env python
2 """
3 #
4 # Copyright 2016 RIFT.IO Inc
5 #
6 # Licensed under the Apache License, Version 2.0 (the "License");
7 # you may not use this file except in compliance with the License.
8 # You may obtain a copy of the License at
9 #
10 # http://www.apache.org/licenses/LICENSE-2.0
11 #
12 # Unless required by applicable law or agreed to in writing, software
13 # distributed under the License is distributed on an "AS IS" BASIS,
14 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 # See the License for the specific language governing permissions and
16 # limitations under the License.
17 #
18
19 @file test_onboard.py
20 @author Varun Prasad (varun.prasad@riftio.com)
21 @brief Onboard descriptors
22 """
23
24 import json
25 import logging
26 import os
27 import pytest
28 import shlex
29 import requests
30 import shutil
31 import subprocess
32 import time
33 import uuid
34
35 import rift.auto.mano
36 import rift.auto.session
37
38 import gi
39 gi.require_version('RwNsrYang', '1.0')
40 gi.require_version('RwVnfdYang', '1.0')
41 gi.require_version('RwLaunchpadYang', '1.0')
42 gi.require_version('RwBaseYang', '1.0')
43
44 from gi.repository import (
45 RwcalYang,
46 NsdYang,
47 RwNsrYang,
48 RwVnfrYang,
49 NsrYang,
50 VnfrYang,
51 VldYang,
52 RwVnfdYang,
53 RwLaunchpadYang,
54 RwBaseYang
55 )
56
57 logging.basicConfig(level=logging.DEBUG)
58
59
60 @pytest.fixture(scope='module')
61 def vnfd_proxy(request, mgmt_session):
62 return mgmt_session.proxy(RwVnfdYang)
63
64 @pytest.fixture(scope='module')
65 def rwvnfr_proxy(request, mgmt_session):
66 return mgmt_session.proxy(RwVnfrYang)
67
68 @pytest.fixture(scope='module')
69 def vld_proxy(request, mgmt_session):
70 return mgmt_session.proxy(VldYang)
71
72
73 @pytest.fixture(scope='module')
74 def nsd_proxy(request, mgmt_session):
75 return mgmt_session.proxy(NsdYang)
76
77
78 @pytest.fixture(scope='module')
79 def rwnsr_proxy(request, mgmt_session):
80 return mgmt_session.proxy(RwNsrYang)
81
82 @pytest.fixture(scope='module')
83 def base_proxy(request, mgmt_session):
84 return mgmt_session.proxy(RwBaseYang)
85
86
87 @pytest.fixture(scope="module")
88 def endpoint():
89 return "upload"
90
91 def create_nsr(nsd, input_param_list, cloud_account_name):
92 """
93 Create the NSR record object
94
95 Arguments:
96 nsd - NSD
97 input_param_list - list of input-parameter objects
98
99 Return:
100 NSR object
101 """
102 nsr = RwNsrYang.YangData_Nsr_NsInstanceConfig_Nsr()
103
104 nsr.id = str(uuid.uuid4())
105 nsr.name = rift.auto.mano.resource_name(nsr.id)
106 nsr.short_name = "nsr_short_name"
107 nsr.description = "This is a description"
108 nsr.nsd.from_dict(nsd.as_dict())
109 nsr.admin_status = "ENABLED"
110 nsr.input_parameter.extend(input_param_list)
111 nsr.cloud_account = cloud_account_name
112
113 return nsr
114
115
116 def upload_descriptor(
117 logger,
118 descriptor_file,
119 scheme,
120 cert,
121 host="127.0.0.1",
122 endpoint="upload"):
123 curl_cmd = ('curl --cert {cert} --key {key} -F "descriptor=@{file}" -k '
124 '{scheme}://{host}:4567/api/{endpoint}'.format(
125 cert=cert[0],
126 key=cert[1],
127 scheme=scheme,
128 endpoint=endpoint,
129 file=descriptor_file,
130 host=host,
131 ))
132
133 logger.debug("Uploading descriptor %s using cmd: %s", descriptor_file, curl_cmd)
134 stdout = subprocess.check_output(shlex.split(curl_cmd), universal_newlines=True)
135
136 json_out = json.loads(stdout)
137 transaction_id = json_out["transaction_id"]
138
139 return transaction_id
140
141
142 class DescriptorOnboardError(Exception):
143 pass
144
145
146 def wait_onboard_transaction_finished(
147 logger,
148 transaction_id,
149 scheme,
150 cert,
151 timeout=600,
152 host="127.0.0.1",
153 endpoint="upload"):
154
155 logger.info("Waiting for onboard trans_id %s to complete", transaction_id)
156 uri = '%s://%s:4567/api/%s/%s/state' % (scheme, host, endpoint, transaction_id)
157
158 elapsed = 0
159 start = time.time()
160 while elapsed < timeout:
161 reply = requests.get(uri, cert=cert, verify=False)
162 state = reply.json()
163 if state["status"] == "success":
164 break
165 if state["status"] != "pending":
166 raise DescriptorOnboardError(state)
167
168 time.sleep(1)
169 elapsed = time.time() - start
170
171
172 if state["status"] != "success":
173 raise DescriptorOnboardError(state)
174 logger.info("Descriptor onboard was successful")
175
176
177 def onboard_descriptor(host, file_name, logger, endpoint, scheme, cert):
178 """On-board/update the descriptor.
179
180 Args:
181 host (str): Launchpad IP
182 file_name (str): Full file path.
183 logger: Logger instance
184 endpoint (str): endpoint to be used for the upload operation.
185
186 """
187 logger.info("Onboarding package: %s", file_name)
188 trans_id = upload_descriptor(
189 logger,
190 file_name,
191 scheme,
192 cert,
193 host=host,
194 endpoint=endpoint)
195 wait_onboard_transaction_finished(
196 logger,
197 trans_id,
198 scheme,
199 cert,
200 host=host,
201 endpoint=endpoint)
202
203 def terminate_nsr(rwvnfr_proxy, rwnsr_proxy, logger, wait_after_kill=True):
204 """
205 Terminate the instance and check if the record is deleted.
206
207 Asserts:
208 1. NSR record is deleted from instance-config.
209
210 """
211 logger.debug("Terminating NSRs")
212
213 nsr_path = "/ns-instance-config"
214 nsr = rwnsr_proxy.get_config(nsr_path)
215 nsrs = nsr.nsr
216
217 xpaths = []
218 for nsr in nsrs:
219 xpath = "/ns-instance-config/nsr[id='{}']".format(nsr.id)
220 rwnsr_proxy.delete_config(xpath)
221 xpaths.append(xpath)
222
223 if wait_after_kill:
224 time.sleep(30)
225 else:
226 time.sleep(5)
227
228 for xpath in xpaths:
229 nsr = rwnsr_proxy.get_config(xpath)
230 assert nsr is None
231
232 # Get the ns-instance-config
233 ns_instance_config = rwnsr_proxy.get_config("/ns-instance-config")
234
235 # Termination tests
236 vnfr = "/vnfr-catalog/vnfr"
237 vnfrs = rwvnfr_proxy.get(vnfr, list_obj=True)
238 assert vnfrs is None or len(vnfrs.vnfr) == 0
239
240 # nsr = "/ns-instance-opdata/nsr"
241 # nsrs = rwnsr_proxy.get(nsr, list_obj=True)
242 # assert len(nsrs.nsr) == 0
243
244
245
246 @pytest.mark.setup('nsr')
247 @pytest.mark.depends('launchpad')
248 @pytest.mark.incremental
249 class TestNsrStart(object):
250 """A brief overview of the steps performed.
251 1. Generate & on-board new descriptors
252 2. Start the NSR
253 """
254
255 def test_upload_descriptors(
256 self,
257 logger,
258 vnfd_proxy,
259 nsd_proxy,
260 mgmt_session,
261 scheme,
262 cert,
263 descriptors
264 ):
265 """Generates & On-boards the descriptors.
266 """
267 endpoint = "upload"
268
269 for file_name in descriptors:
270 onboard_descriptor(
271 mgmt_session.host,
272 file_name,
273 logger,
274 endpoint,
275 scheme,
276 cert)
277
278 descriptor_vnfds, descriptor_nsd = descriptors[:-1], descriptors[-1]
279
280 catalog = vnfd_proxy.get_config('/vnfd-catalog')
281 actual_vnfds = catalog.vnfd
282 assert len(actual_vnfds) == len(descriptor_vnfds), \
283 "There should {} vnfds".format(len(descriptor_vnfds))
284
285 catalog = nsd_proxy.get_config('/nsd-catalog')
286 actual_nsds = catalog.nsd
287 assert len(actual_nsds) == 1, "There should only be a single nsd"
288
289 @pytest.mark.feature("upload-image")
290 def test_upload_images(self, descriptor_images, cloud_host, cloud_user, cloud_tenants):
291
292 openstack = rift.auto.mano.OpenstackManoSetup(
293 cloud_host,
294 cloud_user,
295 [(tenant, "private") for tenant in cloud_tenants])
296
297 for image_location in descriptor_images:
298 image = RwcalYang.ImageInfoItem.from_dict({
299 'name': os.path.basename(image_location),
300 'location': image_location,
301 'disk_format': 'qcow2',
302 'container_format': 'bare'})
303 openstack.create_image(image)
304
305
306 def test_set_scaling_params(self, nsd_proxy):
307 nsds = nsd_proxy.get('/nsd-catalog')
308 nsd = nsds.nsd[0]
309 for scaling_group in nsd.scaling_group_descriptor:
310 scaling_group.max_instance_count = 2
311
312 nsd_proxy.replace_config('/nsd-catalog/nsd[id="{}"]'.format(
313 nsd.id), nsd)
314
315
316 def test_instantiate_nsr(self, logger, nsd_proxy, rwnsr_proxy, base_proxy, cloud_account_name):
317
318 def verify_input_parameters(running_config, config_param):
319 """
320 Verify the configured parameter set against the running configuration
321 """
322 for run_input_param in running_config.input_parameter:
323 if (run_input_param.xpath == config_param.xpath and
324 run_input_param.value == config_param.value):
325 return True
326
327 assert False, ("Verification of configured input parameters: { xpath:%s, value:%s} "
328 "is unsuccessful.\nRunning configuration: %s" % (config_param.xpath,
329 config_param.value,
330 running_config.input_parameter))
331
332 catalog = nsd_proxy.get_config('/nsd-catalog')
333 nsd = catalog.nsd[0]
334
335 input_parameters = []
336 descr_xpath = "/nsd:nsd-catalog/nsd:nsd[nsd:id='%s']/nsd:description" % nsd.id
337 descr_value = "New NSD Description"
338 in_param_id = str(uuid.uuid4())
339
340 input_param_1 = NsrYang.YangData_Nsr_NsInstanceConfig_Nsr_InputParameter(
341 xpath=descr_xpath,
342 value=descr_value)
343
344 input_parameters.append(input_param_1)
345
346 nsr = create_nsr(nsd, input_parameters, cloud_account_name)
347
348 logger.info("Instantiating the Network Service")
349 rwnsr_proxy.create_config('/ns-instance-config/nsr', nsr)
350
351 nsr_opdata = rwnsr_proxy.get('/ns-instance-opdata/nsr[ns-instance-config-ref="{}"]'.format(nsr.id))
352 assert nsr_opdata is not None
353
354 # Verify the input parameter configuration
355 running_config = rwnsr_proxy.get_config("/ns-instance-config/nsr[id='%s']" % nsr.id)
356 for input_param in input_parameters:
357 verify_input_parameters(running_config, input_param)
358
359 def test_wait_for_nsr_started(self, rwnsr_proxy):
360 nsr_opdata = rwnsr_proxy.get('/ns-instance-opdata')
361 nsrs = nsr_opdata.nsr
362
363 for nsr in nsrs:
364 xpath = "/ns-instance-opdata/nsr[ns-instance-config-ref='{}']/operational-status".format(nsr.ns_instance_config_ref)
365 rwnsr_proxy.wait_for(xpath, "running", fail_on=['failed'], timeout=240)
366
367
368 @pytest.mark.teardown('nsr')
369 @pytest.mark.depends('launchpad')
370 @pytest.mark.incremental
371 class TestNsrTeardown(object):
372 def test_terminate_nsr(self, rwvnfr_proxy, rwnsr_proxy, logger, cloud_type):
373 """
374 Terminate the instance and check if the record is deleted.
375
376 Asserts:
377 1. NSR record is deleted from instance-config.
378
379 """
380 logger.debug("Terminating NSR")
381
382 wait_after_kill = True
383 if cloud_type == "mock":
384 wait_after_kill = False
385
386 terminate_nsr(rwvnfr_proxy, rwnsr_proxy, logger, wait_after_kill=wait_after_kill)
387
388 def test_delete_records(self, nsd_proxy, vnfd_proxy):
389 """Delete the NSD & VNFD records
390
391 Asserts:
392 The records are deleted.
393 """
394 nsds = nsd_proxy.get("/nsd-catalog/nsd", list_obj=True)
395 for nsd in nsds.nsd:
396 xpath = "/nsd-catalog/nsd[id='{}']".format(nsd.id)
397 nsd_proxy.delete_config(xpath)
398
399 nsds = nsd_proxy.get("/nsd-catalog/nsd", list_obj=True)
400 assert nsds is None or len(nsds.nsd) == 0
401
402 vnfds = vnfd_proxy.get("/vnfd-catalog/vnfd", list_obj=True)
403 for vnfd_record in vnfds.vnfd:
404 xpath = "/vnfd-catalog/vnfd[id='{}']".format(vnfd_record.id)
405 vnfd_proxy.delete_config(xpath)
406
407 vnfds = vnfd_proxy.get("/vnfd-catalog/vnfd", list_obj=True)
408 assert vnfds is None or len(vnfds.vnfd) == 0