3 # Interactively prompts for variable values
4 # expected arguments are
5 # command -d [default-xml [custom-xml [ consolidated-xml ]]]
7 # we use 3 instances of PLCConfiguration throughout:
8 # cdef : models the defaults, from plc_default.xml
9 # cread : merged from plc_default & configs/site.xml
10 # cwrite : site.xml + pending changes
17 from optparse import OptionParser
19 from plc_config import PLCConfiguration
20 from plc_config import ConfigurationException
24 release_rev = "$Revision$"
27 def validator (validated_variables):
28 maint_user = validated_variables["PLC_API_MAINTENANCE_USER"]
29 root_user = validated_variables["PLC_ROOT_USER"]
30 if maint_user == root_user:
31 raise ConfigurationException("PLC_API_MAINTENANCE_USER=%s cannot be the same as PLC_ROOT_USER=%s"%(maint_user,root_user))
33 # historically we could also configure the devel pkg....
35 'def_default_config' : "/etc/planetlab/default_config.xml",
36 'def_site_config' : "/etc/planetlab/configs/site.xml",
37 'def_consolidated_config' : "/etc/planetlab/plc_config.xml",
38 'usual_variables': ["PLC_NAME",
44 "PLC_MAIL_SUPPORT_ADDRESS",
55 command_usage="%prog [options] [default-xml [site-xml [consolidated-xml]]]"
58 \t default-xml defaults to %s
59 \t site-xml defaults to %s
60 \t consolidated-xml defaults to %s""" % (globals['def_default_config'],
61 globals['def_site_config'],
62 globals['def_consolidated_config'])
66 def get_value (config, category_id, variable_id):
67 (category, variable) = config.get (category_id, variable_id)
68 return variable['value']
70 def get_current_value (cread, cwrite, category_id, variable_id):
71 # the value stored in cwrite, if present, is the one we want
73 result=get_value (cwrite,category_id,variable_id)
75 result=get_value (cread,category_id,variable_id)
78 # refrain from using plc_config's _sanitize
79 def get_varname (config, category_id, variable_id):
80 (category, variable) = config.get (category_id, variable_id)
81 return (category_id+"_"+variable['id']).upper()
83 # could not avoid using _sanitize here..
84 def get_name_comments (config, cid, vid):
86 (category, variable) = config.get (cid, vid)
87 (id, name, value, comments) = config._sanitize_variable (cid,variable)
88 return (name,comments)
92 def print_name_comments (config, cid, vid):
93 (name,comments)=get_name_comments(config,cid,vid)
100 print "!!! No comment associated to %s_%s" % (cid,vid)
103 def list_categories (config):
105 for (category_id, (category, variables)) in config.variables().iteritems():
106 result += [category_id]
109 def print_categories (config):
110 print "Known categories"
111 for cid in list_categories(config):
112 print "%s" % (cid.upper())
115 def list_category (config, cid):
117 for (category_id, (category, variables)) in config.variables().iteritems():
118 if (cid == category_id):
119 for variable in variables.values():
120 result += ["%s_%s" %(cid,variable['id'])]
123 def print_category (config, cid, show_comments=True):
126 vids=list_category(config,cid)
128 print "%s : no such category"%CID
130 print "Category %s contains" %(CID)
135 def consolidate (default_config, site_config, consolidated_config):
137 conso = PLCConfiguration (default_config)
138 conso.load (site_config)
139 conso.save (consolidated_config)
140 except Exception, inst:
141 print "Could not consolidate, %s" % (str(inst))
143 print ("Merged\n\t%s\nand\t%s\ninto\t%s"%(default_config,site_config,
144 consolidated_config))
146 def reload_service ():
147 os.system("set -x ; service plc reload")
150 def restart_service ():
151 print ("==================== Stopping plc" )
152 os.system("service plc stop" )
153 print ("==================== Starting plc" )
154 os.system("service plc start")
157 def prompt_variable (cdef, cread, cwrite, category, variable,
158 show_comments, support_next=False):
160 assert category.has_key('id')
161 assert variable.has_key('id')
163 category_id = category ['id']
164 variable_id = variable['id']
167 default_value = get_value(cdef,category_id,variable_id)
168 current_value = get_current_value(cread,cwrite,category_id, variable_id)
169 varname = get_varname (cread,category_id, variable_id)
172 print_name_comments (cdef, category_id, variable_id)
173 prompt = "== %s : [%s] " % (varname,current_value)
175 answer = raw_input(prompt).strip()
177 raise Exception ('BailOut')
178 except KeyboardInterrupt:
180 raise Exception ('BailOut')
183 if (answer == "") or (answer == current_value):
185 elif (answer == "."):
186 raise Exception ('BailOut')
187 elif (answer == "#"):
188 print_name_comments(cread,category_id,variable_id)
189 elif (answer == "?"):
190 variable_usage = """Edit Commands :
191 #\tShow variable comments
192 .\tStops prompting, return to mainloop
193 /\tCleans any site-defined value, reverts to default
194 =\tShows default value
195 >\tSkips to next category
198 print variable_usage.strip()
199 elif (answer == "="):
200 print ("%s defaults to %s" %(varname,default_value))
201 # revert to default : remove from cwrite (i.e. site-config)
202 elif (answer == "/"):
203 cwrite.delete(category_id,variable_id)
204 print ("%s reverted to %s" %(varname,default_value))
206 elif (answer == ">"):
208 raise Exception ('NextCategory')
210 print "No support for next category"
212 variable['value'] = answer
213 cwrite.set(category,variable)
216 def prompt_variables_all (cdef, cread, cwrite, show_comments):
218 for (category_id, (category, variables)) in cread.variables().iteritems():
219 print ("========== Category = %s" % category_id.upper())
220 for variable in variables.values():
222 newvar = prompt_variable (cdef, cread, cwrite, category, variable,
224 except Exception, inst:
225 if (str(inst) == 'NextCategory'): break
228 except Exception, inst:
229 if (str(inst) == 'BailOut'): return
232 def prompt_variables_category (cdef, cread, cwrite, cid, show_comments):
236 print ("========== Category = %s" % CID)
237 for vid in list_category(cdef,cid):
238 (category,variable) = cdef.locate_varname(vid.upper())
239 newvar = prompt_variable (cdef, cread, cwrite, category, variable,
240 show_comments, False)
241 except Exception, inst:
242 if (str(inst) == 'BailOut'): return
246 def show_variable (cdef, cread, cwrite,
247 category, variable,show_value,show_comments):
248 assert category.has_key('id')
249 assert variable.has_key('id')
251 category_id = category ['id']
252 variable_id = variable['id']
254 default_value = get_value(cdef,category_id,variable_id)
255 current_value = get_current_value(cread,cwrite,category_id,variable_id)
256 varname = get_varname (cread,category_id, variable_id)
258 print_name_comments (cdef, category_id, variable_id)
260 print "%s = %s" % (varname,current_value)
262 print "%s" % (varname)
264 def show_variables_all (cdef, cread, cwrite, show_value, show_comments):
265 for (category_id, (category, variables)) in cread.variables().iteritems():
266 print ("========== Category = %s" % category_id.upper())
267 for variable in variables.values():
268 show_variable (cdef, cread, cwrite,
269 category, variable,show_value,show_comments)
271 def show_variables_category (cdef, cread, cwrite, cid, show_value,show_comments):
274 print ("========== Category = %s" % CID)
275 for vid in list_category(cdef,cid):
276 (category,variable) = cdef.locate_varname(vid.upper())
277 show_variable (cdef, cread, cwrite, category, variable,
278 show_value,show_comments)
281 re_mainloop_0arg="^(?P<command>[uUwrRqlLsSeEcvVhH\?])[ \t]*$"
282 re_mainloop_1arg="^(?P<command>[sSeEvV])[ \t]+(?P<arg>\w+)$"
283 matcher_mainloop_0arg=re.compile(re_mainloop_0arg)
284 matcher_mainloop_1arg=re.compile(re_mainloop_1arg)
286 def mainloop (cdef, cread, cwrite, default_config, site_config, consolidated_config):
289 answer = raw_input("Enter command (u for usual changes, w to save, ? for help) ").strip()
292 except KeyboardInterrupt:
296 if (answer == "") or (answer in "?hH"):
297 mainloop_usage = """Available commands:
298 Uppercase versions give variables comments, when available
299 u/U\t\t\tEdit usual variables
300 w/W\t\t\tWrite / Write & reload
301 r\t\t\tRestart plc service
302 q\t\t\tQuit (without saving)
305 l/L [<cat>|<var>]\tShow Locally modified variables/values
306 s/S [<cat>|<var>]\tShow variables/values (all, in category, single)
307 e/E [<cat>|<var>]\tEdit variables (all, in category, single)
309 c\t\t\tList categories
310 v/V [<cat>|<var>]List Variables (all, in category, single)
312 Typical usage involves: u, [l,] w, r, q
316 groups_parse = matcher_mainloop_0arg.match(answer)
319 command = groups_parse.group('command')
322 groups_parse = matcher_mainloop_1arg.match(answer)
324 command = groups_parse.group('command')
325 arg=groups_parse.group('arg')
327 print ("Unknown command >%s< -- use h for help" % answer)
330 show_comments=command.isupper()
331 command=command.lower()
337 variables=list_category (cdef,arg)
339 # category_id as the category name
340 # variables as the list of variable names
344 (category,variable)=cdef.locate_varname(arg)
346 # category/variable as output by locate_varname
349 print "%s: no such category or variable" % arg
352 if (command in "qQ"):
353 # todo check confirmation
355 elif (command == "w"):
356 global defined_flavour
358 # Confirm that various constraints are met before saving file.
359 validate_variables = {"PLC_API":"MAINTENANCE_USER","PLC":"ROOT_USER"}
360 validated_variables = cwrite.verify(cdef, cread, validate_variables)
361 validator(validated_variables)
362 cwrite.save(site_config)
363 except ConfigurationException, e:
364 print "Save failed due to a configuration exception: %s" % e
367 print traceback.print_exc()
368 print ("Could not save -- fix write access on %s" % site_config)
370 print "Wrote",site_config
371 consolidate(default_config, site_config, consolidated_config)
372 print "You might want to type 'r' (restart plc), 'R' (reload plc) or 'q' (quit)"
373 elif (command == "u"):
376 for varname in globals['usual_variables']:
377 (category,variable) = cdef.locate_varname(varname)
378 prompt_variable(cdef, cread, cwrite, category, variable, False)
379 except Exception, inst:
380 if (str(inst) != 'BailOut'):
382 elif (command == "r"):
384 elif (command == "R"):
386 elif (command == "c"):
387 print_categories(cread)
388 elif (command in "eE"):
390 prompt_variables_all(cdef, cread, cwrite,show_comments)
391 elif mode == 'CATEGORY':
392 prompt_variables_category(cdef,cread,cwrite,category_id,show_comments)
393 elif mode == 'VARIABLE':
395 prompt_variable (cdef,cread,cwrite,category,variable,
397 except Exception, inst:
398 if (str(inst) != 'BailOut'):
400 elif (command in "vVsSlL"):
401 show_value=(command in "sSlL")
402 (c1,c2,c3) = (cdef, cread, cwrite)
403 if (command in "lL"):
404 (c1,c2,c3) = (cwrite,cwrite,cwrite)
406 show_variables_all(c1,c2,c3,show_value,show_comments)
407 elif mode == 'CATEGORY':
408 show_variables_category(c1,c2,c3,category_id,show_value,show_comments)
409 elif mode == 'VARIABLE':
410 show_variable (c1,c2,c3,category,variable,show_value,show_comments)
412 print ("Unknown command >%s< -- use h for help" % answer)
415 # creates directory for file if not yet existing
416 def check_dir (config_file):
417 dirname = os.path.dirname (config_file)
418 if (not os.path.exists (dirname)):
420 os.makedirs(dirname,0755)
422 print "Cannot create dir %s for file %s - error=[%s] - exiting" % (dirname,config_file,e)
425 if (not os.path.exists (dirname)):
426 print "Cannot create dir %s for file %s - exiting" % (dirname,config_file)
429 print "Created directory %s" % dirname
434 parser = OptionParser(usage=usage(), version="%prog " + release_rev + release_url)
435 (config,args) = parser.parse_args()
437 parser.error("too many arguments")
439 # use any provided arg as advertised
441 (default_config,site_config,consolidated_config) = (globals['def_default_config'],
442 globals['def_site_config'],
443 globals['def_consolidated_config'])
445 default_config=args[0]
449 consolidated_config=args[2]
451 for c in (default_config,site_config,consolidated_config):
455 # the default settings only - read only
456 cdef = PLCConfiguration(default_config)
458 # in effect : default settings + local settings - read only
459 cread = PLCConfiguration(default_config)
461 except ConfigurationException, e:
462 print ("Error %s in default config file %s" %(e,default_config))
465 print traceback.print_exc()
466 print ("default config files %s not found, is myplc installed ?" % default_config)
470 # local settings only, will be modified & saved
471 cwrite=PLCConfiguration()
474 cread.load(site_config)
475 cwrite.load(site_config)
477 cwrite = PLCConfiguration()
479 mainloop (cdef, cread, cwrite, default_config, site_config, consolidated_config)
482 if __name__ == '__main__':