Fix SO restart without test-name
[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
286 def get_ui_ssl_args():
287 """Returns the SSL parameter string for launchpad UI processes"""
288
289 try:
290 use_ssl, certfile_path, keyfile_path = certs.get_bootstrap_cert_and_key()
291 except certs.BootstrapSslMissingException:
292 logger.error('No bootstrap certificates found. Disabling UI SSL')
293 use_ssl = False
294
295 # If we're not using SSL, no SSL arguments are necessary
296 if not use_ssl:
297 return ""
298
299 return "--enable-https --keyfile-path=%s --certfile-path=%s" % (keyfile_path, certfile_path)
300
301
302 class UIServer(rift.vcs.NativeProcess):
303 def __init__(self, name="RW.MC.UI",
304 config_ready=True,
305 recovery_action=core.RecoveryType.FAILCRITICAL.value,
306 data_storetype=core.DataStore.NOSTORE.value,
307 ):
308 super(UIServer, self).__init__(
309 name=name,
310 exe="./usr/share/rw.ui/skyquake/scripts/launch_ui.sh",
311 config_ready=config_ready,
312 recovery_action=recovery_action,
313 data_storetype=data_storetype,
314 )
315
316 @property
317 def args(self):
318 return get_ui_ssl_args()
319
320 class ConfigManagerTasklet(rift.vcs.core.Tasklet):
321 """
322 This class represents a Resource Manager tasklet.
323 """
324
325 def __init__(self, name='Configuration-Manager', uid=None,
326 config_ready=True,
327 recovery_action=core.RecoveryType.FAILCRITICAL.value,
328 data_storetype=core.DataStore.NOSTORE.value,
329 ):
330 """
331 Creates a ConfigManagerTasklet object.
332
333 Arguments:
334 name - the name of the tasklet
335 uid - a unique identifier
336 """
337 super(ConfigManagerTasklet, self).__init__(name=name, uid=uid,
338 config_ready=config_ready,
339 recovery_action=recovery_action,
340 data_storetype=data_storetype,
341 )
342
343 plugin_directory = ClassProperty('./usr/lib/rift/plugins/rwconmantasklet')
344 plugin_name = ClassProperty('rwconmantasklet')
345
346 class GlanceServer(rift.vcs.NativeProcess):
347 def __init__(self, name="glance-image-catalog",
348 config_ready=True,
349 recovery_action=core.RecoveryType.FAILCRITICAL.value,
350 data_storetype=core.DataStore.NOSTORE.value,
351 ):
352 super(GlanceServer, self).__init__(
353 name=name,
354 exe="./usr/bin/glance_start_wrapper",
355 config_ready=config_ready,
356 recovery_action=recovery_action,
357 data_storetype=data_storetype,
358 )
359
360 @property
361 def args(self):
362 return "./etc/glance"
363
364
365 class Demo(rift.vcs.demo.Demo):
366 def __init__(self, no_ui=False, ha_mode=None, mgmt_ip_list=[], test_name=None):
367 procs = [
368 ConfigManagerTasklet(),
369 GlanceServer(),
370 rift.vcs.DtsRouterTasklet(),
371 rift.vcs.MsgBrokerTasklet(),
372 rift.vcs.RestPortForwardTasklet(),
373 rift.vcs.RestconfTasklet(),
374 rift.vcs.RiftCli(),
375 rift.vcs.uAgentTasklet(),
376 rift.vcs.Launchpad(),
377 ]
378
379 standby_procs = [
380 RedisServer(),
381 rift.vcs.DtsRouterTasklet(),
382 rift.vcs.MsgBrokerTasklet(),
383 ]
384
385 datastore = core.DataStore.BDB.value
386 if ha_mode:
387 procs.append(RedisServer())
388 datastore = core.DataStore.REDIS.value
389
390 if not no_ui:
391 procs.append(UIServer())
392
393 restart_procs = [
394 VnfmTasklet(recovery_action=core.RecoveryType.RESTART.value, data_storetype=datastore),
395 VnsTasklet(recovery_action=core.RecoveryType.RESTART.value, data_storetype=datastore),
396 MonitorTasklet(recovery_action=core.RecoveryType.RESTART.value, data_storetype=datastore),
397 MonitoringParameterTasklet(recovery_action=core.RecoveryType.RESTART.value, data_storetype=datastore),
398 NsmTasklet(recovery_action=core.RecoveryType.RESTART.value, data_storetype=datastore),
399 ResMgrTasklet(recovery_action=core.RecoveryType.RESTART.value, data_storetype=datastore),
400 ImageMgrTasklet(recovery_action=core.RecoveryType.RESTART.value, data_storetype=datastore),
401 AutoscalerTasklet(recovery_action=core.RecoveryType.RESTART.value, data_storetype=datastore),
402 ]
403
404 if not mgmt_ip_list or len(mgmt_ip_list) == 0:
405 mgmt_ip_list.append("127.0.0.1")
406
407 colony = rift.vcs.core.Colony(name='top', uid=1)
408
409 lead_lp_vm = rift.vcs.VirtualMachine(
410 name='vm-launchpad-1',
411 ip=mgmt_ip_list[0],
412 procs=procs,
413 restart_procs=restart_procs,
414 )
415 lead_lp_vm.leader = True
416 colony.append(lead_lp_vm)
417
418 if ha_mode:
419 stby_lp_vm = rift.vcs.VirtualMachine(
420 name='launchpad-vm-2',
421 ip=mgmt_ip_list[1],
422 procs=standby_procs,
423 start=False,
424 )
425 # WA to Agent mode_active flag reset
426 stby_lp_vm.add_tasklet(rift.vcs.uAgentTasklet(), mode_active=False)
427 colony.append(stby_lp_vm)
428
429 sysinfo = rift.vcs.SystemInfo(
430 mode='ethsim',
431 zookeeper=rift.vcs.manifest.RaZookeeper(master_ip=mgmt_ip_list[0]),
432 colonies=[colony],
433 multi_broker=True,
434 multi_dtsrouter=True,
435 mgmt_ip_list=mgmt_ip_list,
436 test_name=test_name,
437 )
438
439 super(Demo, self).__init__(
440 # Construct the system. This system consists of 1 cluster in 1
441 # colony. The master cluster houses CLI and management VMs
442 sysinfo = sysinfo,
443
444 # Define the generic portmap.
445 port_map = {},
446
447 # Define a mapping from the placeholder logical names to the real
448 # port names for each of the different modes supported by this demo.
449 port_names = {
450 'ethsim': {
451 },
452 'pci': {
453 }
454 },
455
456 # Define the connectivity between logical port names.
457 port_groups = {},
458 )
459
460
461 def main(argv=sys.argv[1:]):
462 logging.basicConfig(format='%(asctime)-15s %(levelname)s %(message)s')
463
464 # Create a parser which includes all generic demo arguments
465 parser = rift.vcs.demo.DemoArgParser()
466 parser.add_argument("--no-ui", action='store_true')
467 args = parser.parse_args(argv)
468
469 # Disable loading any kernel modules for the launchpad VM
470 # since it doesn't need it and it will fail within containers
471 os.environ["NO_KERNEL_MODS"] = "1"
472
473
474 cleanup_dir_name = None
475 if os.environ["INSTALLDIR"] in ["/", "/home/rift", "/home/rift/.install",
476 "/usr/rift/build/fc20_debug/install/usr/rift", "/usr/rift"]:
477 cleanup_dir_name = os.environ["INSTALLDIR"] + "/var/rift/"
478
479 if args.test_name and not cleanup_dir_name:
480 cleanup_dir_name = "find {rift_install}/var/rift -name '*{pattern}*' -type d".format( \
481 rift_install=os.environ['RIFT_INSTALL'],
482 pattern = args.test_name)
483 try:
484 cleanup_dir_name = subprocess.check_output(cleanup_dir_name, shell=True)
485 cleanup_dir_name = cleanup_dir_name[:-1].decode("utf-8") + "/"
486 except Exception as e:
487 print ("Directory not found exception occurred. Probably running for first time")
488 print ("Zookeper cleanup cmd = {}".format(cleanup_dir_name))
489 else:
490 if not cleanup_dir_name:
491 cleanup_dir_name = os.environ["INSTALLDIR"] + "/"
492
493 # Remove the persistent Redis data
494 try:
495 for f in os.listdir(cleanup_dir_name):
496 if f.endswith(".aof") or f.endswith(".rdb"):
497 os.remove(os.path.join(cleanup_dir_name, f))
498
499 # Remove the persistant DTS recovery files
500 for f in os.listdir(cleanup_dir_name):
501 if f.endswith(".db"):
502 os.remove(os.path.join(cleanup_dir_name, f))
503
504 shutil.rmtree(os.path.join(cleanup_dir_name, "zk/server-1"))
505 shutil.rmtree(os.path.join(os.environ["INSTALLDIR"], "var/rift/tmp*"))
506 except FileNotFoundError as e:
507 pass
508 except Exception as e:
509 print ("Error while cleanup: {}".format(str(e)))
510
511 ha_mode = args.ha_mode
512 mgmt_ip_list = [] if not args.mgmt_ip_list else args.mgmt_ip_list
513
514 #load demo info and create Demo object
515 demo = Demo(args.no_ui, ha_mode, mgmt_ip_list, args.test_name)
516
517 # Create the prepared system from the demo
518 system = rift.vcs.demo.prepared_system_from_demo_and_args(demo, args,
519 northbound_listing="cli_launchpad_schema_listing.txt",
520 netconf_trace_override=True)
521
522 confd_ip = socket.gethostbyname(socket.gethostname())
523 intf = netifaces.ifaddresses('eth0')
524 if intf and netifaces.AF_INET in intf and len(intf[netifaces.AF_INET]):
525 confd_ip = intf[netifaces.AF_INET][0]['addr']
526 rift.vcs.logger.configure_sink(config_file=None, confd_ip=confd_ip)
527
528 # Start the prepared system
529 system.start()
530
531
532 if __name__ == "__main__":
533 resource.setrlimit(resource.RLIMIT_CORE, (resource.RLIM_INFINITY, resource.RLIM_INFINITY) )
534 try:
535 main()
536 except rift.vcs.demo.ReservationError:
537 print("ERROR: unable to retrieve a list of IP addresses from the reservation system")
538 sys.exit(1)
539 except rift.vcs.demo.MissingModeError:
540 print("ERROR: you need to provide a mode to run the script")
541 sys.exit(1)
542 finally:
543 os.system("stty sane")