ddns.py.in 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. #!@PYTHON@
  2. # Copyright (C) 2010 Internet Systems Consortium.
  3. #
  4. # Permission to use, copy, modify, and distribute this software for any
  5. # purpose with or without fee is hereby granted, provided that the above
  6. # copyright notice and this permission notice appear in all copies.
  7. #
  8. # THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
  9. # DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
  10. # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
  11. # INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
  12. # INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
  13. # FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
  14. # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
  15. # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  16. import sys; sys.path.append ('@@PYTHONPATH@@')
  17. import isc
  18. import bind10_config
  19. from isc.dns import *
  20. from isc.config.ccsession import *
  21. from isc.cc import SessionError, SessionTimeout
  22. import isc.util.process
  23. from isc.log_messages.ddns_messages import *
  24. from optparse import OptionParser, OptionValueError
  25. import os
  26. import signal
  27. import threading
  28. isc.log.init("b10-ddns")
  29. logger = isc.log.Logger("ddns")
  30. DATA_PATH = bind10_config.DATA_PATH
  31. if "B10_FROM_BUILD" in os.environ:
  32. DATA_PATH = DATA_PATH + "/src/bin/ddns"
  33. SPECFILE_LOCATION = DATA_PATH + "/ddns.spec"
  34. isc.util.process.rename()
  35. class DDNSConfigError(Exception):
  36. """An exception indicating an error in updating ddns configuration.
  37. This exception is raised when the ddns process encouters an error in
  38. handling configuration updates. Not all syntax error can be caught
  39. at the module-CC layer, so ddns needs to (explicitly or implicitly)
  40. validate the given configuration data itself. When it finds an error
  41. it raises this exception (either directly or by converting an exception
  42. from other modules) as a unified error in configuration.
  43. """
  44. pass
  45. class DDNSSessionError(Exception):
  46. '''An exception raised for some unexpected events during an ddns session.
  47. '''
  48. pass
  49. class DDNSSession:
  50. """Class to handle one DDNS update"""
  51. def __init__(self):
  52. self._handle()
  53. def _handle(self):
  54. '''
  55. Handle a DDNS update.
  56. This should be called from the initializer, and should contain the
  57. logic for doing the checks, handling the update, and responding with
  58. the result.
  59. '''
  60. pass
  61. class DDNSServer:
  62. def __init__(self):
  63. self._cc = isc.config.ModuleCCSession(SPECFILE_LOCATION,
  64. self.config_handler,
  65. self.command_handler)
  66. self._config_data = self._cc.get_full_config()
  67. self._cc.start()
  68. self._shutdown_event = threading.Event()
  69. def config_handler(self, new_config):
  70. '''Update config data.'''
  71. answer = create_answer(0)
  72. return answer
  73. def command_handler(self, cmd, args):
  74. if cmd == "shutdown":
  75. logger.info(DDNS_RECEIVED_SHUTDOWN_COMMAND)
  76. self.shutdown()
  77. answer = create_answer(0)
  78. else:
  79. answer = create_answer(1, "Unknown command:" + str(cmd))
  80. return answer
  81. def shutdown(self):
  82. self._shutdown_event.set()
  83. main_thread = threading.currentThread()
  84. for th in threading.enumerate():
  85. if th is main_thread:
  86. continue
  87. th.join()
  88. def run(self):
  89. '''Get and process all commands sent from cfgmgr or other modules. '''
  90. logger.info(DDNS_RUNNING)
  91. while not self._shutdown_event.is_set():
  92. self._cc.check_command(False)
  93. ddns_server = None
  94. def signal_handler(signal, frame):
  95. if ddns_server is not None:
  96. ddns_server.shutdown()
  97. sys.exit(0)
  98. def set_signal_handler():
  99. signal.signal(signal.SIGTERM, signal_handler)
  100. signal.signal(signal.SIGINT, signal_handler)
  101. def set_cmd_options(parser):
  102. parser.add_option("-v", "--verbose", dest="verbose", action="store_true",
  103. help="display more about what is going on")
  104. if '__main__' == __name__:
  105. try:
  106. parser = OptionParser()
  107. set_cmd_options(parser)
  108. (options, args) = parser.parse_args()
  109. VERBOSE_MODE = options.verbose
  110. set_signal_handler()
  111. ddns_server = DDNSServer()
  112. ddns_server.run()
  113. except KeyboardInterrupt:
  114. logger.INFO(DDNS_STOPPED_BY_KEYBOARD)
  115. except SessionError as e:
  116. logger.error(DDNS_CC_SESSION_ERROR, str(e))
  117. except ModuleCCSessionError as e:
  118. logger.error(DDNS_MODULECC_SESSION_ERROR, str(e))
  119. except DDNSConfigError as e:
  120. logger.error(DDNS_CONFIG_ERROR, str(e))
  121. except SessionTimeout as e:
  122. logger.error(DDNS_CC_SESSION_TIMEOUT_ERROR)
  123. if ddns_server:
  124. ddns_server.shutdown()