Does not exit after w/W, so as to allow for a restart to be issued afterwards
[myplc.git] / plc-config-tty
1 #!/usr/bin/python
2
3 # Interactively prompts for variable values
4 # expected arguments are
5 # command [default-xml [custom-xml]]
6 #
7 # Two-steps logic:
8 # (1) scans all variables (todo: pass categories as arguments)
9 #     and prompts for value
10 #     current value proposed as default
11 #     also allows to remove site-dependent setting
12 # (2) epilogue : allows to
13 #     list the site-dependent vars with values
14 #     and to locally (re-)edit a variable from its shell name
15 #     quit with or without saving
16
17 import sys
18 import os
19 import re
20 import readline
21
22 from plc_config import PLCConfiguration
23
24 ####################
25 release = "$Id"
26
27 def_main_config = "/etc/planetlab/default_config.xml"
28 def_site_config = "/etc/planetlab/configs/site.xml"
29 def_consolidated_config = "/etc/planetlab/plc_config.xml"
30
31 command_usage="""Usage: %s [default-xml [site-xml [consolidated-xml]]]
32 \t default-xml defaults to %s
33 \t site-xml defaults to %s
34 \t consolidated-xml defaults to %s
35 """ % (sys.argv[0],def_main_config,def_site_config, def_consolidated_config)
36
37 ####################
38 variable_usage= """Special answers :
39 #\tShow variable comments
40 .\tStops prompting, return to mainloop
41 /\tCleans any site-defined value, reverts to default
42 =\tShows default value
43 >\tSkips to next category
44 ?\tThis help
45 """
46
47 def usage ():
48     print(command_usage)
49     sys.exit(1)
50
51 ####################
52 def get_value (config,  category_id, variable_id):
53     (category, variable) = config.get (category_id, variable_id)
54     return variable['value']
55
56 # refrain from using plc_config's _sanitize 
57 def get_varname (config,  category_id, variable_id):
58     (category, variable) = config.get (category_id, variable_id)
59     return (category_id+"_"+variable['id']).upper()
60
61 def prompt_variable (cdef, cread, cwrite, category, variable):
62
63     assert category.has_key('id')
64     assert variable.has_key('id')
65
66     category_id = category ['id']
67     variable_id = variable['id']
68
69     while True:
70         default_value = get_value(cdef,category_id,variable_id)
71         current_value = get_value(cread,category_id, variable_id)
72         varname = get_varname (cread,category_id, variable_id)
73         
74         prompt = "== %s : [%s] " % (varname,current_value)
75         try:
76             answer = raw_input(prompt).strip()
77         except EOFError :
78             raise Exception ('BailOut')
79
80         # no change
81         if (answer == "") or (answer == current_value):
82             return None
83         elif (answer == "."):
84             raise Exception ('BailOut')
85         elif (answer == ">"):
86             raise Exception ('NextCategory')
87         elif (answer == "#"):
88             if friendly_name is not None:
89                 print ("### " + friendly_name)
90             if comments == None:
91                 print ("!!! No comment associated to %s" % varname)
92             else:
93                 for line in comments:
94                     print ("# " + line)
95         elif (answer == "?"):
96             print variable_usage.strip()
97         elif (answer == "="):
98             print ("%s defaults to %s" %(varname,default_value))
99         # revert to default : remove from cwrite (i.e. site-config)
100         elif (answer == "/"):
101             cwrite.delete(category_id,variable_id)
102             print ("%s reverted to %s" %(varname,default_value))
103             return
104         else:
105             variable['value'] = answer
106             cwrite.set(category,variable)
107             return
108
109 ####################
110 def prompt_all_variables (cdef, cread, cwrite):
111     try:
112         for (category_id, (category, variables)) in cread.variables().iteritems():
113             print ("========== Category = %s" % category_id)
114             for variable in variables.values():
115                 try:
116                     newvar = prompt_variable (cdef, cread, cwrite, category, variable)
117                 except Exception, inst:
118                     if (str(inst) == 'NextCategory'): break
119                     else: raise
120                     
121     except Exception, inst:
122         if (str(inst) == 'BailOut'): return
123         else: raise
124
125
126 ####################
127 def consolidate (main_config, site_config, consolidated_config):
128     try:
129         conso = PLCConfiguration (main_config)
130         conso.load (site_config)
131         conso.save (consolidated_config)
132     except Exception, inst:
133         print "Could not consolidate, %s" % (str(inst))
134         return
135     print ("Overwote %s\n\tfrom %s\n\tand %s"%(consolidated_config,main_config,site_config))
136         
137 ####################
138 def restart_plc ():
139     print ("==================== Stopping plc")
140     os.system("service plc stop")
141     print ("==================== Starting plc")
142     os.system("service plc start")
143
144 ####################
145 mainloop_usage= """Available commands
146 c\tEdits commonly tuned variables
147 e\tEdits all variables
148 p\tPrints all locally-customized vars and values
149 e <var>\tPrompts (edit) fro variable <var>
150 p <var>\tShows current setting for <var>
151 l\tlists all known variables
152 w\tSaves and quit
153 W\tsaves, consolidates and quit
154 r\trestarts plc service
155 q\tQuits without saving
156 """
157
158 re_mainloop_var="^(?P<command>[pe])[ \t]+(?P<varname>\w+)$"
159 matcher_mainloop_var=re.compile(re_mainloop_var)
160
161 common_variables=("PLC_NAME",
162                   "PLC_ROOT_USER",
163                   "PLC_ROOT_PASSWORD",
164                   "PLC_MAIL_SUPPORT_ADDRESS",
165                   "PLC_DB_HOST",
166                   "PLC_API_HOST",
167                   "PLC_WWW_HOST",
168                   "PLC_BOOT_HOST",
169                   "PLC_NET_DNS1",
170                   "PLC_NET_DNS2")
171
172 def mainloop (cdef, cread, cwrite,main_config, site_config, consolidated_config):
173     while True:
174         try:
175             answer = raw_input("Enter command (c for usual changes, w to save, ? for help) ").strip()
176         except EOFError:
177             answer =""
178         if (answer == "") or (answer == "?") or (answer == "h"):
179             print mainloop_usage
180         elif (answer == "q"):
181             # todo check confirmation
182             return
183         elif (answer == "e"):
184             prompt_all_variables(cdef, cread, cwrite)
185         elif (answer.lower() == "w"):
186             try:
187                 cwrite.save(site_config)
188             except:
189                 print ("Could not save -- fix write access on %s" % site_config)
190                 break
191             print ("Wrote %s" % site_config)
192             if (answer == "W"):
193                 consolidate(main_config, site_config, consolidated_config)
194             print ("You might want to type 'r' (restart plc) or 'q' (quit)")
195         elif (answer == "l"):
196             print ("Config involves the following variables")
197             sys.stdout.write(cread.output_variables())
198         elif (answer == "p"):
199             print ("Current site config")
200             sys.stdout.write(cwrite.output_shell(False))
201         elif (answer == "c"):
202             try:
203                 for varname in common_variables:
204                     (category,variable) = cdef.locate_varname(varname)
205                     prompt_variable(cdef, cread, cwrite, category, variable)
206             except Exception, inst:
207                 if (str(inst) != 'BailOut'):
208                     raise
209         elif (answer == "r"):
210             restart_plc()
211         else:
212             groups_var = matcher_mainloop_var.match(answer)
213             if (groups_var):
214                 command = groups_var.group('command')
215                 varname = groups_var.group('varname')
216                 (category,variable) = cdef.locate_varname(varname)
217                 if not category:
218                     print "Unknown variable %s" % varname
219                 elif (command == 'p'):
220                     print ("%s = %s" % (varname,get_value(cwrite,
221                                                           category['id'],
222                                                           variable['id'])))
223                 else:
224                     try:
225                         prompt_variable(cdef, cread, cwrite, category,variable)
226                     except Exception, inst:
227                         if (str(inst) != 'BailOut'):
228                             raise
229             else:
230                 print ("Unknown command >%s<" % answer)
231
232 ####################
233 def main ():
234
235     save = True
236     command=sys.argv[0]
237     argv = sys.argv[1:]
238     if len(argv) == 0:
239         (main_config,site_config,consolidated_config) = (def_main_config, def_site_config, def_consolidated_config)
240     elif len(argv) == 1:
241         (main_config,site_config,consolidated_config) = (argv[1], def_site_config, def_consolidated_config)
242     elif len(argv) == 2:
243         (main_config, site_config,consolidated_config)  = (argv[1], argv[2], def_consolidated_config)
244     elif len(argv) == 3:
245         (main_config, site_config,consolidated_config)  = argv
246     else:
247         usage()
248
249     try:
250         # the default settings only - read only
251         cdef = PLCConfiguration(main_config)
252
253         # in effect : default settings + local settings - read only
254         cread = PLCConfiguration(main_config)
255
256     except:
257         print ("default config files not found, is myplc installed ?")
258         return 1
259
260     # local settings only, will be modified & saved
261     cwrite=PLCConfiguration()
262     
263     try:
264         cread.load(site_config)
265         cwrite.load(site_config)
266     except:
267         cwrite = PLCConfiguration()
268
269         print ("This is %s - %s -- Type ? at the prompt for help" %(command,release))
270     mainloop (cdef, cread, cwrite,main_config, site_config, consolidated_config)
271     return 0
272
273 if __name__ == '__main__':
274     main()