--- /dev/null
-if "B10_FROM_BUILD" in os.environ:
- DATA_PATH = os.environ['B10_FROM_BUILD'] + "/src/bin/ddns"
+ #!@PYTHON@
+
+ # Copyright (C) 2011 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.
+
+
+ import sys; sys.path.append ('@@PYTHONPATH@@')
+ import isc
+ import bind10_config
+ from isc.dns import *
+ from isc.config.ccsession import *
+ from isc.cc import SessionError, SessionTimeout
+ import isc.util.process
+
+ from isc.log_messages.ddns_messages import *
+
+ from optparse import OptionParser, OptionValueError
+ import os
+ import signal
+
+ isc.log.init("b10-ddns")
+ logger = isc.log.Logger("ddns")
+
+ DATA_PATH = bind10_config.DATA_PATH
++if "B10_FROM_SOURCE" in os.environ:
++ DATA_PATH = os.environ['B10_FROM_SOURCE'] + "/src/bin/ddns"
+ SPECFILE_LOCATION = DATA_PATH + "/ddns.spec"
+
+
+ isc.util.process.rename()
+
+ class DDNSConfigError(Exception):
+ '''An exception indicating an error in updating ddns configuration.
+
+ This exception is raised when the ddns process encounters an error in
+ handling configuration updates. Not all syntax error can be caught
+ at the module-CC layer, so ddns needs to (explicitly or implicitly)
+ validate the given configuration data itself. When it finds an error
+ it raises this exception (either directly or by converting an exception
+ from other modules) as a unified error in configuration.
+ '''
+ pass
+
+ class DDNSSessionError(Exception):
+ '''An exception raised for some unexpected events during a ddns session.
+ '''
+ pass
+
+ class DDNSSession:
+ '''Class to handle one DDNS update'''
+
+ def __init__(self):
+ '''Initialize a DDNS Session'''
+ pass
+
+ class DDNSServer:
+ def __init__(self, cc_session=None):
+ '''
+ Initialize the DDNS Server.
+ This sets up a ModuleCCSession for the BIND 10 system.
+ Parameters:
+ cc_session: If None (default), a new ModuleCCSession will be set up.
+ If specified, the given session will be used. This is
+ mainly used for testing.
+ '''
+ if cc_session is not None:
+ self._cc = cc_session
+ else:
+ self._cc = isc.config.ModuleCCSession(SPECFILE_LOCATION,
+ self.config_handler,
+ self.command_handler)
+
+ self._config_data = self._cc.get_full_config()
+ self._cc.start()
+ self._shutdown = False
+
+ def config_handler(self, new_config):
+ '''Update config data.'''
+ answer = create_answer(0)
+ return answer
+
+ def command_handler(self, cmd, args):
+ '''
+ Handle a CC session command, as sent from bindctl or other
+ BIND 10 modules.
+ '''
+ if cmd == "shutdown":
+ logger.info(DDNS_RECEIVED_SHUTDOWN_COMMAND)
+ self.trigger_shutdown()
+ answer = create_answer(0)
+ else:
+ answer = create_answer(1, "Unknown command: " + str(cmd))
+ return answer
+
+ def trigger_shutdown(self):
+ '''Initiate a shutdown sequence.
+
+ This method is expected to be called in various ways including
+ in the middle of a signal handler, and is designed to be as simple
+ as possible to minimize side effects. Actual shutdown will take
+ place in a normal control flow.
+
+ '''
+ logger.info(DDNS_SHUTDOWN)
+ self._shutdown = True
+
+ def shutdown_cleanup(self):
+ '''
+ Perform any cleanup that is necessary when shutting down the server.
+ Do NOT call this to initialize shutdown, use trigger_shutdown().
+
+ Currently, it does nothing, but cleanup routines are expected.
+ '''
+ pass
+
+ def run(self):
+ '''
+ Get and process all commands sent from cfgmgr or other modules.
+ This loops waiting for events until self.shutdown() has been called.
+ '''
+ logger.info(DDNS_RUNNING)
+ while not self._shutdown:
+ # We do not catch any exceptions here right now, but this would
+ # be a good place to catch any exceptions that b10-ddns can
+ # recover from. We currently have no exception hierarchy to
+ # make such a distinction easily, but once we do, this would
+ # be the place to catch.
+ self._cc.check_command(False)
+ self.shutdown_cleanup()
+ logger.info(DDNS_STOPPED)
+
+ def create_signal_handler(ddns_server):
+ '''
+ This creates a signal_handler for use in set_signal_handler, which
+ shuts down the given DDNSServer (or any object that has a shutdown()
+ method)
+ '''
+ def signal_handler(signal, frame):
+ '''
+ Handler for process signals. Since only signals to shut down are sent
+ here, the actual signal is not checked and the server is simply shut
+ down.
+ '''
+ ddns_server.trigger_shutdown()
+ return signal_handler
+
+ def set_signal_handler(signal_handler):
+ '''
+ Sets the signal handler(s).
+ '''
+ signal.signal(signal.SIGTERM, signal_handler)
+ signal.signal(signal.SIGINT, signal_handler)
+
+ def set_cmd_options(parser):
+ '''
+ Helper function to set command-line options
+ '''
+ parser.add_option("-v", "--verbose", dest="verbose", action="store_true",
+ help="display more about what is going on")
+
+ def main(ddns_server=None):
+ '''
+ The main function.
+ Parameters:
+ ddns_server: If None (default), a DDNSServer object is initialized.
+ If specified, the given DDNSServer will be used. This is
+ mainly used for testing.
+ cc_session: If None (default), a new ModuleCCSession will be set up.
+ If specified, the given session will be used. This is
+ mainly used for testing.
+ '''
+ try:
+ parser = OptionParser()
+ set_cmd_options(parser)
+ (options, args) = parser.parse_args()
+ if options.verbose:
+ print("[b10-ddns] Warning: -v verbose option is ignored at this point.")
+
+ if ddns_server is None:
+ ddns_server = DDNSServer()
+ set_signal_handler(create_signal_handler(ddns_server))
+ ddns_server.run()
+ except KeyboardInterrupt:
+ logger.info(DDNS_STOPPED_BY_KEYBOARD)
+ except SessionError as e:
+ logger.error(DDNS_CC_SESSION_ERROR, str(e))
+ except ModuleCCSessionError as e:
+ logger.error(DDNS_MODULECC_SESSION_ERROR, str(e))
+ except DDNSConfigError as e:
+ logger.error(DDNS_CONFIG_ERROR, str(e))
+ except SessionTimeout as e:
+ logger.error(DDNS_CC_SESSION_TIMEOUT_ERROR)
+ except Exception as e:
+ logger.error(DDNS_UNCAUGHT_EXCEPTION, type(e).__name__, str(e))
+
+ if '__main__' == __name__:
+ main()