Merge pull request #210 from coreemu/cleanup/codacy-cleanup
Cleanup/codacy cleanup
This commit is contained in:
commit
3c8fbc73ad
50 changed files with 528 additions and 4062 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -20,6 +20,9 @@ stamp-h1
|
|||
# python build directory
|
||||
dist
|
||||
|
||||
# vscode
|
||||
.vscode
|
||||
|
||||
# intellij
|
||||
*.iml
|
||||
.idea
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# CORE
|
||||
# CORE [![Codacy Badge](https://api.codacy.com/project/badge/Grade/d94eb0244ade4510a106b4af76077a92)](https://www.codacy.com/app/blakeharnden/core?utm_source=github.com&utm_medium=referral&utm_content=coreemu/core&utm_campaign=Badge_Grade)
|
||||
|
||||
CORE: Common Open Research Emulator
|
||||
|
||||
|
@ -17,7 +17,7 @@ scripting network emulation.
|
|||
## Documentation and Examples
|
||||
|
||||
* Documentation hosted on GitHub
|
||||
* http://coreemu.github.io/core/
|
||||
* <http://coreemu.github.io/core/>
|
||||
* Basic Script Examples
|
||||
* [Examples](daemon/examples/api)
|
||||
* Custom Service Example
|
||||
|
@ -30,7 +30,7 @@ scripting network emulation.
|
|||
We are leveraging Discord for persistent chat rooms, voice chat, and
|
||||
GitHub integration. This allows for more dynamic conversations and the
|
||||
capability to respond faster. Feel free to join us at the link below.
|
||||
https://discord.gg/AKd7kmP
|
||||
<https://discord.gg/AKd7kmP>
|
||||
|
||||
You can also get help with questions, comments, or trouble, by using
|
||||
the CORE mailing lists:
|
||||
|
@ -42,7 +42,6 @@ the CORE mailing lists:
|
|||
|
||||
See [CORE Installation](http://coreemu.github.io/core/install.html) for detailed build instructions.
|
||||
|
||||
Running CORE
|
||||
------------
|
||||
### Running CORE
|
||||
|
||||
See [Using the CORE GUI](http://coreemu.github.io/core/usage.html) for more details on running CORE.
|
||||
|
|
|
@ -91,7 +91,7 @@ class CoreTlvDataObj(CoreTlvData):
|
|||
"""
|
||||
|
||||
@classmethod
|
||||
def pack(cls, obj):
|
||||
def pack(cls, value):
|
||||
"""
|
||||
Convenience method for packing custom object data.
|
||||
|
||||
|
@ -99,7 +99,7 @@ class CoreTlvDataObj(CoreTlvData):
|
|||
:return: length of data and the packed data itself
|
||||
:rtype: tuple
|
||||
"""
|
||||
value = cls.get_value(obj)
|
||||
value = cls.get_value(value)
|
||||
return super(CoreTlvDataObj, cls).pack(value)
|
||||
|
||||
@classmethod
|
||||
|
@ -244,7 +244,7 @@ class CoreTlvDataUint16List(CoreTlvData):
|
|||
:return: unint 16 list
|
||||
:rtype: list
|
||||
"""
|
||||
return tuple(map(lambda (x): int(x), value.split()))
|
||||
return tuple(int(x) for x in value.split())
|
||||
|
||||
|
||||
class CoreTlvDataIpv4Addr(CoreTlvDataObj):
|
||||
|
@ -266,7 +266,7 @@ class CoreTlvDataIpv4Addr(CoreTlvDataObj):
|
|||
return obj.addr
|
||||
|
||||
@staticmethod
|
||||
def new_obj(value):
|
||||
def new_obj(obj):
|
||||
"""
|
||||
Retrieve Ipv4 address from a string representation.
|
||||
|
||||
|
@ -274,7 +274,7 @@ class CoreTlvDataIpv4Addr(CoreTlvDataObj):
|
|||
:return: Ipv4 address
|
||||
:rtype: core.misc.ipaddress.IpAddress
|
||||
"""
|
||||
return IpAddress(af=socket.AF_INET, address=value)
|
||||
return IpAddress(af=socket.AF_INET, address=obj)
|
||||
|
||||
|
||||
class CoreTlvDataIPv6Addr(CoreTlvDataObj):
|
||||
|
@ -380,7 +380,7 @@ class CoreTlv(object):
|
|||
tlv_type, tlv_len = struct.unpack(cls.header_format, data[:cls.header_len])
|
||||
header_len = cls.header_len
|
||||
if tlv_len == 0:
|
||||
tlv_type, zero, tlv_len = struct.unpack(cls.long_header_format, data[:cls.long_header_len])
|
||||
tlv_type, _zero, tlv_len = struct.unpack(cls.long_header_format, data[:cls.long_header_len])
|
||||
header_len = cls.long_header_len
|
||||
tlv_size = header_len + tlv_len
|
||||
# for 32-bit alignment
|
||||
|
|
|
@ -58,7 +58,9 @@ class CoreDistributedServer(object):
|
|||
|
||||
:return: nothing
|
||||
"""
|
||||
assert self.sock is None
|
||||
if self.sock:
|
||||
raise ValueError("socket already connected")
|
||||
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
|
||||
try:
|
||||
|
@ -168,7 +170,7 @@ class CoreBroker(object):
|
|||
self.network_nodes.clear()
|
||||
self.physical_nodes.clear()
|
||||
while len(self.tunnels) > 0:
|
||||
key, gt = self.tunnels.popitem()
|
||||
_key, gt = self.tunnels.popitem()
|
||||
gt.shutdown()
|
||||
|
||||
def startrecvloop(self):
|
||||
|
@ -202,7 +204,7 @@ class CoreBroker(object):
|
|||
for server in self.servers.itervalues():
|
||||
if server.sock is not None:
|
||||
rlist.append(server.sock)
|
||||
r, w, x = select.select(rlist, [], [], 1.0)
|
||||
r, _w, _x = select.select(rlist, [], [], 1.0)
|
||||
for sock in r:
|
||||
server = self.getserverbysock(sock)
|
||||
logger.info("attempting to receive from server: peer:%s remote:%s",
|
||||
|
@ -319,7 +321,8 @@ class CoreBroker(object):
|
|||
with self.servers_lock:
|
||||
try:
|
||||
s = self.servers.pop(server.name)
|
||||
assert s == server
|
||||
if s != server:
|
||||
raise ValueError("server removed was not the server provided")
|
||||
except KeyError:
|
||||
logger.exception("error deleting server")
|
||||
|
||||
|
@ -709,7 +712,7 @@ class CoreBroker(object):
|
|||
:param str host: host address
|
||||
:return: packed core execute tlv data
|
||||
"""
|
||||
msgtype, msgflags, msglen = coreapi.CoreMessage.unpack_header(msghdr)
|
||||
msgtype, msgflags, _msglen = coreapi.CoreMessage.unpack_header(msghdr)
|
||||
msgcls = coreapi.CLASS_MAP[msgtype]
|
||||
msg = msgcls(msgflags, msghdr, msgdata)
|
||||
|
||||
|
@ -722,7 +725,6 @@ class CoreBroker(object):
|
|||
tlvdata += coreapi.CoreExecuteTlv.pack(ExecuteTlvs.NODE.value, nodenum)
|
||||
tlvdata += coreapi.CoreExecuteTlv.pack(ExecuteTlvs.NUMBER.value, execnum)
|
||||
tlvdata += coreapi.CoreExecuteTlv.pack(ExecuteTlvs.COMMAND.value, cmd)
|
||||
title = "\\\"CORE: n%s @ %s\\\"" % (nodenum, host)
|
||||
res = "ssh -X -f " + host + " xterm -e " + res
|
||||
tlvdata += coreapi.CoreExecuteTlv.pack(ExecuteTlvs.RESULT.value, res)
|
||||
|
||||
|
@ -931,7 +933,7 @@ class CoreBroker(object):
|
|||
:rtype: bool
|
||||
"""
|
||||
hdr = msg[:coreapi.CoreMessage.header_len]
|
||||
msgtype, flags, msglen = coreapi.CoreMessage.unpack_header(hdr)
|
||||
msgtype, flags, _msglen = coreapi.CoreMessage.unpack_header(hdr)
|
||||
msgcls = coreapi.CLASS_MAP[msgtype]
|
||||
return self.handle_message(msgcls(flags, hdr, msg[coreapi.CoreMessage.header_len:]))
|
||||
|
||||
|
@ -1067,7 +1069,7 @@ class CoreBroker(object):
|
|||
|
||||
value_strings = values_str.split("|")
|
||||
for value_string in value_strings:
|
||||
key, value = value_string.split("=", 1)
|
||||
key, _value = value_string.split("=", 1)
|
||||
if key == "controlnet":
|
||||
self.handle_distributed_control_net(message, value_strings, value_strings.index(value_string))
|
||||
|
||||
|
@ -1083,7 +1085,7 @@ class CoreBroker(object):
|
|||
:return: nothing
|
||||
"""
|
||||
key_value = values[index]
|
||||
key, value = key_value.split("=", 1)
|
||||
_key, value = key_value.split("=", 1)
|
||||
control_nets = value.split()
|
||||
|
||||
if len(control_nets) < 2:
|
||||
|
|
|
@ -1005,17 +1005,17 @@ class CoreHandler(SocketServer.BaseRequestHandler):
|
|||
if not config_data.data_values:
|
||||
logger.warn("location data missing")
|
||||
else:
|
||||
values = config_data.data_values.split("|")
|
||||
values = [float(x) for x in config_data.data_values.split("|")]
|
||||
|
||||
# Cartesian coordinate reference point
|
||||
refx, refy = map(lambda x: float(x), values[0:2])
|
||||
refx, refy = values[0], values[1]
|
||||
refz = 0.0
|
||||
lat, lon, alt = map(lambda x: float(x), values[2:5])
|
||||
lat, lon, alt = values[2], values[3], values[4]
|
||||
# xyz point
|
||||
self.session.location.refxyz = (refx, refy, refz)
|
||||
# geographic reference point
|
||||
self.session.location.setrefgeo(lat, lon, alt)
|
||||
self.session.location.refscale = float(values[5])
|
||||
self.session.location.refscale = values[5]
|
||||
logger.info("location configured: %s = %s scale=%s", self.session.location.refxyz,
|
||||
self.session.location.refgeo, self.session.location.refscale)
|
||||
logger.info("location configured: UTM%s", self.session.location.refutm)
|
||||
|
@ -1475,8 +1475,7 @@ class CoreHandler(SocketServer.BaseRequestHandler):
|
|||
return ()
|
||||
elif event_type == EventTypes.FILE_SAVE:
|
||||
filename = event_data.name
|
||||
xml_version = self.session.options.get_config("xmlfilever")
|
||||
self.session.save_xml(filename, xml_version)
|
||||
self.session.save_xml(filename)
|
||||
elif event_type == EventTypes.SCHEDULED:
|
||||
etime = event_data.time
|
||||
node = event_data.node
|
||||
|
|
|
@ -85,6 +85,9 @@ class PyCoreObj(object):
|
|||
if name is None:
|
||||
name = "o%s" % self.objid
|
||||
self.name = name
|
||||
self.type = None
|
||||
self.server = None
|
||||
self.services = None
|
||||
# ifindex is key, PyCoreNetIf instance is value
|
||||
self._netif = {}
|
||||
self.ifindex = 0
|
||||
|
@ -205,21 +208,12 @@ class PyCoreObj(object):
|
|||
return None
|
||||
|
||||
x, y, _ = self.getposition()
|
||||
model = self.type
|
||||
emulation_server = self.server
|
||||
|
||||
model = None
|
||||
if hasattr(self, "type"):
|
||||
model = self.type
|
||||
|
||||
emulation_server = None
|
||||
if hasattr(self, "server"):
|
||||
emulation_server = self.server
|
||||
|
||||
services = None
|
||||
if hasattr(self, "services") and len(self.services) != 0:
|
||||
nodeservices = []
|
||||
for s in self.services:
|
||||
nodeservices.append(s.name)
|
||||
services = "|".join(nodeservices)
|
||||
services = self.services
|
||||
if services is not None:
|
||||
services = "|".join([service.name for service in services])
|
||||
|
||||
node_data = NodeData(
|
||||
message_type=message_type,
|
||||
|
@ -269,10 +263,8 @@ class PyCoreNode(PyCoreObj):
|
|||
:param str name: object name
|
||||
:param bool start: boolean for starting
|
||||
"""
|
||||
PyCoreObj.__init__(self, session, objid, name, start=start)
|
||||
super(PyCoreNode, self).__init__(session, objid, name, start=start)
|
||||
self.services = []
|
||||
if not hasattr(self, "type"):
|
||||
self.type = None
|
||||
self.nodedir = None
|
||||
self.tmpnodedir = False
|
||||
|
||||
|
@ -460,6 +452,19 @@ class PyCoreNet(PyCoreObj):
|
|||
"""
|
||||
linktype = LinkTypes.WIRED.value
|
||||
|
||||
def __init__(self, session, objid, name, start=True):
|
||||
"""
|
||||
Create a PyCoreNet instance.
|
||||
|
||||
:param core.session.Session session: CORE session object
|
||||
:param int objid: object id
|
||||
:param str name: object name
|
||||
:param bool start: should object start
|
||||
"""
|
||||
super(PyCoreNet, self).__init__(session, objid, name, start=start)
|
||||
self._linked = {}
|
||||
self._linked_lock = threading.Lock()
|
||||
|
||||
def startup(self):
|
||||
"""
|
||||
Each object implements its own startup method.
|
||||
|
@ -476,19 +481,6 @@ class PyCoreNet(PyCoreObj):
|
|||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def __init__(self, session, objid, name, start=True):
|
||||
"""
|
||||
Create a PyCoreNet instance.
|
||||
|
||||
:param core.session.Session session: CORE session object
|
||||
:param int objid: object id
|
||||
:param str name: object name
|
||||
:param bool start: should object start
|
||||
"""
|
||||
PyCoreObj.__init__(self, session, objid, name, start=start)
|
||||
self._linked = {}
|
||||
self._linked_lock = threading.Lock()
|
||||
|
||||
def attach(self, netif):
|
||||
"""
|
||||
Attach network interface.
|
||||
|
@ -550,7 +542,7 @@ class PyCoreNet(PyCoreObj):
|
|||
interface2_ip6 = None
|
||||
interface2_ip6_mask = None
|
||||
for address in netif.addrlist:
|
||||
ip, sep, mask = address.partition('/')
|
||||
ip, _sep, mask = address.partition("/")
|
||||
mask = int(mask)
|
||||
if ipaddress.is_ipv4_address(ip):
|
||||
family = AF_INET
|
||||
|
@ -627,7 +619,8 @@ class PyCoreNetIf(object):
|
|||
self._params = {}
|
||||
self.addrlist = []
|
||||
self.hwaddr = None
|
||||
self.poshook = None
|
||||
# placeholder position hook
|
||||
self.poshook = lambda a, b, c, d: None
|
||||
# used with EMANE
|
||||
self.transport_type = None
|
||||
# interface index on the network
|
||||
|
@ -760,5 +753,4 @@ class PyCoreNetIf(object):
|
|||
:param z: z position
|
||||
:return: nothing
|
||||
"""
|
||||
if self.poshook is not None:
|
||||
self.poshook(self, x, y, z)
|
||||
self.poshook(self, x, y, z)
|
||||
|
|
|
@ -25,7 +25,7 @@ def convert_none(x):
|
|||
"""
|
||||
Helper to use 0 for None values.
|
||||
"""
|
||||
if type(x) is str:
|
||||
if isinstance(x, basestring):
|
||||
x = float(x)
|
||||
if x is None:
|
||||
return 0
|
||||
|
|
|
@ -627,11 +627,11 @@ class EmaneManager(ModelManager):
|
|||
if realtime:
|
||||
emanecmd += "-r",
|
||||
|
||||
otagroup, otaport = self.get_config("otamanagergroup").split(":")
|
||||
otagroup, _otaport = self.get_config("otamanagergroup").split(":")
|
||||
otadev = self.get_config("otamanagerdevice")
|
||||
otanetidx = self.session.get_control_net_index(otadev)
|
||||
|
||||
eventgroup, eventport = self.get_config("eventservicegroup").split(":")
|
||||
eventgroup, _eventport = self.get_config("eventservicegroup").split(":")
|
||||
eventdev = self.get_config("eventservicedevice")
|
||||
eventservicenetidx = self.session.get_control_net_index(eventdev)
|
||||
|
||||
|
@ -781,7 +781,7 @@ class EmaneManager(ModelManager):
|
|||
return
|
||||
logger.info("subscribing to EMANE location events. (%s)", threading.currentThread().getName())
|
||||
while self.doeventloop is True:
|
||||
uuid, seq, events = self.service.nextEvent()
|
||||
_uuid, _seq, events = self.service.nextEvent()
|
||||
|
||||
# this occurs with 0.9.1 event service
|
||||
if not self.doeventloop:
|
||||
|
@ -820,7 +820,7 @@ class EmaneManager(ModelManager):
|
|||
Returns True if successfully parsed and a Node Message was sent.
|
||||
"""
|
||||
# convert nemid to node number
|
||||
emanenode, netif = self.nemlookup(nemid)
|
||||
_emanenode, netif = self.nemlookup(nemid)
|
||||
if netif is None:
|
||||
logger.info("location event for unknown NEM %s", nemid)
|
||||
return False
|
||||
|
|
|
@ -37,7 +37,7 @@ class EmaneNode(EmaneNet):
|
|||
"""
|
||||
|
||||
def __init__(self, session, objid=None, name=None, start=True):
|
||||
PyCoreNet.__init__(self, session, objid, name, start)
|
||||
super(EmaneNode, self).__init__(session, objid, name, start)
|
||||
self.conf = ""
|
||||
self.up = False
|
||||
self.nemidmap = {}
|
||||
|
|
|
@ -262,7 +262,7 @@ class EmuSession(Session):
|
|||
|
||||
# network to network
|
||||
if net_one and net_two:
|
||||
logger.info("adding link from network to network: %s", net_one.name, net_two.name)
|
||||
logger.info("adding link from network to network: %s - %s", net_one.name, net_two.name)
|
||||
if nodeutils.is_node(net_two, NodeTypes.RJ45):
|
||||
interface = net_two.linknet(net_one)
|
||||
else:
|
||||
|
@ -326,7 +326,7 @@ class EmuSession(Session):
|
|||
:return: nothing
|
||||
"""
|
||||
# get node objects identified by link data
|
||||
node_one, node_two, net_one, net_two, tunnel = self._link_nodes(node_one_id, node_two_id)
|
||||
node_one, node_two, net_one, net_two, _tunnel = self._link_nodes(node_one_id, node_two_id)
|
||||
|
||||
if node_one:
|
||||
node_one.lock.acquire()
|
||||
|
@ -388,7 +388,7 @@ class EmuSession(Session):
|
|||
:return: nothing
|
||||
"""
|
||||
# get node objects identified by link data
|
||||
node_one, node_two, net_one, net_two, tunnel = self._link_nodes(node_one_id, node_two_id)
|
||||
node_one, node_two, net_one, net_two, _tunnel = self._link_nodes(node_one_id, node_two_id)
|
||||
|
||||
if node_one:
|
||||
node_one.lock.acquire()
|
||||
|
@ -670,12 +670,11 @@ class EmuSession(Session):
|
|||
self.file_name = file_name
|
||||
self.instantiate()
|
||||
|
||||
def save_xml(self, file_name, version):
|
||||
def save_xml(self, file_name):
|
||||
"""
|
||||
Export a session to the EmulationScript XML format.
|
||||
|
||||
:param str file_name: file name to write session xml to
|
||||
:param str version: xml version type
|
||||
:return: nothing
|
||||
"""
|
||||
CoreXmlWriter(self).write(file_name)
|
||||
|
|
|
@ -139,7 +139,7 @@ class CoreLocation(object):
|
|||
"""
|
||||
# convert lat/lon to UTM coordinates in meters
|
||||
e, n, zonen, zonel = utm.from_latlon(lat, lon)
|
||||
rlat, rlon, ralt = self.refgeo
|
||||
_rlat, _rlon, ralt = self.refgeo
|
||||
xshift = self.geteastingshift(zonen, zonel)
|
||||
if xshift is None:
|
||||
xm = e - self.refutm[1]
|
||||
|
@ -180,11 +180,11 @@ class CoreLocation(object):
|
|||
if z in self.zoneshifts and self.zoneshifts[z][0] is not None:
|
||||
return self.zoneshifts[z][0]
|
||||
|
||||
rlat, rlon, ralt = self.refgeo
|
||||
rlat, rlon, _ralt = self.refgeo
|
||||
# ea. zone is 6deg band
|
||||
lon2 = rlon + 6 * (zonen - rzonen)
|
||||
# ignore northing
|
||||
e2, n2, zonen2, zonel2 = utm.from_latlon(rlat, lon2)
|
||||
e2, _n2, _zonen2, _zonel2 = utm.from_latlon(rlat, lon2)
|
||||
# NOTE: great circle distance used here, not reference ellipsoid!
|
||||
xshift = utm.haversine(rlon, rlat, lon2, rlat) - e2
|
||||
# cache the return value
|
||||
|
@ -216,12 +216,12 @@ class CoreLocation(object):
|
|||
if z in self.zoneshifts and self.zoneshifts[z][1] is not None:
|
||||
return self.zoneshifts[z][1]
|
||||
|
||||
rlat, rlon, ralt = self.refgeo
|
||||
rlat, rlon, _ralt = self.refgeo
|
||||
# zonemap is used to calculate degrees difference between zone letters
|
||||
latshift = self.zonemap[zonel] - self.zonemap[rzonel]
|
||||
# ea. latitude band is 8deg high
|
||||
lat2 = rlat + latshift
|
||||
e2, n2, zonen2, zonel2 = utm.from_latlon(lat2, rlon)
|
||||
_e2, n2, _zonen2, _zonel2 = utm.from_latlon(lat2, rlon)
|
||||
# NOTE: great circle distance used here, not reference ellipsoid
|
||||
yshift = -(utm.haversine(rlon, rlat, rlon, lat2) + n2)
|
||||
# cache the return value
|
||||
|
@ -244,12 +244,12 @@ class CoreLocation(object):
|
|||
:rtype: tuple
|
||||
"""
|
||||
zone = self.refutm[0]
|
||||
rlat, rlon, ralt = self.refgeo
|
||||
rlat, rlon, _ralt = self.refgeo
|
||||
if e > 834000 or e < 166000:
|
||||
num_zones = (int(e) - 166000) / (utm.R / 10)
|
||||
# estimate number of zones to shift, E (positive) or W (negative)
|
||||
rlon2 = self.refgeo[1] + (num_zones * 6)
|
||||
e2, n2, zonen2, zonel2 = utm.from_latlon(rlat, rlon2)
|
||||
_e2, _n2, zonen2, zonel2 = utm.from_latlon(rlat, rlon2)
|
||||
xshift = utm.haversine(rlon, rlat, rlon2, rlat)
|
||||
# after >3 zones away from refpt, the above estimate won't work
|
||||
# (the above estimate could be improved)
|
||||
|
@ -257,7 +257,7 @@ class CoreLocation(object):
|
|||
# move one more zone away
|
||||
num_zones = (abs(num_zones) + 1) * (abs(num_zones) / num_zones)
|
||||
rlon2 = self.refgeo[1] + (num_zones * 6)
|
||||
e2, n2, zonen2, zonel2 = utm.from_latlon(rlat, rlon2)
|
||||
_e2, _n2, zonen2, zonel2 = utm.from_latlon(rlat, rlon2)
|
||||
xshift = utm.haversine(rlon, rlat, rlon2, rlat)
|
||||
e = e - xshift
|
||||
zone = (zonen2, zonel2)
|
||||
|
|
|
@ -155,7 +155,8 @@ class EventLoop(object):
|
|||
schedule = True
|
||||
break
|
||||
event = heapq.heappop(self.queue)
|
||||
assert event.time <= now
|
||||
if event.time > now:
|
||||
raise ValueError("invalid event time: %s > %s", event.time, now)
|
||||
event.run()
|
||||
|
||||
with self.lock:
|
||||
|
@ -170,11 +171,13 @@ class EventLoop(object):
|
|||
:return: nothing
|
||||
"""
|
||||
with self.lock:
|
||||
assert self.running
|
||||
if not self.running:
|
||||
raise ValueError("scheduling event while not running")
|
||||
if not self.queue:
|
||||
return
|
||||
delay = self.queue[0].time - time.time()
|
||||
assert self.timer is None
|
||||
if self.timer:
|
||||
raise ValueError("timer was already set")
|
||||
self.timer = Timer(delay, self.__run_events)
|
||||
self.timer.daemon = True
|
||||
self.timer.start()
|
||||
|
|
|
@ -31,7 +31,7 @@ class MacAddress(object):
|
|||
:return: string representation
|
||||
:rtype: str
|
||||
"""
|
||||
return ":".join(map(lambda x: "%02x" % ord(x), self.addr))
|
||||
return ":".join("%02x" % ord(x) for x in self.addr)
|
||||
|
||||
def to_link_local(self):
|
||||
"""
|
||||
|
@ -61,7 +61,7 @@ class MacAddress(object):
|
|||
:return: mac address class
|
||||
:rtype: MacAddress
|
||||
"""
|
||||
addr = "".join(map(lambda x: chr(int(x, 16)), s.split(":")))
|
||||
addr = "".join(chr(int(x, 16)) for x in s.split(":"))
|
||||
return cls(addr)
|
||||
|
||||
@classmethod
|
||||
|
@ -154,14 +154,14 @@ class IpAddress(object):
|
|||
logger.exception("error during addition")
|
||||
return NotImplemented
|
||||
|
||||
tmp = map(lambda x: ord(x), self.addr)
|
||||
tmp = [ord(x) for x in self.addr]
|
||||
for i in xrange(len(tmp) - 1, -1, -1):
|
||||
x = tmp[i] + carry
|
||||
tmp[i] = x & 0xff
|
||||
carry = x >> 8
|
||||
if carry == 0:
|
||||
break
|
||||
addr = "".join(map(lambda x: chr(x), tmp))
|
||||
addr = "".join(chr(x) for x in tmp)
|
||||
return self.__class__(self.af, addr)
|
||||
|
||||
def __sub__(self, other):
|
||||
|
@ -200,8 +200,8 @@ class IpAddress(object):
|
|||
:return: integer value
|
||||
:rtype: int
|
||||
"""
|
||||
bin = socket.inet_pton(AF_INET, s)
|
||||
return struct.unpack("!I", bin)[0]
|
||||
value = socket.inet_pton(AF_INET, s)
|
||||
return struct.unpack("!I", value)[0]
|
||||
|
||||
|
||||
class IpPrefix(object):
|
||||
|
|
|
@ -293,10 +293,10 @@ def file_demunge(pathname, header):
|
|||
start = None
|
||||
end = None
|
||||
|
||||
for i in range(len(lines)):
|
||||
if lines[i] == "# BEGIN %s\n" % header:
|
||||
for i, line in enumerate(lines):
|
||||
if line == "# BEGIN %s\n" % header:
|
||||
start = i
|
||||
elif lines[i] == "# END %s\n" % header:
|
||||
elif line == "# END %s\n" % header:
|
||||
end = i + 1
|
||||
|
||||
if start is None or end is None:
|
||||
|
|
|
@ -211,9 +211,7 @@ class PtpNet(LxBrNet):
|
|||
if len(self._netif) != 2:
|
||||
return all_links
|
||||
|
||||
if1, if2 = self._netif.items()
|
||||
if1 = if1[1]
|
||||
if2 = if2[1]
|
||||
if1, if2 = self._netif.values()
|
||||
|
||||
unidirectional = 0
|
||||
if if1.getparams() != if2.getparams():
|
||||
|
@ -224,7 +222,7 @@ class PtpNet(LxBrNet):
|
|||
interface1_ip6 = None
|
||||
interface1_ip6_mask = None
|
||||
for address in if1.addrlist:
|
||||
ip, sep, mask = address.partition("/")
|
||||
ip, _sep, mask = address.partition("/")
|
||||
mask = int(mask)
|
||||
if ipaddress.is_ipv4_address(ip):
|
||||
family = AF_INET
|
||||
|
@ -242,7 +240,7 @@ class PtpNet(LxBrNet):
|
|||
interface2_ip6 = None
|
||||
interface2_ip6_mask = None
|
||||
for address in if2.addrlist:
|
||||
ip, sep, mask = address.partition("/")
|
||||
ip, _sep, mask = address.partition("/")
|
||||
mask = int(mask)
|
||||
if ipaddress.is_ipv4_address(ip):
|
||||
family = AF_INET
|
||||
|
|
|
@ -449,9 +449,7 @@ class OvsPtpNet(OvsNet):
|
|||
if len(self._netif) != 2:
|
||||
return all_links
|
||||
|
||||
if1, if2 = self._netif.items()
|
||||
if1 = if1[1]
|
||||
if2 = if2[1]
|
||||
if1, if2 = self._netif.values()
|
||||
|
||||
unidirectional = 0
|
||||
if if1.getparams() != if2.getparams():
|
||||
|
@ -462,7 +460,7 @@ class OvsPtpNet(OvsNet):
|
|||
interface1_ip6 = None
|
||||
interface1_ip6_mask = None
|
||||
for address in if1.addrlist:
|
||||
ip, sep, mask = address.partition("/")
|
||||
ip, _sep, mask = address.partition("/")
|
||||
mask = int(mask)
|
||||
if ipaddress.is_ipv4_address(ip):
|
||||
family = AF_INET
|
||||
|
@ -480,7 +478,7 @@ class OvsPtpNet(OvsNet):
|
|||
interface2_ip6 = None
|
||||
interface2_ip6_mask = None
|
||||
for address in if2.addrlist:
|
||||
ip, sep, mask = address.partition("/")
|
||||
ip, _sep, mask = address.partition("/")
|
||||
mask = int(mask)
|
||||
if ipaddress.is_ipv4_address(ip):
|
||||
family = AF_INET
|
||||
|
|
|
@ -140,11 +140,9 @@ class EbtablesQueue(object):
|
|||
while self.doupdateloop:
|
||||
with self.updatelock:
|
||||
for wlan in self.updates:
|
||||
"""
|
||||
Check if wlan is from a previously closed session. Because of the
|
||||
rate limiting scheme employed here, this may happen if a new session
|
||||
is started soon after closing a previous session.
|
||||
"""
|
||||
# Check if wlan is from a previously closed session. Because of the
|
||||
# rate limiting scheme employed here, this may happen if a new session
|
||||
# is started soon after closing a previous session.
|
||||
# TODO: if these are WlanNodes, this will never throw an exception
|
||||
try:
|
||||
wlan.session
|
||||
|
|
|
@ -364,7 +364,7 @@ class SimpleLxcNode(PyCoreNode):
|
|||
if self.up:
|
||||
self.check_cmd([constants.IP_BIN, "addr", "del", str(addr), "dev", self.ifname(ifindex)])
|
||||
|
||||
def delalladdr(self, ifindex, address_types=valid_address_types):
|
||||
def delalladdr(self, ifindex, address_types=None):
|
||||
"""
|
||||
Delete all addresses from an interface.
|
||||
|
||||
|
@ -373,6 +373,9 @@ class SimpleLxcNode(PyCoreNode):
|
|||
:return: nothing
|
||||
:raises CoreCommandError: when a non-zero exit status occurs
|
||||
"""
|
||||
if not address_types:
|
||||
address_types = self.valid_address_types
|
||||
|
||||
interface_name = self.ifname(ifindex)
|
||||
addresses = self.client.getaddr(interface_name, rescan=True)
|
||||
|
||||
|
@ -570,7 +573,7 @@ class LxcNode(SimpleLxcNode):
|
|||
:rtype: file
|
||||
"""
|
||||
hostfilename = self.hostfilename(filename)
|
||||
dirname, basename = os.path.split(hostfilename)
|
||||
dirname, _basename = os.path.split(hostfilename)
|
||||
if not os.path.isdir(dirname):
|
||||
os.makedirs(dirname, mode=0755)
|
||||
return open(hostfilename, mode)
|
||||
|
|
|
@ -35,7 +35,7 @@ class PhysicalNode(PyCoreNode):
|
|||
|
||||
with self.lock:
|
||||
while self._mounts:
|
||||
source, target = self._mounts.pop(-1)
|
||||
_source, target = self._mounts.pop(-1)
|
||||
self.umount(target)
|
||||
|
||||
for netif in self.netifs():
|
||||
|
|
|
@ -183,10 +183,10 @@ class Sdt(object):
|
|||
if not self.cmd("path \"%s/icons/normal\"" % constants.CORE_DATA_DIR):
|
||||
return False
|
||||
# send node type to icon mappings
|
||||
for type, icon in self.DEFAULT_SPRITES:
|
||||
if not self.cmd("sprite %s image %s" % (type, icon)):
|
||||
for node_type, icon in self.DEFAULT_SPRITES:
|
||||
if not self.cmd("sprite %s image %s" % (node_type, icon)):
|
||||
return False
|
||||
(lat, long) = self.session.location.refgeo[:2]
|
||||
lat, long = self.session.location.refgeo[:2]
|
||||
return self.cmd("flyto %.6f,%.6f,%d" % (long, lat, self.DEFAULT_ALT))
|
||||
|
||||
def disconnect(self):
|
||||
|
@ -238,7 +238,7 @@ class Sdt(object):
|
|||
self.connected = False
|
||||
return False
|
||||
|
||||
def updatenode(self, nodenum, flags, x, y, z, name=None, type=None, icon=None):
|
||||
def updatenode(self, nodenum, flags, x, y, z, name=None, node_type=None, icon=None):
|
||||
"""
|
||||
Node is updated from a Node Message or mobility script.
|
||||
|
||||
|
@ -248,7 +248,7 @@ class Sdt(object):
|
|||
:param y: y position
|
||||
:param z: z position
|
||||
:param str name: node name
|
||||
:param type: node type
|
||||
:param node_type: node type
|
||||
:param icon: node icon
|
||||
:return: nothing
|
||||
"""
|
||||
|
@ -263,11 +263,11 @@ class Sdt(object):
|
|||
pos = "pos %.6f,%.6f,%.6f" % (lon, lat, alt)
|
||||
if flags & MessageFlags.ADD.value:
|
||||
if icon is not None:
|
||||
type = name
|
||||
node_type = name
|
||||
icon = icon.replace("$CORE_DATA_DIR", constants.CORE_DATA_DIR)
|
||||
icon = icon.replace("$CORE_CONF_DIR", constants.CORE_CONF_DIR)
|
||||
self.cmd("sprite %s image %s" % (type, icon))
|
||||
self.cmd("node %d type %s label on,\"%s\" %s" % (nodenum, type, name, pos))
|
||||
self.cmd("node %d type %s label on,\"%s\" %s" % (nodenum, node_type, name, pos))
|
||||
else:
|
||||
self.cmd("node %d %s" % (nodenum, pos))
|
||||
|
||||
|
@ -403,12 +403,12 @@ class Sdt(object):
|
|||
nodetype == NodeTypes.PHYSICAL.value:
|
||||
if model is None:
|
||||
model = "router"
|
||||
type = model
|
||||
nodetype = model
|
||||
elif nodetype is not None:
|
||||
type = nodeutils.get_node_class(NodeTypes(nodetype)).type
|
||||
nodetype = nodeutils.get_node_class(NodeTypes(nodetype)).type
|
||||
net = True
|
||||
else:
|
||||
type = None
|
||||
nodetype = None
|
||||
|
||||
try:
|
||||
node = self.session.get_object(nodenum)
|
||||
|
@ -421,15 +421,15 @@ class Sdt(object):
|
|||
remote = self.remotes[nodenum]
|
||||
if name is None:
|
||||
name = remote.name
|
||||
if type is None:
|
||||
type = remote.type
|
||||
if nodetype is None:
|
||||
nodetype = remote.type
|
||||
if icon is None:
|
||||
icon = remote.icon
|
||||
else:
|
||||
remote = Bunch(objid=nodenum, type=type, icon=icon, name=name, net=net, links=set())
|
||||
remote = Bunch(objid=nodenum, type=nodetype, icon=icon, name=name, net=net, links=set())
|
||||
self.remotes[nodenum] = remote
|
||||
remote.pos = (x, y, z)
|
||||
self.updatenode(nodenum, msg.flags, x, y, z, name, type, icon)
|
||||
self.updatenode(nodenum, msg.flags, x, y, z, name, nodetype, icon)
|
||||
|
||||
def handlelinkmsg(self, msg):
|
||||
"""
|
||||
|
@ -467,8 +467,8 @@ class Sdt(object):
|
|||
:rtype: bool
|
||||
"""
|
||||
if nodenum in self.remotes:
|
||||
type = self.remotes[nodenum].type
|
||||
if type in ("wlan", "emane"):
|
||||
node_type = self.remotes[nodenum].type
|
||||
if node_type in ("wlan", "emane"):
|
||||
return True
|
||||
else:
|
||||
try:
|
||||
|
|
|
@ -138,7 +138,7 @@ class ServiceShim(object):
|
|||
if not service.custom:
|
||||
valmap[1] = service.get_configs(node)
|
||||
valmap[3] = service.get_startup(node)
|
||||
vals = map(lambda a, b: "%s=%s" % (a, str(b)), cls.keys, valmap)
|
||||
vals = ["%s=%s" % (x, y) for x, y in zip(cls.keys, valmap)]
|
||||
return "|".join(vals)
|
||||
|
||||
@classmethod
|
||||
|
@ -469,7 +469,7 @@ class CoreServices(object):
|
|||
try:
|
||||
node.privatedir(directory)
|
||||
except (CoreCommandError, ValueError) as e:
|
||||
logger.warn("error mounting private dir '%s' for service '%s': %s",
|
||||
logger.warn("error mounting private dir '%s' for service '%s': %s",
|
||||
directory, service.name, e)
|
||||
|
||||
# create service files
|
||||
|
|
|
@ -602,8 +602,7 @@ class MgenActor(NrlService):
|
|||
comments = ""
|
||||
cmd = "mgenBasicActor.py -n %s -a 0.0.0.0" % node.name
|
||||
|
||||
servicenames = map(lambda x: x.name, node.services)
|
||||
netifs = filter(lambda x: not getattr(x, 'control', False), node.netifs())
|
||||
netifs = [x for x in node.netifs() if not getattr(x, "control", False)]
|
||||
if len(netifs) == 0:
|
||||
return ""
|
||||
|
||||
|
|
|
@ -551,7 +551,6 @@ class Babel(QuaggaService):
|
|||
|
||||
@classmethod
|
||||
def generatequaggaifcconfig(cls, node, ifc):
|
||||
type = "wired"
|
||||
if ifc.net and ifc.net.linktype == LinkTypes.WIRELESS.value:
|
||||
return " babel wireless\n no babel split-horizon\n"
|
||||
else:
|
||||
|
|
|
@ -35,12 +35,6 @@ class OvsService(SdnService):
|
|||
if s.name == "zebra":
|
||||
has_zebra = 1
|
||||
|
||||
# Check whether the node is running an SDN controller
|
||||
has_sdn_ctrlr = 0
|
||||
for s in node.services:
|
||||
if s.name == "ryuService":
|
||||
has_sdn_ctrlr = 1
|
||||
|
||||
cfg = "#!/bin/sh\n"
|
||||
cfg += "# auto-generated by OvsService (OvsService.py)\n"
|
||||
cfg += "/etc/init.d/openvswitch-switch start < /dev/null\n"
|
||||
|
|
|
@ -107,11 +107,6 @@ ${UCARP_EXEC} -B ${UCARP_OPTS}
|
|||
"""
|
||||
Generate a shell script used to boot the Ucarp daemons.
|
||||
"""
|
||||
|
||||
try:
|
||||
ucarp_bin = node.session.cfg['ucarp_bin']
|
||||
except KeyError:
|
||||
ucarp_bin = "/usr/sbin/ucarp"
|
||||
return """\
|
||||
#!/bin/sh
|
||||
# Location of the UCARP config directory
|
||||
|
@ -129,11 +124,6 @@ ${UCARP_CFGDIR}/default.sh
|
|||
"""
|
||||
Generate a shell script used to start the virtual ip
|
||||
"""
|
||||
try:
|
||||
ucarp_bin = node.session.cfg['ucarp_bin']
|
||||
except KeyError:
|
||||
ucarp_bin = "/usr/sbin/ucarp"
|
||||
|
||||
return """\
|
||||
#!/bin/bash
|
||||
|
||||
|
@ -156,10 +146,6 @@ fi
|
|||
"""
|
||||
Generate a shell script used to stop the virtual ip
|
||||
"""
|
||||
try:
|
||||
ucarp_bin = node.session.cfg['ucarp_bin']
|
||||
except KeyError:
|
||||
ucarp_bin = "/usr/sbin/ucarp"
|
||||
return """\
|
||||
#!/bin/bash
|
||||
|
||||
|
|
|
@ -83,10 +83,8 @@ class DefaultRouteService(UtilService):
|
|||
def addrstr(x):
|
||||
if x.find(":") >= 0:
|
||||
net = Ipv6Prefix(x)
|
||||
fam = "inet6 ::"
|
||||
else:
|
||||
net = Ipv4Prefix(x)
|
||||
fam = "inet 0.0.0.0"
|
||||
if net.max_addr() == net.min_addr():
|
||||
return ""
|
||||
else:
|
||||
|
@ -145,11 +143,9 @@ class StaticRouteService(UtilService):
|
|||
def routestr(x):
|
||||
if x.find(":") >= 0:
|
||||
net = Ipv6Prefix(x)
|
||||
fam = "inet6"
|
||||
dst = "3ffe:4::/64"
|
||||
else:
|
||||
net = Ipv4Prefix(x)
|
||||
fam = "inet"
|
||||
dst = "10.9.8.0/24"
|
||||
if net.max_addr() == net.min_addr():
|
||||
return ""
|
||||
|
|
|
@ -252,8 +252,9 @@ class Session(object):
|
|||
hooks = self._hooks.get(state, [])
|
||||
|
||||
# execute all state hooks
|
||||
for hook in hooks:
|
||||
self.run_hook(hook)
|
||||
if hooks:
|
||||
for hook in hooks:
|
||||
self.run_hook(hook)
|
||||
else:
|
||||
logger.info("no state hooks for %s", state)
|
||||
|
||||
|
@ -269,7 +270,7 @@ class Session(object):
|
|||
"""
|
||||
logger.info("setting state hook: %s - %s from %s", hook_type, file_name, source_name)
|
||||
|
||||
hook_id, state = hook_type.split(':')[:2]
|
||||
_hook_id, state = hook_type.split(':')[:2]
|
||||
if not state.isdigit():
|
||||
logger.error("error setting hook having state '%s'", state)
|
||||
return
|
||||
|
@ -352,7 +353,8 @@ class Session(object):
|
|||
:return: nothing
|
||||
"""
|
||||
hooks = self._state_hooks.setdefault(state, [])
|
||||
assert hook not in hooks
|
||||
if hook in hooks:
|
||||
raise ValueError("attempting to add duplicate state hook")
|
||||
hooks.append(hook)
|
||||
|
||||
if self.state == state:
|
||||
|
@ -629,13 +631,10 @@ class Session(object):
|
|||
"""
|
||||
|
||||
with self._objects_lock:
|
||||
count = len(filter(lambda x: not nodeutils.is_node(x, (NodeTypes.PEER_TO_PEER, NodeTypes.CONTROL_NET)),
|
||||
self.objects))
|
||||
count = len([x for x in self.objects if not nodeutils.is_node(x, (NodeTypes.PEER_TO_PEER, NodeTypes.CONTROL_NET))])
|
||||
|
||||
# on Linux, GreTapBridges are auto-created, not part of GUI's node count
|
||||
count -= len(filter(
|
||||
lambda (x): nodeutils.is_node(x, NodeTypes.TAP_BRIDGE) and not nodeutils.is_node(x, NodeTypes.TUNNEL),
|
||||
self.objects))
|
||||
count -= len([x for x in self.objects if nodeutils.is_node(x, NodeTypes.TAP_BRIDGE) and not nodeutils.is_node(x, NodeTypes.TUNNEL)])
|
||||
|
||||
return count
|
||||
|
||||
|
|
|
@ -6,7 +6,6 @@ from core.emulator.emudata import InterfaceData
|
|||
from core.emulator.emudata import LinkOptions
|
||||
from core.emulator.emudata import NodeOptions
|
||||
from core.enumerations import NodeTypes
|
||||
from core.misc import ipaddress
|
||||
from core.misc import nodeutils
|
||||
from core.misc.ipaddress import MacAddress
|
||||
from core.netns import nodes
|
||||
|
@ -98,79 +97,6 @@ def add_configuration(parent, name, value):
|
|||
add_attribute(config_element, "value", value)
|
||||
|
||||
|
||||
def get_endpoints(node):
|
||||
endpoints = []
|
||||
for interface in node.netifs(sort=True):
|
||||
endpoint = get_endpoint(node, interface)
|
||||
endpoints.append(endpoint)
|
||||
return endpoints
|
||||
|
||||
|
||||
def get_endpoint(node, interface):
|
||||
l2devport = None
|
||||
othernet = getattr(interface, "othernet", None)
|
||||
|
||||
# reference interface of node that is part of this network
|
||||
if interface.net.objid == node.objid and interface.node:
|
||||
params = interface.getparams()
|
||||
if nodeutils.is_node(interface.net, (NodeTypes.HUB, NodeTypes.SWITCH)):
|
||||
l2devport = "%s/e%s" % (interface.net.name, interface.netindex)
|
||||
endpoint_id = "%s/%s" % (interface.node.name, interface.name)
|
||||
endpoint = Endpoint(
|
||||
node,
|
||||
interface,
|
||||
"interface",
|
||||
endpoint_id,
|
||||
l2devport,
|
||||
params
|
||||
)
|
||||
# references another node connected to this network
|
||||
elif othernet and othernet.objid == node.objid:
|
||||
interface.swapparams("_params_up")
|
||||
params = interface.getparams()
|
||||
interface.swapparams("_params_up")
|
||||
l2devport = "%s/e%s" % (othernet.name, interface.netindex)
|
||||
endpoint_id = "%s/%s/%s" % (node.name, interface.node.name, interface.netindex)
|
||||
endpoint = Endpoint(
|
||||
interface.net,
|
||||
interface,
|
||||
"interface",
|
||||
endpoint_id,
|
||||
l2devport,
|
||||
params
|
||||
)
|
||||
else:
|
||||
endpoint = Endpoint(
|
||||
node,
|
||||
interface,
|
||||
)
|
||||
|
||||
return endpoint
|
||||
|
||||
|
||||
def get_downstream_l2_devices(node):
|
||||
all_endpoints = []
|
||||
l2_devices = [node]
|
||||
current_endpoint = get_endpoints(node)
|
||||
all_endpoints.extend(current_endpoint)
|
||||
for endpoint in current_endpoint:
|
||||
if endpoint.type and endpoint.network.objid != node.objid:
|
||||
new_l2_devices, new_endpoints = get_downstream_l2_devices(endpoint.network)
|
||||
l2_devices.extend(new_l2_devices)
|
||||
all_endpoints.extend(new_endpoints)
|
||||
return l2_devices, all_endpoints
|
||||
|
||||
|
||||
class Endpoint(object):
|
||||
def __init__(self, network, interface, _type=None, _id=None, l2devport=None, params=None):
|
||||
self.network = network
|
||||
self.interface = interface
|
||||
self.type = _type
|
||||
self.id = _id
|
||||
self.l2devport = l2devport
|
||||
self.params = params
|
||||
|
||||
|
||||
class NodeElement(object):
|
||||
def __init__(self, session, node, element_name):
|
||||
self.session = session
|
||||
|
@ -198,50 +124,6 @@ class NodeElement(object):
|
|||
add_attribute(position, "alt", alt)
|
||||
|
||||
|
||||
class InterfaceElement(object):
|
||||
def __init__(self, session, node, interface):
|
||||
self.session = session
|
||||
self.node = node
|
||||
self.interface = interface
|
||||
self.element = etree.Element("interface")
|
||||
add_attribute(self.element, "id", interface.netindex)
|
||||
add_attribute(self.element, "name", interface.name)
|
||||
mac = etree.SubElement(self.element, "mac")
|
||||
mac.text = str(interface.hwaddr)
|
||||
self.add_mtu()
|
||||
self.addresses = etree.SubElement(self.element, "addresses")
|
||||
self.add_addresses()
|
||||
self.add_model()
|
||||
|
||||
def add_mtu(self):
|
||||
# check to add mtu
|
||||
if self.interface.mtu and self.interface.mtu != 1500:
|
||||
add_attribute(self.element, "mtu", self.interface.mtu)
|
||||
|
||||
def add_model(self):
|
||||
# check for emane specific interface configuration
|
||||
net_model = None
|
||||
if self.interface.net and hasattr(self.interface.net, "model"):
|
||||
net_model = self.interface.net.model
|
||||
|
||||
if net_model and net_model.name.startswith("emane_"):
|
||||
config = self.session.emane.getifcconfig(self.node.objid, self.interface, net_model.name)
|
||||
if config:
|
||||
emane_element = create_emane_model_config(net_model, config)
|
||||
self.element.append(emane_element)
|
||||
|
||||
def add_addresses(self):
|
||||
for address in self.interface.addrlist:
|
||||
ip, mask = address.split("/")
|
||||
if ipaddress.is_ipv4_address(ip):
|
||||
address_type = "IPv4"
|
||||
else:
|
||||
address_type = "IPv6"
|
||||
address_element = etree.SubElement(self.addresses, "address")
|
||||
add_attribute(address_element, "type", address_type)
|
||||
address_element.text = str(address)
|
||||
|
||||
|
||||
class ServiceElement(object):
|
||||
def __init__(self, service):
|
||||
self.service = service
|
||||
|
@ -309,7 +191,6 @@ class DeviceElement(NodeElement):
|
|||
def __init__(self, session, node):
|
||||
super(DeviceElement, self).__init__(session, node, "device")
|
||||
add_attribute(self.element, "type", node.type)
|
||||
# self.add_interfaces()
|
||||
self.add_services()
|
||||
|
||||
def add_services(self):
|
||||
|
@ -320,15 +201,6 @@ class DeviceElement(NodeElement):
|
|||
if service_elements.getchildren():
|
||||
self.element.append(service_elements)
|
||||
|
||||
def add_interfaces(self):
|
||||
interfaces = etree.Element("interfaces")
|
||||
for interface in self.node.netifs(sort=True):
|
||||
interface_element = InterfaceElement(self.session, self.node, interface)
|
||||
interfaces.append(interface_element.element)
|
||||
|
||||
if interfaces.getchildren():
|
||||
self.element.append(interfaces)
|
||||
|
||||
|
||||
class NetworkElement(NodeElement):
|
||||
def __init__(self, session, node):
|
||||
|
@ -343,9 +215,6 @@ class NetworkElement(NodeElement):
|
|||
if grekey and grekey is not None:
|
||||
add_attribute(self.element, "grekey", grekey)
|
||||
self.add_type()
|
||||
# self.endpoints = get_endpoints(self.node)
|
||||
# self.l2_devices = self.get_l2_devices()
|
||||
# self.add_configs()
|
||||
|
||||
def add_type(self):
|
||||
if self.node.apitype:
|
||||
|
@ -354,35 +223,6 @@ class NetworkElement(NodeElement):
|
|||
node_type = self.node.__class__.__name__
|
||||
add_attribute(self.element, "type", node_type)
|
||||
|
||||
def get_l2_devices(self):
|
||||
l2_devices = []
|
||||
found_l2_devices = []
|
||||
found_endpoints = []
|
||||
if nodeutils.is_node(self.node, (NodeTypes.SWITCH, NodeTypes.HUB)):
|
||||
for endpoint in self.endpoints:
|
||||
if endpoint.type and endpoint.network.objid != self.node.objid:
|
||||
downstream_l2_devices, downstream_endpoints = get_downstream_l2_devices(endpoint.network)
|
||||
found_l2_devices.extend(downstream_l2_devices)
|
||||
found_endpoints.extend(downstream_endpoints)
|
||||
|
||||
for l2_device in found_l2_devices:
|
||||
pass
|
||||
|
||||
self.endpoints.extend(found_endpoints)
|
||||
return l2_devices
|
||||
|
||||
def add_peer_to_peer_config(self):
|
||||
pass
|
||||
|
||||
def add_switch_hub_tunnel_config(self):
|
||||
pass
|
||||
|
||||
def add_configs(self):
|
||||
if nodeutils.is_node(self.node, NodeTypes.PEER_TO_PEER):
|
||||
self.add_peer_to_peer_config()
|
||||
elif nodeutils.is_node(self.node, (NodeTypes.SWITCH, NodeTypes.HUB, NodeTypes.TUNNEL)):
|
||||
self.add_switch_hub_tunnel_config()
|
||||
|
||||
|
||||
class CoreXmlWriter(object):
|
||||
def __init__(self, session):
|
||||
|
|
|
@ -49,7 +49,7 @@ def add_emane_interface(host_element, netif, platform_name="p1", transport_name=
|
|||
|
||||
|
||||
def get_address_type(address):
|
||||
addr, slash, prefixlen = address.partition("/")
|
||||
addr, _slash, _prefixlen = address.partition("/")
|
||||
if ipaddress.is_ipv4_address(addr):
|
||||
address_type = "IPv4"
|
||||
elif ipaddress.is_ipv6_address(addr):
|
||||
|
@ -120,20 +120,13 @@ class CoreXmlDeployment(object):
|
|||
return host_element
|
||||
|
||||
def add_virtual_host(self, physical_host, node):
|
||||
assert isinstance(node, PyCoreNode)
|
||||
if not isinstance(node, PyCoreNode):
|
||||
raise TypeError("invalid node type: %s" % node)
|
||||
|
||||
# create virtual host element
|
||||
host_id = "%s/%s" % (physical_host.get("id"), node.name)
|
||||
host_element = etree.SubElement(physical_host, "testHost", id=host_id, name=node.name)
|
||||
|
||||
# TODO: need to inject mapping into device element?
|
||||
self.find_device(node.name)
|
||||
# device = self.find_device(self.root.base_element, obj.name)
|
||||
# if device is None:
|
||||
# logger.warn("corresponding XML device not found for %s", obj.name)
|
||||
# return
|
||||
# add_mapping(device, "testHost", host_id)
|
||||
|
||||
# add host type
|
||||
add_type(host_element, "virtual")
|
||||
|
||||
|
@ -149,7 +142,3 @@ class CoreXmlDeployment(object):
|
|||
for address in netif.addrlist:
|
||||
address_type = get_address_type(address)
|
||||
add_address(parent_element, address_type, address, netif.name)
|
||||
|
||||
# TODO: need to inject mapping in interface?
|
||||
# interface = self.find_interface(device, netif.name)
|
||||
# add_mapping(interface, "nem", nem.getAttribute("id"))
|
||||
|
|
|
@ -1,191 +0,0 @@
|
|||
import os
|
||||
import socket
|
||||
|
||||
from core import constants
|
||||
from core import logger
|
||||
from core.enumerations import NodeTypes
|
||||
from core.misc import ipaddress
|
||||
from core.misc import nodeutils
|
||||
from core.misc import utils
|
||||
from core.netns import nodes
|
||||
from core.xml import xmlutils
|
||||
|
||||
|
||||
class CoreDeploymentWriter(object):
|
||||
def __init__(self, dom, root, session):
|
||||
self.dom = dom
|
||||
self.root = root
|
||||
self.session = session
|
||||
self.hostname = socket.gethostname()
|
||||
|
||||
@staticmethod
|
||||
def get_ipv4_addresses(hostname):
|
||||
if hostname == 'localhost':
|
||||
addr_list = []
|
||||
args = [constants.IP_BIN, '-o', '-f', 'inet', 'addr', 'show']
|
||||
output = utils.check_cmd(args)
|
||||
for line in output.split(os.linesep):
|
||||
split = line.split()
|
||||
if not split:
|
||||
continue
|
||||
addr = split[3]
|
||||
if not addr.startswith('127.'):
|
||||
addr_list.append(addr)
|
||||
return addr_list
|
||||
else:
|
||||
# TODO: handle other hosts
|
||||
raise NotImplementedError
|
||||
|
||||
@staticmethod
|
||||
def get_interface_names(hostname):
|
||||
"""
|
||||
Uses same methodology of get_ipv4_addresses() to get
|
||||
parallel list of interface names to go with ...
|
||||
"""
|
||||
if hostname == 'localhost':
|
||||
iface_list = []
|
||||
args = [constants.IP_BIN, '-o', '-f', 'inet', 'addr', 'show']
|
||||
output = utils.check_cmd(args)
|
||||
for line in output.split(os.linesep):
|
||||
split = line.split()
|
||||
if not split:
|
||||
continue
|
||||
interface_name = split[1]
|
||||
addr = split[3]
|
||||
if not addr.startswith('127.'):
|
||||
iface_list.append(interface_name)
|
||||
return iface_list
|
||||
else:
|
||||
# TODO: handle other hosts
|
||||
raise NotImplementedError
|
||||
|
||||
@staticmethod
|
||||
def find_device(scenario, name):
|
||||
tag_name = ('device', 'host', 'router')
|
||||
for d in xmlutils.iter_descendants_with_attribute(scenario, tag_name, 'name', name):
|
||||
return d
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def find_interface(device, name):
|
||||
for i in xmlutils.iter_descendants_with_attribute(device, 'interface', 'name', name):
|
||||
return i
|
||||
return None
|
||||
|
||||
def add_deployment(self):
|
||||
testbed = self.dom.createElement('container')
|
||||
testbed.setAttribute('name', 'TestBed')
|
||||
testbed.setAttribute('id', 'TestBed')
|
||||
self.root.base_element.appendChild(testbed)
|
||||
nodelist = []
|
||||
for obj in self.session.objects.itervalues():
|
||||
if isinstance(obj, nodes.PyCoreNode):
|
||||
nodelist.append(obj)
|
||||
name = self.hostname
|
||||
ipv4_addresses = self.get_ipv4_addresses('localhost')
|
||||
iface_names = self.get_interface_names('localhost')
|
||||
testhost = self.add_physical_host(testbed, name, ipv4_addresses, iface_names)
|
||||
for n in nodelist:
|
||||
self.add_virtual_host(testhost, n)
|
||||
# TODO: handle other servers
|
||||
# servers = self.session.broker.getservernames()
|
||||
# servers.remove('localhost')
|
||||
|
||||
def add_child_element(self, parent, tag_name):
|
||||
el = self.dom.createElement(tag_name)
|
||||
parent.appendChild(el)
|
||||
return el
|
||||
|
||||
def add_child_element_with_nameattr(self, parent, tag_name, name, setid=True):
|
||||
el = self.add_child_element(parent, tag_name)
|
||||
el.setAttribute('name', name)
|
||||
if setid:
|
||||
el.setAttribute('id', '%s/%s' % (parent.getAttribute('id'), name))
|
||||
return el
|
||||
|
||||
def add_address(self, parent, address_type, address_str, address_iface=None):
|
||||
el = self.add_child_element(parent, 'address')
|
||||
el.setAttribute('type', address_type)
|
||||
if address_iface is not None:
|
||||
el.setAttribute('iface', address_iface)
|
||||
el.appendChild(self.dom.createTextNode(address_str))
|
||||
return el
|
||||
|
||||
def add_type(self, parent, type_str):
|
||||
el = self.add_child_element(parent, 'type')
|
||||
el.appendChild(self.dom.createTextNode(type_str))
|
||||
return el
|
||||
|
||||
def add_platform(self, parent, name):
|
||||
el = self.add_child_element_with_nameattr(parent, 'emanePlatform', name)
|
||||
return el
|
||||
|
||||
def add_transport(self, parent, name):
|
||||
el = self.add_child_element_with_nameattr(parent, 'transport', name)
|
||||
return el
|
||||
|
||||
def add_nem(self, parent, name):
|
||||
el = self.add_child_element_with_nameattr(parent, 'nem', name)
|
||||
return el
|
||||
|
||||
def add_parameter(self, parent, name, val):
|
||||
el = self.add_child_element_with_nameattr(parent, 'parameter', name, False)
|
||||
el.appendChild(self.dom.createTextNode(val))
|
||||
return el
|
||||
|
||||
def add_mapping(self, parent, maptype, mapref):
|
||||
el = self.add_child_element(parent, 'mapping')
|
||||
el.setAttribute('type', maptype)
|
||||
el.setAttribute('ref', mapref)
|
||||
return el
|
||||
|
||||
def add_host(self, parent, name):
|
||||
el = self.add_child_element_with_nameattr(parent, 'testHost', name)
|
||||
return el
|
||||
|
||||
def add_physical_host(self, parent, name, ipv4_addresses, iface_names):
|
||||
el = self.add_host(parent, name)
|
||||
self.add_type(el, 'physical')
|
||||
for i in range(0, len(ipv4_addresses)):
|
||||
addr = ipv4_addresses[i]
|
||||
if iface_names:
|
||||
interface_name = iface_names[i]
|
||||
else:
|
||||
interface_name = None
|
||||
self.add_address(el, 'IPv4', addr, interface_name)
|
||||
return el
|
||||
|
||||
def add_virtual_host(self, parent, obj):
|
||||
assert isinstance(obj, nodes.PyCoreNode)
|
||||
el = self.add_host(parent, obj.name)
|
||||
device = self.find_device(self.root.base_element, obj.name)
|
||||
if device is None:
|
||||
logger.warn('corresponding XML device not found for %s' % obj.name)
|
||||
return
|
||||
self.add_mapping(device, 'testHost', el.getAttribute('id'))
|
||||
self.add_type(el, 'virtual')
|
||||
for netif in obj.netifs():
|
||||
for address in netif.addrlist:
|
||||
addr, slash, prefixlen = address.partition('/')
|
||||
if ipaddress.is_ipv4_address(addr):
|
||||
addr_type = 'IPv4'
|
||||
elif ipaddress.is_ipv6_address(addr):
|
||||
addr_type = 'IPv6'
|
||||
else:
|
||||
raise NotImplementedError
|
||||
self.add_address(el, addr_type, address, netif.name)
|
||||
if nodeutils.is_node(netif.net, NodeTypes.EMANE):
|
||||
nem = self.add_emane_interface(parent, el, netif)
|
||||
interface = self.find_interface(device, netif.name)
|
||||
self.add_mapping(interface, 'nem', nem.getAttribute('id'))
|
||||
return el
|
||||
|
||||
def add_emane_interface(self, physical_host, virtual_host, netif, platform_name='p1', transport_name='t1'):
|
||||
nemid = netif.net.nemidmap[netif]
|
||||
platform = self.add_platform(virtual_host, name=platform_name)
|
||||
transport = self.add_transport(virtual_host, name=transport_name)
|
||||
nem_name = 'nem%s' % nemid
|
||||
nem = self.add_nem(platform, nem_name)
|
||||
self.add_parameter(nem, 'nemid', str(nemid))
|
||||
self.add_mapping(transport, 'nem', nem.getAttribute('id'))
|
||||
return nem
|
|
@ -1,54 +0,0 @@
|
|||
from xml.dom.minidom import parse
|
||||
|
||||
from core.xml.xmlparser0 import CoreDocumentParser0
|
||||
from core.xml.xmlparser1 import CoreDocumentParser1
|
||||
from core.xml.xmlutils import get_first_child_by_tag_name
|
||||
|
||||
|
||||
class CoreVersionParser(object):
|
||||
"""
|
||||
Helper class to check the version of Network Plan document. This
|
||||
simply looks for a "Scenario" element; when present, this
|
||||
indicates a 0.0 version document. The dom member is set in order
|
||||
to prevent parsing a file twice (it can be passed to the
|
||||
appropriate CoreDocumentParser class.)
|
||||
"""
|
||||
|
||||
DEFAULT_SCENARIO_VERSION = '1.0'
|
||||
|
||||
def __init__(self, filename, options):
|
||||
if 'dom' in options:
|
||||
self.dom = options['dom']
|
||||
else:
|
||||
self.dom = parse(filename)
|
||||
scenario = get_first_child_by_tag_name(self.dom, 'scenario')
|
||||
if scenario:
|
||||
version = scenario.getAttribute('version')
|
||||
if not version:
|
||||
version = self.DEFAULT_SCENARIO_VERSION
|
||||
self.version = version
|
||||
elif get_first_child_by_tag_name(self.dom, 'Scenario'):
|
||||
self.version = '0.0'
|
||||
else:
|
||||
self.version = 'unknown'
|
||||
|
||||
|
||||
def core_document_parser(session, filename, options):
|
||||
"""
|
||||
Retrieves the xml document parser.
|
||||
|
||||
:param core.session.Session session: core
|
||||
:param str filename: name of file to save to or load from
|
||||
:param dict options: parsing options
|
||||
:return: xml document parser
|
||||
"""
|
||||
vp = CoreVersionParser(filename, options)
|
||||
if 'dom' not in options:
|
||||
options['dom'] = vp.dom
|
||||
if vp.version == '0.0':
|
||||
doc = CoreDocumentParser0(session, filename, options)
|
||||
elif vp.version == '1.0':
|
||||
doc = CoreDocumentParser1(session, filename, options)
|
||||
else:
|
||||
raise ValueError('unsupported document version: %s' % vp.version)
|
||||
return doc
|
|
@ -1,420 +0,0 @@
|
|||
from xml.dom.minidom import parse
|
||||
|
||||
from core import logger
|
||||
from core.conf import ConfigShim
|
||||
from core.enumerations import NodeTypes
|
||||
from core.misc import nodeutils
|
||||
from core.service import ServiceManager, ServiceShim
|
||||
from core.xml import xmlutils
|
||||
|
||||
|
||||
class CoreDocumentParser0(object):
|
||||
def __init__(self, session, 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.np = xmlutils.get_one_element(self.dom, "NetworkPlan")
|
||||
if self.np is None:
|
||||
raise ValueError, "missing NetworkPlan!"
|
||||
self.mp = xmlutils.get_one_element(self.dom, "MotionPlan")
|
||||
self.sp = xmlutils.get_one_element(self.dom, "ServicePlan")
|
||||
self.meta = xmlutils.get_one_element(self.dom, "CoreMetaData")
|
||||
|
||||
self.coords = self.getmotiondict(self.mp)
|
||||
# link parameters parsed in parsenets(), applied in parsenodes()
|
||||
self.linkparams = {}
|
||||
|
||||
self.parsedefaultservices()
|
||||
self.parseorigin()
|
||||
self.parsenets()
|
||||
self.parsenodes()
|
||||
self.parseservices()
|
||||
self.parsemeta()
|
||||
|
||||
def getmotiondict(self, mp):
|
||||
"""
|
||||
Parse a MotionPlan into a dict with node names for keys and coordinates
|
||||
for values.
|
||||
"""
|
||||
if mp is None:
|
||||
return {}
|
||||
coords = {}
|
||||
for node in mp.getElementsByTagName("Node"):
|
||||
nodename = str(node.getAttribute("name"))
|
||||
if nodename == '':
|
||||
continue
|
||||
for m in node.getElementsByTagName("motion"):
|
||||
if m.getAttribute("type") != "stationary":
|
||||
continue
|
||||
point = m.getElementsByTagName("point")
|
||||
if len(point) == 0:
|
||||
continue
|
||||
txt = point[0].firstChild
|
||||
if txt is None:
|
||||
continue
|
||||
xyz = map(int, txt.nodeValue.split(','))
|
||||
z = None
|
||||
x, y = xyz[0:2]
|
||||
if len(xyz) == 3:
|
||||
z = xyz[2]
|
||||
coords[nodename] = (x, y, z)
|
||||
return coords
|
||||
|
||||
@staticmethod
|
||||
def getcommonattributes(obj):
|
||||
"""
|
||||
Helper to return tuple of attributes common to nodes and nets.
|
||||
"""
|
||||
node_id = obj.getAttribute("id")
|
||||
try:
|
||||
node_id = int(node_id)
|
||||
except:
|
||||
logger.debug("parsing node without integer id: %s", node_id)
|
||||
|
||||
name = str(obj.getAttribute("name"))
|
||||
node_type = str(obj.getAttribute("type"))
|
||||
return node_id, name, node_type
|
||||
|
||||
def parsenets(self):
|
||||
linkednets = []
|
||||
for net in self.np.getElementsByTagName("NetworkDefinition"):
|
||||
node_id, name, node_type = self.getcommonattributes(net)
|
||||
nodecls = xmlutils.xml_type_to_node_class(node_type)
|
||||
if not nodecls:
|
||||
logger.warn("skipping unknown network node '%s' type '%s'", name, node_type)
|
||||
continue
|
||||
n = self.session.add_object(cls=nodecls, objid=node_id, name=name, start=self.start)
|
||||
if name in self.coords:
|
||||
x, y, z = self.coords[name]
|
||||
n.setposition(x, y, z)
|
||||
xmlutils.get_params_set_attrs(net, ("icon", "canvas", "opaque"), n)
|
||||
if hasattr(n, "canvas") and n.canvas is not None:
|
||||
n.canvas = int(n.canvas)
|
||||
# links between two nets (e.g. switch-switch)
|
||||
for ifc in net.getElementsByTagName("interface"):
|
||||
netid = str(ifc.getAttribute("net"))
|
||||
ifcname = str(ifc.getAttribute("name"))
|
||||
linkednets.append((n, netid, ifcname))
|
||||
self.parsemodels(net, n)
|
||||
# link networks together now that they all have been parsed
|
||||
for n, netid, ifcname in linkednets:
|
||||
try:
|
||||
n2 = n.session.get_object_by_name(netid)
|
||||
except KeyError:
|
||||
logger.warn("skipping net %s interface: unknown net %s", n.name, netid)
|
||||
continue
|
||||
upstream = False
|
||||
netif = n.getlinknetif(n2)
|
||||
if netif is None:
|
||||
netif = n2.linknet(n)
|
||||
else:
|
||||
netif.swapparams('_params_up')
|
||||
upstream = True
|
||||
key = (n2.name, ifcname)
|
||||
if key in self.linkparams:
|
||||
for k, v in self.linkparams[key]:
|
||||
netif.setparam(k, v)
|
||||
if upstream:
|
||||
netif.swapparams('_params_up')
|
||||
|
||||
def parsenodes(self):
|
||||
for node in self.np.getElementsByTagName("Node"):
|
||||
id, name, type = self.getcommonattributes(node)
|
||||
if type == "rj45":
|
||||
nodecls = nodeutils.get_node_class(NodeTypes.RJ45)
|
||||
else:
|
||||
nodecls = self.nodecls
|
||||
n = self.session.add_object(cls=nodecls, objid=id, name=name, start=self.start)
|
||||
if name in self.coords:
|
||||
x, y, z = self.coords[name]
|
||||
n.setposition(x, y, z)
|
||||
n.type = type
|
||||
xmlutils.get_params_set_attrs(node, ("icon", "canvas", "opaque"), n)
|
||||
if hasattr(n, "canvas") and n.canvas is not None:
|
||||
n.canvas = int(n.canvas)
|
||||
for ifc in node.getElementsByTagName("interface"):
|
||||
self.parseinterface(n, ifc)
|
||||
|
||||
def parseinterface(self, n, ifc):
|
||||
"""
|
||||
Parse a interface block such as:
|
||||
<interface name="eth0" net="37278">
|
||||
<address type="mac">00:00:00:aa:00:01</address>
|
||||
<address>10.0.0.2/24</address>
|
||||
<address>2001::2/64</address>
|
||||
</interface>
|
||||
"""
|
||||
name = str(ifc.getAttribute("name"))
|
||||
netid = str(ifc.getAttribute("net"))
|
||||
hwaddr = None
|
||||
addrlist = []
|
||||
try:
|
||||
net = n.session.get_object_by_name(netid)
|
||||
except KeyError:
|
||||
logger.warn("skipping node %s interface %s: unknown net %s", n.name, name, netid)
|
||||
return
|
||||
for addr in ifc.getElementsByTagName("address"):
|
||||
addrstr = xmlutils.get_text_child(addr)
|
||||
if addrstr is None:
|
||||
continue
|
||||
if addr.getAttribute("type") == "mac":
|
||||
hwaddr = addrstr
|
||||
else:
|
||||
addrlist.append(addrstr)
|
||||
i = n.newnetif(net, addrlist=addrlist, hwaddr=hwaddr, ifindex=None, ifname=name)
|
||||
for model in ifc.getElementsByTagName("model"):
|
||||
self.parsemodel(model, n, n.objid)
|
||||
key = (n.name, name)
|
||||
if key in self.linkparams:
|
||||
netif = n.netif(i)
|
||||
for k, v in self.linkparams[key]:
|
||||
netif.setparam(k, v)
|
||||
|
||||
def parsemodels(self, dom, obj):
|
||||
"""
|
||||
Mobility/wireless model config is stored in a ConfigurableManager's
|
||||
config dict.
|
||||
"""
|
||||
nodenum = int(dom.getAttribute("id"))
|
||||
for model in dom.getElementsByTagName("model"):
|
||||
self.parsemodel(model, obj, nodenum)
|
||||
|
||||
def parsemodel(self, model, obj, nodenum):
|
||||
"""
|
||||
Mobility/wireless model config is stored in a ConfigurableManager's
|
||||
config dict.
|
||||
"""
|
||||
name = model.getAttribute("name")
|
||||
if name == '':
|
||||
return
|
||||
type = model.getAttribute("type")
|
||||
# convert child text nodes into key=value pairs
|
||||
kvs = xmlutils.get_text_elements_to_list(model)
|
||||
|
||||
mgr = self.session.mobility
|
||||
# TODO: the session.confobj() mechanism could be more generic;
|
||||
# it only allows registering Conf Message callbacks, but here
|
||||
# we want access to the ConfigurableManager, not the callback
|
||||
if name[:5] == "emane":
|
||||
mgr = self.session.emane
|
||||
elif name[:5] == "netem":
|
||||
mgr = None
|
||||
self.parsenetem(model, obj, kvs)
|
||||
|
||||
# TODO: assign other config managers here
|
||||
if mgr:
|
||||
for k, v in kvs:
|
||||
mgr.set_config(k, v, node_id=nodenum, config_type=name)
|
||||
|
||||
def parsenetem(self, model, obj, kvs):
|
||||
"""
|
||||
Determine interface and invoke setparam() using the parsed
|
||||
(key, value) pairs.
|
||||
"""
|
||||
ifname = model.getAttribute("netif")
|
||||
peer = model.getAttribute("peer")
|
||||
key = (peer, ifname)
|
||||
# nodes and interfaces do not exist yet, at this point of the parsing,
|
||||
# save (key, value) pairs for later
|
||||
try:
|
||||
kvs = map(self.numericvalue, kvs)
|
||||
except ValueError:
|
||||
logger.warn("error parsing link parameters for '%s' on '%s'", ifname, peer)
|
||||
self.linkparams[key] = kvs
|
||||
|
||||
@staticmethod
|
||||
def numericvalue(keyvalue):
|
||||
(key, value) = keyvalue
|
||||
if '.' in str(value):
|
||||
value = float(value)
|
||||
else:
|
||||
value = int(value)
|
||||
return key, value
|
||||
|
||||
def parseorigin(self):
|
||||
"""
|
||||
Parse any origin tag from the Mobility Plan and set the CoreLocation
|
||||
reference point appropriately.
|
||||
"""
|
||||
origin = xmlutils.get_one_element(self.mp, "origin")
|
||||
if not origin:
|
||||
return
|
||||
location = self.session.location
|
||||
geo = []
|
||||
attrs = ("lat", "lon", "alt")
|
||||
for i in xrange(3):
|
||||
a = origin.getAttribute(attrs[i])
|
||||
if a is not None:
|
||||
a = float(a)
|
||||
geo.append(a)
|
||||
location.setrefgeo(geo[0], geo[1], geo[2])
|
||||
scale = origin.getAttribute("scale100")
|
||||
if scale is not None and scale:
|
||||
location.refscale = float(scale)
|
||||
point = xmlutils.get_one_element(origin, "point")
|
||||
if point is not None and point.firstChild is not None:
|
||||
xyz = point.firstChild.nodeValue.split(',')
|
||||
if len(xyz) == 2:
|
||||
xyz.append('0.0')
|
||||
if len(xyz) == 3:
|
||||
xyz = map(lambda (x): float(x), xyz)
|
||||
location.refxyz = (xyz[0], xyz[1], xyz[2])
|
||||
|
||||
def parsedefaultservices(self):
|
||||
"""
|
||||
Prior to parsing nodes, use session.services manager to store
|
||||
default services for node types
|
||||
"""
|
||||
for node in self.sp.getElementsByTagName("Node"):
|
||||
type = node.getAttribute("type")
|
||||
if type == '':
|
||||
continue # node-specific service config
|
||||
services = []
|
||||
for service in node.getElementsByTagName("Service"):
|
||||
services.append(str(service.getAttribute("name")))
|
||||
self.session.services.default_services[type] = services
|
||||
logger.info("default services for type %s set to %s" % (type, services))
|
||||
|
||||
def parseservices(self):
|
||||
"""
|
||||
After node objects exist, parse service customizations and add them
|
||||
to the nodes.
|
||||
"""
|
||||
svclists = {}
|
||||
# parse services and store configs into session.services.configs
|
||||
for node in self.sp.getElementsByTagName("Node"):
|
||||
name = node.getAttribute("name")
|
||||
if name == '':
|
||||
continue # node type without name
|
||||
n = self.session.get_object_by_name(name)
|
||||
if n is None:
|
||||
logger.warn("skipping service config for unknown node '%s'" % name)
|
||||
continue
|
||||
for service in node.getElementsByTagName("Service"):
|
||||
svcname = service.getAttribute("name")
|
||||
if self.parseservice(service, n):
|
||||
if n.objid in svclists:
|
||||
svclists[n.objid] += "|" + svcname
|
||||
else:
|
||||
svclists[n.objid] = svcname
|
||||
# nodes in NetworkPlan but not in ServicePlan use the
|
||||
# default services for their type
|
||||
for node in self.np.getElementsByTagName("Node"):
|
||||
id, name, type = self.getcommonattributes(node)
|
||||
if id in svclists:
|
||||
continue # custom config exists
|
||||
else:
|
||||
svclists[int(id)] = None # use defaults
|
||||
|
||||
# associate nodes with services
|
||||
for objid in sorted(svclists.keys()):
|
||||
n = self.session.get_object(objid)
|
||||
services = svclists[objid]
|
||||
if services:
|
||||
services = services.split("|")
|
||||
self.session.services.add_services(node=n, node_type=n.type, services=services)
|
||||
|
||||
def parseservice(self, service, n):
|
||||
"""
|
||||
Use session.services manager to store service customizations before
|
||||
they are added to a node.
|
||||
"""
|
||||
name = service.getAttribute("name")
|
||||
svc = ServiceManager.get(name)
|
||||
if svc is None:
|
||||
return False
|
||||
values = []
|
||||
startup_idx = service.getAttribute("startup_idx")
|
||||
if startup_idx is not None:
|
||||
values.append("startidx=%s" % startup_idx)
|
||||
startup_time = service.getAttribute("start_time")
|
||||
if startup_time is not None:
|
||||
values.append("starttime=%s" % startup_time)
|
||||
dirs = []
|
||||
for dir in service.getElementsByTagName("Directory"):
|
||||
dirname = dir.getAttribute("name")
|
||||
dirs.append(dirname)
|
||||
if len(dirs):
|
||||
values.append("dirs=%s" % dirs)
|
||||
|
||||
startup = []
|
||||
shutdown = []
|
||||
validate = []
|
||||
for cmd in service.getElementsByTagName("Command"):
|
||||
type = cmd.getAttribute("type")
|
||||
cmdstr = xmlutils.get_text_child(cmd)
|
||||
if cmdstr is None:
|
||||
continue
|
||||
if type == "start":
|
||||
startup.append(cmdstr)
|
||||
elif type == "stop":
|
||||
shutdown.append(cmdstr)
|
||||
elif type == "validate":
|
||||
validate.append(cmdstr)
|
||||
if len(startup):
|
||||
values.append("cmdup=%s" % startup)
|
||||
if len(shutdown):
|
||||
values.append("cmddown=%s" % shutdown)
|
||||
if len(validate):
|
||||
values.append("cmdval=%s" % validate)
|
||||
|
||||
files = []
|
||||
for file in service.getElementsByTagName("File"):
|
||||
filename = file.getAttribute("name")
|
||||
files.append(filename)
|
||||
data = xmlutils.get_text_child(file)
|
||||
self.session.services.set_service_file(node_id=n.objid, service_name=name, file_name=filename, data=data)
|
||||
|
||||
if len(files):
|
||||
values.append("files=%s" % files)
|
||||
if not bool(service.getAttribute("custom")):
|
||||
return True
|
||||
self.session.services.set_service(n.objid, svc)
|
||||
# set custom values for custom service
|
||||
svc = self.session.services.get_service(n.objid, None)
|
||||
if not svc:
|
||||
raise ValueError("custom service(%s) for node(%s) does not exist", svc.name, n.objid)
|
||||
values = ConfigShim.str_to_dict("|".join(values))
|
||||
for name, value in values.iteritems():
|
||||
ServiceShim.setvalue(svc, name, value)
|
||||
return True
|
||||
|
||||
def parsehooks(self, hooks):
|
||||
''' Parse hook scripts from XML into session._hooks.
|
||||
'''
|
||||
for hook in hooks.getElementsByTagName("Hook"):
|
||||
filename = hook.getAttribute("name")
|
||||
state = hook.getAttribute("state")
|
||||
data = xmlutils.get_text_child(hook)
|
||||
if data is None:
|
||||
data = "" # allow for empty file
|
||||
type = "hook:%s" % state
|
||||
self.session.set_hook(type, file_name=filename, source_name=None, data=data)
|
||||
|
||||
def parsemeta(self):
|
||||
opt = xmlutils.get_one_element(self.meta, "SessionOptions")
|
||||
if opt:
|
||||
for param in opt.getElementsByTagName("param"):
|
||||
k = str(param.getAttribute("name"))
|
||||
v = str(param.getAttribute("value"))
|
||||
if v == '':
|
||||
v = xmlutils.get_text_child(param) # allow attribute/text for newlines
|
||||
self.session.options.set_config(k, v)
|
||||
hooks = xmlutils.get_one_element(self.meta, "Hooks")
|
||||
if hooks:
|
||||
self.parsehooks(hooks)
|
||||
meta = xmlutils.get_one_element(self.meta, "MetaData")
|
||||
if meta:
|
||||
for param in meta.getElementsByTagName("param"):
|
||||
k = str(param.getAttribute("name"))
|
||||
v = str(param.getAttribute("value"))
|
||||
if v == '':
|
||||
v = xmlutils.get_text_child(param)
|
||||
self.session.metadata.set_config(k, v)
|
|
@ -1,889 +0,0 @@
|
|||
import random
|
||||
from xml.dom.minidom import Node
|
||||
from xml.dom.minidom import parse
|
||||
|
||||
from core import constants
|
||||
from core import logger
|
||||
from core.conf import ConfigShim
|
||||
from core.enumerations import NodeTypes
|
||||
from core.misc import nodeutils
|
||||
from core.misc.ipaddress import MacAddress
|
||||
from core.service import ServiceManager, ServiceShim
|
||||
from core.xml import xmlutils
|
||||
|
||||
|
||||
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(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
|
||||
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.set_model_config(node_id=nodenum, model_name=model_name, config=link_params)
|
||||
|
||||
if mobility_model_name and mobility_params:
|
||||
self.session.mobility.set_model_config(node_id=nodenum, model_name=mobility_model_name,
|
||||
config=mobility_params)
|
||||
|
||||
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.set_service(node.objid, session_service.name)
|
||||
values = ConfigShim.str_to_dict("|".join(values))
|
||||
for key, value in values.iteritems():
|
||||
ServiceShim.setvalue(session_service, key, value)
|
||||
|
||||
# NOTE: if a custom service is used, setservicefile() must be
|
||||
# called after the custom service exists
|
||||
for typestr, filename, data in files:
|
||||
svcname = typestr.split(":")[1]
|
||||
self.session.services.set_service_file(
|
||||
node_id=node.objid,
|
||||
service_name=svcname,
|
||||
file_name=filename,
|
||||
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
|
||||
if services_str:
|
||||
services_str = services_str.split("|")
|
||||
|
||||
self.session.services.add_services(
|
||||
node=node,
|
||||
node_type=node_type,
|
||||
services=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',
|
||||
}
|
||||
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:
|
||||
self.session.options.set_config(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.set_config(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.default_services[t] = s
|
||||
logger.info('default services for node type \'%s\' set to: %s' % (t, s))
|
|
@ -1,36 +0,0 @@
|
|||
"""
|
||||
Helpers for loading and saving XML files. savesessionxml(session, filename) is
|
||||
the main public interface here.
|
||||
"""
|
||||
|
||||
import os.path
|
||||
|
||||
from core.enumerations import NodeTypes
|
||||
from core.misc import nodeutils
|
||||
from core.xml.xmlparser import core_document_parser
|
||||
from core.xml.xmlwriter import core_document_writer
|
||||
|
||||
|
||||
def open_session_xml(session, filename, start=False, nodecls=None):
|
||||
"""
|
||||
Import a session from the EmulationScript XML format.
|
||||
"""
|
||||
|
||||
# set default node class when one is not provided
|
||||
if not nodecls:
|
||||
nodecls = nodeutils.get_node_class(NodeTypes.DEFAULT)
|
||||
|
||||
options = {'start': start, 'nodecls': nodecls}
|
||||
doc = core_document_parser(session, filename, options)
|
||||
if start:
|
||||
session.name = os.path.basename(filename)
|
||||
session.filename = filename
|
||||
session.instantiate()
|
||||
|
||||
|
||||
def save_session_xml(session, filename, version):
|
||||
"""
|
||||
Export a session to the EmulationScript XML format.
|
||||
"""
|
||||
doc = core_document_writer(session, version)
|
||||
doc.writexml(filename)
|
|
@ -1,350 +0,0 @@
|
|||
from xml.dom.minidom import Node
|
||||
|
||||
from core import logger
|
||||
from core.netns import nodes
|
||||
|
||||
|
||||
_NODE_MAP = {
|
||||
nodes.CoreNode.__name__: nodes.CoreNode,
|
||||
nodes.SwitchNode.__name__: nodes.SwitchNode,
|
||||
nodes.HubNode.__name__: nodes.HubNode,
|
||||
nodes.WlanNode.__name__: nodes.WlanNode,
|
||||
nodes.RJ45Node.__name__: nodes.RJ45Node,
|
||||
nodes.TunnelNode.__name__: nodes.TunnelNode,
|
||||
nodes.GreTapBridge.__name__: nodes.GreTapBridge,
|
||||
nodes.PtpNet.__name__: nodes.PtpNet,
|
||||
nodes.CtrlNet.__name__: nodes.CtrlNet
|
||||
}
|
||||
|
||||
|
||||
def add_elements_from_list(dom, parent, iterable, name, attr_name):
|
||||
"""
|
||||
XML helper to iterate through a list and add items to parent using tags
|
||||
of the given name and the item value as an attribute named attr_name.
|
||||
Example: addelementsfromlist(dom, parent, ('a','b','c'), "letter", "value")
|
||||
<parent>
|
||||
<letter value="a"/>
|
||||
<letter value="b"/>
|
||||
<letter value="c"/>
|
||||
</parent>
|
||||
"""
|
||||
for item in iterable:
|
||||
element = dom.createElement(name)
|
||||
element.setAttribute(attr_name, item)
|
||||
parent.appendChild(element)
|
||||
|
||||
|
||||
def add_text_elements_from_list(dom, parent, iterable, name, attrs):
|
||||
"""
|
||||
XML helper to iterate through a list and add items to parent using tags
|
||||
of the given name, attributes specified in the attrs tuple, and having the
|
||||
text of the item within the tags.
|
||||
Example: addtextelementsfromlist(dom, parent, ('a','b','c'), "letter",
|
||||
(('show','True'),))
|
||||
<parent>
|
||||
<letter show="True">a</letter>
|
||||
<letter show="True">b</letter>
|
||||
<letter show="True">c</letter>
|
||||
</parent>
|
||||
"""
|
||||
for item in iterable:
|
||||
element = dom.createElement(name)
|
||||
for k, v in attrs:
|
||||
element.setAttribute(k, v)
|
||||
parent.appendChild(element)
|
||||
txt = dom.createTextNode(item)
|
||||
element.appendChild(txt)
|
||||
|
||||
|
||||
def add_text_elements_from_tuples(dom, parent, iterable, attrs=()):
|
||||
"""
|
||||
XML helper to iterate through a list of tuples and add items to
|
||||
parent using tags named for the first tuple element,
|
||||
attributes specified in the attrs tuple, and having the
|
||||
text of second tuple element.
|
||||
Example: addtextelementsfromtuples(dom, parent,
|
||||
(('first','a'),('second','b'),('third','c')),
|
||||
(('show','True'),))
|
||||
<parent>
|
||||
<first show="True">a</first>
|
||||
<second show="True">b</second>
|
||||
<third show="True">c</third>
|
||||
</parent>
|
||||
"""
|
||||
for name, value in iterable:
|
||||
element = dom.createElement(name)
|
||||
for k, v in attrs:
|
||||
element.setAttribute(k, v)
|
||||
parent.appendChild(element)
|
||||
txt = dom.createTextNode(value)
|
||||
element.appendChild(txt)
|
||||
|
||||
|
||||
def get_text_elements_to_list(parent):
|
||||
"""
|
||||
XML helper to parse child text nodes from the given parent and return
|
||||
a list of (key, value) tuples.
|
||||
"""
|
||||
r = []
|
||||
for n in parent.childNodes:
|
||||
if n.nodeType != Node.ELEMENT_NODE:
|
||||
continue
|
||||
k = str(n.nodeName)
|
||||
# sometimes want None here?
|
||||
v = ''
|
||||
for c in n.childNodes:
|
||||
if c.nodeType != Node.TEXT_NODE:
|
||||
continue
|
||||
v = str(c.nodeValue)
|
||||
break
|
||||
r.append((k, v))
|
||||
return r
|
||||
|
||||
|
||||
def add_param_to_parent(dom, parent, name, value):
|
||||
"""
|
||||
XML helper to add a <param name="name" value="value"/> tag to the parent
|
||||
element, when value is not None.
|
||||
"""
|
||||
if value is None:
|
||||
return None
|
||||
p = dom.createElement("param")
|
||||
parent.appendChild(p)
|
||||
p.setAttribute("name", name)
|
||||
p.setAttribute("value", "%s" % value)
|
||||
return p
|
||||
|
||||
|
||||
def add_text_param_to_parent(dom, parent, name, value):
|
||||
"""
|
||||
XML helper to add a <param name="name">value</param> tag to the parent
|
||||
element, when value is not None.
|
||||
"""
|
||||
if value is None:
|
||||
return None
|
||||
p = dom.createElement("param")
|
||||
parent.appendChild(p)
|
||||
p.setAttribute("name", name)
|
||||
txt = dom.createTextNode(value)
|
||||
p.appendChild(txt)
|
||||
return p
|
||||
|
||||
|
||||
def add_param_list_to_parent(dom, parent, name, values):
|
||||
"""
|
||||
XML helper to return a parameter list and optionally add it to the
|
||||
parent element:
|
||||
<paramlist name="name">
|
||||
<item value="123">
|
||||
<item value="456">
|
||||
</paramlist>
|
||||
"""
|
||||
if values is None:
|
||||
return None
|
||||
p = dom.createElement("paramlist")
|
||||
if parent:
|
||||
parent.appendChild(p)
|
||||
p.setAttribute("name", name)
|
||||
for v in values:
|
||||
item = dom.createElement("item")
|
||||
item.setAttribute("value", str(v))
|
||||
p.appendChild(item)
|
||||
return p
|
||||
|
||||
|
||||
def get_one_element(dom, name):
|
||||
e = dom.getElementsByTagName(name)
|
||||
if len(e) == 0:
|
||||
return None
|
||||
return e[0]
|
||||
|
||||
|
||||
def iter_descendants(dom, max_depth=0):
|
||||
"""
|
||||
Iterate over all descendant element nodes in breadth first order.
|
||||
Only consider nodes up to max_depth deep when max_depth is greater
|
||||
than zero.
|
||||
"""
|
||||
nodes = [dom]
|
||||
depth = 0
|
||||
current_depth_nodes = 1
|
||||
next_depth_nodes = 0
|
||||
while nodes:
|
||||
n = nodes.pop(0)
|
||||
for child in n.childNodes:
|
||||
if child.nodeType == Node.ELEMENT_NODE:
|
||||
yield child
|
||||
nodes.append(child)
|
||||
next_depth_nodes += 1
|
||||
current_depth_nodes -= 1
|
||||
if current_depth_nodes == 0:
|
||||
depth += 1
|
||||
if max_depth > 0 and depth == max_depth:
|
||||
return
|
||||
current_depth_nodes = next_depth_nodes
|
||||
next_depth_nodes = 0
|
||||
|
||||
|
||||
def iter_matching_descendants(dom, match_function, max_depth=0):
|
||||
"""
|
||||
Iterate over descendant elements where matchFunction(descendant)
|
||||
returns true. Only consider nodes up to max_depth deep when
|
||||
max_depth is greater than zero.
|
||||
"""
|
||||
for d in iter_descendants(dom, max_depth):
|
||||
if match_function(d):
|
||||
yield d
|
||||
|
||||
|
||||
def iter_descendants_with_name(dom, tag_name, max_depth=0):
|
||||
"""
|
||||
Iterate over descendant elements whose name is contained in
|
||||
tagName (or is named tagName if tagName is a string). Only
|
||||
consider nodes up to max_depth deep when max_depth is greater than
|
||||
zero.
|
||||
"""
|
||||
if isinstance(tag_name, basestring):
|
||||
tag_name = (tag_name,)
|
||||
|
||||
def match(d):
|
||||
return d.tagName in tag_name
|
||||
|
||||
return iter_matching_descendants(dom, match, max_depth)
|
||||
|
||||
|
||||
def iter_descendants_with_attribute(dom, tag_name, attr_name, attr_value, max_depth=0):
|
||||
"""
|
||||
Iterate over descendant elements whose name is contained in
|
||||
tagName (or is named tagName if tagName is a string) and have an
|
||||
attribute named attrName with value attrValue. Only consider
|
||||
nodes up to max_depth deep when max_depth is greater than zero.
|
||||
"""
|
||||
if isinstance(tag_name, basestring):
|
||||
tag_name = (tag_name,)
|
||||
|
||||
def match(d):
|
||||
return d.tagName in tag_name and \
|
||||
d.getAttribute(attr_name) == attr_value
|
||||
|
||||
return iter_matching_descendants(dom, match, max_depth)
|
||||
|
||||
|
||||
def iter_children(dom, node_type):
|
||||
"""
|
||||
Iterate over all child elements of the given type.
|
||||
"""
|
||||
for child in dom.childNodes:
|
||||
if child.nodeType == node_type:
|
||||
yield child
|
||||
|
||||
|
||||
def get_text_child(dom):
|
||||
"""
|
||||
Return the text node of the given element.
|
||||
"""
|
||||
for child in iter_children(dom, Node.TEXT_NODE):
|
||||
return str(child.nodeValue)
|
||||
return None
|
||||
|
||||
|
||||
def get_child_text_trim(dom):
|
||||
text = get_text_child(dom)
|
||||
if text:
|
||||
text = text.strip()
|
||||
return text
|
||||
|
||||
|
||||
def get_params_set_attrs(dom, param_names, target):
|
||||
"""
|
||||
XML helper to get <param name="name" value="value"/> tags and set
|
||||
the attribute in the target object. String type is used. Target object
|
||||
attribute is unchanged if the XML attribute is not present.
|
||||
"""
|
||||
params = dom.getElementsByTagName("param")
|
||||
for param in params:
|
||||
param_name = param.getAttribute("name")
|
||||
value = param.getAttribute("value")
|
||||
if value is None:
|
||||
# never reached?
|
||||
continue
|
||||
if param_name in param_names:
|
||||
setattr(target, param_name, str(value))
|
||||
|
||||
|
||||
def xml_type_to_node_class(node_type):
|
||||
"""
|
||||
Helper to convert from a type string to a class name in nodes.*.
|
||||
"""
|
||||
logger.error("xml type to node type: %s", node_type)
|
||||
if hasattr(nodes, node_type):
|
||||
return _NODE_MAP[node_type]
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def iter_children_with_name(dom, tag_name):
|
||||
return iter_descendants_with_name(dom, tag_name, 1)
|
||||
|
||||
|
||||
def iter_children_with_attribute(dom, tag_name, attr_name, attr_value):
|
||||
return iter_descendants_with_attribute(dom, tag_name, attr_name, attr_value, 1)
|
||||
|
||||
|
||||
def get_first_child_by_tag_name(dom, tag_name):
|
||||
"""
|
||||
Return the first child element whose name is contained in tagName
|
||||
(or is named tagName if tagName is a string).
|
||||
"""
|
||||
for child in iter_children_with_name(dom, tag_name):
|
||||
return child
|
||||
return None
|
||||
|
||||
|
||||
def get_first_child_text_by_tag_name(dom, tag_name):
|
||||
"""
|
||||
Return the corresponding text of the first child element whose
|
||||
name is contained in tagName (or is named tagName if tagName is a
|
||||
string).
|
||||
"""
|
||||
child = get_first_child_by_tag_name(dom, tag_name)
|
||||
if child:
|
||||
return get_text_child(child)
|
||||
return None
|
||||
|
||||
|
||||
def get_first_child_text_trim_by_tag_name(dom, tag_name):
|
||||
text = get_first_child_text_by_tag_name(dom, tag_name)
|
||||
if text:
|
||||
text = text.strip()
|
||||
return text
|
||||
|
||||
|
||||
def get_first_child_with_attribute(dom, tag_name, attr_name, attr_value):
|
||||
"""
|
||||
Return the first child element whose name is contained in tagName
|
||||
(or is named tagName if tagName is a string) that has an attribute
|
||||
named attrName with value attrValue.
|
||||
"""
|
||||
for child in \
|
||||
iter_children_with_attribute(dom, tag_name, attr_name, attr_value):
|
||||
return child
|
||||
return None
|
||||
|
||||
|
||||
def get_first_child_text_with_attribute(dom, tag_name, attr_name, attr_value):
|
||||
"""
|
||||
Return the corresponding text of the first child element whose
|
||||
name is contained in tagName (or is named tagName if tagName is a
|
||||
string) that has an attribute named attrName with value attrValue.
|
||||
"""
|
||||
child = get_first_child_with_attribute(dom, tag_name, attr_name, attr_value)
|
||||
if child:
|
||||
return get_text_child(child)
|
||||
return None
|
||||
|
||||
|
||||
def get_first_child_text_trim_with_attribute(dom, tag_name, attr_name, attr_value):
|
||||
text = get_first_child_text_with_attribute(dom, tag_name, attr_name, attr_value)
|
||||
if text:
|
||||
text = text.strip()
|
||||
return text
|
|
@ -1,12 +0,0 @@
|
|||
from core.xml.xmlwriter0 import CoreDocumentWriter0
|
||||
from core.xml.xmlwriter1 import CoreDocumentWriter1
|
||||
|
||||
|
||||
def core_document_writer(session, version):
|
||||
if version == '0.0':
|
||||
doc = CoreDocumentWriter0(session)
|
||||
elif version == '1.0':
|
||||
doc = CoreDocumentWriter1(session)
|
||||
else:
|
||||
raise ValueError('unsupported document version: %s' % version)
|
||||
return doc
|
|
@ -1,386 +0,0 @@
|
|||
import os
|
||||
from xml.dom.minidom import Document
|
||||
|
||||
import pwd
|
||||
|
||||
from core import logger
|
||||
from core.coreobj import PyCoreNet
|
||||
from core.coreobj import PyCoreNode
|
||||
from core.enumerations import RegisterTlvs, EventTypes
|
||||
from core.xml import xmlutils
|
||||
|
||||
|
||||
class CoreDocumentWriter0(Document):
|
||||
"""
|
||||
Utility class for writing a CoreSession to XML. The init method builds
|
||||
an xml.dom.minidom.Document, and the writexml() method saves the XML file.
|
||||
"""
|
||||
|
||||
def __init__(self, session):
|
||||
"""
|
||||
Create an empty Scenario XML Document, then populate it with
|
||||
objects from the given session.
|
||||
"""
|
||||
Document.__init__(self)
|
||||
self.session = session
|
||||
self.scenario = self.createElement("Scenario")
|
||||
self.np = self.createElement("NetworkPlan")
|
||||
self.mp = self.createElement("MotionPlan")
|
||||
self.sp = self.createElement("ServicePlan")
|
||||
self.meta = self.createElement("CoreMetaData")
|
||||
|
||||
self.appendChild(self.scenario)
|
||||
self.scenario.appendChild(self.np)
|
||||
self.scenario.appendChild(self.mp)
|
||||
self.scenario.appendChild(self.sp)
|
||||
self.scenario.appendChild(self.meta)
|
||||
|
||||
self.populatefromsession()
|
||||
|
||||
def populatefromsession(self):
|
||||
if self.session.state != EventTypes.RUNTIME_STATE.value:
|
||||
self.session.emane.setup() # not during runtime?
|
||||
self.addorigin()
|
||||
self.adddefaultservices()
|
||||
self.addnets()
|
||||
self.addnodes()
|
||||
self.addmetadata()
|
||||
|
||||
def writexml(self, filename):
|
||||
logger.info("saving session XML file %s", filename)
|
||||
f = open(filename, "w")
|
||||
Document.writexml(self, writer=f, indent="", addindent=" ", newl="\n", encoding="UTF-8")
|
||||
f.close()
|
||||
if self.session.user is not None:
|
||||
uid = pwd.getpwnam(self.session.user).pw_uid
|
||||
gid = os.stat(self.session.sessiondir).st_gid
|
||||
os.chown(filename, uid, gid)
|
||||
|
||||
def addnets(self):
|
||||
"""
|
||||
Add PyCoreNet objects as NetworkDefinition XML elements.
|
||||
"""
|
||||
with self.session._objects_lock:
|
||||
for net in self.session.objects.itervalues():
|
||||
if not isinstance(net, PyCoreNet):
|
||||
continue
|
||||
self.addnet(net)
|
||||
|
||||
def addnet(self, net):
|
||||
"""
|
||||
Add one PyCoreNet object as a NetworkDefinition XML element.
|
||||
"""
|
||||
n = self.createElement("NetworkDefinition")
|
||||
self.np.appendChild(n)
|
||||
n.setAttribute("name", net.name)
|
||||
# could use net.brname
|
||||
n.setAttribute("id", "%s" % net.objid)
|
||||
n.setAttribute("type", "%s" % net.__class__.__name__)
|
||||
self.addnetinterfaces(n, net)
|
||||
# key used with tunnel node
|
||||
if hasattr(net, 'grekey') and net.grekey is not None:
|
||||
n.setAttribute("key", "%s" % net.grekey)
|
||||
# link parameters
|
||||
for netif in net.netifs(sort=True):
|
||||
self.addnetem(n, netif)
|
||||
# wireless/mobility models
|
||||
modelconfigs = net.session.mobility.get_models(net)
|
||||
modelconfigs += net.session.emane.get_models(net)
|
||||
self.addmodels(n, modelconfigs)
|
||||
self.addposition(net)
|
||||
|
||||
def addnetem(self, n, netif):
|
||||
"""
|
||||
Similar to addmodels(); used for writing netem link effects
|
||||
parameters. TODO: Interface parameters should be moved to the model
|
||||
construct, then this separate method shouldn't be required.
|
||||
"""
|
||||
params = netif.getparams()
|
||||
if len(params) == 0:
|
||||
return
|
||||
model = self.createElement("model")
|
||||
model.setAttribute("name", "netem")
|
||||
model.setAttribute("netif", netif.name)
|
||||
if hasattr(netif, "node") and netif.node is not None:
|
||||
model.setAttribute("peer", netif.node.name)
|
||||
# link between switches uses one veth interface
|
||||
elif hasattr(netif, "othernet") and netif.othernet is not None:
|
||||
if netif.othernet.name == n.getAttribute("name"):
|
||||
model.setAttribute("peer", netif.net.name)
|
||||
else:
|
||||
model.setAttribute("peer", netif.othernet.name)
|
||||
model.setAttribute("netif", netif.localname)
|
||||
# hack used for upstream parameters for link between switches
|
||||
# (see LxBrNet.linknet())
|
||||
if netif.othernet.objid == int(n.getAttribute("id")):
|
||||
netif.swapparams('_params_up')
|
||||
params = netif.getparams()
|
||||
netif.swapparams('_params_up')
|
||||
has_params = False
|
||||
for k, v in params:
|
||||
# default netem parameters are 0 or None
|
||||
if v is None or v == 0:
|
||||
continue
|
||||
if k == "has_netem" or k == "has_tbf":
|
||||
continue
|
||||
key = self.createElement(k)
|
||||
key.appendChild(self.createTextNode("%s" % v))
|
||||
model.appendChild(key)
|
||||
has_params = True
|
||||
if has_params:
|
||||
n.appendChild(model)
|
||||
|
||||
def addmodels(self, n, configs):
|
||||
"""
|
||||
Add models from a list of model-class, config values tuples.
|
||||
"""
|
||||
for m, conf in configs:
|
||||
model = self.createElement("model")
|
||||
n.appendChild(model)
|
||||
model.setAttribute("name", m.name)
|
||||
type = "wireless"
|
||||
if m.config_type == RegisterTlvs.MOBILITY.value:
|
||||
type = "mobility"
|
||||
model.setAttribute("type", type)
|
||||
|
||||
for k, value in conf.iteritems():
|
||||
key = self.createElement(k)
|
||||
if value is None:
|
||||
value = ""
|
||||
key.appendChild(self.createTextNode("%s" % value))
|
||||
model.appendChild(key)
|
||||
|
||||
def addnodes(self):
|
||||
"""
|
||||
Add PyCoreNode objects as node XML elements.
|
||||
"""
|
||||
with self.session._objects_lock:
|
||||
for node in self.session.objects.itervalues():
|
||||
if not isinstance(node, PyCoreNode):
|
||||
continue
|
||||
self.addnode(node)
|
||||
|
||||
def addnode(self, node):
|
||||
"""
|
||||
Add a PyCoreNode object as node XML elements.
|
||||
"""
|
||||
n = self.createElement("Node")
|
||||
self.np.appendChild(n)
|
||||
n.setAttribute("name", node.name)
|
||||
n.setAttribute("id", "%s" % node.objid)
|
||||
if node.type:
|
||||
n.setAttribute("type", node.type)
|
||||
self.addinterfaces(n, node)
|
||||
self.addposition(node)
|
||||
xmlutils.add_param_to_parent(self, n, "icon", node.icon)
|
||||
xmlutils.add_param_to_parent(self, n, "canvas", node.canvas)
|
||||
self.addservices(node)
|
||||
|
||||
def addinterfaces(self, n, node):
|
||||
"""
|
||||
Add PyCoreNetIfs to node XML elements.
|
||||
"""
|
||||
for ifc in node.netifs(sort=True):
|
||||
i = self.createElement("interface")
|
||||
n.appendChild(i)
|
||||
i.setAttribute("name", ifc.name)
|
||||
netmodel = None
|
||||
if ifc.net:
|
||||
i.setAttribute("net", ifc.net.name)
|
||||
if hasattr(ifc.net, "model"):
|
||||
netmodel = ifc.net.model
|
||||
if ifc.mtu and ifc.mtu != 1500:
|
||||
i.setAttribute("mtu", "%s" % ifc.mtu)
|
||||
# could use ifc.params, transport_type
|
||||
self.addaddresses(i, ifc)
|
||||
# per-interface models
|
||||
if netmodel and netmodel.name[:6] == "emane_":
|
||||
cfg = self.session.emane.getifcconfig(node.objid, ifc, netmodel.name)
|
||||
if cfg:
|
||||
self.addmodels(i, ((netmodel, cfg),))
|
||||
|
||||
def addnetinterfaces(self, n, net):
|
||||
"""
|
||||
Similar to addinterfaces(), but only adds interface elements to the
|
||||
supplied XML node that would not otherwise appear in the Node elements.
|
||||
These are any interfaces that link two switches/hubs together.
|
||||
"""
|
||||
for ifc in net.netifs(sort=True):
|
||||
if not hasattr(ifc, "othernet") or not ifc.othernet:
|
||||
continue
|
||||
i = self.createElement("interface")
|
||||
n.appendChild(i)
|
||||
if net.objid == ifc.net.objid:
|
||||
i.setAttribute("name", ifc.localname)
|
||||
i.setAttribute("net", ifc.othernet.name)
|
||||
else:
|
||||
i.setAttribute("name", ifc.name)
|
||||
i.setAttribute("net", ifc.net.name)
|
||||
|
||||
def addposition(self, node):
|
||||
"""
|
||||
Add object coordinates as location XML element.
|
||||
"""
|
||||
(x, y, z) = node.position.get()
|
||||
if x is None or y is None:
|
||||
return
|
||||
# <Node name="n1">
|
||||
mpn = self.createElement("Node")
|
||||
mpn.setAttribute("name", node.name)
|
||||
self.mp.appendChild(mpn)
|
||||
|
||||
# <motion type="stationary">
|
||||
motion = self.createElement("motion")
|
||||
motion.setAttribute("type", "stationary")
|
||||
mpn.appendChild(motion)
|
||||
|
||||
# <point>$X$,$Y$,$Z$</point>
|
||||
pt = self.createElement("point")
|
||||
motion.appendChild(pt)
|
||||
coordstxt = "%s,%s" % (x, y)
|
||||
if z:
|
||||
coordstxt += ",%s" % z
|
||||
coords = self.createTextNode(coordstxt)
|
||||
pt.appendChild(coords)
|
||||
|
||||
def addorigin(self):
|
||||
"""
|
||||
Add origin to Motion Plan using canvas reference point.
|
||||
The CoreLocation class maintains this reference point.
|
||||
"""
|
||||
refgeo = self.session.location.refgeo
|
||||
origin = self.createElement("origin")
|
||||
attrs = ("lat", "lon", "alt")
|
||||
have_origin = False
|
||||
for i in xrange(3):
|
||||
if refgeo[i] is not None:
|
||||
origin.setAttribute(attrs[i], str(refgeo[i]))
|
||||
have_origin = True
|
||||
if not have_origin:
|
||||
return
|
||||
if self.session.location.refscale != 1.0: # 100 pixels = refscale m
|
||||
origin.setAttribute("scale100", str(self.session.location.refscale))
|
||||
if self.session.location.refxyz != (0.0, 0.0, 0.0):
|
||||
pt = self.createElement("point")
|
||||
origin.appendChild(pt)
|
||||
x, y, z = self.session.location.refxyz
|
||||
coordstxt = "%s,%s" % (x, y)
|
||||
if z:
|
||||
coordstxt += ",%s" % z
|
||||
coords = self.createTextNode(coordstxt)
|
||||
pt.appendChild(coords)
|
||||
|
||||
self.mp.appendChild(origin)
|
||||
|
||||
def adddefaultservices(self):
|
||||
"""
|
||||
Add default services and node types to the ServicePlan.
|
||||
"""
|
||||
for type in self.session.services.default_services:
|
||||
defaults = self.session.services.get_default_services(type)
|
||||
spn = self.createElement("Node")
|
||||
spn.setAttribute("type", type)
|
||||
self.sp.appendChild(spn)
|
||||
for svc in defaults:
|
||||
s = self.createElement("Service")
|
||||
spn.appendChild(s)
|
||||
s.setAttribute("name", str(svc.name))
|
||||
|
||||
def addservices(self, node):
|
||||
"""
|
||||
Add services and their customizations to the ServicePlan.
|
||||
"""
|
||||
if len(node.services) == 0:
|
||||
return
|
||||
defaults = self.session.services.get_default_services(node.type)
|
||||
if node.services == defaults:
|
||||
return
|
||||
spn = self.createElement("Node")
|
||||
spn.setAttribute("name", node.name)
|
||||
self.sp.appendChild(spn)
|
||||
|
||||
for svc in node.services:
|
||||
s = self.createElement("Service")
|
||||
spn.appendChild(s)
|
||||
s.setAttribute("name", str(svc.name))
|
||||
# only record service names if not a customized service
|
||||
if not svc.custom:
|
||||
continue
|
||||
s.setAttribute("custom", str(svc.custom))
|
||||
xmlutils.add_elements_from_list(self, s, svc.dirs, "Directory", "name")
|
||||
|
||||
for fn in svc.configs:
|
||||
if len(fn) == 0:
|
||||
continue
|
||||
f = self.createElement("File")
|
||||
f.setAttribute("name", fn)
|
||||
# all file names are added to determine when a file has been deleted
|
||||
s.appendChild(f)
|
||||
data = svc.config_data.get(fn)
|
||||
if data is None:
|
||||
# this includes only customized file contents and skips
|
||||
# the auto-generated files
|
||||
continue
|
||||
txt = self.createTextNode(data)
|
||||
f.appendChild(txt)
|
||||
|
||||
xmlutils.add_text_elements_from_list(self, s, svc.startup, "Command", (("type", "start"),))
|
||||
xmlutils.add_text_elements_from_list(self, s, svc.shutdown, "Command", (("type", "stop"),))
|
||||
xmlutils.add_text_elements_from_list(self, s, svc.validate, "Command", (("type", "validate"),))
|
||||
|
||||
def addaddresses(self, i, netif):
|
||||
"""
|
||||
Add MAC and IP addresses to interface XML elements.
|
||||
"""
|
||||
if netif.hwaddr:
|
||||
h = self.createElement("address")
|
||||
i.appendChild(h)
|
||||
h.setAttribute("type", "mac")
|
||||
htxt = self.createTextNode("%s" % netif.hwaddr)
|
||||
h.appendChild(htxt)
|
||||
for addr in netif.addrlist:
|
||||
a = self.createElement("address")
|
||||
i.appendChild(a)
|
||||
# a.setAttribute("type", )
|
||||
atxt = self.createTextNode("%s" % addr)
|
||||
a.appendChild(atxt)
|
||||
|
||||
def addhooks(self):
|
||||
"""
|
||||
Add hook script XML elements to the metadata tag.
|
||||
"""
|
||||
hooks = self.createElement("Hooks")
|
||||
for state in sorted(self.session._hooks.keys()):
|
||||
for filename, data in self.session._hooks[state]:
|
||||
hook = self.createElement("Hook")
|
||||
hook.setAttribute("name", filename)
|
||||
hook.setAttribute("state", str(state))
|
||||
txt = self.createTextNode(data)
|
||||
hook.appendChild(txt)
|
||||
hooks.appendChild(hook)
|
||||
if hooks.hasChildNodes():
|
||||
self.meta.appendChild(hooks)
|
||||
|
||||
def addmetadata(self):
|
||||
"""
|
||||
Add CORE-specific session meta-data XML elements.
|
||||
"""
|
||||
# options
|
||||
options = self.createElement("SessionOptions")
|
||||
defaults = self.session.options.default_values()
|
||||
for name, current_value in self.session.options.get_configs().iteritems():
|
||||
default_value = defaults[name]
|
||||
if current_value != default_value:
|
||||
xmlutils.add_text_param_to_parent(self, options, name, current_value)
|
||||
|
||||
if options.hasChildNodes():
|
||||
self.meta.appendChild(options)
|
||||
|
||||
# hook scripts
|
||||
self.addhooks()
|
||||
|
||||
# meta
|
||||
meta = self.createElement("MetaData")
|
||||
self.meta.appendChild(meta)
|
||||
for name, current_value in self.session.metadata.get_configs().iteritems():
|
||||
xmlutils.add_text_param_to_parent(self, meta, name, current_value)
|
|
@ -1,998 +0,0 @@
|
|||
import collections
|
||||
import os
|
||||
from xml.dom.minidom import Document
|
||||
|
||||
import pwd
|
||||
|
||||
from core import coreobj
|
||||
from core import logger
|
||||
from core.enumerations import EventTypes
|
||||
from core.enumerations import NodeTypes
|
||||
from core.enumerations import RegisterTlvs
|
||||
from core.misc import ipaddress
|
||||
from core.misc import nodeutils
|
||||
from core.netns import nodes
|
||||
from core.xml import xmlutils
|
||||
from core.xml.xmldeployment import CoreDeploymentWriter
|
||||
|
||||
|
||||
class Alias:
|
||||
ID = "COREID"
|
||||
|
||||
|
||||
class MembType:
|
||||
INTERFACE = "interface"
|
||||
CHANNEL = "channel"
|
||||
SWITCH = "switch"
|
||||
HUB = "hub"
|
||||
TUNNEL = "tunnel"
|
||||
NETWORK = "network"
|
||||
|
||||
|
||||
class NodeType:
|
||||
ROUTER = "router"
|
||||
HOST = "host"
|
||||
MDR = "mdr"
|
||||
PC = "PC"
|
||||
RJ45 = "rj45"
|
||||
SWITCH = "lanswitch"
|
||||
HUB = "hub"
|
||||
|
||||
|
||||
class DevType:
|
||||
HOST = "host"
|
||||
ROUTER = "router"
|
||||
SWITCH = "switch"
|
||||
HUB = "hub"
|
||||
|
||||
|
||||
class NetType:
|
||||
WIRELESS = "wireless"
|
||||
ETHERNET = "ethernet"
|
||||
PTP_WIRED = "point-to-point-wired"
|
||||
PTP_WIRELESS = "point-to-point-wireless"
|
||||
|
||||
|
||||
"""
|
||||
A link endpoint in CORE
|
||||
net: the network that the endpoint belongs to
|
||||
netif: the network interface at this end
|
||||
id: the identifier for the endpoint
|
||||
l2devport: if the other end is a layer 2 device, this is the assigned port in that device
|
||||
params: link/interface parameters
|
||||
"""
|
||||
Endpoint = collections.namedtuple('Endpoint',
|
||||
['net', 'netif', 'type', 'id', 'l2devport', 'params'])
|
||||
|
||||
|
||||
class CoreDocumentWriter1(Document):
|
||||
"""
|
||||
Utility class for writing a CoreSession to XML in the NMF scenPlan schema. The init
|
||||
method builds an xml.dom.minidom.Document, and the writexml() method saves the XML file.
|
||||
"""
|
||||
|
||||
def __init__(self, session):
|
||||
"""
|
||||
Create an empty Scenario XML Document, then populate it with
|
||||
objects from the given session.
|
||||
"""
|
||||
Document.__init__(self)
|
||||
logger.debug('Exporting to NMF XML version 1.0')
|
||||
with session._objects_lock:
|
||||
self.scenarioPlan = ScenarioPlan(self, session)
|
||||
if session.state == EventTypes.RUNTIME_STATE.value:
|
||||
deployment = CoreDeploymentWriter(self, self.scenarioPlan, session)
|
||||
deployment.add_deployment()
|
||||
self.scenarioPlan.setAttribute('deployed', 'true')
|
||||
|
||||
def writexml(self, filename):
|
||||
"""
|
||||
Commit to file
|
||||
"""
|
||||
logger.info("saving session XML file %s", filename)
|
||||
f = open(filename, "w")
|
||||
Document.writexml(self, writer=f, indent="", addindent=" ", newl="\n", encoding="UTF-8")
|
||||
f.close()
|
||||
if self.scenarioPlan.coreSession.user is not None:
|
||||
uid = pwd.getpwnam(self.scenarioPlan.coreSession.user).pw_uid
|
||||
gid = os.stat(self.scenarioPlan.coreSession.session_dir).st_gid
|
||||
os.chown(filename, uid, gid)
|
||||
|
||||
|
||||
class XmlElement(object):
|
||||
"""
|
||||
The base class for all XML elements in the scenario plan. Includes
|
||||
convenience functions.
|
||||
"""
|
||||
|
||||
def __init__(self, document, parent, element_type):
|
||||
self.document = document
|
||||
self.parent = parent
|
||||
self.base_element = document.createElement("%s" % element_type)
|
||||
if self.parent is not None:
|
||||
self.parent.appendChild(self.base_element)
|
||||
|
||||
def createElement(self, element_tag):
|
||||
return self.document.createElement(element_tag)
|
||||
|
||||
def getTagName(self):
|
||||
return self.base_element.tagName
|
||||
|
||||
def createTextNode(self, node_tag):
|
||||
return self.document.createTextNode(node_tag)
|
||||
|
||||
def appendChild(self, child):
|
||||
if isinstance(child, XmlElement):
|
||||
self.base_element.appendChild(child.base_element)
|
||||
else:
|
||||
self.base_element.appendChild(child)
|
||||
|
||||
@staticmethod
|
||||
def add_parameter(doc, parent, key, value):
|
||||
if key and value:
|
||||
parm = doc.createElement("parameter")
|
||||
parm.setAttribute("name", str(key))
|
||||
parm.appendChild(doc.createTextNode(str(value)))
|
||||
parent.appendChild(parm)
|
||||
|
||||
def addParameter(self, key, value):
|
||||
"""
|
||||
Add a parameter to the xml element
|
||||
"""
|
||||
self.add_parameter(self.document, self, key, value)
|
||||
|
||||
def setAttribute(self, name, val):
|
||||
self.base_element.setAttribute(name, val)
|
||||
|
||||
def getAttribute(self, name):
|
||||
return self.base_element.getAttribute(name)
|
||||
|
||||
|
||||
class NamedXmlElement(XmlElement):
|
||||
"""
|
||||
The base class for all "named" xml elements. Named elements are
|
||||
xml elements in the scenario plan that have an id and a name attribute.
|
||||
"""
|
||||
|
||||
def __init__(self, scen_plan, parent, element_type, element_name):
|
||||
XmlElement.__init__(self, scen_plan.document, parent, element_type)
|
||||
|
||||
self.scenPlan = scen_plan
|
||||
self.coreSession = scen_plan.coreSession
|
||||
|
||||
element_path = ''
|
||||
self.id = None
|
||||
if self.parent is not None and isinstance(self.parent, XmlElement) and self.parent.getTagName() != "scenario":
|
||||
element_path = "%s/" % self.parent.getAttribute("id")
|
||||
|
||||
self.id = "%s%s" % (element_path, element_name)
|
||||
self.setAttribute("name", element_name)
|
||||
self.setAttribute("id", self.id)
|
||||
|
||||
def addPoint(self, core_object):
|
||||
"""
|
||||
Add position to an object
|
||||
"""
|
||||
(x, y, z) = core_object.position.get()
|
||||
if x is None or y is None:
|
||||
return
|
||||
lat, lon, alt = self.coreSession.location.getgeo(x, y, z)
|
||||
|
||||
pt = self.createElement("point")
|
||||
pt.setAttribute("type", "gps")
|
||||
pt.setAttribute("lat", "%s" % lat)
|
||||
pt.setAttribute("lon", "%s" % lon)
|
||||
if z:
|
||||
pt.setAttribute("z", "%s" % alt)
|
||||
self.appendChild(pt)
|
||||
|
||||
def createAlias(self, domain, value_str):
|
||||
"""
|
||||
Create an alias element for CORE specific information
|
||||
"""
|
||||
a = self.createElement("alias")
|
||||
a.setAttribute("domain", "%s" % domain)
|
||||
a.appendChild(self.createTextNode(value_str))
|
||||
return a
|
||||
|
||||
|
||||
class ScenarioPlan(XmlElement):
|
||||
"""
|
||||
Container class for ScenarioPlan.
|
||||
"""
|
||||
|
||||
def __init__(self, document, session):
|
||||
XmlElement.__init__(self, document, parent=document, element_type='scenario')
|
||||
|
||||
self.coreSession = session
|
||||
|
||||
self.setAttribute('version', '1.0')
|
||||
self.setAttribute("name", "%s" % session.name)
|
||||
|
||||
self.setAttribute('xmlns', 'nmfPlan')
|
||||
self.setAttribute('xmlns:CORE', 'coreSpecific')
|
||||
self.setAttribute('compiled', 'true')
|
||||
|
||||
self.all_channel_members = {}
|
||||
self.last_network_id = 0
|
||||
self.addNetworks()
|
||||
self.addDevices()
|
||||
self.addDefaultServices()
|
||||
self.addSessionConfiguration()
|
||||
|
||||
def addNetworks(self):
|
||||
"""
|
||||
Add networks in the session to the scenPlan.
|
||||
"""
|
||||
for net in self.coreSession.objects.itervalues():
|
||||
if not isinstance(net, coreobj.PyCoreNet):
|
||||
continue
|
||||
|
||||
if nodeutils.is_node(net, NodeTypes.CONTROL_NET):
|
||||
continue
|
||||
|
||||
# Do not add switches and hubs that belong to another network
|
||||
if nodeutils.is_node(net, (NodeTypes.SWITCH, NodeTypes.HUB)):
|
||||
if in_other_network(net):
|
||||
continue
|
||||
|
||||
try:
|
||||
NetworkElement(self, self, net)
|
||||
except:
|
||||
logger.exception("error adding node")
|
||||
if hasattr(net, "name") and net.name:
|
||||
logger.warn('Unsupported net name: %s, class: %s, type: %s',
|
||||
net.name, net.__class__.__name__, net.type)
|
||||
else:
|
||||
logger.warn('Unsupported net class: %s', net.__class__.__name__)
|
||||
|
||||
def addDevices(self):
|
||||
"""
|
||||
Add device elements to the scenario plan.
|
||||
"""
|
||||
for node in self.coreSession.objects.itervalues():
|
||||
if not isinstance(node, nodes.PyCoreNode):
|
||||
continue
|
||||
|
||||
try:
|
||||
DeviceElement(self, self, node)
|
||||
except:
|
||||
logger.exception("error adding device")
|
||||
if hasattr(node, "name") and node.name:
|
||||
logger.warn('Unsupported device name: %s, class: %s, type: %s',
|
||||
node.name, node.__class__.__name__, node.type)
|
||||
else:
|
||||
logger.warn('Unsupported device: %s', node.__class__.__name__)
|
||||
|
||||
def addDefaultServices(self):
|
||||
"""
|
||||
Add default services and node types to the ServicePlan.
|
||||
"""
|
||||
defaultservices = self.createElement("CORE:defaultservices")
|
||||
for type in self.coreSession.services.default_services:
|
||||
defaults = self.coreSession.services.get_default_services(type)
|
||||
spn = self.createElement("device")
|
||||
spn.setAttribute("type", type)
|
||||
defaultservices.appendChild(spn)
|
||||
for svc in defaults:
|
||||
s = self.createElement("service")
|
||||
spn.appendChild(s)
|
||||
s.setAttribute("name", str(svc.name))
|
||||
if defaultservices.hasChildNodes():
|
||||
self.appendChild(defaultservices)
|
||||
|
||||
def addSessionConfiguration(self):
|
||||
"""
|
||||
Add CORE-specific session configuration XML elements.
|
||||
"""
|
||||
config = self.createElement("CORE:sessionconfig")
|
||||
|
||||
# origin: geolocation of cartesian coordinate 0,0,0
|
||||
refgeo = self.coreSession.location.refgeo
|
||||
origin = self.createElement("origin")
|
||||
attrs = ("lat", "lon", "alt")
|
||||
have_origin = False
|
||||
for i in xrange(3):
|
||||
if refgeo[i] is not None:
|
||||
origin.setAttribute(attrs[i], str(refgeo[i]))
|
||||
have_origin = True
|
||||
if have_origin:
|
||||
if self.coreSession.location.refscale != 1.0: # 100 pixels = refscale m
|
||||
origin.setAttribute("scale100", str(self.coreSession.location.refscale))
|
||||
if self.coreSession.location.refxyz != (0.0, 0.0, 0.0):
|
||||
pt = self.createElement("point")
|
||||
origin.appendChild(pt)
|
||||
x, y, z = self.coreSession.location.refxyz
|
||||
coordstxt = "%s,%s" % (x, y)
|
||||
if z:
|
||||
coordstxt += ",%s" % z
|
||||
coords = self.createTextNode(coordstxt)
|
||||
pt.appendChild(coords)
|
||||
config.appendChild(origin)
|
||||
|
||||
# options
|
||||
options = self.createElement("options")
|
||||
options_config = self.coreSession.options.get_configs()
|
||||
for _id, default_value in self.coreSession.options.default_values().iteritems():
|
||||
value = options_config[_id]
|
||||
if value != default_value:
|
||||
XmlElement.add_parameter(self.document, options, _id, value)
|
||||
|
||||
if options.hasChildNodes():
|
||||
config.appendChild(options)
|
||||
|
||||
# hook scripts
|
||||
hooks = self.createElement("hooks")
|
||||
for state in sorted(self.coreSession._hooks.keys()):
|
||||
for filename, data in self.coreSession._hooks[state]:
|
||||
hook = self.createElement("hook")
|
||||
hook.setAttribute("name", filename)
|
||||
hook.setAttribute("state", str(state))
|
||||
txt = self.createTextNode(data)
|
||||
hook.appendChild(txt)
|
||||
hooks.appendChild(hook)
|
||||
if hooks.hasChildNodes():
|
||||
config.appendChild(hooks)
|
||||
|
||||
# metadata
|
||||
meta = self.createElement("metadata")
|
||||
for k, v in self.coreSession.metadata.get_configs().iteritems():
|
||||
XmlElement.add_parameter(self.document, meta, k, v)
|
||||
if meta.hasChildNodes():
|
||||
config.appendChild(meta)
|
||||
|
||||
if config.hasChildNodes():
|
||||
self.appendChild(config)
|
||||
|
||||
|
||||
class NetworkElement(NamedXmlElement):
|
||||
def __init__(self, scen_plan, parent, network_object):
|
||||
"""
|
||||
Add one PyCoreNet object as one network XML element.
|
||||
"""
|
||||
element_name = self.getNetworkName(scen_plan, network_object)
|
||||
NamedXmlElement.__init__(self, scen_plan, parent, "network", element_name)
|
||||
|
||||
self.scenPlan = scen_plan
|
||||
|
||||
self.addPoint(network_object)
|
||||
|
||||
network_type = None
|
||||
if nodeutils.is_node(network_object, (NodeTypes.WIRELESS_LAN, NodeTypes.EMANE)):
|
||||
network_type = NetType.WIRELESS
|
||||
elif nodeutils.is_node(network_object, (NodeTypes.SWITCH, NodeTypes.HUB,
|
||||
NodeTypes.PEER_TO_PEER, NodeTypes.TUNNEL)):
|
||||
network_type = NetType.ETHERNET
|
||||
else:
|
||||
network_type = "%s" % network_object.__class__.__name__
|
||||
|
||||
type_element = self.createElement("type")
|
||||
type_element.appendChild(self.createTextNode(network_type))
|
||||
self.appendChild(type_element)
|
||||
|
||||
# Gather all endpoints belonging to this network
|
||||
self.endpoints = get_endpoints(network_object)
|
||||
|
||||
# Special case for a network of switches and hubs
|
||||
create_alias = True
|
||||
self.l2devices = []
|
||||
if nodeutils.is_node(network_object, (NodeTypes.SWITCH, NodeTypes.HUB)):
|
||||
create_alias = False
|
||||
self.appendChild(type_element)
|
||||
self.addL2Devices(network_object)
|
||||
|
||||
if create_alias:
|
||||
a = self.createAlias(Alias.ID, "%d" % int(network_object.objid))
|
||||
self.appendChild(a)
|
||||
|
||||
# XXXX TODO: Move this to channel?
|
||||
# key used with tunnel node
|
||||
if hasattr(network_object, 'grekey') and network_object.grekey is not None:
|
||||
a = self.createAlias("COREGREKEY", "%s" % network_object.grekey)
|
||||
self.appendChild(a)
|
||||
|
||||
self.addNetMembers(network_object)
|
||||
self.addChannels(network_object)
|
||||
|
||||
presentation_element = self.createElement("CORE:presentation")
|
||||
add_presentation_element = False
|
||||
if network_object.icon and not network_object.icon.isspace():
|
||||
presentation_element.setAttribute("icon", network_object.icon)
|
||||
add_presentation_element = True
|
||||
if network_object.canvas:
|
||||
presentation_element.setAttribute("canvas", str(network_object.canvas))
|
||||
add_presentation_element = True
|
||||
if add_presentation_element:
|
||||
self.appendChild(presentation_element)
|
||||
|
||||
def getNetworkName(self, scenario_plan, network_object):
|
||||
"""
|
||||
Determine the name to use for this network element
|
||||
|
||||
:param ScenarioPlan scenario_plan:
|
||||
:param network_object:
|
||||
:return:
|
||||
"""
|
||||
if nodeutils.is_node(network_object, (NodeTypes.PEER_TO_PEER, NodeTypes.TUNNEL)):
|
||||
name = "net%s" % scenario_plan.last_network_id
|
||||
scenario_plan.last_network_id += 1
|
||||
elif network_object.name:
|
||||
name = str(network_object.name) # could use net.brname for bridges?
|
||||
elif nodeutils.is_node(network_object, (NodeTypes.SWITCH, NodeTypes.HUB)):
|
||||
name = "lan%s" % network_object.objid
|
||||
else:
|
||||
name = ''
|
||||
return name
|
||||
|
||||
def addL2Devices(self, network_object):
|
||||
"""
|
||||
Add switches and hubs
|
||||
"""
|
||||
|
||||
# Add the netObj as a device
|
||||
self.l2devices.append(DeviceElement(self.scenPlan, self, network_object))
|
||||
|
||||
# Add downstream switches/hubs
|
||||
l2devs = []
|
||||
neweps = []
|
||||
for ep in self.endpoints:
|
||||
if ep.type and ep.net.objid != network_object.objid:
|
||||
l2s, eps = get_dowmstream_l2_devices(ep.net)
|
||||
l2devs.extend(l2s)
|
||||
neweps.extend(eps)
|
||||
|
||||
for l2dev in l2devs:
|
||||
self.l2devices.append(DeviceElement(self.scenPlan, self, l2dev))
|
||||
|
||||
self.endpoints.extend(neweps)
|
||||
|
||||
# XXX: Optimize later
|
||||
def addNetMembers(self, network_object):
|
||||
"""
|
||||
Add members to a network XML element.
|
||||
"""
|
||||
|
||||
for ep in self.endpoints:
|
||||
if ep.type:
|
||||
MemberElement(self.scenPlan, self, referenced_type=ep.type, referenced_id=ep.id)
|
||||
|
||||
if ep.l2devport:
|
||||
MemberElement(self.scenPlan,
|
||||
self,
|
||||
referenced_type=MembType.INTERFACE,
|
||||
referenced_id="%s/%s" % (self.id, ep.l2devport))
|
||||
|
||||
# XXX Revisit this
|
||||
# Create implied members given the network type
|
||||
if nodeutils.is_node(network_object, NodeTypes.TUNNEL):
|
||||
MemberElement(self.scenPlan, self, referenced_type=MembType.TUNNEL,
|
||||
referenced_id="%s/%s" % (network_object.name, network_object.name))
|
||||
|
||||
# XXX: Optimize later
|
||||
def addChannels(self, network_object):
|
||||
"""
|
||||
Add channels to a network XML element
|
||||
"""
|
||||
|
||||
if nodeutils.is_node(network_object, (NodeTypes.WIRELESS_LAN, NodeTypes.EMANE)):
|
||||
modelconfigs = network_object.session.mobility.get_models(network_object)
|
||||
modelconfigs += network_object.session.emane.get_models(network_object)
|
||||
chan = None
|
||||
|
||||
for model, conf in modelconfigs:
|
||||
# Handle mobility parameters below
|
||||
if model.config_type == RegisterTlvs.MOBILITY.value:
|
||||
continue
|
||||
|
||||
# Create the channel
|
||||
if chan is None:
|
||||
name = "wireless"
|
||||
chan = ChannelElement(self.scenPlan, self, network_object,
|
||||
channel_type=model.name,
|
||||
channel_name=name,
|
||||
channel_domain="CORE")
|
||||
|
||||
# Add wireless model parameters
|
||||
for key, value in conf.iteritems():
|
||||
if value is not None:
|
||||
chan.addParameter(key, value)
|
||||
|
||||
for model, conf in modelconfigs:
|
||||
if model.config_type == RegisterTlvs.MOBILITY.value:
|
||||
# Add wireless mobility parameters
|
||||
mobility = XmlElement(self.scenPlan, chan, "CORE:mobility")
|
||||
# Add a type child
|
||||
type_element = self.createElement("type")
|
||||
type_element.appendChild(self.createTextNode(model.name))
|
||||
mobility.appendChild(type_element)
|
||||
|
||||
for key, value in conf.iteritems():
|
||||
if value is not None:
|
||||
mobility.addParameter(key, value)
|
||||
|
||||
# Add members to the channel
|
||||
if chan is not None:
|
||||
chan.addChannelMembers(self.endpoints)
|
||||
self.appendChild(chan.base_element)
|
||||
elif nodeutils.is_node(network_object, NodeTypes.PEER_TO_PEER):
|
||||
if len(self.endpoints) < 2:
|
||||
if len(self.endpoints) == 1:
|
||||
logger.warn('Pt2Pt network with only 1 endpoint: %s', self.endpoints[0].id)
|
||||
else:
|
||||
logger.warn('Pt2Pt network with no endpoints encountered in %s', network_object.name)
|
||||
return
|
||||
name = "chan%d" % (0)
|
||||
chan = ChannelElement(self.scenPlan, self, network_object,
|
||||
channel_type=NetType.ETHERNET,
|
||||
channel_name=name)
|
||||
|
||||
# Add interface parameters
|
||||
if self.endpoints[0].params != self.endpoints[1].params:
|
||||
logger.warn('Pt2Pt Endpoint parameters do not match in %s', network_object.name)
|
||||
for key, value in self.endpoints[0].params:
|
||||
# XXX lifted from original addnetem function. revisit this.
|
||||
# default netem parameters are 0 or None
|
||||
if value is None or value == 0:
|
||||
continue
|
||||
if key == "has_netem" or key == "has_tbf":
|
||||
continue
|
||||
chan.addParameter(key, value)
|
||||
|
||||
# Add members to the channel
|
||||
chan.addChannelMembers(self.endpoints)
|
||||
self.appendChild(chan)
|
||||
|
||||
elif nodeutils.is_node(network_object, (NodeTypes.SWITCH, NodeTypes.HUB, NodeTypes.TUNNEL)):
|
||||
cidx = 0
|
||||
channels = []
|
||||
for ep in self.endpoints:
|
||||
# Create one channel member per ep
|
||||
if ep.type:
|
||||
name = "chan%d" % cidx
|
||||
chan = ChannelElement(self.scenPlan, self, network_object, channel_type=NetType.ETHERNET,
|
||||
channel_name=name)
|
||||
|
||||
# Add interface parameters
|
||||
for key, value in ep.params:
|
||||
# XXX lifted from original addnetem function. revisit this.
|
||||
# default netem parameters are 0 or None
|
||||
if value is None or value == 0:
|
||||
continue
|
||||
if key == "has_netem" or key == "has_tbf":
|
||||
continue
|
||||
chan.addParameter(key, value)
|
||||
|
||||
# Add members to the channel
|
||||
chan.addChannelMembers(ep)
|
||||
channels.append(chan)
|
||||
cidx += 1
|
||||
|
||||
for chan in channels:
|
||||
self.appendChild(chan)
|
||||
|
||||
|
||||
class DeviceElement(NamedXmlElement):
|
||||
"""
|
||||
A device element in the scenario plan.
|
||||
"""
|
||||
|
||||
def __init__(self, scen_plan, parent, device_object):
|
||||
"""
|
||||
Add a PyCoreNode object as a device element.
|
||||
"""
|
||||
|
||||
device_type = None
|
||||
core_device_type = None
|
||||
if hasattr(device_object, "type") and device_object.type:
|
||||
core_device_type = device_object.type
|
||||
if device_object.type in [NodeType.ROUTER, NodeType.MDR]:
|
||||
device_type = DevType.ROUTER
|
||||
elif device_object.type == NodeType.HUB:
|
||||
device_type = DevType.HUB
|
||||
elif device_object.type == NodeType.SWITCH:
|
||||
device_type = DevType.SWITCH
|
||||
# includes known node types (HOST, PC, RJ45)
|
||||
# Default custom types (defined in ~/.core/nodes.conf) to HOST
|
||||
else:
|
||||
device_type = DevType.HOST
|
||||
|
||||
if device_type is None:
|
||||
raise ValueError("unknown device type: %s" % core_device_type)
|
||||
|
||||
NamedXmlElement.__init__(self, scen_plan, parent, device_type, device_object.name)
|
||||
|
||||
if core_device_type is not None:
|
||||
type_element = self.createElement("type")
|
||||
type_element.setAttribute("domain", "CORE")
|
||||
type_element.appendChild(self.createTextNode("%s" % core_device_type))
|
||||
self.appendChild(type_element)
|
||||
|
||||
self.interfaces = []
|
||||
self.addInterfaces(device_object)
|
||||
alias = self.createAlias(Alias.ID, "%s" % device_object.objid)
|
||||
self.appendChild(alias)
|
||||
self.addPoint(device_object)
|
||||
self.addServices(device_object)
|
||||
|
||||
presentation_element = self.createElement("CORE:presentation")
|
||||
add_presentation_element = False
|
||||
if device_object.icon and not device_object.icon.isspace():
|
||||
presentation_element.setAttribute("icon", device_object.icon)
|
||||
add_presentation_element = True
|
||||
if device_object.canvas:
|
||||
presentation_element.setAttribute("canvas", str(device_object.canvas))
|
||||
add_presentation_element = True
|
||||
if add_presentation_element:
|
||||
self.appendChild(presentation_element)
|
||||
|
||||
def addInterfaces(self, device_object):
|
||||
"""
|
||||
Add interfaces to a device element.
|
||||
"""
|
||||
idx = 0
|
||||
for interface_object in device_object.netifs(sort=True):
|
||||
if interface_object.net and nodeutils.is_node(interface_object.net, NodeTypes.CONTROL_NET):
|
||||
continue
|
||||
if isinstance(device_object, nodes.PyCoreNode):
|
||||
interface_element = InterfaceElement(self.scenPlan, self, device_object, interface_object)
|
||||
else: # isinstance(node, (nodes.HubNode nodes.SwitchNode)):
|
||||
interface_element = InterfaceElement(self.scenPlan, self, device_object, interface_object, idx)
|
||||
idx += 1
|
||||
|
||||
netmodel = None
|
||||
if interface_object.net:
|
||||
if hasattr(interface_object.net, "model"):
|
||||
netmodel = interface_object.net.model
|
||||
if interface_object.mtu and interface_object.mtu != 1500:
|
||||
interface_element.setAttribute("mtu", "%s" % interface_object.mtu)
|
||||
|
||||
# The interfaces returned for Switches and Hubs are the interfaces of the nodes connected to them.
|
||||
# The addresses are for those interfaces. Don't include them here.
|
||||
if isinstance(device_object, nodes.PyCoreNode):
|
||||
# could use ifcObj.params, transport_type
|
||||
interface_element.addAddresses(interface_object)
|
||||
# per-interface models
|
||||
# XXX Remove???
|
||||
if netmodel and netmodel.name[:6] == "emane_":
|
||||
cfg = self.coreSession.emane.getifcconfig(device_object.objid, interface_object, netmodel.name)
|
||||
if cfg:
|
||||
interface_element.addModels(((netmodel, cfg),))
|
||||
|
||||
self.interfaces.append(interface_element)
|
||||
|
||||
def addServices(self, device_object):
|
||||
"""
|
||||
Add services and their customizations to the ServicePlan.
|
||||
"""
|
||||
if not hasattr(device_object, "services"):
|
||||
return
|
||||
|
||||
if len(device_object.services) == 0:
|
||||
return
|
||||
|
||||
defaults = self.coreSession.services.get_default_services(device_object.type)
|
||||
if device_object.services == defaults:
|
||||
return
|
||||
spn = self.createElement("CORE:services")
|
||||
spn.setAttribute("name", device_object.name)
|
||||
self.appendChild(spn)
|
||||
|
||||
for svc in device_object.services:
|
||||
s = self.createElement("service")
|
||||
spn.appendChild(s)
|
||||
s.setAttribute("name", str(svc.name))
|
||||
# only record service names if not a customized service
|
||||
if not svc.custom:
|
||||
continue
|
||||
s.setAttribute("custom", str(svc.custom))
|
||||
xmlutils.add_elements_from_list(self, s, svc.dirs, "directory", "name")
|
||||
|
||||
for fn in svc.configs:
|
||||
if len(fn) == 0:
|
||||
continue
|
||||
f = self.createElement("file")
|
||||
f.setAttribute("name", fn)
|
||||
# all file names are added to determine when a file has been deleted
|
||||
s.appendChild(f)
|
||||
data = svc.config_data.get(fn)
|
||||
if data is None:
|
||||
# this includes only customized file contents and skips
|
||||
# the auto-generated files
|
||||
continue
|
||||
txt = self.createTextNode("\n" + data)
|
||||
f.appendChild(txt)
|
||||
|
||||
xmlutils.add_text_elements_from_list(self, s, svc.startup, "command", (("type", "start"),))
|
||||
xmlutils.add_text_elements_from_list(self, s, svc.shutdown, "command", (("type", "stop"),))
|
||||
xmlutils.add_text_elements_from_list(self, s, svc.validate, "command", (("type", "validate"),))
|
||||
|
||||
|
||||
class ChannelElement(NamedXmlElement):
|
||||
"""
|
||||
A channel element in the scenario plan
|
||||
"""
|
||||
|
||||
def __init__(self, scen_plan, parent, network_object, channel_type, channel_name, channel_domain=None):
|
||||
NamedXmlElement.__init__(self, scen_plan, parent, "channel", channel_name)
|
||||
'''
|
||||
Create a channel element and append a member child referencing this channel element
|
||||
in the parent element.
|
||||
'''
|
||||
# Create a member element for this channel in the parent
|
||||
MemberElement(self.scenPlan, parent, referenced_type=MembType.CHANNEL, referenced_id=self.id)
|
||||
|
||||
# Add a type child
|
||||
type_element = self.createElement("type")
|
||||
if channel_domain is not None:
|
||||
type_element.setAttribute("domain", "%s" % channel_domain)
|
||||
type_element.appendChild(self.createTextNode(channel_type))
|
||||
self.appendChild(type_element)
|
||||
|
||||
def addChannelMembers(self, endpoints):
|
||||
"""
|
||||
Add network channel members referencing interfaces in the channel
|
||||
"""
|
||||
if isinstance(endpoints, list):
|
||||
# A list of endpoints is given. Create one channel member per endpoint
|
||||
idx = 0
|
||||
for ep in endpoints:
|
||||
self.addChannelMember(ep.type, ep.id, idx)
|
||||
idx += 1
|
||||
else:
|
||||
# A single endpoint is given. Create one channel member for the endpoint,
|
||||
# and if the endpoint is associated with a Layer 2 device port, add the
|
||||
# port as a second member
|
||||
ep = endpoints
|
||||
self.addChannelMember(ep.type, ep.id, 0)
|
||||
if ep.l2devport is not None:
|
||||
member_id = "%s/%s" % (self.parent.getAttribute("id"), ep.l2devport)
|
||||
self.addChannelMember(ep.type, member_id, 1)
|
||||
|
||||
def addChannelMember(self, member_interface_type, member_interface_id, member_index):
|
||||
"""
|
||||
add a member to a given channel
|
||||
"""
|
||||
|
||||
m = MemberElement(self.scenPlan,
|
||||
self,
|
||||
referenced_type=member_interface_type,
|
||||
referenced_id=member_interface_id,
|
||||
index=member_index)
|
||||
self.scenPlan.all_channel_members[member_interface_id] = m
|
||||
|
||||
|
||||
class InterfaceElement(NamedXmlElement):
|
||||
"""
|
||||
A network interface element
|
||||
"""
|
||||
|
||||
def __init__(self, scen_plan, parent, device_object, interface_object, interface_index=None):
|
||||
"""
|
||||
Create a network interface element with references to channel that this
|
||||
interface is used.
|
||||
"""
|
||||
element_name = None
|
||||
if interface_index is not None:
|
||||
element_name = "e%d" % interface_index
|
||||
else:
|
||||
element_name = interface_object.name
|
||||
NamedXmlElement.__init__(self, scen_plan, parent, "interface", element_name)
|
||||
self.ifcObj = interface_object
|
||||
self.addChannelReference()
|
||||
|
||||
def addChannelReference(self):
|
||||
"""
|
||||
Add a reference to the channel that uses this interface
|
||||
"""
|
||||
# cm is None when an interface belongs to a switch
|
||||
# or a hub within a network and the channel is yet to be defined
|
||||
cm = self.scenPlan.all_channel_members.get(self.id)
|
||||
if cm is not None:
|
||||
ch = cm.base_element.parentNode
|
||||
if ch is not None:
|
||||
net = ch.parentNode
|
||||
if net is not None:
|
||||
MemberElement(self.scenPlan,
|
||||
self,
|
||||
referenced_type=MembType.CHANNEL,
|
||||
referenced_id=ch.getAttribute("id"),
|
||||
index=int(cm.getAttribute("index")))
|
||||
MemberElement(self.scenPlan,
|
||||
self,
|
||||
referenced_type=MembType.NETWORK,
|
||||
referenced_id=net.getAttribute("id"))
|
||||
|
||||
def addAddresses(self, interface_object):
|
||||
"""
|
||||
Add MAC and IP addresses to interface XML elements.
|
||||
"""
|
||||
if interface_object.hwaddr:
|
||||
h = self.createElement("address")
|
||||
self.appendChild(h)
|
||||
h.setAttribute("type", "mac")
|
||||
htxt = self.createTextNode("%s" % interface_object.hwaddr)
|
||||
h.appendChild(htxt)
|
||||
for addr in interface_object.addrlist:
|
||||
a = self.createElement("address")
|
||||
self.appendChild(a)
|
||||
(ip, sep, mask) = addr.partition('/')
|
||||
# mask = int(mask) XXX?
|
||||
if ipaddress.is_ipv4_address(ip):
|
||||
a.setAttribute("type", "IPv4")
|
||||
else:
|
||||
a.setAttribute("type", "IPv6")
|
||||
|
||||
# a.setAttribute("type", )
|
||||
atxt = self.createTextNode("%s" % addr)
|
||||
a.appendChild(atxt)
|
||||
|
||||
# XXX Remove?
|
||||
def addModels(self, configs):
|
||||
"""
|
||||
Add models from a list of model-class, config values tuples.
|
||||
"""
|
||||
for m, conf in configs:
|
||||
node_element = self.createElement("model")
|
||||
node_element.setAttribute("name", m.name)
|
||||
type_string = "wireless"
|
||||
if m.config_type == RegisterTlvs.MOBILITY.value:
|
||||
type_string = "mobility"
|
||||
node_element.setAttribute("type", type_string)
|
||||
for i, k in enumerate(m.getnames()):
|
||||
key = self.createElement(k)
|
||||
value = conf[i]
|
||||
if value is None:
|
||||
value = ""
|
||||
key.appendChild(self.createTextNode("%s" % value))
|
||||
node_element.appendChild(key)
|
||||
self.appendChild(node_element)
|
||||
|
||||
|
||||
class MemberElement(XmlElement):
|
||||
"""
|
||||
Member elements are references to other elements in the network plan elements of the scenario.
|
||||
They are used in networks to reference channels, in channels to reference interfaces,
|
||||
and in interfaces to reference networks/channels. Member elements provided allow bi-directional
|
||||
traversal of network plan components.
|
||||
"""
|
||||
|
||||
def __init__(self, scene_plan, parent, referenced_type, referenced_id, index=None):
|
||||
"""
|
||||
Create a member element
|
||||
"""
|
||||
XmlElement.__init__(self, scene_plan.document, parent, "member")
|
||||
self.setAttribute("type", "%s" % referenced_type)
|
||||
# See'Understanding the Network Modeling Framework document'
|
||||
if index is not None:
|
||||
self.setAttribute("index", "%d" % index)
|
||||
self.appendChild(self.createTextNode("%s" % referenced_id))
|
||||
|
||||
|
||||
#
|
||||
# =======================================================================================
|
||||
# Helpers
|
||||
# =======================================================================================
|
||||
|
||||
def get_endpoint(network_object, interface_object):
|
||||
"""
|
||||
Create an Endpoint object given the network and the interface of interest
|
||||
"""
|
||||
ep = None
|
||||
l2devport = None
|
||||
|
||||
# skip if either are none
|
||||
if not network_object or not interface_object:
|
||||
return ep
|
||||
|
||||
# if ifcObj references an interface of a node and is part of this network
|
||||
if interface_object.net.objid == network_object.objid and hasattr(interface_object,
|
||||
'node') and interface_object.node:
|
||||
params = interface_object.getparams()
|
||||
if nodeutils.is_node(interface_object.net, (NodeTypes.HUB, NodeTypes.SWITCH)):
|
||||
l2devport = "%s/e%d" % (interface_object.net.name, interface_object.net.getifindex(interface_object))
|
||||
ep = Endpoint(network_object,
|
||||
interface_object,
|
||||
type=MembType.INTERFACE,
|
||||
id="%s/%s" % (interface_object.node.name, interface_object.name),
|
||||
l2devport=l2devport,
|
||||
params=params)
|
||||
|
||||
# else if ifcObj references another node and is connected to this network
|
||||
elif hasattr(interface_object, "othernet"):
|
||||
if interface_object.othernet.objid == network_object.objid:
|
||||
# #hack used for upstream parameters for link between switches
|
||||
# #(see LxBrNet.linknet())
|
||||
interface_object.swapparams('_params_up')
|
||||
params = interface_object.getparams()
|
||||
interface_object.swapparams('_params_up')
|
||||
owner = interface_object.net
|
||||
l2devport = "%s/e%d" % (
|
||||
interface_object.othernet.name, interface_object.othernet.getifindex(interface_object))
|
||||
|
||||
# Create the endpoint.
|
||||
# XXX the interface index might not match what is shown in the gui. For switches and hubs,
|
||||
# The gui assigns its index but doesn't pass it to the daemon and vice versa.
|
||||
# The gui stores it's index in the IMN file, which it reads and writes without daemon intervention.
|
||||
# Fix this!
|
||||
ep = Endpoint(owner,
|
||||
interface_object,
|
||||
type=MembType.INTERFACE,
|
||||
id="%s/%s/e%d" % (network_object.name, owner.name, owner.getifindex(interface_object)),
|
||||
l2devport=l2devport,
|
||||
params=params)
|
||||
# else this node has an interface that belongs to another network
|
||||
# i.e. a switch/hub interface connected to another switch/hub and CORE has the other switch/hub
|
||||
# as the containing network
|
||||
else:
|
||||
ep = Endpoint(network_object, interface_object, type=None, id=None, l2devport=None, params=None)
|
||||
|
||||
return ep
|
||||
|
||||
|
||||
def get_endpoints(network_object):
|
||||
"""
|
||||
Gather all endpoints of the given network
|
||||
"""
|
||||
# Get all endpoints
|
||||
endpoints = []
|
||||
|
||||
# XXX TODO: How to represent physical interfaces.
|
||||
#
|
||||
# NOTE: The following code works except it would be missing physical (rj45) interfaces from Pt2pt links
|
||||
# TODO: Fix data in net.netifs to include Pt2Pt physical interfaces
|
||||
#
|
||||
# Iterate through all the nodes in the scenario, then iterate through all the interface for each node,
|
||||
# and check if the interface is connected to this network.
|
||||
|
||||
for interface_object in network_object.netifs(sort=True):
|
||||
try:
|
||||
ep = get_endpoint(network_object, interface_object)
|
||||
if ep is not None:
|
||||
endpoints.append(ep)
|
||||
except:
|
||||
logger.debug("error geting endpoints, was skipped before")
|
||||
|
||||
return endpoints
|
||||
|
||||
|
||||
def get_dowmstream_l2_devices(network_object):
|
||||
"""
|
||||
Helper function for getting a list of all downstream layer 2 devices from the given netObj
|
||||
"""
|
||||
l2_device_objects = [network_object]
|
||||
allendpoints = []
|
||||
myendpoints = get_endpoints(network_object)
|
||||
allendpoints.extend(myendpoints)
|
||||
for ep in myendpoints:
|
||||
if ep.type and ep.net.objid != network_object.objid:
|
||||
l2s, eps = get_dowmstream_l2_devices(ep.net)
|
||||
l2_device_objects.extend(l2s)
|
||||
allendpoints.extend(eps)
|
||||
|
||||
return l2_device_objects, allendpoints
|
||||
|
||||
|
||||
def get_all_network_interfaces(session):
|
||||
"""
|
||||
Gather all network interfacecs in the session
|
||||
"""
|
||||
netifs = []
|
||||
for node in session.objects.itervalues():
|
||||
for netif in node.netifs(sort=True):
|
||||
if netif not in netifs:
|
||||
netifs.append(netif)
|
||||
return netifs
|
||||
|
||||
|
||||
def in_other_network(network_object):
|
||||
"""
|
||||
Determine if CORE considers a given network object to be part of another network.
|
||||
Note: CORE considers layer 2 devices to be their own networks. However, if a l2 device
|
||||
is connected to another device, it is possible that one of its ports belong to the other
|
||||
l2 device's network (thus, "othernet").
|
||||
"""
|
||||
for netif in network_object.netifs(sort=True):
|
||||
if hasattr(netif, "othernet"):
|
||||
if netif.othernet.objid != network_object.objid:
|
||||
return True
|
||||
return False
|
|
@ -14,14 +14,14 @@ _EXAMPLES_DIR = "share/core"
|
|||
|
||||
|
||||
def recursive_files(data_path, files_path):
|
||||
data_files = []
|
||||
for path, directories, filenames in os.walk(files_path):
|
||||
all_files = []
|
||||
for path, _directories, filenames in os.walk(files_path):
|
||||
directory = os.path.join(data_path, path)
|
||||
files = []
|
||||
for filename in filenames:
|
||||
files.append(os.path.join(path, filename))
|
||||
data_files.append((directory, files))
|
||||
return data_files
|
||||
all_files.append((directory, files))
|
||||
return all_files
|
||||
|
||||
|
||||
def glob_files(glob_path):
|
||||
|
|
|
@ -8,15 +8,9 @@ from core.enumerations import NodeTypes
|
|||
from core.mobility import BasicRangeModel
|
||||
from core.services.utility import SshService
|
||||
|
||||
_XML_VERSIONS = [
|
||||
"0.0",
|
||||
"1.0"
|
||||
]
|
||||
|
||||
|
||||
class TestXml:
|
||||
@pytest.mark.parametrize("version", _XML_VERSIONS)
|
||||
def test_xml_hooks(self, session, tmpdir, version):
|
||||
def test_xml_hooks(self, session, tmpdir):
|
||||
"""
|
||||
Test save/load hooks in xml.
|
||||
|
||||
|
@ -32,7 +26,7 @@ class TestXml:
|
|||
# save xml
|
||||
xml_file = tmpdir.join("session.xml")
|
||||
file_path = xml_file.strpath
|
||||
session.save_xml(file_path, version)
|
||||
session.save_xml(file_path)
|
||||
|
||||
# verify xml file was created and can be parsed
|
||||
assert xml_file.isfile()
|
||||
|
@ -51,8 +45,7 @@ class TestXml:
|
|||
assert file_name == runtime_hook[0]
|
||||
assert data == runtime_hook[1]
|
||||
|
||||
@pytest.mark.parametrize("version", _XML_VERSIONS)
|
||||
def test_xml_ptp(self, session, tmpdir, version, ip_prefixes):
|
||||
def test_xml_ptp(self, session, tmpdir, ip_prefixes):
|
||||
"""
|
||||
Test xml client methods for a ptp network.
|
||||
|
||||
|
@ -83,7 +76,7 @@ class TestXml:
|
|||
# save xml
|
||||
xml_file = tmpdir.join("session.xml")
|
||||
file_path = xml_file.strpath
|
||||
session.save_xml(file_path, version)
|
||||
session.save_xml(file_path)
|
||||
|
||||
# verify xml file was created and can be parsed
|
||||
assert xml_file.isfile()
|
||||
|
@ -105,8 +98,7 @@ class TestXml:
|
|||
assert session.get_object(n1_id)
|
||||
assert session.get_object(n2_id)
|
||||
|
||||
@pytest.mark.parametrize("version", _XML_VERSIONS)
|
||||
def test_xml_ptp_services(self, session, tmpdir, version, ip_prefixes):
|
||||
def test_xml_ptp_services(self, session, tmpdir, ip_prefixes):
|
||||
"""
|
||||
Test xml client methods for a ptp neetwork.
|
||||
|
||||
|
@ -144,7 +136,7 @@ class TestXml:
|
|||
# save xml
|
||||
xml_file = tmpdir.join("session.xml")
|
||||
file_path = xml_file.strpath
|
||||
session.save_xml(file_path, version)
|
||||
session.save_xml(file_path)
|
||||
|
||||
# verify xml file was created and can be parsed
|
||||
assert xml_file.isfile()
|
||||
|
@ -170,8 +162,7 @@ class TestXml:
|
|||
assert session.get_object(n2_id)
|
||||
assert service.config_data.get(service_file) == file_data
|
||||
|
||||
@pytest.mark.parametrize("version", _XML_VERSIONS)
|
||||
def test_xml_mobility(self, session, tmpdir, version, ip_prefixes):
|
||||
def test_xml_mobility(self, session, tmpdir, ip_prefixes):
|
||||
"""
|
||||
Test xml client methods for mobility.
|
||||
|
||||
|
@ -206,7 +197,7 @@ class TestXml:
|
|||
# save xml
|
||||
xml_file = tmpdir.join("session.xml")
|
||||
file_path = xml_file.strpath
|
||||
session.save_xml(file_path, version)
|
||||
session.save_xml(file_path)
|
||||
|
||||
# verify xml file was created and can be parsed
|
||||
assert xml_file.isfile()
|
||||
|
@ -233,8 +224,7 @@ class TestXml:
|
|||
assert session.get_object(wlan_id)
|
||||
assert value == "1"
|
||||
|
||||
@pytest.mark.parametrize("version", ["1.0"])
|
||||
def test_xml_emane(self, session, tmpdir, version, ip_prefixes):
|
||||
def test_xml_emane(self, session, tmpdir, ip_prefixes):
|
||||
"""
|
||||
Test xml client methods for emane.
|
||||
|
||||
|
@ -274,7 +264,7 @@ class TestXml:
|
|||
# save xml
|
||||
xml_file = tmpdir.join("session.xml")
|
||||
file_path = xml_file.strpath
|
||||
session.save_xml(file_path, version)
|
||||
session.save_xml(file_path)
|
||||
|
||||
# verify xml file was created and can be parsed
|
||||
assert xml_file.isfile()
|
||||
|
|
|
@ -102,7 +102,7 @@ class CoreNs3Node(CoreNode, ns.network.Node):
|
|||
mm = self.GetObject(ns.mobility.MobilityModel.GetTypeId())
|
||||
if z is None:
|
||||
z = 0.0
|
||||
pos = mm.SetPosition(ns.core.Vector(x, y, z))
|
||||
mm.SetPosition(ns.core.Vector(x, y, z))
|
||||
except AttributeError:
|
||||
self.warn("ns-3 mobility model not found, not setting position")
|
||||
|
||||
|
@ -209,10 +209,10 @@ class Ns3LteNet(CoreNs3Net):
|
|||
Register user equipment with a nodeb.
|
||||
Optionally install mobility model while we have the ns-3 devs handy.
|
||||
"""
|
||||
tmp, nodebdev = self.findns3dev(nodeb)
|
||||
tmp, dev = self.findns3dev(node)
|
||||
_tmp, nodebdev = self.findns3dev(nodeb)
|
||||
_tmp, dev = self.findns3dev(node)
|
||||
if nodebdev is None or dev is None:
|
||||
raise KeyError, "ns-3 device for node not found"
|
||||
raise KeyError("ns-3 device for node not found")
|
||||
self.lte.RegisterUeToTheEnb(dev, nodebdev)
|
||||
if mob:
|
||||
self.lte.AddMobility(dev.GetPhy(), mob)
|
||||
|
@ -364,7 +364,7 @@ class Ns3Session(Session):
|
|||
self.duration = duration
|
||||
self.nodes = ns.network.NodeContainer()
|
||||
self.mobhelper = ns.mobility.MobilityHelper()
|
||||
Session.__init__(self, session_id, persistent=persistent)
|
||||
Session.__init__(self, session_id)
|
||||
|
||||
def run(self, vis=False):
|
||||
"""
|
||||
|
@ -488,7 +488,7 @@ class Ns3Session(Session):
|
|||
Start a tracing thread using the ASCII output from the ns3
|
||||
mobility helper.
|
||||
"""
|
||||
net.mobility = WayPointMobility(session=self, object_id=net.objid, config=None)
|
||||
net.mobility = WayPointMobility(session=self, object_id=net.objid)
|
||||
net.mobility.setendtime()
|
||||
net.mobility.refresh_ms = 300
|
||||
net.mobility.empty_queue_stop = False
|
||||
|
@ -528,7 +528,7 @@ class Ns3Session(Session):
|
|||
sleep += 0.001
|
||||
continue
|
||||
sleep = 0.001
|
||||
items = dict(map(lambda x: x.split('='), line.split()))
|
||||
items = dict(x.split("=") for x in line.split())
|
||||
logger.info("trace: %s %s %s", items['node'], items['pos'], items['vel'])
|
||||
x, y, z = map(float, items['pos'].split(':'))
|
||||
vel = map(float, items['vel'].split(':'))
|
||||
|
@ -544,7 +544,7 @@ class Ns3Session(Session):
|
|||
net.mobility.state = net.mobility.STATE_RUNNING
|
||||
self.event_loop.add_event(0, net.mobility.runround)
|
||||
except IOError:
|
||||
logger.exception("mobilitytrace error opening '%s': %s", filename)
|
||||
logger.exception("mobilitytrace error opening: %s", filename)
|
||||
finally:
|
||||
if f:
|
||||
f.close()
|
||||
|
|
|
@ -27,12 +27,9 @@ def ltesession(opt):
|
|||
lte = session.add_object(cls=Ns3LteNet, name="wlan1")
|
||||
lte.setsubchannels(range(25), range(50, 100))
|
||||
if opt.verbose:
|
||||
ascii = ns.network.AsciiTraceHelper()
|
||||
stream = ascii.CreateFileStream('/tmp/ns3lte.tr')
|
||||
ascii_helper = ns.network.AsciiTraceHelper()
|
||||
stream = ascii_helper.CreateFileStream('/tmp/ns3lte.tr')
|
||||
lte.lte.EnableAsciiAll(stream)
|
||||
# ns.core.LogComponentEnable("EnbNetDevice", ns.core.LOG_LEVEL_INFO)
|
||||
# ns.core.LogComponentEnable("UeNetDevice", ns.core.LOG_LEVEL_INFO)
|
||||
# lte.lte.EnableLogComponents()
|
||||
|
||||
prefix = ipaddress.Ipv4Prefix("10.0.0.0/16")
|
||||
mobb = None
|
||||
|
@ -48,7 +45,7 @@ def ltesession(opt):
|
|||
node.newnetif(lte, ["%s/%s" % (prefix.addr(i), prefix.prefixlen)])
|
||||
nodes.append(node)
|
||||
if i == 1:
|
||||
(tmp, ns3dev) = lte.findns3dev(node)
|
||||
_tmp, ns3dev = lte.findns3dev(node)
|
||||
lte.lte.AddMobility(ns3dev.GetPhy(), mob)
|
||||
if i > 1:
|
||||
lte.linknodeb(node, nodes[0], mob, mobb)
|
||||
|
|
0
scripts/perf/configuration_hook.sh
Normal file → Executable file
0
scripts/perf/configuration_hook.sh
Normal file → Executable file
0
scripts/perf/datacollect_hook.sh
Normal file → Executable file
0
scripts/perf/datacollect_hook.sh
Normal file → Executable file
|
@ -2,25 +2,35 @@
|
|||
#
|
||||
# (c)2011-2012 the Boeing Company
|
||||
#
|
||||
# perfmon.py - CORE server and node performace metrics logger and alarmer
|
||||
# server metrics: loadave1, 5, 15, mem, used cpu% of total, cpu1, cpu2, ..., cpun
|
||||
# node metrics: throughput, mem, cpu total, usr, sys, wait
|
||||
#
|
||||
import os, sys, time, re, optparse, signal, commands, pdb
|
||||
|
||||
"""
|
||||
perflogserver.py - CORE server and node performace metrics logger and alarmer
|
||||
server metrics: loadave1, 5, 15, mem, used cpu% of total, cpu1, cpu2, ..., cpun
|
||||
node metrics: throughput, mem, cpu total, usr, sys, wait
|
||||
"""
|
||||
|
||||
import commands
|
||||
import optparse
|
||||
import os
|
||||
import signal
|
||||
import sys
|
||||
import time
|
||||
|
||||
|
||||
def readfile(fname):
|
||||
lines=[]
|
||||
lines = []
|
||||
try:
|
||||
f = open(fname, "r")
|
||||
except:
|
||||
except IOError:
|
||||
if options.timestamp == True:
|
||||
print str(time.time()),
|
||||
print "ERROR: failed to open file %s\n" % fname
|
||||
else :
|
||||
lines = f.readlines()
|
||||
f.close()
|
||||
print str(time.time()),
|
||||
print "ERROR: failed to open file %s\n" % fname
|
||||
else:
|
||||
lines = f.readlines()
|
||||
f.close()
|
||||
return lines
|
||||
|
||||
|
||||
def numcpus():
|
||||
lines = readfile("/proc/stat")
|
||||
n = 0
|
||||
|
@ -30,35 +40,36 @@ def numcpus():
|
|||
n += 1
|
||||
return n
|
||||
|
||||
|
||||
def handler(signum, frame):
|
||||
print "stop timestamp:", str(time.time()) + ", cyclecount=", cyclecount, ", caught signal", signum
|
||||
print "stop timestamp:", str(
|
||||
time.time()) + ", cyclecount=", cyclecount, ", caught signal", signum
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
class ServerMetrics(object):
|
||||
def __init__(self):
|
||||
self.smetrics = { "serverloadavg1" : 0.0,
|
||||
"serverloadavg5" : 0.0,
|
||||
"serverloadavg15" : 0.0,
|
||||
"serverusedmemory" : 0.0,
|
||||
"serverusedcputime" : 0.0,
|
||||
"processorusedcputime" : [] }
|
||||
self.smetrics = {"serverloadavg1": 0.0,
|
||||
"serverloadavg5": 0.0,
|
||||
"serverloadavg15": 0.0,
|
||||
"serverusedmemory": 0.0,
|
||||
"serverusedcputime": 0.0,
|
||||
"processorusedcputime": []}
|
||||
|
||||
# set values from val = (nump, ldavg1, ldavg5, adavg15, mem, cpu, p1cpu, p2cpu...)
|
||||
def setvalues(self, val):
|
||||
"""
|
||||
Set values from val = (nump, ldavg1, ldavg5, adavg15, mem, cpu, p1cpu, p2cpu...).
|
||||
"""
|
||||
self.smetrics["serverloadavg1"] = val[0]
|
||||
self.smetrics["serverloadavg5"] = val[1]
|
||||
self.smetrics["serverloadavg15"] = val[2]
|
||||
self.smetrics["serverusedmemory"] = val[4]
|
||||
self.smetrics["serverusedcputime"] = val[5]
|
||||
#print self.smetrics.keys(), self.smetrics.values()
|
||||
|
||||
pcpu = []
|
||||
for ind in range(5,len(val)):
|
||||
pcpu.append(val[ind])
|
||||
# print "[" + ",".join(map(lambda(x):str(round(x, 2)), pcpu)) +"]"
|
||||
|
||||
pcpu = []
|
||||
for ind in range(5, len(val)):
|
||||
pcpu.append(val[ind])
|
||||
self.smetrics["processorusedcputime"] = pcpu
|
||||
#print self.smetrics.keys(), self.smetrics.values()
|
||||
|
||||
def setvalue(self, key, val):
|
||||
self.smetrics[key] = val
|
||||
|
@ -70,457 +81,470 @@ class ServerMetrics(object):
|
|||
return self.smetrics.keys()
|
||||
|
||||
def tocsv(self):
|
||||
rv = "Server"
|
||||
rv = "Server"
|
||||
for k in self.smetrics:
|
||||
# print k, self.smetrics[k]
|
||||
if isinstance(self.smetrics[k], float):
|
||||
rv += ", %.2f" % self.smetrics[k]
|
||||
else:
|
||||
else:
|
||||
if isinstance(self.smetrics[k], list):
|
||||
rv += ", [" + \
|
||||
", ".join(map(lambda(x):str(round(x, 2)), self.smetrics[k])) \
|
||||
+ "]"
|
||||
else:
|
||||
rv += ", " + str(self.smetrics[k])
|
||||
return rv
|
||||
values = ", ".join(str(round(x, 2)) for x in self.smetrics[k])
|
||||
rv += ", [%s]" % values
|
||||
else:
|
||||
rv += ", " + str(self.smetrics[k])
|
||||
return rv
|
||||
|
||||
|
||||
def readserverthresholds(filename):
|
||||
if filename is None:
|
||||
return
|
||||
return
|
||||
|
||||
lines = readfile(filename)
|
||||
for l in lines:
|
||||
mval = l.strip().split('=')
|
||||
#print "read line %s" % mval
|
||||
if len(mval) > 1 :
|
||||
thekey = mval[0].strip()
|
||||
theval = mval[1].strip()
|
||||
if thekey in serverthresholds.getkeys():
|
||||
serverthresholds.setvalue(thekey, float(theval))
|
||||
# print thekey," = %.2f" % float(theval)
|
||||
|
||||
def checkserverthreshold(metricval):
|
||||
# print out an alarm if a ServerMetrics value crosses threshold
|
||||
mval = l.strip().split('=')
|
||||
if len(mval) > 1:
|
||||
thekey = mval[0].strip()
|
||||
theval = mval[1].strip()
|
||||
if thekey in serverthresholds.getkeys():
|
||||
serverthresholds.setvalue(thekey, float(theval))
|
||||
|
||||
|
||||
def checkserverthreshold(metricval):
|
||||
"""
|
||||
Print out an alarm if a ServerMetrics value crosses threshold.
|
||||
"""
|
||||
for key in serverthresholds.getkeys():
|
||||
# print "checking threshold of key = ", key
|
||||
if key == "processorusedcputime":
|
||||
pcpus = metricval.getvalue(key)
|
||||
# print key, pcpus, serverthresholds[key]
|
||||
for ind in range(0, len(pcpus)):
|
||||
# print ind, pcpus[ind]
|
||||
if pcpus[ind] > serverthresholds.getvalue(key):
|
||||
if key == "processorusedcputime":
|
||||
pcpus = metricval.getvalue(key)
|
||||
for ind, pcpu in enumerate(pcpus):
|
||||
if pcpu > serverthresholds.getvalue(key):
|
||||
alarm = ["server", os.uname()[1], str(ind) + key,
|
||||
"%.2f" % pcpus[ind], ">", serverthresholds.getvalue(key)]
|
||||
"%.2f" % pcpus[ind], ">", serverthresholds.getvalue(key)]
|
||||
if options.timestamp:
|
||||
print str(time.time()) + ",",
|
||||
print ", ".join(map(lambda(x):str(x), alarm))
|
||||
else:
|
||||
if metricval.getvalue(key) > serverthresholds.getvalue(key):
|
||||
print str(time.time()) + ",",
|
||||
print ", ".join(str(x) for x in alarm)
|
||||
else:
|
||||
if metricval.getvalue(key) > serverthresholds.getvalue(key):
|
||||
alarm = ["server", os.uname()[1], key,
|
||||
"%.2f" % metricval.getvalue(key), ">", serverthresholds.getvalue(key)]
|
||||
"%.2f" % metricval.getvalue(key), ">", serverthresholds.getvalue(key)]
|
||||
if options.timestamp:
|
||||
print str(time.time()) + ",",
|
||||
print ", ".join(map(lambda(x):str(x), alarm))
|
||||
print str(time.time()) + ",",
|
||||
print ", ".join(str(x) for x in alarm)
|
||||
|
||||
|
||||
def collectservercputimes():
|
||||
# return cpu times in ticks of this server total and each processor 3*(1+#cpu) columns
|
||||
# (user+nice, sys, idle) from each /proc/stat cpu lines assume columns are:
|
||||
# cpu# user nice sys idle iowait irq softirq steal guest (man 5 proc)
|
||||
"""
|
||||
Return cpu times in ticks of this server total and each processor 3*(1+#cpu) columns
|
||||
(user+nice, sys, idle) from each /proc/stat cpu lines assume columns are:
|
||||
cpu# user nice sys idle iowait irq softirq steal guest (man 5 proc)
|
||||
"""
|
||||
rval = {}
|
||||
lines = readfile("/proc/stat")
|
||||
for i in range(ncpus + 1):
|
||||
items = lines[i].split()
|
||||
(user, nice, sys, idle) = map(lambda(x): int(x), items[1:5])
|
||||
rval[i] = [user+nice, sys, idle]
|
||||
return rval
|
||||
|
||||
def csvservercputimes(cputimes):
|
||||
# return a csv string of this server total and each processor's cpu times
|
||||
# (usr, sys, idle) in ticks
|
||||
rval = ''
|
||||
for i in range(len(cputimes)):
|
||||
rval += ', '.join(map(lambda(x):str(x), cputimes[i]))
|
||||
user, nice, sys, idle = [int(x) for x in items[1:5]]
|
||||
rval[i] = [user+nice, sys, idle]
|
||||
return rval
|
||||
|
||||
|
||||
def csvservercputimes(cputimes):
|
||||
"""
|
||||
Return a csv string of this server total and each processor's cpu times
|
||||
(usr, sys, idle) in ticks.
|
||||
"""
|
||||
rval = ''
|
||||
for i in range(len(cputimes)):
|
||||
rval += ", ".join(str(x) for x in cputimes[i])
|
||||
return rval
|
||||
|
||||
|
||||
def calcservercputimes(cputimea, cputimeb):
|
||||
# return cpu used/total % of this server total and each processor (1+#cpu columns)
|
||||
"""
|
||||
Return cpu used/total % of this server total and each processor (1+#cpu columns).
|
||||
"""
|
||||
p = {}
|
||||
for n in range(ncpus + 1):
|
||||
# print cputimeb[n]
|
||||
p[n] = []
|
||||
for i in range(len(cputimea[n])):
|
||||
p[n].append(cputimeb[n][i] - cputimea[n][i])
|
||||
# print p[n]
|
||||
total = sum(p[n]) # cpu times total delta
|
||||
# print total
|
||||
# cpu times total delta
|
||||
total = sum(p[n])
|
||||
if total == 0:
|
||||
p[n] = 0.0
|
||||
else:
|
||||
p[n] = 100 - ((100.0 * p[n][-1]) / total)
|
||||
return p
|
||||
|
||||
def collectservermems():
|
||||
# return memory (total, free) in KB from proc/meminfo
|
||||
|
||||
def collectservermems():
|
||||
"""
|
||||
Return memory (total, free) in KB from proc/meminfo.
|
||||
"""
|
||||
lines = readfile("/proc/meminfo")
|
||||
mem = map(lambda(x):x.split(), lines[0:2])
|
||||
return map(lambda(x):int(x), zip(*mem)[1])
|
||||
mem = [x.split() for x in lines[0:2]]
|
||||
return [int(x) for x in zip(*mem)[1]]
|
||||
|
||||
def csvservermems(mems):
|
||||
# return a csv string of this server memory (total, free)
|
||||
return ", ".join(map(lambda x: str(x), mems))
|
||||
|
||||
def calcserverusedmem(mems):
|
||||
# return int(100*(MemTotal-MemFree)/MemTotal) from /proc/meminfo
|
||||
def csvservermems(mems):
|
||||
"""
|
||||
Return a csv string of this server memory (total, free).
|
||||
"""
|
||||
return ", ".join(str(x) for x in mems)
|
||||
|
||||
|
||||
def calcserverusedmem(mems):
|
||||
"""
|
||||
Return int(100*(MemTotal-MemFree)/MemTotal) from /proc/meminfo.
|
||||
"""
|
||||
return 100 * (mems[0] - mems[1]) / mems[0]
|
||||
|
||||
|
||||
def collectservermetrics(cputimes, mems, thresholdcheck):
|
||||
# return ServerMetrics object with a dictionary of
|
||||
# loadavg1,loadavg5,loadavg15, usedmem%, usedcpu% for total, cpu1, cpu2, ...
|
||||
"""
|
||||
Return ServerMetrics object with a dictionary of
|
||||
loadavg1,loadavg5,loadavg15, usedmem%, usedcpu% for total, cpu1, cpu2, ...
|
||||
"""
|
||||
metricval = []
|
||||
ldavgs=os.getloadavg()
|
||||
ldavgs = os.getloadavg()
|
||||
for v in ldavgs:
|
||||
metricval.append(v)
|
||||
metricval.append(calcserverusedmem(mems))
|
||||
|
||||
for i in range(ncpus + 1):
|
||||
metricval.append(cputimes[i])
|
||||
# print cputimes[i]
|
||||
metricval.append(cputimes[i])
|
||||
|
||||
srvmetrics = ServerMetrics()
|
||||
srvmetrics.setvalues(metricval)
|
||||
# print srvmetrics.tocsv()
|
||||
|
||||
if thresholdcheck:
|
||||
checkserverthreshold(srvmetrics)
|
||||
checkserverthreshold(srvmetrics)
|
||||
|
||||
return srvmetrics
|
||||
|
||||
|
||||
|
||||
def csvservermetrics(srvmetrics):
|
||||
# return a csv string of ServerMetrics.tocsv()
|
||||
# loadavg1,loadavg5,loadavg15, usedmem%, usedcpu% for total, cpu1, cpu2, ...
|
||||
"""
|
||||
Return a csv string of ServerMetrics.tocsv()
|
||||
loadavg1,loadavg5,loadavg15, usedmem%, usedcpu% for total, cpu1, cpu2, ...
|
||||
"""
|
||||
rv = ""
|
||||
if options.timestamp:
|
||||
rv = str(time.time()) + ", "
|
||||
rv = str(time.time()) + ", "
|
||||
rv += srvmetrics.tocsv()
|
||||
return rv
|
||||
|
||||
|
||||
def csvserverbaseline():
|
||||
# return a csv string of raw server metrics data: memfree, memtotal, cpuused, cpusystem, cpuidle
|
||||
"""
|
||||
Return a csv string of raw server metrics data: memfree, memtotal, cpuused, cpusystem, cpuidle.
|
||||
"""
|
||||
return "memory (total, free) = " + csvservermems(collectservermems()) + "\ncputime (used, sys, idl) = " + csvservercputimes(collectservercputimes())
|
||||
|
||||
|
||||
class NodeMetrics(object):
|
||||
def __init__(self):
|
||||
self.nmetrics = {"nodethroughput" : 0.0,
|
||||
"nodeusedmemory" : 0.0,
|
||||
"nodetotalcpu" : 0.0,
|
||||
"nodeusercpu" : 0.0,
|
||||
"nodesystemcpu" : 0.0,
|
||||
"nodewaitcpu" : 0.0}
|
||||
self.nmetrics = {"nodethroughput": 0.0,
|
||||
"nodeusedmemory": 0.0,
|
||||
"nodetotalcpu": 0.0,
|
||||
"nodeusercpu": 0.0,
|
||||
"nodesystemcpu": 0.0,
|
||||
"nodewaitcpu": 0.0}
|
||||
|
||||
# set values from val = (throughput, mem, tcpu, ucpu, scpu, wcpu):
|
||||
def setvalues(self, val):
|
||||
self.nmetrics["nodethroughput"] = val[0]
|
||||
self.nmetrics["nodeusedmemory"] = val[1]
|
||||
self.nmetrics["nodetotalcpu"] = val[2]
|
||||
self.nmetrics["nodeusercpu"] = val[3]
|
||||
self.nmetrics["nodesystemcpu"] = val[4]
|
||||
self.nmetrics["nodewaitcpu"] = val[5]
|
||||
"""
|
||||
Set values from val = (throughput, mem, tcpu, ucpu, scpu, wcpu).
|
||||
"""
|
||||
self.nmetrics["nodethroughput"] = val[0]
|
||||
self.nmetrics["nodeusedmemory"] = val[1]
|
||||
self.nmetrics["nodetotalcpu"] = val[2]
|
||||
self.nmetrics["nodeusercpu"] = val[3]
|
||||
self.nmetrics["nodesystemcpu"] = val[4]
|
||||
self.nmetrics["nodewaitcpu"] = val[5]
|
||||
|
||||
def setvalue(self, key, val):
|
||||
self.nmetrics[key] = val
|
||||
self.nmetrics[key] = val
|
||||
|
||||
def getvalue(self, key):
|
||||
return self.nmetrics[key]
|
||||
return self.nmetrics[key]
|
||||
|
||||
def getkeys(self):
|
||||
return self.nmetrics.keys()
|
||||
return self.nmetrics.keys()
|
||||
|
||||
def tocsv(self):
|
||||
return ", ".join(map(lambda(x):str(x), self.nmetrics.values()))
|
||||
return ", ".join(str(x) for x in self.nmetrics.values())
|
||||
|
||||
|
||||
class LogSession(object):
|
||||
def __init__(self):
|
||||
self.nodethresholds = NodeMetrics()
|
||||
# set node threshold default values:
|
||||
# nodethroughput=20.0, nodeusedmemory=15.0, nodetotalcpu=90.0,
|
||||
# nodeusercpu=30.0, nodewaitcpu=50.0, nodesystemcpu=20.0}
|
||||
self.nodethresholds.setvalues([20.0, 15.0, 90.0, 30.0, 50.0, 20.0])
|
||||
if options.configfile is not None:
|
||||
self.readnodethresholds(options.configfile)
|
||||
# set node threshold default values:
|
||||
# nodethroughput=20.0, nodeusedmemory=15.0, nodetotalcpu=90.0,
|
||||
# nodeusercpu=30.0, nodewaitcpu=50.0, nodesystemcpu=20.0}
|
||||
self.nodethresholds.setvalues([20.0, 15.0, 90.0, 30.0, 50.0, 20.0])
|
||||
if options.configfile is not None:
|
||||
self.readnodethresholds(options.configfile)
|
||||
self.pids = {}
|
||||
self.nodemetricsA = {}
|
||||
self.nodemetricsB = {}
|
||||
self.nodemetricsC = {}
|
||||
|
||||
def getpids(self):
|
||||
# return dict of all CORE session pids in a dict using node name as the keys
|
||||
# parent pid (vnoded) is the first value
|
||||
def getpids(self):
|
||||
"""
|
||||
Return dict of all CORE session pids in a dict using node name as the keys
|
||||
parent pid (vnoded) is the first value.
|
||||
"""
|
||||
self.pids = {}
|
||||
nodes = commands.getstatusoutput("ls /tmp/pycore.%s/*pid" % options.session)
|
||||
nodes = commands.getstatusoutput(
|
||||
"ls /tmp/pycore.%s/*pid" % options.session)
|
||||
if nodes[0] != 0:
|
||||
# if options.timestamp == True:
|
||||
# print str(time.time()),
|
||||
# print "CORE session %s has not created nodes" % options.session
|
||||
return
|
||||
|
||||
return
|
||||
|
||||
nodes = nodes[1].split('\n')
|
||||
for nod in nodes:
|
||||
nodename = nod.split('/')[-1].strip(".pid")
|
||||
self.pids[nodename] = commands.getoutput("cat %s" % nod)
|
||||
|
||||
nodename = nod.split('/')[-1].strip(".pid")
|
||||
self.pids[nodename] = commands.getoutput("cat %s" % nod)
|
||||
|
||||
# do not expect failure of this command
|
||||
procs = commands.getoutput('ps -eo ppid,pid,comm').split('\n')
|
||||
|
||||
|
||||
# build self.pids dict with key=nodename and val="ppid,pid,cmd"
|
||||
for nname in self.pids:
|
||||
# print nname, self.pids[nname]
|
||||
if self.pids[nname] == "":
|
||||
if options.timestamp == True:
|
||||
print str(time.time()),
|
||||
print "ERROR: null vnoded pid of node: %s" % nname
|
||||
else:
|
||||
childprocs = []
|
||||
ppid = self.pids[nname]
|
||||
if options.timestamp == True:
|
||||
print str(time.time()),
|
||||
print "ERROR: null vnoded pid of node: %s" % nname
|
||||
else:
|
||||
childprocs = []
|
||||
ppid = self.pids[nname]
|
||||
for proc in procs:
|
||||
val=proc.split()
|
||||
if ppid == val[1]:
|
||||
childprocs.append([val[1], val[2]] )
|
||||
if ppid == val[0]:
|
||||
childprocs.append([val[1], val[2]])
|
||||
val = proc.split()
|
||||
if ppid == val[1]:
|
||||
childprocs.append([val[1], val[2]])
|
||||
if ppid == val[0]:
|
||||
childprocs.append([val[1], val[2]])
|
||||
self.pids[nname] = childprocs
|
||||
# print nname, self.pids[nname]
|
||||
return self.pids
|
||||
|
||||
|
||||
def printsesspids(self):
|
||||
if self.pids == {}:
|
||||
return {}
|
||||
for pp in self.pids:
|
||||
if self.pids[pp] != []:
|
||||
if self.pids[pp] != []:
|
||||
for ap in range(len(self.pids[pp]) - 1):
|
||||
print ", " + self.pids[pp][ap][0], # ap pid
|
||||
print ", " + self.pids[pp][ap][1], # ap cmd
|
||||
procmetrics = map(lambda(x):str(x),self.pids[pp][ap][-1])
|
||||
print ", " + ", ".join(procmetrics),
|
||||
nodemetrics = map(lambda(x):str(x), self.pids[pp][-1])
|
||||
print ", " + ", ".join(nodemetrics)
|
||||
# ap pid
|
||||
print ", " + self.pids[pp][ap][0],
|
||||
# ap cmd
|
||||
print ", " + self.pids[pp][ap][1],
|
||||
procmetrics = [str(x) for x in self.pids[pp][ap][-1]]
|
||||
print ", " + ", ".join(procmetrics),
|
||||
nodemetrics = [str(x) for x in self.pids[pp][-1]]
|
||||
print ", " + ", ".join(nodemetrics)
|
||||
|
||||
def getprocessmetrics(self, pid):
|
||||
# return [cpu#, vsize(kb), ttime, utime, stime, wtime]
|
||||
# from a /proc/pid/stat (a single line file) assume columns are:
|
||||
# pid(0) comm(1) state ppid pgrp sess tty_nr tpgid flags
|
||||
# minflt cmiflt majflt cmajflt # utime(12) stime cutime cstime
|
||||
# priority nice num_threads itrealvalue starttime vsize(22) rss rsslim
|
||||
# startcode endcode startstack kstkesp signal blocked sigignore sigcatch
|
||||
# wchan nswap cnswap exit_signal processor(38) rt_priority
|
||||
# policy ioblock guest_time cguest_time (man 5 proc)
|
||||
#rval = ProcessMetrics()
|
||||
#rval.__init__()
|
||||
"""
|
||||
Return [cpu#, vsize(kb), ttime, utime, stime, wtime]
|
||||
from a /proc/pid/stat (a single line file) assume columns are:
|
||||
pid(0) comm(1) state ppid pgrp sess tty_nr tpgid flags
|
||||
minflt cmiflt majflt cmajflt # utime(12) stime cutime cstime
|
||||
priority nice num_threads itrealvalue starttime vsize(22) rss rsslim
|
||||
startcode endcode startstack kstkesp signal blocked sigignore sigcatch
|
||||
wchan nswap cnswap exit_signal processor(38) rt_priority
|
||||
policy ioblock guest_time cguest_time (man 5 proc)
|
||||
"""
|
||||
rval = {}
|
||||
lines = readfile("/proc/" + pid + "/stat")
|
||||
if lines == []:
|
||||
return rval
|
||||
return rval
|
||||
items = lines[0].split()
|
||||
(utime, stime, cutime, cstime) = map(lambda(x):int(x), items[13:17])
|
||||
# print ">???", utime, stime, cutime, cstime
|
||||
utime, stime, cutime, cstime = [int(x) for x in items[13:17]]
|
||||
rval = (items[38], # last run processor
|
||||
int(items[22])/1000, # process virtual mem in kb
|
||||
utime + stime + cutime + cstime,# totoal time
|
||||
int(items[22])/1000, # process virtual mem in kb
|
||||
utime + stime + cutime + cstime, # totoal time
|
||||
utime, # user time
|
||||
stime, # system time
|
||||
cutime + cstime) # wait time
|
||||
# print "pid --- processmetrics", rval
|
||||
return rval
|
||||
|
||||
|
||||
def getnodethroughput(self, pid):
|
||||
# return node throughput of total receive and transmit packets in kb
|
||||
"""
|
||||
Return node throughput of total receive and transmit packets in kb.
|
||||
"""
|
||||
lines = readfile("/proc/" + pid + "/net/dev")
|
||||
if lines == []:
|
||||
return -0.00
|
||||
ifs = map(lambda(x): x.split(), lines[2:])
|
||||
return -0.00
|
||||
ifs = [x.split() for x in lines[2:]]
|
||||
ifm = zip(*ifs)
|
||||
rv = sum(map(lambda(x):int(x), ifm[1])) # received bytes
|
||||
tr = sum(map(lambda(x):int(x), ifm[9])) # transmited bytes
|
||||
#print 'node thruput :', rv, tr, (rv + tr)/1000
|
||||
rv = sum(int(x) for x in ifm[1]) # received bytes
|
||||
tr = sum(int(x) for x in ifm[9]) # transmited bytes
|
||||
return (rv + tr)/1000
|
||||
|
||||
|
||||
def getnodemetrics(self, mindex):
|
||||
# return NodeMetrics with indexed by nodename, values are rows of
|
||||
# [ [ppid, vnoded, [cpu#, vmem(kb), ttime, utime, stime, wtime]],
|
||||
# [cpid, cmd, [cpu#, vmem(kb), ttime, utime, stime, wtime]], ... ,
|
||||
# [thrput, vmem(kb), ttime, utime, stime, wtime]]
|
||||
if mindex == 'a':
|
||||
metricref = self.nodemetricsA
|
||||
else:
|
||||
metricref = self.nodemetricsB
|
||||
"""
|
||||
Return NodeMetrics with indexed by nodename, values are rows of
|
||||
[ [ppid, vnoded, [cpu#, vmem(kb), ttime, utime, stime, wtime]],
|
||||
[cpid, cmd, [cpu#, vmem(kb), ttime, utime, stime, wtime]], ... ,
|
||||
[thrput, vmem(kb), ttime, utime, stime, wtime]]
|
||||
"""
|
||||
if mindex == 'a':
|
||||
metricref = self.nodemetricsA
|
||||
else:
|
||||
metricref = self.nodemetricsB
|
||||
|
||||
self.getpids()
|
||||
# print " inside getnodemetrics()", self.pids
|
||||
if self.pids == {}:
|
||||
return {}
|
||||
|
||||
return {}
|
||||
|
||||
for nod in self.pids:
|
||||
nmetric = NodeMetrics()
|
||||
nmetric.__init__()
|
||||
nodeapps = {}
|
||||
for ap in range(len(self.pids[nod])): # get each process metrics
|
||||
procm = self.getprocessmetrics(self.pids[nod][ap][0])
|
||||
if procm == []:
|
||||
if options.timestamp == True:
|
||||
print str(time.time()),
|
||||
print "WARNING: transient process", self.pids[nod][ap][1], \
|
||||
"/", self.pids[nod][ap][0], "on node %s" % nod
|
||||
else:
|
||||
nodeapps[ap] = procm
|
||||
self.pids[nod][ap].append(nodeapps[ap])
|
||||
processm = zip(*nodeapps.values()) # get overall node metrics
|
||||
# print processm
|
||||
if len(processm) > 0:
|
||||
# if nod == 'n6':
|
||||
# print nod, self.getnodethroughput(self.pids[nod][0][0])
|
||||
nmetric.setvalues(( self.getnodethroughput(self.pids[nod][0][0]),
|
||||
sum(map(lambda(x):int(x), processm[1])), # vsize(kb)
|
||||
sum(map(lambda(x):int(x), processm[2])), # ttime
|
||||
sum(map(lambda(x):int(x), processm[3])), # utime
|
||||
sum(map(lambda(x):int(x), processm[4])), # stime
|
||||
sum(map(lambda(x):int(x), processm[5])))) # wtime
|
||||
for ap in range(len(self.pids[nod])): # get each process metrics
|
||||
procm = self.getprocessmetrics(self.pids[nod][ap][0])
|
||||
if procm == []:
|
||||
if options.timestamp == True:
|
||||
print str(time.time()),
|
||||
print "WARNING: transient process", self.pids[nod][ap][1], \
|
||||
"/", self.pids[nod][ap][0], "on node %s" % nod
|
||||
else:
|
||||
nodeapps[ap] = procm
|
||||
self.pids[nod][ap].append(nodeapps[ap])
|
||||
processm = zip(*nodeapps.values()) # get overall node metrics
|
||||
if len(processm) > 0:
|
||||
nmetric.setvalues((self.getnodethroughput(self.pids[nod][0][0]),
|
||||
# vsize(kb)
|
||||
sum(int(x) for x in processm[1]),
|
||||
# ttime
|
||||
sum(int(x) for x in processm[2]),
|
||||
# utime
|
||||
sum(int(x) for x in processm[3]),
|
||||
# stime
|
||||
sum(int(x) for x in processm[4]),
|
||||
sum(int(x) for x in processm[5]))) # wtime
|
||||
metricref[nod] = nmetric
|
||||
# print nod, self.pids[nod][0][0], metricref[nod].tocsv()
|
||||
return metricref
|
||||
|
||||
def setnodemetricsC(self, key, val):
|
||||
self.nodemetricsC[key] = val
|
||||
def setnodemetricsC(self, key, val):
|
||||
self.nodemetricsC[key] = val
|
||||
|
||||
def printnodemetrics(self, mindex):
|
||||
def printnodemetrics(self, mindex):
|
||||
if mindex == 'c':
|
||||
mm = self.nodemetricsC
|
||||
else:
|
||||
if mindex == 'a':
|
||||
mm = self.nodemetricsA
|
||||
else:
|
||||
mm = self.nodemetricsB
|
||||
mm = self.nodemetricsC
|
||||
else:
|
||||
if mindex == 'a':
|
||||
mm = self.nodemetricsA
|
||||
else:
|
||||
mm = self.nodemetricsB
|
||||
|
||||
for k in self.nodemetricsC:
|
||||
for k in self.nodemetricsC:
|
||||
if options.timestamp:
|
||||
print str(time.time()) + ",",
|
||||
print k, ",", mm[k].tocsv()
|
||||
print k, ",", mm[k].tocsv()
|
||||
|
||||
def readnodethresholds(self, filename):
|
||||
if filename is None:
|
||||
return
|
||||
lines = readfile(filename)
|
||||
def readnodethresholds(self, filename):
|
||||
if filename is None:
|
||||
return
|
||||
lines = readfile(filename)
|
||||
for l in lines:
|
||||
mval = l.strip().split('=')
|
||||
# print "read line %s" % mval
|
||||
if len(mval) > 1 :
|
||||
thekey = mval[0].strip()
|
||||
theval = mval[1].strip()
|
||||
if thekey in self.nodethresholds.getkeys():
|
||||
self.nodethresholds.setvalue(thekey, float(theval))
|
||||
#print thekey," = %.2f" % float(theval)
|
||||
|
||||
mval = l.strip().split('=')
|
||||
if len(mval) > 1:
|
||||
thekey = mval[0].strip()
|
||||
theval = mval[1].strip()
|
||||
if thekey in self.nodethresholds.getkeys():
|
||||
self.nodethresholds.setvalue(thekey, float(theval))
|
||||
|
||||
def checknodethresholds(self, nname):
|
||||
# print "check node thresholds", nname
|
||||
calcm = self.nodemetricsC[nname]
|
||||
calcm = self.nodemetricsC[nname]
|
||||
for keyname in self.nodethresholds.getkeys():
|
||||
# print "HIII", keyname, calcm.getvalue(keyname), self.nodethresholds.getvalue(keyname)
|
||||
if float(calcm.getvalue(keyname)) > float(self.nodethresholds.getvalue(keyname)):
|
||||
# print calculatednodem.getvalue(m)
|
||||
alarm = ["node", nname + "/" + self.pids[nname][0][0], keyname,\
|
||||
calcm.getvalue(keyname), ">", self.nodethresholds.getvalue(keyname)]
|
||||
if float(calcm.getvalue(keyname)) > float(self.nodethresholds.getvalue(keyname)):
|
||||
alarm = ["node", nname + "/" + self.pids[nname][0][0], keyname,
|
||||
calcm.getvalue(keyname), ">", self.nodethresholds.getvalue(keyname)]
|
||||
if options.timestamp:
|
||||
print str(time.time()) + ",",
|
||||
print ", ".join(map(lambda(x):str(x), alarm))
|
||||
print ", ".join(str(x) for x in alarm)
|
||||
|
||||
def calcnodemetrics(self, cputimea, cputimeb, mems):
|
||||
# return a dict of nodemetrics indexed by node name
|
||||
# nodemetrics[nodename][-1] = node/host%
|
||||
"""
|
||||
Return a dict of nodemetrics indexed by node name
|
||||
nodemetrics[nodename][-1] = node/host%.
|
||||
"""
|
||||
p = []
|
||||
for i in range(len(cputimeb[0])):
|
||||
p.append(cputimeb[0][i] - cputimea[0][i])
|
||||
hostusedcpu = p[0] + p[1]
|
||||
hostusedmem = mems[0] - mems[1]
|
||||
if hostusedcpu == 0:
|
||||
print "WARNING: host used cpu = 0, ", p[0], p[1]
|
||||
hostusedcpu = 1
|
||||
print "WARNING: host used cpu = 0, ", p[0], p[1]
|
||||
hostusedcpu = 1
|
||||
if hostusedmem == 0:
|
||||
print "WARNING: host used mem = 0, ", mems[0], mems[1]
|
||||
hostusedmem = 1
|
||||
print "WARNING: host used mem = 0, ", mems[0], mems[1]
|
||||
hostusedmem = 1
|
||||
|
||||
nodesa = self.nodemetricsA
|
||||
nodesb = self.nodemetricsB
|
||||
nodesa = self.nodemetricsA
|
||||
nodesb = self.nodemetricsB
|
||||
for nod in nodesb:
|
||||
calcm = self.nodemetricsC
|
||||
calcm = self.nodemetricsC
|
||||
calcm = NodeMetrics()
|
||||
calcm.__init__()
|
||||
if (nod in nodesa):
|
||||
try:
|
||||
if (nodesb[nod] == []) | (nodesa[nod] == []) | \
|
||||
( False == isinstance(nodesb[nod], NodeMetrics)) | \
|
||||
( False == isinstance(nodesa[nod], NodeMetrics)):
|
||||
if options.timestamp == True:
|
||||
print str(time.time()),
|
||||
print "Warning: nodes %s is not fully instanciated" % nod
|
||||
else:
|
||||
# calc throughput kbps
|
||||
#print "node b : ", nodesb[nod].tocsv()
|
||||
#print "node a : ", nodesa[nod].tocsv()
|
||||
#if nod == 'n6':
|
||||
#print nodesb[nod].getvalue("nodethroughput"), nodesa[nod].getvalue("nodethroughput")
|
||||
calcm.setvalue("nodethroughput", "%.2f" % (8 * (nodesb[nod].getvalue("nodethroughput") \
|
||||
- nodesa[nod].getvalue("nodethroughput")) / options.interval))
|
||||
# calc mem node used / host used
|
||||
calcm.setvalue("nodeusedmemory", "%.2f" % (100.0 * (nodesb[nod].getvalue("nodeusedmemory") / hostusedmem)))
|
||||
|
||||
# calc total cpu time node / host
|
||||
calcm.setvalue("nodetotalcpu", "%.2f" % (100.0 * (nodesb[nod].getvalue("nodetotalcpu")\
|
||||
- nodesa[nod].getvalue("nodetotalcpu")) /hostusedcpu))
|
||||
# calc user cpu time node / host
|
||||
calcm.setvalue("nodeusercpu", "%.2f" % (100.0 * (nodesb[nod].getvalue("nodeusercpu")\
|
||||
- nodesa[nod].getvalue("nodeusercpu")) /hostusedcpu))
|
||||
# calc system cpu time node / host
|
||||
calcm.setvalue("nodesystemcpu", "%.2f" % (100.0 * (nodesb[nod].getvalue("nodesystemcpu")\
|
||||
- nodesa[nod].getvalue("nodesystemcpu")) /hostusedcpu))
|
||||
# calc waitcpu time node / host
|
||||
calcm.setvalue("nodewaitcpu", "%.2f" % (100.0 * (nodesb[nod].getvalue("nodewaitcpu")\
|
||||
- nodesa[nod].getvalue("nodewaitcpu")) /hostusedcpu))
|
||||
calcm.__init__()
|
||||
if (nod in nodesa):
|
||||
try:
|
||||
if (nodesb[nod] == []) | (nodesa[nod] == []) | \
|
||||
(False == isinstance(nodesb[nod], NodeMetrics)) | \
|
||||
(False == isinstance(nodesa[nod], NodeMetrics)):
|
||||
if options.timestamp == True:
|
||||
print str(time.time()),
|
||||
print "Warning: nodes %s is not fully instanciated" % nod
|
||||
else:
|
||||
# calc throughput kbps
|
||||
calcm.setvalue("nodethroughput", "%.2f" % (8 * (nodesb[nod].getvalue("nodethroughput")
|
||||
- nodesa[nod].getvalue("nodethroughput")) / options.interval))
|
||||
# calc mem node used / host used
|
||||
calcm.setvalue("nodeusedmemory", "%.2f" % (
|
||||
100.0 * (nodesb[nod].getvalue("nodeusedmemory") / hostusedmem)))
|
||||
|
||||
#print nod, calcm.tocsv()
|
||||
#print '=========================='
|
||||
logsession.nodemetricsC[nod] = calcm
|
||||
# logsession.printnodemetrics('c')
|
||||
# calc total cpu time node / host
|
||||
calcm.setvalue("nodetotalcpu", "%.2f" % (100.0 * (nodesb[nod].getvalue("nodetotalcpu")
|
||||
- nodesa[nod].getvalue("nodetotalcpu")) / hostusedcpu))
|
||||
# calc user cpu time node / host
|
||||
calcm.setvalue("nodeusercpu", "%.2f" % (100.0 * (nodesb[nod].getvalue("nodeusercpu")
|
||||
- nodesa[nod].getvalue("nodeusercpu")) / hostusedcpu))
|
||||
# calc system cpu time node / host
|
||||
calcm.setvalue("nodesystemcpu", "%.2f" % (100.0 * (nodesb[nod].getvalue("nodesystemcpu")
|
||||
- nodesa[nod].getvalue("nodesystemcpu")) / hostusedcpu))
|
||||
# calc waitcpu time node / host
|
||||
calcm.setvalue("nodewaitcpu", "%.2f" % (100.0 * (nodesb[nod].getvalue("nodewaitcpu")
|
||||
- nodesa[nod].getvalue("nodewaitcpu")) / hostusedcpu))
|
||||
logsession.nodemetricsC[nod] = calcm
|
||||
|
||||
if options.alarm is not None:
|
||||
logsession.checknodethresholds(nod)
|
||||
except IndexError:
|
||||
pass
|
||||
else:
|
||||
print "Warning: transient node %s " % nod
|
||||
logsession.checknodethresholds(nod)
|
||||
except IndexError:
|
||||
pass
|
||||
else:
|
||||
print "Warning: transient node %s " % nod
|
||||
|
||||
return nodesb
|
||||
|
||||
|
||||
|
||||
def main():
|
||||
usagestr = "%prog [-h] [options] [args]\n\nLog server and optional CORE session metrics to stdout."
|
||||
parser = optparse.OptionParser(usage = usagestr)
|
||||
parser.set_defaults(interval=2, timestamp=False,
|
||||
configfile = "/etc/core/perflogserver.conf",\
|
||||
alarm = True, session = None)
|
||||
parser.add_option("-i", "--interval", dest = "interval", type = int,
|
||||
help = "seconds to wait between samples; default=%s" %
|
||||
parser = optparse.OptionParser(usage=usagestr)
|
||||
parser.set_defaults(interval=2, timestamp=False,
|
||||
configfile="/etc/core/perflogserver.conf",
|
||||
alarm=True, session=None)
|
||||
parser.add_option("-i", "--interval", dest="interval", type=int,
|
||||
help="seconds to wait between samples; default=%s" %
|
||||
parser.defaults["interval"])
|
||||
parser.add_option("-t", "--timestamp", action = "store_true",
|
||||
dest = "timestamp",
|
||||
help = "include timestamp on each line")
|
||||
parser.add_option("-c", "--configfile", dest = "configfile",
|
||||
type = "string",
|
||||
help = "read threshold values from the specified file;\
|
||||
parser.add_option("-t", "--timestamp", action="store_true",
|
||||
dest="timestamp",
|
||||
help="include timestamp on each line")
|
||||
parser.add_option("-c", "--configfile", dest="configfile",
|
||||
type="string",
|
||||
help="read threshold values from the specified file;\
|
||||
default=%s" % parser.defaults["configfile"])
|
||||
parser.add_option("-a", "--alarm", action = "store_true",
|
||||
dest = "alarm",
|
||||
help = "generate alarms based threshold check on each cycle")
|
||||
parser.add_option("-s", "--session", dest = "session", type = int,
|
||||
help = "CORE session id; default=%s" %
|
||||
parser.add_option("-a", "--alarm", action="store_true",
|
||||
dest="alarm",
|
||||
help="generate alarms based threshold check on each cycle")
|
||||
parser.add_option("-s", "--session", dest="session", type=int,
|
||||
help="CORE session id; default=%s" %
|
||||
parser.defaults["session"])
|
||||
global options
|
||||
global ncpus
|
||||
|
@ -528,8 +552,7 @@ def main():
|
|||
global logsession
|
||||
global cyclecount
|
||||
|
||||
(options, args) = parser.parse_args()
|
||||
# print options
|
||||
options, _args = parser.parse_args()
|
||||
|
||||
signal.signal(signal.SIGINT, handler)
|
||||
signal.signal(signal.SIGTERM, handler)
|
||||
|
@ -538,51 +561,47 @@ def main():
|
|||
|
||||
# server threshold dictionary - a ServerMetrics instant with default values
|
||||
serverthresholds = ServerMetrics()
|
||||
# set to server threshold default values: serverloadavg1=3.5,
|
||||
# serverloadavg5=3.5, serverloadavg15=3.5, serverusedmemory=80.0,
|
||||
# set to server threshold default values: serverloadavg1=3.5,
|
||||
# serverloadavg5=3.5, serverloadavg15=3.5, serverusedmemory=80.0,
|
||||
# serverusedcputime=80.0, processorusedcputime=90.0
|
||||
serverthresholds.setvalues([3.5, 3.5, 3.5, 80.0, 80.0, 90.0])
|
||||
if options.alarm is True:
|
||||
# read server threshold values from configuration file
|
||||
readserverthresholds(options.configfile)
|
||||
|
||||
readserverthresholds(options.configfile)
|
||||
|
||||
if options.session is not None:
|
||||
logsession = LogSession()
|
||||
# print logsession
|
||||
|
||||
# mark host log baseline
|
||||
print "server: ", ", ".join(map(lambda(x):str(x), os.uname())), ",", ncpus, "CPU cores"
|
||||
print "server: ", ", ".join(str(x) for x in os.uname()), ",", ncpus, "CPU cores"
|
||||
print "start timestamp:", time.time(), ", baseline data: "
|
||||
print csvserverbaseline()
|
||||
print "server metrics: ", ", ".join(map(lambda(x):str(x), serverthresholds.getkeys()))
|
||||
print "server metrics: ", ", ".join(str(x) for x in serverthresholds.getkeys())
|
||||
if options.session is not None:
|
||||
print "node metrics: nodename, ", ", ".join(map(lambda(x):str(x), logsession.nodethresholds.getkeys()))
|
||||
print "node metrics: nodename, ", ", ".join(str(x) for x in logsession.nodethresholds.getkeys())
|
||||
|
||||
cyclecount = 0
|
||||
while True:
|
||||
cputimea = collectservercputimes()
|
||||
if options.session is not None:
|
||||
nodesa = logsession.getnodemetrics('a')
|
||||
# print "nodes a:", nodesa
|
||||
|
||||
nodesa = logsession.getnodemetrics("a")
|
||||
time.sleep(options.interval)
|
||||
|
||||
cputimeb = collectservercputimes()
|
||||
mems = collectservermems()
|
||||
|
||||
mems = collectservermems()
|
||||
calccputime = calcservercputimes(cputimea, cputimeb)
|
||||
m = csvservermetrics(collectservermetrics(calccputime, mems, options.alarm))
|
||||
print m
|
||||
m = csvservermetrics(collectservermetrics(
|
||||
calccputime, mems, options.alarm))
|
||||
print m
|
||||
|
||||
if options.session is not None:
|
||||
nodesb = logsession.getnodemetrics('b')
|
||||
# print "nodes b:", nodesb
|
||||
if nodesb != {}:
|
||||
logsession.calcnodemetrics(cputimea, cputimeb, mems)
|
||||
logsession.printnodemetrics('c')
|
||||
nodesb = logsession.getnodemetrics('b')
|
||||
if nodesb != {}:
|
||||
logsession.calcnodemetrics(cputimea, cputimeb, mems)
|
||||
logsession.printnodemetrics('c')
|
||||
|
||||
sys.stdout.flush()
|
||||
sys.stdout.flush()
|
||||
cyclecount = cyclecount + 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
4
scripts/perf/perflogstart.sh
Normal file → Executable file
4
scripts/perf/perflogstart.sh
Normal file → Executable file
|
@ -4,7 +4,7 @@
|
|||
#
|
||||
# start core performance logging and collect output to file
|
||||
# /tmp/pycore.nnnn/perf<sessionid>.log
|
||||
HOOKS_DIR=`dirname $0`
|
||||
HOOKS_DIR=$(dirname $0)
|
||||
|
||||
sid=` pwd | awk -F / {'print $3'} | awk -F . {'print $2'} `
|
||||
sid=$(pwd | awk -F / {'print $3'} | awk -F . {'print $2'})
|
||||
python $HOOKS_DIR/perflogserver.py -t -a -c /etc/core/perflogserver.conf -s $sid > perf$sid.log &
|
||||
|
|
2
scripts/perf/perflogstop.sh
Normal file → Executable file
2
scripts/perf/perflogstop.sh
Normal file → Executable file
|
@ -4,7 +4,7 @@
|
|||
#
|
||||
# terminate core perfromance logging process
|
||||
|
||||
perfproc=` ps aux | grep perflogserver | grep python | awk {'print $2'} `
|
||||
perfproc=$(ps aux | grep perflogserver | grep python | awk {'print $2'})
|
||||
if [ ! $perfproc = "" ]; then
|
||||
echo "terminating core performance log process $perfproc"
|
||||
kill -9 $perfproc
|
||||
|
|
12
scripts/perf/sessiondatacollect.sh
Normal file → Executable file
12
scripts/perf/sessiondatacollect.sh
Normal file → Executable file
|
@ -6,9 +6,9 @@
|
|||
# Collection such runtime tar balls from all distributed servers to folder
|
||||
# /tmp/<sessionid>-<date>-<time> for example: /tmp/56779-11Oct14-09:33:13
|
||||
|
||||
currentdir=` pwd `
|
||||
currentdir=$(pwd)
|
||||
sid=${currentdir##*.}
|
||||
ts=` date +%y%h%d-%T `
|
||||
ts=$(date +%y%h%d-%T)
|
||||
logfile=/tmp/corelog.tgz
|
||||
echo Collect data from localhost:$currentdir to $logfile
|
||||
cd ..
|
||||
|
@ -18,7 +18,7 @@ if [ ! $? = 0 ]; then
|
|||
fi
|
||||
cd $currentdir
|
||||
|
||||
m=` grep master $currentdir/servers `
|
||||
m=$(grep master $currentdir/servers)
|
||||
if [ ! $sid = ${m##*=} ]; then
|
||||
# quite if this is not a master server
|
||||
echo not a master server
|
||||
|
@ -34,13 +34,13 @@ fi
|
|||
cp $logfile $logdir/localhost-${currentdir##*.}.tgz
|
||||
|
||||
# harvest CORE data from distributed servers
|
||||
hs=` grep -v master= $currentdir/servers | awk {'print $2'} `
|
||||
hs=$(grep -v master= $currentdir/servers | awk {'print $2'})
|
||||
echo hosts are localhost $hs
|
||||
for h in $hs; do
|
||||
echo checking host $h ...
|
||||
out=` ping -c 1 -w 1 $h | grep " 0 received," `
|
||||
out=$(ping -c 1 -w 1 $h | grep " 0 received,")
|
||||
if [ " $out " = " " ]; then
|
||||
slavesid=` ssh $h tar -tzf $logfile | awk -F / {'print $1'} `
|
||||
slavesid=$(ssh $h tar -tzf $logfile | awk -F / {'print $1'})
|
||||
if [ $? = 0 ]; then
|
||||
destlogfile=$logdir/$h-${slavesid##*.}.tgz
|
||||
echo Collect data from $h:$logfile to $destlogfile
|
||||
|
|
0
scripts/perf/timesyncstart.sh
Normal file → Executable file
0
scripts/perf/timesyncstart.sh
Normal file → Executable file
4
scripts/perf/timesyncstop.sh
Normal file → Executable file
4
scripts/perf/timesyncstop.sh
Normal file → Executable file
|
@ -18,7 +18,7 @@ if [ -e /usr/sbin/ntpd ]; then
|
|||
# It is not quick enough for our need here
|
||||
/etc/init.d/ntp status
|
||||
if [ $? = 0 ]; then
|
||||
svs=`ntpq -c peers | awk {'print $1'} | grep ^*`
|
||||
svs=$(ntpq -c peers | awk {'print $1'} | grep ^*)
|
||||
if [ "$dbg" = "debug" ]; then
|
||||
ntpq -c peers
|
||||
echo "get time servers for later need: $svs"
|
||||
|
@ -31,7 +31,7 @@ if [ -e /usr/sbin/ntpd ]; then
|
|||
# if there are time servers configured in file /etc/ntp.conf,
|
||||
# adjust time to the first server
|
||||
if [ "$svs" = "" ]; then
|
||||
svs=`grep ^server /etc/ntp.conf | awk {'print $2'} `
|
||||
svs=$(grep ^server /etc/ntp.conf | awk {'print $2'})
|
||||
if [ "$dbg" = "debug" ]; then
|
||||
echo "$svs"
|
||||
fi
|
||||
|
|
Loading…
Reference in a new issue