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) 
  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 165 2009-11-03 14:26:03Z st-cea $ 
 35   
 36  """ 
 37  Usage: nodeset [options] [command] 
 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  Options: 
 47      --autostep=<number>, -a <number> 
 48          Specify auto step threshold number when folding nodesets. 
 49          If not specified, auto step is disabled. 
 50          Example: autostep=4, "node2 node4 node6" folds in node[2,4,6] 
 51                   autostep=3, "node2 node4 node6" folds in node[2-6/2] 
 52      --exclude=<nodeset>, -x <nodeset> 
 53          Exclude provided node or nodeset from result. Can be specified 
 54          several times. 
 55      --help, -h 
 56          This help page. 
 57      --intersection, -i 
 58          Calculate nodesets intersection before processing command. This 
 59          means that only nodes that are in every provided nodesets are 
 60          used. 
 61      --xor, -X 
 62          Calculate symmetric difference (XOR) between two nodesets before 
 63          processing command. This means that nodes present in only one of 
 64          the nodesets are used. 
 65      --rangeset, -R 
 66          Switch to RangeSet instead of NodeSet. Useful when working on 
 67          numerical cluster ranges, eg. 1,5,18-31. 
 68      --quiet, -q 
 69          Quiet mode, hide any parse error messages (on stderr). 
 70      --version, -v 
 71          Show ClusterShell version and exit. 
 72  """ 
 73   
 74  import getopt 
 75  import signal 
 76  import sys 
 77   
 78  sys.path.insert(0, '../lib') 
 79   
 80  from ClusterShell.NodeSet import NodeSet, NodeSetParseError 
 81  from ClusterShell.NodeSet import RangeSet, RangeSetParseError 
 82  from ClusterShell import __version__ 
 83   
 84   
85 -def run_nodeset(args):
86 """ 87 Main script function. 88 """ 89 autostep = None 90 command = None 91 preprocess = None 92 quiet = False 93 class_set = NodeSet 94 95 # Parse command options using getopt 96 try: 97 opts, args = getopt.getopt(args[1:], "a:cefhiqvx:RX", ["autostep=", 98 "count", "expand", "fold", "help", "intersection", "quiet", 99 "rangeset", "version", "exclude=", "xor"]) 100 except getopt.error, msg: 101 print >>sys.stderr, msg 102 print >>sys.stderr, "Try `%s -h' for more information." % args[0] 103 sys.exit(2) 104 105 # Search for RangeSet switch in options 106 for opt in [ "-R", "--rangeset" ]: 107 if opt in [k for k, v in opts]: 108 class_set = RangeSet 109 110 # Initialize excludes set 111 excludes = class_set() 112 113 # Parse other options 114 for k, v in opts: 115 if k in ("-a", "--autostep"): 116 try: 117 autostep = int(v) 118 except ValueError, e: 119 print >>sys.stderr, e 120 elif k in ("-c", "--count"): 121 command = "count" 122 elif k in ("-e", "--expand"): 123 command = "expand" 124 elif k in ("-f", "--fold"): 125 command = "fold" 126 elif k in ("-h", "--help"): 127 print __doc__ 128 sys.exit(0) 129 elif k in ("-i", "--intersection"): 130 if preprocess and preprocess != class_set.intersection_update: 131 print >>sys.stderr, "ERROR: Conflicting options." 132 sys.exit(2) 133 preprocess = class_set.intersection_update 134 elif k in ("-q", "--quiet"): 135 quiet = True 136 elif k in ("-v", "--version"): 137 print __version__ 138 sys.exit(0) 139 elif k in ("-x", "--exclude"): 140 excludes.update(class_set(v)) 141 elif k in ("-X", "--xor"): 142 if preprocess and preprocess != class_set.symmetric_difference_update: 143 print >>sys.stderr, "ERROR: Conflicting options." 144 sys.exit(2) 145 preprocess = class_set.symmetric_difference_update 146 147 # Check for command presence 148 if not command: 149 print >>sys.stderr, "ERROR: no command specified." 150 print __doc__ 151 sys.exit(1) 152 153 try: 154 # Check for nodeset argument(s) 155 read_stdin = len(args) < 1 156 ns = None 157 158 if len(args): 159 if '-' in args: 160 # Special argument '-' means read from stdin 161 read_stdin = True 162 args.remove('-') 163 if len(args): 164 # Parse arguments 165 if not preprocess: 166 preprocess = class_set.update 167 # Create a base nodeset from first argument (do not use an 168 # empty nodeset as it wouldn't work when preprocess is 169 # intersection) 170 ns = class_set(args[0], autostep=autostep) 171 for arg in args[1:]: 172 preprocess(ns, class_set(arg, autostep=autostep)) 173 174 if read_stdin: 175 # Read standard input when argument is missing or when 176 # the special argument '-' is specified. 177 if not preprocess: 178 preprocess = class_set.update 179 # Support multi-lines and multi-nodesets per line 180 for line in sys.stdin.readlines(): 181 line = line[0:line.find('#')].strip() 182 for node in line.split(): 183 if not ns: 184 ns = class_set(node, autostep=autostep) 185 else: 186 preprocess(ns, class_set(node, autostep=autostep)) 187 188 # Finally, remove excluding nodes 189 if excludes: 190 ns.difference_update(excludes) 191 # Display result according to command choice 192 if command == "expand": 193 print " ".join(ns) 194 elif command == "fold": 195 print ns 196 else: 197 print len(ns) 198 except (NodeSetParseError, RangeSetParseError), e: 199 if not quiet: 200 print >>sys.stderr, "%s parse error:" % class_set.__name__, e 201 # In some case, NodeSet might report the part of the string 202 # that causes problem. For RangeSet it is always included 203 # in the error message. 204 if hasattr(e, 'part') and e.part: 205 print >>sys.stderr, ">>", e.part 206 sys.exit(1)
207 208 if __name__ == '__main__': 209 try: 210 run_nodeset(sys.argv) 211 except AssertionError, e: 212 print >>sys.stderr, "ERROR:", e 213 sys.exit(1) 214 except KeyboardInterrupt: 215 sys.exit(128 + signal.SIGINT) 216 sys.exit(0) 217