4 # Copyright 2016 RIFT.IO Inc
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
10 # http://www.apache.org/licenses/LICENSE-2.0
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.
19 @file test_multi_vm_vnf_trafgen.py
20 @author Karun Ganesharatnam (karun.ganesharatnam@riftio.com)
22 @brief Scriptable load-balancer test with multi-vm VNFs
36 from gi
.repository
import (
46 gi
.require_version('RwKeyspec', '1.0')
47 from gi
.repository
.RwKeyspec
import quoted_key
51 logging
.basicConfig(level
=logging
.DEBUG
)
52 logger
= logging
.getLogger(__name__
)
54 @pytest.fixture(scope
='module')
55 def multi_vm_vnf_nsd_package_file(request
, package_gen_script
, mvv_descr_dir
, package_dir
):
56 pkg_cmd
= "{pkg_scr} --descriptor-type='nsd' --format='xml' --infile='{infile}' --outdir='{outdir}'".format(
57 pkg_scr
=package_gen_script
,
58 infile
=os
.path
.join(mvv_descr_dir
, 'nsd/xml/multivm_tg_ts_config_nsd.xml'),
60 pkg_file
= os
.path
.join(package_dir
, 'multivm_tg_ts_config_nsd.tar.gz')
61 logger
.debug("Generating NSD package: %s", pkg_file
)
62 command
= shlex
.split(pkg_cmd
)
63 print("Running the command arguments: %s" % command
)
64 command
= [package_gen_script
,
65 "--descriptor-type", "nsd",
67 "--infile", "%s" % os
.path
.join(mvv_descr_dir
, 'vnfd/xml/multivm_tg_ts_config_nsd.xml'),
68 "--outdir", "%s" % package_dir
]
69 print("Running new command arguments: %s" % command
)
70 subprocess
.check_call(shlex
.split(pkg_cmd
))
73 def create_nsr(nsd_id
, input_param_list
, cloud_account_name
):
75 Create the NSR record object
79 input_param_list - list of input-parameter objects
84 nsr
= RwNsrYang
.YangData_RwProject_Project_NsInstanceConfig_Nsr()
86 nsr
.id = str(uuid
.uuid4())
87 nsr
.name
= rift
.auto
.mano
.resource_name(nsr
.id)
88 nsr
.short_name
= "nsr_short_name"
89 nsr
.description
= "This is a description"
91 nsr
.admin_status
= "ENABLED"
92 nsr
.input_parameter
.extend(input_param_list
)
93 nsr
.datacenter
= cloud_account_name
98 def upload_descriptor(logger
, descriptor_file
, host
="127.0.0.1"):
99 curl_cmd
= 'curl --insecure -F "descriptor=@{file}" http://{host}:4567/api/upload '.format(
100 file=descriptor_file
,
103 logger
.debug("Uploading descriptor %s using cmd: %s", descriptor_file
, curl_cmd
)
104 stdout
= subprocess
.check_output(shlex
.split(curl_cmd
), universal_newlines
=True)
106 json_out
= json
.loads(stdout
)
107 transaction_id
= json_out
["transaction_id"]
109 return transaction_id
112 class DescriptorOnboardError(Exception):
116 def wait_onboard_transaction_finished(logger
, transaction_id
, timeout
=10, host
="127.0.0.1", project
="default"):
117 logger
.info("Waiting for onboard trans_id %s to complete", transaction_id
)
118 def check_status_onboard_status():
119 uri
= 'http://%s:8008/api/operational/project/%s/create-jobs/job/%s' % (host
, project
, transaction_id
)
120 curl_cmd
= 'curl --insecure {uri}'.format(
123 return subprocess
.check_output(shlex
.split(curl_cmd
), universal_newlines
=True)
127 while elapsed
< timeout
:
128 reply
= check_status_onboard_status()
129 state
= json
.loads(reply
)
130 if state
["status"] == "success":
133 if state
["status"] != "pending":
134 raise DescriptorOnboardError(state
)
137 elapsed
= time
.time() - start
139 if state
["status"] != "success":
140 raise DescriptorOnboardError(state
)
142 logger
.info("Descriptor onboard was successful")
145 @pytest.mark
.setup('multivmvnf')
146 @pytest.mark
.depends('launchpad')
147 @pytest.mark
.incremental
148 class TestMultiVmVnfTrafgenApp(object):
151 def teardown_class(cls
):
152 """ remove the temporary directory contains the descriptor packages
154 logger
.debug("Removing the temporary package directory: %s", cls
.pkg_dir
)
155 if not cls
.pkg_dir
is None:
156 shutil
.rmtree(cls
.pkg_dir
)
158 def test_onboard_trafgen_vnfd(self
, logger
, launchpad_host
, vnfd_proxy
, trafgen_vnfd_package_file
):
159 TestMultiVmVnfTrafgenApp
.pkg_dir
= os
.path
.dirname(trafgen_vnfd_package_file
)
160 logger
.info("Onboarding trafgen vnfd package: %s", trafgen_vnfd_package_file
)
161 trans_id
= upload_descriptor(logger
, trafgen_vnfd_package_file
, launchpad_host
)
162 wait_onboard_transaction_finished(logger
, trans_id
, host
=launchpad_host
)
164 catalog
= vnfd_proxy
.get_config('/rw-project:project[rw-project:name="default"]/vnfd-catalog')
166 assert len(vnfds
) == 1, "There should only be a single vnfd"
168 assert vnfd
.name
== "multivm_trafgen_vnfd"
170 def test_onboard_trafsink_vnfd(self
, logger
, launchpad_host
, vnfd_proxy
, trafsink_vnfd_package_file
):
171 TestMultiVmVnfTrafgenApp
.pkg_dir
= os
.path
.dirname(trafsink_vnfd_package_file
)
172 logger
.info("Onboarding trafsink vnfd package: %s", trafsink_vnfd_package_file
)
173 trans_id
= upload_descriptor(logger
, trafsink_vnfd_package_file
, launchpad_host
)
174 wait_onboard_transaction_finished(logger
, trans_id
, host
=launchpad_host
)
176 catalog
= vnfd_proxy
.get_config('/rw-project:project[rw-project:name="default"]/vnfd-catalog')
178 assert len(vnfds
) == 2, "There should be two vnfds"
179 assert "multivm_trafsink_vnfd" in [vnfds
[0].name
, vnfds
[1].name
]
181 def test_onboard_multi_vm_vnf_nsd(self
, logger
, launchpad_host
, nsd_proxy
, multi_vm_vnf_nsd_package_file
):
182 logger
.info("Onboarding tg_ts nsd package: %s", multi_vm_vnf_nsd_package_file
)
183 trans_id
= upload_descriptor(logger
, multi_vm_vnf_nsd_package_file
, launchpad_host
)
184 wait_onboard_transaction_finished(logger
, trans_id
, host
=launchpad_host
)
186 catalog
= nsd_proxy
.get_config('/rw-project:project[rw-project:name="default"]/nsd-catalog')
188 assert len(nsds
) == 1, "There should only be a single nsd"
190 assert nsd
.name
== "multivm_tg_ts_config_nsd"
192 def test_instantiate_multi_vm_vnf_nsr(self
, logger
, nsd_proxy
, nsr_proxy
, rwnsr_proxy
, base_proxy
, cloud_account_name
):
194 def verify_input_parameters (running_config
, config_param
):
196 Verify the configured parameter set against the running configuration
198 for run_input_param
in running_config
.input_parameter
:
199 if (input_param
.xpath
== config_param
.xpath
and
200 input_param
.value
== config_param
.value
):
203 assert False, ("Verification of configured input parameters: { xpath:%s, value:%s} "
204 "is unsuccessful.\nRunning configuration: %s" % (config_param
.xpath
,
206 running_nsr_config
.input_parameter
))
208 catalog
= nsd_proxy
.get_config('/rw-project:project[rw-project:name="default"]/nsd-catalog')
211 input_parameters
= []
212 descr_xpath
= "/rw-project:project/project-nsd:nsd-catalog/project-nsd:nsd[project-nsd:id=%s]/project-nsd:description" % quoted_key(nsd
.id)
213 descr_value
= "New NSD Description"
214 in_param_id
= str(uuid
.uuid4())
216 input_param_1
= NsrYang
.YangData_RwProject_Project_NsInstanceConfig_Nsr_InputParameter(
220 input_parameters
.append(input_param_1
)
222 nsr
= create_nsr(nsd
.id, input_parameters
, cloud_account_name
)
224 logger
.info("Instantiating the Network Service")
225 rwnsr_proxy
.create_config('/rw-project:project[rw-project:name="default"]/ns-instance-config/nsr', nsr
)
227 nsr_opdata
= rwnsr_proxy
.get('/rw-project:project[rw-project:name="default"]/ns-instance-opdata')
228 nsrs
= nsr_opdata
.nsr
230 # Verify the input parameter configuration
231 running_config
= rwnsr_proxy
.get_config("/rw-project:project[rw-project:name='default']/ns-instance-config/nsr[id=%s]" % quoted_key(nsr
.id))
232 for input_param
in input_parameters
:
233 verify_input_parameters(running_config
, input_param
)
235 assert len(nsrs
) == 1
236 assert nsrs
[0].ns_instance_config_ref
== nsr
.id
238 xpath
= "/rw-project:project[rw-project:name='default']/ns-instance-opdata/nsr[ns-instance-config-ref={}]/operational-status".format(quoted_key(nsr
.id))
239 rwnsr_proxy
.wait_for(xpath
, "running", fail_on
=['failed'], timeout
=360)
242 @pytest.mark
.teardown('multivmvnf')
243 @pytest.mark
.depends('launchpad')
244 @pytest.mark
.incremental
245 class TestMultiVmVnfTrafgenAppTeardown(object):
246 def test_terminate_nsr(self
, nsr_proxy
, vnfr_proxy
, rwnsr_proxy
, logger
):
248 Terminate the instance and check if the record is deleted.
251 1. NSR record is deleted from instance-config.
254 logger
.debug("Terminating Multi VM VNF's NSR")
256 nsr_path
= "/rw-project:project[rw-project:name='default']/ns-instance-config"
257 nsr
= rwnsr_proxy
.get_config(nsr_path
)
259 ping_pong
= nsr
.nsr
[0]
260 rwnsr_proxy
.delete_config("/rw-project:project[rw-project:name='default']/ns-instance-config/nsr[id={}]".format(quoted_key(ping_pong
.id)))
264 def test_delete_records(self
, nsd_proxy
, vnfd_proxy
):
265 """Delete the NSD & VNFD records
268 The records are deleted.
270 nsds
= nsd_proxy
.get("/rw-project:project[rw-project:name='default']/nsd-catalog/nsd", list_obj
=True)
272 xpath
= "/rw-project:project[rw-project:name='default']/nsd-catalog/nsd[id={}]".format(quoted_key(nsd
.id))
273 nsd_proxy
.delete_config(xpath
)
275 vnfds
= vnfd_proxy
.get("/rw-project:project[rw-project:name='default']/vnfd-catalog/vnfd", list_obj
=True)
276 for vnfd_record
in vnfds
.vnfd
:
277 xpath
= "/rw-project:project[rw-project:name='default']/vnfd-catalog/vnfd[id={}]".format(quoted_key(vnfd_record
.id))
278 vnfd_proxy
.delete_config(xpath
)
281 nsds
= nsd_proxy
.get("/rw-project:project[rw-project:name='default']/nsd-catalog/nsd", list_obj
=True)
282 assert nsds
is None or len(nsds
.nsd
) == 0
284 vnfds
= vnfd_proxy
.get("/rw-project:project[rw-project:name='default']/vnfd-catalog/vnfd", list_obj
=True)
285 assert vnfds
is None or len(vnfds
.vnfd
) == 0