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} && {{ echo restarting {s} ; systemctl restart {s}; }}"
239 def prompt_variable(cdef, cread, cwrite, category, variable,
240 show_comments, support_next=False):
242 category_id = category
243 variable_id = variable
246 default_value = get_value(cdef, category_id, variable_id)
247 variable_type = get_type(cdef, category_id, variable_id)
248 current_value = get_current_value(
249 cread, cwrite, category_id, variable_id)
250 varname = get_varname(cread, category_id, variable_id)
253 print_name_comments(cdef, category_id, variable_id)
254 prompt = "== %s : [%s] " % (varname, current_value)
256 answer = raw_input(prompt).strip()
258 raise Exception('BailOut')
259 except KeyboardInterrupt:
261 raise Exception('BailOut')
264 if (answer == "") or (answer == current_value):
266 elif (answer == "."):
267 raise Exception('BailOut')
268 elif (answer == "#"):
269 print_name_comments(cread, category_id, variable_id)
270 elif (answer == "?"):
271 print variable_usage.strip()
272 elif (answer == "="):
273 print("%s defaults to %s" % (varname, default_value))
274 # revert to default : remove from cwrite (i.e. site-config)
275 elif (answer == "/"):
276 cwrite.delete(category_id, variable_id)
277 print("%s reverted to %s" % (varname, default_value))
279 elif (answer == ">"):
281 raise Exception('NextCategory')
283 print "No support for next category"
285 if cdef.validate_type(variable_type, answer):
286 cwrite.set(category_id, variable_id, answer)
289 print "Not a valid value"
292 def prompt_variables_all(cdef, cread, cwrite, show_comments):
294 for (category_id, (category, variables)) in cread.variables().iteritems():
295 print("========== Category = %s" % category_id.upper())
296 for variable in variables.values():
298 newvar = prompt_variable(cdef, cread, cwrite, category, variable,
300 except Exception, inst:
301 if (str(inst) == 'NextCategory'):
306 except Exception, inst:
307 if (str(inst) == 'BailOut'):
313 def prompt_variables_category(cdef, cread, cwrite, cid, show_comments):
317 print("========== Category = %s" % CID)
318 for vid in list_category(cdef, cid):
319 (category, variable) = cdef.locate_varname(vid.upper())
320 newvar = prompt_variable(cdef, cread, cwrite, category, variable,
321 show_comments, False)
322 except Exception, inst:
323 if (str(inst) == 'BailOut'):
331 def show_variable(cdef, cread, cwrite,
332 category, variable, show_value, show_comments):
333 assert category.has_key('id')
334 assert variable.has_key('id')
336 category_id = category['id']
337 variable_id = variable['id']
339 default_value = get_value(cdef, category_id, variable_id)
340 current_value = get_current_value(cread, cwrite, category_id, variable_id)
341 varname = get_varname(cread, category_id, variable_id)
343 print_name_comments(cdef, category_id, variable_id)
345 print "%s = %s" % (varname, current_value)
347 print "%s" % (varname)
350 def show_variables_all(cdef, cread, cwrite, show_value, show_comments):
351 for (category_id, (category, variables)) in cread.variables().iteritems():
352 print("========== Category = %s" % category_id.upper())
353 for variable in variables.values():
354 show_variable(cdef, cread, cwrite,
355 category, variable, show_value, show_comments)
358 def show_variables_category(cdef, cread, cwrite, cid, show_value, show_comments):
361 print("========== Category = %s" % CID)
362 for vid in list_category(cdef, cid):
363 (category, variable) = cdef.locate_varname(vid.upper())
364 show_variable(cdef, cread, cwrite, category, variable,
365 show_value, show_comments)
368 re_mainloop_0arg = "^(?P<command>[uUwrRqlLsSeEcvVhH\?])[ \t]*$"
369 re_mainloop_1arg = "^(?P<command>[sSeEvV])[ \t]+(?P<arg>\w+)$"
370 matcher_mainloop_0arg = re.compile(re_mainloop_0arg)
371 matcher_mainloop_1arg = re.compile(re_mainloop_1arg)
374 def mainloop(cdef, cread, cwrite, default_config, site_config, consolidated_config):
379 "Enter command (u for usual changes, w to save, ? for help) ").strip()
382 except KeyboardInterrupt:
386 if (answer == "") or (answer in "?hH"):
389 groups_parse = matcher_mainloop_0arg.match(answer)
392 command = groups_parse.group('command')
395 groups_parse = matcher_mainloop_1arg.match(answer)
397 command = groups_parse.group('command')
398 arg = groups_parse.group('arg')
400 print("Unknown command >%s< -- use h for help" % answer)
403 show_comments = command.isupper()
409 variables = list_category(cdef, arg)
411 # category_id as the category name
412 # variables as the list of variable names
416 (category, variable) = cdef.locate_varname(arg)
418 # category/variable as output by locate_varname
421 print "%s: no such category or variable" % arg
425 # todo check confirmation
429 # Confirm that various constraints are met before saving file.
430 validate_variables = g_configuration.get(
431 'validate_variables', {})
432 validated_variables = cwrite.verify(
433 cdef, cread, validate_variables)
434 validator = g_configuration.get('validator', noop_validator)
435 validator(validated_variables)
436 cwrite.save(site_config)
438 print "Save failed due to a configuration exception:"
439 print traceback.print_exc()
440 print("Could not save -- fix write access on %s" % site_config)
442 print("Wrote %s" % site_config)
443 consolidate(default_config, site_config, consolidated_config)
444 print("You might want to type 'r' (restart %s), 'R' (reload %s) or 'q' (quit)" %
446 elif command in "uU":
447 global usual_variables
448 global flavour_xml_section_hash
450 for varname in usual_variables:
451 (category, variable) = cdef.locate_varname(varname)
452 if not (category is None and variable is None):
453 prompt_variable(cdef, cread, cwrite,
454 category, variable, False)
456 # set the driver variable according to the already set flavour
457 generic_flavour = cwrite.items('sfa')[0][1]
458 for section in cdef.sections():
459 if generic_flavour in flavour_xml_section_hash and flavour_xml_section_hash[generic_flavour] == section:
460 for item in cdef.items(section):
463 prompt_variable(cdef, cread, cwrite,
464 category, variable, False)
467 except Exception, inst:
468 if (str(inst) != 'BailOut'):
475 print_categories(cread)
476 elif command in "eE":
478 prompt_variables_all(cdef, cread, cwrite, show_comments)
479 elif mode == 'CATEGORY':
480 prompt_variables_category(
481 cdef, cread, cwrite, category_id, show_comments)
482 elif mode == 'VARIABLE':
484 prompt_variable(cdef, cread, cwrite, category, variable,
485 show_comments, False)
486 except Exception, inst:
487 if str(inst) != 'BailOut':
489 elif command in "vVsSlL":
490 show_value = (command in "sSlL")
491 (c1, c2, c3) = (cdef, cread, cwrite)
493 (c1, c2, c3) = (cwrite, cwrite, cwrite)
495 show_variables_all(c1, c2, c3, show_value, show_comments)
496 elif mode == 'CATEGORY':
497 show_variables_category(
498 c1, c2, c3, category_id, show_value, show_comments)
499 elif mode == 'VARIABLE':
500 show_variable(c1, c2, c3, category, variable,
501 show_value, show_comments)
503 print("Unknown command >%s< -- use h for help" % answer)
507 # creates directory for file if not yet existing
508 def check_dir(config_file):
509 dirname = os.path.dirname(config_file)
510 if (not os.path.exists(dirname)):
512 os.makedirs(dirname, 0755)
514 print "Cannot create dir %s due to %s - exiting" % (dirname, e)
517 if (not os.path.exists(dirname)):
518 print "Cannot create dir %s - exiting" % dirname
521 print "Created directory %s" % dirname
526 def optParserSetup(configuration):
527 parser = OptionParser(usage=usage(), version="%prog " + version_tag)
528 parser.set_defaults(config_dir=configuration['config_dir'],
529 service=configuration['service'],
530 usual_variables=configuration['usual_variables'])
531 parser.add_option("", "--configdir", dest="config_dir",
532 help="specify configuration directory")
533 parser.add_option("", "--service", dest="service",
534 help="specify /etc/init.d style service name")
535 parser.add_option("", "--usual_variable", dest="usual_variables",
536 action="append", help="add a usual variable")
540 def main(command, argv, configuration):
541 global g_configuration
542 g_configuration = configuration
544 parser = optParserSetup(configuration)
545 (config, args) = parser.parse_args()
547 parser.error("too many arguments")
549 configuration['service'] = config.service
550 configuration['usual_variables'] = config.usual_variables
551 configuration['config_dir'] = config.config_dir
552 # add in new usual_variables defined on the command line
553 for usual_variable in config.usual_variables:
554 if usual_variable not in configuration['usual_variables']:
555 configuration['usual_variables'].append(usual_variable)
557 # intialize configuration
560 default_config, site_config, consolidated_config = \
561 def_default_config, def_site_config, def_consolidated_config
563 default_config = args[0]
565 site_config = args[1]
567 consolidated_config = args[2]
569 for c in (default_config, site_config, consolidated_config):
573 # the default settings only - read only
574 cdef = Config(default_config)
576 # in effect : default settings + local settings - read only
577 cread = Config(default_config)
579 print traceback.print_exc()
580 print("default config files %s not found, is myplc installed ?" %
584 # local settings only, will be modified & saved
585 config_filename = "%s/sfa_config" % config.config_dir
586 cwrite = Config(config_filename)
588 cread.load(site_config)
589 cwrite.load(default_config)
590 cwrite.load(site_config)
594 mainloop(cdef, cread, cwrite, default_config,
595 site_config, consolidated_config)
598 if __name__ == '__main__':
599 command = sys.argv[0]
601 main(command, argv, configuration)