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',
43 'usual_variables':usual_variables,
44 'config_dir':"/etc/sfa",
45 'validate_variables':{},
46 'validator':validator,
57 def noop_validator(validated_variables):
60 # historically we could also configure the devel pkg....
61 def init_configuration ():
62 global g_configuration
63 global usual_variables, config_dir, service
65 usual_variables=g_configuration["usual_variables"]
66 config_dir=g_configuration["config_dir"]
67 service=g_configuration["service"]
69 global def_default_config, def_site_config, def_consolidated_config
70 def_default_config= "%s/default_config.xml" % config_dir
71 def_site_config = "%s/configs/site_config" % config_dir
72 def_consolidated_config = "%s/%s_config" % (config_dir, service)
75 mainloop_usage= """Available commands:
76 Uppercase versions give variables comments, when available
77 u/U\t\t\tEdit usual variables
79 r\t\t\tRestart %(service)s service
80 R\t\t\tReload %(service)s service (rebuild config files for sh, python....)
81 q\t\t\tQuit (without saving)
84 l/L [<cat>|<var>]\tShow Locally modified variables/values
85 s/S [<cat>|<var>]\tShow variables/values (all, in category, single)
86 e/E [<cat>|<var>]\tEdit variables (all, in category, single)
88 c\t\t\tList categories
89 v/V [<cat>|<var>]\tList Variables (all, in category, single)
91 Typical usage involves: u, [l,] w, r, q
95 command_usage="%prog [options] [default-xml [site-xml [consolidated-xml]]]"
98 \t default-xml defaults to %s
99 \t site-xml defaults to %s
100 \t consolidated-xml defaults to %s""" % (def_default_config,def_site_config, def_consolidated_config)
104 variable_usage= """Edit Commands :
105 #\tShow variable comments
106 .\tStops prompting, return to mainloop
107 /\tCleans any site-defined value, reverts to default
108 =\tShows default value
109 >\tSkips to next category
114 def get_value (config, category_id, variable_id):
115 value = config.get (category_id, variable_id)
118 def get_type (config, category_id, variable_id):
119 value = config.get (category_id, variable_id)
120 #return variable['type']
123 def get_current_value (cread, cwrite, category_id, variable_id):
124 # the value stored in cwrite, if present, is the one we want
126 result=get_value (cwrite,category_id,variable_id)
128 result=get_value (cread,category_id,variable_id)
131 # refrain from using plc_config's _sanitize
132 def get_varname (config, category_id, variable_id):
133 varname = category_id +"_"+ variable_id
134 config.locate_varname(varname)
137 # could not avoid using _sanitize here..
138 def get_name_comments (config, cid, vid):
140 (category, variable) = config.get (cid, vid)
141 (id, name, value, comments) = config._sanitize_variable (cid,variable)
142 return (name,comments)
146 def print_name_comments (config, cid, vid):
147 (name,comments)=get_name_comments(config,cid,vid)
149 print "### %s" % name
151 for line in comments:
154 print "!!! No comment associated to %s_%s" % (cid,vid)
157 def list_categories (config):
159 for section in config.sections():
163 def print_categories (config):
164 print "Known categories"
165 for cid in list_categories(config):
166 print "%s" % (cid.upper())
169 def list_category (config, cid):
171 for section in config.sections():
172 if section == cid.lower():
173 for (name,value) in config.items(section):
174 result += ["%s_%s" %(cid,name)]
177 def print_category (config, cid, show_comments=True):
180 vids=list_category(config,cid)
182 print "%s : no such category"%CID
184 print "Category %s contains" %(CID)
189 def consolidate (default_config, site_config, consolidated_config):
192 conso = Config(default_config)
193 conso.load (site_config)
194 conso.save (consolidated_config)
195 except Exception, inst:
196 print "Could not consolidate, %s" % (str(inst))
198 print ("Merged\n\t%s\nand\t%s\ninto\t%s"%(default_config,site_config,
199 consolidated_config))
201 def reload_service ():
203 os.system("set -x ; service %s reload" % service)
206 def restart_service ():
208 print ("==================== Stopping %s" % service)
209 os.system("service %s stop" % service)
210 print ("==================== Starting %s" % service)
211 os.system("service %s start" % service)
214 def prompt_variable (cdef, cread, cwrite, category, variable,
215 show_comments, support_next=False):
218 category_id = category
219 variable_id = variable
222 default_value = get_value(cdef,category_id,variable_id)
223 variable_type = get_type(cdef,category_id,variable_id)
224 current_value = get_current_value(cread,cwrite,category_id, variable_id)
225 varname = get_varname (cread,category_id, variable_id)
228 print_name_comments (cdef, category_id, variable_id)
229 prompt = "== %s : [%s] " % (varname,current_value)
231 answer = raw_input(prompt).strip()
233 raise Exception ('BailOut')
234 except KeyboardInterrupt:
236 raise Exception ('BailOut')
239 if (answer == "") or (answer == current_value):
241 elif (answer == "."):
242 raise Exception ('BailOut')
243 elif (answer == "#"):
244 print_name_comments(cread,category_id,variable_id)
245 elif (answer == "?"):
246 print variable_usage.strip()
247 elif (answer == "="):
248 print ("%s defaults to %s" %(varname,default_value))
249 # revert to default : remove from cwrite (i.e. site-config)
250 elif (answer == "/"):
251 cwrite.delete(category_id,variable_id)
252 print ("%s reverted to %s" %(varname,default_value))
254 elif (answer == ">"):
256 raise Exception ('NextCategory')
258 print "No support for next category"
260 if cdef.validate_type(variable_type, answer):
261 cwrite.set(category_id, variable_id, answer)
264 print "Not a valid value"
266 def prompt_variables_all (cdef, cread, cwrite, show_comments):
268 for (category_id, (category, variables)) in cread.variables().iteritems():
269 print ("========== Category = %s" % category_id.upper())
270 for variable in variables.values():
272 newvar = prompt_variable (cdef, cread, cwrite, category, variable,
274 except Exception, inst:
275 if (str(inst) == 'NextCategory'): break
278 except Exception, inst:
279 if (str(inst) == 'BailOut'): return
282 def prompt_variables_category (cdef, cread, cwrite, cid, show_comments):
286 print ("========== Category = %s" % CID)
287 for vid in list_category(cdef,cid):
288 (category,variable) = cdef.locate_varname(vid.upper())
289 newvar = prompt_variable (cdef, cread, cwrite, category, variable,
290 show_comments, False)
291 except Exception, inst:
292 if (str(inst) == 'BailOut'): return
296 def show_variable (cdef, cread, cwrite,
297 category, variable,show_value,show_comments):
298 assert category.has_key('id')
299 assert variable.has_key('id')
301 category_id = category ['id']
302 variable_id = variable['id']
304 default_value = get_value(cdef,category_id,variable_id)
305 current_value = get_current_value(cread,cwrite,category_id,variable_id)
306 varname = get_varname (cread,category_id, variable_id)
308 print_name_comments (cdef, category_id, variable_id)
310 print "%s = %s" % (varname,current_value)
312 print "%s" % (varname)
314 def show_variables_all (cdef, cread, cwrite, show_value, show_comments):
315 for (category_id, (category, variables)) in cread.variables().iteritems():
316 print ("========== Category = %s" % category_id.upper())
317 for variable in variables.values():
318 show_variable (cdef, cread, cwrite,
319 category, variable,show_value,show_comments)
321 def show_variables_category (cdef, cread, cwrite, cid, show_value,show_comments):
324 print ("========== Category = %s" % CID)
325 for vid in list_category(cdef,cid):
326 (category,variable) = cdef.locate_varname(vid.upper())
327 show_variable (cdef, cread, cwrite, category, variable,
328 show_value,show_comments)
331 re_mainloop_0arg="^(?P<command>[uUwrRqlLsSeEcvVhH\?])[ \t]*$"
332 re_mainloop_1arg="^(?P<command>[sSeEvV])[ \t]+(?P<arg>\w+)$"
333 matcher_mainloop_0arg=re.compile(re_mainloop_0arg)
334 matcher_mainloop_1arg=re.compile(re_mainloop_1arg)
336 def mainloop (cdef, cread, cwrite, default_config, site_config, consolidated_config):
340 answer = raw_input("Enter command (u for usual changes, w to save, ? for help) ").strip()
343 except KeyboardInterrupt:
347 if (answer == "") or (answer in "?hH"):
350 groups_parse = matcher_mainloop_0arg.match(answer)
353 command = groups_parse.group('command')
356 groups_parse = matcher_mainloop_1arg.match(answer)
358 command = groups_parse.group('command')
359 arg=groups_parse.group('arg')
361 print ("Unknown command >%s< -- use h for help" % answer)
364 show_comments=command.isupper()
370 variables=list_category (cdef,arg)
372 # category_id as the category name
373 # variables as the list of variable names
377 (category,variable)=cdef.locate_varname(arg)
379 # category/variable as output by locate_varname
382 print "%s: no such category or variable" % arg
386 # todo check confirmation
390 # Confirm that various constraints are met before saving file.
391 validate_variables = g_configuration.get('validate_variables',{})
392 validated_variables = cwrite.verify(cdef, cread, validate_variables)
393 validator = g_configuration.get('validator',noop_validator)
394 validator(validated_variables)
395 cwrite.save(site_config)
397 print "Save failed due to a configuration exception:"
398 print traceback.print_exc()
399 print ("Could not save -- fix write access on %s" % site_config)
401 print ("Wrote %s" % site_config)
402 consolidate(default_config, site_config, consolidated_config)
403 print ("You might want to type 'r' (restart %s), 'R' (reload %s) or 'q' (quit)" % \
405 elif command in "uU":
406 global usual_variables
407 global flavour_xml_section_hash
409 for varname in usual_variables:
410 (category,variable) = cdef.locate_varname(varname)
411 if not (category is None and variable is None):
412 prompt_variable(cdef, cread, cwrite, category, variable, False)
414 # set the driver variable according to the already set flavour
415 generic_flavour = cwrite.items('sfa')[0][1]
416 for section in cdef.sections():
417 if generic_flavour in flavour_xml_section_hash and flavour_xml_section_hash[generic_flavour] == section:
418 for item in cdef.items(section):
421 prompt_variable(cdef, cread, cwrite, category, variable, False)
424 except Exception, inst:
425 if (str(inst) != 'BailOut'):
432 print_categories(cread)
433 elif command in "eE":
435 prompt_variables_all(cdef, cread, cwrite,show_comments)
436 elif mode == 'CATEGORY':
437 prompt_variables_category(cdef,cread,cwrite,category_id,show_comments)
438 elif mode == 'VARIABLE':
440 prompt_variable (cdef,cread,cwrite,category,variable,
442 except Exception, inst:
443 if str(inst) != 'BailOut':
445 elif command in "vVsSlL":
446 show_value=(command in "sSlL")
447 (c1,c2,c3) = (cdef, cread, cwrite)
449 (c1,c2,c3) = (cwrite,cwrite,cwrite)
451 show_variables_all(c1,c2,c3,show_value,show_comments)
452 elif mode == 'CATEGORY':
453 show_variables_category(c1,c2,c3,category_id,show_value,show_comments)
454 elif mode == 'VARIABLE':
455 show_variable (c1,c2,c3,category,variable,show_value,show_comments)
457 print ("Unknown command >%s< -- use h for help" % answer)
461 # creates directory for file if not yet existing
462 def check_dir (config_file):
463 dirname = os.path.dirname (config_file)
464 if (not os.path.exists (dirname)):
466 os.makedirs(dirname,0755)
468 print "Cannot create dir %s due to %s - exiting" % (dirname,e)
471 if (not os.path.exists (dirname)):
472 print "Cannot create dir %s - exiting" % dirname
475 print "Created directory %s" % dirname
478 def optParserSetup(configuration):
479 parser = OptionParser(usage=usage(), version="%prog " + version_tag )
480 parser.set_defaults(config_dir=configuration['config_dir'],
481 service=configuration['service'],
482 usual_variables=configuration['usual_variables'])
483 parser.add_option("","--configdir",dest="config_dir",help="specify configuration directory")
484 parser.add_option("","--service",dest="service",help="specify /etc/init.d style service name")
485 parser.add_option("","--usual_variable",dest="usual_variables",action="append", help="add a usual variable")
488 def main(command,argv,configuration):
489 global g_configuration
490 g_configuration=configuration
492 parser = optParserSetup(configuration)
493 (config,args) = parser.parse_args()
495 parser.error("too many arguments")
497 configuration['service']=config.service
498 configuration['usual_variables']=config.usual_variables
499 configuration['config_dir']=config.config_dir
500 # add in new usual_variables defined on the command line
501 for usual_variable in config.usual_variables:
502 if usual_variable not in configuration['usual_variables']:
503 configuration['usual_variables'].append(usual_variable)
505 # intialize configuration
508 (default_config,site_config,consolidated_config) = (def_default_config, def_site_config, def_consolidated_config)
510 default_config=args[0]
514 consolidated_config=args[2]
516 for c in (default_config,site_config,consolidated_config):
520 # the default settings only - read only
521 cdef = Config(default_config)
523 # in effect : default settings + local settings - read only
524 cread = Config(default_config)
526 print traceback.print_exc()
527 print ("default config files %s not found, is myplc installed ?" % default_config)
530 # local settings only, will be modified & saved
531 config_filename = "%s/sfa_config" % config.config_dir
532 cwrite=Config(config_filename)
534 cread.load(site_config)
535 cwrite.load(default_config)
536 cwrite.load(site_config)
540 mainloop (cdef, cread, cwrite, default_config, site_config, consolidated_config)
543 if __name__ == '__main__':
546 main(command,argv,configuration)