Changes between Version 20 and Version 21 of TopdlLibrary


Ignore:
Timestamp:
Oct 8, 2012 3:19:37 PM (12 years ago)
Author:
faber
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • TopdlLibrary

    v20 v21  
    683683The result is something that looks like this:
    684684
     685[[Image(topo2.png)]]
     686
     687The code for this is below:
     688
     689{{{
     690def add_links(top):
     691    '''
     692    For each router - Computer with FreeBSD assigned as an OS - select one of
     693    its Linux children and make a connection to one of the other router's
     694    children.
     695    '''
     696
     697    def has_os(e, os_name):
     698        '''
     699        Return true if any of e's os classes has the given os_name
     700        '''
     701        if e.os is None: return False
     702        else: return any([ o.name == os_name for o in e.os ])
     703
     704    # At the end of this loop, leaves contains a list of leaves for each router
     705    # in the topology.
     706    leaves = [ ]
     707    for e in top.elements:
     708        if not isinstance(e, topdl.Computer): continue
     709        if not has_os(e, 'FreeBSD'): continue
     710        # This is a Computer running FreeBsd
     711        my_leaves = []
     712        # walk the interfaces
     713        for inf in e.interface:
     714            # Walk the interface's substrates
     715            for s in inf.subs:
     716                # Walk the substrate's interfaces looking for the other
     717                # elements - not this router.
     718                for sinf in s.interfaces:
     719                    ee = sinf.element
     720                    # all the Linux computers get attached to the leaves dict
     721                    if isinstance(ee, topdl.Computer) and ee != e:
     722                        if has_os(ee, 'Linux'):
     723                            my_leaves.append(ee)
     724        # One router has no leaves.  Ignore it.
     725        if len(my_leaves) > 0:
     726            leaves.append(my_leaves)
     727
     728
     729    # This loop takes the first computer in one entry in leaves and connects it
     730    # to the last computer in the next entry in leaves (wrapping around at the
     731    # top).
     732    for i in range(0, len(leaves)):
     733        link_name = 'new-link%d' % i
     734        f = leaves[i][0]
     735        t = leaves[(i+1) % len(leaves)][-1]
     736        f.interface.append(topdl.Interface(substrate=[link_name]))
     737        t.interface.append(topdl.Interface(substrate=[link_name]))
     738        top.substrates.append(topdl.Substrate(name=link_name))
     739
     740    # Now incorporate the new links
     741    top.incorporate_elements()
     742    return top
     743}}}
     744
     745This code demonstrates the basic loop that walks through a topology, looking at neighbors of elements.  To look at an element's neighbors, code must walk the element's interfaces to find the substrates it is connected to.  Then for each substrate, the other elements having an interface on the substrate are examined.
     746
     747The {{{has_os}}} nested function is typical of this sort of loop.  It encapsulates a bit of complexity - addressing the possibility that a Computer has more than one OS - in a side function.  In most cases that complexity is not used, but the snippet covers the possibility.
     748
     749It is also important to note the {{{Topology.incorporate_elements}}} call near the end.  That call completes the connections between interface objects and substrate objects (filling in the {{{Interface.subs}}} members and {{{Substrate.intrefaces}}} member) and between Interfaces and elements (by filling in the {{{Interface.element}}} member).  Without that call further use of the topology is difficult.  That call will also throw exceptions if the changes have introduced inconsistencies - multiple substrates with the same name, etc.
     750
     751== Output to NS2 ==
     752
     753Finally, we want to output out example topology in ns2 format so that we can directly swap it in to DETER.  Of course, fedd and the containers system will take (and prefer) topdl, but as an example, we show outputting ns2.
     754
     755This shows the use of a filter to tweak ns2 output for local requirements.  The {{{os_filter}}} function defined in {{{output_ns}}} below converts a single [TopdlLibrary#OperatingSystemClass OperatingSystem object] attached to a computer into a local DETER OSID.  Notice that the filter always returns a string - the empty one when no changes are made.  Do not return None from a filter.
     756
     757Here is the output code:
     758
     759{{{
     760def output_ns(top, filename):
     761    '''
     762    Output ns2 with the OperatingSystem specifications converted to local OSIDs
     763    when known.
     764    '''
     765    def os_filter(e):
     766        '''
     767        Convert OS id to local equivalents:
     768            FreeBSD -> FBSD8-STD
     769            Lunix/Ubuntu -> Ubuntu-64-STD
     770        '''
     771        # Only work on Computers
     772        if not isinstance(e, topdl.Computer): return ''
     773        # Only handle exactly 1 specified OS
     774        if len(e.os) != 1 : return ''
     775        # String translation
     776        if e.os[0].name == 'FreeBSD':
     777            return 'tb-set-node-os ${%s} FBSD8-STD\n' % \
     778                    topdl.to_tcl_name(e.name)
     779        elif e.os[0].name == 'Linux' and e.os[0].distribution == 'Ubuntu':
     780            return 'tb-set-node-os ${%s} Ubuntu1204-64-STD\n' % \
     781                    topdl.to_tcl_name(e.name)
     782        else:
     783            return ''
     784       
     785    # Main line.  Open the file and write the otcl to it.
     786    try:
     787        f = open(filename, 'w')
     788        # Include the os_filter
     789        f.write(topdl.topology_to_ns2(top,
     790            filters=[os_filter], routing='Static'))
     791        f.close()
     792    except EnvironmentError, e:
     793        sys.exit('Cannot write %s: %s' % (e.filename, e.strerror))
     794
     795}}}
     796
     797== Putting it all together ==