def __handle_set_config_all(self, cmd): old_data = copy.deepcopy(self.config.data) got_error = False err_list = [] # The format of the command is a dict with module->newconfig # sets, so we simply call set_config_module for each of those for module in cmd: if module != "version": answer = self.__handle_set_config_module(module, cmd[module]) if answer == None: got_error = True err_list.append("No answer message from " + module) else: rcode, val = ccsession.parse_answer(answer) if rcode != 0: got_error = True err_list.append(val) if not got_error: # if Logging config is in there, update our config as well self.check_logging_config(cmd); self.write_config() return ccsession.create_answer(0) 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))
def __handle_get_config(self, cmd): """Private function that handles the 'get_config' command""" if cmd != None: if type(cmd) == dict: return self.__handle_get_config_dict(cmd) else: return ccsession.create_answer(1, "Bad get_config command, argument not a dict") else: return ccsession.create_answer(0, self.config.data)
def __handle_get_config_dict(self, cmd): """Private function that handles the 'get_config' command where the command has been checked to be a dict""" if 'module_name' in cmd and cmd['module_name'] != '': module_name = cmd['module_name'] try: return ccsession.create_answer(0, data.find(self.config.data, module_name)) except data.DataNotFoundError as dnfe: # no data is ok, that means we have nothing that # deviates from default values return ccsession.create_answer(0, { 'version': config_data.BIND10_CONFIG_DATA_VERSION }) else: return ccsession.create_answer(1, "Bad module_name in get_config command")
def __handle_set_config(self, cmd): """Private function that handles the 'set_config' command""" answer = None if cmd == None: return ccsession.create_answer(1, "Wrong number of arguments") if len(cmd) == 2: answer = self.__handle_set_config_module(cmd[0], cmd[1]) elif len(cmd) == 1: answer = self.__handle_set_config_all(cmd[0]) else: answer = ccsession.create_answer(1, "Wrong number of arguments") if not answer: answer = ccsession.create_answer(1, "No answer message from " + cmd[0]) return answer
def __handle_module_spec(self, spec): """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) answer = {} self.set_module_spec(spec) self._send_module_spec_to_cmdctl(spec.get_module_name(), spec.get_full_spec()) return ccsession.create_answer(0)
def __handle_get_module_spec(self, cmd): """Private function that handles the 'get_module_spec' command""" answer = {} if cmd != None: if type(cmd) == dict: if 'module_name' in cmd and cmd['module_name'] != '': module_name = cmd['module_name'] spec = self.get_module_spec(cmd['module_name']) if type(spec) != type({}): # this is a ModuleSpec object. Extract the # internal spec. spec = spec.get_full_spec() answer = ccsession.create_answer(0, spec) else: answer = ccsession.create_answer(1, "Bad module_name in get_module_spec command") else: answer = ccsession.create_answer(1, "Bad get_module_spec command, argument not a dict") else: answer = ccsession.create_answer(0, self.get_module_spec()) return answer
def handle_msg(self, msg): """Handle a command from the cc channel to the configuration manager""" answer = {} cmd, arg = ccsession.parse_command(msg) if cmd: if cmd == ccsession.COMMAND_GET_COMMANDS_SPEC: answer = ccsession.create_answer(0, self.get_commands_spec()) elif cmd == ccsession.COMMAND_GET_STATISTICS_SPEC: answer = ccsession.create_answer(0, self.get_statistics_spec()) elif cmd == ccsession.COMMAND_GET_MODULE_SPEC: answer = self.__handle_get_module_spec(arg) elif cmd == ccsession.COMMAND_GET_CONFIG: answer = self.__handle_get_config(arg) elif cmd == ccsession.COMMAND_SET_CONFIG: answer = self.__handle_set_config(arg) elif cmd == ccsession.COMMAND_MODULE_STOPPING: answer = self.__handle_module_stopping(arg) elif cmd == ccsession.COMMAND_SHUTDOWN: self.running = False answer = ccsession.create_answer(0) elif cmd == ccsession.COMMAND_MODULE_SPEC: try: answer = self.__handle_module_spec(isc.config.ModuleSpec(arg)) except isc.config.ModuleSpecError as dde: answer = ccsession.create_answer(1, "Error in data definition: " + str(dde)) else: answer = ccsession.create_answer(1, "Unknown command: " + str(cmd)) else: answer = ccsession.create_answer(1, "Unknown message format: " + str(msg)) return answer
def __handle_set_config_module(self, module_name, cmd): # the answer comes (or does not come) from the relevant module # so we need a variable to see if we got it answer = None # todo: use api (and check the data against the definition?) old_data = copy.deepcopy(self.config.data) conf_part = data.find_no_exc(self.config.data, module_name) update_cmd = None use_part = None if conf_part: data.merge(conf_part, cmd) use_part = conf_part else: conf_part = data.set(self.config.data, module_name, {}) data.merge(conf_part[module_name], cmd) use_part = conf_part[module_name] # The command to send update_cmd = ccsession.create_command(ccsession.COMMAND_CONFIG_UPDATE, 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). if module_name in self.virtual_modules: # The module is virtual, so call it to get the answer try: error = self.virtual_modules[module_name](use_part) if error is None: answer = ccsession.create_answer(0) # OK, it is successful, send the notify, but don't wait # for answer seq = self.cc.group_sendmsg(update_cmd, module_name) else: answer = ccsession.create_answer(1, error) # Make sure just a validating plugin don't kill the whole manager except Exception as excp: # Provide answer answer = ccsession.create_answer(1, "Exception: " + str(excp)) else: # Real module, send it over the wire to it # send out changed info and wait for answer seq = self.cc.group_sendmsg(update_cmd, module_name) try: # replace 'our' answer with that of the module answer, env = self.cc.group_recvmsg(False, seq) 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)) if answer: rcode, val = ccsession.parse_answer(answer) if rcode == 0: self.write_config() else: self.config.data = old_data return answer
def __handle_set_config_module(self, module_name, cmd): # the answer comes (or does not come) from the relevant module # so we need a variable to see if we got it answer = None # todo: use api (and check the data against the definition?) old_data = copy.deepcopy(self.config.data) conf_part = data.find_no_exc(self.config.data, module_name) update_cmd = None use_part = None if conf_part: data.merge(conf_part, cmd) use_part = conf_part else: conf_part = data.set(self.config.data, module_name, {}) data.merge(conf_part[module_name], cmd) use_part = conf_part[module_name] # The command to send update_cmd = ccsession.create_command(ccsession.COMMAND_CONFIG_UPDATE, 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 incorrect behaviour here when a config is # rejected (spying modules don't know it was rejected and some modules # might have been committed already). if module_name in self.virtual_modules: # The module is virtual, so call it to get the answer try: error = self.virtual_modules[module_name](use_part) if error is None: answer = ccsession.create_answer(0) # OK, it is successful, send the notify, but don't wait # for answer seq = self.cc.group_sendmsg(update_cmd, module_name) else: answer = ccsession.create_answer(1, error) # Make sure just a validating plugin don't kill the whole manager except Exception as excp: # Provide answer answer = ccsession.create_answer(1, "Exception: " + str(excp)) else: # Real module, send it over the wire to it # send out changed info and wait for answer seq = self.cc.group_sendmsg(update_cmd, module_name) try: # replace 'our' answer with that of the module answer, env = self.cc.group_recvmsg(False, seq) 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)) if answer: rcode, val = ccsession.parse_answer(answer) if rcode == 0: self.write_config() else: self.config.data = old_data return answer