summaryrefslogtreecommitdiffstats
path: root/src/lib/Bcfg2/Server/Admin/Viz.py
blob: 2faa423c1ab8c6f13a803fb9a1b658d707f8651f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
import getopt
from subprocess import Popen, PIPE
import sys
import pipes
import Bcfg2.Server.Admin


class Viz(Bcfg2.Server.Admin.MetadataCore):
    __shorthelp__ = "Produce graphviz diagrams of metadata structures"
    __longhelp__ = (__shorthelp__ + "\n\nbcfg2-admin viz [--includehosts] "
                                    "[--includebundles] [--includekey] "
                                    "[--only-client clientname] "
                                    "[-o output.<ext>]\n")
    __usage__ = ("bcfg2-admin viz [options]\n\n"
                 "     %-32s%s\n"
                 "     %-32s%s\n"
                 "     %-32s%s\n"
                 "     %-32s%s\n"
                 "     %-32s%s\n" %
                ("-H, --includehosts",
                 "include hosts in the viz output",
                 "-b, --includebundles",
                 "include bundles in the viz output",
                 "-k, --includekey",
                 "show a key for different digraph shapes",
                 "-c, --only-client <clientname>",
                 "show only the groups, bundles for the named client",
                 "-o, --outfile <file>",
                 "write viz output to an output file"))

    colors = ['steelblue1', 'chartreuse', 'gold', 'magenta',
              'indianred1', 'limegreen', 'orange1', 'lightblue2',
              'green1', 'blue1', 'yellow1', 'darkturquoise', 'gray66']

    __plugin_blacklist__ = ['DBStats', 'Snapshots', 'Cfg', 'Pkgmgr', 'Packages',
                            'Rules', 'Account', 'Decisions', 'Deps', 'Git',
                            'Svn', 'Fossil', 'Bzr', 'Bundler', 'TGenshi',
                            'SGenshi', 'Base']

    def __call__(self, args):
        Bcfg2.Server.Admin.MetadataCore.__call__(self, args)
        # First get options to the 'viz' subcommand
        try:
            opts, args = getopt.getopt(args, 'Hbkc:o:',
                                       ['includehosts', 'includebundles',
                                        'includekey', 'only-client=', 'outfile='])
        except getopt.GetoptError:
            msg = sys.exc_info()[1]
            print(msg)
            print(self.__longhelp__)
            raise SystemExit(1)

        hset = False
        bset = False
        kset = False
        only_client = None
        outputfile = False
        for opt, arg in opts:
            if opt in ("-H", "--includehosts"):
                hset = True
            elif opt in ("-b", "--includebundles"):
                bset = True
            elif opt in ("-k", "--includekey"):
                kset = True
            elif opt in ("-c", "--only-client"):
                only_client = arg
            elif opt in ("-o", "--outfile"):
                outputfile = arg

        data = self.Visualize(self.setup['repo'], hset, bset,
                              kset, only_client, outputfile)
        if data:
            print(data)
        raise SystemExit(0)

    def Visualize(self, repopath, hosts=False,
                  bundles=False, key=False, only_client=None, output=False):
        """Build visualization of groups file."""
        if output:
            format = output.split('.')[-1]
        else:
            format = 'png'

        cmd = ["dot", "-T", format]
        if output:
            cmd.extend(["-o", output])
        try:
            dotpipe = Popen(cmd, stdin=PIPE, stdout=PIPE, close_fds=True)
        except OSError:
            # on some systems (RHEL 6), you cannot run dot with
            # shell=True.  on others (Gentoo with Python 2.7), you
            # must.  In yet others (RHEL 5), either way works.  I have
            # no idea what the difference is, but it's kind of a PITA.
            cmd = ["dot", "-T", pipes.quote(format)]
            if output:
                cmd.extend(["-o", pipes.quote(output)])
            dotpipe = Popen(cmd, shell=True,
                            stdin=PIPE, stdout=PIPE, close_fds=True)
        try:
            dotpipe.stdin.write("digraph groups {\n")
        except:
            print("write to dot process failed. Is graphviz installed?")
            raise SystemExit(1)
        dotpipe.stdin.write('\trankdir="LR";\n')
        dotpipe.stdin.write(self.metadata.viz(hosts, bundles,
                                              key, only_client, self.colors))
        if key:
            dotpipe.stdin.write("\tsubgraph cluster_key {\n")
            dotpipe.stdin.write('''\tstyle="filled";\n''')
            dotpipe.stdin.write('''\tcolor="lightblue";\n''')
            dotpipe.stdin.write('''\tBundle [ shape="septagon" ];\n''')
            dotpipe.stdin.write('''\tGroup [shape="ellipse"];\n''')
            dotpipe.stdin.write('''\tProfile [style="bold", shape="ellipse"];\n''')
            dotpipe.stdin.write('''\tHblock [label="Host1|Host2|Host3", shape="record"];\n''')
            dotpipe.stdin.write('''\tlabel="Key";\n''')
            dotpipe.stdin.write("\t}\n")
        dotpipe.stdin.write("}\n")
        dotpipe.stdin.close()
        return dotpipe.stdout.read()