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_slb.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} --outdir {outdir} --infile {infile} --descriptor-type nsd --format xml".format(
57 pkg_scr
=package_gen_script
,
59 infile
=os
.path
.join(mvv_descr_dir
, 'nsd/xml/multivm_tg_slb_ts_config_nsd.xml'),
61 pkg_file
= os
.path
.join(package_dir
, 'multivm_tg_slb_ts_config_nsd.tar.gz')
62 logger
.debug("Generating NSD package: %s", pkg_file
)
63 subprocess
.check_call(shlex
.split(pkg_cmd
))
66 def create_nsr(nsd_id
, input_param_list
, cloud_account_name
):
68 Create the NSR record object
72 input_param_list - list of input-parameter objects
77 nsr
= RwNsrYang
.YangData_RwProject_Project_NsInstanceConfig_Nsr()
79 nsr
.id = str(uuid
.uuid4())
80 nsr
.name
= rift
.auto
.mano
.resource_name(nsr
.id)
81 nsr
.short_name
= "nsr_short_name"
82 nsr
.description
= "This is a description"
84 nsr
.admin_status
= "ENABLED"
85 nsr
.input_parameter
.extend(input_param_list
)
86 nsr
.datacenter
= cloud_account_name
91 def upload_descriptor(logger
, descriptor_file
, host
="127.0.0.1"):
92 curl_cmd
= 'curl --insecure -F "descriptor=@{file}" http://{host}:4567/api/upload'.format(
96 logger
.debug("Uploading descriptor %s using cmd: %s", descriptor_file
, curl_cmd
)
97 stdout
= subprocess
.check_output(shlex
.split(curl_cmd
), universal_newlines
=True)
99 json_out
= json
.loads(stdout
)
100 transaction_id
= json_out
["transaction_id"]
102 return transaction_id
105 class DescriptorOnboardError(Exception):
109 def wait_onboard_transaction_finished(logger
, transaction_id
, timeout
=10, host
="127.0.0.1", project
="default"):
110 logger
.info("Waiting for onboard trans_id %s to complete", transaction_id
)
111 def check_status_onboard_status():
112 uri
= 'http://%s:8008/api/operational/project/%s/create-jobs/job/%s' % (host
, project
, transaction_id
)
113 curl_cmd
= 'curl --insecure {uri}'.format(
116 return subprocess
.check_output(shlex
.split(curl_cmd
), universal_newlines
=True)
120 while elapsed
< timeout
:
121 reply
= check_status_onboard_status()
122 state
= json
.loads(reply
)
123 if state
["status"] == "success":
126 if state
["status"] != "pending":
127 raise DescriptorOnboardError(state
)
130 elapsed
= time
.time() - start
132 if state
["status"] != "success":
133 raise DescriptorOnboardError(state
)
135 logger
.info("Descriptor onboard was successful")
138 @pytest.mark
.setup('multivmvnf')
139 @pytest.mark
.depends('launchpad')
140 @pytest.mark
.incremental
141 class TestMultiVmVnfSlb(object):
144 def teardown_class(cls
):
145 """ remove the temporary directory contains the descriptor packages
147 logger
.debug("Removing the temporary package directory: %s", cls
.pkg_dir
)
148 # if not cls.pkg_dir is None:
149 # shutil.rmtree(cls.pkg_dir)
151 def test_onboard_trafgen_vnfd(self
, logger
, launchpad_host
, vnfd_proxy
, trafgen_vnfd_package_file
):
152 TestMultiVmVnfSlb
.pkg_dir
= os
.path
.dirname(trafgen_vnfd_package_file
)
153 logger
.info("Onboarding trafgen vnfd package: %s", trafgen_vnfd_package_file
)
154 trans_id
= upload_descriptor(logger
, trafgen_vnfd_package_file
, launchpad_host
)
155 wait_onboard_transaction_finished(logger
, trans_id
, host
=launchpad_host
)
157 catalog
= vnfd_proxy
.get_config('/rw-project:project[rw-project:name="default"]/vnfd-catalog')
159 assert len(vnfds
) == 1, "There should only be a single vnfd"
161 assert vnfd
.name
== "multivm_trafgen_vnfd"
163 def test_onboard_trafsink_vnfd(self
, logger
, launchpad_host
, vnfd_proxy
, trafsink_vnfd_package_file
):
164 TestMultiVmVnfSlb
.pkg_dir
= os
.path
.dirname(trafsink_vnfd_package_file
)
165 logger
.info("Onboarding trafsink vnfd package: %s", trafsink_vnfd_package_file
)
166 trans_id
= upload_descriptor(logger
, trafsink_vnfd_package_file
, launchpad_host
)
167 wait_onboard_transaction_finished(logger
, trans_id
, host
=launchpad_host
)
169 catalog
= vnfd_proxy
.get_config('/rw-project:project[rw-project:name="default"]/vnfd-catalog')
171 assert len(vnfds
) == 2, "There should be two vnfds"
172 assert "multivm_trafsink_vnfd" in [vnfds
[0].name
, vnfds
[1].name
]
174 def test_onboard_slb_vnfd(self
, logger
, launchpad_host
, vnfd_proxy
, slb_vnfd_package_file
):
175 TestMultiVmVnfSlb
.pkg_dir
= os
.path
.dirname(slb_vnfd_package_file
)
176 logger
.info("Onboarding slb vnfd package: %s", slb_vnfd_package_file
)
177 trans_id
= upload_descriptor(logger
, slb_vnfd_package_file
, launchpad_host
)
178 wait_onboard_transaction_finished(logger
, trans_id
, host
=launchpad_host
)
180 catalog
= vnfd_proxy
.get_config('/rw-project:project[rw-project:name="default"]/vnfd-catalog')
182 assert len(vnfds
) == 3, "There should be two vnfds"
183 assert "multivm_slb_vnfd" in [vnfds
[0].name
, vnfds
[1].name
]
185 def test_onboard_multi_vm_vnf_nsd(self
, logger
, launchpad_host
, nsd_proxy
, multi_vm_vnf_nsd_package_file
):
186 logger
.info("Onboarding tg_slb_ts nsd package: %s", multi_vm_vnf_nsd_package_file
)
187 trans_id
= upload_descriptor(logger
, multi_vm_vnf_nsd_package_file
, launchpad_host
)
188 wait_onboard_transaction_finished(logger
, trans_id
, host
=launchpad_host
)
190 catalog
= nsd_proxy
.get_config('/rw-project:project[rw-project:name="default"]/nsd-catalog')
192 assert len(nsds
) == 1, "There should only be a single nsd"
194 assert nsd
.name
== "multivm_tg_slb_ts_config_nsd"
196 def test_instantiate_multi_vm_vnf_nsr(self
, logger
, nsd_proxy
, nsr_proxy
, rwnsr_proxy
, base_proxy
, cloud_account_name
):
198 def verify_input_parameters (running_config
, config_param
):
200 Verify the configured parameter set against the running configuration
202 for run_input_param
in running_config
.input_parameter
:
203 if (input_param
.xpath
== config_param
.xpath
and
204 input_param
.value
== config_param
.value
):
207 assert False, ("Verification of configured input parameters: { xpath:%s, value:%s} "
208 "is unsuccessful.\nRunning configuration: %s" % (config_param
.xpath
,
210 running_nsr_config
.input_parameter
))
212 catalog
= nsd_proxy
.get_config('/rw-project:project[rw-project:name="default"]/nsd-catalog')
215 input_parameters
= []
216 descr_xpath
= "/rw-project:project/project-nsd:nsd-catalog/project-nsd:nsd[project-nsd:id=%s]/project-nsd:description" % quoted_key(nsd
.id)
217 descr_value
= "New NSD Description"
218 in_param_id
= str(uuid
.uuid4())
220 input_param_1
= NsrYang
.YangData_RwProject_Project_NsInstanceConfig_Nsr_InputParameter(
224 input_parameters
.append(input_param_1
)
226 nsr
= create_nsr(nsd
.id, input_parameters
, cloud_account_name
)
228 logger
.info("Instantiating the Network Service")
229 rwnsr_proxy
.create_config('/rw-project:project[rw-project:name="default"]/ns-instance-config/nsr', nsr
)
231 nsr_opdata
= rwnsr_proxy
.get('/rw-project:project[rw-project:name="default"]/ns-instance-opdata')
232 nsrs
= nsr_opdata
.nsr
234 # Verify the input parameter configuration
235 running_config
= rwnsr_proxy
.get_config("/rw-project:project[rw-project:name='default']/ns-instance-config/nsr[id=%s]" % quoted_key(nsr
.id))
236 for input_param
in input_parameters
:
237 verify_input_parameters(running_config
, input_param
)
239 assert len(nsrs
) == 1
240 assert nsrs
[0].ns_instance_config_ref
== nsr
.id
242 xpath
= "/rw-project:project[rw-project:name='default']/ns-instance-opdata/nsr[ns-instance-config-ref={}]/operational-status".format(quoted_key(nsr
.id))
243 rwnsr_proxy
.wait_for(xpath
, "running", fail_on
=['failed'], timeout
=360)
246 @pytest.mark
.teardown('multivmvnf')
247 @pytest.mark
.depends('launchpad')
248 @pytest.mark
.incremental
249 class TestMultiVmVnfSlbTeardown(object):
250 def test_terminate_nsr(self
, nsr_proxy
, vnfr_proxy
, rwnsr_proxy
, logger
):
252 Terminate the instance and check if the record is deleted.
255 1. NSR record is deleted from instance-config.
258 logger
.debug("Terminating Multi VM VNF's NSR")
260 nsr_path
= "/rw-project:project[rw-project:name='default']/ns-instance-config"
261 nsr
= rwnsr_proxy
.get_config(nsr_path
)
263 ping_pong
= nsr
.nsr
[0]
264 rwnsr_proxy
.delete_config("/rw-project:project[rw-project:name='default']/ns-instance-config/nsr[id={}]".format(quoted_key(ping_pong
.id)))
268 def test_delete_records(self
, nsd_proxy
, vnfd_proxy
):
269 """Delete the NSD & VNFD records
272 The records are deleted.
274 nsds
= nsd_proxy
.get("/rw-project:project[rw-project:name='default']/nsd-catalog/nsd", list_obj
=True)
276 xpath
= "/rw-project:project[rw-project:name='default']/nsd-catalog/nsd[id={}]".format(quoted_key(nsd
.id))
277 nsd_proxy
.delete_config(xpath
)
279 vnfds
= vnfd_proxy
.get("/rw-project:project[rw-project:name='default']/vnfd-catalog/vnfd", list_obj
=True)
280 for vnfd_record
in vnfds
.vnfd
:
281 xpath
= "/rw-project:project[rw-project:name='default']/vnfd-catalog/vnfd[id={}]".format(quoted_key(vnfd_record
.id))
282 vnfd_proxy
.delete_config(xpath
)
285 nsds
= nsd_proxy
.get("/rw-project:project[rw-project:name='default']/nsd-catalog/nsd", list_obj
=True)
286 assert nsds
is None or len(nsds
.nsd
) == 0
288 vnfds
= vnfd_proxy
.get("/rw-project:project[rw-project:name='default']/vnfd-catalog/vnfd", list_obj
=True)
289 assert vnfds
is None or len(vnfds
.vnfd
) == 0