Change v3 to v4 yumgroups.xml
[myplc.git] / plc-config-tty
index a762105..79f7233 100755 (executable)
@@ -2,40 +2,98 @@
 
 # Interactively prompts for variable values
 # expected arguments are
-# command [default-xml [custom-xml]]
+# command -d [default-xml [custom-xml [ consolidated-xml ]]]
 #
-# Two-steps logic:
-# (1) scans all variables (todo: pass categories as arguments)
-#     and prompts for value
-#     current value proposed as default
-#     also allows to remove site-dependent setting
-# (2) epilogue : allows to
-#     list the site-dependent vars with values
-#     and to locally (re-)edit a variable from its shell name
-#     quit with or without saving
+# -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"
+release_id = "$Id: plc-config-tty,v 1.10 2006/12/12 10:14:44 thierry Exp $"
+release_rev = "$Revision: 1.10 $"
+
+def init_flavour (flavour):
+    global service
+    global usual_variables
+    if (flavour == "devel"):
+        service="plc-devel"
+        usual_variables=("PLC_DEVEL_FEDORA_URL",
+                          "PLC_DEVEL_CVSROOT")
+        config_dir = "/plc/devel/data/etc/planetlab"
+    else:
+        service="plc"
+        usual_variables=("PLC_NAME",
+                         "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",
+                         )
+        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
 
-def_main_config = "/etc/planetlab/default_config.xml"
-def_site_config = "/etc/planetlab/configs/site.xml"
-def_consolidated_config = "/etc/planetlab/plc_config.xml"
+    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 [<cat>|<var>]\tShow Locally modified variables/values
+-s/S [<cat>|<var>]\tShow variables/values (all, in category, single)
+-e/E [<cat>|<var>]\tEdit variables (all, in category, single)
+---
+-c\t\t\tList categories
+-v/V [<cat>|<var>]List Variables (all, in category, single)
+---
+Typical usage involves: u, [l,] w, r, q
+""" % service
 
-command_usage="""Usage: %s [default-xml [site-xml [consolidated-xml]]]
+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
-""" % (sys.argv[0],def_main_config,def_site_config, def_consolidated_config)
+\t consolidated-xml defaults to %s""" % (def_default_config,def_site_config, def_consolidated_config)
+    print(command_usage)
+    sys.exit(1)
 
 ####################
-variable_usage= """Special answers :
+variable_usage= """Edit Commands :
 #\tShow variable comments
 .\tStops prompting, return to mainloop
 /\tCleans any site-defined value, reverts to default
@@ -44,21 +102,97 @@ variable_usage= """Special answers :
 ?\tThis help
 """
 
-def usage ():
-    print(command_usage)
-    sys.exit(1)
-
 ####################
 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()
 
-def prompt_variable (cdef, cread, cwrite, category, variable):
+# 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')
@@ -68,9 +202,11 @@ def prompt_variable (cdef, cread, cwrite, category, variable):
 
     while True:
         default_value = get_value(cdef,category_id,variable_id)
-        current_value = get_value(cread,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()
@@ -82,16 +218,8 @@ def prompt_variable (cdef, cread, cwrite, category, variable):
             return None
         elif (answer == "."):
             raise Exception ('BailOut')
-        elif (answer == ">"):
-            raise Exception ('NextCategory')
         elif (answer == "#"):
-            if friendly_name is not None:
-                print ("### " + friendly_name)
-            if comments == None:
-                print ("!!! No comment associated to %s" % varname)
-            else:
-                for line in comments:
-                    print ("# " + line)
+            print_name_comments(cread,category_id,variable_id)
         elif (answer == "?"):
             print variable_usage.strip()
         elif (answer == "="):
@@ -101,19 +229,24 @@ def prompt_variable (cdef, cread, cwrite, category, variable):
             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_all_variables (cdef, cread, cwrite):
+def prompt_variables_all (cdef, cread, cwrite, show_comments):
     try:
         for (category_id, (category, variables)) in cread.variables().iteritems():
-            print ("========== Category = %s" % category_id)
+            print ("========== Category = %s" % category_id.upper())
             for variable in variables.values():
                 try:
-                    newvar = prompt_variable (cdef, cread, cwrite, category, variable)
+                    newvar = prompt_variable (cdef, cread, cwrite, category, variable,
+                                              show_comments, True)
                 except Exception, inst:
                     if (str(inst) == 'NextCategory'): break
                     else: raise
@@ -122,136 +255,214 @@ def prompt_all_variables (cdef, cread, cwrite):
         if (str(inst) == 'BailOut'): return
         else: raise
 
-
-####################
-def consolidate (main_config, site_config, consolidated_config):
+def prompt_variables_category (cdef, cread, cwrite, cid, show_comments):
+    cid=cid.lower()
+    CID=cid.upper()
     try:
-        conso = PLCConfiguration (main_config)
-        conso.load (site_config)
-        conso.save (consolidated_config)
+        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:
-        print "Could not consolidate, %s" % (str(inst))
-        return
-    print ("Overwote %s\n\tfrom %s\n\tand %s"%(consolidated_config,main_config,site_config))
-        
+        if (str(inst) == 'BailOut'): return
+        else: raise
+
 ####################
-def restart_plc ():
-    print ("==================== Stopping plc")
-    os.system("service plc stop")
-    print ("==================== Starting plc")
-    os.system("service plc start")
+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)
 
 ####################
-mainloop_usage= """Available commands
-c\tEdits commonly tuned variables
-e\tEdits all variables
-p\tPrints all locally-customized vars and values
-e <var>\tPrompts (edit) fro variable <var>
-p <var>\tShows current setting for <var>
-l\tlists all known variables
-w\tSaves and quit
-W\tsaves, consolidates and quit
-r\trestarts plc service
-q\tQuits without saving
-"""
+re_mainloop_0arg="^(?P<command>[uUwrqlLsSeEcvVhH\?])[ \t]*$"
+re_mainloop_1arg="^(?P<command>[sSeEvV])[ \t]+(?P<arg>\w+)$"
+matcher_mainloop_0arg=re.compile(re_mainloop_0arg)
+matcher_mainloop_1arg=re.compile(re_mainloop_1arg)
 
-re_mainloop_var="^(?P<command>[pe])[ \t]+(?P<varname>\w+)$"
-matcher_mainloop_var=re.compile(re_mainloop_var)
-
-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")
-
-def mainloop (cdef, cread, cwrite,main_config, site_config, consolidated_config):
+def mainloop (cdef, cread, cwrite, default_config, site_config, consolidated_config):
     while True:
         try:
-            answer = raw_input("Enter command (c for usual changes, w to save, ? for help) ").strip()
+            answer = raw_input("Enter command (u for usual changes, w to save, ? for help) ").strip()
         except EOFError:
             answer =""
-        if (answer == "") or (answer == "?") or (answer == "h"):
+        if (answer == "") or (answer in "?hH"):
             print mainloop_usage
-        elif (answer == "q"):
+            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 (answer == "e"):
-            prompt_all_variables(cdef, cread, cwrite)
-        elif (answer.lower() == "w"):
+        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)
-            if (answer == "W"):
-                consolidate(main_config, site_config, consolidated_config)
-            return
-        elif (answer == "l"):
-            print ("Config involves the following variables")
-            sys.stdout.write(cread.output_variables())
-        elif (answer == "p"):
-            print ("Current site config")
-            sys.stdout.write(cwrite.output_shell(False))
-        elif (answer == "c"):
+            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:
+                for varname in usual_variables:
                     (category,variable) = cdef.locate_varname(varname)
-                    prompt_variable(cdef, cread, cwrite, category, variable)
+                    prompt_variable(cdef, cread, cwrite, category, variable, False)
             except Exception, inst:
                 if (str(inst) != 'BailOut'):
                     raise
-        elif (answer == "r"):
+        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:
-            groups_var = matcher_mainloop_var.match(answer)
-            if (groups_var):
-                command = groups_var.group('command')
-                varname = groups_var.group('varname')
-                (category,variable) = cdef.locate_varname(varname)
-                if not category:
-                    print "Unknown variable %s" % varname
-                elif (command == 'p'):
-                    print ("%s = %s" % (varname,get_value(cwrite,
-                                                          category['id'],
-                                                          variable['id'])))
-                else:
-                    try:
-                        prompt_variable(cdef, cread, cwrite, category,variable)
-                    except Exception, inst:
-                        if (str(inst) != 'BailOut'):
-                            raise
+            os.makedirs(dirname,0755)
+            if (not os.path.exists (dirname)):
+                print "Cannot create dir %s - exiting" % dirname
+                sys.exit(1)
             else:
-                print ("Unknown command >%s<" % answer)
+                print "Created directory %s" % dirname
 
+                
 ####################
 def main ():
 
-    save = True
     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:
-        (main_config,site_config,consolidated_config) = (def_main_config, def_site_config, def_consolidated_config)
+        (default_config,site_config,consolidated_config) = (def_default_config, def_site_config, def_consolidated_config)
     elif len(argv) == 1:
-        (main_config,site_config,consolidated_config) = (argv[1], def_site_config, def_consolidated_config)
+        (default_config,site_config,consolidated_config) = (argv[0], def_site_config, def_consolidated_config)
     elif len(argv) == 2:
-        (main_config, site_config,consolidated_config)  = (argv[1], argv[2], def_consolidated_config)
+        (default_config, site_config,consolidated_config)  = (argv[0], argv[1], def_consolidated_config)
     elif len(argv) == 3:
-        (main_config, site_config,consolidated_config)  = argv
+        (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(main_config)
+        cdef = PLCConfiguration(default_config)
 
         # in effect : default settings + local settings - read only
-        cread = PLCConfiguration(main_config)
+        cread = PLCConfiguration(default_config)
 
     except:
         print ("default config files not found, is myplc installed ?")
@@ -266,8 +477,7 @@ def main ():
     except:
         cwrite = PLCConfiguration()
 
-        print ("This is %s - %s -- Type ? at the prompt for help" %(command,release))
-    mainloop (cdef, cread, cwrite,main_config, site_config, consolidated_config)
+    mainloop (cdef, cread, cwrite,default_config, site_config, consolidated_config)
     return 0
 
 if __name__ == '__main__':