def start_routing_protocol(protocol, rmap, ids, ignore_error=False): beg_count = count_instances(protocol, rmap) beg_ms = millis() for id in ids: remote = rmap[id] interface_up(remote, id, 'uplink', ignore_error) if protocol == 'babel': start_babel_instances(ids, rmap) elif protocol == 'batman-adv': start_batmanadv_instances(ids, rmap) elif protocol == 'bmx6': start_bmx6_instances(ids, rmap) elif protocol == 'cjdns': start_cjdns_instances(ids, rmap) elif protocol == 'olsr1': start_olsr1_instances(ids, rmap) elif protocol == 'olsr2': start_olsr2_instances(ids, rmap) elif protocol == 'ospf': start_ospf_instances(ids, rmap) elif protocol == 'yggdrasil': start_yggdrasil_instances(ids, rmap) elif protocol == 'none': return else: eprint(f'Error: unknown routing protocol: {protocol}') exit(1) wait_for_completion() # wait for last started process to fork # otherwise we might have one extra counted instance time.sleep(0.5) end_ms = millis() end_count = count_instances(protocol, rmap) count = end_count - beg_count if count != len(ids): eprint( f'Error: Failed to start {protocol} instances: {count}/{len(ids)} started' ) stop_all_terminals() exit(1) if verbosity != 'quiet': print('Started {} {} instances in {}'.format( count, protocol, format_duration(end_ms - beg_ms)))
def stop_routing_protocol(protocol, rmap, ids, ignore_error=False): beg_count = count_instances(protocol, rmap) beg_ms = millis() if protocol == 'babel': stop_babel_instances(ids, rmap) elif protocol == 'batman-adv': stop_batmanadv_instances(ids, rmap) elif protocol == 'bmx6': stop_bmx6_instances(ids, rmap) elif protocol == 'cjdns': stop_cjdns_instances(ids, rmap) elif protocol == 'olsr1': stop_olsr1_instances(ids, rmap) elif protocol == 'olsr2': stop_olsr2_instances(ids, rmap) elif protocol == 'ospf': stop_ospf_instances(ids, rmap) elif protocol == 'yggdrasil': stop_yggdrasil_instances(ids, rmap) elif protocol == 'none': pass else: eprint('Error: unknown routing protocol: {}'.format(protocol)) exit(1) for id in ids: remote = rmap[id] interface_down(remote, id, 'uplink', ignore_error=ignore_error) wait_for_completion() # wait for last stopped process to disappear # otherwise we might have one extra counted instance time.sleep(0.5) end_ms = millis() end_count = count_instances(protocol, rmap) count = beg_count - end_count if count != len(ids): eprint( f'Error: Failed to stop {protocol} instances: {count}/{len(ids)} left' ) exit(1) if not ignore_error and verbosity != 'quiet': print('Stopped {} {} instances in {}'.format( len(ids), protocol, format_duration(end_ms - beg_ms)))
def apply(state={}, node_command=None, link_command=None, remotes=default_remotes): check_access(remotes) new_state = state (cur_state, cur_state_rmap) = get_current_state(remotes) # handle different new_state types if isinstance(new_state, str): if new_state == 'none': new_state = {} else: if not os.path.isfile(new_state): eprint(f'File not found: {new_state}') stop_all_terminals() exit(1) with open(new_state) as file: new_state = json.load(file) # map each node to a remote or local computer # distribute evenly with minimized interconnects rmap = _get_remote_mapping(cur_state, new_state, remotes, cur_state_rmap) data = _get_task(cur_state, new_state) beg_ms = millis() # add "switch" namespace if state_empty(cur_state): for remote in remotes: # add switch if it does not exist yet exec(remote, 'ip netns add "switch" || true') # disable IPv6 in switch namespace (no need, less overhead) exec( remote, 'ip netns exec "switch" sysctl -q -w net.ipv6.conf.all.disable_ipv6=1' ) for node in data.nodes_update: update_node(node, node_command, rmap) for link in data.links_update: update_link(link, link_command, rmap) for node in data.nodes_create: create_node(node, node_command, rmap) for link in data.links_create: create_link(link, link_command, rmap) for link in data.links_remove: remove_link(link, rmap) for node in data.nodes_remove: remove_node(node, rmap) # remove "switch" namespace if state_empty(new_state): for remote in remotes: exec(remote, 'ip netns del "switch" || true') # wait for tasks to complete wait_for_completion() end_ms = millis() if verbosity != 'quiet': print('Network setup in {}:'.format(format_duration(end_ms - beg_ms))) print( f' nodes: {len(data.nodes_create)} created, {len(data.nodes_remove)} removed, {len(data.nodes_update)} updated' ) print( f' links: {len(data.links_create)} created, {len(data.links_remove)} removed, {len(data.links_update)} updated' ) return new_state
def main(): parser = argparse.ArgumentParser() parser.add_argument('--verbosity', choices=['verbose', 'normal', 'quiet'], default='normal', help='Set verbosity.') parser.add_argument( '--remotes', help='Distribute nodes and links on remotes described in the JSON file.' ) parser.set_defaults(to_state=None) subparsers = parser.add_subparsers(dest='action', required=True, help='Action') parser_start = subparsers.add_parser( 'start', help='Run start script in every namespace.') parser_start.add_argument('protocol', help='Routing protocol script prefix.') parser_start.add_argument('to_state', nargs='?', default=None, help='To state') parser_stop = subparsers.add_parser( 'stop', help='Run stop script in every namespace.') parser_stop.add_argument('protocol', help='Routing protocol script prefix.') parser_stop.add_argument('to_state', nargs='?', default=None, help='To state') parser_change = subparsers.add_parser( 'apply', help='Run stop/start scripts in every namespace.') parser_change.add_argument('protocol', help='Routing protocol script prefix.') parser_change.add_argument('to_state', nargs='?', default=None, help='To state') parser_run = subparsers.add_parser( 'run', help='Execute any command in every namespace.') parser_run.add_argument( 'command', nargs=argparse.REMAINDER, help= 'Shell command that is run. Remote address and namespace id is added to call arguments.' ) parser_run.add_argument('to_state', nargs='?', default=None, help='To state') parser_copy = subparsers.add_parser('copy', help='Copy to all remotes.') parser_copy.add_argument('source', nargs='+') parser_copy.add_argument('destination') parser_clear = subparsers.add_parser( 'clear', help='Run all stop scripts in every namespaces.') args = parser.parse_args() if args.remotes: if not os.path.isfile(args.remotes): eprint(f'File not found: {args.remotes}') stop_all_terminals() exit(1) with open(args.remotes) as file: args.remotes = [Remote.from_json(obj) for obj in json.load(file)] else: args.remotes = default_remotes check_access(args.remotes) global verbosity verbosity = args.verbosity # get nodes that have been added or will be removed (old_ids, new_ids, rmap) = _get_update(args.to_state, args.remotes) if args.action == 'start': ids = new_ids if args.to_state else list(rmap.keys()) beg_ms = millis() _start_protocol(args.protocol, rmap, ids) end_ms = millis() if verbosity != 'quiet': print('started {} in {} namespaces in {}'.format( args.protocol, len(ids), format_duration(end_ms - beg_ms))) elif args.action == 'stop': ids = old_ids if args.to_state else list(rmap.keys()) beg_ms = millis() _stop_protocol(args.protocol, rmap, ids) end_ms = millis() if verbosity != 'quiet': print('stopped {} in {} namespaces in {}'.format( args.protocol, len(ids), format_duration(end_ms - beg_ms))) elif args.action == 'apply': beg_ms = millis() _stop_protocol(args.protocol, rmap, old_ids) _start_protocol(args.protocol, rmap, new_ids) end_ms = millis() if verbosity != 'quiet': print('applied {} in {} namespaces in {}'.format( args.protocol, len(rmap.keys()), format_duration(end_ms - beg_ms))) elif args.action == 'clear': beg_ms = millis() clear(args.remotes) end_ms = millis() if verbosity != 'quiet': print('cleared on {} remotes in {}'.format( len(args.remotes), format_duration(end_ms - beg_ms))) elif args.action == 'copy': beg_ms = millis() copy(args.remotes, args.source, args.destination) end_ms = millis() if verbosity != 'quiet': print('copied on {} remotes in {}'.format( len(args.remotes), format_duration(end_ms - beg_ms))) elif args.action == 'run': ids = new_ids if args.to_state else list(rmap.keys()) for id in ids: remote = rmap[id] label = remote.address or 'local' cmd = f'ip netns exec ns-{id} {" ".join(args.command)} {label} {id}' _exec_verbose(remote, cmd) else: eprint('Unknown action: {}'.format(args.action)) stop_all_terminals() exit(1) stop_all_terminals()