Module src.ReBalancer.UserReBalancer
Expand source code
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2022 Universidade da Coruña
# Authors:
# - Jonatan Enes [main](jonatan.enes@udc.es)
# - Roberto R. Expósito
# - Juan Touriño
#
# This file is part of the ServerlessContainers framework, from
# now on referred to as ServerlessContainers.
#
# ServerlessContainers is free software: you can redistribute it
# and/or modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation, either version 3
# of the License, or (at your option) any later version.
#
# ServerlessContainers is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with ServerlessContainers. If not, see <http://www.gnu.org/licenses/>.
import requests
from src.MyUtils import MyUtils
from src.ReBalancer.Utils import CONFIG_DEFAULT_VALUES, app_can_be_rebalanced, get_user_apps
from src.StateDatabase import couchdb
class UserRebalancer:
def __init__(self):
self.__couchdb_handler = couchdb.CouchDBServer()
self.__debug = True
self.__config = {}
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 __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)
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)
Classes
class UserRebalancer
-
Expand source code
class UserRebalancer: def __init__(self): self.__couchdb_handler = couchdb.CouchDBServer() self.__debug = True self.__config = {} 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 __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) 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)
Methods
def rebalance_users(self, config)
-
Expand source code
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)
def update_user_used_energy(self, applications, users)
-
Expand source code
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)