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
17 def validator(validated_variables):
19 # maint_user = validated_variables["PLC_API_MAINTENANCE_USER"]
20 # root_user = validated_variables["PLC_ROOT_USER"]
21 # if maint_user == root_user:
22 # errStr="PLC_API_MAINTENANCE_USER=%s cannot be the same as PLC_ROOT_USER=%s"%(maint_user, root_user)
23 # raise plc_config.ConfigurationException(errStr)
26 "SFA_GENERIC_FLAVOUR",
28 "SFA_REGISTRY_ROOT_AUTH",
34 flavour_xml_section_hash = {
41 'usual_variables': usual_variables,
42 'config_dir': "/etc/sfa",
43 'validate_variables': {},
44 'validator': validator,
50 g_configuration = None
51 usual_variables = None
56 def noop_validator(validated_variables):
59 # 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
97 command_usage = "%prog [options] [default-xml [site-xml [consolidated-xml]]]"
100 \t default-xml defaults to %s
101 \t site-xml defaults to %s
102 \t consolidated-xml defaults to %s""" % (def_default_config, def_site_config, def_consolidated_config)
106 variable_usage = """Edit Commands :
107 #\tShow variable comments
108 .\tStops prompting, return to mainloop
109 /\tCleans any site-defined value, reverts to default
110 =\tShows default value
111 >\tSkips to next category
118 def get_value(config, category_id, variable_id):
119 value = config.get(category_id, variable_id)
123 def get_type(config, category_id, variable_id):
124 value = config.get(category_id, variable_id)
125 # return variable['type']
129 def get_current_value(cread, cwrite, category_id, variable_id):
130 # the value stored in cwrite, if present, is the one we want
132 result = get_value(cwrite, category_id, variable_id)
134 result = get_value(cread, category_id, variable_id)
137 # refrain from using plc_config's _sanitize
140 def get_varname(config, category_id, variable_id):
141 varname = category_id + "_" + variable_id
142 config.locate_varname(varname)
145 # could not avoid using _sanitize here..
148 def get_name_comments(config, cid, vid):
150 (category, variable) = config.get(cid, vid)
151 (id, name, value, comments) = config._sanitize_variable(cid, variable)
152 return (name, comments)
157 def print_name_comments(config, cid, vid):
158 name, comments = get_name_comments(config, cid, vid)
160 print "### %s" % name
162 for line in comments:
165 print "!!! No comment associated to %s_%s" % (cid, vid)
170 def list_categories(config):
172 for section in config.sections():
177 def print_categories(config):
178 print "Known categories"
179 for cid in list_categories(config):
180 print "%s" % (cid.upper())
185 def list_category(config, cid):
187 for section in config.sections():
188 if section == cid.lower():
189 for (name, value) in config.items(section):
190 result += ["%s_%s" % (cid, name)]
194 def print_category(config, cid, show_comments=True):
197 vids = list_category(config, cid)
199 print "%s : no such category" % CID
201 print "Category %s contains" % (CID)
208 def consolidate(default_config, site_config, consolidated_config):
211 conso = Config(default_config)
212 conso.load(site_config)
213 conso.save(consolidated_config)
214 except Exception, inst:
215 print "Could not consolidate, %s" % (str(inst))
217 print("Merged\n\t%s\nand\t%s\ninto\t%s" % (default_config, site_config,
218 consolidated_config))
221 def reload_service():
222 reload = "sfa-setup.sh reload"
223 print("Running: {}".format(reload))
229 def restart_service():
230 services = ('sfa-db', 'sfa-aggregate', 'sfa-registry')
231 for service in services:
232 restart = ("systemctl -q is-active {s} && "
233 "{{ echo restarting {s} ; systemctl restart {s}; }}"
240 def prompt_variable(cdef, cread, cwrite, category, variable,
241 show_comments, support_next=False):
243 category_id = category
244 variable_id = variable
247 default_value = get_value(cdef, category_id, variable_id)
248 variable_type = get_type(cdef, category_id, variable_id)
249 current_value = get_current_value(
250 cread, cwrite, category_id, variable_id)
251 varname = get_varname(cread, category_id, variable_id)
254 print_name_comments(cdef, category_id, variable_id)
255 prompt = "== %s : [%s] " % (varname, current_value)
257 answer = raw_input(prompt).strip()
259 raise Exception('BailOut')
260 except KeyboardInterrupt:
262 raise Exception('BailOut')
265 if (answer == "") or (answer == current_value):
267 elif (answer == "."):
268 raise Exception('BailOut')
269 elif (answer == "#"):
270 print_name_comments(cread, category_id, variable_id)
271 elif (answer == "?"):
272 print variable_usage.strip()
273 elif (answer == "="):
274 print("%s defaults to %s" % (varname, default_value))
275 # revert to default : remove from cwrite (i.e. site-config)
276 elif (answer == "/"):
277 cwrite.delete(category_id, variable_id)
278 print("%s reverted to %s" % (varname, default_value))
280 elif (answer == ">"):
282 raise Exception('NextCategory')
284 print "No support for next category"
286 if cdef.validate_type(variable_type, answer):
287 cwrite.set(category_id, variable_id, answer)
290 print "Not a valid value"
293 def prompt_variables_all(cdef, cread, cwrite, show_comments):
295 for (category_id, (category, variables)) in cread.variables().iteritems():
296 print("========== Category = %s" % category_id.upper())
297 for variable in variables.values():
299 newvar = prompt_variable(cdef, cread, cwrite, category, variable,
301 except Exception, inst:
302 if (str(inst) == 'NextCategory'):
307 except Exception, inst:
308 if (str(inst) == 'BailOut'):
314 def prompt_variables_category(cdef, cread, cwrite, cid, show_comments):
318 print("========== Category = %s" % CID)
319 for vid in list_category(cdef, cid):
320 (category, variable) = cdef.locate_varname(vid.upper())
321 newvar = prompt_variable(cdef, cread, cwrite, category, variable,
322 show_comments, False)
323 except Exception, inst:
324 if (str(inst) == 'BailOut'):
332 def show_variable(cdef, cread, cwrite,
333 category, variable, show_value, show_comments):
334 assert category.has_key('id')
335 assert variable.has_key('id')
337 category_id = category['id']
338 variable_id = variable['id']
340 default_value = get_value(cdef, category_id, variable_id)
341 current_value = get_current_value(cread, cwrite, category_id, variable_id)
342 varname = get_varname(cread, category_id, variable_id)
344 print_name_comments(cdef, category_id, variable_id)
346 print "%s = %s" % (varname, current_value)
348 print "%s" % (varname)
351 def show_variables_all(cdef, cread, cwrite, show_value, show_comments):
352 for (category_id, (category, variables)) in cread.variables().iteritems():
353 print("========== Category = %s" % category_id.upper())
354 for variable in variables.values():
355 show_variable(cdef, cread, cwrite,
356 category, variable, show_value, show_comments)
359 def show_variables_category(cdef, cread, cwrite, cid, show_value, show_comments):
362 print("========== Category = %s" % CID)
363 for vid in list_category(cdef, cid):
364 (category, variable) = cdef.locate_varname(vid.upper())
365 show_variable(cdef, cread, cwrite, category, variable,
366 show_value, show_comments)
369 re_mainloop_0arg = "^(?P<command>[uUwrRqlLsSeEcvVhH\?])[ \t]*$"
370 re_mainloop_1arg = "^(?P<command>[sSeEvV])[ \t]+(?P<arg>\w+)$"
371 matcher_mainloop_0arg = re.compile(re_mainloop_0arg)
372 matcher_mainloop_1arg = re.compile(re_mainloop_1arg)
375 def mainloop(cdef, cread, cwrite, default_config, site_config, consolidated_config):
380 "Enter command (u for usual changes, w to save, ? for help) ").strip()
383 except KeyboardInterrupt:
387 if (answer == "") or (answer in "?hH"):
390 groups_parse = matcher_mainloop_0arg.match(answer)
393 command = groups_parse.group('command')
396 groups_parse = matcher_mainloop_1arg.match(answer)
398 command = groups_parse.group('command')
399 arg = groups_parse.group('arg')
401 print("Unknown command >%s< -- use h for help" % answer)
404 show_comments = command.isupper()
410 variables = list_category(cdef, arg)
412 # category_id as the category name
413 # variables as the list of variable names
417 (category, variable) = cdef.locate_varname(arg)
419 # category/variable as output by locate_varname
422 print "%s: no such category or variable" % arg
426 # todo check confirmation
430 # Confirm that various constraints are met before saving file.
431 validate_variables = g_configuration.get(
432 'validate_variables', {})
433 validated_variables = cwrite.verify(
434 cdef, cread, validate_variables)
435 validator = g_configuration.get('validator', noop_validator)
436 validator(validated_variables)
437 cwrite.save(site_config)
439 print "Save failed due to a configuration exception:"
440 print traceback.print_exc()
441 print("Could not save -- fix write access on %s" % site_config)
443 print("Wrote %s" % site_config)
444 consolidate(default_config, site_config, consolidated_config)
445 print("You might want to type 'r' (restart %s), 'R' (reload %s) or 'q' (quit)" %
447 elif command in "uU":
448 global usual_variables
449 global flavour_xml_section_hash
451 for varname in usual_variables:
452 (category, variable) = cdef.locate_varname(varname)
453 if not (category is None and variable is None):
454 prompt_variable(cdef, cread, cwrite,
455 category, variable, False)
457 # set the driver variable according to the already set flavour
458 generic_flavour = cwrite.items('sfa')[0][1]
459 for section in cdef.sections():
460 if generic_flavour in flavour_xml_section_hash and flavour_xml_section_hash[generic_flavour] == section:
461 for item in cdef.items(section):
464 prompt_variable(cdef, cread, cwrite,
465 category, variable, False)
468 except Exception, inst:
469 if (str(inst) != 'BailOut'):
476 print_categories(cread)
477 elif command in "eE":
479 prompt_variables_all(cdef, cread, cwrite, show_comments)
480 elif mode == 'CATEGORY':
481 prompt_variables_category(
482 cdef, cread, cwrite, category_id, show_comments)
483 elif mode == 'VARIABLE':
485 prompt_variable(cdef, cread, cwrite, category, variable,
486 show_comments, False)
487 except Exception, inst:
488 if str(inst) != 'BailOut':
490 elif command in "vVsSlL":
491 show_value = (command in "sSlL")
492 (c1, c2, c3) = (cdef, cread, cwrite)
494 (c1, c2, c3) = (cwrite, cwrite, cwrite)
496 show_variables_all(c1, c2, c3, show_value, show_comments)
497 elif mode == 'CATEGORY':
498 show_variables_category(
499 c1, c2, c3, category_id, show_value, show_comments)
500 elif mode == 'VARIABLE':
501 show_variable(c1, c2, c3, category, variable,
502 show_value, show_comments)
504 print("Unknown command >%s< -- use h for help" % answer)
508 # creates directory for file if not yet existing
509 def check_dir(config_file):
510 dirname = os.path.dirname(config_file)
511 if (not os.path.exists(dirname)):
513 os.makedirs(dirname, 0755)
515 print "Cannot create dir %s due to %s - exiting" % (dirname, e)
518 if (not os.path.exists(dirname)):
519 print "Cannot create dir %s - exiting" % dirname
522 print "Created directory %s" % dirname
527 def optParserSetup(configuration):
528 parser = OptionParser(usage=usage(), version="%prog " + version_tag)
529 parser.set_defaults(config_dir=configuration['config_dir'],
530 service=configuration['service'],
531 usual_variables=configuration['usual_variables'])
532 parser.add_option("", "--configdir", dest="config_dir",
533 help="specify configuration directory")
534 parser.add_option("", "--service", dest="service",
535 help="specify /etc/init.d style service name")
536 parser.add_option("", "--usual_variable", dest="usual_variables",
537 action="append", help="add a usual variable")
541 def main(command, argv, configuration):
542 global g_configuration
543 g_configuration = configuration
545 parser = optParserSetup(configuration)
546 (config, args) = parser.parse_args()
548 parser.error("too many arguments")
550 configuration['service'] = config.service
551 configuration['usual_variables'] = config.usual_variables
552 configuration['config_dir'] = config.config_dir
553 # add in new usual_variables defined on the command line
554 for usual_variable in config.usual_variables:
555 if usual_variable not in configuration['usual_variables']:
556 configuration['usual_variables'].append(usual_variable)
558 # intialize configuration
561 default_config, site_config, consolidated_config = \
562 def_default_config, def_site_config, def_consolidated_config
564 default_config = args[0]
566 site_config = args[1]
568 consolidated_config = args[2]
570 for c in (default_config, site_config, consolidated_config):
574 # the default settings only - read only
575 cdef = Config(default_config)
577 # in effect : default settings + local settings - read only
578 cread = Config(default_config)
580 print traceback.print_exc()
581 print("default config files %s not found, is myplc installed ?" %
585 # local settings only, will be modified & saved
586 config_filename = "%s/sfa_config" % config.config_dir
587 cwrite = Config(config_filename)
589 cread.load(site_config)
590 cwrite.load(default_config)
591 cwrite.load(site_config)
595 mainloop(cdef, cread, cwrite, default_config,
596 site_config, consolidated_config)
599 if __name__ == '__main__':
600 command = sys.argv[0]
602 main(command, argv, configuration)