#!/bin/env python
+import os
import sys
+import re
+import time
+import traceback
+import types
import readline
-import plc_config
+from StringIO import StringIO
+from optparse import OptionParser
+from sfa.util.config import Config
def validator(validated_variables):
pass
'validator':validator,
}
+
+# GLOBAL VARIABLES
+#
+release_id = "$Id$"
+release_rev = "$Revision$"
+release_url = "$URL$"
+
+g_configuration=None
+usual_variables=None
+config_dir=None
+service=None
+
+def noop_validator(validated_variables):
+ pass
+
+# historically we could also configure the devel pkg....
+def init_configuration ():
+ global g_configuration
+ global usual_variables, config_dir, service
+
+ usual_variables=g_configuration["usual_variables"]
+ config_dir=g_configuration["config_dir"]
+ service=g_configuration["service"]
+
+ global def_default_config, def_site_config, def_consolidated_config
+ def_default_config= "%s/default_config.xml" % config_dir
+ def_site_config = "%s/configs/site_config" % config_dir
+ def_consolidated_config = "%s/%s_config" % (config_dir, service)
+
+ 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
+ r\t\t\tRestart %(service)s service
+ R\t\t\tReload %(service)s service (rebuild config files for sh, python....)
+ 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>]\tList Variables (all, in category, single)
+---
+Typical usage involves: u, [l,] w, r, q
+""" % globals()
+
+def usage ():
+ command_usage="%prog [options] [default-xml [site-xml [consolidated-xml]]]"
+ init_configuration ()
+ 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)
+ return command_usage
+
+####################
+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):
+ value = config.get (category_id, variable_id)
+ return value
+
+def get_type (config, category_id, variable_id):
+ value = config.get (category_id, variable_id)
+ #return variable['type']
+ return str
+
+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):
+ varname = category_id +"_"+ variable_id
+ config.locate_varname(varname)
+ return varname
+
+# 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):
+ global service
+ try:
+ conso = Config(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 ():
+ global service
+ os.system("set -x ; service %s reload" % service)
+
+####################
+def restart_service ():
+ global service
+ 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):
+
+
+ category_id = category
+ variable_id = variable
+
+ while True:
+ default_value = get_value(cdef,category_id,variable_id)
+ variable_type = get_type(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 == "?"):
+ 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:
+ if cdef.validate_type(variable_type, answer):
+ cwrite.set(category_id, variable_id, answer)
+ else:
+ print "Not a valid value"
+
+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<command>[uUwrRqlLsSeEcvVhH\?])[ \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)
+
+def mainloop (cdef, cread, cwrite, default_config, site_config, consolidated_config):
+ global service
+ 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"):
+ 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()
+
+ 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":
+ try:
+ # Confirm that various constraints are met before saving file.
+ validate_variables = g_configuration.get('validate_variables',{})
+ validated_variables = cwrite.verify(cdef, cread, validate_variables)
+ validator = g_configuration.get('validator',noop_validator)
+ validator(validated_variables)
+ cwrite.save(site_config)
+ except:
+ print "Save failed due to a configuration exception:"
+ print traceback.print_exc()
+ 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 %s), 'R' (reload %s) or 'q' (quit)" % \
+ (service,service))
+ elif command in "uU":
+ global usual_variables
+ try:
+ for varname in usual_variables:
+ (category,variable) = cdef.locate_varname(varname)
+ if not (category is None and variable is None):
+ 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 due to %s - exiting" % (dirname,e)
+ sys.exit(1)
+
+ if (not os.path.exists (dirname)):
+ print "Cannot create dir %s - exiting" % dirname
+ sys.exit(1)
+ else:
+ print "Created directory %s" % dirname
+
+####################
+def optParserSetup(configuration):
+ parser = OptionParser(usage=usage(), version="%prog " + release_rev + release_url )
+ parser.set_defaults(config_dir=configuration['config_dir'],
+ service=configuration['service'],
+ usual_variables=configuration['usual_variables'])
+ parser.add_option("","--configdir",dest="config_dir",help="specify configuration directory")
+ parser.add_option("","--service",dest="service",help="specify /etc/init.d style service name")
+ parser.add_option("","--usual_variable",dest="usual_variables",action="append", help="add a usual variable")
+ return parser
+
+def main(command,argv,configuration):
+ global g_configuration
+ g_configuration=configuration
+
+ parser = optParserSetup(configuration)
+ (config,args) = parser.parse_args()
+ if len(args)>3:
+ parser.error("too many arguments")
+
+ configuration['service']=config.service
+ configuration['usual_variables']=config.usual_variables
+ configuration['config_dir']=config.config_dir
+ # add in new usual_variables defined on the command line
+ for usual_variable in config.usual_variables:
+ if usual_variable not in configuration['usual_variables']:
+ configuration['usual_variables'].append(usual_variable)
+
+ # intialize configuration
+ init_configuration()
+
+ (default_config,site_config,consolidated_config) = (def_default_config, def_site_config, 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 = Config(default_config)
+
+ # in effect : default settings + local settings - read only
+ cread = Config(default_config)
+ 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
+ config_filename = "%s/sfa_config" % config.config_dir
+ try:
+ cwrite=Config(config_filename)
+ except ConfigParser.MissingSectionHeaderError:
+ # remove legacy config
+ os.unlink(config_filename)
+ cwrite=Config(config_filename)
+
+ try:
+ cread.load(site_config)
+ cwrite.load(site_config)
+ except:
+ cwrite = Config()
+
+ mainloop (cdef, cread, cwrite, default_config, site_config, consolidated_config)
+ return 0
+
if __name__ == '__main__':
command=sys.argv[0]
argv = sys.argv[1:]
- plc_config.main(command,argv,configuration)
+ main(command,argv,configuration)
-##
-# SFA Configuration Info
-#
-# This module holds configuration parameters for SFA. There are two
-# main pieces of information that are used: the database connection and
-# the PLCAPI connection
-##
+#!/usr/bin/python
+import sys
+import os
+import ConfigParser
+import tempfile
+from sfa.util.xml import XML
-##
-# SFA uses a MYSQL database to store records. This database may be
-# co-located with the PLC database, or it may be a separate database. The
-# following parameters define the connection to the database.
-#
-# Note that SFA does not access any of the PLC databases directly via
-# a mysql connection; All PLC databases are accessed via PLCAPI.
-
-import os.path
-import traceback
+default_config = \
+"""
+"""
class Config:
- """
- Parse the bash/Python/PHP version of the configuration file. Very
- fast but no type conversions.
- """
-
- def __init__(self, config_file = "/etc/sfa/sfa_config.py"):
- self.config_file = None
- self.config_path = None
- self.data_path = None
- self.load(config_file)
-
- def load(self, config_file):
- try:
- execfile(config_file, self.__dict__)
- self.config_file = config_file
- # path to configuration data
- self.config_path = os.path.dirname(config_file)
-
- ### xxx todo implement defaults in default_config.xml
- # path to server data
- if not hasattr(self, 'SFA_DATA_DIR'):
- # default to /var/lib/sfa not specified in config
- self.SFA_DATA_DIR="/var/lib/sfa"
- self.data_path = self.SFA_DATA_DIR
+
+ def __init__(self, config_file='/etc/sfa/sfa_config'):
+ self.config = ConfigParser.ConfigParser()
+ self.filename = config_file
+ if not os.path.isfile(self.filename):
+ self.create(self.filename)
+ self.load(self.filename)
+
+ def create(self, filename):
+ if not os.path.exists(os.path.dirname(filename)):
+ os.makedirs(os.path.dirname(filename))
+ configfile = open(filename, 'w')
+ configfile.write(default_config)
+ configfile.close()
+
+
+ def load(self, filename):
+ if filename:
+ if filename.endswith('.xml'):
+ try:
+ self.load_xml(filename)
+ except:
+ raise
+ self.config.read(filename)
else:
- self.data_path = self.SFA_DATA_DIR
+ self.config.read(filename)
+ self.set_attributes()
- # path to config data
- if not hasattr(self, 'SFA_CONFIG_DIR'):
- # default to /etc/sfa not specified in config
- self.SFA_CONFIG_DIR="/etc/sfa"
-
- if not hasattr(self, 'SFA_REGISTRY_LEVEL1_AUTH'):
- self.SFA_REGISTRY_LEVEL1_AUTH=None
-
- # create the data directory if it doesnt exist
- if not os.path.isdir(self.SFA_DATA_DIR):
- try:
- os.mkdir(self.SFA_DATA_DIR)
- except: pass
-
- except IOError, e:
- raise IOError, "Could not find or load the configuration file: %s" % config_file
-
- def get_trustedroots_dir(self):
- return self.config_path + os.sep + 'trusted_roots'
-
- def get_openflow_aggrMgr_info(self):
- aggr_mgr_ip = 'localhost'
- if (hasattr(self,'OPENFLOW_AGGREGATE_MANAGER_IP')):
- aggr_mgr_ip = self.OPENFLOW_AGGREGATE_MANAGER_IP
-
- aggr_mgr_port = 2603
- if (hasattr(self,'OPENFLOW_AGGREGATE_MANAGER_PORT')):
- aggr_mgr_port = self.OPENFLOW_AGGREGATE_MANAGER_PORT
-
- return (aggr_mgr_ip,aggr_mgr_port)
-
- def get_interface_hrn(self):
- if (hasattr(self,'SFA_INTERFACE_HRN')):
- return self.SFA_INTERFACE_HRN
- else:
- return "plc"
-
- # TODO: find a better place to put this method
- def get_max_aggrMgr_info(self):
- am_apiclient_path = '/usr/local/MAXGENI_AM_APIClient'
- if (hasattr(self,'MAXGENI_AM_APICLIENT_PATH')):
- am_client_path = self.MAXGENI_AM_APICLIENT_PATH
-
- am_url = 'https://geni.dragon.maxgigapop.net:8443/axis2/services/AggregateGENI'
- if (hasattr(self,'MAXGENI_AM_URL')):
- am_url = self.MAXGENI_AM_URL
-
- return (am_apiclient_path,am_url)
-
+ def load_xml(self, filename):
+ xml = XML(filename)
+ categories = xml.xpath('//configuration/variables/category')
+ for category in categories:
+ section_name = category.get('id')
+ if not self.config.has_section(section_name):
+ self.config.add_section(section_name)
+ options = category.xpath('./variablelist/variable')
+ for option in options:
+ option_name = option.get('id')
+ value = option.xpath('./value')[0].text
+ if not value:
+ value = ""
+ self.config.set(section_name, option_name, value)
+
+
+ def locate_varname(self, varname):
+ varname = varname.lower()
+ sections = self.config.sections()
+ section_name = ""
+ var_name = ""
+ for section in sections:
+ if varname.startswith(section.lower()) and len(section) > len(section_name):
+ section_name = section.lower()
+ var_name = varname.replace(section_name, "")[1:]
+ if not self.config.has_option(section_name, var_name):
+ raise ConfigParser.NoOptionError(varname, section_name)
+ return (section_name, var_name)
+
+ def set_attributes(self):
+ sections = self.config.sections()
+ for section in sections:
+ for item in self.config.items(section):
+ name = "%s_%s" % (section, item[0])
+ value = item[1]
+ setattr(self, name, value)
+ setattr(self, name.upper(), value)
+
+
+ def verify(self, config1, config2, validate_method):
+ return True
+
+ def validate_type(self, var_type, value):
+ return True
+
+ def dump(self, sections = []):
+ if not sections:
+ sections = self.config.sections()
+ print ""
+ for section in sections:
+ print "[%s]" % section
+ for item in self.config.items(section):
+ print "%s=%s" % (item[0], item[1])
+ print ""
+
+ def write(self, filename=None):
+ if not filename:
+ filename = self.filename
+ configfile = open(filename, 'w')
+ self.config.write(configfile)
+
+ def save(self, filename=None):
+ self.write(filename)
+
+ def __getattr__(self, attr):
+ return getattr(self.config, attr)
+
+if __name__ == '__main__':
+ filename = None
+ if len(sys.argv) > 1:
+ filename = sys.argv[1]
+ config = Config(filename)
+ else:
+ config = Config()
+ config.dump()
+