10 from StringIO import StringIO
11 from optparse import OptionParser
13 from sfa.util.version import version_tag
14 from sfa.util.config import Config
16 def validator(validated_variables):
18 # maint_user = validated_variables["PLC_API_MAINTENANCE_USER"]
19 # root_user = validated_variables["PLC_ROOT_USER"]
20 # if maint_user == root_user:
21 # errStr="PLC_API_MAINTENANCE_USER=%s cannot be the same as PLC_ROOT_USER=%s"%(maint_user,root_user)
22 # raise plc_config.ConfigurationException(errStr)
25 "SFA_GENERIC_FLAVOUR",
27 "SFA_REGISTRY_ROOT_AUTH",
34 flavour_xml_section_hash = { \
36 'openstack':'sfa_nova',
44 'usual_variables':usual_variables,
45 'config_dir':"/etc/sfa",
46 'validate_variables':{},
47 'validator':validator,
58 def noop_validator(validated_variables):
61 # historically we could also configure the devel pkg....
62 def init_configuration ():
63 global g_configuration
64 global usual_variables, config_dir, service
66 usual_variables=g_configuration["usual_variables"]
67 config_dir=g_configuration["config_dir"]
68 service=g_configuration["service"]
70 global def_default_config, def_site_config, def_consolidated_config
71 def_default_config= "%s/default_config.xml" % config_dir
72 def_site_config = "%s/configs/site_config" % config_dir
73 def_consolidated_config = "%s/%s_config" % (config_dir, service)
76 mainloop_usage= """Available commands:
77 Uppercase versions give variables comments, when available
78 u/U\t\t\tEdit usual variables
80 r\t\t\tRestart %(service)s service
81 R\t\t\tReload %(service)s service (rebuild config files for sh, python....)
82 q\t\t\tQuit (without saving)
85 l/L [<cat>|<var>]\tShow Locally modified variables/values
86 s/S [<cat>|<var>]\tShow variables/values (all, in category, single)
87 e/E [<cat>|<var>]\tEdit variables (all, in category, single)
89 c\t\t\tList categories
90 v/V [<cat>|<var>]\tList Variables (all, in category, single)
92 Typical usage involves: u, [l,] w, r, q
96 command_usage="%prog [options] [default-xml [site-xml [consolidated-xml]]]"
99 \t default-xml defaults to %s
100 \t site-xml defaults to %s
101 \t consolidated-xml defaults to %s""" % (def_default_config,def_site_config, def_consolidated_config)
105 variable_usage= """Edit Commands :
106 #\tShow variable comments
107 .\tStops prompting, return to mainloop
108 /\tCleans any site-defined value, reverts to default
109 =\tShows default value
110 >\tSkips to next category
115 def get_value (config, category_id, variable_id):
116 value = config.get (category_id, variable_id)
119 def get_type (config, category_id, variable_id):
120 value = config.get (category_id, variable_id)
121 #return variable['type']
124 def get_current_value (cread, cwrite, category_id, variable_id):
125 # the value stored in cwrite, if present, is the one we want
127 result=get_value (cwrite,category_id,variable_id)
129 result=get_value (cread,category_id,variable_id)
132 # refrain from using plc_config's _sanitize
133 def get_varname (config, category_id, variable_id):
134 varname = category_id +"_"+ variable_id
135 config.locate_varname(varname)
138 # could not avoid using _sanitize here..
139 def get_name_comments (config, cid, vid):
141 (category, variable) = config.get (cid, vid)
142 (id, name, value, comments) = config._sanitize_variable (cid,variable)
143 return (name,comments)
147 def print_name_comments (config, cid, vid):
148 (name,comments)=get_name_comments(config,cid,vid)
150 print "### %s" % name
152 for line in comments:
155 print "!!! No comment associated to %s_%s" % (cid,vid)
158 def list_categories (config):
160 for section in config.sections():
164 def print_categories (config):
165 print "Known categories"
166 for cid in list_categories(config):
167 print "%s" % (cid.upper())
170 def list_category (config, cid):
172 for section in config.sections():
173 if section == cid.lower():
174 for (name,value) in config.items(section):
175 result += ["%s_%s" %(cid,name)]
178 def print_category (config, cid, show_comments=True):
181 vids=list_category(config,cid)
183 print "%s : no such category"%CID
185 print "Category %s contains" %(CID)
190 def consolidate (default_config, site_config, consolidated_config):
193 conso = Config(default_config)
194 conso.load (site_config)
195 conso.save (consolidated_config)
196 except Exception, inst:
197 print "Could not consolidate, %s" % (str(inst))
199 print ("Merged\n\t%s\nand\t%s\ninto\t%s"%(default_config,site_config,
200 consolidated_config))
202 def reload_service ():
204 os.system("set -x ; service %s reload" % service)
207 def restart_service ():
209 print ("==================== Stopping %s" % service)
210 os.system("service %s stop" % service)
211 print ("==================== Starting %s" % service)
212 os.system("service %s start" % service)
215 def prompt_variable (cdef, cread, cwrite, category, variable,
216 show_comments, support_next=False):
219 category_id = category
220 variable_id = variable
223 default_value = get_value(cdef,category_id,variable_id)
224 variable_type = get_type(cdef,category_id,variable_id)
225 current_value = get_current_value(cread,cwrite,category_id, variable_id)
226 varname = get_varname (cread,category_id, variable_id)
229 print_name_comments (cdef, category_id, variable_id)
230 prompt = "== %s : [%s] " % (varname,current_value)
232 answer = raw_input(prompt).strip()
234 raise Exception ('BailOut')
235 except KeyboardInterrupt:
237 raise Exception ('BailOut')
240 if (answer == "") or (answer == current_value):
242 elif (answer == "."):
243 raise Exception ('BailOut')
244 elif (answer == "#"):
245 print_name_comments(cread,category_id,variable_id)
246 elif (answer == "?"):
247 print variable_usage.strip()
248 elif (answer == "="):
249 print ("%s defaults to %s" %(varname,default_value))
250 # revert to default : remove from cwrite (i.e. site-config)
251 elif (answer == "/"):
252 cwrite.delete(category_id,variable_id)
253 print ("%s reverted to %s" %(varname,default_value))
255 elif (answer == ">"):
257 raise Exception ('NextCategory')
259 print "No support for next category"
261 if cdef.validate_type(variable_type, answer):
262 cwrite.set(category_id, variable_id, answer)
265 print "Not a valid value"
267 def prompt_variables_all (cdef, cread, cwrite, show_comments):
269 for (category_id, (category, variables)) in cread.variables().iteritems():
270 print ("========== Category = %s" % category_id.upper())
271 for variable in variables.values():
273 newvar = prompt_variable (cdef, cread, cwrite, category, variable,
275 except Exception, inst:
276 if (str(inst) == 'NextCategory'): break
279 except Exception, inst:
280 if (str(inst) == 'BailOut'): return
283 def prompt_variables_category (cdef, cread, cwrite, cid, show_comments):
287 print ("========== Category = %s" % CID)
288 for vid in list_category(cdef,cid):
289 (category,variable) = cdef.locate_varname(vid.upper())
290 newvar = prompt_variable (cdef, cread, cwrite, category, variable,
291 show_comments, False)
292 except Exception, inst:
293 if (str(inst) == 'BailOut'): return
297 def show_variable (cdef, cread, cwrite,
298 category, variable,show_value,show_comments):
299 assert category.has_key('id')
300 assert variable.has_key('id')
302 category_id = category ['id']
303 variable_id = variable['id']
305 default_value = get_value(cdef,category_id,variable_id)
306 current_value = get_current_value(cread,cwrite,category_id,variable_id)
307 varname = get_varname (cread,category_id, variable_id)
309 print_name_comments (cdef, category_id, variable_id)
311 print "%s = %s" % (varname,current_value)
313 print "%s" % (varname)
315 def show_variables_all (cdef, cread, cwrite, show_value, show_comments):
316 for (category_id, (category, variables)) in cread.variables().iteritems():
317 print ("========== Category = %s" % category_id.upper())
318 for variable in variables.values():
319 show_variable (cdef, cread, cwrite,
320 category, variable,show_value,show_comments)
322 def show_variables_category (cdef, cread, cwrite, cid, show_value,show_comments):
325 print ("========== Category = %s" % CID)
326 for vid in list_category(cdef,cid):
327 (category,variable) = cdef.locate_varname(vid.upper())
328 show_variable (cdef, cread, cwrite, category, variable,
329 show_value,show_comments)
332 re_mainloop_0arg="^(?P<command>[uUwrRqlLsSeEcvVhH\?])[ \t]*$"
333 re_mainloop_1arg="^(?P<command>[sSeEvV])[ \t]+(?P<arg>\w+)$"
334 matcher_mainloop_0arg=re.compile(re_mainloop_0arg)
335 matcher_mainloop_1arg=re.compile(re_mainloop_1arg)
337 def mainloop (cdef, cread, cwrite, default_config, site_config, consolidated_config):
341 answer = raw_input("Enter command (u for usual changes, w to save, ? for help) ").strip()
344 except KeyboardInterrupt:
348 if (answer == "") or (answer in "?hH"):
351 groups_parse = matcher_mainloop_0arg.match(answer)
354 command = groups_parse.group('command')
357 groups_parse = matcher_mainloop_1arg.match(answer)
359 command = groups_parse.group('command')
360 arg=groups_parse.group('arg')
362 print ("Unknown command >%s< -- use h for help" % answer)
365 show_comments=command.isupper()
371 variables=list_category (cdef,arg)
373 # category_id as the category name
374 # variables as the list of variable names
378 (category,variable)=cdef.locate_varname(arg)
380 # category/variable as output by locate_varname
383 print "%s: no such category or variable" % arg
387 # todo check confirmation
391 # Confirm that various constraints are met before saving file.
392 validate_variables = g_configuration.get('validate_variables',{})
393 validated_variables = cwrite.verify(cdef, cread, validate_variables)
394 validator = g_configuration.get('validator',noop_validator)
395 validator(validated_variables)
396 cwrite.save(site_config)
398 print "Save failed due to a configuration exception:"
399 print traceback.print_exc()
400 print ("Could not save -- fix write access on %s" % site_config)
402 print ("Wrote %s" % site_config)
403 consolidate(default_config, site_config, consolidated_config)
404 print ("You might want to type 'r' (restart %s), 'R' (reload %s) or 'q' (quit)" % \
406 elif command in "uU":
407 global usual_variables
408 global flavour_xml_section_hash
410 for varname in usual_variables:
411 (category,variable) = cdef.locate_varname(varname)
412 if not (category is None and variable is None):
413 prompt_variable(cdef, cread, cwrite, category, variable, False)
415 # set the driver variable according to the already set flavour
416 generic_flavour = cwrite.items('sfa')[0][1]
417 for section in cdef.sections():
418 if generic_flavour in flavour_xml_section_hash and flavour_xml_section_hash[generic_flavour] == section:
419 for item in cdef.items(section):
422 prompt_variable(cdef, cread, cwrite, category, variable, False)
425 except Exception, inst:
426 if (str(inst) != 'BailOut'):
433 print_categories(cread)
434 elif command in "eE":
436 prompt_variables_all(cdef, cread, cwrite,show_comments)
437 elif mode == 'CATEGORY':
438 prompt_variables_category(cdef,cread,cwrite,category_id,show_comments)
439 elif mode == 'VARIABLE':
441 prompt_variable (cdef,cread,cwrite,category,variable,
443 except Exception, inst:
444 if str(inst) != 'BailOut':
446 elif command in "vVsSlL":
447 show_value=(command in "sSlL")
448 (c1,c2,c3) = (cdef, cread, cwrite)
450 (c1,c2,c3) = (cwrite,cwrite,cwrite)
452 show_variables_all(c1,c2,c3,show_value,show_comments)
453 elif mode == 'CATEGORY':
454 show_variables_category(c1,c2,c3,category_id,show_value,show_comments)
455 elif mode == 'VARIABLE':
456 show_variable (c1,c2,c3,category,variable,show_value,show_comments)
458 print ("Unknown command >%s< -- use h for help" % answer)
462 # creates directory for file if not yet existing
463 def check_dir (config_file):
464 dirname = os.path.dirname (config_file)
465 if (not os.path.exists (dirname)):
467 os.makedirs(dirname,0755)
469 print "Cannot create dir %s due to %s - exiting" % (dirname,e)
472 if (not os.path.exists (dirname)):
473 print "Cannot create dir %s - exiting" % dirname
476 print "Created directory %s" % dirname
479 def optParserSetup(configuration):
480 parser = OptionParser(usage=usage(), version="%prog " + version_tag )
481 parser.set_defaults(config_dir=configuration['config_dir'],
482 service=configuration['service'],
483 usual_variables=configuration['usual_variables'])
484 parser.add_option("","--configdir",dest="config_dir",help="specify configuration directory")
485 parser.add_option("","--service",dest="service",help="specify /etc/init.d style service name")
486 parser.add_option("","--usual_variable",dest="usual_variables",action="append", help="add a usual variable")
489 def main(command,argv,configuration):
490 global g_configuration
491 g_configuration=configuration
493 parser = optParserSetup(configuration)
494 (config,args) = parser.parse_args()
496 parser.error("too many arguments")
498 configuration['service']=config.service
499 configuration['usual_variables']=config.usual_variables
500 configuration['config_dir']=config.config_dir
501 # add in new usual_variables defined on the command line
502 for usual_variable in config.usual_variables:
503 if usual_variable not in configuration['usual_variables']:
504 configuration['usual_variables'].append(usual_variable)
506 # intialize configuration
509 (default_config,site_config,consolidated_config) = (def_default_config, def_site_config, def_consolidated_config)
511 default_config=args[0]
515 consolidated_config=args[2]
517 for c in (default_config,site_config,consolidated_config):
521 # the default settings only - read only
522 cdef = Config(default_config)
524 # in effect : default settings + local settings - read only
525 cread = Config(default_config)
527 print traceback.print_exc()
528 print ("default config files %s not found, is myplc installed ?" % default_config)
531 # local settings only, will be modified & saved
532 config_filename = "%s/sfa_config" % config.config_dir
533 cwrite=Config(config_filename)
535 cread.load(site_config)
536 cwrite.load(default_config)
537 cwrite.load(site_config)
541 mainloop (cdef, cread, cwrite, default_config, site_config, consolidated_config)
544 if __name__ == '__main__':
547 main(command,argv,configuration)