4 # Copyright 2016-2017 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.
31 gi
.require_version('RwCloudYang', '1.0')
32 gi
.require_version('RwDts', '1.0')
33 gi
.require_version('RwNsmYang', '1.0')
34 gi
.require_version('RwLaunchpadYang', '1.0')
35 gi
.require_version('RwResourceMgrYang', '1.0')
36 gi
.require_version('RwcalYang', '1.0')
37 gi
.require_version('RwNsrYang', '1.0')
38 gi
.require_version('NsrYang', '1.0')
39 gi
.require_version('RwlogMgmtYang', '1.0')
41 from gi
.repository
import (
42 RwCloudYang
as rwcloudyang
,
44 RwLaunchpadYang
as launchpadyang
,
45 RwNsmYang
as rwnsmyang
,
46 RwNsrYang
as rwnsryang
,
48 RwResourceMgrYang
as rmgryang
,
49 RwcalYang
as rwcalyang
,
50 RwConfigAgentYang
as rwcfg_agent
,
53 gi
.require_version('RwKeyspec', '1.0')
54 from gi
.repository
.RwKeyspec
import quoted_key
56 from gi
.repository
.RwTypes
import RwStatus
57 import rift
.mano
.examples
.ping_pong_nsd
as ping_pong_nsd
61 from rift
.mano
.utils
.project
import (
71 'password': 'mypasswd',
72 'auth_url': 'http://10.66.4.27:5000/v3/',
73 'project_name': 'demo',
74 'mgmt_network': 'private',
78 if sys
.version_info
< (3, 4, 4):
79 asyncio
.ensure_future
= asyncio
.async
85 return ("C,/project-nsd:nsd-catalog/project-nsd:nsd" +
86 ("[project-nsd:id={}]".format(quoted_key(k
)) if k
is not None else ""))
90 return ("C,/vld:vld-catalog/vld:vld" +
91 ("[vld:id={}]".format(quoted_key(k
)) if k
is not None else ""))
95 return ("C,/project-vnfd:vnfd-catalog/project-vnfd:vnfd" +
96 ("[project-vnfd:id={}]".format(quoted_key(k
)) if k
is not None else ""))
100 return ("D,/vnfr:vnfr-catalog/vnfr:vnfr" +
101 ("[vnfr:id={}]".format(quoted_key(k
)) if k
is not None else ""))
105 return ("D,/vlr:vlr-catalog/vlr:vlr" +
106 ("[vlr:id={}]".format(quoted_key(k
)) if k
is not None else ""))
109 def vnfd_ref_count(k
=None):
110 return ("D,/vnfr:vnfr-catalog/rw-vnfr:vnfd-ref-count" +
111 ("[rw-nsr:nsd-id-ref={}]".format(quoted_key(k
)) if k
is not None else ""))
114 def nsr_config(k
=None):
115 return ("C,/nsr:ns-instance-config/nsr:nsr" +
116 ("[nsr:id={}]".format(quoted_key(k
)) if k
is not None else ""))
119 def nsr_opdata(k
=None):
120 return ("D,/nsr:ns-instance-opdata/nsr:nsr" +
121 ("[nsr:ns-instance-config-ref={}]".format(quoted_key(k
)) if k
is not None else ""))
124 def nsr_config_status(k
=None):
125 return ("D,/nsr:ns-instance-opdata/nsr:nsr" +
126 ("[nsr:ns-instance-config-ref={}]/config_status".format(quoted_key(k
)) if k
is not None else ""))
129 def cm_state(k
=None):
130 return ("D,/rw-conman:cm-state/rw-conman:cm-nsr" +
131 ("[rw-conman:id={}]".format(quoted_key(k
)) if k
is not None else ""))
134 def nsr_scale_group_instance(nsr_id
=None, group_name
=None, index
=None):
135 return (("D,/nsr:ns-instance-opdata/nsr:nsr") +
136 ("[nsr:ns-instance-config-ref={}]".format(quoted_key(nsr_id
)) if nsr_id
is not None else "") +
137 ("/nsr:scaling-group-record") +
138 ("[nsr:scaling-group-name-ref={}]".format(quoted_key(group_name
)) if group_name
is not None else "") +
140 ("[nsr:scaling-group-index-ref={}]".format(quoted_key(index
)) if index
is not None else ""))
143 def nsr_scale_group_instance_config(nsr_id
=None, group_name
=None, index
=None):
144 return (("C,/nsr:ns-instance-config/nsr:nsr") +
145 ("[nsr:id={}]".format(nsr_id
) if nsr_id
is not None else "") +
146 ("/nsr:scaling-group") +
147 ("[nsr:scaling-group-name-ref={}]".format(quoted_key(group_name
)) if group_name
is not None else "") +
149 ("[nsr:index={}]".format(quoted_key(index
)) if index
is not None else ""))
152 def cloud_account(k
=None):
153 return ("C,/rw-cloud:cloud/rw-cloud:account" +
154 ("[rw-cloud:name={}]".format(quoted_key(k
)) if k
is not None else ""))
158 return ("C,/rw-project:project" +
159 ("[rw-project:name={}]".format(quoted_key(k
)) if k
is not None else ""))
162 class ManoQuerier(object):
163 def __init__(self
, log
, dts
, project
):
166 self
.project
= project
168 def add_project(self
, xpath
):
169 return self
.project
.add_project(xpath
)
172 def _read_query(self
, xpath
, do_trace
=False, project
=True):
174 xp
= self
.add_project(xpath
)
177 self
.log
.debug("Running XPATH read query: %s (trace: %s)", xp
, do_trace
)
178 flags
= rwdts
.XactFlag
.MERGE
179 flags
+= rwdts
.XactFlag
.TRACE
if do_trace
else 0
180 res_iter
= yield from self
.dts
.query_read(
186 result
= yield from i
187 if result
is not None:
188 results
.append(result
.result
)
193 def _delete_query(self
, xpath
, flags
=0):
194 xp
= self
.add_project(xpath
)
195 self
.log
.debug("Running XPATH delete query: %s (flags: %d)", xp
, flags
)
196 with self
.dts
.transaction() as xact
:
197 yield from self
.dts
.query_delete(
203 def _update_query(self
, xpath
, msg
, flags
=0):
204 xp
= self
.add_project(xpath
)
205 self
.log
.debug("Running XPATH update query: %s (flags: %d)", xp
, flags
)
206 with self
.dts
.transaction() as xact
:
207 yield from self
.dts
.query_update(
214 def get_cm_state(self
, nsr_id
=None):
215 return (yield from self
._read
_query
(XPaths
.cm_state(nsr_id
), False))
218 def get_nsr_opdatas(self
, nsr_id
=None):
219 return (yield from self
._read
_query
(XPaths
.nsr_opdata(nsr_id
), False))
222 def get_nsr_scale_group_instance_opdata(self
, nsr_id
=None, group_name
=None, index
=None):
223 return (yield from self
._read
_query
(XPaths
.nsr_scale_group_instance(nsr_id
, group_name
, index
), False))
226 def get_nsr_configs(self
, nsr_id
=None):
227 return (yield from self
._read
_query
(XPaths
.nsr_config(nsr_id
)))
230 def get_nsr_config_status(self
, nsr_id
=None):
231 return (yield from self
._read
_query
(XPaths
.nsr_config_status(nsr_id
)))
234 def get_vnfrs(self
, vnfr_id
=None):
235 return (yield from self
._read
_query
(XPaths
.vnfr(vnfr_id
)))
238 def get_vlrs(self
, vlr_id
=None):
239 return (yield from self
._read
_query
(XPaths
.vlr(vlr_id
)))
242 def get_vnfd_ref_counts(self
, vnfd_id
=None):
243 return (yield from self
._read
_query
(XPaths
.vnfd_ref_count(vnfd_id
)))
246 def delete_nsr(self
, nsr_id
):
247 return (yield from self
._delete
_query
(XPaths
.nsr_config(nsr_id
)))
250 def delete_nsd(self
, nsd_id
):
251 return (yield from self
._delete
_query
(XPaths
.nsd(nsd_id
),
252 rwdts
.XactFlag
.ADVISE
))
255 def delete_vnfd(self
, vnfd_id
):
256 return (yield from self
._delete
_query
(XPaths
.vnfd(vnfd_id
),
257 rwdts
.XactFlag
.ADVISE
))
260 def update_nsd(self
, nsd_id
, nsd_msg
):
261 return (yield from self
._update
_query
(XPaths
.nsd(nsd_id
), nsd_msg
,
262 rwdts
.XactFlag
.ADVISE
))
265 def update_vnfd(self
, vnfd_id
, vnfd_msg
):
266 return (yield from self
._update
_query
(XPaths
.vnfd(vnfd_id
), vnfd_msg
,
267 rwdts
.XactFlag
.ADVISE
))
270 def update_nsr_config(self
, nsr_id
, nsr_msg
):
271 return (yield from self
._update
_query
(
272 XPaths
.nsr_config(nsr_id
),
274 rwdts
.XactFlag
.ADVISE|rwdts
.XactFlag
.REPLACE
))
277 class ManoTestCase(rift
.test
.dts
.AbstractDTSTest
):
279 def verify_nsr_state(self
, nsr_id
, state
):
280 nsrs
= yield from self
.querier
.get_nsr_opdatas(nsr_id
)
281 self
.assertEqual(1, len(nsrs
))
284 self
.log
.debug("Got nsr = %s", nsr
)
285 self
.assertEqual(state
, nsr
.operational_status
)
288 def verify_vlr_state(self
, vlr_id
, state
):
289 vlrs
= yield from self
.querier
.get_vlrs(vlr_id
)
290 self
.assertEqual(1, len(vlrs
))
293 self
.assertEqual(state
, vlr
.operational_status
)
295 def verify_vdu_state(self
, vdu
, state
):
296 self
.assertEqual(state
, vdu
.operational_status
)
299 def verify_vnf_state(self
, vnfr_id
, state
):
300 vnfrs
= yield from self
.querier
.get_vnfrs(vnfr_id
)
301 self
.assertEqual(1, len(vnfrs
))
304 self
.assertEqual(state
, vnfr
.operational_status
)
307 def terminate_nsr(self
, nsr_id
):
308 self
.log
.debug("Terminating nsr id: %s", nsr_id
)
309 yield from self
.querier
.delete_nsr(nsr_id
)
312 def verify_nsr_deleted(self
, nsr_id
):
313 nsr_opdatas
= yield from self
.querier
.get_nsr_opdatas(nsr_id
)
314 self
.assertEqual(0, len(nsr_opdatas
))
316 nsr_configs
= yield from self
.querier
.get_nsr_configs(nsr_id
)
317 self
.assertEqual(0, len(nsr_configs
))
320 def verify_num_vlrs(self
, num_vlrs
):
321 vlrs
= yield from self
.querier
.get_vlrs()
322 self
.assertEqual(num_vlrs
, len(vlrs
))
325 def get_nsr_vlrs(self
, nsr_id
):
326 nsrs
= yield from self
.querier
.get_nsr_opdatas(nsr_id
)
327 return [v
.vlr_ref
for v
in nsrs
[0].vlr
]
330 def get_nsr_vnfs(self
, nsr_id
):
331 nsrs
= yield from self
.querier
.get_nsr_opdatas(nsr_id
)
332 return nsrs
[0].constituent_vnfr_ref
335 def get_vnf_vlrs(self
, vnfr_id
):
336 vnfrs
= yield from self
.querier
.get_vnfrs(vnfr_id
)
337 return [i
.vlr_ref
for i
in vnfrs
[0].internal_vlr
]
340 def verify_num_nsr_vlrs(self
, nsr_id
, num_vlrs
):
341 vlrs
= yield from self
.get_nsr_vlrs(nsr_id
)
342 self
.assertEqual(num_vlrs
, len(vlrs
))
345 def verify_num_nsr_vnfrs(self
, nsr_id
, num_vnfs
):
346 vnfs
= yield from self
.get_nsr_vnfs(nsr_id
)
347 self
.assertEqual(num_vnfs
, len(vnfs
))
350 def verify_num_vnfr_vlrs(self
, vnfr_id
, num_vlrs
):
351 vlrs
= yield from self
.get_vnf_vlrs(vnfr_id
)
352 self
.assertEqual(num_vlrs
, len(vlrs
))
355 def get_vnf_vdus(self
, vnfr_id
):
356 vnfrs
= yield from self
.querier
.get_vnfrs(vnfr_id
)
357 return [i
for i
in vnfrs
[0].vdur
]
360 def verify_num_vnfr_vdus(self
, vnfr_id
, num_vdus
):
361 vdus
= yield from self
.get_vnf_vdus(vnfr_id
)
362 self
.assertEqual(num_vdus
, len(vdus
))
365 def verify_num_vnfrs(self
, num_vnfrs
):
366 vnfrs
= yield from self
.querier
.get_vnfrs()
367 self
.assertEqual(num_vnfrs
, len(vnfrs
))
371 class DescriptorPublisher(object):
372 def __init__(self
, log
, loop
, dts
, project
):
376 self
.project
= project
378 self
._registrations
= []
381 def publish(self
, w_path
, path
, desc
):
382 ready_event
= asyncio
.Event(loop
=self
.loop
)
383 if 'rw-project' in path
:
387 w_xp
= self
.project
.add_project(w_path
)
388 xp
= self
.project
.add_project(path
)
391 def on_ready(regh
, status
):
392 self
.log
.debug("Create element: %s, obj-type:%s obj:%s",
393 xp
, type(desc
), desc
)
394 with self
.dts
.transaction() as xact
:
395 regh
.create_element(xp
, desc
, xact
.xact
)
396 self
.log
.debug("Created element: %s, obj:%s", xp
, desc
)
399 handler
= rift
.tasklets
.DTS
.RegistrationHandler(
403 self
.log
.debug("Registering path: %s, obj:%s", w_xp
, desc
)
404 reg
= yield from self
.dts
.register(
407 flags
=rwdts
.Flag
.PUBLISHER | rwdts
.Flag
.NO_PREP_READ
409 self
._registrations
.append(reg
)
410 self
.log
.debug("Registered path : %s", w_xp
)
411 yield from ready_event
.wait()
415 def unpublish_all(self
):
416 self
.log
.debug("Deregistering all published descriptors")
417 for reg
in self
._registrations
:
421 class ProjectPublisher(object):
422 XPATH
= "C,/rw-project:project"
424 def __init__(self
, log
, loop
, dts
, project
):
428 self
.project
= project
431 self
.querier
= ManoQuerier(log
, dts
, project
)
432 self
.publisher
= DescriptorPublisher(log
, loop
,
435 self
._ready
_event
= asyncio
.Event(loop
=self
.loop
)
436 asyncio
.ensure_future(self
.register(), loop
=loop
)
441 def on_ready(regh
, status
):
442 self
._ready
_event
.set()
444 self
.log
.debug("Registering path: %s", ProjectPublisher
.XPATH
)
445 self
.reg
= yield from self
.dts
.register(
446 ProjectPublisher
.XPATH
,
447 flags
=rwdts
.Flag
.PUBLISHER
,
448 handler
=rift
.tasklets
.DTS
.RegistrationHandler(
453 def deregister(self
):
454 if self
.reg
is not None:
455 self
.reg
.deregister()
458 def publish_project(self
, config
, xpath
, xpath_wild
):
460 self
.log
.debug("Publishing cloud_account path: %s - %s, type:%s, obj:%s",
461 xpath
, xpath_wild
, type(config
), config
)
462 yield from self
.publisher
.publish(xpath_wild
, xpath
, config
)
465 class CloudAccountPublisher(object):
466 XPATH
= "C,/rw-cloud:cloud"
468 def __init__(self
, log
, loop
, dts
, project
):
472 self
.project
= project
475 self
.querier
= ManoQuerier(log
, dts
, project
)
476 self
.publisher
= DescriptorPublisher(log
, loop
,
479 self
.xpath
= self
.project
.add_project(CloudAccountPublisher
.XPATH
)
481 self
._ready
_event
= asyncio
.Event(loop
=self
.loop
)
482 asyncio
.ensure_future(self
.register(), loop
=loop
)
487 def on_ready(regh
, status
):
488 self
._ready
_event
.set()
490 self
.log
.debug("Registering path: %s", self
.xpath
)
491 self
.reg
= yield from self
.dts
.register(
493 flags
=rwdts
.Flag
.PUBLISHER
,
494 handler
=rift
.tasklets
.DTS
.RegistrationHandler(
499 def deregister(self
):
500 if self
.reg
is not None:
501 self
.reg
.deregister()
504 def publish_account(self
, account
, xpath
, xpath_wild
):
505 # Publish cloud account
506 self
.log
.debug("Publishing cloud_account path: %s - %s, type:%s, obj:%s",
507 xpath
, xpath_wild
, type(account
), account
)
508 yield from self
.publisher
.publish(xpath_wild
, xpath
, account
)
511 class PingPongNsrConfigPublisher(object):
512 XPATH
= "C,/nsr:ns-instance-config"
514 def __init__(self
, log
, loop
, dts
, ping_pong
, cloud_account_name
, project
):
518 self
.project
= project
521 self
.querier
= ManoQuerier(log
, dts
, project
)
522 self
.xpath
= self
.project
.add_project(PingPongNsrConfigPublisher
.XPATH
)
523 self
.nsr_config
= rwnsryang
.YangData_RwProject_Project_NsInstanceConfig()
525 nsr
= rwnsryang
.YangData_RwProject_Project_NsInstanceConfig_Nsr()
526 nsr
.id = str(uuid
.uuid4())
527 nsr
.name
= "ns1.{}".format(nsr
.id)
528 nsr
.nsd
= nsryang
.YangData_RwProject_Project_NsInstanceConfig_Nsr_Nsd()
529 nsr
.nsd
.from_dict(ping_pong
.ping_pong_nsd
.nsd
.as_dict())
530 nsr
.cloud_account
= cloud_account_name
532 nsr
.vnf_cloud_account_map
.add().from_dict({
533 'member_vnf_index_ref': nsr
.nsd
.constituent_vnfd
[0].member_vnf_index
,
534 'config_agent_account': 'RiftCA',
535 #'cloud_account':'mock_account1'
538 inputs
= nsryang
.YangData_RwProject_Project_NsInstanceConfig_Nsr_InputParameter()
539 inputs
.xpath
= self
.project
.add_project(
540 "/project-nsd:nsd-catalog/project-nsd:nsd[project-nsd:id={}]/project-nsd:name".format(quoted_key(ping_pong
.nsd_id
)))
541 inputs
.value
= "inigo montoya"
543 fast_cpu
= {'metadata_key': 'FASTCPU', 'metadata_value': 'True'}
544 self
.create_nsd_placement_group_map(nsr
,
545 group_name
= 'Orcus',
546 cloud_type
= 'openstack',
547 construct_type
= 'host_aggregate',
548 construct_value
= [fast_cpu
])
550 fast_storage
= {'metadata_key': 'FASTSSD', 'metadata_value': 'True'}
551 self
.create_nsd_placement_group_map(nsr
,
552 group_name
= 'Quaoar',
553 cloud_type
= 'openstack',
554 construct_type
= 'host_aggregate',
555 construct_value
= [fast_storage
])
557 fast_cpu
= {'metadata_key': 'BLUE_HW', 'metadata_value': 'True'}
558 self
.create_vnfd_placement_group_map(nsr
,
560 vnfd_id
= ping_pong
.ping_vnfd_id
,
561 cloud_type
= 'openstack',
562 construct_type
= 'host_aggregate',
563 construct_value
= [fast_cpu
])
565 fast_storage
= {'metadata_key': 'YELLOW_HW', 'metadata_value': 'True'}
566 self
.create_vnfd_placement_group_map(nsr
,
567 group_name
= 'Weywot',
568 vnfd_id
= ping_pong
.pong_vnfd_id
,
569 cloud_type
= 'openstack',
570 construct_type
= 'host_aggregate',
571 construct_value
= [fast_storage
])
574 nsr
.input_parameter
.append(inputs
)
577 self
.nsr_config
.nsr
.append(nsr
)
579 self
._ready
_event
= asyncio
.Event(loop
=self
.loop
)
580 asyncio
.ensure_future(self
.register(), loop
=loop
)
585 def on_ready(regh
, status
):
586 self
._ready
_event
.set()
588 self
.log
.debug("Registering path: %s", self
.xpath
)
589 self
.reg
= yield from self
.dts
.register(
591 flags
=rwdts
.Flag
.PUBLISHER
,
592 handler
=rift
.tasklets
.DTS
.RegistrationHandler(
599 self
.log
.debug("Publishing NSR: {}".format(self
.nsr_config
))
600 yield from self
._ready
_event
.wait()
601 with self
.dts
.transaction() as xact
:
602 self
.reg
.create_element(
611 def create_scale_group_instance(self
, group_name
, index
):
613 scaling_group
= self
.nsr_config
.nsr
[0].scaling_group
.add()
614 scaling_group
.from_dict({
615 "scaling_group_name_ref": group_name
,
616 "instance": [{"index": index
}],
618 with self
.dts
.transaction() as xact
:
619 self
.reg
.update_element(
627 def create_nsd_placement_group_map(self
,
633 placement_group
= nsr
.nsd_placement_group_maps
.add()
634 placement_group
.from_dict({
635 "placement_group_ref" : group_name
,
636 "cloud_type" : cloud_type
,
637 construct_type
: construct_value
,
641 def create_vnfd_placement_group_map(self
,
648 placement_group
= nsr
.vnfd_placement_group_maps
.add()
649 placement_group
.from_dict({
650 "placement_group_ref" : group_name
,
651 "vnfd_id_ref" : vnfd_id
,
652 "cloud_type" : cloud_type
,
653 construct_type
: construct_value
,
658 def delete_scale_group_instance(self
, group_name
, index
):
659 self
.log
.debug("Deleting scale group %s instance %s", group_name
, index
)
660 #del self.nsr_config.nsr[0].scaling_group[0].instance[0]
661 xpath
= self
.project
.add_project(
662 XPaths
.nsr_scale_group_instance_config(self
.nsr_config
.nsr
[0].id,
664 yield from self
.dts
.query_delete(xpath
, flags
=rwdts
.XactFlag
.ADVISE
)
666 def deregister(self
):
667 if self
.reg
is not None:
668 self
.reg
.deregister()
670 def create_nsr_vl(self
):
671 vld
= self
.nsr_config
.nsr
[0].nsd
.vld
.add()
672 vld
.id = 'ping_pong_vld_2'
673 vld
.name
= 'ping_pong_vld_2' # hard coded
674 vld
.short_name
= vld
.name
675 vld
.vendor
= 'RIFT.io'
676 vld
.description
= 'Toy VL'
678 vld
.type_yang
= 'ELAN'
680 # cpref = vld.vnfd_connection_point_ref.add()
681 # cpref.member_vnf_index_ref = cp[0]
682 # cpref.vnfd_id_ref = cp[1]
683 # cpref.vnfd_connection_point_ref = cp[2]
685 vld
= self
.nsr_config
.nsr
[0].vl_cloud_account_map
.add()
686 vld
.vld_id_ref
= 'ping_pong_vld_2'
687 vld
.cloud_accounts
= ["mock_account"]
690 def add_nsr_vl(self
):
692 yield from self
.querier
.update_nsr_config(
693 self
.nsr_config
.nsr
[0].id,
694 self
.nsr_config
.nsr
[0],
698 def del_nsr_vl(self
):
699 for vld
in self
.nsr_config
.nsr
[0].nsd
.vld
:
700 if vld
.id == 'ping_pong_vld_2':
701 self
.nsr_config
.nsr
[0].nsd
.vld
.remove(vld
)
704 yield from self
.querier
.update_nsr_config(
705 self
.nsr_config
.nsr
[0].id,
706 self
.nsr_config
.nsr
[0],
709 def update_vnf_cloud_map(self
,vnf_cloud_map
):
710 self
.log
.debug("Modifying NSR to add VNF cloud account map: {}".format(vnf_cloud_map
))
711 for vnf_index
,cloud_acct
in vnf_cloud_map
.items():
712 vnf_maps
= [vnf_map
for vnf_map
in \
713 self
.nsr_config
.nsr
[0].vnf_cloud_account_map \
714 if vnf_index
== vnf_map
.member_vnf_index_ref
]
716 vnf_maps
[0].cloud_account
= cloud_acct
718 self
.nsr_config
.nsr
[0].vnf_cloud_account_map
.add().from_dict({
719 'member_vnf_index_ref':vnf_index
,
720 'cloud_account':cloud_acct
724 class PingPongDescriptorPublisher(object):
725 def __init__(self
, log
, loop
, dts
, project
,
726 num_external_vlrs
=1, num_internal_vlrs
=1, num_ping_vms
=1):
730 self
.project
= project
732 self
.querier
= ManoQuerier(self
.log
, self
.dts
, self
.project
)
733 self
.publisher
= DescriptorPublisher(self
.log
, self
.loop
,
734 self
.dts
, self
.project
)
735 self
.ping_vnfd
, self
.pong_vnfd
, self
.ping_pong_nsd
= \
736 ping_pong_nsd
.generate_ping_pong_descriptors(
738 external_vlr_count
=num_external_vlrs
,
739 internal_vlr_count
=num_internal_vlrs
,
742 use_scale_group
=False,
743 use_mon_params
=False,
747 return self
.ping_pong_nsd
.id
750 def ping_vnfd_id(self
):
751 return self
.ping_vnfd
.id
754 def pong_vnfd_id(self
):
755 return self
.pong_vnfd
.id
758 def publish_desciptors(self
):
760 xpath
= XPaths
.vnfd(self
.ping_vnfd_id
)
761 xpath_wild
= XPaths
.vnfd()
762 for obj
in self
.ping_vnfd
.descriptor
.vnfd
:
763 self
.log
.debug("Publishing ping_vnfd path: %s - %s, type:%s, obj:%s",
764 xpath
, xpath_wild
, type(obj
), obj
)
765 yield from self
.publisher
.publish(xpath_wild
, xpath
, obj
)
768 xpath
= XPaths
.vnfd(self
.pong_vnfd_id
)
769 xpath_wild
= XPaths
.vnfd()
770 for obj
in self
.pong_vnfd
.descriptor
.vnfd
:
771 self
.log
.debug("Publishing pong_vnfd path: %s, wild_path: %s, obj:%s",
772 xpath
, xpath_wild
, obj
)
773 yield from self
.publisher
.publish(xpath_wild
, xpath
, obj
)
775 # Publish ping_pong_nsd
776 xpath
= XPaths
.nsd(self
.nsd_id
)
777 xpath_wild
= XPaths
.nsd()
778 for obj
in self
.ping_pong_nsd
.descriptor
.nsd
:
779 self
.log
.debug("Publishing ping_pong nsd path: %s, wild_path: %s, obj:%s",
780 xpath
, xpath_wild
, obj
)
781 yield from self
.publisher
.publish(xpath_wild
, xpath
, obj
)
783 self
.log
.debug("DONE - publish_desciptors")
785 def unpublish_descriptors(self
):
786 self
.publisher
.unpublish_all()
789 def delete_nsd(self
):
790 yield from self
.querier
.delete_nsd(self
.ping_pong_nsd
.id)
793 def delete_ping_vnfd(self
):
794 yield from self
.querier
.delete_vnfd(self
.ping_vnfd
.id)
797 def update_nsd(self
):
798 yield from self
.querier
.update_nsd(
799 self
.ping_pong_nsd
.id,
800 self
.ping_pong_nsd
.descriptor
.nsd
[0]
804 def update_ping_vnfd(self
):
805 yield from self
.querier
.update_vnfd(
807 self
.ping_vnfd
.descriptor
.vnfd
[0]
811 class ManoTestCase(rift
.test
.dts
.AbstractDTSTest
):
813 DTS GI interface unittests
815 Note: Each tests uses a list of asyncio.Events for staging through the
816 test. These are required here because we are bring up each coroutine
817 ("tasklet") at the same time and are not implementing any re-try
818 mechanisms. For instance, this is used in numerous tests to make sure that
819 a publisher is up and ready before the subscriber sends queries. Such
820 event lists should not be used in production software.
824 def configure_suite(cls
, rwmain
):
825 vns_dir
= os
.environ
.get('VNS_DIR')
826 vnfm_dir
= os
.environ
.get('VNFM_DIR')
827 nsm_dir
= os
.environ
.get('NSM_DIR')
828 rm_dir
= os
.environ
.get('RM_DIR')
830 rwmain
.add_tasklet(vns_dir
, 'rwvnstasklet')
831 rwmain
.add_tasklet(vnfm_dir
, 'rwvnfmtasklet')
832 rwmain
.add_tasklet(nsm_dir
, 'rwnsmtasklet')
833 rwmain
.add_tasklet(rm_dir
, 'rwresmgrtasklet')
834 rwmain
.add_tasklet(rm_dir
, 'rwconmantasklet')
837 def configure_schema(cls
):
838 return rwnsmyang
.get_schema()
841 def configure_timeout(cls
):
845 def get_cal_account(account_type
, account_name
):
847 Creates an object for class RwcalYang.Cloud
849 account
= rwcloudyang
.YangData_RwProject_Project_Cloud_Account()
850 if account_type
== 'mock':
851 account
.name
= account_name
852 account
.account_type
= "mock"
853 account
.mock
.username
= "mock_user"
854 elif ((account_type
== 'openstack_static') or (account_type
== 'openstack_dynamic')):
855 account
.name
= account_name
856 account
.account_type
= 'openstack'
857 account
.openstack
.key
= openstack_info
['username']
858 account
.openstack
.secret
= openstack_info
['password']
859 account
.openstack
.auth_url
= openstack_info
['auth_url']
860 account
.openstack
.tenant
= openstack_info
['project_name']
861 account
.openstack
.mgmt_network
= openstack_info
['mgmt_network']
865 def configure_project(self
, project
=None):
867 project
= self
.project
869 proj_xpath
= "C,{}/project-config".format(project
.prefix
)
870 self
.log
.info("Creating project: {} with {}".
871 format(proj_xpath
, project
.config
.as_dict()))
872 xpath_wild
= "C,/rw-project:project/project-config"
873 yield from self
.project_publisher
.publish_project(project
.config
,
878 def configure_cloud_account(self
, dts
, cloud_type
, cloud_name
="cloud1", project
=None):
879 account
= self
.get_cal_account(cloud_type
, cloud_name
)
880 self
.log
.info("Configuring cloud-account: %s", account
)
882 project
= self
.project
883 xpath
= project
.add_project(XPaths
.cloud_account(account
.name
))
884 xpath_wild
= project
.add_project(XPaths
.cloud_account())
886 # account_xpath = project.add_project(
887 # "C,/rw-cloud:cloud/rw-cloud:account[rw-cloud:name={}]".format(quoted_key(cloud_name)))
888 # yield from dts.query_create(account_xpath,
889 # rwdts.XactFlag.ADVISE,
891 yield from self
.cloud_publisher
.publish_account(account
, xpath
, xpath_wild
)
894 def wait_tasklets(self
):
895 yield from asyncio
.sleep(5, loop
=self
.loop
)
897 def configure_test(self
, loop
, test_id
):
898 self
.log
.debug("STARTING - %s", self
.id())
899 self
.tinfo
= self
.new_tinfo(self
.id())
900 self
.dts
= rift
.tasklets
.DTS(self
.tinfo
, self
.schema
, self
.loop
)
901 self
.project
= ManoProject(self
.log
,
902 name
=DEFAULT_PROJECT
)
903 self
.project1
= ManoProject(self
.log
,
905 self
.ping_pong
= PingPongDescriptorPublisher(self
.log
, self
.loop
,
906 self
.dts
, self
.project
)
907 self
.querier
= ManoQuerier(self
.log
, self
.dts
, self
.project
)
908 self
.project_publisher
= ProjectPublisher(
914 self
.cloud_publisher
= CloudAccountPublisher(
920 self
.nsr_publisher
= PingPongNsrConfigPublisher(
929 def test_create_nsr_record(self
):
932 def verify_projects(termination
=False):
933 self
.log
.debug("Verifying projects = %s", XPaths
.project())
935 accts
= yield from self
.querier
._read
_query
(XPaths
.project(),
939 self
.log
.debug("Project: {}".format(acc
.as_dict()))
940 if acc
.name
not in projs
:
941 projs
.append(acc
.name
)
942 self
.log
.debug("Merged: {}".format(projs
))
943 self
.assertEqual(2, len(projs
))
946 def verify_cloud_accounts(termination
=False):
947 self
.log
.debug("Verifying cloud accounts = %s", XPaths
.cloud_account())
949 accts
= yield from self
.querier
._read
_query
(XPaths
.cloud_account())
950 self
.assertEqual(2, len(accts
))
952 accts
= yield from self
.querier
._read
_query
(
953 self
.project1
.add_project(XPaths
.cloud_account()), project
=False)
954 self
.assertEqual(1, len(accts
))
956 accts
= yield from self
.querier
._read
_query
(
957 "C,/rw-project:project/rw-cloud:cloud/rw-cloud:account",
959 self
.assertEqual(3, len(accts
))
961 accts
= yield from self
.querier
._read
_query
(
962 "C,/rw-project:project/rw-cloud:cloud/rw-cloud:account[rw-cloud:name='mock_account']",
964 self
.assertEqual(2, len(accts
))
967 def verify_cm_state(termination
=False, nsrid
=None):
968 self
.log
.debug("Verifying cm_state path = %s", XPaths
.cm_state(nsrid
))
973 yield from asyncio
.sleep(loop_sleep
, loop
=self
.loop
)
976 cm_nsr_i
= yield from self
.querier
.get_cm_state(nsr_id
=nsrid
)
977 if (cm_nsr_i
is not None and len(cm_nsr_i
) != 0):
978 self
.assertEqual(1, len(cm_nsr_i
))
979 cm_nsr
= cm_nsr_i
[0].as_dict()
980 #print("###>>> cm_nsr=", cm_nsr)
982 if len(cm_nsr_i
) == 0:
983 print("\n###>>> cm-state NSR deleted OK <<<###\n")
985 elif (cm_nsr
is not None and
986 'state' in cm_nsr
and
987 (cm_nsr
['state'] == 'ready')):
988 self
.log
.debug("Got cm_nsr record %s", cm_nsr
)
989 print("\n###>>> cm-state NSR 'ready' OK <<<###\n")
992 # if (len(cm_nsr_i) == 1 and cm_nsr_i[0].state == 'ready'):
993 # self.log.debug("Got cm_nsr record %s", cm_nsr)
995 # yield from asyncio.sleep(10, loop=self.loop)
997 print("###>>> Failed cm-state, termination:", termination
)
998 self
.assertEqual(1, loop_count
)
1001 def verify_nsr_opdata(termination
=False):
1002 self
.log
.debug("Verifying nsr opdata path = %s", XPaths
.nsr_opdata())
1005 nsrs
= yield from self
.querier
.get_nsr_opdatas()
1009 nsrs
= yield from self
.querier
.get_nsr_opdatas()
1011 self
.log
.debug("No active NSR records found. NSR termination successful")
1014 self
.assertEqual(0, len(nsrs
))
1015 self
.log
.error("Active NSR records found. NSR termination failed")
1018 self
.log
.debug("No active NSR records found. NSR termination successful")
1019 self
.assertEqual(0, len(nsrs
))
1023 self
.log
.debug("Got nsr record %s", nsr
)
1024 if nsr
.operational_status
== 'running':
1025 self
.log
.debug("!!! Rcvd NSR with running status !!!")
1026 self
.assertEqual("configuring", nsr
.config_status
)
1029 self
.log
.debug("Rcvd NSR with %s status", nsr
.operational_status
)
1030 self
.log
.debug("Sleeping for 10 seconds")
1031 yield from asyncio
.sleep(10, loop
=self
.loop
)
1034 def verify_nsr_config(termination
=False):
1035 self
.log
.debug("Verifying nsr config path = %s", XPaths
.nsr_config())
1037 nsr_configs
= yield from self
.querier
.get_nsr_configs()
1038 self
.assertEqual(1, len(nsr_configs
))
1040 nsr_config
= nsr_configs
[0]
1042 "/rw-project:project/project-nsd:nsd-catalog/project-nsd:nsd[project-nsd:id={}]/project-nsd:name".format(quoted_key(self
.ping_pong
.nsd_id
)),
1043 nsr_config
.input_parameter
[0].xpath
,
1047 def verify_nsr_config_status(termination
=False, nsrid
=None):
1048 if termination
is False and nsrid
is not None:
1049 self
.log
.debug("Verifying nsr config status path = %s", XPaths
.nsr_opdata(nsrid
))
1055 yield from asyncio
.sleep(loop_sleep
, loop
=self
.loop
)
1056 nsr_opdata_l
= yield from self
.querier
.get_nsr_opdatas(nsrid
)
1057 self
.assertEqual(1, len(nsr_opdata_l
))
1058 nsr_opdata
= nsr_opdata_l
[0].as_dict()
1059 self
.log
.debug("NSR opdata: {}".format(nsr_opdata
))
1060 if ("configured" == nsr_opdata
['config_status']):
1061 print("\n###>>> NSR Config Status 'configured' OK <<<###\n")
1063 self
.assertEqual("configured", nsr_opdata
['config_status'])
1066 def verify_vnfr_record(termination
=False):
1067 self
.log
.debug("Verifying vnfr record path = %s, Termination=%d",
1068 XPaths
.vnfr(), termination
)
1071 vnfrs
= yield from self
.querier
.get_vnfrs()
1076 self
.log
.debug("VNFR still exists = %s", vnfr
)
1078 yield from asyncio
.sleep(.5, loop
=self
.loop
)
1081 assert len(vnfrs
) == 0
1084 vnfrs
= yield from self
.querier
.get_vnfrs()
1085 if len(vnfrs
) != 0 and termination
is False:
1087 self
.log
.debug("Rcvd VNFR with %s status", vnfr
.operational_status
)
1088 if vnfr
.operational_status
== 'running':
1089 self
.log
.debug("!!! Rcvd VNFR with running status !!!")
1092 elif vnfr
.operational_status
== "failed":
1093 self
.log
.debug("!!! Rcvd VNFR with failed status !!!")
1096 self
.log
.debug("Sleeping for 10 seconds")
1097 yield from asyncio
.sleep(10, loop
=self
.loop
)
1101 def verify_vnfr_cloud_account(vnf_index
, cloud_account
):
1102 self
.log
.debug("Verifying vnfr record Cloud account for vnf index = %d is %s", vnf_index
,cloud_account
)
1103 vnfrs
= yield from self
.querier
.get_vnfrs()
1104 cloud_accounts
= [vnfr
.cloud_account
for vnfr
in vnfrs
if vnfr
.member_vnf_index_ref
== vnf_index
]
1105 self
.log
.debug("VNFR cloud account for index %d is %s", vnf_index
,cloud_accounts
[0])
1106 assert cloud_accounts
[0] == cloud_account
1109 def verify_vlr_record(termination
=False):
1110 vlr_xpath
= XPaths
.vlr()
1111 self
.log
.debug("Verifying vlr record path = %s, termination: %s",
1112 vlr_xpath
, termination
)
1113 res_iter
= yield from self
.dts
.query_read(vlr_xpath
)
1116 result
= yield from i
1118 self
.assertIsNone(result
)
1120 self
.log
.debug("Got vlr record %s", result
)
1123 def verify_vlrs(nsr_id
, count
=0):
1125 nsrs
= yield from self
.querier
.get_nsr_opdatas()
1127 self
.log
.debug("Got nsr record %s", nsr
)
1128 if nsr
.operational_status
== 'running':
1129 self
.log
.debug("!!! Rcvd NSR with running status !!!")
1130 # Check the VLR count
1131 if (len(nsr
.vlr
)) == count
:
1132 self
.log
.debug("NSR %s has %d VLRs", nsr_id
, count
)
1135 self
.log
.debug("Rcvd NSR %s with %s status", nsr_id
, nsr
.operational_status
)
1136 self
.log
.debug("Sleeping for 10 seconds")
1137 yield from asyncio
.sleep(10, loop
=self
.loop
)
1141 def verify_vnfd_ref_count(termination
):
1142 self
.log
.debug("Verifying vnfd ref count= %s", XPaths
.vnfd_ref_count())
1143 res_iter
= yield from self
.dts
.query_read(XPaths
.vnfd_ref_count())
1146 result
= yield from i
1147 self
.log
.debug("Got vnfd ref count record %s", result
)
1150 def verify_scale_group_reaches_state(nsr_id
, scale_group
, index
, state
, timeout
=1000):
1151 start_time
= time
.time()
1152 instance_state
= None
1153 while (time
.time() - start_time
) < timeout
:
1154 results
= yield from self
.querier
.get_nsr_opdatas(nsr_id
=nsr_id
)
1155 if len(results
) == 1:
1157 if len(result
.scaling_group_record
) == 0:
1160 if len(result
.scaling_group_record
[0].instance
) == 0:
1163 instance
= result
.scaling_group_record
[0].instance
[0]
1164 self
.assertEqual(instance
.scaling_group_index_ref
, index
)
1166 instance_state
= instance
.op_status
1167 if instance_state
== state
:
1168 self
.log
.debug("Scale group instance reached %s state", state
)
1171 yield from asyncio
.sleep(1, loop
=self
.loop
)
1173 self
.assertEqual(state
, instance_state
)
1176 def verify_results(termination
=False, nsrid
=None):
1177 yield from verify_vnfr_record(termination
)
1178 #yield from verify_vlr_record(termination)
1179 yield from verify_nsr_opdata(termination
)
1180 yield from verify_nsr_config(termination
)
1181 yield from verify_vnfd_ref_count(termination
)
1184 yield from verify_cm_state(termination
, nsrid
)
1185 yield from verify_nsr_config_status(termination
, nsrid
)
1187 yield from verify_cloud_account(termination
)
1188 yield from verify_project_record(termination
)
1191 def verify_scale_instance(index
):
1192 self
.log
.debug("Verifying scale record path = %s, Termination=%d",
1193 XPaths
.vnfr(), termination
)
1196 vnfrs
= yield from self
.querier
.get_vnfrs()
1201 self
.log
.debug("VNFR still exists = %s", vnfr
)
1204 assert len(vnfrs
) == 0
1207 vnfrs
= yield from self
.querier
.get_vnfrs()
1208 if len(vnfrs
) != 0 and termination
is False:
1210 self
.log
.debug("Rcvd VNFR with %s status", vnfr
.operational_status
)
1211 if vnfr
.operational_status
== 'running':
1212 self
.log
.debug("!!! Rcvd VNFR with running status !!!")
1215 elif vnfr
.operational_status
== "failed":
1216 self
.log
.debug("!!! Rcvd VNFR with failed status !!!")
1219 self
.log
.debug("Sleeping for 10 seconds")
1220 yield from asyncio
.sleep(10, loop
=self
.loop
)
1223 def terminate_ns(nsr_id
):
1224 xpath
= XPaths
.nsr_config(nsr_id
)
1225 self
.log
.debug("Terminating network service with path %s", xpath
)
1226 yield from self
.dts
.query_delete(xpath
, flags
=rwdts
.XactFlag
.ADVISE
)
1227 self
.log
.debug("Terminated network service with path %s", xpath
)
1231 yield from self
.wait_tasklets()
1233 yield from self
.configure_project()
1234 yield from self
.configure_project(project
=self
.project1
)
1237 yield from self
.configure_cloud_account(self
.dts
, cloud_type
, "mock_account")
1238 yield from self
.configure_cloud_account(self
.dts
, cloud_type
, "mock_account1")
1239 yield from self
.configure_cloud_account(self
.dts
, cloud_type
, "mock_account",
1240 project
=self
.project1
)
1242 yield from verify_cloud_accounts()
1243 yield from verify_projects()
1245 yield from self
.ping_pong
.publish_desciptors()
1248 # Attempt deleting VNFD not in use
1249 yield from self
.ping_pong
.update_ping_vnfd()
1251 # Attempt updating NSD not in use
1252 yield from self
.ping_pong
.update_nsd()
1254 # Attempt deleting VNFD not in use
1255 yield from self
.ping_pong
.delete_ping_vnfd()
1257 # Attempt deleting NSD not in use
1258 yield from self
.ping_pong
.delete_nsd()
1260 yield from self
.ping_pong
.publish_desciptors()
1262 nsr_id
= yield from self
.nsr_publisher
.publish()
1264 yield from verify_results(nsrid
=nsr_id
)
1266 # yield from self.nsr_publisher.create_scale_group_instance("ping_group", 1)
1268 # yield from verify_scale_group_reaches_state(nsr_id, "ping_group", 1, "running")
1270 # yield from self.nsr_publisher.delete_scale_group_instance("ping_group", 1)
1272 yield from asyncio
.sleep(10, loop
=self
.loop
)
1274 # Attempt deleting VNFD in use
1275 yield from self
.ping_pong
.delete_ping_vnfd()
1277 # Attempt updating NSD in use
1278 yield from self
.ping_pong
.update_nsd()
1280 # Update NSD in use with new VL
1281 yield from self
.nsr_publisher
.add_nsr_vl()
1283 # Verify the new VL has been added
1284 yield from verify_vlrs(nsr_id
, count
=2)
1286 # Delete the added VL
1287 yield from self
.nsr_publisher
.del_nsr_vl()
1289 # Verify the new VL has been added
1290 yield from verify_vlrs(nsr_id
, count
=1)
1292 # Attempt deleting NSD in use
1293 yield from self
.ping_pong
.delete_nsd()
1295 yield from terminate_ns(nsr_id
)
1297 yield from asyncio
.sleep(25, loop
=self
.loop
)
1298 self
.log
.debug("Verifying termination results")
1299 yield from verify_results(termination
=True, nsrid
=nsr_id
)
1300 self
.log
.debug("Verified termination results")
1302 # Multi site NS case
1303 self
.log
.debug("Testing multi site NS")
1304 self
.nsr_publisher
.update_vnf_cloud_map({1:"mock_account1",2:"mock_account"})
1305 nsr_id
= yield from self
.nsr_publisher
.publish()
1307 yield from verify_results(nsrid
=nsr_id
)
1308 yield from verify_vnfr_cloud_account(1,"mock_account1")
1309 yield from verify_vnfr_cloud_account(2,"mock_account")
1310 yield from verify_vlrs(nsr_id
, count
=2)
1312 yield from terminate_ns(nsr_id
)
1314 yield from asyncio
.sleep(25, loop
=self
.loop
)
1315 self
.log
.debug("Verifying termination results for multi site NS")
1316 yield from verify_results(termination
=True, nsrid
=nsr_id
)
1317 self
.log
.debug("Verified termination results for multi site NS")
1319 self
.log
.debug("Attempting to delete VNFD for real")
1320 yield from self
.ping_pong
.delete_ping_vnfd()
1322 self
.log
.debug("Attempting to delete NSD for real")
1323 yield from self
.ping_pong
.delete_nsd()
1325 future
= asyncio
.ensure_future(run_test(), loop
=self
.loop
)
1326 self
.run_until(future
.done
)
1327 if future
.exception() is not None:
1328 self
.log
.error("Caught exception during test")
1329 raise future
.exception()
1333 plugin_dir
= os
.path
.join(os
.environ
["RIFT_INSTALL"], "usr/lib/rift/plugins")
1334 if 'VNS_DIR' not in os
.environ
:
1335 os
.environ
['VNS_DIR'] = os
.path
.join(plugin_dir
, 'rwvns')
1337 if 'VNFM_DIR' not in os
.environ
:
1338 os
.environ
['VNFM_DIR'] = os
.path
.join(plugin_dir
, 'rwvnfm')
1340 if 'NSM_DIR' not in os
.environ
:
1341 os
.environ
['NSM_DIR'] = os
.path
.join(plugin_dir
, 'rwnsm')
1343 if 'RM_DIR' not in os
.environ
:
1344 os
.environ
['RM_DIR'] = os
.path
.join(plugin_dir
, 'rwresmgrtasklet')
1346 runner
= xmlrunner
.XMLTestRunner(output
=os
.environ
["RIFT_MODULE_TEST"])
1348 parser
= argparse
.ArgumentParser()
1349 parser
.add_argument('-v', '--verbose', action
='store_true')
1350 parser
.add_argument('-n', '--no-runner', action
='store_true')
1351 args
, unittest_args
= parser
.parse_known_args()
1355 ManoTestCase
.log_level
= logging
.DEBUG
if args
.verbose
else logging
.WARN
1357 unittest
.main(testRunner
=runner
, argv
=[sys
.argv
[0]] + unittest_args
)
1359 if __name__
== '__main__':