Exemple #1
0
    def __init__(self, app_id, plugin_info):
        self.logger = ScalingLog("pid.controller.log", "controller.log",
                                 app_id)

        self.app_id = app_id

        self.instances = plugin_info["instances"]
        self.check_interval = plugin_info["check_interval"]
        self.trigger_down = plugin_info["trigger_down"]
        self.trigger_up = plugin_info["trigger_up"]
        self.min_cap = plugin_info["min_cap"]
        self.max_cap = plugin_info["max_cap"]
        self.metric_rounding = plugin_info["metric_rounding"]
        self.actuator_type = plugin_info["actuator"]
        self.metric_source_type = plugin_info["metric_source"]
        self.heuristic_options = plugin_info["heuristic_options"]

        self.running = True
        self.running_lock = threading.RLock()

        metric_source = MetricSourceBuilder().get_metric_source(
            self.metric_source_type, plugin_info)

        actuator = ActuatorBuilder().get_actuator(self.actuator_type)

        self.alarm = PIDAlarm(actuator, metric_source, self.trigger_down,
                              self.trigger_up, self.min_cap, self.max_cap,
                              self.metric_rounding, self.heuristic_options,
                              self.app_id, self.instances)
    def test_proportional_derivative_integrative(self):
        self.heuristic_options = {
            "heuristic_name": "error_pid",
            "proportional_factor": self.proportional_factor,
            "derivative_factor": self.derivative_factor,
            "integrative_factor": self.integrative_factor
        }

        self.alarm = PIDAlarm(self.actuator, self.metric_source,
                              self.trigger_down, self.trigger_up, self.min_cap,
                              self.max_cap, self.metric_round,
                              self.heuristic_options, self.application_id_9,
                              self.instances)

        # Set up mocks
        self.metric_source.get_most_recent_value = MagicMock()
        self.metric_source.get_most_recent_value.side_effect = self.metrics

        self.actuator.adjust_resources = MagicMock(return_value=None)
        self.actuator.get_allocated_resources_to_cluster = \
            MagicMock(return_value=self.allocated_resources_scale_up)

        self.alarm.check_application_state()

        self.metric_source.get_most_recent_value.\
            assert_any_call(PIDAlarm.ERROR_METRIC_NAME,
                            {"application_id": self.application_id_9})

        self.actuator.get_allocated_resources_to_cluster\
            .assert_called_once_with(
                self.instances)

        proportional_component = 15
        derivative_component = 0
        integrative_component = 15
        component_sum = proportional_component + \
            derivative_component + integrative_component

        new_cap = min(
            max(self.allocated_resources_scale_up + component_sum,
                self.min_cap), self.max_cap)

        self.actuator.adjust_resources.assert_called_once_with({
            self.instance_name_1:
            new_cap,
            self.instance_name_2:
            new_cap
        })

        # Second call

        # Set up mocks
        self.actuator.adjust_resources = MagicMock(return_value=None)
        self.actuator.get_allocated_resources_to_cluster = \
            MagicMock(return_value=self.allocated_resources_scale_up)

        self.alarm.check_application_state()

        self.metric_source.get_most_recent_value.\
            assert_any_call(PIDAlarm.ERROR_METRIC_NAME,
                            {"application_id": self.application_id_9})

        self.actuator.get_allocated_resources_to_cluster\
            .assert_called_once_with(
                self.instances)

        proportional_component = 0
        derivative_component = -5
        integrative_component = 15
        component_sum = proportional_component + \
            derivative_component + integrative_component

        new_cap = min(
            max(self.allocated_resources_scale_up + component_sum,
                self.min_cap), self.max_cap)

        self.actuator.adjust_resources.assert_called_once_with({
            self.instance_name_1:
            new_cap,
            self.instance_name_2:
            new_cap
        })

        # Third call

        # Set up mocks
        self.actuator.adjust_resources = MagicMock(return_value=None)
        self.actuator.get_allocated_resources_to_cluster = \
            MagicMock(return_value=self.allocated_resources_scale_up)

        self.alarm.check_application_state()

        self.metric_source.get_most_recent_value.\
            assert_any_call(PIDAlarm.ERROR_METRIC_NAME,
                            {"application_id": self.application_id_9})

        self.actuator.get_allocated_resources_to_cluster\
            .assert_called_once_with(
                self.instances)

        proportional_component = -15
        derivative_component = -5
        integrative_component = 0
        component_sum = proportional_component + \
            derivative_component + integrative_component

        new_cap = min(
            max(self.allocated_resources_scale_up + component_sum,
                self.min_cap), self.max_cap)

        self.actuator.adjust_resources.assert_called_once_with({
            self.instance_name_1:
            new_cap,
            self.instance_name_2:
            new_cap
        })

        # Fourth call

        # Set up mocks
        self.actuator.adjust_resources = MagicMock(return_value=None)
        self.actuator.get_allocated_resources_to_cluster = \
            MagicMock(return_value=self.allocated_resources_scale_up)

        self.alarm.check_application_state()

        self.metric_source.get_most_recent_value.\
            assert_any_call(PIDAlarm.ERROR_METRIC_NAME,
                            {"application_id": self.application_id_9})

        self.actuator.get_allocated_resources_to_cluster\
            .assert_called_once_with(
                self.instances)

        proportional_component = -7.5
        derivative_component = 2.5
        integrative_component = -7.5
        component_sum = proportional_component + \
            derivative_component + integrative_component

        new_cap = min(
            max(self.allocated_resources_scale_up + component_sum,
                self.min_cap), self.max_cap)

        self.actuator.adjust_resources.assert_called_once_with({
            self.instance_name_1:
            new_cap,
            self.instance_name_2:
            new_cap
        })
    def test_alarm_negative_to_positive_error(self):
        #
        # First call - there is no derivative effect - timestamp_1
        # Proportional effect = 45
        # Derivative effect = 0
        self.heuristic_options = {
            "heuristic_name": "error_pid",
            "proportional_factor": self.proportional_factor,
            "derivative_factor": self.derivative_factor,
            "integrative_factor": 0
        }

        self.alarm = PIDAlarm(self.actuator, self.metric_source, 0, 0,
                              self.min_cap, self.max_cap, self.metric_round,
                              self.heuristic_options, self.application_id_6,
                              self.instances)

        self.metric_source.get_most_recent_value = MagicMock()
        self.metric_source.get_most_recent_value.side_effect = self.metrics

        self.actuator.adjust_resources = MagicMock(return_value=None)
        self.actuator.get_allocated_resources_to_cluster = \
            MagicMock(return_value=self.allocated_resources_scale_up)

        self.alarm.check_application_state()

        self.metric_source.get_most_recent_value.\
            assert_any_call(PIDAlarm.ERROR_METRIC_NAME,
                            {"application_id": self.application_id_6})

        # The method tries to get the amount of allocated resources
        self.actuator.get_allocated_resources_to_cluster\
            .assert_called_once_with(
                self.instances)

        new_cap = self.allocated_resources_scale_up + 45

        # The method tries to adjust the amount of resources
        self.actuator.adjust_resources.assert_called_once_with({
            self.instance_name_1:
            new_cap,
            self.instance_name_2:
            new_cap
        })

        #
        # Second call - timestamp_2
        # Proportional effect = -15
        # Derivative effect = -20
        #

        # Set up mocks
        self.metric_source.get_most_recent_value = MagicMock()
        self.metric_source.get_most_recent_value.side_effect = self.metrics

        self.actuator.adjust_resources = MagicMock(return_value=None)
        self.actuator.get_allocated_resources_to_cluster = \
            MagicMock(return_value=self.allocated_resources_scale_down)

        self.alarm.check_application_state()

        self.metric_source.get_most_recent_value.\
            assert_any_call(PIDAlarm.ERROR_METRIC_NAME,
                            {"application_id": self.application_id_6})

        # The method tries to get the amount of allocated resources
        self.actuator.get_allocated_resources_to_cluster\
            .assert_called_once_with(
                self.instances)

        new_cap = self.allocated_resources_scale_down - 35

        # The method tries to adjust the amount of resources
        self.actuator.adjust_resources.assert_called_once_with({
            self.instance_name_1:
            new_cap,
            self.instance_name_2:
            new_cap
        })

        #
        # Third call - timestamp_3
        # Proportional effect = -45
        # Derivative effect = -10
        #

        self.metric_source.get_most_recent_value = MagicMock()
        self.metric_source.get_most_recent_value.side_effect = self.metrics

        self.actuator.adjust_resources = MagicMock(return_value=None)
        self.actuator.get_allocated_resources_to_cluster = \
            MagicMock(return_value=self.allocated_resources_scale_down)

        self.alarm.check_application_state()

        self.metric_source.get_most_recent_value.\
            assert_any_call(PIDAlarm.ERROR_METRIC_NAME,
                            {"application_id": self.application_id_6})

        # The method tries to get the amount of allocated resources
        self.actuator.get_allocated_resources_to_cluster\
            .assert_called_once_with(
                self.instances)

        new_cap = self.allocated_resources_scale_down - 55

        # The method tries to adjust the amount of resources
        self.actuator.adjust_resources.assert_called_once_with({
            self.instance_name_1:
            new_cap,
            self.instance_name_2:
            new_cap
        })
    def test_integrative_only(self):

        # First call

        self.proportional_factor = 0.0
        self.derivative_factor = 0.0
        self.allocated_resources_scale_up = 30

        self.heuristic_options = {
            "heuristic_name": "error_pid",
            "proportional_factor": self.proportional_factor,
            "derivative_factor": self.derivative_factor,
            "integrative_factor": self.integrative_factor
        }

        self.alarm = PIDAlarm(self.actuator, self.metric_source,
                              self.trigger_down, self.trigger_up, self.min_cap,
                              self.max_cap, self.metric_round,
                              self.heuristic_options, self.application_id_8,
                              self.instances)

        # Set up mocks
        self.metric_source.get_most_recent_value = MagicMock()
        self.metric_source.get_most_recent_value.side_effect = self.metrics

        self.actuator.adjust_resources = MagicMock(return_value=None)
        self.actuator.get_allocated_resources_to_cluster = \
            MagicMock(return_value=self.allocated_resources_scale_up)

        self.alarm.check_application_state()

        self.metric_source.get_most_recent_value.\
            assert_any_call(PIDAlarm.ERROR_METRIC_NAME,
                            {"application_id": self.application_id_8})

        self.actuator.get_allocated_resources_to_cluster\
            .assert_called_once_with(
                self.instances)

        # Accumulated error is negative, therefore scale up
        new_cap = self.allocated_resources_scale_up + 15

        self.actuator.adjust_resources.assert_called_once_with({
            self.instance_name_1:
            new_cap,
            self.instance_name_2:
            new_cap
        })

        # Second call

        # Set up mocks
        self.actuator.adjust_resources = MagicMock(return_value=None)
        self.actuator.get_allocated_resources_to_cluster = \
            MagicMock(return_value=self.allocated_resources_scale_up)

        self.alarm.check_application_state()

        self.metric_source.get_most_recent_value.\
            assert_any_call(PIDAlarm.ERROR_METRIC_NAME,
                            {"application_id": self.application_id_8})

        self.actuator.get_allocated_resources_to_cluster\
            .assert_called_once_with(
                self.instances)

        # Accumulated error is negative, therefore scale up
        new_cap = self.allocated_resources_scale_up + 22.5

        self.actuator.adjust_resources.assert_called_once_with({
            self.instance_name_1:
            new_cap,
            self.instance_name_2:
            new_cap
        })

        # Third call

        # Set up mocks
        self.actuator.adjust_resources = MagicMock(return_value=None)
        self.actuator.get_allocated_resources_to_cluster = \
            MagicMock(return_value=self.allocated_resources_scale_up)

        self.alarm.check_application_state()

        self.metric_source.get_most_recent_value.\
            assert_any_call(PIDAlarm.ERROR_METRIC_NAME,
                            {"application_id": self.application_id_8})

        self.actuator.get_allocated_resources_to_cluster\
            .assert_called_once_with(
                self.instances)

        # Accumulated error is positive, therefore scale down
        new_cap = self.allocated_resources_scale_up - 7.5

        self.actuator.adjust_resources.assert_called_once_with({
            self.instance_name_1:
            new_cap,
            self.instance_name_2:
            new_cap
        })

        # Fourth call

        # Set up mocks
        self.actuator.adjust_resources = MagicMock(return_value=None)
        self.actuator.get_allocated_resources_to_cluster = \
            MagicMock(return_value=self.allocated_resources_scale_up)

        self.alarm.check_application_state()

        self.metric_source.get_most_recent_value.\
            assert_any_call(PIDAlarm.ERROR_METRIC_NAME,
                            {"application_id": self.application_id_8})

        self.actuator.get_allocated_resources_to_cluster\
            .assert_called_once_with(
                self.instances)

        # Accumulated error is zero, therefore do not scale
        new_cap = self.allocated_resources_scale_up

        self.actuator.adjust_resources.assert_called_once_with({
            self.instance_name_1:
            new_cap,
            self.instance_name_2:
            new_cap
        })