Coverage for src/lib/python/isc/config/cfgmgr : 90%
        
        
Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
| 
 # Copyright (C) 2010 Internet Systems Consortium. # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM # DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL # INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, # INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING # FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 
 
 It stores the system configuration, and sends updates of the configuration to the modules that need them. """ 
 
 
 """This exception is thrown when there is an error while reading the current configuration on startup.""" 
 """This exception is thrown when the currently stored configuration is not found, or appears empty.""" 
 """This class hold the actual configuration information, and reads it from and writes it to persistent storage""" 
 """Initialize the data for the configuration manager, and set the version and path for the data store. Initializing this does not yet read the database, a call to read_from_file is needed for that. 
 In case the file_name is absolute, data_path is ignored and the directory where the file_name lives is used instead. """ else: 
 """Read the current configuration found in the file file_name. If file_name is absolute, data_path is ignored. Otherwise we look for the file_name in data_path directory. 
 If the file does not exist, a ConfigManagerDataEmpty exception is raised. If there is a parse error, or if the data in the file has the wrong version, a ConfigManagerDataReadError is raised. In the first case, it is probably safe to log and ignore. In the case of the second exception, the best way is probably to report the error and stop loading the system. """ # handle different versions here # If possible, we automatically convert to the new # scheme and update the configuration # If not, we raise an exception # only format change, no other changes necessary file_config['version'] = 2 logger.info(CFGMGR_AUTOMATIC_CONFIG_DATABASE_UPDATE, 1, 2) config.data = file_config else: else: raise ConfigManagerDataReadError("Cannot load configuration file: version %d not yet supported" % file_config['version']) else: raise ConfigManagerDataReadError("No version information in configuration file " + config.db_filename) # if IOError is 'no such file or directory', then continue # (raise empty), otherwise fail (raise error) else: raise ConfigManagerDataReadError("Can't read configuration file: " + str(ioe)) finally: 
 """Writes the current configuration data to a file. If output_file_name is not specified, the file used in read_from_file is used.""" 
 prefix="b10-config.db.", dir=self.data_path, delete=False) else: except IOError as ioe: logger.error(CFGMGR_IOERROR_WHILE_WRITING_CONFIGURATION, ioe) except OSError as ose: logger.error(CFGMGR_OSERROR_WHILE_WRITING_CONFIGURATION, ose) os.remove(filename) except OSError: # Ok if we really can't delete it anymore, leave it pass 
 """Renames the given configuration file to the given new file name, if it exists. If it does not exist, nothing happens. If old_file_name is None (default), the file used in read_from_file is used. If new_file_name is None (default), the file old_file_name appended with .bak is used. If that file exists already, .1 is appended. If that file exists, .2 is appended, etc. """ old_file_name = self.db_filename 
 """Returns True if the data contained is equal. data_path and db_filename may be different.""" 
 """Creates a configuration manager. The data_path is the path to the directory containing the configuraton file, database_filename points to the configuration file. If session is set, this will be used as the communication channel session. If not, a new session will be created. The ability to specify a custom session is for testing purposes and should not be needed for normal usage.""" clear_config=False): """Initialize the configuration manager. The data_path string is the path to the directory where the configuration is stored (in <data_path>/<database_filename> or in <database_filename>, if it is absolute). The database_filename is the config file to load. Session is an optional cc-channel session. If this is not given, a new one is created. If clear_config is True, the configuration file is renamed and a new one is created.""" # Virtual modules are the ones which have no process running. The # checking of validity is done by functions presented here instead # of some other process self.config.rename_config_file() else: # As a core module, CfgMgr is different than other modules, # as it does not use a ModuleCCSession, and hence needs # to handle logging config on its own isc.config.module_spec_from_file( path_search('logging.spec', bind10_config.PLUGIN_PATHS))) # store the logging 'module' name for easier reference 
 ccsession.default_logconfig_handler(config[self.log_module_name], self.log_config_data) 
 """Notifies the Boss module that the Config Manager is running""" 
 """Adds a ModuleSpec""" 
 """Adds a virtual module with its spec and checking function.""" 
 """Removes the full ModuleSpec for the given module_name. Also removes the virtual module check function if it was present. Does nothing if the module was not present.""" 
 """Returns the full ModuleSpec for the module with the given module_name. If no module name is given, a dict will be returned with 'name': module_spec values. If the module name is given, but does not exist, an empty dict is returned""" else: # TODO: log error? else: 
 """Returns a dict containing 'module_name': config_spec for all modules. If name is specified, only that module will be included""" else: 
 """Returns a dict containing 'module_name': commands_spec for all modules. If name is specified, only that module will be included""" else: 
 """Returns a dict containing 'module_name': statistics_spec for all modules. If name is specified, only that module will be included""" else: 
 """Read the current configuration from the file specificied at init()""" self.\ database_filename) # ok, just start with an empty config self.database_filename) 
 """Write the current configuration to the file specificied at init()""" 
 """Private function that handles the 'get_module_spec' command""" # this is a ModuleSpec object. Extract the # internal spec. spec = spec.get_full_spec() else: else: else: 
 """Private function that handles the 'get_config' command where the command has been checked to be a dict""" # no data is ok, that means we have nothing that # deviates from default values else: 
 """Private function that handles the 'get_config' command""" else: else: 
 # the answer comes (or does not come) from the relevant module # so we need a variable to see if we got it # todo: use api (and check the data against the definition?) else: 
 # The command to send use_part) 
 # TODO: This design might need some revisiting. We might want some # polymorphism instead of branching. But it just might turn out it # will get solved by itself when we move everything to virtual modules # (which is possible solution to the offline configuration problem) # or when we solve the incorect behaviour here when a config is # rejected (spying modules don't know it was rejected and some modules # might have been commited already). # The module is virtual, so call it to get the answer # OK, it is successful, send the notify, but don't wait # for answer else: # Make sure just a validating plugin don't kill the whole manager # Provide answer else: # Real module, send it over the wire to it # send out changed info and wait for answer # replace 'our' answer with that of the module except isc.cc.SessionTimeout: answer = ccsession.create_answer(1, "Timeout waiting for answer from " + module_name) except isc.cc.SessionError as se: logger.error(CFGMGR_BAD_UPDATE_RESPONSE_FROM_MODULE, module_name, se) answer = ccsession.create_answer(1, "Unable to parse response from " + module_name + ": " + str(se)) else: 
 # The format of the command is a dict with module->newconfig # sets, so we simply call set_config_module for each of those got_error = True err_list.append("No answer message from " + module) else: got_error = True err_list.append(val) # if Logging config is in there, update our config as well else: # TODO rollback changes that did get through, should we re-send update? self.config.data = old_data return ccsession.create_answer(1, " ".join(err_list)) 
 """Private function that handles the 'set_config' command""" 
 else: 
 
 """Private function that handles the 'module_spec' command""" # todo: validate? (no direct access to spec as # todo: use ModuleSpec class # todo: error checking (like keyerrors) spec.get_full_spec()) 
 """Private function that handles a 'stopping' command; The argument is of the form { 'module_name': <name> }. If the module is known, it is removed from the known list, and a message is sent to the Cmdctl channel to remove it as well. If it is unknown, the message is ignored.""" # This command is not expected to be answered 
 """Sends the given module spec for the given module name to Cmdctl. Parameters: module_name: A string with the name of the module spec: dict containing full module specification, as returned by ModuleSpec.get_full_spec(). This argument may also be None, in which case it signals Cmdctl to remove said module from its list. No response from Cmdctl is expected.""" [ module_name, spec ]) 
 """Handle a command from the cc channel to the configuration manager""" else: else: 
 """Runs the configuration manager.""" # we just wait eternally for any command here, so disable # timeouts for this specific recv # and set it back to whatever we default to # ignore 'None' value (even though they should not occur) # and messages that are answers to questions we did # not ask # Only respond if there actually is something to respond with  |