Example #1
0
def main():
    try:
        check_sanity()
    except Exception as e:
        MyUtils.log_error("{0} {1}".format(str(e),
                                           str(traceback.format_exc())),
                          debug=True)
Example #2
0
def main():
    try:
        rebalancer = ReBalancer()
        rebalancer.rebalance()
    except Exception as e:
        MyUtils.log_error("{0} {1}".format(str(e),
                                           str(traceback.format_exc())),
                          debug=True)
def main():
    try:
        energy_manager = EnergyManager()
        energy_manager.process()
    except Exception as e:
        MyUtils.log_error("{0} {1}".format(str(e),
                                           str(traceback.format_exc())),
                          debug=True)
Example #4
0
def check_unstable_configuration():
    try:
        MyUtils.log_info("Checking for invalid configuration", debug)
        service = MyUtils.get_service(db_handler, "guardian")
        guardian_configuration = service["config"]
        event_timeout = MyUtils.get_config_value(
            guardian_configuration,
            src.Guardian.Guardian.CONFIG_DEFAULT_VALUES, "EVENT_TIMEOUT")
        window_timelapse = MyUtils.get_config_value(
            guardian_configuration,
            src.Guardian.Guardian.CONFIG_DEFAULT_VALUES, "WINDOW_TIMELAPSE")

        rules = db_handler.get_rules()
        for rule in rules:
            if "generates" in rule and rule[
                    "generates"] == "requests" and rule["active"]:
                event_count = int(rule["events_to_remove"])
                event_window_time_to_trigger = window_timelapse * (event_count)
                # Leave a slight buffer time to account for window times skewness
                if event_window_time_to_trigger > event_timeout:
                    MyUtils.log_error(
                        "Rule: '{0}' could never be activated -> guardian event timeout: '{1}', number of events"
                        .format(rule["name"], str(event_timeout)) +
                        " required to trigger the rule: '{0}' and guardian polling time: '{1}'"
                        .format(str(event_count), str(window_timelapse)),
                        debug)
    except Exception as e:
        MyUtils.log_error(
            "Error doing configuration check up: {0} {1}".format(
                str(e), str(traceback.format_exc())), debug)
Example #5
0
def app_can_be_rebalanced(application, rebalancing_level, couchdb_handler):
    try:
        data = {
            # "energy":
            #     {"structure":
            #          {"energy":
            #               {"usage": application["resources"]["energy"]["usage"],
            #                "max": application["resources"]["energy"]["max"]}}},
            "cpu": {
                "structure": {
                    "cpu": {
                        "usage": application["resources"]["cpu"]["usage"],
                        "min": application["resources"]["cpu"]["min"],
                        "current": application["resources"]["cpu"]["current"]
                    }
                }
            }
        }
    except KeyError:
        return False

    if rebalancing_level != "container" and rebalancing_level != "application":
        MyUtils.log_error(
            "Invalid app rebalancing policy '{0}'".format(rebalancing_level),
            debug=True)
        return False

    # rule_low_usage = couchdb_handler.get_rule("energy_exceeded_upper")
    # if jsonLogic(rule_low_usage["rule"], data):
    #     # Application is overusing energy
    #     if rebalancing_level == "container":
    #         # Let the Guardian or the dynamic energy balancing deal with it
    #         return False
    #     elif rebalancing_level == "application":
    #         # It may be a receiver for dynamic energy rebalancing
    #         return True
    #
    # rule_high_usage = couchdb_handler.get_rule("energy_dropped_lower")
    # if jsonLogic(rule_high_usage["rule"], data):
    #     # Application is underusing energy
    #     if rebalancing_level == "container":
    #         # Let the Guardian or the dynamic energy balancing deal with it
    #         return False
    #         # It may be a donor for dynamic energy rebalancing
    #     elif rebalancing_level == "application":
    #         return True

    # The application is in the middle area of energy utilization
    if rebalancing_level == "container":
        # Perform an internal balancing through container cpu limit rebalancing
        return True
    elif rebalancing_level == "application":
        # It may need internal container rebalancing
        return False
Example #6
0
    def rebalance(self, ):
        logging.basicConfig(filename=SERVICE_NAME + '.log', level=logging.INFO)
        while True:
            # Get service info
            service = MyUtils.get_service(self.couchdb_handler, SERVICE_NAME)

            # Heartbeat
            MyUtils.beat(self.couchdb_handler, SERVICE_NAME)

            # CONFIG
            self.config = service["config"]
            self.debug = MyUtils.get_config_value(self.config,
                                                  CONFIG_DEFAULT_VALUES,
                                                  "DEBUG")
            window_difference = MyUtils.get_config_value(
                self.config, CONFIG_DEFAULT_VALUES, "WINDOW_TIMELAPSE")

            #self.userReBalancer.rebalance_users(self.config)
            #self.applicationReBalancer.rebalance_applications(self.config)
            self.containerRebalancer.rebalance_containers(self.config)

            MyUtils.log_info(
                "Epoch processed at {0}".format(MyUtils.get_time_now_string()),
                self.debug)

            time.sleep(window_difference)
Example #7
0
    def __dynamic_app_rebalancing(self, applications):
        donors, receivers = list(), list()
        for app in applications:
            if self.__app_energy_can_be_rebalanced(app):
                diff = app["resources"]["energy"]["max"] - app["resources"][
                    "energy"]["usage"]
                if diff > self.__ENERGY_DIFF_PERCENTAGE * app["resources"][
                        "energy"]["max"]:
                    donors.append(app)
                else:
                    receivers.append(app)

        if not receivers:
            MyUtils.log_info("No app to give energy shares", self.__debug)
            return
        else:
            # Order the apps from lower to upper energy limit
            apps_to_receive = sorted(
                receivers, key=lambda c: c["resources"]["energy"]["max"])

        shuffling_tuples = list()
        for app in donors:
            diff = app["resources"]["energy"]["max"] - app["resources"][
                "energy"]["usage"]
            stolen_amount = self.__ENERGY_STOLEN_PERCENTAGE * diff
            shuffling_tuples.append((app, stolen_amount))
        shuffling_tuples = sorted(shuffling_tuples, key=lambda c: c[1])

        # Give the resources to the bottlenecked applications
        for receiver in apps_to_receive:

            if shuffling_tuples:
                donor, amount_to_scale = shuffling_tuples.pop(0)
            else:
                MyUtils.log_info(
                    "No more donors, app {0} left out".format(
                        receiver["name"]), self.__debug)
                continue

            donor["resources"]["energy"]["max"] -= amount_to_scale
            receiver["resources"]["energy"]["max"] += amount_to_scale

            MyUtils.update_structure(donor, self.__couchdb_handler,
                                     self.__debug)
            MyUtils.update_structure(receiver, self.__couchdb_handler,
                                     self.__debug)

            MyUtils.log_info(
                "Energy swap between {0}(donor) and {1}(receiver)".format(
                    donor["name"], receiver["name"]), self.__debug)
Example #8
0
def check_sanity():
    logging.basicConfig(filename=SERVICE_NAME + '.log', level=logging.INFO)
    global debug
    while True:
        # Get service info
        service = MyUtils.get_service(db_handler, SERVICE_NAME)

        # CONFIG
        config = service["config"]
        debug = MyUtils.get_config_value(config, CONFIG_DEFAULT_VALUES,
                                         "DEBUG")
        delay = MyUtils.get_config_value(config, CONFIG_DEFAULT_VALUES,
                                         "DELAY")

        compact_databases()
        check_unstable_configuration()
        # check_core_mapping()
        MyUtils.log_info("Sanity checked", debug)

        time_waited = 0
        heartbeat_delay = 10  # seconds

        while time_waited < delay:
            # Heartbeat
            MyUtils.beat(db_handler, SERVICE_NAME)
            time.sleep(heartbeat_delay)
            time_waited += heartbeat_delay
Example #9
0
 def beat(self):
     # Serverless Containers
     from src.StateDatabase import couchdb as couchDB
     from src.MyUtils import MyUtils as MyUtils
     self.logger.info("Starting heartbeat of " + self.SERVICE_NAME)
     db_handler = couchDB.CouchDBServer()
     while True:
         try:
             MyUtils.beat(db_handler, self.SERVICE_NAME)
             time.sleep(10)
         except ValueError:
             # Service not found:
             # - maybe it doesn't exist at all, register it
             # - it may have been deleted while the daemon was running, re-register it
             register_service(db_handler, self.SERVICE_NAME)
         except requests.ConnectionError:
             # Error connecting to the Couchdb database, ignore as it may be temporary
             pass
def disable_scaler(scaler_service):
    scaler_service["config"]["ACTIVE"] = False
    get_db().update_service(scaler_service)

    # Wait a little bit, half the polling time of the Scaler
    polling_freq = MyUtils.get_config_value(
        scaler_service["config"], src.Scaler.Scaler.CONFIG_DEFAULT_VALUES,
        "POLLING_FREQUENCY")
    time.sleep(int(polling_freq))
Example #11
0
    def __inter_user_rebalancing(self, users):
        donors, receivers = list(), list()
        for user in users:
            diff = user["energy"]["max"] - user["energy"]["used"]
            if diff > self.__ENERGY_DIFF_PERCENTAGE * user["energy"]["max"]:
                donors.append(user)
            else:
                receivers.append(user)

        if not receivers:
            MyUtils.log_info("No user to give energy shares", self.__debug)
            return
        else:
            # Order the apps from lower to upper energy limit
            users_to_receive = sorted(receivers,
                                      key=lambda c: c["energy"]["max"])

        shuffling_tuples = list()
        for user in donors:
            diff = user["energy"]["max"] - user["energy"]["used"]
            stolen_amount = self.__ENERGY_STOLEN_PERCENTAGE * diff
            shuffling_tuples.append((user, stolen_amount))
        shuffling_tuples = sorted(shuffling_tuples, key=lambda c: c[1])

        # Give the resources to the other users
        for receiver in users_to_receive:
            if shuffling_tuples:
                donor, amount_to_scale = shuffling_tuples.pop(0)
            else:
                MyUtils.log_info(
                    "No more donors, user {0} left out".format(
                        receiver["name"]), self.__debug)
                continue

            donor["energy"]["max"] -= amount_to_scale
            receiver["energy"]["max"] += amount_to_scale

            MyUtils.update_user(donor, self.__couchdb_handler, self.__debug)
            MyUtils.update_user(receiver, self.__couchdb_handler, self.__debug)

            MyUtils.log_info(
                "Energy swap between {0}(donor) and {1}(receiver)".format(
                    donor["name"], receiver["name"]), self.__debug)
Example #12
0
    def __static_app_rebalancing(self, applications, max_energy):
        # Add up all the shares
        total_shares = sum(
            [app["resources"]["energy"]["shares"] for app in applications])

        # For each application calculate the energy according to its shares
        for app in applications:
            percentage = app["resources"]["energy"]["shares"] / total_shares

            limit_energy = int(max_energy * percentage)
            current_energy = app["resources"]["energy"]["max"]

            # If the database record and the new limit are not the same, update
            if current_energy != limit_energy:
                app["resources"]["energy"]["max"] = limit_energy
                self.__couchdb_handler.update_structure(app)
                MyUtils.log_info(
                    "Updated energy limit of app {0}".format(app["name"]),
                    self.__debug)
Example #13
0
    def update_user_used_energy(self, applications, users):
        for user in users:
            total_user = {"cpu": 0, "energy": 0}
            total_user_current_cpu = 0
            user_apps = get_user_apps(applications, user)
            for app in user_apps:
                for resource in ["energy", "cpu"]:
                    if "usage" in app["resources"][resource] and app[
                            "resources"][resource]["usage"]:
                        total_user[resource] += app["resources"][resource][
                            "usage"]
                    else:
                        MyUtils.log_error(
                            "Application {0} of user {1} has no used {2} field or value"
                            .format(app["name"], user["name"],
                                    resource), self.__debug)

                if "current" in app["resources"]["cpu"] and app["resources"][
                        "cpu"]["usage"]:
                    total_user_current_cpu += app["resources"][resource][
                        "current"]
                else:
                    MyUtils.log_error(
                        "Application {0} of user {1} has no current cpu field or value"
                        .format(app["name"], user["name"]), self.__debug)

            user["energy"]["used"] = total_user["energy"]
            user["cpu"]["usage"] = total_user["cpu"]
            user["cpu"]["current"] = total_user_current_cpu
            self.__couchdb_handler.update_user(user)
            MyUtils.log_info(
                "Updated energy consumed by user {0}".format(user["name"]),
                self.__debug)
def desubscribe_container(structure_name):
    structure = retrieve_structure(structure_name)
    cont_name = structure["name"]

    # Look for any application that hosts this container, and remove it from the list
    apps = get_db().get_structures(subtype="application")
    for app in apps:
        if cont_name in app["containers"]:
            desubscribe_container_from_app(structure_name, app["name"])

    # Disable the Scaler as we will modify the core mapping of a host
    scaler_service = get_db().get_service(src.Scaler.Scaler.SERVICE_NAME)
    previous_state = MyUtils.get_config_value(
        scaler_service["config"], src.Scaler.Scaler.CONFIG_DEFAULT_VALUES,
        "ACTIVE")
    if previous_state:
        disable_scaler(scaler_service)

    # Free resources

    # CPU
    # Get the core map of the container's host and free the allocated shares for this container
    cont_host = structure["host"]
    host = get_db().get_structure(cont_host)
    core_map = host["resources"]["cpu"]["core_usage_mapping"]
    freed_shares = 0
    for core in core_map:
        if cont_name in core_map[core]:
            core_shares = core_map[core][cont_name]
            freed_shares += core_shares
            core_map[core][cont_name] = 0
            core_map[core]["free"] += core_shares
    host["resources"]["cpu"]["core_usage_mapping"] = core_map
    host["resources"]["cpu"]["free"] += freed_shares

    # MEM
    host["resources"]["mem"]["free"] += structure["resources"]["mem"][
        "current"]

    get_db().update_structure(host)

    # Delete the document for this structure
    get_db().delete_structure(structure)

    # Restore the previous state of the Scaler service
    restore_scaler_state(scaler_service, previous_state)

    return jsonify(201)
Example #15
0
def compact_databases():
    try:
        compacted_dbs = list()
        for db in DATABASES:
            success = db_handler.compact_database(db)
            if success:
                compacted_dbs.append(db)
            else:
                MyUtils.log_warning(
                    "Database {0} could not be compacted".format(db), debug)
        MyUtils.log_info(
            "Databases {0} have been compacted".format(str(compacted_dbs)),
            debug)
    except Exception as e:
        MyUtils.log_error(
            "Error doing database compaction: {0} {1}".format(
                str(e), str(traceback.format_exc())), debug)
Example #16
0
    def rebalance_users(self, config):
        self.__config = config
        self.__debug = MyUtils.get_config_value(self.__config,
                                                CONFIG_DEFAULT_VALUES, "DEBUG")

        rebalance_users = MyUtils.get_config_value(self.__config,
                                                   CONFIG_DEFAULT_VALUES,
                                                   "REBALANCE_USERS")

        self.__ENERGY_DIFF_PERCENTAGE = MyUtils.get_config_value(
            self.__config, CONFIG_DEFAULT_VALUES, "ENERGY_DIFF_PERCENTAGE")
        self.__ENERGY_STOLEN_PERCENTAGE = MyUtils.get_config_value(
            self.__config, CONFIG_DEFAULT_VALUES, "ENERGY_STOLEN_PERCENTAGE")
        MyUtils.log_info(
            "ENERGY_DIFF_PERCENTAGE -> {0}".format(
                self.__ENERGY_DIFF_PERCENTAGE), self.__debug)
        MyUtils.log_info(
            "ENERGY_STOLEN_PERCENTAGE -> {0}".format(
                self.__ENERGY_STOLEN_PERCENTAGE), self.__debug)

        MyUtils.log_info("_______________", self.__debug)
        MyUtils.log_info("Performing USER ENERGY Balancing", self.__debug)

        try:
            #applications = MyUtils.get_structures(self.__couchdb_handler, self.__debug, subtype="application")
            users = self.__couchdb_handler.get_users()
        except requests.exceptions.HTTPError as e:
            MyUtils.log_error("Couldn't get users and/or applications",
                              self.__debug)
            MyUtils.log_error(str(e), self.__debug)
            return

        #self.update_user_used_energy(applications, users)

        if rebalance_users:
            self.__inter_user_rebalancing(users)

        MyUtils.log_info("_______________\n", self.__debug)
Example #17
0
def register_service(db_handler, service_name):
    service = dict(name=service_name,
                   heartbeat="",
                   heartbeat_human="",
                   type="service")
    MyUtils.register_service(db_handler, service)
def subscribe_container(structure_name):
    req_cont = request.json["container"]
    req_limits = request.json["limits"]

    node_scaler_session = requests.Session()

    # Check that all the needed data is present on the requestes container
    container = {}
    for key in [
            "name", "host_rescaler_ip", "host_rescaler_port", "host", "guard",
            "subtype"
    ]:
        if key not in req_cont:
            return abort(400, {"message": "Missing key '{0}'".format(key)})
        else:
            container[key] = req_cont[key]

    # Check that all the needed data for resources is present on the requested container
    container["resources"] = {}
    if "resources" not in req_cont:
        return abort(400, {"message": "Missing resource information"})
    elif "cpu" not in req_cont["resources"] or "mem" not in req_cont[
            "resources"]:
        return abort(400,
                     {"message": "Missing cpu or mem resource information"})
    else:
        container["resources"] = {"cpu": {}, "mem": {}}
        for key in ["max", "min", "current", "guard"]:
            if key not in req_cont["resources"]["cpu"] or key not in req_cont[
                    "resources"]["mem"]:
                return abort(
                    400, {
                        "message":
                        "Missing key '{0}' for cpu or mem resource".format(key)
                    })
            else:
                container["resources"]["cpu"][key] = req_cont["resources"][
                    "cpu"][key]
                container["resources"]["mem"][key] = req_cont["resources"][
                    "mem"][key]

    # Check that the endpoint requested container name matches with the one in the request
    if container["name"] != structure_name:
        return abort(400, {"message": "Name mismatch".format(key)})

    # Check if the container already exists
    try:
        cont = get_db().get_structure(structure_name)
        if cont:
            return abort(400, {
                "message":
                "Container with this name already exists".format(key)
            })
    except ValueError:
        pass

    # Check that its supposed host exists and that it reports this container
    try:
        get_db().get_structure(container["host"])
    except ValueError:
        return abort(400,
                     {"message": "Container host does not exist".format(key)})
    host_containers = get_host_containers(container["host_rescaler_ip"],
                                          container["host_rescaler_port"],
                                          node_scaler_session, True)

    if container["name"] not in host_containers:
        return abort(
            400, {
                "message":
                "Container host does not report any container named '{0}'".
                format(container["name"])
            })

    container["type"] = "structure"

    # Check that all the needed data for resources is present on the requested container LIMITS
    limits = {}
    if "resources" not in req_limits:
        return abort(
            400, {"message": "Missing resource information for the limits"})
    elif "cpu" not in req_limits["resources"] or "mem" not in req_limits[
            "resources"]:
        return abort(400, {
            "message":
            "Missing cpu or mem resource information for the limits"
        })
    else:
        limits["resources"] = {"cpu": {}, "mem": {}}
        for key in ["boundary"]:
            if key not in req_limits["resources"][
                    "cpu"] or key not in req_limits["resources"]["mem"]:
                return abort(
                    400, {
                        "message":
                        "Missing key '{0}' for cpu or mem resource".format(key)
                    })
            else:
                limits["resources"]["cpu"][key] = req_limits["resources"][
                    "cpu"][key]
                limits["resources"]["mem"][key] = req_limits["resources"][
                    "mem"][key]

    limits["type"] = 'limit'
    limits["name"] = container["name"]

    #### ALL looks good up to this point, proceed

    # Disable the Scaler as we will modify the core mapping of a host
    scaler_service = get_db().get_service(src.Scaler.Scaler.SERVICE_NAME)
    previous_state = MyUtils.get_config_value(
        scaler_service["config"], src.Scaler.Scaler.CONFIG_DEFAULT_VALUES,
        "ACTIVE")
    if previous_state:
        disable_scaler(scaler_service)

    # Get the host info
    cont_host = container["host"]
    cont_name = container["name"]
    host = get_db().get_structure(cont_host)

    # CPU

    # Look for resource shares on the container's host
    needed_shares = container["resources"]["cpu"]["current"]
    if host["resources"]["cpu"]["free"] < needed_shares:
        return abort(
            400, {"message": "Host does not have enough shares".format(key)})

    core_map = host["resources"]["cpu"]["core_usage_mapping"]
    host_max_cores = int(host["resources"]["cpu"]["max"] / 100)
    host_cpu_list = [str(i) for i in range(host_max_cores)]

    pending_shares = needed_shares
    used_cores = list()

    # Try to satisfy the request by looking and adding a single core
    for core in host_cpu_list:
        if core_map[core]["free"] >= pending_shares:
            core_map[core]["free"] -= pending_shares
            core_map[core][cont_name] += pending_shares
            pending_shares = 0
            used_cores.append(core)
            break

    # Finally, if unsuccessful, add as many cores as necessary, starting with the ones with the largest free shares to avoid too much spread
    if pending_shares > 0:
        l = list()
        for core in host_cpu_list:
            l.append((core, core_map[core]["free"]))
        l.sort(key=lambda tup: tup[1], reverse=True)
        less_used_cores = [i[0] for i in l]

        for core in less_used_cores:
            # If this core has free shares
            if core_map[core]["free"] > 0 and pending_shares > 0:
                if cont_name not in core_map[core]:
                    core_map[core][cont_name] = 0

                    # If it has more free shares than needed, assign them and finish
                if core_map[core]["free"] >= pending_shares:
                    core_map[core]["free"] -= pending_shares
                    core_map[core][cont_name] += pending_shares
                    pending_shares = 0
                    used_cores.append(core)
                    break
                else:
                    # Otherwise, assign as many as possible and continue
                    core_map[core][cont_name] += core_map[core]["free"]
                    pending_shares -= core_map[core]["free"]
                    core_map[core]["free"] = 0
                    used_cores.append(core)

    if pending_shares > 0:
        return abort(
            400, {
                "message":
                "Container host does not have enough free CPU shares as requested"
            })

    host["resources"]["cpu"]["core_usage_mapping"] = core_map
    host["resources"]["cpu"]["free"] -= needed_shares

    # MEM
    needed_memory = container["resources"]["mem"]["current"]
    host_memory = host["resources"]["mem"]["free"]

    if needed_memory > host_memory:
        return abort(400, {
            "message":
            "Container host does not have enough free memory requested"
        })

    host["resources"]["mem"]["free"] -= needed_memory

    resource_dict = {
        "cpu": {
            "cpu_num": ",".join(used_cores),
            "cpu_allowance_limit": needed_shares
        },
        "mem": {
            "mem_limit": needed_memory
        }
    }

    Scaler.set_container_resources(node_scaler_session, container,
                                   resource_dict, True)

    get_db().add_structure(container)
    get_db().add_limit(limits)
    get_db().update_structure(host)

    # Restore the previous state of the Scaler service
    restore_scaler_state(scaler_service, previous_state)

    return jsonify(201)
    def process(self, ):
        logging.basicConfig(filename=SERVICE_NAME + '.log', level=logging.INFO)
        while True:

            # Get service info
            service = MyUtils.get_service(self.couchdb_handler, SERVICE_NAME)
            config = service["config"]
            self.debug = MyUtils.get_config_value(config,
                                                  CONFIG_DEFAULT_VALUES,
                                                  "DEBUG")
            polling_frequency = MyUtils.get_config_value(
                config, CONFIG_DEFAULT_VALUES, "POLLING_FREQUENCY")

            # Heartbeat
            MyUtils.beat(self.couchdb_handler, SERVICE_NAME)

            # Remote database operation
            users = None
            structures = None
            try:
                structures = MyUtils.get_structures(self.couchdb_handler,
                                                    self.debug,
                                                    subtype="application")
                users = self.couchdb_handler.get_users()
            except requests.exceptions.HTTPError as e:
                MyUtils.log_error("Couldn't get users", self.debug)
                MyUtils.log_error(str(e), self.debug)

            for user in users:
                MyUtils.log_info("Processing user {0}".format(user["name"]),
                                 self.debug)
                max_energy = user["energy"]["max"]

                # Add up all the shares
                total_shares = 0
                for structure in structures:
                    if structure["name"] in user["clusters"]:
                        total_shares += structure["resources"]["energy"][
                            "shares"]

                total_user_energy = 0
                for structure in structures:
                    if structure["name"] in user["clusters"]:
                        percentage = structure["resources"]["energy"][
                            "shares"] / total_shares
                        limit_energy = max_energy * percentage
                        current_energy = structure["resources"]["energy"][
                            "max"]

                        if current_energy != limit_energy:
                            structure["resources"]["energy"][
                                "max"] = limit_energy
                            self.couchdb_handler.update_structure(structure)

                        MyUtils.log_info(
                            "Processed cluster {0} with an energy share of {1}% and {2} Watts"
                            .format(structure["name"],
                                    str("%.2f" % (100 * percentage)),
                                    limit_energy), self.debug)

                        if "used" in structure["resources"]["energy"]:
                            total_user_energy += structure["resources"][
                                "energy"]["used"]

                MyUtils.log_info(
                    "Updated energy consumed by user {0}".format(user["name"]),
                    self.debug)
                user["energy"]["used"] = total_user_energy
                self.couchdb_handler.update_user(user)

            MyUtils.log_info(
                "Epoch processed at {0}".format(MyUtils.get_time_now_string()),
                self.debug)
            time.sleep(polling_frequency)
    def test_match_rules_and_events(self):

        def get_valid_state():
            st = {
                "guard": True,
                "guard_policy": "serverless",
                "host": "c14-13",
                "host_rescaler_ip": "c14-13",
                "host_rescaler_port": "8000",
                "name": "node0",
                "resources": {
                    "cpu": {
                        "current": 140,
                        "guard": True,
                        "max": 200,
                        "min": 50
                    },
                    "energy": {
                        "guard": False,
                        "max": 20,
                        "min": 0,
                        "usage": 2.34
                    },
                    "mem": {
                        "current": 3072,
                        "guard": True,
                        "max": 10240,
                        "min": 512
                    }
                },
                "subtype": "container",
                "type": "structure"
            }
            lim = {"cpu": {"upper": 120, "lower": 80, "boundary": 20},
                   "mem": {"upper": 2048, "lower": 1024, "boundary": 1024},
                   "energy": {"upper": 20, "lower": 10, "boundary": 5},
                   }

            us = {"structure.cpu.usage": 100, "structure.mem.usage": 1536, "structure.energy.usage": 15}

            return st, lim, us

        event_rules = [cpu_exceeded_upper, cpu_dropped_lower, mem_exceeded_upper, mem_dropped_lower,
                       energy_exceeded_upper, energy_dropped_lower]
        rescaling_rules = [CpuRescaleUp, CpuRescaleDown, MemRescaleUp, MemRescaleDown, EnergyRescaleUp,
                           EnergyRescaleDown]
        for rule in event_rules + rescaling_rules:
            rule["active"] = True

        self.guardian.guardable_resources = ["cpu", "mem"]

        for tuple in [("cpu", CpuRescaleDown, -50), ("mem", MemRescaleDown, -50), ("cpu", CpuRescaleUp, 100),
                      ("mem", MemRescaleUp, 2034)]:

            resource, rescale_rule, amount = tuple
            structure, limits, usages = get_valid_state()

            usages["structure." + resource + ".usage"] = limits[resource]["lower"] + amount
            events = list()

            num_needed_events = rescale_rule["rule"]["and"][0][">="][1]

            for i in range(num_needed_events):
                events += self.guardian.match_usages_and_limits(structure["name"], event_rules, usages, limits,
                                                                structure["resources"])
            events = self.guardian.reduce_structure_events(events)

            generated_requests, events_to_remove = self.guardian.match_rules_and_events(structure, rescaling_rules, events, limits, usages)

            expected_events_to_remove = dict()
            event_to_remove_name = MyUtils.generate_event_name(events[resource]["events"], resource)
            expected_events_to_remove[event_to_remove_name] = num_needed_events

            TestCase.assertEqual(self, first=expected_events_to_remove, second=events_to_remove)
Example #21
0
    def rebalance_applications(self, config):
        self.__config = config
        self.__debug = MyUtils.get_config_value(self.__config,
                                                CONFIG_DEFAULT_VALUES, "DEBUG")
        self.__ENERGY_DIFF_PERCENTAGE = MyUtils.get_config_value(
            self.__config, CONFIG_DEFAULT_VALUES, "ENERGY_DIFF_PERCENTAGE")
        self.__ENERGY_STOLEN_PERCENTAGE = MyUtils.get_config_value(
            self.__config, CONFIG_DEFAULT_VALUES, "ENERGY_STOLEN_PERCENTAGE")
        MyUtils.log_info("_______________", self.__debug)
        MyUtils.log_info("Performing APP ENERGY Balancing", self.__debug)
        MyUtils.log_info(
            "ENERGY_DIFF_PERCENTAGE -> {0}".format(
                self.__ENERGY_DIFF_PERCENTAGE), self.__debug)
        MyUtils.log_info(
            "ENERGY_STOLEN_PERCENTAGE -> {0}".format(
                self.__ENERGY_STOLEN_PERCENTAGE), self.__debug)

        try:
            applications = MyUtils.get_structures(self.__couchdb_handler,
                                                  self.__debug,
                                                  subtype="application")
            users = self.__couchdb_handler.get_users()
        except requests.exceptions.HTTPError as e:
            MyUtils.log_error("Couldn't get users and/or applications",
                              self.__debug)
            MyUtils.log_error(str(e), self.__debug)
            return

        for user in users:
            MyUtils.log_info("Processing user {0}".format(user["name"]),
                             self.__debug)
            user_apps = get_user_apps(applications, user)
            if "energy_policy" not in user:
                balancing_policy = "static"
                MyUtils.log_info(
                    "Energy balancing policy unset for user {0}, defaulting to 'static'"
                    .format(user["name"]), self.__debug)
            else:
                balancing_policy = user["energy_policy"]

            MyUtils.log_info(
                "User {0} has {1} policy".format(user["name"],
                                                 balancing_policy),
                self.__debug)
            if balancing_policy == "static":
                max_energy = user["energy"]["max"]
                self.__static_app_rebalancing(user_apps, max_energy)

            elif balancing_policy == "dynamic":
                self.__dynamic_app_rebalancing(user_apps)

            else:
                MyUtils.log_error(
                    "Unknown energy balancing policy '{0}'".format(
                        balancing_policy), self.__debug)

        MyUtils.log_info("_______________\n", self.__debug)