core-extra/daemon/core/xml/xmlparser1.py

882 lines
35 KiB
Python

import random
from xml.dom.minidom import Node
from xml.dom.minidom import parse
from core import constants
from core.enumerations import NodeTypes
from core.misc import log
from core.misc import nodeutils
from core.misc.ipaddress import MacAddress
from core.service import ServiceManager
from core.xml import xmlutils
logger = log.get_logger(__name__)
class CoreDocumentParser1(object):
layer2_device_types = 'hub', 'switch'
layer3_device_types = 'host', 'router'
device_types = layer2_device_types + layer3_device_types
# TODO: support CORE interface classes:
# RJ45Node
# TunnelNode
def __init__(self, session, filename, options):
"""
Creates an CoreDocumentParser1 object.
:param core.session.Session session:
:param str filename: file name to open and parse
:param dict options: parsing options
:return:
"""
logger.info("creating xml parser: file (%s) options(%s)", filename, options)
self.session = session
self.filename = filename
if 'dom' in options:
# this prevents parsing twice when detecting file versions
self.dom = options['dom']
else:
self.dom = parse(filename)
self.start = options['start']
self.nodecls = options['nodecls']
self.scenario = self.get_scenario(self.dom)
self.location_refgeo_set = False
self.location_refxyz_set = False
# saved link parameters saved when parsing networks and applied later
self.link_params = {}
# map from id-string to objid, for files having node names but
# not node numbers
self.objidmap = {}
self.objids = set()
self.default_services = {}
if self.scenario:
self.parse_scenario()
@staticmethod
def get_scenario(dom):
scenario = xmlutils.get_first_child_by_tag_name(dom, 'scenario')
if not scenario:
raise ValueError('no scenario element found')
version = scenario.getAttribute('version')
if version and version != '1.0':
raise ValueError('unsupported scenario version found: \'%s\'' % version)
return scenario
def parse_scenario(self):
self.parse_default_services()
self.parse_session_config()
self.parse_network_plan()
def assign_id(self, idstr, idval):
if idstr in self.objidmap:
assert self.objidmap[idstr] == idval and idval in self.objids
return
self.objidmap[idstr] = idval
self.objids.add(idval)
def rand_id(self):
while True:
x = random.randint(0, 0xffff)
if x not in self.objids:
return x
def get_id(self, idstr):
"""
Get a, possibly new, object id (node number) corresponding to
the given XML string id.
"""
if not idstr:
idn = self.rand_id()
self.objids.add(idn)
return idn
elif idstr in self.objidmap:
return self.objidmap[idstr]
else:
try:
idn = int(idstr)
except ValueError:
idn = self.rand_id()
self.assign_id(idstr, idn)
return idn
def get_common_attributes(self, node):
"""
Return id, name attributes for the given XML element. These
attributes are common to nodes and networks.
"""
idstr = node.getAttribute('id')
# use an explicit set COREID if it exists
coreid = self.find_core_id(node)
if coreid:
idn = int(coreid)
if idstr:
self.assign_id(idstr, idn)
else:
idn = self.get_id(idstr)
# TODO: consider supporting unicode; for now convert to an
# ascii string
namestr = str(node.getAttribute('name'))
return idn, namestr
def iter_network_member_devices(self, element):
# element can be a network or a channel
for interface in xmlutils.iter_children_with_attribute(element, 'member', 'type', 'interface'):
if_id = xmlutils.get_child_text_trim(interface)
assert if_id # XXX for testing
if not if_id:
continue
device, if_name = self.find_device_with_interface(if_id)
assert device, 'no device for if_id: %s' % if_id # XXX for testing
if device:
yield device, if_name
def network_class(self, network, network_type):
"""
Return the corresponding CORE network class for the given
network/network_type.
"""
if network_type in ['ethernet', 'satcom']:
return nodeutils.get_node_class(NodeTypes.PEER_TO_PEER)
elif network_type == 'wireless':
channel = xmlutils.get_first_child_by_tag_name(network, 'channel')
if channel:
# use an explicit CORE type if it exists
coretype = xmlutils.get_first_child_text_trim_with_attribute(channel, 'type', 'domain', 'CORE')
if coretype:
if coretype == 'basic_range':
return nodeutils.get_node_class(NodeTypes.WIRELESS_LAN)
elif coretype.startswith('emane'):
return nodeutils.get_node_class(NodeTypes.EMANE)
else:
logger.warn('unknown network type: \'%s\'', coretype)
return xmlutils.xml_type_to_node_class(self.session, coretype)
return nodeutils.get_node_class(NodeTypes.WIRELESS_LAN)
logger.warn('unknown network type: \'%s\'', network_type)
return None
def create_core_object(self, objcls, objid, objname, element, node_type):
obj = self.session.add_object(cls=objcls, objid=objid, name=objname, start=self.start)
logger.info('added object objid=%s name=%s cls=%s' % (objid, objname, objcls))
self.set_object_position(obj, element)
self.set_object_presentation(obj, element, node_type)
return obj
def get_core_object(self, idstr):
if idstr and idstr in self.objidmap:
objid = self.objidmap[idstr]
return self.session.get_object(objid)
return None
def parse_network_plan(self):
# parse the scenario in the following order:
# 1. layer-2 devices
# 2. other networks (ptp/wlan)
# 3. layer-3 devices
self.parse_layer2_devices()
self.parse_networks()
self.parse_layer3_devices()
def set_ethernet_link_parameters(self, channel, link_params, mobility_model_name, mobility_params):
# save link parameters for later use, indexed by the tuple
# (device_id, interface_name)
for dev, if_name in self.iter_network_member_devices(channel):
if self.device_type(dev) in self.device_types:
dev_id = dev.getAttribute('id')
key = (dev_id, if_name)
self.link_params[key] = link_params
if mobility_model_name or mobility_params:
raise NotImplementedError
def set_wireless_link_parameters(self, channel, link_params, mobility_model_name, mobility_params):
network = self.find_channel_network(channel)
network_id = network.getAttribute('id')
if network_id in self.objidmap:
nodenum = self.objidmap[network_id]
else:
logger.warn('unknown network: %s', network.toxml('utf-8'))
assert False # XXX for testing
model_name = xmlutils.get_first_child_text_trim_with_attribute(channel, 'type', 'domain', 'CORE')
if not model_name:
model_name = 'basic_range'
if model_name == 'basic_range':
mgr = self.session.mobility
elif model_name.startswith('emane'):
mgr = self.session.emane
elif model_name.startswith('xen'):
mgr = self.session.xen
else:
# TODO: any other config managers?
raise NotImplementedError
logger.info("setting wireless link params: node(%s) model(%s) mobility_model(%s)",
nodenum, model_name, mobility_model_name)
mgr.setconfig_keyvalues(nodenum, model_name, link_params.items())
if mobility_model_name and mobility_params:
mgr.setconfig_keyvalues(nodenum, mobility_model_name, mobility_params.items())
def link_layer2_devices(self, device1, ifname1, device2, ifname2):
"""
Link two layer-2 devices together.
"""
devid1 = device1.getAttribute('id')
dev1 = self.get_core_object(devid1)
devid2 = device2.getAttribute('id')
dev2 = self.get_core_object(devid2)
assert dev1 and dev2 # XXX for testing
if dev1 and dev2:
# TODO: review this
if nodeutils.is_node(dev2, NodeTypes.RJ45):
# RJ45 nodes have different linknet()
netif = dev2.linknet(dev1)
else:
netif = dev1.linknet(dev2)
self.set_wired_link_parameters(dev1, netif, devid1, ifname1)
@classmethod
def parse_xml_value(cls, valtext):
if not valtext:
return None
try:
if not valtext.translate(None, '0123456789'):
val = int(valtext)
else:
val = float(valtext)
except ValueError:
val = str(valtext)
return val
@classmethod
def parse_parameter_children(cls, parent):
params = {}
for parameter in xmlutils.iter_children_with_name(parent, 'parameter'):
param_name = parameter.getAttribute('name')
assert param_name # XXX for testing
if not param_name:
continue
# TODO: consider supporting unicode; for now convert
# to an ascii string
param_name = str(param_name)
param_val = cls.parse_xml_value(xmlutils.get_child_text_trim(parameter))
# TODO: check if the name already exists?
if param_name and param_val:
params[param_name] = param_val
return params
def parse_network_channel(self, channel):
element = self.search_for_element(channel, 'type', lambda x: not x.hasAttributes())
channel_type = xmlutils.get_child_text_trim(element)
link_params = self.parse_parameter_children(channel)
mobility = xmlutils.get_first_child_by_tag_name(channel, 'CORE:mobility')
if mobility:
mobility_model_name = xmlutils.get_first_child_text_trim_by_tag_name(mobility, 'type')
mobility_params = self.parse_parameter_children(mobility)
else:
mobility_model_name = None
mobility_params = None
if channel_type == 'wireless':
self.set_wireless_link_parameters(channel, link_params, mobility_model_name, mobility_params)
elif channel_type == 'ethernet':
# TODO: maybe this can be done in the loop below to avoid
# iterating through channel members multiple times
self.set_ethernet_link_parameters(channel, link_params, mobility_model_name, mobility_params)
else:
raise NotImplementedError
layer2_device = []
for dev, if_name in self.iter_network_member_devices(channel):
if self.device_type(dev) in self.layer2_device_types:
layer2_device.append((dev, if_name))
assert len(layer2_device) <= 2
if len(layer2_device) == 2:
self.link_layer2_devices(layer2_device[0][0], layer2_device[0][1],
layer2_device[1][0], layer2_device[1][1])
def parse_network(self, network):
"""
Each network element should have an 'id' and 'name' attribute
and include the following child elements:
type (one)
member (zero or more with type="interface" or type="channel")
channel (zero or more)
"""
layer2_members = set()
layer3_members = 0
for dev, if_name in self.iter_network_member_devices(network):
if not dev:
continue
devtype = self.device_type(dev)
if devtype in self.layer2_device_types:
layer2_members.add(dev)
elif devtype in self.layer3_device_types:
layer3_members += 1
else:
raise NotImplementedError
if len(layer2_members) == 0:
net_type = xmlutils.get_first_child_text_trim_by_tag_name(network, 'type')
if not net_type:
logger.warn('no network type found for network: \'%s\'', network.toxml('utf-8'))
assert False # XXX for testing
net_cls = self.network_class(network, net_type)
objid, net_name = self.get_common_attributes(network)
logger.info('parsing network: name=%s id=%s' % (net_name, objid))
if objid in self.session.objects:
return
n = self.create_core_object(net_cls, objid, net_name, network, None)
# handle channel parameters
for channel in xmlutils.iter_children_with_name(network, 'channel'):
self.parse_network_channel(channel)
def parse_networks(self):
"""
Parse all 'network' elements.
"""
for network in xmlutils.iter_descendants_with_name(self.scenario, 'network'):
self.parse_network(network)
def parse_addresses(self, interface):
mac = []
ipv4 = []
ipv6 = []
hostname = []
for address in xmlutils.iter_children_with_name(interface, 'address'):
addr_type = address.getAttribute('type')
if not addr_type:
msg = 'no type attribute found for address ' \
'in interface: \'%s\'' % interface.toxml('utf-8')
logger.warn(msg)
assert False # XXX for testing
addr_text = xmlutils.get_child_text_trim(address)
if not addr_text:
msg = 'no text found for address ' \
'in interface: \'%s\'' % interface.toxml('utf-8')
logger.warn(msg)
assert False # XXX for testing
if addr_type == 'mac':
mac.append(addr_text)
elif addr_type == 'IPv4':
ipv4.append(addr_text)
elif addr_type == 'IPv6':
ipv6.append(addr_text)
elif addr_type == 'hostname':
hostname.append(addr_text)
else:
msg = 'skipping unknown address type \'%s\' in ' \
'interface: \'%s\'' % (addr_type, interface.toxml('utf-8'))
logger.warn(msg)
assert False # XXX for testing
return mac, ipv4, ipv6, hostname
def parse_interface(self, node, device_id, interface):
"""
Each interface can have multiple 'address' elements.
"""
if_name = interface.getAttribute('name')
network = self.find_interface_network_object(interface)
if not network:
msg = 'skipping node \'%s\' interface \'%s\': ' \
'unknown network' % (node.name, if_name)
logger.warn(msg)
assert False # XXX for testing
mac, ipv4, ipv6, hostname = self.parse_addresses(interface)
if mac:
hwaddr = MacAddress.from_string(mac[0])
else:
hwaddr = None
ifindex = node.newnetif(network, addrlist=ipv4 + ipv6, hwaddr=hwaddr, ifindex=None, ifname=if_name)
# TODO: 'hostname' addresses are unused
msg = 'node \'%s\' interface \'%s\' connected ' \
'to network \'%s\'' % (node.name, if_name, network.name)
logger.info(msg)
# set link parameters for wired links
if nodeutils.is_node(network, (NodeTypes.HUB, NodeTypes.PEER_TO_PEER, NodeTypes.SWITCH)):
netif = node.netif(ifindex)
self.set_wired_link_parameters(network, netif, device_id)
def set_wired_link_parameters(self, network, netif, device_id, netif_name=None):
if netif_name is None:
netif_name = netif.name
key = (device_id, netif_name)
if key in self.link_params:
link_params = self.link_params[key]
if self.start:
bw = link_params.get('bw')
delay = link_params.get('delay')
loss = link_params.get('loss')
duplicate = link_params.get('duplicate')
jitter = link_params.get('jitter')
network.linkconfig(netif, bw=bw, delay=delay, loss=loss, duplicate=duplicate, jitter=jitter)
else:
for k, v in link_params.iteritems():
netif.setparam(k, v)
@staticmethod
def search_for_element(node, tag_name, match=None):
"""
Search the given node and all ancestors for an element named
tagName that satisfies the given matching function.
"""
while True:
for child in xmlutils.iter_children(node, Node.ELEMENT_NODE):
if child.tagName == tag_name and (match is None or match(child)):
return child
node = node.parentNode
if not node:
break
return None
@classmethod
def find_core_id(cls, node):
def match(x):
domain = x.getAttribute('domain')
return domain == 'COREID'
alias = cls.search_for_element(node, 'alias', match)
if alias:
return xmlutils.get_child_text_trim(alias)
return None
@classmethod
def find_point(cls, node):
return cls.search_for_element(node, 'point')
@staticmethod
def find_channel_network(channel):
p = channel.parentNode
if p and p.tagName == 'network':
return p
return None
def find_interface_network_object(self, interface):
network_id = xmlutils.get_first_child_text_trim_with_attribute(interface, 'member', 'type', 'network')
if not network_id:
# support legacy notation: <interface net="netid" ...
network_id = interface.getAttribute('net')
obj = self.get_core_object(network_id)
if obj:
# the network_id should exist for ptp or wlan/emane networks
return obj
# the network should correspond to a layer-2 device if the
# network_id does not exist
channel_id = xmlutils.get_first_child_text_trim_with_attribute(interface, 'member', 'type', 'channel')
if not network_id or not channel_id:
return None
network = xmlutils.get_first_child_with_attribute(self.scenario, 'network', 'id', network_id)
if not network:
return None
channel = xmlutils.get_first_child_with_attribute(network, 'channel', 'id', channel_id)
if not channel:
return None
device = None
for dev, if_name in self.iter_network_member_devices(channel):
if self.device_type(dev) in self.layer2_device_types:
assert not device # XXX
device = dev
if device:
obj = self.get_core_object(device.getAttribute('id'))
if obj:
return obj
return None
def set_object_position_pixel(self, obj, point):
x = float(point.getAttribute('x'))
y = float(point.getAttribute('y'))
z = point.getAttribute('z')
if z:
z = float(z)
else:
z = 0.0
# TODO: zMode is unused
# z_mode = point.getAttribute('zMode'))
if x < 0.0:
logger.warn('limiting negative x position of \'%s\' to zero: %s' % (obj.name, x))
x = 0.0
if y < 0.0:
logger.warn('limiting negative y position of \'%s\' to zero: %s' % (obj.name, y))
y = 0.0
obj.setposition(x, y, z)
def set_object_position_gps(self, obj, point):
lat = float(point.getAttribute('lat'))
lon = float(point.getAttribute('lon'))
zalt = point.getAttribute('z')
if zalt:
zalt = float(zalt)
else:
zalt = 0.0
# TODO: zMode is unused
# z_mode = point.getAttribute('zMode'))
if not self.location_refgeo_set:
# for x,y,z conversion, we need a reasonable refpt; this
# picks the first coordinates as the origin
self.session.location.setrefgeo(lat, lon, zalt)
self.location_refgeo_set = True
x, y, z = self.session.location.getxyz(lat, lon, zalt)
if x < 0.0:
logger.warn('limiting negative x position of \'%s\' to zero: %s' % (obj.name, x))
x = 0.0
if y < 0.0:
logger.warn('limiting negative y position of \'%s\' to zero: %s' % (obj.name, y))
y = 0.0
obj.setposition(x, y, z)
def set_object_position_cartesian(self, obj, point):
# TODO: review this
xm = float(point.getAttribute('x'))
ym = float(point.getAttribute('y'))
zm = point.getAttribute('z')
if zm:
zm = float(zm)
else:
zm = 0.0
# TODO: zMode is unused
# z_mode = point.getAttribute('zMode'))
if not self.location_refxyz_set:
self.session.location.refxyz = xm, ym, zm
self.location_refxyz_set = True
# need to convert meters to pixels
x = self.session.location.m2px(xm) + self.session.location.refxyz[0]
y = self.session.location.m2px(ym) + self.session.location.refxyz[1]
z = self.session.location.m2px(zm) + self.session.location.refxyz[2]
if x < 0.0:
logger.warn('limiting negative x position of \'%s\' to zero: %s' % (obj.name, x))
x = 0.0
if y < 0.0:
logger.warn('limiting negative y position of \'%s\' to zero: %s' % (obj.name, y))
y = 0.0
obj.setposition(x, y, z)
def set_object_position(self, obj, element):
"""
Set the x,y,x position of obj from the point associated with
the given element.
"""
point = self.find_point(element)
if not point:
return False
point_type = point.getAttribute('type')
if not point_type:
msg = 'no type attribute found for point: \'%s\'' % \
point.toxml('utf-8')
logger.warn(msg)
assert False # XXX for testing
elif point_type == 'pixel':
self.set_object_position_pixel(obj, point)
elif point_type == 'gps':
self.set_object_position_gps(obj, point)
elif point_type == 'cart':
self.set_object_position_cartesian(obj, point)
else:
logger.warn("skipping unknown point type: '%s'" % point_type)
assert False # XXX for testing
logger.info('set position of %s from point element: \'%s\'', obj.name, point.toxml('utf-8'))
return True
def parse_device_service(self, service, node):
name = service.getAttribute('name')
session_service = ServiceManager.get(name)
if not session_service:
assert False # XXX for testing
values = []
startup_idx = service.getAttribute('startup_idx')
if startup_idx:
values.append('startidx=%s' % startup_idx)
startup_time = service.getAttribute('start_time')
if startup_time:
values.append('starttime=%s' % startup_time)
dirs = []
for directory in xmlutils.iter_children_with_name(service, 'directory'):
dirname = directory.getAttribute('name')
dirs.append(str(dirname))
if dirs:
values.append("dirs=%s" % dirs)
startup = []
shutdown = []
validate = []
for command in xmlutils.iter_children_with_name(service, 'command'):
command_type = command.getAttribute('type')
command_text = xmlutils.get_child_text_trim(command)
if not command_text:
continue
if command_type == 'start':
startup.append(str(command_text))
elif command_type == 'stop':
shutdown.append(str(command_text))
elif command_type == 'validate':
validate.append(str(command_text))
if startup:
values.append('cmdup=%s' % startup)
if shutdown:
values.append('cmddown=%s' % shutdown)
if validate:
values.append('cmdval=%s' % validate)
filenames = []
files = []
for f in xmlutils.iter_children_with_name(service, 'file'):
filename = f.getAttribute('name')
if not filename:
continue
filenames.append(filename)
data = xmlutils.get_child_text_trim(f)
if data:
data = str(data)
else:
data = None
typestr = 'service:%s:%s' % (name, filename)
files.append((typestr, filename, data))
if filenames:
values.append('files=%s' % filenames)
custom = service.getAttribute('custom')
if custom and custom.lower() == 'true':
self.session.services.setcustomservice(node.objid, session_service, values)
# NOTE: if a custom service is used, setservicefile() must be
# called after the custom service exists
for typestr, filename, data in files:
self.session.services.setservicefile(
nodenum=node.objid,
type=typestr,
filename=filename,
srcname=None,
data=data
)
return str(name)
def parse_device_services(self, services, node):
"""
Use session.services manager to store service customizations
before they are added to a node.
"""
service_names = []
for service in xmlutils.iter_children_with_name(services, 'service'):
name = self.parse_device_service(service, node)
if name:
service_names.append(name)
return '|'.join(service_names)
def add_device_services(self, node, device, node_type):
"""
Add services to the given node.
"""
services = xmlutils.get_first_child_by_tag_name(device, 'CORE:services')
if services:
services_str = self.parse_device_services(services, node)
logger.info('services for node \'%s\': %s' % (node.name, services_str))
elif node_type in self.default_services:
services_str = None # default services will be added
else:
return
self.session.services.addservicestonode(
node=node,
nodetype=node_type,
services_str=services_str
)
def set_object_presentation(self, obj, element, node_type):
# defaults from the CORE GUI
default_icons = {
'router': 'router.gif',
'host': 'host.gif',
'PC': 'pc.gif',
'mdr': 'mdr.gif',
# 'prouter': 'router_green.gif',
# 'xen': 'xen.gif'
}
icon_set = False
for child in xmlutils.iter_children_with_name(element, 'CORE:presentation'):
canvas = child.getAttribute('canvas')
if canvas:
obj.canvas = int(canvas)
icon = child.getAttribute('icon')
if icon:
icon = str(icon).replace("$CORE_DATA_DIR",
constants.CORE_DATA_DIR)
obj.icon = icon
icon_set = True
if not icon_set and node_type in default_icons:
obj.icon = default_icons[node_type]
def device_type(self, device):
if device.tagName in self.device_types:
return device.tagName
return None
def core_node_type(self, device):
# use an explicit CORE type if it exists
coretype = xmlutils.get_first_child_text_trim_with_attribute(device, 'type', 'domain', 'CORE')
if coretype:
return coretype
return self.device_type(device)
def find_device_with_interface(self, interface_id):
# TODO: suport generic 'device' elements
for device in xmlutils.iter_descendants_with_name(self.scenario, self.device_types):
interface = xmlutils.get_first_child_with_attribute(device, 'interface', 'id', interface_id)
if interface:
if_name = interface.getAttribute('name')
return device, if_name
return None, None
def parse_layer2_device(self, device):
objid, device_name = self.get_common_attributes(device)
logger.info('parsing layer-2 device: name=%s id=%s' % (device_name, objid))
try:
return self.session.get_object(objid)
except KeyError:
logger.exception("error geting object: %s", objid)
device_type = self.device_type(device)
if device_type == 'hub':
device_class = nodeutils.get_node_class(NodeTypes.HUB)
elif device_type == 'switch':
device_class = nodeutils.get_node_class(NodeTypes.SWITCH)
else:
logger.warn('unknown layer-2 device type: \'%s\'' % device_type)
assert False # XXX for testing
n = self.create_core_object(device_class, objid, device_name, device, None)
return n
def parse_layer3_device(self, device):
objid, device_name = self.get_common_attributes(device)
logger.info('parsing layer-3 device: name=%s id=%s', device_name, objid)
try:
return self.session.get_object(objid)
except KeyError:
logger.exception("error getting session object: %s", objid)
device_cls = self.nodecls
core_node_type = self.core_node_type(device)
n = self.create_core_object(device_cls, objid, device_name, device, core_node_type)
n.type = core_node_type
self.add_device_services(n, device, core_node_type)
for interface in xmlutils.iter_children_with_name(device, 'interface'):
self.parse_interface(n, device.getAttribute('id'), interface)
return n
def parse_layer2_devices(self):
"""
Parse all layer-2 device elements. A device can be: 'switch',
'hub'.
"""
# TODO: suport generic 'device' elements
for device in xmlutils.iter_descendants_with_name(self.scenario, self.layer2_device_types):
self.parse_layer2_device(device)
def parse_layer3_devices(self):
"""
Parse all layer-3 device elements. A device can be: 'host',
'router'.
"""
# TODO: suport generic 'device' elements
for device in xmlutils.iter_descendants_with_name(self.scenario, self.layer3_device_types):
self.parse_layer3_device(device)
def parse_session_origin(self, session_config):
"""
Parse the first origin tag and set the CoreLocation reference
point appropriately.
"""
# defaults from the CORE GUI
self.session.location.setrefgeo(47.5791667, -122.132322, 2.0)
self.session.location.refscale = 150.0
origin = xmlutils.get_first_child_by_tag_name(session_config, 'origin')
if not origin:
return
lat = origin.getAttribute('lat')
lon = origin.getAttribute('lon')
alt = origin.getAttribute('alt')
if lat and lon and alt:
self.session.location.setrefgeo(float(lat), float(lon), float(alt))
self.location_refgeo_set = True
scale100 = origin.getAttribute("scale100")
if scale100:
self.session.location.refscale = float(scale100)
point = xmlutils.get_first_child_text_trim_by_tag_name(origin, 'point')
if point:
xyz = point.split(',')
if len(xyz) == 2:
xyz.append('0.0')
if len(xyz) == 3:
self.session.location.refxyz = (float(xyz[0]), float(xyz[1]), float(xyz[2]))
self.location_refxyz_set = True
def parse_session_options(self, session_config):
options = xmlutils.get_first_child_by_tag_name(session_config, 'options')
if not options:
return
params = self.parse_parameter_children(options)
for name, value in params.iteritems():
if name and value:
setattr(self.session.options, str(name), str(value))
def parse_session_hooks(self, session_config):
"""
Parse hook scripts.
"""
hooks = xmlutils.get_first_child_by_tag_name(session_config, 'hooks')
if not hooks:
return
for hook in xmlutils.iter_children_with_name(hooks, 'hook'):
filename = hook.getAttribute('name')
state = hook.getAttribute('state')
data = xmlutils.get_child_text_trim(hook)
if data is None:
data = '' # allow for empty file
hook_type = "hook:%s" % state
self.session.set_hook(hook_type, file_name=str(filename), source_name=None, data=str(data))
def parse_session_metadata(self, session_config):
metadata = xmlutils.get_first_child_by_tag_name(session_config, 'metadata')
if not metadata:
return
params = self.parse_parameter_children(metadata)
for name, value in params.iteritems():
if name and value:
self.session.metadata.add_item(str(name), str(value))
def parse_session_config(self):
session_config = xmlutils.get_first_child_by_tag_name(self.scenario, 'CORE:sessionconfig')
if not session_config:
return
self.parse_session_origin(session_config)
self.parse_session_options(session_config)
self.parse_session_hooks(session_config)
self.parse_session_metadata(session_config)
def parse_default_services(self):
# defaults from the CORE GUI
self.default_services = {
'router': ['zebra', 'OSPFv2', 'OSPFv3', 'IPForward'],
'host': ['DefaultRoute', 'SSH'],
'PC': ['DefaultRoute', ],
'mdr': ['zebra', 'OSPFv3MDR', 'IPForward'],
}
default_services = xmlutils.get_first_child_by_tag_name(self.scenario, 'CORE:defaultservices')
if not default_services:
return
for device in xmlutils.iter_children_with_name(default_services, 'device'):
device_type = device.getAttribute('type')
if not device_type:
logger.warn('parse_default_services: no type attribute found for device')
continue
services = []
for service in xmlutils.iter_children_with_name(device, 'service'):
name = service.getAttribute('name')
if name:
services.append(str(name))
self.default_services[device_type] = services
# store default services for the session
for t, s in self.default_services.iteritems():
self.session.services.defaultservices[t] = s
logger.info('default services for node type \'%s\' set to: %s' % (t, s))