import repository from arizona
[raven.git] / apps / tempest / xmlgroupparse.py
1 #!/usr/bin/env python
2
3 #           [option,    long option,            variable,               action,         data,           default,                                metavar,        description]
4 """arizonaconfig
5     options=[["",       "--pacmanconfigfile",   "pacmanconfigFile",     "store",        "string",       "/usr/local/stork/etc/stork.conf",      "FILENAME",     "configuration file"],
6              ["",       "--dtd-groups",         "dtdGroups",            "store",        "string",       "/usr/local/stork/bin/groups.dtd",      "FILENAME",     "groups DTD file"]]
7     includes=[]
8 """
9
10 import sys, os, string, re, socket
11 import arizonaconfig
12 import arizonareport
13 from arizonaxml import *
14 import storkusername
15 import arizonacrypt
16 import arizonageneral
17 import time
18
19 glo_node_names = []
20 verbose = False
21
22 class GroupApp(XMLApplication):
23     """This class parses the groups.xml file."""
24     def __init__(self):
25         XMLApplication.__init__(self)
26         CreateAttr(self, 'groups', {})          # Dictionary of group members
27         CreateAttr(self, 'group', None)         # Current GROUP
28         CreateAttr(self, 'loc', None)           # Parser locator
29         CreateAttr(self, 'target', None)        # Target of current action (e.g INCLUDE)
30
31     def set_locator(self, locator):
32         self.loc = locator
33     def doc_start(self):
34         self.group = None
35     def handle_start_tag(self, tag, attrs):
36         if tag == "GROUP":
37             self.group = attrs.get("NAME");
38             if self.group in self.groups:
39                 raise XMLError, "duplicate group:", self.group
40             self.groups[self.group] = []
41         elif tag == "GROUPS" or tag == "INCLUDE" or tag == "EXCLUDE" or tag == "INTERSECT":
42             self.target = attrs.get("NAME");
43             pass
44         else:
45             # Shouldn't happen if DTD is correct
46             raise XMLError , "invalid element: " + tag
47
48     def handle_end_tag(self,tag):
49         global glo_node_names
50         if tag == "GROUP":
51             self.group = None
52             return
53         elif tag == "GROUPS":
54             return
55         if self.target in self.groups:
56             members = self.groups[self.target]
57         else:
58             if str(self.target).lower() == "self":
59                 members = glo_node_names
60             else:
61                 members = [self.target]
62         self.target = None
63         if tag == "INCLUDE":
64             self.groups[self.group].extend(members)
65         elif tag == "EXCLUDE":
66             for m in members:
67                 if m in self.groups[self.group]:
68                     self.groups[self.group].remove(m)
69         elif tag == "INTERSECT":
70             tmp = []
71             for i in self.groups[self.group]:
72                 if i in members:
73                     tmp.append(i)
74             self.groups[self.group] = tmp
75         else:
76             # Shouldn't happen if DTD is correct
77             raise XMLError , "invalid closing element: " + tag
78
79 def strip_leading_comments(lines):
80     """ removes all lines that start with '#', until some line that doesn't
81         start with '#' is encountered.
82     """
83     result = []
84     nonComment = False
85     for line in lines:
86         if (not nonComment) and line.startswith("#"):
87             pass
88         else:
89             nonComment = True
90             result.append(line)
91
92     return result
93
94
95 def GroupFileParse(dtd, group_file_name):
96     """Creates the parser for the groups.xml file and parses it.
97  Returns a dictionary of group members."""
98     lines = file(group_file_name).readlines()
99     lines = strip_leading_comments(lines)
100
101     app = GroupApp()
102     try:
103         app.parse(contents = "\n".join(lines))
104     except XMLError, e:
105         print e
106         sys.exit(1)
107
108     # remove the temeporary file we created when we extracted the signed version
109     try:
110         os.remove(temp_contents)
111     except:
112         pass
113
114     return app.groups
115
116 def NodeGroups(groups):
117     """ Creates a dictionary in which each entry is keyed by a node
118  name and contains a list of all groups of which the node is a
119  member."""
120     nodes = {}
121
122     for g in groups.keys():
123         for n in groups[g]:
124             if nodes.has_key(n) == False:
125                 nodes[n] = [g]
126             elif g not in nodes[n]:
127                 nodes[n].append(g)
128     return nodes
129
130 def MyGroups(groups, node_names):
131     """Inverts the groups to create a dictionary of nodes and the groups they are in."""
132     global verbose
133     #
134     # Invert the groups to create a dictionary of nodes and the groups they are in.
135     # This is overkill (we only care about our node) but perhaps it will be useful
136     # someday to have the complete mapping. It's also useful for debugging.
137
138     node_groups = NodeGroups(groups)
139
140     if verbose:
141         print "\nNodes:"
142         for n in node_groups.keys():
143             print "%s: %s" % (n,','.join(node_groups[n]))
144
145     #
146     # Make a list of groups this node is in (if a node name has been specified).
147     #
148     myGroups = []
149     for node in node_names:
150         if node in node_groups:
151             for group in node_groups[node]:
152                 if not group in myGroups:
153                     myGroups.append(group)
154
155     return myGroups
156
157 def commentOutputFunc(callType, callVerb, outputstring):
158    if callType == "send_out":
159       return "#" + outputstring
160    else:
161       return outputstring
162
163 def main():
164     global glo_node_names
165
166     # causes everything sent to arizonareport to get a "#" in front of it
167     arizonareport.set_output_function(commentOutputFunc)
168
169     args = arizonaconfig.init_options('xmlgroupparse.py', configfile_optvar='pacmanconfigFile', version='2.0')
170
171     dtdGroups = arizonaconfig.get_option("dtdGroups")
172
173     if len(args) < 2:
174         arizonareport.send_error(0, "Syntax: xmlgroupparse.py groupsfilename hostname")
175         exit(-1)
176
177     groupFileName = args[0]
178     node_names = args[1].split(",")
179
180     glo_node_names = node_names
181
182     groups = GroupFileParse(dtdGroups, groupFileName)
183     myGroups = MyGroups(groups, node_names)
184
185     arizonareport.unset_output_function(commentOutputFunc)
186
187     for group in myGroups:
188         arizonareport.send_out(0, group)
189
190 if __name__ == "__main__":
191     main()