0ec3d18857fda093a9132e6aeaa831eca71354cb
[osm/SO.git] / rwlaunchpad / test / launchpad.py
1 #!/usr/bin/env python3
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
20 import logging
21 import os
22 import resource
23 import socket
24 import sys
25 import subprocess
26 import shlex
27 import shutil
28 import netifaces
29
30 from rift.rwlib.util import certs
31 import rift.rwcal.cloudsim
32 import rift.rwcal.cloudsim.net
33 import rift.vcs
34 import rift.vcs.core as core
35 import rift.vcs.demo
36 import rift.vcs.vms
37
38 import rift.rwcal.cloudsim
39 import rift.rwcal.cloudsim.net
40
41 from rift.vcs.ext import ClassProperty
42
43 logger = logging.getLogger(__name__)
44
45
46 class NsmTasklet(rift.vcs.core.Tasklet):
47 """
48 This class represents a network services manager tasklet.
49 """
50
51 def __init__(self, name='network-services-manager', uid=None,
52 config_ready=True,
53 recovery_action=core.RecoveryType.FAILCRITICAL.value,
54 data_storetype=core.DataStore.NOSTORE.value,
55 ):
56 """
57 Creates a NsmTasklet object.
58
59 Arguments:
60 name - the name of the tasklet
61 uid - a unique identifier
62 """
63 super(NsmTasklet, self).__init__(name=name, uid=uid,
64 config_ready=config_ready,
65 recovery_action=recovery_action,
66 data_storetype=data_storetype,
67 )
68
69 plugin_directory = ClassProperty('./usr/lib/rift/plugins/rwnsmtasklet')
70 plugin_name = ClassProperty('rwnsmtasklet')
71
72
73 class VnsTasklet(rift.vcs.core.Tasklet):
74 """
75 This class represents a network services manager tasklet.
76 """
77
78 def __init__(self, name='virtual-network-service', uid=None,
79 config_ready=True,
80 recovery_action=core.RecoveryType.FAILCRITICAL.value,
81 data_storetype=core.DataStore.NOSTORE.value,
82 ):
83 """
84 Creates a VnsTasklet object.
85
86 Arguments:
87 name - the name of the tasklet
88 uid - a unique identifier
89 """
90 super(VnsTasklet, self).__init__(name=name, uid=uid,
91 config_ready=config_ready,
92 recovery_action=recovery_action,
93 data_storetype=data_storetype,
94 )
95
96 plugin_directory = ClassProperty('./usr/lib/rift/plugins/rwvnstasklet')
97 plugin_name = ClassProperty('rwvnstasklet')
98
99
100 class VnfmTasklet(rift.vcs.core.Tasklet):
101 """
102 This class represents a virtual network function manager tasklet.
103 """
104
105 def __init__(self, name='virtual-network-function-manager', uid=None,
106 config_ready=True,
107 recovery_action=core.RecoveryType.FAILCRITICAL.value,
108 data_storetype=core.DataStore.NOSTORE.value,
109 ):
110 """
111 Creates a VnfmTasklet object.
112
113 Arguments:
114 name - the name of the tasklet
115 uid - a unique identifier
116 """
117 super(VnfmTasklet, self).__init__(name=name, uid=uid,
118 config_ready=config_ready,
119 recovery_action=recovery_action,
120 data_storetype=data_storetype,
121 )
122
123 plugin_directory = ClassProperty('./usr/lib/rift/plugins/rwvnfmtasklet')
124 plugin_name = ClassProperty('rwvnfmtasklet')
125
126
127 class ResMgrTasklet(rift.vcs.core.Tasklet):
128 """
129 This class represents a Resource Manager tasklet.
130 """
131
132 def __init__(self, name='Resource-Manager', uid=None,
133 config_ready=True,
134 recovery_action=core.RecoveryType.FAILCRITICAL.value,
135 data_storetype=core.DataStore.NOSTORE.value,
136 ):
137 """
138 Creates a ResMgrTasklet object.
139
140 Arguments:
141 name - the name of the tasklet
142 uid - a unique identifier
143 """
144 super(ResMgrTasklet, self).__init__(name=name, uid=uid,
145 config_ready=config_ready,
146 recovery_action=recovery_action,
147 data_storetype=data_storetype,
148 )
149
150 plugin_directory = ClassProperty('./usr/lib/rift/plugins/rwresmgrtasklet')
151 plugin_name = ClassProperty('rwresmgrtasklet')
152
153
154 class ImageMgrTasklet(rift.vcs.core.Tasklet):
155 """
156 This class represents a Image Manager tasklet.
157 """
158
159 def __init__(self, name='Image-Manager', uid=None,
160 config_ready=True,
161 recovery_action=core.RecoveryType.FAILCRITICAL.value,
162 data_storetype=core.DataStore.NOSTORE.value,
163 ):
164 """
165 Creates a Image Manager Tasklet object.
166
167 Arguments:
168 name - the name of the tasklet
169 uid - a unique identifier
170 """
171 super(ImageMgrTasklet, self).__init__(
172 name=name, uid=uid,
173 config_ready=config_ready,
174 recovery_action=recovery_action,
175 data_storetype=data_storetype,
176 )
177
178 plugin_directory = ClassProperty('./usr/lib/rift/plugins/rwimagemgrtasklet')
179 plugin_name = ClassProperty('rwimagemgrtasklet')
180
181
182 class MonitorTasklet(rift.vcs.core.Tasklet):
183 """
184 This class represents a tasklet that is used to monitor NFVI metrics.
185 """
186
187 def __init__(self, name='nfvi-metrics-monitor', uid=None,
188 config_ready=True,
189 recovery_action=core.RecoveryType.FAILCRITICAL.value,
190 data_storetype=core.DataStore.NOSTORE.value,
191 ):
192 """
193 Creates a MonitorTasklet object.
194
195 Arguments:
196 name - the name of the tasklet
197 uid - a unique identifier
198
199 """
200 super(MonitorTasklet, self).__init__(name=name, uid=uid,
201 config_ready=config_ready,
202 recovery_action=recovery_action,
203 data_storetype=data_storetype,
204 )
205
206 plugin_directory = ClassProperty('./usr/lib/rift/plugins/rwmonitor')
207 plugin_name = ClassProperty('rwmonitor')
208
209 class RedisServer(rift.vcs.NativeProcess):
210 def __init__(self, name="RW.Redis.Server",
211 config_ready=True,
212 recovery_action=core.RecoveryType.FAILCRITICAL.value,
213 data_storetype=core.DataStore.NOSTORE.value,
214 ):
215 super(RedisServer, self).__init__(
216 name=name,
217 exe="/usr/bin/redis-server",
218 config_ready=config_ready,
219 recovery_action=recovery_action,
220 data_storetype=data_storetype,
221 )
222
223 @property
224 def args(self):
225 return "./usr/bin/active_redis.conf --port 9999"
226
227
228 class MonitoringParameterTasklet(rift.vcs.core.Tasklet):
229 """
230 This class represents a tasklet that is used to generate monitoring
231 parameters.
232 """
233
234 def __init__(self, name='Monitoring-Parameter', uid=None,
235 config_ready=True,
236 recovery_action=core.RecoveryType.FAILCRITICAL.value,
237 data_storetype=core.DataStore.NOSTORE.value,
238 ):
239 """
240 Creates a MonitoringParameterTasklet object.
241
242 Arguments:
243 name - the name of the tasklet
244 uid - a unique identifier
245
246 """
247 super(MonitoringParameterTasklet, self).__init__(name=name, uid=uid,
248 config_ready=config_ready,
249 recovery_action=recovery_action,
250 data_storetype=data_storetype,
251 )
252
253 plugin_directory = ClassProperty('./usr/lib/rift/plugins/rwmonparam')
254 plugin_name = ClassProperty('rwmonparam')
255
256
257 class AutoscalerTasklet(rift.vcs.core.Tasklet):
258 """
259 This class represents a tasklet that is used to generate monitoring
260 parameters.
261 """
262
263 def __init__(self, name='Autoscaler', uid=None,
264 config_ready=True,
265 recovery_action=core.RecoveryType.FAILCRITICAL.value,
266 data_storetype=core.DataStore.NOSTORE.value,
267 ):
268 """
269 Creates a MonitoringParameterTasklet object.
270
271 Arguments:
272 name - the name of the tasklet
273 uid - a unique identifier
274
275 """
276 super(AutoscalerTasklet, self).__init__(name=name, uid=uid,
277 config_ready=config_ready,
278 recovery_action=recovery_action,
279 data_storetype=data_storetype,
280 )
281
282 plugin_directory = ClassProperty('./usr/lib/rift/plugins/rwautoscaler')
283 plugin_name = ClassProperty('rwautoscaler')
284
285 class StagingManagerTasklet(rift.vcs.core.Tasklet):
286 """
287 A class that provide a simple staging area for all tasklets
288 """
289
290 def __init__(self, name='StagingManager', uid=None,
291 config_ready=True,
292 recovery_action=core.RecoveryType.FAILCRITICAL.value,
293 data_storetype=core.DataStore.NOSTORE.value,
294 ):
295 """
296 Creates a StagingMangerTasklet object.
297
298 Arguments:
299 name - the name of the tasklet
300 uid - a unique identifier
301
302 """
303 super(StagingManagerTasklet, self).__init__(name=name, uid=uid,
304 config_ready=config_ready,
305 recovery_action=recovery_action,
306 data_storetype=data_storetype,
307 )
308
309 plugin_directory = ClassProperty('./usr/lib/rift/plugins/rwstagingmgr')
310 plugin_name = ClassProperty('rwstagingmgr')
311
312 def get_ui_ssl_args():
313 """Returns the SSL parameter string for launchpad UI processes"""
314
315 try:
316 use_ssl, certfile_path, keyfile_path = certs.get_bootstrap_cert_and_key()
317 except certs.BootstrapSslMissingException:
318 logger.error('No bootstrap certificates found. Disabling UI SSL')
319 use_ssl = False
320
321 # If we're not using SSL, no SSL arguments are necessary
322 if not use_ssl:
323 return ""
324
325 return "--enable-https --keyfile-path=%s --certfile-path=%s" % (keyfile_path, certfile_path)
326
327
328 class UIServer(rift.vcs.NativeProcess):
329 def __init__(self, name="RW.MC.UI",
330 config_ready=True,
331 recovery_action=core.RecoveryType.FAILCRITICAL.value,
332 data_storetype=core.DataStore.NOSTORE.value,
333 ):
334 super(UIServer, self).__init__(
335 name=name,
336 exe="./usr/share/rw.ui/skyquake/scripts/launch_ui.sh",
337 config_ready=config_ready,
338 recovery_action=recovery_action,
339 data_storetype=data_storetype,
340 )
341
342 @property
343 def args(self):
344 return get_ui_ssl_args()
345
346 class ConfigManagerTasklet(rift.vcs.core.Tasklet):
347 """
348 This class represents a Resource Manager tasklet.
349 """
350
351 def __init__(self, name='Configuration-Manager', uid=None,
352 config_ready=True,
353 recovery_action=core.RecoveryType.FAILCRITICAL.value,
354 data_storetype=core.DataStore.NOSTORE.value,
355 ):
356 """
357 Creates a ConfigManagerTasklet object.
358
359 Arguments:
360 name - the name of the tasklet
361 uid - a unique identifier
362 """
363 super(ConfigManagerTasklet, self).__init__(name=name, uid=uid,
364 config_ready=config_ready,
365 recovery_action=recovery_action,
366 data_storetype=data_storetype,
367 )
368
369 plugin_directory = ClassProperty('./usr/lib/rift/plugins/rwconmantasklet')
370 plugin_name = ClassProperty('rwconmantasklet')
371
372 class PackageManagerTasklet(rift.vcs.core.Tasklet):
373 """
374 This class represents a Resource Manager tasklet.
375 """
376
377 def __init__(self, name='Package-Manager', uid=None,
378 config_ready=True,
379 recovery_action=core.RecoveryType.FAILCRITICAL.value,
380 data_storetype=core.DataStore.NOSTORE.value,
381 ):
382 """
383 Creates a PackageManager object.
384
385 Arguments:
386 name - the name of the tasklet
387 uid - a unique identifier
388 """
389 super(PackageManagerTasklet, self).__init__(name=name, uid=uid,
390 config_ready=config_ready,
391 recovery_action=recovery_action,
392 data_storetype=data_storetype,
393 )
394
395 plugin_directory = ClassProperty('./usr/lib/rift/plugins/rwpkgmgr')
396 plugin_name = ClassProperty('rwpkgmgr')
397
398 class GlanceServer(rift.vcs.NativeProcess):
399 def __init__(self, name="glance-image-catalog",
400 config_ready=True,
401 recovery_action=core.RecoveryType.FAILCRITICAL.value,
402 data_storetype=core.DataStore.NOSTORE.value,
403 ):
404 super(GlanceServer, self).__init__(
405 name=name,
406 exe="./usr/bin/glance_start_wrapper",
407 config_ready=config_ready,
408 recovery_action=recovery_action,
409 data_storetype=data_storetype,
410 )
411
412 @property
413 def args(self):
414 return "./etc/glance"
415
416
417 class Demo(rift.vcs.demo.Demo):
418 def __init__(self, no_ui=False, ha_mode=None, mgmt_ip_list=[], test_name=None):
419 procs = [
420 ConfigManagerTasklet(),
421 GlanceServer(),
422 rift.vcs.DtsRouterTasklet(),
423 rift.vcs.MsgBrokerTasklet(),
424 rift.vcs.RestPortForwardTasklet(),
425 rift.vcs.RestconfTasklet(),
426 rift.vcs.RiftCli(),
427 rift.vcs.uAgentTasklet(),
428 rift.vcs.Launchpad(),
429 ]
430
431 standby_procs = [
432 RedisServer(),
433 rift.vcs.DtsRouterTasklet(),
434 rift.vcs.MsgBrokerTasklet(),
435 ]
436
437 datastore = core.DataStore.BDB.value
438 if ha_mode:
439 procs.append(RedisServer())
440 datastore = core.DataStore.REDIS.value
441
442 if not no_ui:
443 procs.append(UIServer())
444
445 restart_procs = [
446 VnfmTasklet(recovery_action=core.RecoveryType.RESTART.value, data_storetype=datastore),
447 VnsTasklet(recovery_action=core.RecoveryType.RESTART.value, data_storetype=datastore),
448 # MonitorTasklet(recovery_action=core.RecoveryType.RESTART.value, data_storetype=datastore),
449 MonitoringParameterTasklet(recovery_action=core.RecoveryType.RESTART.value, data_storetype=datastore),
450 NsmTasklet(recovery_action=core.RecoveryType.RESTART.value, data_storetype=datastore),
451 ResMgrTasklet(recovery_action=core.RecoveryType.RESTART.value, data_storetype=datastore),
452 ImageMgrTasklet(recovery_action=core.RecoveryType.RESTART.value, data_storetype=datastore),
453 AutoscalerTasklet(recovery_action=core.RecoveryType.RESTART.value, data_storetype=datastore),
454 PackageManagerTasklet(recovery_action=core.RecoveryType.RESTART.value, data_storetype=datastore),
455 StagingManagerTasklet(recovery_action=core.RecoveryType.RESTART.value, data_storetype=datastore),
456 ]
457
458 if not mgmt_ip_list or len(mgmt_ip_list) == 0:
459 mgmt_ip_list.append("127.0.0.1")
460
461 colony = rift.vcs.core.Colony(name='top', uid=1)
462
463 lead_lp_vm = rift.vcs.VirtualMachine(
464 name='vm-launchpad-1',
465 ip=mgmt_ip_list[0],
466 procs=procs,
467 restart_procs=restart_procs,
468 )
469 lead_lp_vm.leader = True
470 colony.append(lead_lp_vm)
471
472 if ha_mode:
473 stby_lp_vm = rift.vcs.VirtualMachine(
474 name='launchpad-vm-2',
475 ip=mgmt_ip_list[1],
476 procs=standby_procs,
477 start=False,
478 )
479 # WA to Agent mode_active flag reset
480 stby_lp_vm.add_tasklet(rift.vcs.uAgentTasklet(), mode_active=False)
481 colony.append(stby_lp_vm)
482
483 sysinfo = rift.vcs.SystemInfo(
484 mode='ethsim',
485 zookeeper=rift.vcs.manifest.RaZookeeper(master_ip=mgmt_ip_list[0]),
486 colonies=[colony],
487 multi_broker=True,
488 multi_dtsrouter=True,
489 mgmt_ip_list=mgmt_ip_list,
490 test_name=test_name,
491 )
492
493 super(Demo, self).__init__(
494 # Construct the system. This system consists of 1 cluster in 1
495 # colony. The master cluster houses CLI and management VMs
496 sysinfo = sysinfo,
497
498 # Define the generic portmap.
499 port_map = {},
500
501 # Define a mapping from the placeholder logical names to the real
502 # port names for each of the different modes supported by this demo.
503 port_names = {
504 'ethsim': {
505 },
506 'pci': {
507 }
508 },
509
510 # Define the connectivity between logical port names.
511 port_groups = {},
512 )
513
514
515 def main(argv=sys.argv[1:]):
516 logging.basicConfig(format='%(asctime)-15s %(levelname)s %(message)s')
517
518 # Create a parser which includes all generic demo arguments
519 parser = rift.vcs.demo.DemoArgParser()
520 parser.add_argument("--no-ui", action='store_true')
521 args = parser.parse_args(argv)
522
523 # Disable loading any kernel modules for the launchpad VM
524 # since it doesn't need it and it will fail within containers
525 os.environ["NO_KERNEL_MODS"] = "1"
526
527 cleanup_dir_name = None
528 if os.environ["INSTALLDIR"] in ["/", "/home/rift", "/home/rift/.install",
529 "/usr/rift/build/fc20_debug/install/usr/rift", "/usr/rift"]:
530 cleanup_dir_name = os.environ["INSTALLDIR"] + "/var/rift/"
531
532 if args.test_name and not cleanup_dir_name:
533 cleanup_dir_name = "find {rift_install}/var/rift -name '*{pattern}*' -type d".format( \
534 rift_install=os.environ['RIFT_INSTALL'],
535 pattern = args.test_name)
536 try:
537 cleanup_dir_name = subprocess.check_output(cleanup_dir_name, shell=True)
538 cleanup_dir_name = cleanup_dir_name[:-1].decode("utf-8") + "/"
539 except Exception as e:
540 print ("Directory not found exception occurred. Probably running for first time")
541 print ("Zookeper cleanup cmd = {}".format(cleanup_dir_name))
542 else:
543 if not cleanup_dir_name:
544 cleanup_dir_name = os.environ["INSTALLDIR"] + "/"
545
546 # Remove the persistent Redis data
547 try:
548 for f in os.listdir(cleanup_dir_name):
549 if f.endswith(".aof") or f.endswith(".rdb"):
550 os.remove(os.path.join(cleanup_dir_name, f))
551
552 # Remove the persistant DTS recovery files
553 for f in os.listdir(cleanup_dir_name):
554 if f.endswith(".db"):
555 os.remove(os.path.join(cleanup_dir_name, f))
556
557 shutil.rmtree(os.path.join(cleanup_dir_name, "zk/server-1"))
558 shutil.rmtree(os.path.join(os.environ["INSTALLDIR"], "var/rift/tmp*"))
559 except FileNotFoundError as e:
560 pass
561 except Exception as e:
562 print ("Error while cleanup: {}".format(str(e)))
563
564 ha_mode = args.ha_mode
565 mgmt_ip_list = [] if not args.mgmt_ip_list else args.mgmt_ip_list
566
567 #load demo info and create Demo object
568 demo = Demo(args.no_ui, ha_mode, mgmt_ip_list, args.test_name)
569
570 # Create the prepared system from the demo
571 system = rift.vcs.demo.prepared_system_from_demo_and_args(demo, args,
572 northbound_listing="cli_launchpad_schema_listing.txt",
573 netconf_trace_override=True)
574
575 confd_ip = socket.gethostbyname(socket.gethostname())
576 # TODO: This need to be changed when launchpad starts running on multiple VMs
577 rift.vcs.logger.configure_sink(config_file=None, confd_ip="127.0.0.1")
578
579 # Start the prepared system
580 system.start()
581
582
583 if __name__ == "__main__":
584 resource.setrlimit(resource.RLIMIT_CORE, (resource.RLIM_INFINITY, resource.RLIM_INFINITY) )
585 try:
586 main()
587 except rift.vcs.demo.ReservationError:
588 print("ERROR: unable to retrieve a list of IP addresses from the reservation system")
589 sys.exit(1)
590 except rift.vcs.demo.MissingModeError:
591 print("ERROR: you need to provide a mode to run the script")
592 sys.exit(1)
593 finally:
594 os.system("stty sane")