Changeset 0d830de for fedd


Ignore:
Timestamp:
Aug 27, 2008 7:24:55 PM (16 years ago)
Author:
Ted Faber <faber@…>
Branches:
axis_example, compt_changes, info-ops, master, version-1.30, version-2.00, version-3.01, version-3.02
Children:
b234bb9
Parents:
3441fe3
Message:

topology and visualization into real data structures

File:
1 edited

Legend:

Unmodified
Added
Removed
  • fedd/fedd_create_experiment.py

    r3441fe3 r0d830de  
    267267        pid = tbparams[tb]['project']
    268268        # XXX
    269         base_confs = ( "hosts", "vtopo.xml", "viz.xml")
     269        base_confs = ( "hosts",)
    270270        tclfile = "%s.%s.tcl" % (eid, tb)
    271271        expinfo_exec = "/usr/testbed/bin/expinfo"
     
    299299                if m: state = "none"
    300300        rv = status.wait()
    301         # No experiment returns a non-zero rv.  If we successfully parsed a
    302         # "none" outcome, ignore teh return code.
     301        # If the experiment is not present the subcommand returns a non-zero
     302        # return value.  If we successfully parsed a "none" outcome, ignore the
     303        # return code.
    303304        if rv != 0 and state != "none":
    304305            raise service_error(service_error.internal,
     
    456457                            % (self.ssh_keygen, rv))
    457458
    458     def genviz(self, topo_file, viz_file):
     459    def gentopo(self, str):
     460        class topo_parse:
     461            def __init__(self):
     462                self.str_subelements = ('vname', 'vnode', 'ips', 'ip', 'member')
     463                self.int_subelements = ( 'bandwidth',)
     464                self.float_subelements = ( 'delay',)
     465                self.nodes = [ ]
     466                self.lans =  [ ]
     467                self.element = { }
     468                self.topo = { \
     469                        'nodes': { 'node': self.nodes  },\
     470                        'lans' : { 'lan' : self.lans },\
     471                    }
     472                self.chars = ""
     473
     474            def end_element(self, name):
     475                if name == 'node':
     476                    self.nodes.append(self.element)
     477                    self.element = { }
     478                elif name == 'lan':
     479                    self.lans.append(self.element)
     480                    self.element = { }
     481                elif name in self.str_subelements:
     482                    self.element[name] = self.chars
     483                    self.chars = ""
     484                elif name in self.int_subelements:
     485                    self.element[name] = int(self.chars)
     486                    self.chars = ""
     487                elif name in self.float_subelements:
     488                    self.element[name] = float(self.chars)
     489                    self.chars = ""
     490
     491            def found_chars(self, data):
     492                self.chars += data.rstrip()
     493
     494
     495        tp = topo_parse();
     496        parser = xml.parsers.expat.ParserCreate()
     497        parser.EndElementHandler = tp.end_element
     498        parser.CharacterDataHandler = tp.found_chars
     499
     500        parser.Parse(str)
     501
     502        return tp.topo
     503       
     504
     505    def genviz(self, topo):
    459506        """
    460         Generate the visualization file from the topology file
     507        Generate the visualization the virtual topology
    461508        """
    462 
    463         class topo_parse:
    464             """
    465             Parse the vtopo file into a set of lans, links and nodes.
    466             """
    467             def __init__(self):
    468                 self.links = {}         # Each link is a list of at most 2 nodes
    469                 self.lans = {}          # Lans have more than 2 nodes
    470                 self.nodes = {}         # The nodes in the experiment
    471                 self.lan = {}           # The current link/len being collected
    472                 self.in_lan = False     # Is the conatining element lan?
    473                 self.in_node = False    # Is the conatining element node?
    474                 self.chars = None       # Last set of marked-up chars
    475 
    476             def start_element(self, name, attrs):
    477                 """
    478                 New element started.  Set flags and clear lan
    479                 """
    480                 if name == "node":
    481                     self.in_node = True
    482                 elif name == "lan":
    483                     self.in_lan = True
    484                     self.lan.clear()
    485            
    486             def end_element(self, name):
    487                 """
    488                 End of element.  Collect data if appropriate
    489 
    490                 If a node or lan is ending, create an entry in nodes or
    491                 lans/links.  If a vname/vnode in a node or lan is ending,
    492                 capture its name.  If a lan is ending, add the node to the
    493                 evolving link or lan.
    494                 """
    495                 if name == "node":
    496                     self.in_node = False
    497                 if self.in_node and name == "vname":
    498                     self.nodes[self.chars] = "node"
    499                 if self.in_lan:
    500                     if name != "lan":
    501                         if name == 'vname' or name == 'vnode':
    502                             self.lan[name] = self.chars
    503                     else:
    504                         self.in_lan = False
    505                         vname = self.lan['vname']
    506                         links = self.links.get(vname, [])
    507                         if len(links) == 2:
    508                             # This link needs to be a lan instead
    509                             self.nodes[vname] = "lan"
    510                             self.lans[vname] = \
    511                                     [ l for l in links, self.lan['vnode'] ]
    512                             del self.links[vname]
    513                             self.lan = {}
    514                             return
    515                         lans = self.lans.get(vname, [])
    516                         if len(lans) > 0:
    517                             lans.append(self.lan['vnode'])
    518                             self.lan = {}
    519                             return
    520                         if not vname in self.links:
    521                             self.links[vname] = []
    522                         self.links[vname].append(self.lan['vnode'])
    523                         self.lan = {}
    524                         return
    525 
    526             def found_chars(self, data):
    527                 """
    528                 Capture marked up chars for later
    529                 """
    530                 self.chars = data
    531509
    532510        neato = "/usr/local/bin/neato"
     
    535513        vis_re = re.compile('^\s*"?([\w\-]+)"?\s+\[.*pos="(\d+),(\d+)"')
    536514        vis_fmt = "<node><name>%s</name><x>%s</x><y>%s</y><type>" + \
    537                 "%s</type></node>"
     515                "%s</type></node>"
     516
     517        try:
     518            # Node names
     519            nodes = [ n['vname'] for n in topo['nodes']['node'] ]
     520            topo_lans = topo['lans']['lan']
     521        except KeyError:
     522            raise service_error(service_error.internal, "Bad topology")
     523
     524        lans = { }
     525        links = { }
     526
     527        # Walk through the virtual topology, organizing the connections into
     528        # 2-node connections (links) and more-than-2-node connections (lans).
     529        # When a lan is created, it's added to the list of nodes (there's a
     530        # node in the visualization for the lan).
     531        for l in topo_lans:
     532            if links.has_key(l['vname']):
     533                if len(links[l['vname']]) < 2:
     534                    links[l['vname']].append(l['vnode'])
     535                else:
     536                    nodes.append(l['vname'])
     537                    lans[l['vname']] = links[l['vname']]
     538                    del links[l['vname']]
     539                    lans[l['vname']].append(l['vnode'])
     540            elif lans.has_key(l['vname']):
     541                lans[l['vname']].append(l['vnode'])
     542            else:
     543                links[l['vname']] = [ l['vnode'] ]
     544
     545
     546        # Open up a temporary file for dot to turn into a visualization
    538547        try:
    539548            df, dotname = tempfile.mkstemp()
    540549            dotfile = os.fdopen(df, 'w')
    541             infile = open(topo_file, 'r')
    542             out = open(viz_file, "w")
    543550        except IOError:
    544551            raise service_error(service_error.internal,
    545552                    "Failed to open file in genviz")
    546553
    547         # Parse the topology file using XML tools
    548         tp = topo_parse();
    549         parser = xml.parsers.expat.ParserCreate()
    550         parser.StartElementHandler = tp.start_element
    551         parser.EndElementHandler = tp.end_element
    552         parser.CharacterDataHandler = tp.found_chars
    553 
    554         parser.ParseFile(infile)
    555 
    556554        # Generate a dot/neato input file from the links, nodes and lans
    557555        try:
    558556            print >>dotfile, "graph G {"
    559             for n in tp.nodes.keys():
     557            for n in nodes:
    560558                print >>dotfile, '\t"%s"' % n
    561             for l in tp.links.keys():
    562                 print >>dotfile, " -- ".join(tp.links[l])
    563             for l in tp.lans.keys():
    564                 for n in tp.lans[l]:
     559            for l in links.keys():
     560                print >>dotfile, '\t"%s" -- "%s"' %  tuple(links[l])
     561            for l in lans.keys():
     562                for n in lans[l]:
    565563                    print >>dotfile, '\t "%s" -- "%s"' % (n,l)
    566564            print >>dotfile, "}"
    567565            dotfile.close()
     566        except TypeError:
     567            raise service_error(service_error.internal,
     568                    "Single endpoint link in vtopo")
    568569        except IOError:
    569570            raise service_error(service_error.internal, "Cannot write dot file")
     
    573574                '-Gpack=true', dotname], stdout=PIPE)
    574575
    575         # Translate dot to emulab format
    576         try:
    577             print >>out, "<vis>"
    578             for line in dot.stdout:
    579                 m = vis_re.match(line)
    580                 if m:
    581                     n, x, y = (m.group(1), m.group(2), m.group(3))
    582                     if tp.nodes.has_key(n):
    583                         print >>out, vis_fmt % (n, x, y, tp.nodes[n])
    584             print >>out, "</vis>"
    585             out.close()
    586         except IOError:
    587             raise service_error(service_error.internal,
    588                     "Failed to write visualization file")
     576        # Translate dot to vis format
     577        vis_nodes = [ ]
     578        vis = { 'node': vis_nodes }
     579        for line in dot.stdout:
     580            m = vis_re.match(line)
     581            if m:
     582                vn = m.group(1)
     583                vis_node = {'name': vn, \
     584                        'x': int(m.group(2)),\
     585                        'y' : int(m.group(3)),\
     586                    }
     587                if vn in links.keys() or vn in lans.keys():
     588                    vis_node['type'] = 'lan'
     589                else:
     590                    vis_node['type'] = 'node'
     591                vis_nodes.append(vis_node)
    589592        rv = dot.wait()
     593
    590594        os.remove(dotname)
    591         return rv == 0
     595        if rv == 0 : return vis
     596        else: return None
    592597
    593598
     
    10351040                return True
    10361041
     1042    class shunt_to_string:
     1043        def __init__(self, begin, end):
     1044            self.begin = re.compile(begin)
     1045            self.end = re.compile(end)
     1046            self.in_shunt = False
     1047            self.str = ""
     1048       
     1049        def __call__(self, line):
     1050            if not self.in_shunt:
     1051                if self.begin.match(line):
     1052                    self.in_shunt = True
     1053                    return True
     1054                else:
     1055                    return False
     1056            else:
     1057                if self.end.match(line):
     1058                    self.in_shunt = False
     1059                else:
     1060                    self.str += line
     1061                return True
     1062
    10371063    def create_experiment(self, req, fid):
    10381064        try:
     
    11021128        parse_gateways = self.gateways(eid, master, tmpdir,
    11031129                gw_pubkey_base, gw_secretkey_base, self.copy_file)
    1104         parse_vtopo = self.shunt_to_file("^#\s+Begin\s+Vtopo",
    1105                     "^#\s+End\s+Vtopo", tmpdir + "/vtopo.xml")
     1130        parse_vtopo = self.shunt_to_string("^#\s+Begin\s+Vtopo",
     1131                    "^#\s+End\s+Vtopo")
    11061132        parse_hostnames = self.shunt_to_file("^#\s+Begin\s+hostnames",
    11071133                    "^#\s+End\s+hostnames", tmpdir + "/hosts")
     
    11311157                        "Bad tcl parse? %s" % line)
    11321158
    1133         self.genviz(tmpdir + "/vtopo.xml", tmpdir + "/viz.xml")
     1159        vtopo = self.gentopo(parse_vtopo.str)
     1160        if not vtopo:
     1161            raise service_error(service_error.internal,
     1162                    "Failed to generate virtual topology")
     1163
     1164        vis = self.genviz(vtopo)
     1165        if not vis:
     1166            raise service_error(service_error.internal,
     1167                    "Failed to generate visualization")
    11341168
    11351169        # Copy tarfiles and rpms needed at remote sites into a staging area
     
    12001234        return { 'emulab' : [ tbparams[tb]['emulab'] \
    12011235                for tb in tbparams.keys() \
    1202                     if tbparams[tb].has_key('emulab') ] }
     1236                    if tbparams[tb].has_key('emulab') ],\
     1237                    'experiment': vtopo,\
     1238                    'vis' : vis }
    12031239
    12041240if __name__ == '__main__':
Note: See TracChangeset for help on using the changeset viewer.