setup.py 45 KB

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