예제 #1
0
def main():  # pragma: no cover
    username = pwd.getpwuid(os.getuid()).pw_name
    if username not in ['root', 'decisionengine']:
        sys.exit(f"User '{username}' is not allowed to run this script.")

    config_file = policies.global_config_file()
    global_config = ValidConfig(config_file)
    reaper = Reaper(global_config)
    reaper.reap()
예제 #2
0
class TestReaper(unittest.TestCase):
    logger = logging.getLogger()

    def setUp(self):
        with mock.patch.object(dataspace.DataSourceLoader,
                               "create_datasource") as source:
            source.return_value = MockSource()
            GLOBAL_CONFIG["dataspace"]["retention_interval_in_days"] = 365
            self.reaper = Reaper(GLOBAL_CONFIG)

    def tearDown(self):
        # Make sure there are no dangling reapers
        try:
            if self.reaper.thread.is_alive(
            ) or not self.reaper.state.should_stop():
                self.reaper.state.set(State.OFFLINE)
                time.sleep(0.5)
        except Exception:
            pass

    def test_reap_default_state(self):
        self.assertEqual(self.reaper.state.get(), State.BOOT)

    def test_reaper_can_reap(self):
        self.reaper.reap()

    def test_just_stop_no_error(self):
        self.reaper.stop()

    def test_start_stop(self):
        self.reaper.start()
        self.assertIn(self.reaper.state.get(),
                      (State.IDLE, State.ACTIVE, State.STEADY))

        self.reaper.stop()
        self.assertIn(self.reaper.state.get(),
                      (State.SHUTTINGDOWN, State.SHUTDOWN))

    def test_start_stop_stop(self):
        self.reaper.start()
        self.assertIn(self.reaper.state.get(),
                      (State.IDLE, State.ACTIVE, State.STEADY))

        self.reaper.stop()
        self.assertIn(self.reaper.state.get(),
                      (State.SHUTTINGDOWN, State.SHUTDOWN))

        self.logger.debug("running second stop")
        self.reaper.stop()
        self.assertIn(self.reaper.state.get(),
                      (State.SHUTTINGDOWN, State.SHUTDOWN))

    def test_state_can_be_active(self):
        self.reaper.start()
        time.sleep(0.5)  # make sure reaper has a chance to get the lock
        self.assertEqual(self.reaper.state.get(), State.ACTIVE)

    @pytest.mark.timeout(20)
    def test_state_sets_timer_and_uses_it(self):
        self.reaper.MIN_SECONDS_BETWEEN_RUNS = 1
        self.reaper.seconds_between_runs = 1
        self.reaper.start(delay=2)
        self.assertEqual(self.reaper.seconds_between_runs, 1)
        self.reaper.state.wait_while(
            State.IDLE)  # Make sure the reaper started
        self.assertEqual(self.reaper.state.get(), State.ACTIVE)
        self.reaper.state.wait_while(
            State.ACTIVE)  # let the reaper finish its scan
        self.reaper.state.wait_while(
            State.IDLE)  # Make sure the reaper started a second time
        self.reaper.state.wait_while(
            State.ACTIVE)  # let the reaper finish its scan

    def test_start_delay(self):
        self.reaper.start(delay=90)
        self.assertEqual(self.reaper.state.get(), State.IDLE)

    @pytest.mark.timeout(20)
    def test_loop_of_start_stop_in_clumps(self):
        for _ in range(3):
            self.logger.debug(f"run {_} of rapid start/stop")
            self.reaper.start()
            self.assertIn(self.reaper.state.get(),
                          (State.IDLE, State.ACTIVE, State.STEADY))
            self.reaper.stop()
            self.assertIn(self.reaper.state.get(),
                          (State.SHUTTINGDOWN, State.SHUTDOWN))

    def test_fail_small_retain(self):
        with self.assertRaises(ValueError):
            self.reaper.retention_interval = 1

    def test_fail_small_run_interval(self):
        with self.assertRaises(ValueError):
            self.reaper.seconds_between_runs = 1

    def test_fail_start_two_reapers(self):
        self.reaper.start()
        self.assertIn(self.reaper.state.get(),
                      (State.IDLE, State.ACTIVE, State.STEADY))
        with self.assertRaises(RuntimeError):
            self.logger.debug("running second start")
            self.reaper.start()

    def test_fail_missing_config(self):
        with self.assertRaises(dataspace.DataSpaceConfigurationError):
            with mock.patch.object(dataspace.DataSourceLoader,
                                   "create_datasource") as source:
                source.return_value = MockSource()
                test_config = GLOBAL_CONFIG.copy()
                del test_config["dataspace"]
                Reaper(test_config)

    def test_fail_bad_config(self):
        with self.assertRaises(dataspace.DataSpaceConfigurationError):
            with mock.patch.object(dataspace.DataSourceLoader,
                                   "create_datasource") as source:
                source.return_value = MockSource()
                test_config = GLOBAL_CONFIG.copy()
                test_config["dataspace"] = 'somestring'
                Reaper(test_config)

    def test_fail_missing_config_key(self):
        with self.assertRaises(dataspace.DataSpaceConfigurationError):
            with mock.patch.object(dataspace.DataSourceLoader,
                                   "create_datasource") as source:
                source.return_value = MockSource()
                test_config = GLOBAL_CONFIG.copy()
                del test_config["dataspace"]["retention_interval_in_days"]
                Reaper(test_config)

    def test_fail_wrong_config_key(self):
        with self.assertRaises(ValueError):
            with mock.patch.object(dataspace.DataSourceLoader,
                                   "create_datasource") as source:
                source.return_value = MockSource()
                test_config = GLOBAL_CONFIG.copy()
                test_config["dataspace"]["retention_interval_in_days"] = "abc"
                Reaper(test_config)

    @pytest.mark.timeout(20)
    def test_source_fail_can_be_fixed(self):
        with mock.patch.object(MockSource,
                               "delete_data_older_than") as function:
            function.side_effect = KeyError
            self.reaper.start()
            time.sleep(
                1)  # make sure stack trace bubbles up before checking state
            self.assertEqual(self.reaper.state.get(), State.ERROR)

            self.reaper.stop()
            self.assertEqual(self.reaper.state.get(), State.ERROR)

            function.side_effect = None
            self.reaper.start(delay=30)
            self.assertEqual(self.reaper.state.get(), State.IDLE)

            self.reaper.stop()
            self.assertEqual(self.reaper.state.get(), State.SHUTDOWN)