Compare commits

..

2 commits

Author SHA1 Message Date
Chebart
86385261fe added docker-compose file 2025-10-25 16:19:27 +03:00
Chebart
c1603b5e12 fix bugs discussed at the meeting 2025-10-25 16:17:17 +03:00
5 changed files with 108 additions and 29 deletions

View file

@ -0,0 +1,13 @@
services:
master-node:
container_name: master_node_container
image: master_node_image
build:
context: ./
dockerfile: Dockerfile
volumes:
- ./src:/app/src
- /var/run/docker.sock:/var/run/docker.sock
networks:
- defaults
restart: unless-stopped

View file

@ -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))

View file

@ -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"]

View file

@ -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,
)
)

View file

@ -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}' не найден")