diff --git a/master-node/src/app.py b/master-node/src/app.py index 4b9873b..20a213e 100644 --- a/master-node/src/app.py +++ b/master-node/src/app.py @@ -1,4 +1,5 @@ import os +import requests import configparser import datetime @@ -77,6 +78,9 @@ app.config["SESSION_TYPE"] = "filesystem" @app.before_first_request def startup(): # Приведем систему в начальное состояние + # TODO: запуск плейбука, который проверит кодовую базу + # желательно, чтобы он скопировал код и указал путь к корневой директории + # в переменной окружения ML_PATH reset_to_initial_state() app_logger.info("master-node запущена!") @@ -111,6 +115,47 @@ def run_ansible(): app_logger.error(data) return make_response(jsonify(data), 400) +@app.route('/api/v1.0/interact_with_custom_modules', methods=['POST']) +@auth.login_required +def interact_with_custom_modules(): + # Получим данные запроса + data = request.get_json() + # TODO: настроить адрес бекенда + back_url = "https://api.statanly.com:8443" + + try: + # TODO: получим токен авторизации + token = requests.post( + f"{back_url}/api/auth/login", + data = {"username": "admin@eatom.ru", "password": "admin"} + ).json()['access_token'] + + # выполним необходимую операция с кастомными модулями + if data["request_type"] == "get_all_modules": + response = requests.get( + f"{back_url}/api/custom-modules", + headers = {"Authorization": f"Bearer {token}"} + ) + elif data["request_type"] == "change_status": + response = requests.patch( + f"{back_url}/api/custom-modules/{data['module_id']}", + json = {"status": data["status"]} + ) + + data = { + "response": response.json(), + "message": "", + "code": "SUCCESS" + } + return make_response(jsonify(data), 200) + except Exception as e: + data = { + "response": "", + "message": f"Cannot interact with custom modules: {e}", + "code": "FAILED" + } + return make_response(jsonify(data), 400) + # -------------------------- # Методы, которыми управляет scheduler # -------------------------- @@ -125,14 +170,12 @@ def run_ansible(): # AUTO.check_cluster_state() # app_logger.debug("Finished with auto cluster state") -#@scheduler.task( -# "interval", -# id="cluster_state", -# seconds=30, -# misfire_grace_time=900 -#) -#def custom_modules(): -# create_custom_containers() +scheduler.task( + "interval", + id="cluster_state", + seconds=30, + misfire_grace_time=900 +)(create_custom_containers) if __name__ == "__main__": port = int(os.environ.get("PORT", 5010)) diff --git a/master-node/src/custom_modules/get_env_vars.py b/master-node/src/custom_modules/get_env_vars.py index c62ae48..766b9cb 100644 --- a/master-node/src/custom_modules/get_env_vars.py +++ b/master-node/src/custom_modules/get_env_vars.py @@ -16,8 +16,10 @@ def load_env_files( def get_env_vars(): # Проверяем наличие кодовой базы - # TODO: ansible playbook - ml_path = "/path-to-ml" + try: + ml_path = os.environ["ML_PATH"] + except KeyError: + raise RuntimeError("Не указан путь к кодовой базе мл модулей") # Получаем переменные env_files = [f"{ml_path}/.env", f"{ml_path}/docker/.env.dev", f"{ml_path}/docker/.env.compose_vars"] diff --git a/master-node/src/custom_modules/manager.py b/master-node/src/custom_modules/manager.py index 2b144ee..b1b21b7 100644 --- a/master-node/src/custom_modules/manager.py +++ b/master-node/src/custom_modules/manager.py @@ -1,21 +1,29 @@ from multiprocessing import Process +import os import requests from .manager_methods import start_container, stop_container from .get_env_vars import get_env_vars from ..logger import LoggerFactory -_AUTH_URL = "https://api.statanly.com:8443/api/auth/login" -_ALL_MODULES_URL = "https://api.statanly.com:8443/api/custom-modules" manager_logger = LoggerFactory.get_logger("CustomModuleManager") +def get_all_modules(): + response = requests.post( + f"http://localhost:{int(os.environ.get('PORT', 5010))}/api/v1.0/interact_with_custom_modules", + data = {"request_type": "get_all_modules", "module_id": None, "status": None} + ) + if response.status_code != 200: + manager_logger.warning(f"Не удалось получить информацию о кастомных модулях. Код: {response['message']}") + return + + return response.json() def reset_to_initial_state(): # получим информацию о кастомных модулей - response = requests.get(_ALL_MODULES_URL) - if response.status_code != 200: - manager_logger.warning(f"Не удалось получить информацию о кастомных модулях. Код: {response.status_code}") - return + custom_modules = get_all_modules() + if not custom_modules: + return # получим переменные окружения try: @@ -26,13 +34,13 @@ def reset_to_initial_state(): # проходимся по всем модулям (id, title, is_SIZ, status, model) processed_modules = [] - custom_modules = response.json() for module in custom_modules: # инициализируем переменные контейнера container_name = f"{all_envs['COMPOSE_PROJECT_NAME']}_custom_module{module['id']}" # останавливаем контейнер в отдельном процессе p = Process(target=stop_container, args=( + module['id'], container_name, ) ) @@ -45,10 +53,9 @@ def reset_to_initial_state(): def create_custom_containers(): # получим информацию о кастомных модулей - response = requests.get(_ALL_MODULES_URL) - if response.status_code != 200: - manager_logger.warning(f"Не удалось получить информацию о кастомных модулях. Код: {response.status_code}") - return + custom_modules = get_all_modules() + if not custom_modules: + return # получим переменные окружения try: @@ -59,8 +66,6 @@ def create_custom_containers(): # проходимся по всем модулям (id, title, is_SIZ, status, model) processed_modules = [] - custom_modules = response.json() - print(custom_modules) for module in custom_modules: if module["status"] in ["остановлен", "не создан"] and module["model"]["weights"].strip(): # инициализируем переменные контейнера @@ -70,6 +75,7 @@ def create_custom_containers(): # запускаем контейнер в отдельном процессе p = Process(target=start_container, args=( + module['id'], image_name, build_args, container_name, @@ -86,10 +92,9 @@ def create_custom_containers(): def stop_all_custom_containers(): # получим информацию о кастомных модулей - response = requests.get(_ALL_MODULES_URL) - if response.status_code != 200: - manager_logger.warning(f"Не удалось получить информацию о кастомных модулях. Код: {response.status_code}") - return + custom_modules = get_all_modules() + if not custom_modules: + return # получим переменные окружения try: @@ -100,7 +105,6 @@ def stop_all_custom_containers(): # проходимся по всем модулям (id, title, is_SIZ, status, model) processed_modules = [] - custom_modules = response.json() for module in custom_modules: if module["status"] in ["работает"]: # инициализируем переменные контейнера @@ -108,6 +112,7 @@ def stop_all_custom_containers(): # останавливаем контейнер в отдельном процессе p = Process(target=stop_container, args=( + module['id'], container_name, ) ) diff --git a/master-node/src/custom_modules/manager_methods.py b/master-node/src/custom_modules/manager_methods.py index 3289c23..c9ff40a 100644 --- a/master-node/src/custom_modules/manager_methods.py +++ b/master-node/src/custom_modules/manager_methods.py @@ -1,10 +1,20 @@ +import requests import docker +import os from ..logger import LoggerFactory -_ALL_MODULES_URL = "https://api.statanly.com:8443/api/custom-modules" manager_logger = LoggerFactory.get_logger("CustomModuleManager") +def change_module_status( + module_id: int, + status: str +): + _ = requests.post( + f"http://localhost:{int(os.environ.get('PORT', 5010))}/api/v1.0/interact_with_custom_modules", + data = {"request_type": "change_status", "model_id": module_id, "status": status} + ) + def build_image( client: docker.DockerClient, path: str, @@ -25,6 +35,7 @@ def build_image( manager_logger.info(chunk['stream'].strip()) def start_container( + module_id: int, image_name: str, build_args: dict, container_name: str, @@ -39,9 +50,11 @@ def start_container( # Соберем контейнер try: + change_module_status(module_id, status = "работает") build_image(client, **build_args) manager_logger.info(f"Контейнер '{container_name}' успешно собран") except Exception as e: + change_module_status(module_id, status = "не создан") manager_logger.error(f"Ошибка при сборке контейнера: {e}") return @@ -60,9 +73,11 @@ def start_container( ) manager_logger.info(f"Контейнер '{container_name}' с ID: {container.short_id} запустился") except Exception as e: + change_module_status(module_id, status = "остановлен") manager_logger.error(f"Ошибка при запуске контейнера: {e}") def stop_container( + module_id: int, name: str ): """Удаление docker контейнеров по имени""" @@ -75,5 +90,6 @@ def stop_container( container.stop() container.remove() manager_logger.info(f"Контейнер '{name}' был остановлен") + change_module_status(module_id, status = "остановлен") except docker.errors.NotFound: manager_logger.warning(f"Контейнер '{name}' не найден") \ No newline at end of file