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",
35 flavour_xml_section_hash = {
43 'usual_variables': usual_variables,
44 'config_dir': "/etc/sfa",
45 'validate_variables': {},
46 'validator': validator,
52 g_configuration = None
53 usual_variables = None
58 def noop_validator(validated_variables):
61 # historically we could also configure the devel pkg....
64 def init_configuration():
65 global g_configuration
66 global usual_variables, config_dir, service
68 usual_variables = g_configuration["usual_variables"]
69 config_dir = g_configuration["config_dir"]
70 service = g_configuration["service"]
72 global def_default_config, def_site_config, def_consolidated_config
73 def_default_config = "%s/default_config.xml" % config_dir
74 def_site_config = "%s/configs/site_config" % config_dir
75 def_consolidated_config = "%s/%s_config" % (config_dir, service)
78 mainloop_usage = """Available commands:
79 Uppercase versions give variables comments, when available
80 u/U\t\t\tEdit usual variables
82 r\t\t\tRestart %(service)s service
83 R\t\t\tReload %(service)s service (rebuild config files for sh, python....)
84 q\t\t\tQuit (without saving)
87 l/L [<cat>|<var>]\tShow Locally modified variables/values
88 s/S [<cat>|<var>]\tShow variables/values (all, in category, single)
89 e/E [<cat>|<var>]\tEdit variables (all, in category, single)
91 c\t\t\tList categories
92 v/V [<cat>|<var>]\tList Variables (all, in category, single)
94 Typical usage involves: u, [l,] w, r, q
99 command_usage = "%prog [options] [default-xml [site-xml [consolidated-xml]]]"
102 \t default-xml defaults to %s
103 \t site-xml defaults to %s
104 \t consolidated-xml defaults to %s""" % (def_default_config, def_site_config, def_consolidated_config)
108 variable_usage = """Edit Commands :
109 #\tShow variable comments
110 .\tStops prompting, return to mainloop
111 /\tCleans any site-defined value, reverts to default
112 =\tShows default value
113 >\tSkips to next category
120 def get_value(config, category_id, variable_id):
121 value = config.get(category_id, variable_id)
125 def get_type(config, category_id, variable_id):
126 value = config.get(category_id, variable_id)
127 # return variable['type']
131 def get_current_value(cread, cwrite, category_id, variable_id):
132 # the value stored in cwrite, if present, is the one we want
134 result = get_value(cwrite, category_id, variable_id)
136 result = get_value(cread, category_id, variable_id)
139 # refrain from using plc_config's _sanitize
142 def get_varname(config, category_id, variable_id):
143 varname = category_id + "_" + variable_id
144 config.locate_varname(varname)
147 # could not avoid using _sanitize here..
150 def get_name_comments(config, cid, vid):
152 (category, variable) = config.get(cid, vid)
153 (id, name, value, comments) = config._sanitize_variable(cid, variable)
154 return (name, comments)
159 def print_name_comments(config, cid, vid):
160 name, comments = get_name_comments(config, cid, vid)
162 print "### %s" % name
164 for line in comments:
167 print "!!! No comment associated to %s_%s" % (cid, vid)
172 def list_categories(config):
174 for section in config.sections():
179 def print_categories(config):
180 print "Known categories"
181 for cid in list_categories(config):
182 print "%s" % (cid.upper())
187 def list_category(config, cid):
189 for section in config.sections():
190 if section == cid.lower():
191 for (name, value) in config.items(section):
192 result += ["%s_%s" % (cid, name)]
196 def print_category(config, cid, show_comments=True):
199 vids = list_category(config, cid)
201 print "%s : no such category" % CID
203 print "Category %s contains" % (CID)
210 def consolidate(default_config, site_config, consolidated_config):
213 conso = Config(default_config)
214 conso.load(site_config)
215 conso.save(consolidated_config)
216 except Exception, inst:
217 print "Could not consolidate, %s" % (str(inst))
219 print("Merged\n\t%s\nand\t%s\ninto\t%s" % (default_config, site_config,
220 consolidated_config))
223 def reload_service():
224 reload = "sfa-setup.sh reload"
225 print("Running: {}".format(reload))
231 def restart_service():
232 services = ('sfa-db', 'sfa-aggregate', 'sfa-registry')
233 for service in services:
234 restart = ("systemctl -q is-active {s} && {{ echo restarting {s} ; systemctl restart {s}; }}"
241 def prompt_variable(cdef, cread, cwrite, category, variable,
242 show_comments, support_next=False):
244 category_id = category
245 variable_id = variable
248 default_value = get_value(cdef, category_id, variable_id)
249 variable_type = get_type(cdef, category_id, variable_id)
250 current_value = get_current_value(
251 cread, cwrite, category_id, variable_id)
252 varname = get_varname(cread, category_id, variable_id)
255 print_name_comments(cdef, category_id, variable_id)
256 prompt = "== %s : [%s] " % (varname, current_value)
258 answer = raw_input(prompt).strip()
260 raise Exception('BailOut')
261 except KeyboardInterrupt:
263 raise Exception('BailOut')
266 if (answer == "") or (answer == current_value):
268 elif (answer == "."):
269 raise Exception('BailOut')
270 elif (answer == "#"):
271 print_name_comments(cread, category_id, variable_id)
272 elif (answer == "?"):
273 print variable_usage.strip()
274 elif (answer == "="):
275 print("%s defaults to %s" % (varname, default_value))
276 # revert to default : remove from cwrite (i.e. site-config)
277 elif (answer == "/"):
278 cwrite.delete(category_id, variable_id)
279 print("%s reverted to %s" % (varname, default_value))
281 elif (answer == ">"):
283 raise Exception('NextCategory')
285 print "No support for next category"
287 if cdef.validate_type(variable_type, answer):
288 cwrite.set(category_id, variable_id, answer)
291 print "Not a valid value"
294 def prompt_variables_all(cdef, cread, cwrite, show_comments):
296 for (category_id, (category, variables)) in cread.variables().iteritems():
297 print("========== Category = %s" % category_id.upper())
298 for variable in variables.values():
300 newvar = prompt_variable(cdef, cread, cwrite, category, variable,
302 except Exception, inst:
303 if (str(inst) == 'NextCategory'):
308 except Exception, inst:
309 if (str(inst) == 'BailOut'):
315 def prompt_variables_category(cdef, cread, cwrite, cid, show_comments):
319 print("========== Category = %s" % CID)
320 for vid in list_category(cdef, cid):
321 (category, variable) = cdef.locate_varname(vid.upper())
322 newvar = prompt_variable(cdef, cread, cwrite, category, variable,
323 show_comments, False)
324 except Exception, inst:
325 if (str(inst) == 'BailOut'):
333 def show_variable(cdef, cread, cwrite,
334 category, variable, show_value, show_comments):
335 assert category.has_key('id')
336 assert variable.has_key('id')
338 category_id = category['id']
339 variable_id = variable['id']
341 default_value = get_value(cdef, category_id, variable_id)
342 current_value = get_current_value(cread, cwrite, category_id, variable_id)
343 varname = get_varname(cread, category_id, variable_id)
345 print_name_comments(cdef, category_id, variable_id)
347 print "%s = %s" % (varname, current_value)
349 print "%s" % (varname)
352 def show_variables_all(cdef, cread, cwrite, show_value, show_comments):
353 for (category_id, (category, variables)) in cread.variables().iteritems():
354 print("========== Category = %s" % category_id.upper())
355 for variable in variables.values():
356 show_variable(cdef, cread, cwrite,
357 category, variable, show_value, show_comments)
360 def show_variables_category(cdef, cread, cwrite, cid, show_value, show_comments):
363 print("========== Category = %s" % CID)
364 for vid in list_category(cdef, cid):
365 (category, variable) = cdef.locate_varname(vid.upper())
366 show_variable(cdef, cread, cwrite, category, variable,
367 show_value, show_comments)
370 re_mainloop_0arg = "^(?P<command>[uUwrRqlLsSeEcvVhH\?])[ \t]*$"
371 re_mainloop_1arg = "^(?P<command>[sSeEvV])[ \t]+(?P<arg>\w+)$"
372 matcher_mainloop_0arg = re.compile(re_mainloop_0arg)
373 matcher_mainloop_1arg = re.compile(re_mainloop_1arg)
376 def mainloop(cdef, cread, cwrite, default_config, site_config, consolidated_config):
381 "Enter command (u for usual changes, w to save, ? for help) ").strip()
384 except KeyboardInterrupt:
388 if (answer == "") or (answer in "?hH"):
391 groups_parse = matcher_mainloop_0arg.match(answer)
394 command = groups_parse.group('command')
397 groups_parse = matcher_mainloop_1arg.match(answer)
399 command = groups_parse.group('command')
400 arg = groups_parse.group('arg')
402 print("Unknown command >%s< -- use h for help" % answer)
405 show_comments = command.isupper()
411 variables = list_category(cdef, arg)
413 # category_id as the category name
414 # variables as the list of variable names
418 (category, variable) = cdef.locate_varname(arg)
420 # category/variable as output by locate_varname
423 print "%s: no such category or variable" % arg
427 # todo check confirmation
431 # Confirm that various constraints are met before saving file.
432 validate_variables = g_configuration.get(
433 'validate_variables', {})
434 validated_variables = cwrite.verify(
435 cdef, cread, validate_variables)
436 validator = g_configuration.get('validator', noop_validator)
437 validator(validated_variables)
438 cwrite.save(site_config)
440 print "Save failed due to a configuration exception:"
441 print traceback.print_exc()
442 print("Could not save -- fix write access on %s" % site_config)
444 print("Wrote %s" % site_config)
445 consolidate(default_config, site_config, consolidated_config)
446 print("You might want to type 'r' (restart %s), 'R' (reload %s) or 'q' (quit)" %
448 elif command in "uU":
449 global usual_variables
450 global flavour_xml_section_hash
452 for varname in usual_variables:
453 (category, variable) = cdef.locate_varname(varname)
454 if not (category is None and variable is None):
455 prompt_variable(cdef, cread, cwrite,
456 category, variable, False)
458 # set the driver variable according to the already set flavour
459 generic_flavour = cwrite.items('sfa')[0][1]
460 for section in cdef.sections():
461 if generic_flavour in flavour_xml_section_hash and flavour_xml_section_hash[generic_flavour] == section:
462 for item in cdef.items(section):
465 prompt_variable(cdef, cread, cwrite,
466 category, variable, False)
469 except Exception, inst:
470 if (str(inst) != 'BailOut'):
477 print_categories(cread)
478 elif command in "eE":
480 prompt_variables_all(cdef, cread, cwrite, show_comments)
481 elif mode == 'CATEGORY':
482 prompt_variables_category(
483 cdef, cread, cwrite, category_id, show_comments)
484 elif mode == 'VARIABLE':
486 prompt_variable(cdef, cread, cwrite, category, variable,
487 show_comments, False)
488 except Exception, inst:
489 if str(inst) != 'BailOut':
491 elif command in "vVsSlL":
492 show_value = (command in "sSlL")
493 (c1, c2, c3) = (cdef, cread, cwrite)
495 (c1, c2, c3) = (cwrite, cwrite, cwrite)
497 show_variables_all(c1, c2, c3, show_value, show_comments)
498 elif mode == 'CATEGORY':
499 show_variables_category(
500 c1, c2, c3, category_id, show_value, show_comments)
501 elif mode == 'VARIABLE':
502 show_variable(c1, c2, c3, category, variable,
503 show_value, show_comments)
505 print("Unknown command >%s< -- use h for help" % answer)
509 # creates directory for file if not yet existing
510 def check_dir(config_file):
511 dirname = os.path.dirname(config_file)
512 if (not os.path.exists(dirname)):
514 os.makedirs(dirname, 0755)
516 print "Cannot create dir %s due to %s - exiting" % (dirname, e)
519 if (not os.path.exists(dirname)):
520 print "Cannot create dir %s - exiting" % dirname
523 print "Created directory %s" % dirname
528 def optParserSetup(configuration):
529 parser = OptionParser(usage=usage(), version="%prog " + version_tag)
530 parser.set_defaults(config_dir=configuration['config_dir'],
531 service=configuration['service'],
532 usual_variables=configuration['usual_variables'])
533 parser.add_option("", "--configdir", dest="config_dir",
534 help="specify configuration directory")
535 parser.add_option("", "--service", dest="service",
536 help="specify /etc/init.d style service name")
537 parser.add_option("", "--usual_variable", dest="usual_variables",
538 action="append", help="add a usual variable")
542 def main(command, argv, configuration):
543 global g_configuration
544 g_configuration = configuration
546 parser = optParserSetup(configuration)
547 (config, args) = parser.parse_args()
549 parser.error("too many arguments")
551 configuration['service'] = config.service
552 configuration['usual_variables'] = config.usual_variables
553 configuration['config_dir'] = config.config_dir
554 # add in new usual_variables defined on the command line
555 for usual_variable in config.usual_variables:
556 if usual_variable not in configuration['usual_variables']:
557 configuration['usual_variables'].append(usual_variable)
559 # intialize configuration
562 default_config, site_config, consolidated_config = \
563 def_default_config, def_site_config, def_consolidated_config
565 default_config = args[0]
567 site_config = args[1]
569 consolidated_config = args[2]
571 for c in (default_config, site_config, consolidated_config):
575 # the default settings only - read only
576 cdef = Config(default_config)
578 # in effect : default settings + local settings - read only
579 cread = Config(default_config)
581 print traceback.print_exc()
582 print("default config files %s not found, is myplc installed ?" %
586 # local settings only, will be modified & saved
587 config_filename = "%s/sfa_config" % config.config_dir
588 cwrite = Config(config_filename)
590 cread.load(site_config)
591 cwrite.load(default_config)
592 cwrite.load(site_config)
596 mainloop(cdef, cread, cwrite, default_config,
597 site_config, consolidated_config)
600 if __name__ == '__main__':
601 command = sys.argv[0]
603 main(command, argv, configuration)