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 __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 get_controller(self, name, app_id, plugin_info): if name == "basic": metric_source_type = plugin_info["policy"]["metric_source"] actuator_type = plugin_info["policy"]["actuator"] metric_source = MetricSourceBuilder().get_metric_source( metric_source_type) actuator = ActuatorBuilder().get_actuator(actuator_type) return BasicController(metric_source, actuator, plugin_info) elif name == "single": return SingleApplicationController(app_id, plugin_info) elif name == "progress_error": return GenericController(app_id, plugin_info) elif name == "proportional": return ProportionalController(app_id, plugin_info) elif name == "proportional_derivative": return ProportionalDerivativeController(app_id, plugin_info) elif name == "pid": return PIDController(app_id, plugin_info) elif name == "progress_tendency": return TendencyAwareProportionalController(app_id, plugin_info) else: # FIXME: exception type raise Exception("Unknown controller type")
def __init__(self, data): # TODO: Check parameters scaling_parameters = data["control_parameters"] self.metric_source = MetricSourceBuilder().\ get_metric_source(scaling_parameters.get('metric_source'), data) self.app_id = data.get('app_id') scaling_parameters.update({'app_id': self.app_id}) self.scheduler = self.setup_scheduler(scaling_parameters) self.actuator = self.setup_actuator(scaling_parameters) self.logger = ScalingLog("%s.generic.alarm.log" % (self.app_id), "controller.log", self.app_id) self.cap_logger = ScalingLog("%s.cap.log" % (self.app_id), "cap.log", self.app_id) self.last_progress_error_timestamp = datetime.datetime.strptime( "0001-01-01T00:00:00.0Z", '%Y-%m-%dT%H:%M:%S.%fZ') self.last_action = "" self.cap = -1
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 __init__(self, application_id, parameters): self.logger = ScalingLog( "diff.controller.log", "controller.log", application_id) scaling_parameters = parameters["control_parameters"] self.application_id = application_id parameters.update({"app_id": application_id}) # Read scaling parameters self.check_interval = scaling_parameters["check_interval"] self.actuator_metric = scaling_parameters["actuator_metric"] self.trigger_down = scaling_parameters["trigger_down"] self.trigger_up = scaling_parameters["trigger_up"] self.min_quota = scaling_parameters["min_quota"] self.max_quota = scaling_parameters["max_quota"] # The actuator plugin name self.actuator_type = scaling_parameters["actuator"] # The metric source plugin name self.metric_source_type = scaling_parameters["metric_source"] # We use a lock here to prevent race conditions when stopping the # controller self.running = True self.running_lock = threading.RLock() # Gets a new metric source plugin using the given name metric_source = MetricSourceBuilder().get_metric_source( self.metric_source_type, parameters) # TODO: Add new actuator as option in the ActuatorBuilder # Gets a new actuator plugin using the given name actuator = ActuatorBuilder().get_actuator(self.actuator_type, parameters=parameters) # The alarm here is responsible for deciding whether to scale up or # down, or even do nothing self.alarm = Vertical( actuator, metric_source, self.actuator_metric, self.trigger_down, self.trigger_up, self.min_quota, self.max_quota, self.application_id)
def __init__(self, application_id, plugin_info): self.logger = Log( "tendency.proportional.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.metric_rounding = plugin_info["metric_rounding"] self.actuation_size = plugin_info["actuation_size"] self.actuator_type = plugin_info["actuator"] self.metric_source_type = plugin_info["metric_source"] self.running = True self.running_lock = threading.RLock() # Gets a new metric source plugin using the given name metric_source = MetricSourceBuilder().get_metric_source( self.metric_source_type, plugin_info ) # Gets a new actuator plugin using the given name actuator = ActuatorBuilder().get_actuator(self.actuator_type, plugin_info) """ The alarm here is responsible for deciding whether to scale up or down, or even do nothing """ self.alarm = TendencyAwareProportionalAlarm(actuator, metric_source, self.trigger_down, self.trigger_up, self.min_cap, self.max_cap, self.actuation_size, self.metric_rounding)
def setUp(self): config = ConfigParser.RawConfigParser() config.get = MagicMock() config.get.side_effect = self.config_values self.bigsea_username = "******" self.bigsea_password = "******" scaling_parameters = { "check_interval": self.CHECK_INTERVAL, "trigger_down": 10, "trigger_up": 10, "min_cap": 10, "max_cap": 100, "actuation_size": 20, "metric_rounding": 2 } parameters = { "scaling_parameters": scaling_parameters, "bigsea_username": self.bigsea_username, "bigsea_password": self.bigsea_password } metric_source = MetricSourceBuilder().get_metric_source("nop", {}) actuator = ActuatorBuilder().get_actuator("nop", parameters) self.controller = BasicController(metric_source, actuator, scaling_parameters) self.application_id_1 = "app-01" self.application_id_2 = "app-02" self.instance_1 = "instance-1" self.instance_2 = "instance-2" self.instances_1 = [self.instance_1, self.instance_2] self.instances_2 = [self.instance_2] self.parameters_1 = {"instances": self.instances_1} self.parameters_2 = {"instances": self.instances_2}
def __init__(self, application_id, plugin_info): self.logger = ScalingLog( "diff.controller.log", "controller.log", application_id) 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"] """ We use a lock here to prevent race conditions when stopping the controller """ self.running = True self.running_lock = threading.RLock() # Gets a new metric source plugin using the given name metric_source = MetricSourceBuilder().get_metric_source( self.metric_source_type, plugin_info) # Gets a new actuator plugin using the given name actuator = ActuatorBuilder().get_actuator(self.actuator_type) """ The alarm here is responsible for deciding whether to scale up or down, or even do nothing """ self.alarm = GenericAlarm(actuator, metric_source, self.trigger_down, self.trigger_up, self.min_cap, self.max_cap, self.actuation_size, self.metric_rounding, application_id, self.instances)
def setUp(self): self.application_id_0 = "app-00" self.application_id_1 = "app-01" self.application_id_2 = "app-02" 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.instances = [self.instance_name_1, self.instance_name_2] 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 = 78 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) 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.proportional_factor = 1 self.factor_up = 1 self.factor_down = 0.5 self.heuristic_options_error_proportional = { "heuristic_name": "error_proportional", "proportional_factor": self.proportional_factor } self.heuristic_options_error_proportional_up_down = \ {"heuristic_name": "error_proportional_up_down", "factor_up": self.factor_up, "factor_down": self.factor_down} self.progress_error = { self.application_id_0: -20.0, self.application_id_1: 0.00, self.application_id_2: 30.0 } self.timestamps = [ self.timestamp_1, self.timestamp_2, self.timestamp_3, self.timestamp_4 ]
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.application_id_5 = "app-05" self.application_id_6 = "app-06" self.application_id_7 = "app-07" self.application_id_8 = "app-08" self.application_id_9 = "app-09" 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.timestamps = [ self.timestamp_1, self.timestamp_2, self.timestamp_3, self.timestamp_4 ] self.instance_name_1 = "instance1" self.instance_name_2 = "instance2" self.instances = [self.instance_name_1, self.instance_name_2] self.trigger_down = 0.0 self.trigger_up = 0.0 self.min_cap = 10.0 self.max_cap = 100.0 self.actuation_size = 10.0 self.allocated_resources_scale_down = 100 self.allocated_resources_scale_up = 10 self.metric_round = 2 self.default_io_cap = 34 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) 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.proportional_factor = 1.5 self.derivative_factor = 0.5 self.integrative_factor = 1.5 self.heuristic_options = { "heuristic_name": "error_pid", "proportional_factor": self.proportional_factor, "derivative_factor": self.derivative_factor, "integrative_factor": self.integrative_factor } self.progress_error = { # CASE 1 self.application_id_0: { self.timestamp_1: -30.0, self.timestamp_2: -20.0, self.timestamp_3: -15.0 }, # CASE 2 self.application_id_1: { self.timestamp_1: -30.0, self.timestamp_2: -40.0, self.timestamp_3: -60.0 }, # CASE 3 self.application_id_2: { self.timestamp_1: 30.0, self.timestamp_2: 20.0, self.timestamp_3: 15.0 }, # CASE 4 self.application_id_3: { self.timestamp_1: 30.0, self.timestamp_2: 40.0, self.timestamp_3: 55.0 }, # CASE 5 self.application_id_4: { self.timestamp_1: 100.0, self.timestamp_2: 100.0, self.timestamp_3: 100.0 }, # CASE 6 self.application_id_5: { self.timestamp_1: -100.0, self.timestamp_2: -100.0, self.timestamp_3: -100.0 }, # CASE 7 self.application_id_6: { self.timestamp_1: -30.0, self.timestamp_2: 10.0, self.timestamp_3: 30.0 }, # CASE 8 self.application_id_7: { self.timestamp_1: -5.0, self.timestamp_2: -1.0, self.timestamp_3: 2.0 }, # CASE 9 self.application_id_8: { self.timestamp_1: -10.0, self.timestamp_2: -5.0, self.timestamp_3: 20.0, self.timestamp_4: -5.0 }, # CASE 10 self.application_id_9: { self.timestamp_1: -10.0, self.timestamp_2: 0.0, self.timestamp_3: 10.0, self.timestamp_4: 5.0 } }
class KubeJobs: ERROR_METRIC_NAME = "application-progress.error" def __init__(self, data): # TODO: Check parameters scaling_parameters = data["control_parameters"] self.metric_source = MetricSourceBuilder().\ get_metric_source(scaling_parameters.get('metric_source'), data) self.app_id = data.get('app_id') scaling_parameters.update({'app_id': self.app_id}) self.scheduler = self.setup_scheduler(scaling_parameters) self.actuator = self.setup_actuator(scaling_parameters) self.logger = ScalingLog("%s.generic.alarm.log" % (self.app_id), "controller.log", self.app_id) self.cap_logger = ScalingLog("%s.cap.log" % (self.app_id), "cap.log", self.app_id) self.last_progress_error_timestamp = datetime.datetime.strptime( "0001-01-01T00:00:00.0Z", '%Y-%m-%dT%H:%M:%S.%fZ') self.last_action = "" self.cap = -1 def setup_scheduler(self, parameters): strategy = parameters.get('schedule_strategy') if strategy == "default": return DefaultScheduler(parameters) elif strategy == "pid": return PidScheduler(parameters) def setup_actuator(self, parameters): actuator = parameters.get('actuator') return ActuatorBuilder().get_actuator(actuator, parameters) def check_application_state(self): """ Checks the application progress by getting progress metrics from a metric source, checks if the metrics are new and tries to modify the amount of allocated resources if necessary. """ # TODO: Check parameters progress_error_timestamp, progress_error = \ self._get_progress_error(self.app_id) self.last_action = "Progress error-[%s]-%f" % \ (str(progress_error_timestamp), progress_error) if self._check_measurements_are_new(progress_error_timestamp): self._scale(progress_error) if self.cap != -1: self.cap_logger.log("%.0f|%s|%s" % (time.time(), str(self.app_id), str(self.cap))) self.last_progress_error_timestamp = progress_error_timestamp else: self.last_action += " Could not acquire more recent metrics" self.logger.log(self.last_action) def _get_progress_error(self, app_id): self.last_action = "Getting progress error" self.logger.log(self.last_action) progress_error_measurement = self.metric_source.get_most_recent_value( app_id) progress_error_timestamp = progress_error_measurement[0] progress_error = progress_error_measurement[1] return progress_error_timestamp, progress_error def _scale(self, progress_error): last_replicas = self.actuator.get_number_of_replicas() info = {'last_replicas': last_replicas, 'progress_error': progress_error} new_resource_allocation = self.scheduler.scale(info) if new_resource_allocation is not None: self.logger.log("Scaling from %d to %d" % (last_replicas, new_resource_allocation)) self.actuator.adjust_resources(new_resource_allocation) def _check_measurements_are_new(self, progress_error_timestamp): return self.last_progress_error_timestamp < progress_error_timestamp def status(self): return self.last_action