1 | #Licensed to the Apache Software Foundation (ASF) under one |
---|
2 | #or more contributor license agreements. See the NOTICE file |
---|
3 | #distributed with this work for additional information |
---|
4 | #regarding copyright ownership. The ASF licenses this file |
---|
5 | #to you under the Apache License, Version 2.0 (the |
---|
6 | #"License"); you may not use this file except in compliance |
---|
7 | #with the License. You may obtain a copy of the License at |
---|
8 | |
---|
9 | # http://www.apache.org/licenses/LICENSE-2.0 |
---|
10 | |
---|
11 | #Unless required by applicable law or agreed to in writing, software |
---|
12 | #distributed under the License is distributed on an "AS IS" BASIS, |
---|
13 | #WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
---|
14 | #See the License for the specific language governing permissions and |
---|
15 | #limitations under the License. |
---|
16 | # $Id:setup.py 5158 2007-04-09 00:14:35Z zim $ |
---|
17 | # $Id:setup.py 5158 2007-04-09 00:14:35Z zim $ |
---|
18 | # |
---|
19 | #------------------------------------------------------------------------------ |
---|
20 | |
---|
21 | """'setup' provides for reading and verifing configuration files based on |
---|
22 | Python's SafeConfigParser class.""" |
---|
23 | |
---|
24 | import sys, os, re, pprint |
---|
25 | |
---|
26 | from ConfigParser import SafeConfigParser |
---|
27 | from optparse import OptionParser, IndentedHelpFormatter, OptionGroup |
---|
28 | from util import get_perms, replace_escapes |
---|
29 | from types import typeValidator, typeValidatorInstance, is_valid_type, \ |
---|
30 | typeToString |
---|
31 | from hodlib.Hod.hod import hodHelp |
---|
32 | |
---|
33 | reEmailAddress = re.compile("^.*@.*$") |
---|
34 | reEmailDelimit = re.compile("@") |
---|
35 | reComma = re.compile("\s*,\s*") |
---|
36 | reDot = re.compile("\.") |
---|
37 | reCommentHack = re.compile("^.*?\s+#|;.*", flags=re.S) |
---|
38 | reCommentNewline = re.compile("\n|\r$") |
---|
39 | reKeyVal = r"(?<!\\)=" |
---|
40 | reKeyVal = re.compile(reKeyVal) |
---|
41 | reKeyValList = r"(?<!\\)," |
---|
42 | reKeyValList = re.compile(reKeyValList) |
---|
43 | |
---|
44 | errorPrefix = 'error' |
---|
45 | requiredPerms = '0660' |
---|
46 | |
---|
47 | class definition: |
---|
48 | def __init__(self): |
---|
49 | """Generates a configuration definition object.""" |
---|
50 | self.__def = {} |
---|
51 | self.__defOrder = [] |
---|
52 | |
---|
53 | def __repr__(self): |
---|
54 | return pprint.pformat(self.__def) |
---|
55 | |
---|
56 | def __getitem__(self, section): |
---|
57 | return self.__def[section] |
---|
58 | |
---|
59 | def __iter__(self): |
---|
60 | return iter(self.__def) |
---|
61 | |
---|
62 | def sections(self): |
---|
63 | """Returns a list of sections/groups.""" |
---|
64 | |
---|
65 | if len(self.__defOrder): |
---|
66 | return self.__defOrder |
---|
67 | else: |
---|
68 | return self.__def.keys() |
---|
69 | |
---|
70 | def add_section(self, section): |
---|
71 | """Add a configuration section / option group.""" |
---|
72 | |
---|
73 | if self.__def.has_key(section): |
---|
74 | raise Exception("Section already exists: '%s'" % section) |
---|
75 | else: |
---|
76 | self.__def[section] = {} |
---|
77 | |
---|
78 | def add_def(self, section, var, type, desc, help = True, default = None, |
---|
79 | req = True, validate = True, short = None): |
---|
80 | """ Add a variable definition. |
---|
81 | |
---|
82 | section - section name |
---|
83 | var - variable name |
---|
84 | type - valid hodlib.types |
---|
85 | desc - description of variable |
---|
86 | help - display help for this variable |
---|
87 | default - default value |
---|
88 | req - bool, requried? |
---|
89 | validate - bool, validate type value? |
---|
90 | short - short symbol (1 character), |
---|
91 | help - bool, display help?""" |
---|
92 | |
---|
93 | if self.__def.has_key(section): |
---|
94 | if not is_valid_type(type): |
---|
95 | raise Exception("Type (type) is invalid: %s.%s - '%s'" % (section, var, |
---|
96 | type)) |
---|
97 | if not isinstance(desc, str): |
---|
98 | raise Exception("Description (desc) must be a string: %s.%s - '%s'" % ( |
---|
99 | section, var, desc)) |
---|
100 | if not isinstance(req, bool): |
---|
101 | raise Exception("Required (req) must be a bool: %s.%s - '%s'" % (section, |
---|
102 | var, |
---|
103 | req)) |
---|
104 | if not isinstance(validate, bool): |
---|
105 | raise Exception("Validate (validate) must be a bool: %s.%s - '%s'" % ( |
---|
106 | section, var, validate)) |
---|
107 | |
---|
108 | if self.__def[section].has_key(var): |
---|
109 | raise Exception("Variable name already defined: '%s'" % var) |
---|
110 | else: |
---|
111 | self.__def[section][var] = { 'type' : type, |
---|
112 | 'desc' : desc, |
---|
113 | 'help' : help, |
---|
114 | 'default' : default, |
---|
115 | 'req' : req, |
---|
116 | 'validate' : validate, |
---|
117 | 'short' : short } |
---|
118 | else: |
---|
119 | raise Exception("Section does not exist: '%s'" % section) |
---|
120 | |
---|
121 | def add_defs(self, defList, defOrder=None): |
---|
122 | """ Add a series of definitions. |
---|
123 | |
---|
124 | defList = { section0 : ((name0, |
---|
125 | type0, |
---|
126 | desc0, |
---|
127 | help0, |
---|
128 | default0, |
---|
129 | req0, |
---|
130 | validate0, |
---|
131 | short0), |
---|
132 | .... |
---|
133 | (nameN, |
---|
134 | typeN, |
---|
135 | descN, |
---|
136 | helpN, |
---|
137 | defaultN, |
---|
138 | reqN, |
---|
139 | validateN, |
---|
140 | shortN)), |
---|
141 | .... |
---|
142 | |
---|
143 | sectionN : ... } |
---|
144 | |
---|
145 | Where the short synmbol is optional and can only be one char.""" |
---|
146 | |
---|
147 | for section in defList.keys(): |
---|
148 | self.add_section(section) |
---|
149 | for defTuple in defList[section]: |
---|
150 | if isinstance(defTuple, tuple): |
---|
151 | if len(defTuple) < 7: |
---|
152 | raise Exception( |
---|
153 | "section %s is missing an element: %s" % ( |
---|
154 | section, pprint.pformat(defTuple))) |
---|
155 | else: |
---|
156 | raise Exception("section %s of defList is not a tuple" % |
---|
157 | section) |
---|
158 | |
---|
159 | if len(defTuple) == 7: |
---|
160 | self.add_def(section, defTuple[0], defTuple[1], |
---|
161 | defTuple[2], defTuple[3], defTuple[4], |
---|
162 | defTuple[5], defTuple[6]) |
---|
163 | else: |
---|
164 | self.add_def(section, defTuple[0], defTuple[1], |
---|
165 | defTuple[2], defTuple[3], defTuple[4], |
---|
166 | defTuple[5], defTuple[6], defTuple[7]) |
---|
167 | if defOrder: |
---|
168 | for section in defOrder: |
---|
169 | if section in self.__def: |
---|
170 | self.__defOrder.append(section) |
---|
171 | |
---|
172 | for section in self.__def: |
---|
173 | if not section in defOrder: |
---|
174 | raise Exception( |
---|
175 | "section %s is missing from specified defOrder." % |
---|
176 | section) |
---|
177 | |
---|
178 | class baseConfig: |
---|
179 | def __init__(self, configDef, originalDir=None): |
---|
180 | self.__toString = typeToString() |
---|
181 | self.__validated = False |
---|
182 | self._configDef = configDef |
---|
183 | self._options = None |
---|
184 | self._mySections = [] |
---|
185 | self._dict = {} |
---|
186 | self.configFile = None |
---|
187 | self.__originalDir = originalDir |
---|
188 | |
---|
189 | if self._configDef: |
---|
190 | self._mySections = configDef.sections() |
---|
191 | |
---|
192 | def __repr__(self): |
---|
193 | """Returns a string representation of a config object including all |
---|
194 | normalizations.""" |
---|
195 | |
---|
196 | print_string = ''; |
---|
197 | for section in self._mySections: |
---|
198 | print_string = "%s[%s]\n" % (print_string, section) |
---|
199 | options = self._dict[section].keys() |
---|
200 | for option in options: |
---|
201 | print_string = "%s%s = %s\n" % (print_string, option, |
---|
202 | self._dict[section][option]) |
---|
203 | |
---|
204 | print_string = "%s\n" % (print_string) |
---|
205 | |
---|
206 | print_string = re.sub("\n\n$", "", print_string) |
---|
207 | |
---|
208 | return print_string |
---|
209 | |
---|
210 | def __getitem__(self, section): |
---|
211 | """ Returns a dictionary of configuration name and values by section. |
---|
212 | """ |
---|
213 | return self._dict[section] |
---|
214 | |
---|
215 | def __setitem__(self, section, value): |
---|
216 | self._dict[section] = value |
---|
217 | |
---|
218 | def __iter__(self): |
---|
219 | return iter(self._dict) |
---|
220 | |
---|
221 | def has_key(self, section): |
---|
222 | status = False |
---|
223 | if section in self._dict: |
---|
224 | status = True |
---|
225 | |
---|
226 | return status |
---|
227 | |
---|
228 | # Prints configuration error messages |
---|
229 | def var_error(self, section, option, *addData): |
---|
230 | errorStrings = [] |
---|
231 | if not self._dict[section].has_key(option): |
---|
232 | self._dict[section][option] = None |
---|
233 | errorStrings.append("%s: invalid '%s' specified in section %s (--%s.%s): %s" % ( |
---|
234 | errorPrefix, option, section, section, option, self._dict[section][option])) |
---|
235 | |
---|
236 | if addData: |
---|
237 | errorStrings.append("%s: additional info: %s\n" % (errorPrefix, |
---|
238 | addData[0])) |
---|
239 | return errorStrings |
---|
240 | |
---|
241 | def var_error_suggest(self, errorStrings): |
---|
242 | if self.configFile: |
---|
243 | errorStrings.append("Check your command line options and/or " + \ |
---|
244 | "your configuration file %s" % self.configFile) |
---|
245 | |
---|
246 | def __get_args(self, section): |
---|
247 | def __dummyToString(type, value): |
---|
248 | return value |
---|
249 | |
---|
250 | toString = __dummyToString |
---|
251 | if self.__validated: |
---|
252 | toString = self.__toString |
---|
253 | |
---|
254 | args = [] |
---|
255 | if isinstance(self._dict[section], dict): |
---|
256 | for option in self._dict[section]: |
---|
257 | if section in self._configDef and \ |
---|
258 | option in self._configDef[section]: |
---|
259 | if self._configDef[section][option]['type'] == 'bool': |
---|
260 | if self._dict[section][option] == 'True' or \ |
---|
261 | self._dict[section][option] == True: |
---|
262 | args.append("--%s.%s" % (section, option)) |
---|
263 | else: |
---|
264 | args.append("--%s.%s" % (section, option)) |
---|
265 | args.append(toString( |
---|
266 | self._configDef[section][option]['type'], |
---|
267 | self._dict[section][option])) |
---|
268 | else: |
---|
269 | if section in self._configDef: |
---|
270 | if self._configDef[section][option]['type'] == 'bool': |
---|
271 | if self._dict[section] == 'True' or \ |
---|
272 | self._dict[section] == True: |
---|
273 | args.append("--%s" % section) |
---|
274 | else: |
---|
275 | if self._dict[section] != 'config': |
---|
276 | args.append("--%s" % section) |
---|
277 | args.append(toString(self._configDef[section]['type'], |
---|
278 | self._dict[section])) |
---|
279 | |
---|
280 | return args |
---|
281 | |
---|
282 | def values(self): |
---|
283 | return self._dict.values() |
---|
284 | |
---|
285 | def keys(self): |
---|
286 | return self._dict.keys() |
---|
287 | |
---|
288 | def get_args(self, exclude=None, section=None): |
---|
289 | """Retrieve a tuple of config arguments.""" |
---|
290 | |
---|
291 | args = [] |
---|
292 | if section: |
---|
293 | args = self.__get_args(section) |
---|
294 | else: |
---|
295 | for section in self._dict: |
---|
296 | if exclude: |
---|
297 | if not section in exclude: |
---|
298 | args.extend(self.__get_args(section)) |
---|
299 | else: |
---|
300 | args.extend(self.__get_args(section)) |
---|
301 | |
---|
302 | return tuple(args) |
---|
303 | |
---|
304 | def verify(self): |
---|
305 | """Verifies each configuration variable, using the configValidator |
---|
306 | class, based on its type as defined by the dictionary configDef. |
---|
307 | Upon encountering a problem an error is printed to STDERR and |
---|
308 | false is returned.""" |
---|
309 | |
---|
310 | oldDir = os.getcwd() |
---|
311 | if self.__originalDir: |
---|
312 | os.chdir(self.__originalDir) |
---|
313 | |
---|
314 | status = True |
---|
315 | statusMsgs = [] |
---|
316 | |
---|
317 | if self._configDef: |
---|
318 | errorCount = 0 |
---|
319 | configValidator = typeValidator(self.__originalDir) |
---|
320 | |
---|
321 | # foreach section and option by type string as defined in configDef |
---|
322 | # add value to be validated to validator |
---|
323 | for section in self._mySections: |
---|
324 | for option in self._configDef[section].keys(): |
---|
325 | configVarName = "%s.%s" % (section, option) |
---|
326 | |
---|
327 | if self._dict[section].has_key(option): |
---|
328 | if self._configDef[section][option].has_key('validate'): |
---|
329 | if self._configDef[section][option]['validate']: |
---|
330 | # is the section.option needed to be validated? |
---|
331 | configValidator.add(configVarName, |
---|
332 | self._configDef[section][option]['type'], |
---|
333 | self._dict[section][option]) |
---|
334 | else: |
---|
335 | # If asked not to validate, just normalize |
---|
336 | self[section][option] = \ |
---|
337 | configValidator.normalize( |
---|
338 | self._configDef[section][option]['type'], |
---|
339 | self._dict[section][option]) |
---|
340 | if self._configDef[section][option]['default'] != \ |
---|
341 | None: |
---|
342 | self._configDef[section][option]['default'] = \ |
---|
343 | configValidator.normalize( |
---|
344 | self._configDef[section][option]['type'], |
---|
345 | self._configDef[section][option]['default'] |
---|
346 | ) |
---|
347 | self._configDef[section][option]['default'] = \ |
---|
348 | self.__toString( |
---|
349 | self._configDef[section][option]['type'], |
---|
350 | self._configDef[section][option]['default'] |
---|
351 | ) |
---|
352 | else: |
---|
353 | # This should not happen. Just in case, take this as 'to be validated' case. |
---|
354 | configValidator.add(configVarName, |
---|
355 | self._configDef[section][option]['type'], |
---|
356 | self._dict[section][option]) |
---|
357 | elif self._configDef[section][option]['req']: |
---|
358 | statusMsgs.append("%s: %s.%s is not defined." |
---|
359 | % (errorPrefix, section, option)) |
---|
360 | errorCount = errorCount + 1 |
---|
361 | |
---|
362 | configValidator.validate() |
---|
363 | |
---|
364 | for valueInfo in configValidator.validatedInfo: |
---|
365 | sectionsOptions = reDot.split(valueInfo['name']) |
---|
366 | |
---|
367 | if valueInfo['isValid'] == 1: |
---|
368 | self._dict[sectionsOptions[0]][sectionsOptions[1]] = \ |
---|
369 | valueInfo['normalized'] |
---|
370 | else: |
---|
371 | if valueInfo['errorData']: |
---|
372 | statusMsgs.extend(self.var_error(sectionsOptions[0], |
---|
373 | sectionsOptions[1], valueInfo['errorData'])) |
---|
374 | else: |
---|
375 | statusMsgs.extend(self.var_error(sectionsOptions[0], |
---|
376 | sectionsOptions[1])) |
---|
377 | errorCount = errorCount + 1 |
---|
378 | |
---|
379 | if errorCount > 1: |
---|
380 | statusMsgs.append( "%s: %s problems found." % ( |
---|
381 | errorPrefix, errorCount)) |
---|
382 | self.var_error_suggest(statusMsgs) |
---|
383 | status = False |
---|
384 | elif errorCount > 0: |
---|
385 | statusMsgs.append( "%s: %s problem found." % ( |
---|
386 | errorPrefix, errorCount)) |
---|
387 | self.var_error_suggest(statusMsgs) |
---|
388 | status = False |
---|
389 | |
---|
390 | self.__validated = True |
---|
391 | |
---|
392 | if self.__originalDir: |
---|
393 | os.chdir(oldDir) |
---|
394 | |
---|
395 | return status,statusMsgs |
---|
396 | |
---|
397 | def normalizeValue(self, section, option) : |
---|
398 | return typeValidatorInstance.normalize( |
---|
399 | self._configDef[section][option]['type'], |
---|
400 | self[section][option]) |
---|
401 | |
---|
402 | def validateValue(self, section, option): |
---|
403 | # Validates a section.option and exits on error |
---|
404 | valueInfo = typeValidatorInstance.verify( |
---|
405 | self._configDef[section][option]['type'], |
---|
406 | self[section][option]) |
---|
407 | if valueInfo['isValid'] == 1: |
---|
408 | return [] |
---|
409 | else: |
---|
410 | if valueInfo['errorData']: |
---|
411 | return self.var_error(section, option, valueInfo['errorData']) |
---|
412 | else: |
---|
413 | return self.var_error(section, option) |
---|
414 | |
---|
415 | class config(SafeConfigParser, baseConfig): |
---|
416 | def __init__(self, configFile, configDef=None, originalDir=None, |
---|
417 | options=None, checkPerms=False): |
---|
418 | """Constructs config object. |
---|
419 | |
---|
420 | configFile - configuration file to read |
---|
421 | configDef - definition object |
---|
422 | options - options object |
---|
423 | checkPerms - check file permission on config file, 0660 |
---|
424 | |
---|
425 | sample configuration file: |
---|
426 | |
---|
427 | [snis] |
---|
428 | modules_dir = modules/ ; location of infoModules |
---|
429 | md5_defs_dir = etc/md5_defs ; location of infoTree md5 defs |
---|
430 | info_store = var/info ; location of nodeInfo store |
---|
431 | cam_daemon = localhost:8200 ; cam daemon address""" |
---|
432 | |
---|
433 | |
---|
434 | SafeConfigParser.__init__(self) |
---|
435 | baseConfig.__init__(self, configDef, originalDir) |
---|
436 | |
---|
437 | if(os.path.exists(configFile)): |
---|
438 | self.configFile = configFile |
---|
439 | else: |
---|
440 | raise IOError |
---|
441 | |
---|
442 | self._options = options |
---|
443 | |
---|
444 | ## UNUSED CODE : checkPerms is never True |
---|
445 | ## zim: this code is used if one instantiates config() with checkPerms set to |
---|
446 | ## True. |
---|
447 | if checkPerms: self.__check_perms() |
---|
448 | |
---|
449 | self.read(configFile) |
---|
450 | |
---|
451 | self._configDef = configDef |
---|
452 | if not self._configDef: |
---|
453 | self._mySections = self.sections() |
---|
454 | |
---|
455 | self.__initialize_config_dict() |
---|
456 | |
---|
457 | def __initialize_config_dict(self): |
---|
458 | """ build a dictionary of config vars keyed by section name defined in |
---|
459 | configDef, if options defined override config""" |
---|
460 | |
---|
461 | for section in self._mySections: |
---|
462 | items = self.items(section) |
---|
463 | self._dict[section] = {} |
---|
464 | |
---|
465 | # First fill self._dict with whatever is given in hodrc. |
---|
466 | # Going by this, options given at the command line either override |
---|
467 | # options in hodrc, or get appended to the list, like for |
---|
468 | # hod.client-params. Note that after this dict has _only_ hodrc |
---|
469 | # params |
---|
470 | for keyValuePair in items: |
---|
471 | # stupid commenting bug in ConfigParser class, lines without an |
---|
472 | # option value pair or section required that ; or # are at the |
---|
473 | # beginning of the line, :( |
---|
474 | newValue = reCommentHack.sub("", keyValuePair[1]) |
---|
475 | newValue = reCommentNewline.sub("", newValue) |
---|
476 | self._dict[section][keyValuePair[0]] = newValue |
---|
477 | # end of filling with options given in hodrc |
---|
478 | # now start filling in command line options |
---|
479 | if self._options: |
---|
480 | for option in self._configDef[section].keys(): |
---|
481 | if self._options[section].has_key(option): |
---|
482 | # the user has given an option |
---|
483 | compoundOpt = "%s.%s" %(section,option) |
---|
484 | if ( compoundOpt == \ |
---|
485 | 'gridservice-mapred.final-server-params' \ |
---|
486 | or compoundOpt == \ |
---|
487 | 'gridservice-hdfs.final-server-params' \ |
---|
488 | or compoundOpt == \ |
---|
489 | 'gridservice-mapred.server-params' \ |
---|
490 | or compoundOpt == \ |
---|
491 | 'gridservice-hdfs.server-params' \ |
---|
492 | or compoundOpt == \ |
---|
493 | 'hod.client-params' ): |
---|
494 | |
---|
495 | if ( compoundOpt == \ |
---|
496 | 'gridservice-mapred.final-server-params' \ |
---|
497 | or compoundOpt == \ |
---|
498 | 'gridservice-hdfs.final-server-params' ): |
---|
499 | overwrite = False |
---|
500 | else: overwrite = True |
---|
501 | |
---|
502 | # Append to the current list of values in self._dict |
---|
503 | if not self._dict[section].has_key(option): |
---|
504 | self._dict[section][option] = "" |
---|
505 | dictOpts = reKeyValList.split(self._dict[section][option]) |
---|
506 | dictOptsKeyVals = {} |
---|
507 | for opt in dictOpts: |
---|
508 | if opt != '': |
---|
509 | # when dict _has_ params from hodrc |
---|
510 | if reKeyVal.search(opt): |
---|
511 | (key, val) = reKeyVal.split(opt,1) |
---|
512 | # we only consider the first '=' for splitting |
---|
513 | # we do this to support passing params like |
---|
514 | # mapred.child.java.opts=-Djava.library.path=some_dir |
---|
515 | # Even in case of an invalid error like unescaped '=', |
---|
516 | # we don't want to fail here itself. We leave such errors |
---|
517 | # to be caught during validation which happens after this |
---|
518 | dictOptsKeyVals[key] = val |
---|
519 | else: |
---|
520 | # this means an invalid option. Leaving it |
---|
521 | #for config.verify to catch |
---|
522 | dictOptsKeyVals[opt] = None |
---|
523 | |
---|
524 | cmdLineOpts = reKeyValList.split(self._options[section][option]) |
---|
525 | |
---|
526 | for opt in cmdLineOpts: |
---|
527 | if reKeyVal.search(opt): |
---|
528 | # Same as for hodrc options. only consider |
---|
529 | # the first = |
---|
530 | ( key, val ) = reKeyVal.split(opt,1) |
---|
531 | else: |
---|
532 | key = opt |
---|
533 | val = None |
---|
534 | # whatever is given at cmdline overrides |
---|
535 | # what is given in hodrc only for non-final params |
---|
536 | if dictOptsKeyVals.has_key(key): |
---|
537 | if overwrite: |
---|
538 | dictOptsKeyVals[key] = val |
---|
539 | else: dictOptsKeyVals[key] = val |
---|
540 | |
---|
541 | self._dict[section][option] = "" |
---|
542 | for key in dictOptsKeyVals: |
---|
543 | if self._dict[section][option] == "": |
---|
544 | if dictOptsKeyVals[key]: |
---|
545 | self._dict[section][option] = key + "=" + \ |
---|
546 | dictOptsKeyVals[key] |
---|
547 | else: #invalid option. let config.verify catch |
---|
548 | self._dict[section][option] = key |
---|
549 | else: |
---|
550 | if dictOptsKeyVals[key]: |
---|
551 | self._dict[section][option] = \ |
---|
552 | self._dict[section][option] + "," + key + \ |
---|
553 | "=" + dictOptsKeyVals[key] |
---|
554 | else: #invalid option. let config.verify catch |
---|
555 | self._dict[section][option] = \ |
---|
556 | self._dict[section][option] + "," + key |
---|
557 | |
---|
558 | else: |
---|
559 | # for rest of the options, that don't need |
---|
560 | # appending business. |
---|
561 | # options = cmdline opts + defaults |
---|
562 | # dict = hodrc opts only |
---|
563 | # only non default opts can overwrite any opt |
---|
564 | # currently in dict |
---|
565 | if not self._dict[section].has_key(option): |
---|
566 | # options not mentioned in hodrc |
---|
567 | self._dict[section][option] = \ |
---|
568 | self._options[section][option] |
---|
569 | elif self._configDef[section][option]['default'] != \ |
---|
570 | self._options[section][option]: |
---|
571 | # option mentioned in hodrc but user has given a |
---|
572 | # non-default option |
---|
573 | self._dict[section][option] = \ |
---|
574 | self._options[section][option] |
---|
575 | |
---|
576 | ## UNUSED METHOD |
---|
577 | ## zim: is too :) |
---|
578 | def __check_perms(self): |
---|
579 | perms = None |
---|
580 | if self._options: |
---|
581 | try: |
---|
582 | perms = get_perms(self.configFile) |
---|
583 | except OSError, data: |
---|
584 | self._options.print_help() |
---|
585 | raise Exception("*** could not find config file: %s" % data) |
---|
586 | sys.exit(1) |
---|
587 | else: |
---|
588 | perms = get_perms(self.configFile) |
---|
589 | |
---|
590 | if perms != requiredPerms: |
---|
591 | error = "*** '%s' has invalid permission: %s should be %s\n" % \ |
---|
592 | (self.configFile, perms, requiredPerms) |
---|
593 | raise Exception( error) |
---|
594 | sys.exit(1) |
---|
595 | |
---|
596 | def replace_escape_seqs(self): |
---|
597 | """ replace any escaped characters """ |
---|
598 | replace_escapes(self) |
---|
599 | |
---|
600 | class formatter(IndentedHelpFormatter): |
---|
601 | def format_option_strings(self, option): |
---|
602 | """Return a comma-separated list of option strings & metavariables.""" |
---|
603 | if option.takes_value(): |
---|
604 | metavar = option.metavar or option.dest.upper() |
---|
605 | short_opts = [sopt |
---|
606 | for sopt in option._short_opts] |
---|
607 | long_opts = [self._long_opt_fmt % (lopt, metavar) |
---|
608 | for lopt in option._long_opts] |
---|
609 | else: |
---|
610 | short_opts = option._short_opts |
---|
611 | long_opts = option._long_opts |
---|
612 | |
---|
613 | if self.short_first: |
---|
614 | opts = short_opts + long_opts |
---|
615 | else: |
---|
616 | opts = long_opts + short_opts |
---|
617 | |
---|
618 | return ", ".join(opts) |
---|
619 | |
---|
620 | class options(OptionParser, baseConfig): |
---|
621 | |
---|
622 | def __init__(self, optionDef, usage, version, originalDir=None, |
---|
623 | withConfig=False, defaultConfig=None, defaultLocation=None, |
---|
624 | name=None): |
---|
625 | """Constructs and options object. |
---|
626 | |
---|
627 | optionDef - definition object |
---|
628 | usage - usage statement |
---|
629 | version - version string |
---|
630 | withConfig - used in conjunction with a configuration file |
---|
631 | defaultConfig - default configuration file |
---|
632 | |
---|
633 | """ |
---|
634 | OptionParser.__init__(self, usage=usage) |
---|
635 | baseConfig.__init__(self, optionDef, originalDir) |
---|
636 | |
---|
637 | self.formatter = formatter(4, max_help_position=100, width=180, |
---|
638 | short_first=1) |
---|
639 | |
---|
640 | self.__name = name |
---|
641 | self.__version = version |
---|
642 | self.__withConfig = withConfig |
---|
643 | self.__defaultConfig = defaultConfig |
---|
644 | self.__defaultLoc = defaultLocation |
---|
645 | self.args = [] |
---|
646 | self.__optionList = [] |
---|
647 | self.__compoundOpts = [] |
---|
648 | self.__shortMap = {} |
---|
649 | self.__alphaString = 'abcdefghijklmnopqrstuvxyzABCDEFGHIJKLMNOPQRSTUVXYZ1234567890' |
---|
650 | self.__alpha = [] |
---|
651 | self.__parsedOptions = {} |
---|
652 | self.__reserved = [ 'h' ] |
---|
653 | |
---|
654 | self.__orig_grps = [] |
---|
655 | self.__orig_grp_lists = {} |
---|
656 | self.__orig_option_list = [] |
---|
657 | |
---|
658 | self.__display_grps = [] |
---|
659 | self.__display_grp_lists = {} |
---|
660 | self.__display_option_list = [] |
---|
661 | |
---|
662 | self.config = None |
---|
663 | |
---|
664 | if self.__withConfig: |
---|
665 | self.__reserved.append('c') |
---|
666 | self.__reserved.append('v') |
---|
667 | |
---|
668 | self.__gen_alpha() |
---|
669 | |
---|
670 | # build self.__optionList, so it contains all the options that are |
---|
671 | # possible. the list elements are of the form section.option |
---|
672 | for section in self._mySections: |
---|
673 | if self.__withConfig and section == 'config': |
---|
674 | raise Exception( |
---|
675 | "withConfig set 'config' cannot be used as a section name") |
---|
676 | for option in self._configDef[section].keys(): |
---|
677 | if '.' in option: |
---|
678 | raise Exception("Options cannot contain: '.'") |
---|
679 | elif self.__withConfig and option == 'config': |
---|
680 | raise Exception( |
---|
681 | "With config set, option config is not allowed.") |
---|
682 | elif self.__withConfig and option == 'verbose-help': |
---|
683 | raise Exception( |
---|
684 | "With config set, option verbose-help is not allowed.") |
---|
685 | self.__optionList.append(self.__splice_compound(section, |
---|
686 | option)) |
---|
687 | self.__build_short_map() |
---|
688 | self.__add_options() |
---|
689 | self.__init_display_options() |
---|
690 | |
---|
691 | (self.__parsedOptions, self.args) = self.parse_args() |
---|
692 | |
---|
693 | # Now process the positional arguments only for the client side |
---|
694 | if self.__name == 'hod': |
---|
695 | |
---|
696 | hodhelp = hodHelp() |
---|
697 | |
---|
698 | _operation = getattr(self.__parsedOptions,'hod.operation') |
---|
699 | _script = getattr(self.__parsedOptions, 'hod.script') |
---|
700 | nArgs = self.args.__len__() |
---|
701 | if _operation: |
---|
702 | # -o option is given |
---|
703 | if nArgs != 0: |
---|
704 | self.error('invalid syntax : command and operation(-o) cannot coexist') |
---|
705 | elif nArgs == 0 and _script: |
---|
706 | # for a script option, without subcommand: hod -s script ... |
---|
707 | pass |
---|
708 | elif nArgs == 0: |
---|
709 | print "Usage: ",hodhelp.help() |
---|
710 | sys.exit(0) |
---|
711 | else: |
---|
712 | # subcommand is given |
---|
713 | cmdstr = self.args[0] # the subcommand itself |
---|
714 | cmdlist = hodhelp.ops |
---|
715 | if cmdstr not in cmdlist: |
---|
716 | print "Usage: ", hodhelp.help() |
---|
717 | sys.exit(2) |
---|
718 | |
---|
719 | numNodes = None |
---|
720 | clusterDir = None |
---|
721 | # Check which subcommand. cmdstr = subcommand itself now. |
---|
722 | if cmdstr == "allocate": |
---|
723 | clusterDir = getattr(self.__parsedOptions, 'hod.clusterdir') |
---|
724 | numNodes = getattr(self.__parsedOptions, 'hod.nodecount') |
---|
725 | |
---|
726 | if not clusterDir or not numNodes: |
---|
727 | print hodhelp.usage(cmdstr) |
---|
728 | sys.exit(3) |
---|
729 | |
---|
730 | cmdstr = cmdstr + ' ' + clusterDir + ' ' + numNodes |
---|
731 | |
---|
732 | setattr(self.__parsedOptions,'hod.operation', cmdstr) |
---|
733 | |
---|
734 | elif cmdstr == "deallocate" or cmdstr == "info": |
---|
735 | clusterDir = getattr(self.__parsedOptions, 'hod.clusterdir') |
---|
736 | |
---|
737 | if not clusterDir: |
---|
738 | print hodhelp.usage(cmdstr) |
---|
739 | sys.exit(3) |
---|
740 | |
---|
741 | cmdstr = cmdstr + ' ' + clusterDir |
---|
742 | setattr(self.__parsedOptions,'hod.operation', cmdstr) |
---|
743 | |
---|
744 | elif cmdstr == "list": |
---|
745 | setattr(self.__parsedOptions,'hod.operation', cmdstr) |
---|
746 | pass |
---|
747 | |
---|
748 | elif cmdstr == "script": |
---|
749 | clusterDir = getattr(self.__parsedOptions, 'hod.clusterdir') |
---|
750 | numNodes = getattr(self.__parsedOptions, 'hod.nodecount') |
---|
751 | originalDir = getattr(self.__parsedOptions, 'hod.original-dir') |
---|
752 | |
---|
753 | if originalDir and clusterDir: |
---|
754 | self.remove_exit_code_file(originalDir, clusterDir) |
---|
755 | |
---|
756 | if not _script or not clusterDir or not numNodes: |
---|
757 | print hodhelp.usage(cmdstr) |
---|
758 | sys.exit(3) |
---|
759 | pass |
---|
760 | |
---|
761 | elif cmdstr == "help": |
---|
762 | if nArgs == 1: |
---|
763 | self.print_help() |
---|
764 | sys.exit(0) |
---|
765 | elif nArgs != 2: |
---|
766 | self.print_help() |
---|
767 | sys.exit(3) |
---|
768 | elif self.args[1] == 'options': |
---|
769 | self.print_options() |
---|
770 | sys.exit(0) |
---|
771 | cmdstr = cmdstr + ' ' + self.args[1] |
---|
772 | setattr(self.__parsedOptions,'hod.operation', cmdstr) |
---|
773 | |
---|
774 | # end of processing for arguments on the client side |
---|
775 | |
---|
776 | if self.__withConfig: |
---|
777 | self.config = self.__parsedOptions.config |
---|
778 | if not self.config: |
---|
779 | self.error("configuration file must be specified") |
---|
780 | if not os.path.isabs(self.config): |
---|
781 | # A relative path. Append the original directory which would be the |
---|
782 | # current directory at the time of launch |
---|
783 | try: |
---|
784 | origDir = getattr(self.__parsedOptions, 'hod.original-dir') |
---|
785 | if origDir is not None: |
---|
786 | self.config = os.path.join(origDir, self.config) |
---|
787 | self.__parsedOptions.config = self.config |
---|
788 | except AttributeError, e: |
---|
789 | self.error("hod.original-dir is not defined.\ |
---|
790 | Cannot get current directory") |
---|
791 | if not os.path.exists(self.config): |
---|
792 | if self.__defaultLoc and not re.search("/", self.config): |
---|
793 | self.__parsedOptions.config = os.path.join( |
---|
794 | self.__defaultLoc, self.config) |
---|
795 | self.__build_dict() |
---|
796 | |
---|
797 | def norm_cluster_dir(self, orig_dir, directory): |
---|
798 | directory = os.path.expanduser(directory) |
---|
799 | if not os.path.isabs(directory): |
---|
800 | directory = os.path.join(orig_dir, directory) |
---|
801 | directory = os.path.abspath(directory) |
---|
802 | |
---|
803 | return directory |
---|
804 | |
---|
805 | def remove_exit_code_file(self, orig_dir, dir): |
---|
806 | try: |
---|
807 | dir = self.norm_cluster_dir(orig_dir, dir) |
---|
808 | if os.path.exists(dir): |
---|
809 | exit_code_file = os.path.join(dir, "script.exitcode") |
---|
810 | if os.path.exists(exit_code_file): |
---|
811 | os.remove(exit_code_file) |
---|
812 | except: |
---|
813 | print >>sys.stderr, "Could not remove the script.exitcode file." |
---|
814 | |
---|
815 | def __init_display_options(self): |
---|
816 | self.__orig_option_list = self.option_list[:] |
---|
817 | optionListTitleMap = {} |
---|
818 | for option in self.option_list: |
---|
819 | optionListTitleMap[option._long_opts[0]] = option |
---|
820 | |
---|
821 | self.__orig_grps = self.option_groups[:] |
---|
822 | for group in self.option_groups: |
---|
823 | self.__orig_grp_lists[group.title] = group.option_list[:] |
---|
824 | |
---|
825 | groupTitleMap = {} |
---|
826 | optionTitleMap = {} |
---|
827 | for group in self.option_groups: |
---|
828 | groupTitleMap[group.title] = group |
---|
829 | optionTitleMap[group.title] = {} |
---|
830 | for option in group.option_list: |
---|
831 | (sectionName, optionName) = \ |
---|
832 | self.__split_compound(option._long_opts[0]) |
---|
833 | optionTitleMap[group.title][optionName] = option |
---|
834 | |
---|
835 | for section in self._mySections: |
---|
836 | for option in self._configDef[section]: |
---|
837 | if self._configDef[section][option]['help']: |
---|
838 | if groupTitleMap.has_key(section): |
---|
839 | if not self.__display_grp_lists.has_key(section): |
---|
840 | self.__display_grp_lists[section] = [] |
---|
841 | self.__display_grp_lists[section].append( |
---|
842 | optionTitleMap[section][option]) |
---|
843 | |
---|
844 | try: |
---|
845 | self.__display_option_list.append( |
---|
846 | optionListTitleMap["--" + self.__splice_compound( |
---|
847 | section, option)]) |
---|
848 | except KeyError: |
---|
849 | pass |
---|
850 | try: |
---|
851 | self.__display_option_list.append(optionListTitleMap['--config']) |
---|
852 | except KeyError: |
---|
853 | pass |
---|
854 | |
---|
855 | self.__display_option_list.append(optionListTitleMap['--help']) |
---|
856 | self.__display_option_list.append(optionListTitleMap['--verbose-help']) |
---|
857 | self.__display_option_list.append(optionListTitleMap['--version']) |
---|
858 | |
---|
859 | self.__display_grps = self.option_groups[:] |
---|
860 | for section in self._mySections: |
---|
861 | if self.__display_grp_lists.has_key(section): |
---|
862 | self.__orig_grp_lists[section] = \ |
---|
863 | groupTitleMap[section].option_list |
---|
864 | else: |
---|
865 | try: |
---|
866 | self.__display_grps.remove(groupTitleMap[section]) |
---|
867 | except KeyError: |
---|
868 | pass |
---|
869 | |
---|
870 | def __gen_alpha(self): |
---|
871 | assignedOptions = [] |
---|
872 | for section in self._configDef: |
---|
873 | for option in self._configDef[section]: |
---|
874 | if self._configDef[section][option]['short']: |
---|
875 | assignedOptions.append( |
---|
876 | self._configDef[section][option]['short']) |
---|
877 | |
---|
878 | for symbol in self.__alphaString: |
---|
879 | if not symbol in assignedOptions: |
---|
880 | self.__alpha.append(symbol) |
---|
881 | |
---|
882 | def __splice_compound(self, section, option): |
---|
883 | return "%s.%s" % (section, option) |
---|
884 | |
---|
885 | def __split_compound(self, compound): |
---|
886 | return compound.split('.') |
---|
887 | |
---|
888 | def __build_short_map(self): |
---|
889 | """ build a short_map of parametername : short_option. This is done |
---|
890 | only for those parameters that don't have short options already |
---|
891 | defined in configDef. |
---|
892 | If possible, the first letter in the option that is not already |
---|
893 | used/reserved as a short option is allotted. Otherwise the first |
---|
894 | letter in __alpha that isn't still used is allotted. |
---|
895 | e.g. { 'hodring.java-home': 'T', 'resource_manager.batch-home': 'B' } |
---|
896 | """ |
---|
897 | |
---|
898 | optionsKey = {} |
---|
899 | for compound in self.__optionList: |
---|
900 | (section, option) = self.__split_compound(compound) |
---|
901 | if not optionsKey.has_key(section): |
---|
902 | optionsKey[section] = [] |
---|
903 | optionsKey[section].append(option) |
---|
904 | |
---|
905 | for section in self._configDef.sections(): |
---|
906 | options = optionsKey[section] |
---|
907 | options.sort() |
---|
908 | for option in options: |
---|
909 | if not self._configDef[section][option]['short']: |
---|
910 | compound = self.__splice_compound(section, option) |
---|
911 | shortOptions = self.__shortMap.values() |
---|
912 | for i in range(0, len(option)): |
---|
913 | letter = option[i] |
---|
914 | letter = letter.lower() |
---|
915 | if letter in self.__alpha: |
---|
916 | if not letter in shortOptions and \ |
---|
917 | not letter in self.__reserved: |
---|
918 | self.__shortMap[compound] = letter |
---|
919 | break |
---|
920 | if not self.__shortMap.has_key(compound): |
---|
921 | for i in range(0, len(self.__alpha)): |
---|
922 | letter = self.__alpha[i] |
---|
923 | if not letter in shortOptions and \ |
---|
924 | not letter in self.__reserved: |
---|
925 | self.__shortMap[compound] = letter |
---|
926 | |
---|
927 | def __add_option(self, config, compoundOpt, section, option, group=None): |
---|
928 | addMethod = self.add_option |
---|
929 | if group: addMethod=group.add_option |
---|
930 | |
---|
931 | self.__compoundOpts.append(compoundOpt) |
---|
932 | |
---|
933 | if compoundOpt == 'gridservice-mapred.final-server-params' or \ |
---|
934 | compoundOpt == 'gridservice-hdfs.final-server-params' or \ |
---|
935 | compoundOpt == 'gridservice-mapred.server-params' or \ |
---|
936 | compoundOpt == 'gridservice-hdfs.server-params' or \ |
---|
937 | compoundOpt == 'hod.client-params': |
---|
938 | _action = 'append' |
---|
939 | elif config[section][option]['type'] == 'bool': |
---|
940 | _action = 'store_true' |
---|
941 | else: |
---|
942 | _action = 'store' |
---|
943 | |
---|
944 | if self.__shortMap.has_key(compoundOpt): |
---|
945 | addMethod("-" + self.__shortMap[compoundOpt], |
---|
946 | "--" + compoundOpt, dest=compoundOpt, |
---|
947 | action= _action, |
---|
948 | metavar=config[section][option]['type'], |
---|
949 | default=config[section][option]['default'], |
---|
950 | help=config[section][option]['desc']) |
---|
951 | else: |
---|
952 | if config[section][option]['short']: |
---|
953 | addMethod("-" + config[section][option]['short'], |
---|
954 | "--" + compoundOpt, dest=compoundOpt, |
---|
955 | action= _action, |
---|
956 | metavar=config[section][option]['type'], |
---|
957 | default=config[section][option]['default'], |
---|
958 | help=config[section][option]['desc']) |
---|
959 | else: |
---|
960 | addMethod('', "--" + compoundOpt, dest=compoundOpt, |
---|
961 | action= _action, |
---|
962 | metavar=config[section][option]['type'], |
---|
963 | default=config[section][option]['default'], |
---|
964 | help=config[section][option]['desc']) |
---|
965 | |
---|
966 | def __add_options(self): |
---|
967 | if self.__withConfig: |
---|
968 | self.add_option("-c", "--config", dest='config', |
---|
969 | action='store', default=self.__defaultConfig, |
---|
970 | metavar='config_file', |
---|
971 | help="Full path to configuration file.") |
---|
972 | |
---|
973 | self.add_option("", "--verbose-help", |
---|
974 | action='help', default=None, |
---|
975 | metavar='flag', |
---|
976 | help="Display verbose help information.") |
---|
977 | |
---|
978 | self.add_option("-v", "--version", |
---|
979 | action='version', default=None, |
---|
980 | metavar='flag', |
---|
981 | help="Display version information.") |
---|
982 | |
---|
983 | self.version = self.__version |
---|
984 | |
---|
985 | if len(self._mySections) > 1: |
---|
986 | for section in self._mySections: |
---|
987 | group = OptionGroup(self, section) |
---|
988 | for option in self._configDef[section]: |
---|
989 | compoundOpt = self.__splice_compound(section, option) |
---|
990 | self.__add_option(self._configDef, compoundOpt, section, |
---|
991 | option, group) |
---|
992 | self.add_option_group(group) |
---|
993 | else: |
---|
994 | for section in self._mySections: |
---|
995 | for option in self._configDef[section]: |
---|
996 | compoundOpt = self.__splice_compound(section, option) |
---|
997 | self.__add_option(self._configDef, compoundOpt, section, |
---|
998 | option) |
---|
999 | |
---|
1000 | def __build_dict(self): |
---|
1001 | if self.__withConfig: |
---|
1002 | self._dict['config'] = str(getattr(self.__parsedOptions, 'config')) |
---|
1003 | for compoundOption in dir(self.__parsedOptions): |
---|
1004 | if compoundOption in self.__compoundOpts: |
---|
1005 | (section, option) = self.__split_compound(compoundOption) |
---|
1006 | if not self._dict.has_key(section): |
---|
1007 | self._dict[section] = {} |
---|
1008 | |
---|
1009 | if getattr(self.__parsedOptions, compoundOption): |
---|
1010 | _attr = getattr(self.__parsedOptions, compoundOption) |
---|
1011 | # when we have multi-valued parameters passed separately |
---|
1012 | # from command line, python optparser pushes them into a |
---|
1013 | # list. So converting all such lists to strings |
---|
1014 | if type(_attr) == type([]): |
---|
1015 | import string |
---|
1016 | _attr = string.join(_attr,',') |
---|
1017 | self._dict[section][option] = _attr |
---|
1018 | |
---|
1019 | for section in self._configDef: |
---|
1020 | for option in self._configDef[section]: |
---|
1021 | if self._configDef[section][option]['type'] == 'bool': |
---|
1022 | compoundOption = self.__splice_compound(section, option) |
---|
1023 | if not self._dict.has_key(section): |
---|
1024 | self._dict[section] = {} |
---|
1025 | |
---|
1026 | if option not in self._dict[section]: |
---|
1027 | self._dict[section][option] = False |
---|
1028 | |
---|
1029 | def __set_display_groups(self): |
---|
1030 | if not '--verbose-help' in sys.argv: |
---|
1031 | self.option_groups = self.__display_grps |
---|
1032 | self.option_list = self.__display_option_list |
---|
1033 | for group in self.option_groups: |
---|
1034 | group.option_list = self.__display_grp_lists[group.title] |
---|
1035 | |
---|
1036 | def __unset_display_groups(self): |
---|
1037 | if not '--verbose-help' in sys.argv: |
---|
1038 | self.option_groups = self.__orig_grps |
---|
1039 | self.option_list = self.__orig_option_list |
---|
1040 | for group in self.option_groups: |
---|
1041 | group.option_list = self.__orig_grp_lists[group.title] |
---|
1042 | |
---|
1043 | def print_help(self, file=None): |
---|
1044 | self.__set_display_groups() |
---|
1045 | OptionParser.print_help(self, file) |
---|
1046 | self.__unset_display_groups() |
---|
1047 | |
---|
1048 | def print_options(self): |
---|
1049 | _usage = self.usage |
---|
1050 | self.set_usage('') |
---|
1051 | self.print_help() |
---|
1052 | self.set_usage(_usage) |
---|
1053 | |
---|
1054 | def verify(self): |
---|
1055 | return baseConfig.verify(self) |
---|
1056 | |
---|
1057 | def replace_escape_seqs(self): |
---|
1058 | replace_escapes(self) |
---|