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 Usage: nodeset [COMMAND] [OPTIONS] [ns1 [-ixX] ns2|...]
38
39 Commands:
40 --count, -c <nodeset> [nodeset ...]
41 Return the number of nodes in nodesets.
42 --expand, -e <nodeset> [nodeset ...]
43 Expand nodesets to separate nodes.
44 --fold, -f <nodeset> [nodeset ...]
45 Compact/fold nodesets (or separate nodes) into one nodeset.
46 --list, -l
47 List node groups (see --groupsource).
48 --regroup, -r <nodeset> [nodeset ...]
49 Fold nodes using node groups (see --groupsource).
50 --groupsources
51 List all configured group sources (see groups.conf(5)).
52 Options:
53 --all, -a
54 Call external node groups support to display all nodes.
55 --autostep=<number>
56 Specify auto step threshold number when folding nodesets.
57 If not specified, auto step is disabled.
58 Example: autostep=4, "node2 node4 node6" folds in node[2,4,6]
59 autostep=3, "node2 node4 node6" folds in node[2-6/2]
60 --help, -h
61 This help page.
62 --quiet, -q
63 Quiet mode, hide any parse error messages (on stderr).
64 --rangeset, -R
65 Switch to RangeSet instead of NodeSet. Useful when working on
66 numerical cluster ranges, eg. 1,5,18-31.
67 --groupsource, -s <GroupSource>
68 Specify group source (ie. section to use in groups.conf(5)).
69 --groupbase, -G
70 Do not display group source prefix (always "@groupname").
71 --separator=<string>, -S <string>
72 Specify separator string for expanding nodesets (default: ' ').
73 --version, -v
74 Show ClusterShell version and exit.
75 Operations (default is union):
76 The default operation is the union of node or nodeset.
77 --exclude=<nodeset>, -x <nodeset>
78 Exclude provided node or nodeset.
79 --intersection, -i
80 Calculate nodesets intersection.
81 --xor, -X
82 Calculate symmetric difference (XOR) between two nodesets.
83 """
84
85 import getopt
86 import os
87 import signal
88 import sys
89
90 from ClusterShell.NodeUtils import GroupResolverConfigError
91 from ClusterShell.NodeUtils import GroupResolverSourceError
92 from ClusterShell.NodeUtils import GroupSourceException
93 from ClusterShell.NodeUtils import GroupSourceNoUpcall
94 try:
95 from ClusterShell.NodeSet import NodeSet
96 from ClusterShell.NodeSet import NodeSetExternalError, NodeSetParseError
97 from ClusterShell.NodeSet import RangeSet, RangeSetParseError
98 from ClusterShell.NodeSet import grouplist, STD_GROUP_RESOLVER
99 from ClusterShell import __version__
100 except GroupResolverConfigError, e:
101 print >> sys.stderr, \
102 "ERROR: ClusterShell Groups configuration error:\n\t%s" % e
103 sys.exit(1)
104
105
107 """Process standard input and populate xset."""
108 for line in sys.stdin.readlines():
109
110 line = line[0:line.find('#')].strip()
111 for node in line.split():
112 xset.update(xset.__class__(node, autostep=autostep))
113
115 """Apply operations and operands from args on xset, an initial
116 RangeSet or NodeSet."""
117 class_set = xset.__class__
118
119 while args:
120 arg = args.pop(0)
121 if arg in ("-i", "--intersection"):
122 xset.intersection_update(class_set(args.pop(0),
123 autostep=autostep))
124 elif arg in ("-x", "--exclude"):
125 xset.difference_update(class_set(args.pop(0),
126 autostep=autostep))
127 elif arg in ("-X", "--xor"):
128 xset.symmetric_difference_update(class_set(args.pop(0),
129 autostep=autostep))
130 elif arg == '-':
131 process_stdin(xset, autostep)
132 else:
133 xset.update(class_set(arg, autostep=autostep))
134
135 return xset
136
138 print >> sys.stderr, message
139 print >> sys.stderr, "Try `%s -h' for more information." % progname
140 sys.exit(status)
141
143 """
144 Main script function.
145 """
146 autostep = None
147 all = False
148 command = None
149 verbosity = 1
150 class_set = NodeSet
151 separator = ' '
152 source = None
153 groupbase = False
154 progname = args[0]
155 multcmds_errstr = "ERROR: multiple commands not allowed"
156
157
158 try:
159 opts, args = getopt.getopt(args[1:], "acdefhlqs:vrGRS:",
160 ["autostep=", "count", "debug", "expand", "fold", "groupbase",
161 "groupsource=", "groupsources", "help", "list", "quiet",
162 "regroup", "rangeset", "separator=", "version"])
163 except getopt.error, err:
164 if err.opt in [ "i", "intersection", "x", "exclude", "X", "xor" ]:
165 message = "option -%s not allowed here" % err.opt
166 else:
167 message = err.msg
168 error_exit(progname, message, 2)
169
170 for k, val in opts:
171 if k in ("-a", "--all"):
172 all = True
173 elif k in ("--autostep"):
174 try:
175 autostep = int(val)
176 except ValueError, exc:
177 print >> sys.stderr, exc
178 elif k in ("-c", "--count"):
179 if command:
180 error_exit(progname, multcmds_errstr, 2)
181 command = "count"
182 elif k in ("-d", "--debug"):
183 verbosity = 2
184 elif k in ("-e", "--expand"):
185 if command:
186 error_exit(progname, multcmds_errstr, 2)
187 command = "expand"
188 elif k in ("-f", "--fold"):
189 if command:
190 error_exit(progname, multcmds_errstr, 2)
191 command = "fold"
192 elif k in ("-h", "--help"):
193 print __doc__
194 sys.exit(0)
195 elif k in ("-l", "--list"):
196 if command:
197 error_exit(progname, multcmds_errstr, 2)
198 command = "list"
199 elif k in ("-G", "--groupbase"):
200 groupbase = True
201 elif k in ("-q", "--quiet"):
202 verbosity = 0
203 elif k in ("-r", "--regroup"):
204 if command:
205 error_exit(progname, multcmds_errstr, 2)
206 command = "regroup"
207 elif k in ("-R", "--rangeset"):
208 class_set = RangeSet
209 elif k in ("-S", "--separator"):
210 separator = val
211 elif k in ("-s", "--groupsource"):
212 source = val
213 elif k in ("--groupsources"):
214 command = "groupsources"
215 elif k in ("-v", "--version"):
216 print __version__
217 sys.exit(0)
218
219
220 if not command:
221 print >> sys.stderr, "ERROR: no command specified."
222 print >> sys.stderr, __doc__
223 sys.exit(1)
224
225 if all: assert class_set == NodeSet, "-a is only supported in NodeSet mode"
226
227 if source and (class_set == RangeSet or command == "groupsources"):
228 print >> sys.stderr, "WARNING: option group source \"%s\" ignored" \
229 % source
230
231
232 if command == "list":
233 for group in grouplist(source):
234 if source and not groupbase:
235 print "@%s:%s" % (source, group)
236 else:
237 print "@%s" % group
238 return
239
240 elif command == "groupsources":
241 dispdefault = "(default)"
242 for src in STD_GROUP_RESOLVER.sources():
243 print "%s%s" % (src, dispdefault)
244 dispdefault = ""
245 return
246
247 try:
248 if verbosity > 1:
249 STD_GROUP_RESOLVER.set_verbosity(1)
250
251
252
253 if source:
254 STD_GROUP_RESOLVER.default_sourcename = source
255
256
257 xset = class_set()
258
259 if all:
260
261 xset.update(NodeSet.fromall())
262
263
264 elif not args:
265
266 process_stdin(xset, autostep)
267
268
269 compute_nodeset(xset, args, autostep)
270
271
272 separator = eval('\'%s\'' % separator, {"__builtins__":None}, {})
273
274
275 if command == "expand":
276 print separator.join(xset)
277 elif command == "fold":
278 print xset
279 elif command == "regroup":
280 print xset.regroup(source, noprefix=groupbase)
281 else:
282 print len(xset)
283
284 except (NodeSetParseError, RangeSetParseError), exc:
285 if verbosity > 0:
286 print >> sys.stderr, "%s parse error:" % class_set.__name__, exc
287 sys.exit(1)
288
289
290 if __name__ == '__main__':
291 try:
292 run_nodeset(sys.argv)
293 sys.exit(0)
294 except AssertionError, e:
295 print >> sys.stderr, "ERROR:", e
296 sys.exit(1)
297 except IndexError:
298 print >> sys.stderr, "ERROR: syntax error"
299 sys.exit(1)
300 except SyntaxError:
301 print >> sys.stderr, "ERROR: invalid separator"
302 sys.exit(1)
303 except NodeSetExternalError, e:
304 print >> sys.stderr, "ERROR: external error:", e
305 sys.exit(1)
306 except GroupResolverSourceError, e:
307 print >> sys.stderr, "ERROR: unknown group source: \"%s\"" % e
308 sys.exit(1)
309 except GroupSourceNoUpcall, e:
310 print >> sys.stderr, "ERROR: no %s upcall defined for group " \
311 "source \"%s\"" % (e, e.group_source.name)
312 sys.exit(1)
313 except GroupSourceException, e:
314 print >> sys.stderr, "ERROR: other group error:", e
315 sys.exit(1)
316 except KeyboardInterrupt:
317 sys.exit(128 + signal.SIGINT)
318