#!/usr/bin/python # Interactively prompts for variable values # expected arguments are # command -d [default-xml [custom-xml [ consolidated-xml ]]] # # -d is for the myplc-devel package # 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 getopt from plc_config import PLCConfiguration #################### release_id = "$Id: plc-config-tty,v 1.8 2006/08/18 14:34:45 thierry Exp $" release_rev = "$Revision: 1.8 $" def init_flavour (flavour): global service global common_variables if (flavour == "devel"): service="plc-devel" common_variables=("PLC_DEVEL_FEDORA_URL", "PLC_DEVEL_CVSROOT") config_dir = "/plc/devel/data/etc/planetlab" else: service="plc" common_variables=("PLC_NAME", "PLC_ROOT_USER", "PLC_ROOT_PASSWORD", "PLC_MAIL_SUPPORT_ADDRESS", "PLC_DB_HOST", "PLC_API_HOST", "PLC_WWW_HOST", "PLC_BOOT_HOST", "PLC_NET_DNS1", "PLC_NET_DNS2") config_dir = "/etc/planetlab" global def_default_config def_default_config= "%s/default_config.xml" % config_dir global def_site_config def_site_config = "%s/configs/site.xml" % config_dir global def_consolidated_config def_consolidated_config = "%s/plc_config.xml" % config_dir 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 & consolidate -r\t\t\tRestart %s 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 """ % service def usage (): command_usage="Usage: %s [-d] [-v] [default-xml [site-xml [consolidated-xml]]]"% sys.argv[0] init_flavour ("boot") command_usage +=""" -v shows version and exits \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) command_usage += """ Unless you specify the -d option, meaning you want to configure myplc-devel instead of regular myplc, in which case""" init_flavour ("devel") 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) print(command_usage) sys.exit(1) #################### 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): (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 restart_plc (): 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): 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') # 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: 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[uUwrqlLsSeEcvVhH\?])[ \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 ="" 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() 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 in "wW"): try: cwrite.save(site_config) except: 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 plc) or 'q' (quit)") elif (command == "u"): try: for varname in common_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_plc() 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) #################### def check_dir (config_file): dirname = os.path.dirname (config_file) if (not os.path.exists (dirname)): print "Config file %s located under a non-existing directory" % config_file answer=raw_input("Want to create %s [y]/n ? " % dirname) answer = answer.lower() if (answer == 'n'): print "Cannot proceed - good bye" sys.exit(1) else: os.makedirs(dirname,0755) if (not os.path.exists (dirname)): print "Cannot create dir %s - exiting" % dirname sys.exit(1) else: print "Created directory %s" % dirname #################### def main (): command=sys.argv[0] argv = sys.argv[1:] save = True # default is myplc (non -devel) unless -d is specified init_flavour("boot") optlist,list = getopt.getopt(argv,":dhv") for opt in optlist: if opt[0] == "-h": usage() if opt[0] == "-v": print ("This is %s - %s" %(command,release_rev)) sys.exit(1) if opt[0] == "-d": init_flavour("devel") argv=argv[1:] if len(argv) == 0: (default_config,site_config,consolidated_config) = (def_default_config, def_site_config, def_consolidated_config) elif len(argv) == 1: (default_config,site_config,consolidated_config) = (argv[0], def_site_config, def_consolidated_config) elif len(argv) == 2: (default_config, site_config,consolidated_config) = (argv[0], argv[1], def_consolidated_config) elif len(argv) == 3: (default_config, site_config,consolidated_config) = argv else: usage() 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: print ("default config files not found, is myplc installed ?") 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()