daemon: Initial support for writing different versions of XML scenario files.
This commit is contained in:
parent
899b5ae5be
commit
ca8856d6c8
3 changed files with 388 additions and 376 deletions
|
@ -14,7 +14,7 @@ the main public interface here.
|
||||||
import os.path
|
import os.path
|
||||||
from core.netns import nodes
|
from core.netns import nodes
|
||||||
from xmlparser import core_document_parser
|
from xmlparser import core_document_parser
|
||||||
from xmlwriter import CoreDocumentWriter
|
from xmlwriter import core_document_writer
|
||||||
|
|
||||||
def opensessionxml(session, filename, start=False, nodecls=nodes.CoreNode):
|
def opensessionxml(session, filename, start=False, nodecls=nodes.CoreNode):
|
||||||
''' Import a session from the EmulationScript XML format.
|
''' Import a session from the EmulationScript XML format.
|
||||||
|
@ -27,8 +27,8 @@ def opensessionxml(session, filename, start=False, nodecls=nodes.CoreNode):
|
||||||
session.node_count = str(session.getnodecount())
|
session.node_count = str(session.getnodecount())
|
||||||
session.instantiate()
|
session.instantiate()
|
||||||
|
|
||||||
def savesessionxml(session, filename):
|
def savesessionxml(session, filename, version = 0.0):
|
||||||
''' Export a session to the EmulationScript XML format.
|
''' Export a session to the EmulationScript XML format.
|
||||||
'''
|
'''
|
||||||
doc = CoreDocumentWriter(session)
|
doc = core_document_writer(session, version)
|
||||||
doc.writexml(filename)
|
doc.writexml(filename)
|
||||||
|
|
|
@ -1,377 +1,12 @@
|
||||||
#
|
|
||||||
# CORE
|
# CORE
|
||||||
# Copyright (c)2011-2013 the Boeing Company.
|
# Copyright (c) 2015 The Boeing Company.
|
||||||
# See the LICENSE file included in this distribution.
|
# See the LICENSE file included in this distribution.
|
||||||
#
|
|
||||||
# author: Jeff Ahrenholz <jeffrey.m.ahrenholz@boeing.com>
|
|
||||||
#
|
|
||||||
|
|
||||||
import os
|
from xmlwriter0 import CoreDocumentWriter0
|
||||||
import pwd
|
|
||||||
from core.netns import nodes
|
|
||||||
from core.api import coreapi
|
|
||||||
from xml.dom.minidom import Document
|
|
||||||
from xmlutils import *
|
|
||||||
|
|
||||||
class CoreDocumentWriter(Document):
|
def core_document_writer(session, version):
|
||||||
''' Utility class for writing a CoreSession to XML. The init method builds
|
if version == 0.0:
|
||||||
an xml.dom.minidom.Document, and the writexml() method saves the XML file.
|
doc = CoreDocumentWriter0(session)
|
||||||
'''
|
else:
|
||||||
def __init__(self, session):
|
raise ValueError, 'unsupported document version: %s' % version
|
||||||
''' Create an empty Scenario XML Document, then populate it with
|
return doc
|
||||||
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):
|
|
||||||
self.session.emane.setup() # not during runtime?
|
|
||||||
self.addorigin()
|
|
||||||
self.adddefaultservices()
|
|
||||||
self.addnets()
|
|
||||||
self.addnodes()
|
|
||||||
self.addmetadata()
|
|
||||||
|
|
||||||
def writexml(self, filename):
|
|
||||||
self.session.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._objslock:
|
|
||||||
for net in self.session.objs():
|
|
||||||
if not isinstance(net, nodes.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.getmodels(net)
|
|
||||||
modelconfigs += net.session.emane.getmodels(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._type == coreapi.CORE_TLV_REG_MOBILITY:
|
|
||||||
type = "mobility"
|
|
||||||
model.setAttribute("type", type)
|
|
||||||
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))
|
|
||||||
model.appendChild(key)
|
|
||||||
|
|
||||||
def addnodes(self):
|
|
||||||
''' Add PyCoreNode objects as node XML elements.
|
|
||||||
'''
|
|
||||||
with self.session._objslock:
|
|
||||||
for node in self.session.objs():
|
|
||||||
if not isinstance(node, nodes.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.nodeid())
|
|
||||||
if node.type:
|
|
||||||
n.setAttribute("type", node.type)
|
|
||||||
self.addinterfaces(n, node)
|
|
||||||
self.addposition(node)
|
|
||||||
addparamtoparent(self, n, "icon", node.icon)
|
|
||||||
addparamtoparent(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, netmodel._name,
|
|
||||||
None, ifc)
|
|
||||||
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.defaultservices:
|
|
||||||
defaults = self.session.services.getdefaultservices(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.getdefaultservices(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))
|
|
||||||
s.setAttribute("startup_idx", str(svc._startindex))
|
|
||||||
if svc._starttime != "":
|
|
||||||
s.setAttribute("start_time", str(svc._starttime))
|
|
||||||
# only record service names if not a customized service
|
|
||||||
if not svc._custom:
|
|
||||||
continue
|
|
||||||
s.setAttribute("custom", str(svc._custom))
|
|
||||||
addelementsfromlist(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 = self.session.services.getservicefiledata(svc, 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)
|
|
||||||
|
|
||||||
addtextelementsfromlist(self, s, svc._startup, "Command",
|
|
||||||
(("type","start"),))
|
|
||||||
addtextelementsfromlist(self, s, svc._shutdown, "Command",
|
|
||||||
(("type","stop"),))
|
|
||||||
addtextelementsfromlist(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.getdefaultvalues()
|
|
||||||
for i, (k, v) in enumerate(self.session.options.getkeyvaluelist()):
|
|
||||||
if str(v) != str(defaults[i]):
|
|
||||||
addtextparamtoparent(self, options, k, v)
|
|
||||||
#addparamtoparent(self, options, k, v)
|
|
||||||
if options.hasChildNodes():
|
|
||||||
self.meta.appendChild(options)
|
|
||||||
# hook scripts
|
|
||||||
self.addhooks()
|
|
||||||
# meta
|
|
||||||
meta = self.createElement("MetaData")
|
|
||||||
self.meta.appendChild(meta)
|
|
||||||
for (k, v) in self.session.metadata.items():
|
|
||||||
addtextparamtoparent(self, meta, k, v)
|
|
||||||
#addparamtoparent(self, meta, k, v)
|
|
||||||
|
|
377
daemon/core/misc/xmlwriter0.py
Normal file
377
daemon/core/misc/xmlwriter0.py
Normal file
|
@ -0,0 +1,377 @@
|
||||||
|
#
|
||||||
|
# CORE
|
||||||
|
# Copyright (c)2011-2013 the Boeing Company.
|
||||||
|
# See the LICENSE file included in this distribution.
|
||||||
|
#
|
||||||
|
# author: Jeff Ahrenholz <jeffrey.m.ahrenholz@boeing.com>
|
||||||
|
#
|
||||||
|
|
||||||
|
import os
|
||||||
|
import pwd
|
||||||
|
from core.netns import nodes
|
||||||
|
from core.api import coreapi
|
||||||
|
from xml.dom.minidom import Document
|
||||||
|
from xmlutils import *
|
||||||
|
|
||||||
|
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):
|
||||||
|
self.session.emane.setup() # not during runtime?
|
||||||
|
self.addorigin()
|
||||||
|
self.adddefaultservices()
|
||||||
|
self.addnets()
|
||||||
|
self.addnodes()
|
||||||
|
self.addmetadata()
|
||||||
|
|
||||||
|
def writexml(self, filename):
|
||||||
|
self.session.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._objslock:
|
||||||
|
for net in self.session.objs():
|
||||||
|
if not isinstance(net, nodes.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.getmodels(net)
|
||||||
|
modelconfigs += net.session.emane.getmodels(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._type == coreapi.CORE_TLV_REG_MOBILITY:
|
||||||
|
type = "mobility"
|
||||||
|
model.setAttribute("type", type)
|
||||||
|
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))
|
||||||
|
model.appendChild(key)
|
||||||
|
|
||||||
|
def addnodes(self):
|
||||||
|
''' Add PyCoreNode objects as node XML elements.
|
||||||
|
'''
|
||||||
|
with self.session._objslock:
|
||||||
|
for node in self.session.objs():
|
||||||
|
if not isinstance(node, nodes.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.nodeid())
|
||||||
|
if node.type:
|
||||||
|
n.setAttribute("type", node.type)
|
||||||
|
self.addinterfaces(n, node)
|
||||||
|
self.addposition(node)
|
||||||
|
addparamtoparent(self, n, "icon", node.icon)
|
||||||
|
addparamtoparent(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, netmodel._name,
|
||||||
|
None, ifc)
|
||||||
|
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.defaultservices:
|
||||||
|
defaults = self.session.services.getdefaultservices(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.getdefaultservices(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))
|
||||||
|
s.setAttribute("startup_idx", str(svc._startindex))
|
||||||
|
if svc._starttime != "":
|
||||||
|
s.setAttribute("start_time", str(svc._starttime))
|
||||||
|
# only record service names if not a customized service
|
||||||
|
if not svc._custom:
|
||||||
|
continue
|
||||||
|
s.setAttribute("custom", str(svc._custom))
|
||||||
|
addelementsfromlist(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 = self.session.services.getservicefiledata(svc, 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)
|
||||||
|
|
||||||
|
addtextelementsfromlist(self, s, svc._startup, "Command",
|
||||||
|
(("type","start"),))
|
||||||
|
addtextelementsfromlist(self, s, svc._shutdown, "Command",
|
||||||
|
(("type","stop"),))
|
||||||
|
addtextelementsfromlist(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.getdefaultvalues()
|
||||||
|
for i, (k, v) in enumerate(self.session.options.getkeyvaluelist()):
|
||||||
|
if str(v) != str(defaults[i]):
|
||||||
|
addtextparamtoparent(self, options, k, v)
|
||||||
|
#addparamtoparent(self, options, k, v)
|
||||||
|
if options.hasChildNodes():
|
||||||
|
self.meta.appendChild(options)
|
||||||
|
# hook scripts
|
||||||
|
self.addhooks()
|
||||||
|
# meta
|
||||||
|
meta = self.createElement("MetaData")
|
||||||
|
self.meta.appendChild(meta)
|
||||||
|
for (k, v) in self.session.metadata.items():
|
||||||
|
addtextparamtoparent(self, meta, k, v)
|
||||||
|
#addparamtoparent(self, meta, k, v)
|
Loading…
Add table
Add a link
Reference in a new issue