Esempio n. 1
0
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)))
Esempio n. 2
0
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)))
Esempio n. 3
0
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
Esempio n. 4
0
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()