#!/bin/env python # Interactively prompts for variable values # expected arguments are # command -d [default-xml [custom-xml [ consolidated-xml ]]] # we use 3 instances of PLCConfiguration throughout: # cdef : models the defaults, from plc_default.xml # cread : merged from plc_default & configs/site.xml # cwrite : site.xml + pending changes import sys import os import re import readline import traceback from optparse import OptionParser from plc_config import PLCConfiguration from plc_config import ConfigurationException #################### release_id = "$Id$" release_rev = "$Revision$" release_url = "$URL$" def validator (validated_variables): maint_user = validated_variables["PLC_API_MAINTENANCE_USER"] root_user = validated_variables["PLC_ROOT_USER"] if maint_user == root_user: raise ConfigurationException("PLC_API_MAINTENANCE_USER=%s cannot be the same as PLC_ROOT_USER=%s"%(maint_user,root_user)) # historically we could also configure the devel pkg.... globals = { 'def_default_config' : "/etc/planetlab/default_config.xml", 'def_site_config' : "/etc/planetlab/configs/site.xml", 'def_consolidated_config' : "/etc/planetlab/plc_config.xml", 'usual_variables': ["PLC_NAME", "PLC_SHORTNAME", "PLC_SLICE_PREFIX", "PLC_ROOT_USER", "PLC_ROOT_PASSWORD", "PLC_MAIL_ENABLED", "PLC_MAIL_SUPPORT_ADDRESS", "PLC_DB_HOST", "PLC_API_HOST", "PLC_WWW_HOST", "PLC_BOOT_HOST", "PLC_NET_DNS1", "PLC_NET_DNS2", ], } def usage (): command_usage="%prog [options] [default-xml [site-xml [consolidated-xml]]]" global globals command_usage +=""" \t default-xml defaults to %s \t site-xml defaults to %s \t consolidated-xml defaults to %s""" % (globals['def_default_config'], globals['def_site_config'], globals['def_consolidated_config']) return command_usage #################### def get_value (config, category_id, variable_id): (category, variable) = config.get (category_id, variable_id) return variable['value'] 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): (category, variable) = config.get (category_id, variable_id) return (category_id+"_"+variable['id']).upper() # 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 (category_id, (category, variables)) in config.variables().iteritems(): result += [category_id] 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 (category_id, (category, variables)) in config.variables().iteritems(): if (cid == category_id): for variable in variables.values(): result += ["%s_%s" %(cid,variable['id'])] 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): try: conso = PLCConfiguration (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 (): os.system("set -x ; service plc reload") #################### def restart_service (): print ("==================== Stopping plc" ) os.system("service plc stop" ) print ("==================== Starting plc" ) os.system("service plc start") #################### def prompt_variable (cdef, cread, cwrite, category, variable, show_comments, support_next=False): assert category.has_key('id') assert variable.has_key('id') category_id = category ['id'] variable_id = variable['id'] while True: 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) 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 == "?"): 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 """ 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: variable['value'] = answer cwrite.set(category,variable) return 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): 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"): mainloop_usage = """Available commands: Uppercase versions give variables comments, when available u/U\t\t\tEdit usual variables w/W\t\t\tWrite / Write & reload r\t\t\tRestart plc service 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 [|]List Variables (all, in category, single) --- Typical usage involves: u, [l,] w, r, q """ 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() command=command.lower() 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"): global defined_flavour try: # Confirm that various constraints are met before saving file. validate_variables = {"PLC_API":"MAINTENANCE_USER","PLC":"ROOT_USER"} validated_variables = cwrite.verify(cdef, cread, validate_variables) validator(validated_variables) cwrite.save(site_config) except ConfigurationException, e: print "Save failed due to a configuration exception: %s" % e break; except: print traceback.print_exc() print ("Could not save -- fix write access on %s" % site_config) break print "Wrote",site_config consolidate(default_config, site_config, consolidated_config) print "You might want to type 'r' (restart plc), 'R' (reload plc) or 'q' (quit)" elif (command == "u"): try: global globals for varname in globals['usual_variables']: (category,variable) = cdef.locate_varname(varname) 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 for file %s - error=[%s] - exiting" % (dirname,config_file,e) sys.exit(1) if (not os.path.exists (dirname)): print "Cannot create dir %s for file %s - exiting" % (dirname,config_file) sys.exit(1) else: print "Created directory %s" % dirname #################### def main (): parser = OptionParser(usage=usage(), version="%prog " + release_rev + release_url) (config,args) = parser.parse_args() if len(args)>3: parser.error("too many arguments") # use any provided arg as advertised global globals (default_config,site_config,consolidated_config) = (globals['def_default_config'], globals['def_site_config'], globals['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 = PLCConfiguration(default_config) # in effect : default settings + local settings - read only cread = PLCConfiguration(default_config) except ConfigurationException, e: print ("Error %s in default config file %s" %(e,default_config)) return 1 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 cwrite=PLCConfiguration() try: cread.load(site_config) cwrite.load(site_config) except: cwrite = PLCConfiguration() mainloop (cdef, cread, cwrite, default_config, site_config, consolidated_config) return 0 if __name__ == '__main__': main()