Changeset 1f356d3 for fedd/fedd_image.py


Ignore:
Timestamp:
Dec 1, 2010 3:37:18 PM (13 years ago)
Author:
Ted Faber <faber@…>
Branches:
axis_example, compt_changes, info-ops, master
Children:
5c3d542
Parents:
c324ad3
Message:

Generate images with nodes paritioned by attribute

File:
1 edited

Legend:

Unmodified
Added
Removed
  • fedd/fedd_image.py

    rc324ad3 r1f356d3  
    3939        self.add_option("--file", dest="file",
    4040                help="experiment description file")
    41 
    42 def gen_dot_topo(t, labels, dotfile):
     41        self.add_option("--group", dest="group", default=None,
     42                help="Group nodes by this attribute")
     43
     44def make_subgraph(topelems, attr):
     45    """
     46    Take a list of topdl elements (Computers and Substrates ) and partition
     47    them into groups based on the value of the given attribute.  All computers
     48    with the same value for the attribute are in a subgraph. A substrate is in
     49    the subgraph if all its interfaces are, and in the "default" subgraph if
     50    not.
     51    """
     52
     53    def add_to_map(m, a, v):
     54        """
     55        Add this value to the list in m[a] if that list exists, or create it.
     56        """
     57        if a in m: m[a].append(v)
     58        else: m[a] = [ v]
     59
     60    sg = { }
     61    for e in topelems:
     62        if isinstance(e, topdl.Computer):
     63            add_to_map(sg, e.get_attribute(attr) or 'default', e)
     64        elif isinstance(e, topdl.Substrate):
     65            # A little hairy.  Make a set of the values of the given attribute
     66            # for all the elements in the substrate's interfaces.  If that set
     67            # has one element, put the substrate in that subgraph.  Otherwise
     68            # put it in default.
     69            atts = set([i.element.get_attribute(attr) or 'default' \
     70                    for i in e.interfaces])
     71
     72            if len(atts) == 1: add_to_map(sg, atts.pop(), e)
     73            else: add_to_map(sg, 'default', e)
     74
     75    return sg
     76
     77def gen_dot_topo(t, labels, dotfile, sg_attr=None):
    4378    """
    4479    Write a dot description of the topology in t, a topdl.Topology to the open
     
    4883    """
    4984
     85
    5086    # The routine draws a circle for substrates with more than 2 interfaces
    5187    # connected to it, so this makes lists of each of those.
     
    5389    links = [ s for s in t.substrates if len(s.interfaces) == 2]
    5490
    55     # Output the nodes.  Deal with the possibility that there's no name, but
    56     # that's unlikely.
    57     for i, n in enumerate(t.elements):
    58         if n.name:
    59             print >>dotfile, '\t"%s" [shape=box,style=filled,\\' % n.name
    60         else:
    61             print >>dotfile, \
    62                     '\t"unnamed_node%d" [shape=box,style=filled,\\' % i
    63         print >>dotfile, '\t\tcolor=black,fillcolor="#60f8c0",regular=1]'
    64 
    65     # Encode the lans and the links
     91    # Break into subgraphs by the attribute of one's given
     92    if sg_attr: sg = make_subgraph(t.elements + lans, sg_attr)
     93    else: sg = { 'default': t.elements + lans }
     94
     95
     96    # Construct subgraphs featurning nodes from those graphs
     97    for sn, nodes in sg.items():
     98        # Output the computers and lans in subgraphs, if necessary.  Subgraphs
     99        # treated as clusters are designated by "cluster" starting the name.
     100        # (The default subgraph is not treated as a cluster.
     101        if sn != 'default':
     102            print >>dotfile, 'subgraph "cluster-%s" {' % sn
     103            print >>dotfile, 'label="%s"' % sn
     104        else:
     105            print >>dotfile, 'subgraph "%s" {' % sn
     106        print >>dotfile, 'color="#08c0f8"'
     107        print >>dotfile, 'clusterrank="local"'
     108
     109        # For each node in the subgraph, output its representation
     110        for i, n in enumerate(nodes):
     111            if isinstance(n, topdl.Computer):
     112                if n.name:
     113                    print >>dotfile, '\t"%s" [shape=box,style=filled,\\' % \
     114                            n.name
     115                else:
     116                    print >>dotfile, \
     117                            '\t"unnamed_node%d" [shape=box,style=filled,\\' % i
     118                print >>dotfile, \
     119                        '\t\tcolor=black,fillcolor="#60f8c0",regular=1]'
     120            elif isinstance(n, topdl.Substrate):
     121                print >>dotfile, '\t"%s" [shape=ellipse, style=filled,\\' % \
     122                        n.name
     123                print >>dotfile,'\t\tcolor=black,fillcolor="#80c0f8",regular=1]'
     124        print >>dotfile, '}'
     125
     126    # Pull the edges out ot the lans and links
    66127    for l in lans:
    67         print >>dotfile, '\t"%s" [shape=ellipse, style=filled,\\' % l.name
    68         print >>dotfile,'\t\tcolor=black,fillcolor="#80c0f8",regular=1]'
    69128        for i in l.interfaces:
    70129            ip = i.get_attribute('ip4_address')
     
    90149                    (s.element.name, d.element.name)
    91150
    92 def gen_image(top, file, fmt, neato, labels, pix=None):
     151def gen_image(top, file, fmt, neato, labels, pix=None, sg_attr=None):
    93152    """
    94153    Create a dot formatted input file from the topdl.Topology in top and run
     
    109168    # Look for neato if the executable is unspecified.
    110169    if not neato:
    111         for f in ['/usr/bin/neato', '/usr/local/bin/neato',
    112                 '/usr/bin/dot', '/usr/local/bin/dot']:
     170        # If a subgraph attribute has been specified, prefer dot to neato.  dot
     171        # is more "natural" looking graphs, but neato segregates better.
     172        if sg_attr:
     173            search_list = ['/usr/bin/dot', '/usr/local/bin/dot',
     174                    '/usr/bin/neato', '/usr/local/bin/neato']
     175        else:
     176            search_list = ['/usr/bin/neato', '/usr/local/bin/neato',
     177                '/usr/bin/dot', '/usr/local/bin/dot']
     178
     179        for f in search_list:
    113180            if os.access(f, os.X_OK):
    114181                neato = f
     
    141208                % (size, size, dpi)
    142209    else:
    143         print >>dotfile, '\tgraph [size="%i,%i", ratio=fill];' \
     210        print >>dotfile, '\tgraph [size="%i,%i", ratio=fill, clusterrank="local"compound="true"];' \
    144211                % (size, size)
    145212
     
    150217        print >>dotfile, '\tnode [label=""];'
    151218
    152     gen_dot_topo(top, labels, dotfile)
     219    gen_dot_topo(top, labels, dotfile, sg_attr=sg_attr)
    153220    print >>dotfile, "}"
    154221    dotfile.close()
     
    311378if not opts.serialize_only:
    312379    try:
    313         if gen_image(top, file, fmt, opts.neato, opts.labels, opts.pixels) !=0:
     380        if gen_image(top, file, fmt, opts.neato, opts.labels, opts.pixels,
     381                opts.group) !=0:
    314382            sys.exit("Error rendering graph (subcommand returned non-0)")
    315383    except EnvironmentError, e:
Note: See TracChangeset for help on using the changeset viewer.