Commit b39675a9 authored by Simon Redman's avatar Simon Redman

Add basic emulab topomap parser

parent bf351e3a
#!/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.
import argparse
from collections import namedtuple
import json
# A lan is defined by a netmask and a cost
Lan = namedtuple('Lan', ['netmask', 'cost', ])
def parse_comment_line(line):
"""
Get the next action by parsing TMCD's comment
:param line:
:return: String indicating the next action
"""
body = line.split(' ')
assert body[0] == "#", "Unexpected input to parse_comment_line"
assert body[1].endswith(':'), "Unexpected comment body syntax"
# Remove that trailing colon
option = body[1][:-1]
return option
def raise_unexpected_option_error(option):
raise ValueError('Unexpected option: {option}'.format(option=option))
def parse_node_line(line):
"""
Parse a line formatted as node_name, links, where node_name is any string and links is a space-
separated list of net names and attached interface IP addresses
:param line:
:return: Tuple of node name and dict of net names -> ip addresses
"""
node, nets = line.split(',')
nets = nets.split(' ')
nets_dict = {}
for net in nets:
net_name, ip = net.split(':')
nets_dict[net_name] = ip
return node, nets_dict
def parse_link_line(line):
"""
Parse a line formatted as a comma-separated list of lan parameters starting with its name
:param line:
:return:
"""
name, *parameters = line.split(',')
return name, Lan(*parameters)
def parse_topomap(topomap):
"""
Parse the passed topomap string into a Python dictionary
It shall contain one key per datatype defined in TMCD's topomap, currently 'nodes' and 'lans'
'nodes' shall map to a dictionary of node names -> parameters
'lans' shall map to a dictionary of lan names -> parameters
:param topomap: File to open and parse
:return: Dictionary as defined above
"""
to_return = {}
option = ''
switch = {
'nodes': parse_node_line,
'lans': parse_link_line,
'default': lambda x: raise_unexpected_option_error(option), # Take the line, ignore it, and print a semi-useful error
}
with open(topomap, 'r') as contents:
for line in contents:
line = line.strip() # Clean whitespace
if line.startswith('#'):
option = parse_comment_line(line)
if not option in to_return:
to_return[option] = {}
else:
key, value = switch.get(option, switch['default'])(line)
to_return[option][key] = value
return to_return
if __name__ == "__main__":
parser = argparse.ArgumentParser("Parse Emulab's topomap into a Python dictionary")
parser.add_argument("--in-file", action='store', default='/var/emulab/boot/topomap', type=str,
help="Path to the netinfo file to parse")
parser.add_argument("--out-file", action='store', default='./netinfo.json', type=str,
help="Path to the where the result should be written. Existing file will be deleted")
args = parser.parse_args()
dict = parse_topomap(args.in_file)
with open(args.out_file, 'w') as out_file:
out_file.write(json.dumps(dict))
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment