Example #1
0
    def test_retry_deletion(self):
        delete_age = self.configuration.get("delete_age")
        delete_delta = timezone.timedelta(days=(delete_age + 1))
        delete_timestamp = timezone.now() - delete_delta
        state = 'RESUME_COMPLETE'
        stack_name = 'bogus_stack'
        stack = Stack(student_id=self.student_id,
                      course_id=self.course_id,
                      name=stack_name,
                      suspend_timestamp=delete_timestamp)
        stack.status = state
        stack.save()
        mock_heat_client = Mock()
        mock_heat_client.stacks.get.side_effect = [
            self.stacks[state], self.stacks[DELETE_FAILED_STATE],
            self.stacks[DELETE_FAILED_STATE], self.stacks[DELETE_FAILED_STATE]
        ]

        job = ReaperJob(self.configuration)
        with patch.multiple(
                job, get_heat_client=Mock(return_value=mock_heat_client)):
            job.run()

        mock_heat_client.stacks.delete.assert_has_calls([
            call(stack_id=stack_name),
            call(stack_id=stack_name),
            call(stack_id=stack_name)
        ])
        stack = Stack.objects.get(name=stack_name)
        self.assertEqual(stack.status, DELETE_FAILED_STATE)
Example #2
0
    def test_dont_suspend_stack_with_no_provider(self):
        # Setup
        suspend_timeout = self.settings.get("suspend_timeout")
        timedelta = timezone.timedelta(seconds=(suspend_timeout + 1))
        suspend_timestamp = timezone.now() - timedelta
        state = "RESUME_COMPLETE"
        stack = Stack(student_id=self.student_id,
                      course_id=self.course_id,
                      suspend_timestamp=suspend_timestamp,
                      name=self.stack_name,
                      status=state)
        stack.save()
        mock_suspend_task = self.get_suspend_task_mock()

        # Run
        job = SuspenderJob(self.settings)
        job.run()

        # Assert
        mock_suspend_task.apply_async.assert_not_called()
        stack = Stack.objects.get(name=self.stack_name)
        self.assertEqual(stack.status, state)
Example #3
0
    def test_dont_delete_if_age_is_zero(self):
        self.configuration["delete_age"] = 0
        delete_delta = timezone.timedelta(days=15)
        delete_timestamp = timezone.now() - delete_delta
        state = 'RESUME_COMPLETE'
        stack_name = 'bogus_stack'
        stack = Stack(student_id=self.student_id,
                      course_id=self.course_id,
                      name=stack_name,
                      suspend_timestamp=delete_timestamp,
                      status=state)
        stack.save()
        mock_heat_client = Mock()

        job = ReaperJob(self.configuration)
        with patch.multiple(
                job, get_heat_client=Mock(return_value=mock_heat_client)):
            job.run()

        mock_heat_client.stacks.delete.assert_not_called()
        stack = Stack.objects.get(name=stack_name)
        self.assertEqual(stack.status, state)
Example #4
0
    def test_dont_suspend_deleted_stack(self):
        suspend_timeout = self.configuration.get("suspend_timeout")
        timedelta = timezone.timedelta(seconds=(suspend_timeout + 1))
        suspend_timestamp = timezone.now() - timedelta
        state = 'RESUME_COMPLETE'
        stack = Stack(student_id=self.student_id,
                      course_id=self.course_id,
                      suspend_timestamp=suspend_timestamp,
                      name=self.stack_name,
                      status=state)
        stack.save()
        mock_heat_client = Mock()
        mock_heat_client.stacks.get.side_effect = [HTTPNotFound]

        job = SuspenderJob(self.configuration)
        with patch.multiple(
                job, get_heat_client=Mock(return_value=mock_heat_client)):
            job.run()

        mock_heat_client.actions.suspend.assert_not_called()
        stack = Stack.objects.get(name=self.stack_name)
        self.assertEqual(stack.status, DELETED_STATE)
Example #5
0
    def test_stack_log(self):
        suspend_timeout = self.configuration.get("suspend_timeout")
        timedelta = timezone.timedelta(seconds=(suspend_timeout + 1))
        suspend_timestamp = timezone.now() - timedelta
        state = 'CREATE_COMPLETE'
        stack = Stack(student_id=self.student_id,
                      course_id=self.course_id,
                      suspend_timestamp=suspend_timestamp,
                      name=self.stack_name)
        stack.status = state
        stack.save()
        mock_heat_client = Mock()
        mock_heat_client.stacks.get.side_effect = [self.stacks[state]]

        job = SuspenderJob(self.configuration)
        with patch.multiple(
                job, get_heat_client=Mock(return_value=mock_heat_client)):
            job.run()

        stacklog = StackLog.objects.filter(stack_id=stack.id)
        states = [l.status for l in stacklog]
        expected_states = [state, 'SUSPEND_PENDING', 'SUSPEND_ISSUED']
        self.assertEqual(states, expected_states)
Example #6
0
    def test_suspend_stack_for_the_first_time(self):
        # Setup
        suspend_timeout = self.settings.get("suspend_timeout")
        timedelta = timezone.timedelta(seconds=(suspend_timeout + 1))
        suspend_timestamp = timezone.now() - timedelta
        state = "CREATE_COMPLETE"
        stack = Stack(student_id=self.student_id,
                      course_id=self.course_id,
                      suspend_timestamp=suspend_timestamp,
                      name=self.stack_name,
                      provider="provider1",
                      status=state)
        stack.save()
        mock_suspend_task = self.get_suspend_task_mock()

        # Run
        job = SuspenderJob(self.settings)
        job.run()

        # Assert
        mock_suspend_task.apply_async.assert_called()
        stack = Stack.objects.get(name=self.stack_name)
        self.assertEqual(stack.status, SUSPEND_PENDING)
Example #7
0
    def test_stack_log(self):
        # Setup
        suspend_timeout = self.settings.get("suspend_timeout")
        timedelta = timezone.timedelta(seconds=(suspend_timeout + 1))
        suspend_timestamp = timezone.now() - timedelta
        state = 'CREATE_COMPLETE'
        stack = Stack(student_id=self.student_id,
                      course_id=self.course_id,
                      suspend_timestamp=suspend_timestamp,
                      provider='provider1',
                      name=self.stack_name)
        stack.status = state
        stack.save()

        # Run
        job = SuspenderJob(self.settings)
        job.run()

        # Assert
        stacklog = StackLog.objects.filter(stack_id=stack.id)
        states = [l.status for l in stacklog]
        expected_states = [state, SUSPEND_PENDING]
        self.assertEqual(states, expected_states)
Example #8
0
    def test_dont_delete_if_age_is_zero(self):
        # Setup
        self.settings["delete_age"] = 0
        delete_delta = timezone.timedelta(days=15)
        delete_timestamp = timezone.now() - delete_delta
        state = 'RESUME_COMPLETE'
        stack_name = 'bogus_stack'
        stack = Stack(student_id=self.student_id,
                      course_id=self.course_id,
                      name=stack_name,
                      suspend_timestamp=delete_timestamp,
                      provider='provider1',
                      status=state)
        stack.save()
        mock_delete_task = self.get_delete_task_mock()

        # Run
        job = ReaperJob(self.settings)
        job.run()

        mock_delete_task.apply_async.assert_not_called()
        stack = Stack.objects.get(name=stack_name)
        self.assertEqual(stack.status, state)
Example #9
0
    def test_dont_try_to_delete_certain_stack_states(self):
        delete_age = self.configuration.get("delete_age")
        delete_delta = timezone.timedelta(days=(delete_age + 1))
        delete_timestamp = timezone.now() - delete_delta
        stack1_name = 'bogus_stack_1'
        stack1 = Stack(student_id=self.student_id,
                       course_id=self.course_id,
                       name=stack1_name,
                       suspend_timestamp=delete_timestamp,
                       status=DELETE_STATE)
        stack1.save()
        stack2_name = 'bogus_stack_2'
        stack2 = Stack(student_id=self.student_id,
                       course_id=self.course_id,
                       name=stack2_name,
                       suspend_timestamp=delete_timestamp,
                       status=DELETE_IN_PROGRESS_STATE)
        stack2.save()
        stack3_name = 'bogus_stack_3'
        stack3 = Stack(student_id=self.student_id,
                       course_id=self.course_id,
                       name=stack3_name,
                       suspend_timestamp=delete_timestamp,
                       status=DELETED_STATE)
        stack3.save()
        mock_heat_client = Mock()

        job = ReaperJob(self.configuration)
        with patch.multiple(
                job, get_heat_client=Mock(return_value=mock_heat_client)):
            job.run()

        mock_heat_client.stacks.delete.assert_not_called()
        stack1 = Stack.objects.get(name=stack1_name)
        self.assertEqual(stack1.status, DELETE_STATE)
        stack2 = Stack.objects.get(name=stack2_name)
        self.assertEqual(stack2.status, DELETE_IN_PROGRESS_STATE)
        stack3 = Stack.objects.get(name=stack3_name)
        self.assertEqual(stack3.status, DELETED_STATE)
Example #10
0
    def test_delete_old_stacks(self):
        delete_age = self.configuration.get("delete_age")
        delete_delta = timezone.timedelta(days=(delete_age + 1))
        delete_timestamp = timezone.now() - delete_delta
        dont_delete_delta = timezone.timedelta(days=(delete_age - 1))
        dont_delete_timestamp = timezone.now() - dont_delete_delta
        state = 'RESUME_COMPLETE'
        stack1_name = 'bogus_stack_1'
        stack1 = Stack(student_id=self.student_id,
                       course_id=self.course_id,
                       name=stack1_name,
                       suspend_timestamp=delete_timestamp,
                       status=state)
        stack1.save()
        stack2_name = 'bogus_stack_2'
        stack2 = Stack(student_id=self.student_id,
                       course_id=self.course_id,
                       name=stack2_name,
                       suspend_timestamp=delete_timestamp,
                       status=state)
        stack2.save()
        stack3_name = 'bogus_stack_3'
        stack3 = Stack(student_id=self.student_id,
                       course_id=self.course_id,
                       name=stack3_name,
                       suspend_timestamp=dont_delete_timestamp,
                       status=state)
        stack3.save()
        mock_heat_client = Mock()
        mock_heat_client.stacks.get.side_effect = [
            self.stacks[state], self.stacks[DELETE_IN_PROGRESS_STATE],
            HTTPNotFound, self.stacks[state],
            self.stacks[DELETE_IN_PROGRESS_STATE], HTTPNotFound
        ]

        job = ReaperJob(self.configuration)
        with patch.multiple(
                job, get_heat_client=Mock(return_value=mock_heat_client)):
            job.run()

        mock_heat_client.stacks.delete.assert_has_calls(
            [call(stack_id=stack1_name),
             call(stack_id=stack2_name)])
        self.assertNotIn(call(stack_id=stack3_name),
                         mock_heat_client.stacks.delete.mock_calls)
        stack1 = Stack.objects.get(name=stack1_name)
        self.assertEqual(stack1.status, DELETED_STATE)
        stack2 = Stack.objects.get(name=stack2_name)
        self.assertEqual(stack2.status, DELETED_STATE)
        stack3 = Stack.objects.get(name=stack3_name)
        self.assertEqual(stack3.status, state)
Example #11
0
    def test_suspend_concurrency(self):
        self.configuration["suspend_concurrency"] = 2
        suspend_timeout = self.configuration.get("suspend_timeout")
        timedelta = timezone.timedelta(seconds=(suspend_timeout + 1))
        suspend_timestamp = timezone.now() - timedelta
        state = 'CREATE_COMPLETE'
        stack1_name = 'bogus_stack_1'
        stack1 = Stack(student_id=self.student_id,
                       course_id=self.course_id,
                       name=stack1_name,
                       suspend_timestamp=suspend_timestamp,
                       status=state)
        stack1.save()
        stack2_name = 'bogus_stack_2'
        stack2 = Stack(student_id=self.student_id,
                       course_id=self.course_id,
                       name=stack2_name,
                       suspend_timestamp=suspend_timestamp,
                       status=state)
        stack2.save()
        stack3_name = 'bogus_stack_3'
        stack3 = Stack(student_id=self.student_id,
                       course_id=self.course_id,
                       name=stack3_name,
                       suspend_timestamp=suspend_timestamp,
                       status=state)
        stack3.save()
        mock_heat_client = Mock()
        mock_heat_client.stacks.get.side_effect = [
            self.stacks[state], self.stacks[state]
        ]

        job = SuspenderJob(self.configuration)
        with patch.multiple(
                job, get_heat_client=Mock(return_value=mock_heat_client)):
            job.run()

        mock_heat_client.actions.suspend.assert_has_calls(
            [call(stack_id=stack1_name),
             call(stack_id=stack2_name)])
        self.assertNotIn(call(stack_id=stack3_name),
                         mock_heat_client.actions.suspend.mock_calls)
        stack1 = Stack.objects.get(name=stack1_name)
        self.assertEqual(stack1.status, SUSPEND_ISSUED_STATE)
        stack2 = Stack.objects.get(name=stack2_name)
        self.assertEqual(stack2.status, SUSPEND_ISSUED_STATE)
        stack3 = Stack.objects.get(name=stack3_name)
        self.assertEqual(stack3.status, state)
Example #12
0
    def test_destroy_zombies(self):
        # Setup
        delete_age = self.settings.get("delete_age")
        delete_delta = timezone.timedelta(days=(delete_age + 1))
        delete_timestamp = timezone.now() - delete_delta
        dont_delete_delta = timezone.timedelta(days=(delete_age - 1))
        dont_delete_timestamp = timezone.now() - dont_delete_delta
        stack_names = ('zombie_stack_1', 'zombie_stack_2', 'zombie_stack_3',
                       'zombie_stack_4', 'not_a_zombie_stack')

        # Create zombie stacks
        for i in range(0, 4):
            _stack = Stack(student_id=self.student_id,
                           course_id=self.course_id,
                           name=stack_names[i],
                           suspend_timestamp=delete_timestamp,
                           status=DELETE_COMPLETE)
            _stack.save()

        # Create living stack
        _stack = Stack(student_id=self.student_id,
                       course_id=self.course_id,
                       name=stack_names[4],
                       suspend_timestamp=dont_delete_timestamp,
                       status=CREATE_COMPLETE)
        _stack.save()

        mock_provider = self.mocks["Provider"].init.return_value
        provider1_stacks = []
        for i in range(0, 3):
            provider1_stacks.append({
                "name": stack_names[i],
                "status": CREATE_COMPLETE
            })
        provider2_stacks = []
        for i in range(3, 5):
            provider2_stacks.append({
                "name": stack_names[i],
                "status": CREATE_COMPLETE
            })
        provider3_stacks = [{"name": "unknown", "status": CREATE_COMPLETE}]
        mock_provider.get_stacks.side_effect = [
            provider1_stacks, provider2_stacks, provider3_stacks
        ]
        self.settings["providers"] = {
            "provider1": {},
            "provider2": {},
            "provider3": {}
        }
        mock_delete_task = self.get_delete_task_mock()

        # Run
        job = ReaperJob(self.settings)
        job.run()

        # Assert
        self.assertEqual(4, len(mock_delete_task.apply_async.mock_calls))
        stack = Stack.objects.get(name=stack_names[0])
        self.assertEqual(stack.status, DELETE_PENDING)
        stack = Stack.objects.get(name=stack_names[1])
        self.assertEqual(stack.status, DELETE_PENDING)
        stack = Stack.objects.get(name=stack_names[2])
        self.assertEqual(stack.status, DELETE_PENDING)
        stack = Stack.objects.get(name=stack_names[3])
        self.assertEqual(stack.status, DELETE_PENDING)
        stack = Stack.objects.get(name=stack_names[4])
        self.assertEqual(stack.status, CREATE_COMPLETE)
Example #13
0
    def test_dont_try_to_delete_certain_stack_states(self):
        # Setup
        delete_age = self.settings.get("delete_age")
        delete_delta = timezone.timedelta(days=(delete_age + 1))
        delete_timestamp = timezone.now() - delete_delta
        stack1_name = "bogus_stack_1"
        stack1 = Stack(student_id=self.student_id,
                       course_id=self.course_id,
                       name=stack1_name,
                       suspend_timestamp=delete_timestamp,
                       provider="provider1",
                       status=DELETE_PENDING)
        stack1.save()
        stack2_name = "bogus_stack_2"
        stack2 = Stack(student_id=self.student_id,
                       course_id=self.course_id,
                       name=stack2_name,
                       suspend_timestamp=delete_timestamp,
                       provider="provider2",
                       status=DELETE_IN_PROGRESS)
        stack2.save()
        stack3_name = "bogus_stack_3"
        stack3 = Stack(student_id=self.student_id,
                       course_id=self.course_id,
                       name=stack3_name,
                       suspend_timestamp=delete_timestamp,
                       provider="provider3",
                       status=DELETE_COMPLETE)
        stack3.save()
        stack4_name = "bogus_stack_4"
        stack4 = Stack(student_id=self.student_id,
                       course_id=self.course_id,
                       name=stack4_name,
                       suspend_timestamp=delete_timestamp,
                       status="CREATE_FAILED")
        stack4.save()
        mock_delete_task = self.get_delete_task_mock()

        # Run
        job = ReaperJob(self.settings)
        job.run()

        # Assert
        mock_delete_task.apply_async.assert_not_called()
        stack1 = Stack.objects.get(name=stack1_name)
        self.assertEqual(stack1.status, DELETE_PENDING)
        stack2 = Stack.objects.get(name=stack2_name)
        self.assertEqual(stack2.status, DELETE_IN_PROGRESS)
        stack3 = Stack.objects.get(name=stack3_name)
        self.assertEqual(stack3.status, DELETE_COMPLETE)
        stack4 = Stack.objects.get(name=stack4_name)
        self.assertEqual(stack4.status, "CREATE_FAILED")
Example #14
0
    def test_delete_old_stacks(self):
        # Setup
        delete_age = self.settings.get("delete_age")
        delete_delta = timezone.timedelta(days=(delete_age + 1))
        delete_timestamp = timezone.now() - delete_delta
        dont_delete_delta = timezone.timedelta(days=(delete_age - 1))
        dont_delete_timestamp = timezone.now() - dont_delete_delta
        state = "RESUME_COMPLETE"
        stack1_name = "bogus_stack_1"
        stack1 = Stack(student_id=self.student_id,
                       course_id=self.course_id,
                       name=stack1_name,
                       suspend_timestamp=delete_timestamp,
                       provider="provider1",
                       status=state)
        stack1.save()
        stack2_name = "bogus_stack_2"
        stack2 = Stack(student_id=self.student_id,
                       course_id=self.course_id,
                       name=stack2_name,
                       suspend_timestamp=delete_timestamp,
                       provider="provider2",
                       status=state)
        stack2.save()
        stack3_name = "bogus_stack_3"
        stack3 = Stack(student_id=self.student_id,
                       course_id=self.course_id,
                       name=stack3_name,
                       suspend_timestamp=dont_delete_timestamp,
                       provider='provider3',
                       status=state)
        stack3.save()
        mock_delete_task = self.get_delete_task_mock()

        # Run
        job = ReaperJob(self.settings)
        job.run()

        # Assert
        self.assertEqual(2, len(mock_delete_task.apply_async.mock_calls))
        stack1 = Stack.objects.get(name=stack1_name)
        self.assertEqual(stack1.status, DELETE_PENDING)
        stack2 = Stack.objects.get(name=stack2_name)
        self.assertEqual(stack2.status, DELETE_PENDING)
        stack3 = Stack.objects.get(name=stack3_name)
        self.assertEqual(stack3.status, state)
Example #15
0
    def test_suspend_concurrency(self):
        # Setup
        self.settings["suspend_concurrency"] = 2
        suspend_timeout = self.settings.get("suspend_timeout")
        timedelta = timezone.timedelta(seconds=(suspend_timeout + 1))
        suspend_timestamp = timezone.now() - timedelta
        state = "CREATE_COMPLETE"
        stack1_name = "bogus_stack_1"
        stack1 = Stack(student_id=self.student_id,
                       course_id=self.course_id,
                       name=stack1_name,
                       suspend_timestamp=suspend_timestamp,
                       provider="provider1",
                       status=state)
        stack1.save()
        stack2_name = "bogus_stack_2"
        stack2 = Stack(student_id=self.student_id,
                       course_id=self.course_id,
                       name=stack2_name,
                       suspend_timestamp=suspend_timestamp,
                       provider="provider2",
                       status=state)
        stack2.save()
        stack3_name = "bogus_stack_3"
        stack3 = Stack(student_id=self.student_id,
                       course_id=self.course_id,
                       name=stack3_name,
                       suspend_timestamp=suspend_timestamp,
                       provider="provider3",
                       status=state)
        stack3.save()
        mock_suspend_task = self.get_suspend_task_mock()

        # Run
        job = SuspenderJob(self.settings)
        job.run()

        # Assert
        self.assertEqual(2, len(mock_suspend_task.apply_async.mock_calls))
        stack1 = Stack.objects.get(name=stack1_name)
        self.assertEqual(stack1.status, SUSPEND_PENDING)
        stack2 = Stack.objects.get(name=stack2_name)
        self.assertEqual(stack2.status, SUSPEND_PENDING)
        stack3 = Stack.objects.get(name=stack3_name)
        self.assertEqual(stack3.status, state)