orchestrator.py 5.34 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
#!/usr/bin/env python3

# Copyright (C) 2018 Simon Redman <sredman@cs.utah.edu>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# For future reference, here is the OSPFv6 RFC: https://tools.ietf.org/html/rfc2740.html

import add_routable_ipv6_addrs
import frr_configurator
22
import json
23
import ospf_sniffer_configurator
24
import ssh_helper
25
import sysctl_configurator
26 27 28 29 30
import topomap_parser

import argparse
import getpass
from netdiff import NetJsonParser
31
import re
32 33 34 35 36 37 38

if __name__ == "__main__":
    parser = argparse.ArgumentParser("Setup an Emulab experiment for Segment Routing")
    parser.add_argument("--topomap-file", action='store', default='/var/emulab/boot/topomap', type=str,
                        help="Path to the emulab topomap file to parse")
    parser.add_argument("--netgraph-file", action='store', type=str, required=False,
                        help="Path to the NetJSON file to parse. Skips parsing the netgrap from the topomap-file")
39 40
    parser.add_argument("--netgraph-write", action='store', type=str, required=False,
                        help="(Optional) Path to write the final NetJSON file")
41 42
    parser.add_argument("--username", action='store', type=str, default=getpass.getuser(),
                        help="Username to use on all hosts. Defaults to current user's username")
43 44 45 46
    parser.add_argument("--no-frr", action='store_true',
                        help="Do not start the FRR daemons")
    parser.add_argument("--no-sniffer", action='store_true',
                        help="Do not start the OSPF sniffer daemons")
47 48 49 50
    parser.add_argument("--controller-name", action='store', type=str, default=ospf_sniffer_configurator.DEFAULT_CONTROLLER,
                        help="Hostname or IP of the node which is listening to the OSPF reports (Default: {default})".format(default=ospf_sniffer_configurator.DEFAULT_CONTROLLER))
    parser.add_argument("--controller-port", action='store', type=int, default=ospf_sniffer_configurator.DEFAULT_CONTROLLER_PORT,
                        help="Port number on the server listening for OSPF reports (Default: {default})".format(default=ospf_sniffer_configurator.DEFAULT_CONTROLLER_PORT))
51 52 53 54
    parser.add_argument("--ovs-regex", action='store', type=str, default='^ovs.*',
                        help="Regex to distinguish OVS nodes by label (Default \"^ovs.*\")")
    parser.add_argument("--host-regex", action='store', type=str, default='^host.*',
                        help="Regex to distinguish host nodes by label (Default \"^host.*\")")
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72

    args = parser.parse_args()

    if not args.netgraph_file:
        netgraph = NetJsonParser(data=topomap_parser.parse_topomap_to_netjson(args.topomap_file))
    else:
        netgraph = NetJsonParser(file=args.netgraph_file)

    ssh_helper.network_graph_login(netgraph.graph, args.username)

    # Skip adding ipv6 addresses to the management interfaces
    management_ips = [node["management-ip"] for node in netgraph.graph._node.values()]

    ULA_map = add_routable_ipv6_addrs.construct_ULAs(netgraph.graph, ignore_addrs=management_ips)

    add_routable_ipv6_addrs.add_ULAs_to_hosts(netgraph.graph, ULA_map)
    add_routable_ipv6_addrs.add_interfaces_to_netgraph(netgraph.graph, ULA_map)

73
    # Prepare a list of nodes which run OVS and should thus be ignore for router-related activites
74 75 76
    ovs_nodes = []
    for node in netgraph.graph.nodes:
        node_name = netgraph.graph._node[node]['label']
77
        if re.match(args.ovs_regex, node_name):
78
            ovs_nodes.append(node)
79

80
    # Prepare a list of nodes which are "customer host nodes" and should thus be ignored for core network-related activities
81 82 83 84 85 86
    host_nodes = []
    for node in netgraph.graph.nodes:
        node_name = netgraph.graph._node[node]['label']
        if re.match(args.host_regex, node_name):
            host_nodes.append(node)

87
    frr_configurator.configure_nodes(netgraph.graph, ignore_nodes=ovs_nodes)
88
    sysctl_configurator.configure_nodes(netgraph.graph,ignore_nodes=ovs_nodes)
89

90
    ospf_sniffer_configurator.clone_repo_on_network(netgraph.graph, ignore_nodes=ovs_nodes + host_nodes)
91
    ospf_sniffer_configurator.stop_sniffer_on_network(netgraph.graph, ignore_nodes=ovs_nodes + host_nodes)  # Stopping with the app not running is not great, but better than starting twice
Simon Redman's avatar
Simon Redman committed
92

93
    if not args.no_frr:
Simon Redman's avatar
Simon Redman committed
94
        frr_configurator.start_frr_on_network(netgraph.graph, ignore_nodes=ovs_nodes)
95
    if not args.no_sniffer:
Simon Redman's avatar
Simon Redman committed
96 97 98 99
        ospf_sniffer_configurator.start_sniffer_on_network(netgraph.graph,
                                                           controller=args.controller_name,
                                                           port=args.controller_port,
                                                           ignore_nodes=ovs_nodes + host_nodes)
100

101
    ssh_helper.network_graph_logout(netgraph.graph)
102 103

    if args.netgraph_write:
104 105
        with open(args.netgraph_write, 'w') as outfile:
            json.dump(netgraph.json(dict=True), outfile)