#!/bin/env python import os import sys import re import time import traceback import types import readline from StringIO import StringIO from optparse import OptionParser from sfa.util.config import Config def validator(validated_variables): pass # maint_user = validated_variables["PLC_API_MAINTENANCE_USER"] # root_user = validated_variables["PLC_ROOT_USER"] # if maint_user == root_user: # errStr="PLC_API_MAINTENANCE_USER=%s cannot be the same as PLC_ROOT_USER=%s"%(maint_user,root_user) # raise plc_config.ConfigurationException(errStr) usual_variables = [ "SFA_GENERIC_FLAVOUR", "SFA_INTERFACE_HRN", "SFA_REGISTRY_ROOT_AUTH", "SFA_REGISTRY_HOST", "SFA_AGGREGATE_HOST", "SFA_SM_HOST", "SFA_DB_HOST", "SFA_PLC_URL", "SFA_PLC_USER", "SFA_PLC_PASSWORD", ] configuration={ \ 'name':'sfa', 'service':"sfa", 'usual_variables':usual_variables, 'config_dir':"/etc/sfa", 'validate_variables':{}, 'validator':validator, } # GLOBAL VARIABLES # release_id = "$Id$" release_rev = "$Revision$" release_url = "$URL$" g_configuration=None usual_variables=None config_dir=None service=None def noop_validator(validated_variables): pass # historically we could also configure the devel pkg.... def init_configuration (): global g_configuration global usual_variables, config_dir, service usual_variables=g_configuration["usual_variables"] config_dir=g_configuration["config_dir"] service=g_configuration["service"] global def_default_config, def_site_config, def_consolidated_config def_default_config= "%s/default_config.xml" % config_dir def_site_config = "%s/configs/site_config" % config_dir def_consolidated_config = "%s/%s_config" % (config_dir, service) global mainloop_usage mainloop_usage= """Available commands: Uppercase versions give variables comments, when available u/U\t\t\tEdit usual variables w\t\t\tWrite r\t\t\tRestart %(service)s service R\t\t\tReload %(service)s service (rebuild config files for sh, python....) q\t\t\tQuit (without saving) h/?\t\t\tThis help --- l/L [|]\tShow Locally modified variables/values s/S [|]\tShow variables/values (all, in category, single) e/E [|]\tEdit variables (all, in category, single) --- c\t\t\tList categories v/V [|]\tList Variables (all, in category, single) --- Typical usage involves: u, [l,] w, r, q """ % globals() def usage (): command_usage="%prog [options] [default-xml [site-xml [consolidated-xml]]]" init_configuration () command_usage +=""" \t default-xml defaults to %s \t site-xml defaults to %s \t consolidated-xml defaults to %s""" % (def_default_config,def_site_config, def_consolidated_config) return command_usage #################### variable_usage= """Edit Commands : #\tShow variable comments .\tStops prompting, return to mainloop /\tCleans any site-defined value, reverts to default =\tShows default value >\tSkips to next category ?\tThis help """ #################### def get_value (config, category_id, variable_id): value = config.get (category_id, variable_id) return value def get_type (config, category_id, variable_id): value = config.get (category_id, variable_id) #return variable['type'] return str def get_current_value (cread, cwrite, category_id, variable_id): # the value stored in cwrite, if present, is the one we want try: result=get_value (cwrite,category_id,variable_id) except: result=get_value (cread,category_id,variable_id) return result # refrain from using plc_config's _sanitize def get_varname (config, category_id, variable_id): varname = category_id +"_"+ variable_id config.locate_varname(varname) return varname # could not avoid using _sanitize here.. def get_name_comments (config, cid, vid): try: (category, variable) = config.get (cid, vid) (id, name, value, comments) = config._sanitize_variable (cid,variable) return (name,comments) except: return (None,[]) def print_name_comments (config, cid, vid): (name,comments)=get_name_comments(config,cid,vid) if name: print "### %s" % name if comments: for line in comments: print "# %s" % line else: print "!!! No comment associated to %s_%s" % (cid,vid) #################### def list_categories (config): result=[] for section in config.sections(): result += [section] return result def print_categories (config): print "Known categories" for cid in list_categories(config): print "%s" % (cid.upper()) #################### def list_category (config, cid): result=[] for section in config.sections(): if section == cid.lower(): for (name,value) in config.items(section): result += ["%s_%s" %(cid,name)] return result def print_category (config, cid, show_comments=True): cid=cid.lower() CID=cid.upper() vids=list_category(config,cid) if (len(vids) == 0): print "%s : no such category"%CID else: print "Category %s contains" %(CID) for vid in vids: print vid.upper() #################### def consolidate (default_config, site_config, consolidated_config): global service try: conso = Config(default_config) conso.load (site_config) conso.save (consolidated_config) except Exception, inst: print "Could not consolidate, %s" % (str(inst)) return print ("Merged\n\t%s\nand\t%s\ninto\t%s"%(default_config,site_config, consolidated_config)) def reload_service (): global service os.system("set -x ; service %s reload" % service) #################### def restart_service (): global service print ("==================== Stopping %s" % service) os.system("service %s stop" % service) print ("==================== Starting %s" % service) os.system("service %s start" % service) #################### def prompt_variable (cdef, cread, cwrite, category, variable, show_comments, support_next=False): category_id = category variable_id = variable while True: default_value = get_value(cdef,category_id,variable_id) variable_type = get_type(cdef,category_id,variable_id) current_value = get_current_value(cread,cwrite,category_id, variable_id) varname = get_varname (cread,category_id, variable_id) if show_comments : print_name_comments (cdef, category_id, variable_id) prompt = "== %s : [%s] " % (varname,current_value) try: answer = raw_input(prompt).strip() except EOFError : raise Exception ('BailOut') except KeyboardInterrupt: print "\n" raise Exception ('BailOut') # no change if (answer == "") or (answer == current_value): return None elif (answer == "."): raise Exception ('BailOut') elif (answer == "#"): print_name_comments(cread,category_id,variable_id) elif (answer == "?"): print variable_usage.strip() elif (answer == "="): print ("%s defaults to %s" %(varname,default_value)) # revert to default : remove from cwrite (i.e. site-config) elif (answer == "/"): cwrite.delete(category_id,variable_id) print ("%s reverted to %s" %(varname,default_value)) return elif (answer == ">"): if support_next: raise Exception ('NextCategory') else: print "No support for next category" else: if cdef.validate_type(variable_type, answer): cwrite.set(category_id, variable_id, answer) else: print "Not a valid value" def prompt_variables_all (cdef, cread, cwrite, show_comments): try: for (category_id, (category, variables)) in cread.variables().iteritems(): print ("========== Category = %s" % category_id.upper()) for variable in variables.values(): try: newvar = prompt_variable (cdef, cread, cwrite, category, variable, show_comments, True) except Exception, inst: if (str(inst) == 'NextCategory'): break else: raise except Exception, inst: if (str(inst) == 'BailOut'): return else: raise def prompt_variables_category (cdef, cread, cwrite, cid, show_comments): cid=cid.lower() CID=cid.upper() try: print ("========== Category = %s" % CID) for vid in list_category(cdef,cid): (category,variable) = cdef.locate_varname(vid.upper()) newvar = prompt_variable (cdef, cread, cwrite, category, variable, show_comments, False) except Exception, inst: if (str(inst) == 'BailOut'): return else: raise #################### def show_variable (cdef, cread, cwrite, category, variable,show_value,show_comments): assert category.has_key('id') assert variable.has_key('id') category_id = category ['id'] variable_id = variable['id'] default_value = get_value(cdef,category_id,variable_id) current_value = get_current_value(cread,cwrite,category_id,variable_id) varname = get_varname (cread,category_id, variable_id) if show_comments : print_name_comments (cdef, category_id, variable_id) if show_value: print "%s = %s" % (varname,current_value) else: print "%s" % (varname) def show_variables_all (cdef, cread, cwrite, show_value, show_comments): for (category_id, (category, variables)) in cread.variables().iteritems(): print ("========== Category = %s" % category_id.upper()) for variable in variables.values(): show_variable (cdef, cread, cwrite, category, variable,show_value,show_comments) def show_variables_category (cdef, cread, cwrite, cid, show_value,show_comments): cid=cid.lower() CID=cid.upper() print ("========== Category = %s" % CID) for vid in list_category(cdef,cid): (category,variable) = cdef.locate_varname(vid.upper()) show_variable (cdef, cread, cwrite, category, variable, show_value,show_comments) #################### re_mainloop_0arg="^(?P[uUwrRqlLsSeEcvVhH\?])[ \t]*$" re_mainloop_1arg="^(?P[sSeEvV])[ \t]+(?P\w+)$" matcher_mainloop_0arg=re.compile(re_mainloop_0arg) matcher_mainloop_1arg=re.compile(re_mainloop_1arg) def mainloop (cdef, cread, cwrite, default_config, site_config, consolidated_config): global service while True: try: answer = raw_input("Enter command (u for usual changes, w to save, ? for help) ").strip() except EOFError: answer ="" except KeyboardInterrupt: print "\nBye" sys.exit() if (answer == "") or (answer in "?hH"): print mainloop_usage continue groups_parse = matcher_mainloop_0arg.match(answer) command=None if (groups_parse): command = groups_parse.group('command') arg=None else: groups_parse = matcher_mainloop_1arg.match(answer) if (groups_parse): command = groups_parse.group('command') arg=groups_parse.group('arg') if not command: print ("Unknown command >%s< -- use h for help" % answer) continue show_comments=command.isupper() mode='ALL' if arg: mode=None arg=arg.lower() variables=list_category (cdef,arg) if len(variables): # category_id as the category name # variables as the list of variable names mode='CATEGORY' category_id=arg arg=arg.upper() (category,variable)=cdef.locate_varname(arg) if variable: # category/variable as output by locate_varname mode='VARIABLE' if not mode: print "%s: no such category or variable" % arg continue if command in "qQ": # todo check confirmation return elif command == "w": try: # Confirm that various constraints are met before saving file. validate_variables = g_configuration.get('validate_variables',{}) validated_variables = cwrite.verify(cdef, cread, validate_variables) validator = g_configuration.get('validator',noop_validator) validator(validated_variables) cwrite.save(site_config) except: print "Save failed due to a configuration exception:" print traceback.print_exc() print ("Could not save -- fix write access on %s" % site_config) break print ("Wrote %s" % site_config) consolidate(default_config, site_config, consolidated_config) print ("You might want to type 'r' (restart %s), 'R' (reload %s) or 'q' (quit)" % \ (service,service)) elif command in "uU": global usual_variables try: for varname in usual_variables: (category,variable) = cdef.locate_varname(varname) if not (category is None and variable is None): prompt_variable(cdef, cread, cwrite, category, variable, False) except Exception, inst: if (str(inst) != 'BailOut'): raise elif command == "r": restart_service() elif command == "R": reload_service() elif command == "c": print_categories(cread) elif command in "eE": if mode == 'ALL': prompt_variables_all(cdef, cread, cwrite,show_comments) elif mode == 'CATEGORY': prompt_variables_category(cdef,cread,cwrite,category_id,show_comments) elif mode == 'VARIABLE': try: prompt_variable (cdef,cread,cwrite,category,variable, show_comments,False) except Exception, inst: if str(inst) != 'BailOut': raise elif command in "vVsSlL": show_value=(command in "sSlL") (c1,c2,c3) = (cdef, cread, cwrite) if command in "lL": (c1,c2,c3) = (cwrite,cwrite,cwrite) if mode == 'ALL': show_variables_all(c1,c2,c3,show_value,show_comments) elif mode == 'CATEGORY': show_variables_category(c1,c2,c3,category_id,show_value,show_comments) elif mode == 'VARIABLE': show_variable (c1,c2,c3,category,variable,show_value,show_comments) else: print ("Unknown command >%s< -- use h for help" % answer) #################### # creates directory for file if not yet existing def check_dir (config_file): dirname = os.path.dirname (config_file) if (not os.path.exists (dirname)): try: os.makedirs(dirname,0755) except OSError, e: print "Cannot create dir %s due to %s - exiting" % (dirname,e) sys.exit(1) if (not os.path.exists (dirname)): print "Cannot create dir %s - exiting" % dirname sys.exit(1) else: print "Created directory %s" % dirname #################### def optParserSetup(configuration): parser = OptionParser(usage=usage(), version="%prog " + release_rev + release_url ) parser.set_defaults(config_dir=configuration['config_dir'], service=configuration['service'], usual_variables=configuration['usual_variables']) parser.add_option("","--configdir",dest="config_dir",help="specify configuration directory") parser.add_option("","--service",dest="service",help="specify /etc/init.d style service name") parser.add_option("","--usual_variable",dest="usual_variables",action="append", help="add a usual variable") return parser def main(command,argv,configuration): global g_configuration g_configuration=configuration parser = optParserSetup(configuration) (config,args) = parser.parse_args() if len(args)>3: parser.error("too many arguments") configuration['service']=config.service configuration['usual_variables']=config.usual_variables configuration['config_dir']=config.config_dir # add in new usual_variables defined on the command line for usual_variable in config.usual_variables: if usual_variable not in configuration['usual_variables']: configuration['usual_variables'].append(usual_variable) # intialize configuration init_configuration() (default_config,site_config,consolidated_config) = (def_default_config, def_site_config, def_consolidated_config) if len(args) >= 1: default_config=args[0] if len(args) >= 2: site_config=args[1] if len(args) == 3: consolidated_config=args[2] for c in (default_config,site_config,consolidated_config): check_dir (c) try: # the default settings only - read only cdef = Config(default_config) # in effect : default settings + local settings - read only cread = Config(default_config) except: print traceback.print_exc() print ("default config files %s not found, is myplc installed ?" % default_config) return 1 # local settings only, will be modified & saved config_filename = "%s/sfa_config" % config.config_dir try: cwrite=Config(config_filename) except ConfigParser.MissingSectionHeaderError: # remove legacy config os.unlink(config_filename) cwrite=Config(config_filename) try: cread.load(site_config) cwrite.load(site_config) except: cwrite = Config() mainloop (cdef, cread, cwrite, default_config, site_config, consolidated_config) return 0 if __name__ == '__main__': command=sys.argv[0] argv = sys.argv[1:] main(command,argv,configuration)