Module nodeset
[hide private]
[frames] | no frames]

Source Code for Module nodeset

  1  #!/usr/bin/env python 
  2  # 
  3  # Copyright CEA/DAM/DIF (2008, 2009, 2010) 
  4  #  Contributor: Stephane THIELL <stephane.thiell@cea.fr> 
  5  # 
  6  # This file is part of the ClusterShell library. 
  7  # 
  8  # This software is governed by the CeCILL-C license under French law and 
  9  # abiding by the rules of distribution of free software.  You can  use, 
 10  # modify and/ or redistribute the software under the terms of the CeCILL-C 
 11  # license as circulated by CEA, CNRS and INRIA at the following URL 
 12  # "http://www.cecill.info". 
 13  # 
 14  # As a counterpart to the access to the source code and  rights to copy, 
 15  # modify and redistribute granted by the license, users are provided only 
 16  # with a limited warranty  and the software's author,  the holder of the 
 17  # economic rights,  and the successive licensors  have only  limited 
 18  # liability. 
 19  # 
 20  # In this respect, the user's attention is drawn to the risks associated 
 21  # with loading,  using,  modifying and/or developing or reproducing the 
 22  # software by the user in light of its specific status of free software, 
 23  # that may mean  that it is complicated to manipulate,  and  that  also 
 24  # therefore means  that it is reserved for developers  and  experienced 
 25  # professionals having in-depth computer knowledge. Users are therefore 
 26  # encouraged to load and test the software's suitability as regards their 
 27  # requirements in conditions enabling the security of their systems and/or 
 28  # data to be ensured and,  more generally, to use and operate it in the 
 29  # same conditions as regards security. 
 30  # 
 31  # The fact that you are presently reading this means that you have had 
 32  # knowledge of the CeCILL-C license and that you accept its terms. 
 33  # 
 34  # $Id: nodeset.py 280 2010-06-16 21:15:41Z st-cea $ 
 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   
106 -def process_stdin(xset, autostep):
107 """Process standard input and populate xset.""" 108 for line in sys.stdin.readlines(): 109 # Support multi-lines and multi-nodesets per line 110 line = line[0:line.find('#')].strip() 111 for node in line.split(): 112 xset.update(xset.__class__(node, autostep=autostep))
113
114 -def compute_nodeset(xset, args, autostep):
115 """Apply operations and operands from args on xset, an initial 116 RangeSet or NodeSet.""" 117 class_set = xset.__class__ 118 # Process operations 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
137 -def error_exit(progname, message, status=1):
138 print >> sys.stderr, message 139 print >> sys.stderr, "Try `%s -h' for more information." % progname 140 sys.exit(status)
141
142 -def run_nodeset(args):
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 # Parse getoptable options 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 # Check for command presence 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 # The list command doesn't need any NodeSet, check for it first. 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 # Also, the groupsources command simply lists group sources. 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 # We want -s <groupsource> to act as a substition of default groupsource 252 # (ie. it's not necessary to prefix group names by this group source). 253 if source: 254 STD_GROUP_RESOLVER.default_sourcename = source 255 256 # Instantiate RangeSet or NodeSet object 257 xset = class_set() 258 259 if all: 260 # Include all nodes from external node groups support. 261 xset.update(NodeSet.fromall()) # uses default_sourcename 262 # FIXME: only union operation is supported when using -a due to 263 # current options handling. 264 elif not args: 265 # No need to specify '-' to read stdin if no argument at all. 266 process_stdin(xset, autostep) 267 268 # Finish xset computing from args 269 compute_nodeset(xset, args, autostep) 270 271 # Interprate special characters (may raise SyntaxError) 272 separator = eval('\'%s\'' % separator, {"__builtins__":None}, {}) 273 274 # Display result according to command choice 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