Esempio n. 1
0
    def __init__(self, application_id, plugin_info):
        self.logger = Log("single.controller.log", "controller.log")
        configure_logging()

        self.application_id = application_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.actuation_size = plugin_info["actuation_size"]
        self.metric_rounding = plugin_info["metric_rounding"]
        self.actuator_type = plugin_info["actuator"]
        self.metric_source_type = plugin_info["metric_source"]

        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,
                                                  plugin_info)

        self.alarm = BasicAlarm(actuator, metric_source, self.trigger_down,
                                self.trigger_up, self.min_cap, self.max_cap,
                                self.actuation_size, self.metric_rounding)
    def setUp(self):
        self.application_id_0 = "app-00"
        self.application_id_1 = "app-01"
        self.application_id_2 = "app-02"
        self.application_id_3 = "app-03"
        self.application_id_4 = "app-04"

        self.timestamp_1 = datetime.datetime.strptime("2000-01-01T00:00:00.0Z",
                                                      '%Y-%m-%dT%H:%M:%S.%fZ')
        self.timestamp_2 = datetime.datetime.strptime("2000-01-01T00:05:00.0Z",
                                                      '%Y-%m-%dT%H:%M:%S.%fZ')
        self.timestamp_3 = datetime.datetime.strptime("2000-01-01T00:10:00.0Z",
                                                      '%Y-%m-%dT%H:%M:%S.%fZ')
        self.timestamp_4 = datetime.datetime.strptime("2000-01-01T00:15:00.0Z",
                                                      '%Y-%m-%dT%H:%M:%S.%fZ')

        self.instance_name_1 = "instance1"
        self.instance_name_2 = "instance2"

        self.bigsea_username = "******"
        self.bigsea_password = "******"
        self.authorization_url = "authorization_url"
        # self.authorization_data = dict(
        #                                authorization_url=self.authorization_url,
        #                                bigsea_username=self.bigsea_username,
        #                                bigsea_password=self.bigsea_password)

        self.trigger_down = 30.0
        self.trigger_up = 10.0
        self.min_cap = 10.0
        self.max_cap = 100.0
        self.actuation_size = 10.0
        self.allocated_resources = 50
        self.metric_round = 2
        self.default_io_cap = 56

        compute_nodes = []
        compute_nodes_key = "key"
        self.instances = [self.instance_name_1, self.instance_name_2]
        self.metric_source = MetricSourceBuilder().get_metric_source("nop", {})
        self.instance_locator = InstanceLocator(SSHUtils({}), compute_nodes,
                                                compute_nodes_key)
        self.remote_kvm = RemoteKVM(SSHUtils({}), compute_nodes_key)
        self.actuator = KVMActuator(
            self.instance_locator,
            self.remote_kvm,
            # self.authorization_data,
            self.default_io_cap)

        self.alarm = BasicAlarm(self.actuator, self.metric_source,
                                self.trigger_down, self.trigger_up,
                                self.min_cap, self.max_cap,
                                self.actuation_size, self.metric_round)

        self.timestamps = [
            self.timestamp_1, self.timestamp_2, self.timestamp_3,
            self.timestamp_4
        ]
Esempio n. 3
0
class SingleApplicationController(Controller):
    def __init__(self, application_id, plugin_info):
        self.logger = Log("single.controller.log", "controller.log")
        configure_logging()

        plugin_info = plugin_info["plugin_info"]

        self.application_id = application_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.actuation_size = plugin_info["actuation_size"]
        self.metric_rounding = plugin_info["metric_rounding"]
        self.actuator_type = plugin_info["actuator"]
        self.metric_source_type = plugin_info["metric_source"]

        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,
                                                  plugin_info)

        self.alarm = BasicAlarm(actuator, metric_source, self.trigger_down,
                                self.trigger_up, self.min_cap, self.max_cap,
                                self.actuation_size, self.metric_rounding)

    def start_application_scaling(self):
        run = True

        while run:
            self.logger.log("Monitoring application: %s" %
                            (self.application_id))

            self.alarm.check_application_state(self.application_id,
                                               self.instances)

            time.sleep(float(self.check_interval))

            with self.running_lock:
                run = self.running

    def stop_application_scaling(self):
        with self.running_lock:
            self.running = False

    def status(self):
        return ""
Esempio n. 4
0
    def __init__(self, metric_source, actuator, plugin_info):
        # Set up logging
        self.logger = Log("basic.controller.log", "controller.log")
        configure_logging()

        check_interval = plugin_info["check_interval"]
        trigger_down = plugin_info["trigger_down"]
        trigger_up = plugin_info["trigger_up"]
        min_cap = plugin_info["min_cap"]
        max_cap = plugin_info["max_cap"]
        actuation_size = plugin_info["actuation_size"]
        metric_rounding = plugin_info["metric_rounding"]

        # Start alarm
        self.alarm = BasicAlarm(actuator, metric_source, trigger_down,
                                trigger_up, min_cap, max_cap, actuation_size,
                                metric_rounding)

        # Start up controller thread
        # Create lock to access application list
        self.applications_lock = threading.RLock()
        self.applications = {}
        self.controller = _BasicControllerThread(self.applications,
                                                 self.applications_lock,
                                                 self.alarm, check_interval)

        self.controller_thread = threading.Thread(target=self.controller.start)
        self.controller_thread.start()
    def test_alarm_does_not_reuse_metrics_with_same_timestamp(self):
        self.alarm = BasicAlarm(self.actuator, self.metric_source,
                                self.trigger_down, self.trigger_up,
                                self.min_cap, self.max_cap,
                                self.actuation_size, 2)

        # 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 = MagicMock(
            return_value=self.allocated_resources)

        self.alarm.check_application_state(self.application_id_0,
                                           self.instances)

        # The method tries to get the metrics correctly
        self.metric_source.get_most_recent_value.assert_any_call(
            BasicAlarm.PROGRESS_METRIC_NAME,
            {"application_id": self.application_id_0})
        self.metric_source.get_most_recent_value.assert_any_call(
            BasicAlarm.ELAPSED_TIME_METRIC_NAME,
            {"application_id": self.application_id_0})

        # The method tries to get the amount of allocated resources
        self.actuator.get_allocated_resources.assert_called_once_with(
            self.instance_name_1)
        # Add resources
        new_cap = self.allocated_resources + self.actuation_size
        # 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
        })

        #
        # 2nd call. The method checks if the metric is new and does not acts
        #

        # 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 = MagicMock(
            return_value=self.allocated_resources)

        self.alarm.check_application_state(self.application_id_0,
                                           self.instances)

        # The method tries to get the metrics correctly
        self.metric_source.get_most_recent_value.assert_any_call(
            BasicAlarm.PROGRESS_METRIC_NAME,
            {"application_id": self.application_id_0})
        self.metric_source.get_most_recent_value.assert_any_call(
            BasicAlarm.ELAPSED_TIME_METRIC_NAME,
            {"application_id": self.application_id_0})

        # The method doesn't try to get the amount of allocated resources
        self.actuator.get_allocated_resources.assert_not_called()
        # The method doesn't try to adjust the amount of resources
        self.actuator.adjust_resources.assert_not_called()
class TestBasicAlarm(unittest.TestCase):
    def setUp(self):
        self.application_id_0 = "app-00"
        self.application_id_1 = "app-01"
        self.application_id_2 = "app-02"
        self.application_id_3 = "app-03"
        self.application_id_4 = "app-04"

        self.timestamp_1 = datetime.datetime.strptime("2000-01-01T00:00:00.0Z",
                                                      '%Y-%m-%dT%H:%M:%S.%fZ')
        self.timestamp_2 = datetime.datetime.strptime("2000-01-01T00:05:00.0Z",
                                                      '%Y-%m-%dT%H:%M:%S.%fZ')
        self.timestamp_3 = datetime.datetime.strptime("2000-01-01T00:10:00.0Z",
                                                      '%Y-%m-%dT%H:%M:%S.%fZ')
        self.timestamp_4 = datetime.datetime.strptime("2000-01-01T00:15:00.0Z",
                                                      '%Y-%m-%dT%H:%M:%S.%fZ')

        self.instance_name_1 = "instance1"
        self.instance_name_2 = "instance2"

        self.bigsea_username = "******"
        self.bigsea_password = "******"
        self.authorization_url = "authorization_url"
        # self.authorization_data = dict(
        #                                authorization_url=self.authorization_url,
        #                                bigsea_username=self.bigsea_username,
        #                                bigsea_password=self.bigsea_password)

        self.trigger_down = 30.0
        self.trigger_up = 10.0
        self.min_cap = 10.0
        self.max_cap = 100.0
        self.actuation_size = 10.0
        self.allocated_resources = 50
        self.metric_round = 2
        self.default_io_cap = 56

        compute_nodes = []
        compute_nodes_key = "key"
        self.instances = [self.instance_name_1, self.instance_name_2]
        self.metric_source = MetricSourceBuilder().get_metric_source("nop", {})
        self.instance_locator = InstanceLocator(SSHUtils({}), compute_nodes,
                                                compute_nodes_key)
        self.remote_kvm = RemoteKVM(SSHUtils({}), compute_nodes_key)
        self.actuator = KVMActuator(
            self.instance_locator,
            self.remote_kvm,
            # self.authorization_data,
            self.default_io_cap)

        self.alarm = BasicAlarm(self.actuator, self.metric_source,
                                self.trigger_down, self.trigger_up,
                                self.min_cap, self.max_cap,
                                self.actuation_size, self.metric_round)

        self.timestamps = [
            self.timestamp_1, self.timestamp_2, self.timestamp_3,
            self.timestamp_4
        ]

    def metrics(self, metric_name, options):
        application_id = options["application_id"]

        job_progress = {
            self.application_id_0: 30.0,
            self.application_id_1: 50.0,
            self.application_id_2: 80.0,
            self.application_id_3: 50.004,
            self.application_id_4: 80.000
        }
        time_progress = {
            self.application_id_0: 80.0,
            self.application_id_1: 50.0,
            self.application_id_2: 30.0,
            self.application_id_3: 60.000,
            self.application_id_4: 50.003
        }

        if metric_name == BasicAlarm.PROGRESS_METRIC_NAME:
            return self.timestamp_1, job_progress[application_id]
        elif metric_name == BasicAlarm.ELAPSED_TIME_METRIC_NAME:
            return self.timestamp_1, time_progress[application_id]

    def metrics_different_timestamps(self, metric_name, options):
        application_id = options["application_id"]

        job_progress = {
            self.application_id_0: 30.0,
            self.application_id_1: 50.0,
            self.application_id_2: 80.0,
            self.application_id_3: 50.004,
            self.application_id_4: 80.000
        }
        time_progress = {
            self.application_id_0: 80.0,
            self.application_id_1: 50.0,
            self.application_id_2: 30.0,
            self.application_id_3: 60.000,
            self.application_id_4: 50.003
        }

        timestamp = self.timestamps.pop(0)

        if metric_name == BasicAlarm.PROGRESS_METRIC_NAME:
            return timestamp, job_progress[application_id]
        elif metric_name == BasicAlarm.ELAPSED_TIME_METRIC_NAME:
            return timestamp, time_progress[application_id]

    @unittest.skip
    def test_alarm_gets_metrics_and_scales_down(self):
        # 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 = MagicMock(
            return_value=self.allocated_resources)

        self.alarm.check_application_state(self.application_id_2,
                                           self.instances)

        # The method tries to get the metrics correctly
        self.metric_source.get_most_recent_value.assert_any_call(
            BasicAlarm.PROGRESS_METRIC_NAME,
            {"application_id": self.application_id_2})
        self.metric_source.get_most_recent_value.assert_any_call(
            BasicAlarm.ELAPSED_TIME_METRIC_NAME,
            {"application_id": self.application_id_2})

        # The method tries to get the amount of allocated resources
        self.actuator.get_allocated_resources.assert_called_once_with(
            self.instance_name_1)
        # Remove resources
        new_cap = self.allocated_resources - self.actuation_size
        # 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
        })

    @unittest.skip
    def test_alarm_gets_metrics_and_scales_up(self):
        # 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 = MagicMock(
            return_value=self.allocated_resources)

        self.alarm.check_application_state(self.application_id_0,
                                           self.instances)

        # The method tries to get the metrics correctly
        self.metric_source.get_most_recent_value.assert_any_call(
            BasicAlarm.PROGRESS_METRIC_NAME,
            {"application_id": self.application_id_0})
        self.metric_source.get_most_recent_value.assert_any_call(
            BasicAlarm.ELAPSED_TIME_METRIC_NAME,
            {"application_id": self.application_id_0})

        # The method tries to get the amount of allocated resources
        self.actuator.get_allocated_resources.assert_called_once_with(
            self.instance_name_1)
        # Add resources
        new_cap = self.allocated_resources + self.actuation_size
        # 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
        })

    @unittest.skip
    def test_alarm_does_nothing(self):
        # 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 = MagicMock(
            return_value=self.allocated_resources)

        self.alarm.check_application_state(self.application_id_1,
                                           self.instances)

        # The method tries to get the metrics correctly
        self.metric_source.get_most_recent_value.assert_any_call(
            BasicAlarm.PROGRESS_METRIC_NAME,
            {"application_id": self.application_id_1})
        self.metric_source.get_most_recent_value.assert_any_call(
            BasicAlarm.ELAPSED_TIME_METRIC_NAME,
            {"application_id": self.application_id_1})

        # The method doesn't try to get the amount of allocated resources
        self.actuator.get_allocated_resources.assert_not_called()
        # The method doesn't try to adjust the amount of resources
        self.actuator.adjust_resources.assert_not_called()

    @unittest.skip
    def test_alarm_metric_rounding(self):
        #
        # The metrics are rounded to 2 digits from the decimal point
        # There should be scale up and down in these cases
        #
        self.alarm = BasicAlarm(self.actuator, self.metric_source,
                                self.trigger_down, self.trigger_up,
                                self.min_cap, self.max_cap,
                                self.actuation_size, 2)

        # Scale up
        # 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 = MagicMock(
            return_value=self.allocated_resources)

        self.alarm.check_application_state(self.application_id_3,
                                           self.instances)

        # The method tries to get the metrics correctly
        self.metric_source.get_most_recent_value.assert_any_call(
            BasicAlarm.PROGRESS_METRIC_NAME,
            {"application_id": self.application_id_3})
        self.metric_source.get_most_recent_value.assert_any_call(
            BasicAlarm.ELAPSED_TIME_METRIC_NAME,
            {"application_id": self.application_id_3})

        # The method tries to get the amount of allocated resources
        self.actuator.get_allocated_resources.assert_called_once_with(
            self.instance_name_1)
        new_cap = self.allocated_resources + self.actuation_size
        # 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
        })

        # Scale down
        # Set up mocks
        self.alarm = BasicAlarm(self.actuator, self.metric_source,
                                self.trigger_down, self.trigger_up,
                                self.min_cap, self.max_cap,
                                self.actuation_size, 2)

        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 = MagicMock(
            return_value=self.allocated_resources)

        self.alarm.check_application_state(self.application_id_4,
                                           self.instances)

        # The method tries to get the metrics correctly
        self.metric_source.get_most_recent_value.assert_any_call(
            BasicAlarm.PROGRESS_METRIC_NAME,
            {"application_id": self.application_id_4})
        self.metric_source.get_most_recent_value.assert_any_call(
            BasicAlarm.ELAPSED_TIME_METRIC_NAME,
            {"application_id": self.application_id_4})

        # The method tries to get the amount of allocated resources
        self.actuator.get_allocated_resources.assert_called_once_with(
            self.instance_name_1)
        new_cap = self.allocated_resources - self.actuation_size
        # 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
        })

        #
        # The metrics are rounded to 3 digits from the decimal point
        # There should not be scale up and down in these cases
        #
        self.alarm = BasicAlarm(self.actuator, self.metric_source,
                                self.trigger_down, self.trigger_up,
                                self.min_cap, self.max_cap,
                                self.actuation_size, 3)

        # Scale up
        # Start 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 = MagicMock(
            return_value=self.allocated_resources)

        self.alarm.check_application_state(self.application_id_3,
                                           self.instances)

        # The method tries to get the metrics correctly
        self.metric_source.get_most_recent_value.assert_any_call(
            BasicAlarm.PROGRESS_METRIC_NAME,
            {"application_id": self.application_id_3})
        self.metric_source.get_most_recent_value.assert_any_call(
            BasicAlarm.ELAPSED_TIME_METRIC_NAME,
            {"application_id": self.application_id_3})

        # The method doesn't try to get the amount of allocated resources
        self.actuator.get_allocated_resources.assert_not_called()
        # The method doesn't try to adjust the amount of resources
        self.actuator.adjust_resources.assert_not_called()

        # Scale down
        # Start up mocks
        self.alarm = BasicAlarm(self.actuator, self.metric_source,
                                self.trigger_down, self.trigger_up,
                                self.min_cap, self.max_cap,
                                self.actuation_size, 3)

        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 = MagicMock(
            return_value=self.allocated_resources)

        self.alarm.check_application_state(self.application_id_4,
                                           self.instances)

        # The method tries to get the metrics correctly
        self.metric_source.get_most_recent_value.assert_any_call(
            BasicAlarm.PROGRESS_METRIC_NAME,
            {"application_id": self.application_id_4})
        self.metric_source.get_most_recent_value.assert_any_call(
            BasicAlarm.ELAPSED_TIME_METRIC_NAME,
            {"application_id": self.application_id_4})

        # The method doesn't try to get the amount of allocated resources
        self.actuator.get_allocated_resources.assert_not_called()
        # The method doesn't try to adjust the amount of resources
        self.actuator.adjust_resources.assert_not_called()

    @unittest.skip
    def test_alarm_does_not_reuse_metrics_with_same_timestamp(self):
        self.alarm = BasicAlarm(self.actuator, self.metric_source,
                                self.trigger_down, self.trigger_up,
                                self.min_cap, self.max_cap,
                                self.actuation_size, 2)

        # 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 = MagicMock(
            return_value=self.allocated_resources)

        self.alarm.check_application_state(self.application_id_0,
                                           self.instances)

        # The method tries to get the metrics correctly
        self.metric_source.get_most_recent_value.assert_any_call(
            BasicAlarm.PROGRESS_METRIC_NAME,
            {"application_id": self.application_id_0})
        self.metric_source.get_most_recent_value.assert_any_call(
            BasicAlarm.ELAPSED_TIME_METRIC_NAME,
            {"application_id": self.application_id_0})

        # The method tries to get the amount of allocated resources
        self.actuator.get_allocated_resources.assert_called_once_with(
            self.instance_name_1)
        # Add resources
        new_cap = self.allocated_resources + self.actuation_size
        # 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
        })

        #
        # 2nd call. The method checks if the metric is new and does not acts
        #

        # 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 = MagicMock(
            return_value=self.allocated_resources)

        self.alarm.check_application_state(self.application_id_0,
                                           self.instances)

        # The method tries to get the metrics correctly
        self.metric_source.get_most_recent_value.assert_any_call(
            BasicAlarm.PROGRESS_METRIC_NAME,
            {"application_id": self.application_id_0})
        self.metric_source.get_most_recent_value.assert_any_call(
            BasicAlarm.ELAPSED_TIME_METRIC_NAME,
            {"application_id": self.application_id_0})

        # The method doesn't try to get the amount of allocated resources
        self.actuator.get_allocated_resources.assert_not_called()
        # The method doesn't try to adjust the amount of resources
        self.actuator.adjust_resources.assert_not_called()

    @unittest.skip
    def test_alarm_metrics_with_different_timestamps(self):
        # Set up mocks
        self.metric_source.get_most_recent_value = MagicMock()
        self.metric_source.get_most_recent_value\
            .side_effect = self.metrics_different_timestamps

        self.actuator.adjust_resources = MagicMock(return_value=None)
        self.actuator.get_allocated_resources = MagicMock(
            return_value=self.allocated_resources)

        self.alarm.check_application_state(self.application_id_2,
                                           self.instances)

        # The method tries to get the metrics correctly
        self.metric_source.get_most_recent_value.assert_any_call(
            BasicAlarm.PROGRESS_METRIC_NAME,
            {"application_id": self.application_id_2})
        self.metric_source.get_most_recent_value.assert_any_call(
            BasicAlarm.ELAPSED_TIME_METRIC_NAME,
            {"application_id": self.application_id_2})

        # The method tries to get the amount of allocated resources
        self.actuator.get_allocated_resources.assert_called_once_with(
            self.instance_name_1)
        # Remove resources
        new_cap = self.allocated_resources - self.actuation_size
        # 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
        })

        #
        # 2nd call. The method checks if the metric is new and acts
        #

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

        self.actuator.adjust_resources = MagicMock(return_value=None)
        self.actuator.get_allocated_resources = MagicMock(
            return_value=self.allocated_resources)

        self.alarm.check_application_state(self.application_id_2,
                                           self.instances)

        # The method tries to get the metrics correctly
        self.metric_source.get_most_recent_value.assert_any_call(
            BasicAlarm.PROGRESS_METRIC_NAME,
            {"application_id": self.application_id_2})
        self.metric_source.get_most_recent_value.assert_any_call(
            BasicAlarm.ELAPSED_TIME_METRIC_NAME,
            {"application_id": self.application_id_2})

        # The method tries to get the amount of allocated resources
        self.actuator.get_allocated_resources.assert_called_once_with(
            self.instance_name_1)
        # Remove resources
        new_cap = self.allocated_resources - self.actuation_size
        # 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_alarm_metric_rounding(self):
        #
        # The metrics are rounded to 2 digits from the decimal point
        # There should be scale up and down in these cases
        #
        self.alarm = BasicAlarm(self.actuator, self.metric_source,
                                self.trigger_down, self.trigger_up,
                                self.min_cap, self.max_cap,
                                self.actuation_size, 2)

        # Scale up
        # 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 = MagicMock(
            return_value=self.allocated_resources)

        self.alarm.check_application_state(self.application_id_3,
                                           self.instances)

        # The method tries to get the metrics correctly
        self.metric_source.get_most_recent_value.assert_any_call(
            BasicAlarm.PROGRESS_METRIC_NAME,
            {"application_id": self.application_id_3})
        self.metric_source.get_most_recent_value.assert_any_call(
            BasicAlarm.ELAPSED_TIME_METRIC_NAME,
            {"application_id": self.application_id_3})

        # The method tries to get the amount of allocated resources
        self.actuator.get_allocated_resources.assert_called_once_with(
            self.instance_name_1)
        new_cap = self.allocated_resources + self.actuation_size
        # 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
        })

        # Scale down
        # Set up mocks
        self.alarm = BasicAlarm(self.actuator, self.metric_source,
                                self.trigger_down, self.trigger_up,
                                self.min_cap, self.max_cap,
                                self.actuation_size, 2)

        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 = MagicMock(
            return_value=self.allocated_resources)

        self.alarm.check_application_state(self.application_id_4,
                                           self.instances)

        # The method tries to get the metrics correctly
        self.metric_source.get_most_recent_value.assert_any_call(
            BasicAlarm.PROGRESS_METRIC_NAME,
            {"application_id": self.application_id_4})
        self.metric_source.get_most_recent_value.assert_any_call(
            BasicAlarm.ELAPSED_TIME_METRIC_NAME,
            {"application_id": self.application_id_4})

        # The method tries to get the amount of allocated resources
        self.actuator.get_allocated_resources.assert_called_once_with(
            self.instance_name_1)
        new_cap = self.allocated_resources - self.actuation_size
        # 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
        })

        #
        # The metrics are rounded to 3 digits from the decimal point
        # There should not be scale up and down in these cases
        #
        self.alarm = BasicAlarm(self.actuator, self.metric_source,
                                self.trigger_down, self.trigger_up,
                                self.min_cap, self.max_cap,
                                self.actuation_size, 3)

        # Scale up
        # Start 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 = MagicMock(
            return_value=self.allocated_resources)

        self.alarm.check_application_state(self.application_id_3,
                                           self.instances)

        # The method tries to get the metrics correctly
        self.metric_source.get_most_recent_value.assert_any_call(
            BasicAlarm.PROGRESS_METRIC_NAME,
            {"application_id": self.application_id_3})
        self.metric_source.get_most_recent_value.assert_any_call(
            BasicAlarm.ELAPSED_TIME_METRIC_NAME,
            {"application_id": self.application_id_3})

        # The method doesn't try to get the amount of allocated resources
        self.actuator.get_allocated_resources.assert_not_called()
        # The method doesn't try to adjust the amount of resources
        self.actuator.adjust_resources.assert_not_called()

        # Scale down
        # Start up mocks
        self.alarm = BasicAlarm(self.actuator, self.metric_source,
                                self.trigger_down, self.trigger_up,
                                self.min_cap, self.max_cap,
                                self.actuation_size, 3)

        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 = MagicMock(
            return_value=self.allocated_resources)

        self.alarm.check_application_state(self.application_id_4,
                                           self.instances)

        # The method tries to get the metrics correctly
        self.metric_source.get_most_recent_value.assert_any_call(
            BasicAlarm.PROGRESS_METRIC_NAME,
            {"application_id": self.application_id_4})
        self.metric_source.get_most_recent_value.assert_any_call(
            BasicAlarm.ELAPSED_TIME_METRIC_NAME,
            {"application_id": self.application_id_4})

        # The method doesn't try to get the amount of allocated resources
        self.actuator.get_allocated_resources.assert_not_called()
        # The method doesn't try to adjust the amount of resources
        self.actuator.adjust_resources.assert_not_called()