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 })