BIND 10 trac213, updated. b84d1a0e0f13064b8dd68222c063565ac4deec3f [213] Starting and stopping bookkeeping

BIND 10 source code commits bind10-changes at lists.isc.org
Fri Sep 23 12:55:24 UTC 2011


The branch, trac213 has been updated
       via  b84d1a0e0f13064b8dd68222c063565ac4deec3f (commit)
       via  3a6f9f395c141058fb732735beabe7dae1f84bb5 (commit)
      from  842fc917163f0b8cb2a703a4c7fe078d944932e8 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit b84d1a0e0f13064b8dd68222c063565ac4deec3f
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date:   Fri Sep 23 14:54:06 2011 +0200

    [213] Starting and stopping bookkeeping

commit 3a6f9f395c141058fb732735beabe7dae1f84bb5
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date:   Fri Sep 23 14:50:36 2011 +0200

    [213] Component interface, start-stop tests

-----------------------------------------------------------------------

Summary of changes:
 src/lib/python/isc/bind10/Makefile.am             |    2 +-
 src/lib/python/isc/bind10/component.py            |  117 ++++++++++++++++++
 src/lib/python/isc/bind10/tests/Makefile.am       |    2 +-
 src/lib/python/isc/bind10/tests/component_test.py |  137 +++++++++++++++++++++
 4 files changed, 256 insertions(+), 2 deletions(-)
 create mode 100644 src/lib/python/isc/bind10/component.py
 create mode 100644 src/lib/python/isc/bind10/tests/component_test.py

-----------------------------------------------------------------------
diff --git a/src/lib/python/isc/bind10/Makefile.am b/src/lib/python/isc/bind10/Makefile.am
index 43a7605..6a4fef1 100644
--- a/src/lib/python/isc/bind10/Makefile.am
+++ b/src/lib/python/isc/bind10/Makefile.am
@@ -1,4 +1,4 @@
 SUBDIRS = . tests
 
-python_PYTHON = __init__.py sockcreator.py
+python_PYTHON = __init__.py sockcreator.py component.py
 pythondir = $(pyexecdir)/isc/bind10
diff --git a/src/lib/python/isc/bind10/component.py b/src/lib/python/isc/bind10/component.py
new file mode 100644
index 0000000..2864abc
--- /dev/null
+++ b/src/lib/python/isc/bind10/component.py
@@ -0,0 +1,117 @@
+# Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+#
+# 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.
+
+from isc.log_messages.bind10_messages import *
+
+logger = isc.log.Logger("boss")
+
+"""
+Module for managing components (abstraction of process). It allows starting
+them in given order, handling when they crash (what happens depends on kind
+of component) and shutting down. It also handles the configuration of this.
+
+Dependencies between them are not yet handled. It might turn out they are
+needed, in that case they will be added sometime in future.
+"""
+
+class Component:
+    """
+    This represents a single component. It has some defaults of behaviour,
+    which should be reasonable for majority of ordinary components, but
+    it might be inherited and modified for special-purpose components,
+    like the core modules with different ways of starting up.
+    """
+    def __init__(self, process, boss, kind):
+        """
+        Creates the component in not running mode.
+
+        The parameters are:
+        - `process` is the name of the process to start.
+        - `boss` the boss object to plug into. The component needs to plug
+          into it to know when it failed, etc.
+        - `kind` is the kind of component. It may be one of:
+          * 'core' means the system can't run without it and it can't be
+            safely restarted. If it does not start, the system is brought
+            down. If it crashes, the system is turned off as well (with
+            non-zero exit status).
+          * 'needed' means the system is able to restart the component,
+            but it is vital part of the service (like auth server). If
+            it fails to start or crashes in less than 10s after the first
+            startup, the system is brought down. If it crashes later on,
+            it is restarted.
+          * 'dispensable' means the component should be running, but if it
+            doesn't start or crashes for some reason, the system simply tries
+            to restart it and keeps running.
+        """
+        self.__running = False
+    def start(self):
+        """
+        Start the component for the first time or restart it. If you need to
+        modify the way a component is started, do not replace this method,
+        but start_internal. This one does some more bookkeeping around.
+
+        If you try to start an already running component, it raises ValueError.
+        """
+        if self.running():
+            raise ValueError("Can't start already running component")
+        self.start_internal()
+        self.__running = True
+    def start_internal(self):
+        """
+        This method does the actual starting of a process. If you need to
+        change the way the component is started, replace this method.
+        """
+        pass
+    def stop(self):
+        """
+        Stop the component. If you need to modify the way a component is
+        stopped, do not replace this method, but stop_internal. This one
+        does some more bookkeeping.
+
+        If you try to stop a component that is not running, it raises
+        ValueError.
+        """
+        if not self.running():
+            raise ValueError("Can't stop a component which is not running")
+        self.stop_internal()
+        self.__running = False
+    def stop_internal(self):
+        """
+        This is the method that does the actual stopping of a component.
+        You can replace this method if you want a different way to do it.
+        """
+        pass
+    def failed(self):
+        """
+        Notify the component it crashed. This will be called from boss object.
+
+        If you try to call failed on a component that is not running,
+        a ValueError is raised.
+        """
+        pass
+    def failed_internal(self):
+        """
+        This method is called from failed. You can replace it if you need
+        some specific behaviour when the component crashes. The default
+        implementation is empty.
+        """
+        pass
+    def running(self):
+        """
+        Informs if the component is currently running. It assumes the failed
+        is called whenever the component really fails and there might be some
+        time in between actual failure and the call.
+        """
+        return self.__running
diff --git a/src/lib/python/isc/bind10/tests/Makefile.am b/src/lib/python/isc/bind10/tests/Makefile.am
index 0cc12ff..46aaea8 100644
--- a/src/lib/python/isc/bind10/tests/Makefile.am
+++ b/src/lib/python/isc/bind10/tests/Makefile.am
@@ -1,7 +1,7 @@
 PYCOVERAGE_RUN = @PYCOVERAGE_RUN@
 #PYTESTS = args_test.py bind10_test.py
 # NOTE: this has a generated test found in the builddir
-PYTESTS = sockcreator_test.py
+PYTESTS = sockcreator_test.py component_test.py
 
 EXTRA_DIST = $(PYTESTS)
 
diff --git a/src/lib/python/isc/bind10/tests/component_test.py b/src/lib/python/isc/bind10/tests/component_test.py
new file mode 100644
index 0000000..5157d80
--- /dev/null
+++ b/src/lib/python/isc/bind10/tests/component_test.py
@@ -0,0 +1,137 @@
+# Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+#
+# 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.
+
+"""
+Tests for the bind10.component module
+"""
+
+import unittest
+import isc.log
+from isc.bind10.component import Component
+
+class ComponentTests(unittest.TestCase):
+    """
+    Tests for the bind10.component.Component class
+    """
+    def setUp(self):
+        """
+        Pretend a newly started system
+        """
+        self.__shutdown = False
+        self.__exitcode = None
+        self.__start_called = False
+        self.__stop_called = False
+        self.__failed_called = False
+
+    def shutdown(self, exitcode=0):
+        """
+        Mock function to shut down. We just note we were asked to do so.
+        """
+        self.__shutdown = True
+        self.__exitcode = None
+
+    def start(self):
+        """
+        Mock function, installed into the component into start_internal.
+        This only notes the component was "started".
+        """
+        self.__start_called = True
+
+    def stop(self):
+        """
+        Mock function, installed into the component into stop_internal.
+        This only notes the component was "stopped".
+        """
+        self.__stop_called = True
+
+    def fail(self):
+        """
+        Mock function, installed into the component into failed_internal.
+        This only notes the component called the method.
+        """
+        self.__failed_called = True
+
+    def create_component(self, kind):
+        """
+        Convenience function that creates a component of given kind
+        and installs the mock functions into it so we can hook up into
+        its behaviour.
+
+        The process used is some nonsense, as this isn't used in this
+        kind of tests and we pretend to be the boss.
+        """
+        component = Component('No process', self, kind)
+        component.start_internal = self.start
+        component.stop_internal = self.stop
+        component.failed_internal = self.fail
+        return component
+
+    def do_start_stop(self, kind):
+        """
+        This is a body of a test. It creates a componend of given kind,
+        then starts it and stops it. It checks correct functions are called
+        and the component's status is correct.
+
+        It also checks the component can't be started/stopped twice.
+        """
+        # Create it and check it did not do any funny stuff yet
+        component = self.create_component(kind)
+        self.assertFalse(self.__shutdown)
+        self.assertFalse(self.__start_called)
+        self.assertFalse(self.__stop_called)
+        self.assertFalse(self.__failed_called)
+        self.assertFalse(component.running())
+        # Start it and check it called the correct starting functions
+        component.start()
+        self.assertFalse(self.__shutdown)
+        self.assertTrue(self.__start_called)
+        self.assertFalse(self.__stop_called)
+        self.assertFalse(self.__failed_called)
+        self.assertTrue(component.running())
+        # Check it can't be started twice
+        self.assertRaises(ValueError, component.start)
+        # Stop it again and check
+        component.stop()
+        self.assertFalse(self.__shutdown)
+        self.assertTrue(self.__start_called)
+        self.assertTrue(self.__stop_called)
+        self.assertFalse(self.__failed_called)
+        self.assertFalse(component.running())
+        # Check it can't be stopped twice
+        self.assertRaises(ValueError, component.stop)
+        # But it can be started again if it is stopped
+        # (no more checking here, just it doesn't crash)
+        component.start()
+
+    def test_start_stop_core(self):
+        """
+        A start-stop test for core component. See do_start_stop.
+        """
+        self.do_start_stop('core')
+    def test_start_stop_needed(self):
+        """
+        A start-stop test for needed component. See do_start_stop.
+        """
+        self.do_start_stop('needed')
+    def test_start_stop_dispensable(self):
+        """
+        A start-stop test for dispensable component. See do_start_stop.
+        """
+        self.do_start_stop('dispensable')
+
+if __name__ == '__main__':
+    isc.log.init("bind10") # FIXME Should this be needed?
+    isc.log.resetUnitTestRootLogger()
+    unittest.main()




More information about the bind10-changes mailing list