Пример #1
0
    def post(self):

        parser = reqparse.RequestParser()
        parser.add_argument('etcd_key', required=True)
        args = parser.parse_args()

        etcd_manager = EtcdManagement()
        key_data = None
        try:
            key_data = etcd_manager.read_key(args['etcd_key'])
            return {
                "value": key_data,
                "mod_revision": etcd_manager.get_mod_revision(args['etcd_key'])
            }, 200
        except:
            return {'message': "Key can't be get!!", "code": 1001}, 404
Пример #2
0
class DecisionMaker():
    def __init__(self):
        """
		Constructor
		Args:
			available_nodes(list)
		"""
        ###etcd way
        self.etcd_manager = EtcdManagement()
        ###etcd way

    @staticmethod
    def get_docker_api(host_ip):
        """
		Get docker api client
		Args:
			host_ip(str)
		"""
        return docker.DockerClient(base_url='tcp://{}:2375'.format(host_ip))

    @staticmethod
    def list_containers_by_host(host_ip):

        logger = Logger(filename = "orchestrator", \
             logger_name = "DecisionMaker list_containers_by_host", \
             dirname="/aux1/ocorchestrator/")
        docker_api = DecisionMaker.get_docker_api(host_ip)
        cont_names = []
        try:
            for container in docker_api.containers.list():
                app_name_search = re.search('(.*?)\_\d+', container.name)
                if app_name_search:
                    app_name = app_name_search.group(1)
                    cont_names.append(app_name)
        except:
            logger.error("Can't retrieve data from {} host!".format(host_ip))
            ### 2019.09.05
            if isinstance(host_ip, str):
                DecisionMaker().etcd_manager.write("/platform/orchestrator/failed_nodes/{}". \
                      format(host_ip), "1")
                DecisionMaker().etcd_manager.remove_key( \
                    "/platform/orchestrator/platform_nodes/{}".format(host_ip))
            logger.info(
                "Moving host {} from platform_nodes to failed_nodes".format(
                    host_ip))
            ### 2019.09.05

            logger.clear_handler()
        logger.clear_handler()
        return cont_names

    def update_platform_status(self):

        logger_2 = Logger(filename = "orchestrator", \
             logger_name = "DecisionMaker update_platform_status", \
             dirname="/aux1/ocorchestrator/")
        names_by_hosts = {}
        ###etcd way
        orchestrator_conf = self.etcd_manager. \
             get_etcd_orchestrator_config()['platform']['orchestrator']
        for host in orchestrator_conf['platform_nodes']:
            ###etcd way
            names_by_hosts[host] = {}
            try:
                docker_api = DecisionMaker.get_docker_api(host)
                for container in docker_api.containers.list():
                    app_name_search = re.search('(.*?)\_\d+', container.name)
                    if app_name_search:
                        app_name = app_name_search.group(1)
                        if app_name not in names_by_hosts[host]:
                            names_by_hosts[host][app_name] = {}
                        names_by_hosts[host][app_name].update( \
                          {container.name: orchestrator_conf['types_instances'][app_name][container.name]})
            except:
                logger_2.error(
                    "Can't establish connection with {} host!".format(host))
        self.etcd_manager.write("/platform/orchestrator/platform_status",
                                str(names_by_hosts))
        logger_2.clear_handler()
        return names_by_hosts

    def take_containers_by_hosts(self):

        names_by_hosts = {}
        ###orchastrator.json way
        # for host in parse_config('orchastrator.json')['platform_nodes']:
        ###orchastrator.json way
        ###etcd way
        orchestrator_conf = self.etcd_manager. \
             get_etcd_orchestrator_config()['platform']['orchestrator']
        for host in orchestrator_conf['platform_nodes']:
            ###etcd way
            names_by_hosts[host] = dict(
                Counter(self.list_containers_by_host(host)))

        return names_by_hosts

    def counting_app_by_host(self, application):
        """
		Counting application by hosts
		Args:
			application(str)
		Returns:
			container_count(str)
		"""
        apps_by_hosts = self.take_containers_by_hosts()
        container_count = {}
        for host in apps_by_hosts.keys():
            if application not in apps_by_hosts[host]:
                # return host
                container_count[host] = {application: 0}
            else:
                container_count[host] = {
                    application: apps_by_hosts[host][application]
                }

        return container_count

    def calculating_app_on_hosts(self):
        """
		Args:
			None
		Returns:
			app_counts(dict)
		"""

        app_counts = {}
        for app in self.etcd_manager.get_application_instances():
            app_count = self.counting_app_by_host(app)
            number = 0
            for host in app_count:
                number += app_count[host][app]
            app_counts[app] = number

        return app_counts

    def check_for_releasing_node(self):
        """
		Check for finding a node that can 
		be released if it is not necessary
		Args:
			None
		Returns:
			host_for_release(str) or None		
		"""
        thresholds = literal_eval(
            self.etcd_manager.read_key("/platform/orchestrator/thresholds"))
        orchestrator_conf = self.etcd_manager. \
             get_etcd_orchestrator_config()['platform']['orchestrator']
        apps_count = self.calculating_app_on_hosts()
        curr_nodes_number = len(orchestrator_conf['platform_nodes'])
        validation_flag = True
        for app in apps_count.keys():
            app_count = apps_count[app]
            app_per_node = '{}_per_node'.format(app)
            if curr_nodes_number*thresholds[app_per_node] - app_count >= \
             thresholds[app_per_node]:
                pass
            else:
                validation_flag = False
        if validation_flag:
            # return "Should be released some node"
            all_app_count = 1000
            names_by_hosts = self.take_containers_by_hosts()
            for host in names_by_hosts.keys():
                if host == orchestrator_conf['master']:
                    continue
                curr_count = 0
                for app in names_by_hosts[host].keys():
                    curr_count += names_by_hosts[host][app]
                if curr_count < all_app_count:
                    host_for_release = host
                    all_app_count = curr_count
            return host_for_release
        else:
            return None

    def making_host_decision(self, application, decision, release_node=False):
        """
		Make decision on which host to run container
		Args:
			application(str)
			decision(str)
		Returns:
			host(str)
		"""
        orchestrator_conf = self.etcd_manager. \
             get_etcd_orchestrator_config()['platform']['orchestrator']
        thresholds = literal_eval(
            self.etcd_manager.read_key("/platform/orchestrator/thresholds"))
        # swarm_manager = SwarmManagment()
        app_per_node = "{}_per_node".format(application)
        app_by_hosts = self.counting_app_by_host(application)
        if release_node:
            del (app_by_hosts[release_node])
        host_number = len(app_by_hosts.keys())
        if decision is 'up':
            application_number = 0
            for host in app_by_hosts.keys():
                if app_by_hosts[host][application] == 0:
                    return host
                else:
                    application_number += app_by_hosts[host][application]
            average_app_number = application_number / host_number
            logger_2 = Logger(filename = "orchestrator", \
                 logger_name = "DecisionMaker making_host_decision", \
                 dirname="/aux1/ocorchestrator/")
            logger_2.info("Aplication {} ||| Average => {}\tApp_per_node => {}". \
             format(application, average_app_number, thresholds[app_per_node]))
            logger_2.clear_handler()
            ###logic for adding node to the swarm
            if average_app_number >= float(thresholds[app_per_node]):
                if len(list(orchestrator_conf['available_nodes'].keys())) != 0:
                    available_nodes = list(
                        orchestrator_conf['available_nodes'].keys())
                    new_node = available_nodes[0]
                    self.etcd_manager.remove_key("/platform/orchestrator/available_nodes/{}". \
                           format(new_node))
                    self.etcd_manager.write("/platform/orchestrator/platform_nodes/{}". \
                           format(new_node), '1')
                    return new_node
                else:
                    logger = Logger(filename = "orchestrator", \
                        logger_name = "DecisionMaker making_host_decision", \
                        dirname="/aux1/ocorchestrator/")
                    logger.critical(
                        "There are not any available servers should"
                        "look at host stat to run on the lowest"
                        "loaded host a container")
                    logger.clear_handler()
            ###logic for adding node to the swarm
            for host in app_by_hosts.keys():
                if app_by_hosts[host][application] < average_app_number and \
                 app_by_hosts[host][application] < float(thresholds[app_per_node]): #parse_config('orchastrator.json')[app_per_node]:
                    return host
            for host in app_by_hosts.keys():
                return host
        elif decision is 'down':
            application_number = 0
            for host in app_by_hosts.keys():
                application_number += app_by_hosts[host][application]

            min_app = "{}_min".format(application)
            logger = Logger(filename = "orchestrator", \
                logger_name = "DecisionMaker making_host_decision", \
                dirname="/aux1/ocorchestrator/")
            logger.warning("Application => {}\tmin_apps on platform=> {}\tcurrent app_num {}". \
             format(application, thresholds[min_app], application_number))
            logger.clear_handler()
            if application_number == float(thresholds[min_app]):
                return None

            average_app_number = application_number / host_number
            for host in app_by_hosts.keys():
                if app_by_hosts[host][application] > average_app_number and \
                 app_by_hosts[host][application] < thresholds[app_per_node]: #parse_config('orchastrator.json')[app_per_node]:
                    return host
            for host in app_by_hosts.keys():
                return host

    def release_node(self, host):
        """
		Stop all containers from the passed node,
		move them to the other hosts in self.platform_nodes,
		and move the host to available.servers
		Args:
			host(str)
		Returns:
			None
		"""
        container_manager = ContainerManagement()
        apps_by_host = container_manager.get_container_names_by_host(host)
        for app in apps_by_host:
            app_name_search = re.search('(.*?)\_\d+', app)
            if app_name_search:
                app_name = app_name_search.group(1)
            container_manager.stop_container(name=app, host_ip=host)
            new_host = self.making_host_decision(application=app_name, \
                      decision='up', \
                      release_node=host)
            container_manager.run_container_name(host_ip=new_host, \
                     application=app_name, \
                     container_hostname=app)
        #####
        self.etcd_manager.remove_key(
            "/platform/orchestrator/platform_nodes/{}".format(host))
        self.etcd_manager.write(
            "/platform/orchestrator/available_nodes/{}".format(host), '1')
        #####
        logger = Logger(filename = "orchestrator", \
            logger_name = "DecisionMaker release_node", \
            dirname="/aux1/ocorchestrator/")
        logger.warning("Releasing node {} was successfull !".format(host))
        logger.clear_handler()