#!/usr/bin/env python import argparse import re import rumba.model as mod import rumba.log as log def make_experiment(filename, experiment_class, experiment_kwargs, testbed_class, testbed_kwargs, verbosity): """ :type filename str :param filename: path to the .conf file :param experiment_class: subclass of mod.Experiment :param experiment_kwargs: args dict for experiment constructor (nodes will be overwritten) :param testbed_class: subclass of mod.Testbed :param testbed_kwargs: args dict for experiment constructor (nodes will be overwritten) """ shims = {} nodes = {} difs = {} print('Reading file %s.' % (filename,)) print('+++++++++++++++++++') print() with open(filename, 'r') as conf: line_cnt = 0 while 1: line = conf.readline() if line == '': break line_cnt += 1 line = line.replace('\n', '').strip() if line.startswith('#') or line == "": continue m = re.match(r'\s*eth\s+([\w-]+)\s+(\d+)([GMK])bps\s+(\w.*)$', line) if m: shim = m.group(1) speed = int(m.group(2)) speed_unit = m.group(3).lower() vm_list = m.group(4).split() if shim in shims or shim in difs: print('Error: Line %d: shim %s already defined' % (line_cnt, shim)) continue if speed_unit == 'K': speed = speed // 1000 if speed_unit == 'G': speed = speed * 1000 shims[shim] = {'name': shim, 'speed': speed, 'type': 'eth'} for vm in vm_list: nodes.setdefault(vm, {'name': vm, 'difs': [], 'dif_registrations': {}, 'registrations': {}}) nodes[vm]['difs'].append(shim) continue m = re.match(r'\s*dif\s+([\w-]+)\s+([\w-]+)\s+(\w.*)$', line) if m: dif = m.group(1) vm = m.group(2) dif_list = m.group(3).split() if dif in shims: print('Error: Line %d: dif %s already defined as shim' % (line_cnt, dif)) continue difs.setdefault(dif, { 'name': dif}) # Other dict contents might be policies. if vm in nodes and dif in nodes[vm]['dif_registrations']: print('Error: Line %d: vm %s in dif %s already specified' % (line_cnt, vm, dif)) continue nodes.setdefault(vm, {'name': vm, 'difs': [], 'dif_registrations': {}, 'registrations': {}}) nodes[vm]['difs'].append(dif) nodes[vm]['dif_registrations'][dif] = dif_list # It is not defined yet, per check above. continue # No match, spit a warning print('Warning: Line %d unrecognized and ignored' % line_cnt) # File parsed parsed_difs = {} for shim_name, shim in shims.items(): parsed_difs[shim_name] = (mod.ShimEthDIF( shim_name, link_quality=mod.LinkQuality(rate=shim['speed'])) ) for dif_name, dif in difs.items(): parsed_difs[dif_name] = (mod.NormalDIF(dif_name)) parsed_nodes = [] for node, node_data in nodes.items(): name = node_data['name'] difs = [parsed_difs[x] for x in node_data['difs']] dif_registrations = {parsed_difs[x]: [parsed_difs[y] for y in l] for x, l in node_data['dif_registrations'] .items()} parsed_nodes.append(mod.Node(name, difs, dif_registrations)) log.set_logging_level(verbosity) print() print('++++++++++++++++++++') print('Calling constructor of testbed %s with args %s.' % (testbed_class, testbed_kwargs)) print('++++++++++++++++++++') print() testbed = testbed_class(**testbed_kwargs) experiment_kwargs['testbed'] = testbed experiment_kwargs['nodes'] = parsed_nodes exp = experiment_class(**experiment_kwargs) try: exp.swap_in() exp.bootstrap_prototype() input("Press ENTER to quit") finally: exp.swap_out() def setup_testbed_common_args(t_p): t_p.add_argument('-E', '--exp_name', metavar='EXP_NAME', type=str, required=True, help='Experiment name') t_p.add_argument('-U', '--username', metavar='USERNAME', type=str, required=True, help='Testbed user name') t_p.add_argument('-P', '--proj_name', metavar='PROJECT_NAME', type=str, help='Project name') t_p.add_argument('-W', '--password', metavar='PASSWORD', type=str, help='Testbed password') if __name__ == '__main__': description = "Demonstrator config file to rumba script converter" epilog = "2017 Marco Capitani " parser = argparse.ArgumentParser(description=description, epilog=epilog) parser.add_argument('-P', '--prototype', type=str, required=True, choices=['irati', 'ouroboros', 'rlite'], help='The kind of prototype plugin to use to run' ' the experiment.') parser.add_argument('-C', '--conf', metavar='CONFIG', type=str, required=True, help='Path to the config file to parse') parser.add_argument( '--verbosity', metavar='VERBOSITY', type=str, default='INFO', choices=['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'], help='Rumba output verbosity') subparsers = parser.add_subparsers(dest='testbed') emulab_p = subparsers.add_parser('emulab', help='Use emulab testbed') jfed_p = subparsers.add_parser('jfed', help='Use jfed testbed') qemu_p = subparsers.add_parser('qemu', help='Use qemu testbed') fake_p = subparsers.add_parser('fake', help='Use fake testbed') for t in [emulab_p, jfed_p, qemu_p, fake_p]: setup_testbed_common_args(t) qemu_p.add_argument('-B', '--bzimage-path', metavar='BZIMAGE', type=str, required=True, help='path to the bzImage file to use') qemu_p.add_argument('-I', '--initramfs-path', metavar='INITRAMFS', type=str, required=True, help='path to the initramfs file to use') qemu_p.add_argument('-V', '--use_vhost', action='store_true', default=False, help='Use vhost') qemu_p.add_argument('-Q', '--qemu_logs_dir', metavar='QEMU_LOGS', type=str, default=None, help='path to the folder for qemu logs') qemu_p.add_argument('--public-key-path', metavar='PATH', type=str, default=None, help='path to the user ssh public key.') emulab_p.add_argument('-R', '--url', metavar='URL', type=str, default="wall2.ilabt.iminds.be", help='Url') emulab_p.add_argument('-I', '--image', metavar='IMG', type=str, default="UBUNTU14-64-STD", help='Ubuntu image') jfed_p.add_argument('-C', '--cert_file', metavar='CERT', type=str, required=True, help='Certificate file') jfed_p.add_argument('-H', '--exp_hours', metavar='HOURS', type=str, default="2", help='Experiment hours') jfed_p.add_argument('-A', '--authority', metavar='AUTH', type=str, default="wall2.ilabt.iminds.be", help='Authority') jfed_p.add_argument('-I', '--image', metavar='IMAGE', type=str, default=None, help='Image to be used') jfed_p.add_argument('--image-custom', metavar='I_CUSTOM', type=bool, default=False, help='Is the image a custom one?') jfed_p.add_argument('--image-owner', metavar='I_OWNER', type=str, default=None, help='Creator of the image') jfed_p.add_argument('--use-physical-machines', metavar='USE_PM', type=bool, default=None, help='Try to allocate physical machines if True') args = parser.parse_args() if args.testbed == 'emulab': import rumba.testbeds.emulab as emulab test_class = emulab.Testbed testbed_args = {a.dest: getattr(args, a.dest) for a in emulab_p._actions if a.dest != 'help' and getattr(args, a.dest) is not None} elif args.testbed == 'jfed': import rumba.testbeds.jfed as jfed test_class = jfed.Testbed testbed_args = {a.dest: getattr(args, a.dest) for a in jfed_p._actions if a.dest != 'help' and getattr(args, a.dest) is not None} elif args.testbed == 'qemu': import rumba.testbeds.qemu as qemu test_class = qemu.Testbed testbed_args = {a.dest: getattr(args, a.dest) for a in qemu_p._actions if a.dest != 'help' and getattr(args, a.dest) is not None} elif args.testbed == 'local': import rumba.testbeds.local as local test_class = local.Testbed testbed_args = {a.dest: getattr(args, a.dest) for a in fake_p._actions if a.dest != 'help' and getattr(args, a.dest) is not None} else: if args.testbed is None: print('Testbed type must be specified!') print(parser.format_help()) exit(1) raise ValueError('Unexpected testbed: %s.' % args.testbed) if args.prototype == 'irati': import rumba.prototypes.irati as irati exp_class = irati.Experiment elif args.prototype == 'ouroboros': import rumba.prototypes.ouroboros as ouroboros exp_class = ouroboros.Experiment elif args.prototype == 'rlite': import rumba.prototypes.rlite as rlite exp_class = rlite.Experiment else: raise ValueError('Unexpected prototype: %s.' % args.testbed) try: make_experiment(args.conf, experiment_class=exp_class, experiment_kwargs={}, testbed_class=test_class, testbed_kwargs=testbed_args, verbosity=args.verbosity) except KeyboardInterrupt: print("Interrupted. Closing down.")