예제 #1
0
class TestPluginBase(unittest.TestCase):
    """
    Base class for our tests, which sets up log capture.

    """
    def setUp(self):
        self.lc = LogCapture()
        self.lc.setLevel(logging.DEBUG)
        self.lc.addFilter(test_common.MyLogCaptureFilter())
        self.addCleanup(self.cleanup)

    def cleanup(self):
        self.lc.uninstall()
예제 #2
0
class TestWatcherConfigfile(TestBase):

    def additional_setup(self):
        self.temp_dir = tempfile.mkdtemp()
        self.abs_fname = self.temp_dir + "/r.spec"
        self.conf = {
            "file"                : self.abs_fname,
            "region_name"         : "dummy-region",
            "vpc_id"              : "dummy-vpc",
            "mode"                : "configfile",
            "health"              : "icmpecho",
            "icmp_check_interval" : 2
        }
        self.watcher_plugin_class = \
                main.load_plugin("configfile", DEFAULT_WATCHER_PLUGIN_MOD)
        self.health_plugin_class = \
                main.load_plugin("icmpecho", DEFAULT_HEALTH_PLUGIN_MOD)

        # The watcher thread needs to have a config file available right at the
        # start, even if there's nothing in it
        self.write_config({})

    def setUp(self):
        self.lc = LogCapture()
        self.lc.setLevel(logging.DEBUG)
        self.lc.addFilter(test_common.MyLogCaptureFilter())

        self.additional_setup()

        self.addCleanup(self.cleanup)

        self.old_handle_spec = vpc.handle_spec

        # Monkey patch the handle_spec function, which is called by the
        # watcher. The handle_spec function is defined in the VPC module.
        # However, it was directly imported by the watcher module, so it's now
        # a copy in the watcher module namespace. Thus, the patch has to be
        # done actually in the watcher module. For safety, we'll do it in both
        # the vpc and watcher module.
        def new_handle_spec(*args, **kwargs):
            pass
        watcher.handle_spec = vpc.handle_spec = new_handle_spec

    def additional_cleanup(self):
        shutil.rmtree(self.temp_dir)

    def cleanup(self):
        self.lc.uninstall()
        watcher.handle_spec = vpc.handle_spec = self.old_handle_spec
        self.additional_cleanup()

    def write_config(self, data):
        with open(self.abs_fname, "w+") as f:
            f.write(json.dumps(data))

    def start_thread_log_tuple(self):
        return [
            ('root', 'INFO',
             "Configfile watcher plugin: Starting to watch route spec file "
             "'%s' for changes..." % self.abs_fname)
        ]

    def change_event_log_tuple(self):
        return ('root', 'INFO',
                "Detected file change event for %s" %
                self.abs_fname)

    def test_watcher_thread_no_config(self):
        os.remove(self.abs_fname)
        watcher_plugin, health_plugin = \
                watcher.start_plugins(
                    self.conf,
                    self.watcher_plugin_class, self.health_plugin_class,
                    2)
        time.sleep(0.5)

        # Config file doesn't exist yet, so we should get an error.
        # Health monitor is started with a second delay, so no messages from
        # there, yet.
        l = self.start_thread_log_tuple()
        l.extend([
            ('root', 'ERROR',
             "Config ignored: Cannot open file: "
             "[Errno 2] No such file or directory: '%s'" % self.abs_fname),
            ('root', 'INFO',
             'ICMPecho health monitor plugin: Starting to watch instances.')
        ])
        self.lc.check(*l)

        watcher.stop_plugins(watcher_plugin, health_plugin)

    def test_watcher_thread_wrong_config(self):
        watcher_plugin, health_plugin = \
                watcher.start_plugins(
                    self.conf,
                    self.watcher_plugin_class, self.health_plugin_class,
                    2)
        time.sleep(1.2)

        self.lc.clear()
        inp = "MALFORMED"
        self.write_config(inp)

        time.sleep(1)
        # Config file malformed
        l = [
            self.change_event_log_tuple(),
            ('root', 'ERROR',
             'Config ignored: Expected dictionary at top level')
        ]
        self.lc_compare(l)

        watcher.stop_plugins(watcher_plugin, health_plugin)

    def test_watcher_thread(self):
        # Monkey patch the healthcheck method of the ICMP health monitor class,
        # since we don't really want to send out ICMP echo requests when we run
        # the tests. Will indicate failure for all IP addresses starting with
        # "3."
        def new_do_health_checks(s, addrs):
            return [a for a in addrs if a.startswith("3.")], []

        # We do this in the class, before the plugin is instantiated
        self.health_plugin_class.do_health_checks = new_do_health_checks

        watcher_plugin, health_plugin = \
                watcher.start_plugins(
                    self.conf,
                    self.watcher_plugin_class, self.health_plugin_class,
                    2)

        time.sleep(2)

        l = self.start_thread_log_tuple()
        l.extend([
             ('root', 'INFO',
              'ICMPecho health monitor plugin: Starting to watch instances.'),
             ('root', 'DEBUG', 'Checking live IPs: (none alive)')])
        self.lc.check(*l)
        self.lc.clear()

        inp = {
                  u"10.1.0.0/16" : [u"1.1.1.1", u"2.2.2.2"],
                  u"10.2.0.0/16" : [u"3.3.3.3"]
              }
        self.write_config(inp)

        time.sleep(2)

        watcher._event_monitor_loop(
            "dummy-region", "dummy-vpc",
            watcher_plugin, health_plugin,
            iterations=1, sleep_time=0.5)

        time.sleep(2)

        self.lc.check(
            self.change_event_log_tuple(),
            ('root', 'DEBUG', 'Checking live IPs: (none alive)'),
            ('root', 'DEBUG',
             'New route spec detected. Updating health-monitor '
             'with: 1.1.1.1,2.2.2.2,3.3.3.3'),
            ('root', 'DEBUG', 'event_monitor_loop ended: Global stop'),
            ('root', 'DEBUG', u'Checking live IPs: 1.1.1.1,2.2.2.2,3.3.3.3'),
            ('root', 'INFO', u'Currently failed IPs: 3.3.3.3'))
        self.lc.clear()

        inp = {
                  u"10.1.0.0/16" : [u"4.4.4.4", u"2.2.2.2"],
                  u"10.2.0.0/16" : [u"3.3.3.3"]
              }
        self.write_config(inp)

        time.sleep(1)
        """
        Remove this check: The log messages may come through in a different
        order, which isn't a problem.

        self.lc.check(
            ('root', 'INFO',
             'Detected file change event for %s' % self.abs_fname),
            ('root', 'DEBUG', 'Checking live IPs: 1.1.1.1,2.2.2.2'))
        """
        self.lc.clear()

        watcher._event_monitor_loop(
            "dummy-region", "dummy-vpc",
            watcher_plugin, health_plugin,
            iterations=1, sleep_time=0.5)

        time.sleep(2)
        self.lc.check(
            ('root', 'DEBUG',
             'New route spec detected. Updating health-monitor '
             'with: 2.2.2.2,3.3.3.3,4.4.4.4'),
            ('root', 'DEBUG', 'event_monitor_loop ended: Global stop'),
            ('root', 'DEBUG', u'Checking live IPs: 2.2.2.2,4.4.4.4'))

        self.lc.clear()

        watcher._event_monitor_loop(
            "dummy-region", "dummy-vpc",
            watcher_plugin, health_plugin,
            iterations=2, sleep_time=1, route_check_time_interval=1)

        time.sleep(2)
        self.lc.check(
            ('root', 'DEBUG', u'Checking live IPs: 2.2.2.2,4.4.4.4'),
            ('root', 'DEBUG', 'Time for regular route check'),
            ('root', 'DEBUG', 'event_monitor_loop ended: Global stop'),
            ('root', 'DEBUG', u'Checking live IPs: 2.2.2.2,4.4.4.4'))

        watcher.stop_plugins(watcher_plugin, health_plugin)