Compare commits
2 commits
9632552cff
...
86385261fe
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
86385261fe | ||
|
|
c1603b5e12 |
5 changed files with 108 additions and 29 deletions
13
master-node/docker-compose.yaml
Normal file
13
master-node/docker-compose.yaml
Normal 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
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import os
|
import os
|
||||||
|
import requests
|
||||||
import configparser
|
import configparser
|
||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
|
|
@ -77,6 +78,9 @@ app.config["SESSION_TYPE"] = "filesystem"
|
||||||
@app.before_first_request
|
@app.before_first_request
|
||||||
def startup():
|
def startup():
|
||||||
# Приведем систему в начальное состояние
|
# Приведем систему в начальное состояние
|
||||||
|
# TODO: запуск плейбука, который проверит кодовую базу
|
||||||
|
# желательно, чтобы он скопировал код и указал путь к корневой директории
|
||||||
|
# в переменной окружения ML_PATH
|
||||||
reset_to_initial_state()
|
reset_to_initial_state()
|
||||||
app_logger.info("master-node запущена!")
|
app_logger.info("master-node запущена!")
|
||||||
|
|
||||||
|
|
@ -111,6 +115,47 @@ def run_ansible():
|
||||||
app_logger.error(data)
|
app_logger.error(data)
|
||||||
return make_response(jsonify(data), 400)
|
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
|
# Методы, которыми управляет scheduler
|
||||||
# --------------------------
|
# --------------------------
|
||||||
|
|
@ -125,14 +170,12 @@ def run_ansible():
|
||||||
# AUTO.check_cluster_state()
|
# AUTO.check_cluster_state()
|
||||||
# app_logger.debug("Finished with auto cluster state")
|
# app_logger.debug("Finished with auto cluster state")
|
||||||
|
|
||||||
#@scheduler.task(
|
scheduler.task(
|
||||||
# "interval",
|
"interval",
|
||||||
# id="cluster_state",
|
id="cluster_state",
|
||||||
# seconds=30,
|
seconds=30,
|
||||||
# misfire_grace_time=900
|
misfire_grace_time=900
|
||||||
#)
|
)(create_custom_containers)
|
||||||
#def custom_modules():
|
|
||||||
# create_custom_containers()
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
port = int(os.environ.get("PORT", 5010))
|
port = int(os.environ.get("PORT", 5010))
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,10 @@ def load_env_files(
|
||||||
|
|
||||||
def get_env_vars():
|
def get_env_vars():
|
||||||
# Проверяем наличие кодовой базы
|
# Проверяем наличие кодовой базы
|
||||||
# TODO: ansible playbook
|
try:
|
||||||
ml_path = "/path-to-ml"
|
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"]
|
env_files = [f"{ml_path}/.env", f"{ml_path}/docker/.env.dev", f"{ml_path}/docker/.env.compose_vars"]
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,28 @@
|
||||||
from multiprocessing import Process
|
from multiprocessing import Process
|
||||||
|
import os
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
from .manager_methods import start_container, stop_container
|
from .manager_methods import start_container, stop_container
|
||||||
from .get_env_vars import get_env_vars
|
from .get_env_vars import get_env_vars
|
||||||
from ..logger import LoggerFactory
|
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")
|
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():
|
def reset_to_initial_state():
|
||||||
# получим информацию о кастомных модулей
|
# получим информацию о кастомных модулей
|
||||||
response = requests.get(_ALL_MODULES_URL)
|
custom_modules = get_all_modules()
|
||||||
if response.status_code != 200:
|
if not custom_modules:
|
||||||
manager_logger.warning(f"Не удалось получить информацию о кастомных модулях. Код: {response.status_code}")
|
|
||||||
return
|
return
|
||||||
|
|
||||||
# получим переменные окружения
|
# получим переменные окружения
|
||||||
|
|
@ -26,13 +34,13 @@ def reset_to_initial_state():
|
||||||
|
|
||||||
# проходимся по всем модулям (id, title, is_SIZ, status, model)
|
# проходимся по всем модулям (id, title, is_SIZ, status, model)
|
||||||
processed_modules = []
|
processed_modules = []
|
||||||
custom_modules = response.json()
|
|
||||||
for module in custom_modules:
|
for module in custom_modules:
|
||||||
# инициализируем переменные контейнера
|
# инициализируем переменные контейнера
|
||||||
container_name = f"{all_envs['COMPOSE_PROJECT_NAME']}_custom_module{module['id']}"
|
container_name = f"{all_envs['COMPOSE_PROJECT_NAME']}_custom_module{module['id']}"
|
||||||
# останавливаем контейнер в отдельном процессе
|
# останавливаем контейнер в отдельном процессе
|
||||||
p = Process(target=stop_container,
|
p = Process(target=stop_container,
|
||||||
args=(
|
args=(
|
||||||
|
module['id'],
|
||||||
container_name,
|
container_name,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
@ -45,9 +53,8 @@ def reset_to_initial_state():
|
||||||
|
|
||||||
def create_custom_containers():
|
def create_custom_containers():
|
||||||
# получим информацию о кастомных модулей
|
# получим информацию о кастомных модулей
|
||||||
response = requests.get(_ALL_MODULES_URL)
|
custom_modules = get_all_modules()
|
||||||
if response.status_code != 200:
|
if not custom_modules:
|
||||||
manager_logger.warning(f"Не удалось получить информацию о кастомных модулях. Код: {response.status_code}")
|
|
||||||
return
|
return
|
||||||
|
|
||||||
# получим переменные окружения
|
# получим переменные окружения
|
||||||
|
|
@ -59,8 +66,6 @@ def create_custom_containers():
|
||||||
|
|
||||||
# проходимся по всем модулям (id, title, is_SIZ, status, model)
|
# проходимся по всем модулям (id, title, is_SIZ, status, model)
|
||||||
processed_modules = []
|
processed_modules = []
|
||||||
custom_modules = response.json()
|
|
||||||
print(custom_modules)
|
|
||||||
for module in custom_modules:
|
for module in custom_modules:
|
||||||
if module["status"] in ["остановлен", "не создан"] and module["model"]["weights"].strip():
|
if module["status"] in ["остановлен", "не создан"] and module["model"]["weights"].strip():
|
||||||
# инициализируем переменные контейнера
|
# инициализируем переменные контейнера
|
||||||
|
|
@ -70,6 +75,7 @@ def create_custom_containers():
|
||||||
# запускаем контейнер в отдельном процессе
|
# запускаем контейнер в отдельном процессе
|
||||||
p = Process(target=start_container,
|
p = Process(target=start_container,
|
||||||
args=(
|
args=(
|
||||||
|
module['id'],
|
||||||
image_name,
|
image_name,
|
||||||
build_args,
|
build_args,
|
||||||
container_name,
|
container_name,
|
||||||
|
|
@ -86,9 +92,8 @@ def create_custom_containers():
|
||||||
|
|
||||||
def stop_all_custom_containers():
|
def stop_all_custom_containers():
|
||||||
# получим информацию о кастомных модулей
|
# получим информацию о кастомных модулей
|
||||||
response = requests.get(_ALL_MODULES_URL)
|
custom_modules = get_all_modules()
|
||||||
if response.status_code != 200:
|
if not custom_modules:
|
||||||
manager_logger.warning(f"Не удалось получить информацию о кастомных модулях. Код: {response.status_code}")
|
|
||||||
return
|
return
|
||||||
|
|
||||||
# получим переменные окружения
|
# получим переменные окружения
|
||||||
|
|
@ -100,7 +105,6 @@ def stop_all_custom_containers():
|
||||||
|
|
||||||
# проходимся по всем модулям (id, title, is_SIZ, status, model)
|
# проходимся по всем модулям (id, title, is_SIZ, status, model)
|
||||||
processed_modules = []
|
processed_modules = []
|
||||||
custom_modules = response.json()
|
|
||||||
for module in custom_modules:
|
for module in custom_modules:
|
||||||
if module["status"] in ["работает"]:
|
if module["status"] in ["работает"]:
|
||||||
# инициализируем переменные контейнера
|
# инициализируем переменные контейнера
|
||||||
|
|
@ -108,6 +112,7 @@ def stop_all_custom_containers():
|
||||||
# останавливаем контейнер в отдельном процессе
|
# останавливаем контейнер в отдельном процессе
|
||||||
p = Process(target=stop_container,
|
p = Process(target=stop_container,
|
||||||
args=(
|
args=(
|
||||||
|
module['id'],
|
||||||
container_name,
|
container_name,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,20 @@
|
||||||
|
import requests
|
||||||
import docker
|
import docker
|
||||||
|
import os
|
||||||
|
|
||||||
from ..logger import LoggerFactory
|
from ..logger import LoggerFactory
|
||||||
|
|
||||||
_ALL_MODULES_URL = "https://api.statanly.com:8443/api/custom-modules"
|
|
||||||
manager_logger = LoggerFactory.get_logger("CustomModuleManager")
|
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(
|
def build_image(
|
||||||
client: docker.DockerClient,
|
client: docker.DockerClient,
|
||||||
path: str,
|
path: str,
|
||||||
|
|
@ -25,6 +35,7 @@ def build_image(
|
||||||
manager_logger.info(chunk['stream'].strip())
|
manager_logger.info(chunk['stream'].strip())
|
||||||
|
|
||||||
def start_container(
|
def start_container(
|
||||||
|
module_id: int,
|
||||||
image_name: str,
|
image_name: str,
|
||||||
build_args: dict,
|
build_args: dict,
|
||||||
container_name: str,
|
container_name: str,
|
||||||
|
|
@ -39,9 +50,11 @@ def start_container(
|
||||||
|
|
||||||
# Соберем контейнер
|
# Соберем контейнер
|
||||||
try:
|
try:
|
||||||
|
change_module_status(module_id, status = "работает")
|
||||||
build_image(client, **build_args)
|
build_image(client, **build_args)
|
||||||
manager_logger.info(f"Контейнер '{container_name}' успешно собран")
|
manager_logger.info(f"Контейнер '{container_name}' успешно собран")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
change_module_status(module_id, status = "не создан")
|
||||||
manager_logger.error(f"Ошибка при сборке контейнера: {e}")
|
manager_logger.error(f"Ошибка при сборке контейнера: {e}")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
@ -60,9 +73,11 @@ def start_container(
|
||||||
)
|
)
|
||||||
manager_logger.info(f"Контейнер '{container_name}' с ID: {container.short_id} запустился")
|
manager_logger.info(f"Контейнер '{container_name}' с ID: {container.short_id} запустился")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
change_module_status(module_id, status = "остановлен")
|
||||||
manager_logger.error(f"Ошибка при запуске контейнера: {e}")
|
manager_logger.error(f"Ошибка при запуске контейнера: {e}")
|
||||||
|
|
||||||
def stop_container(
|
def stop_container(
|
||||||
|
module_id: int,
|
||||||
name: str
|
name: str
|
||||||
):
|
):
|
||||||
"""Удаление docker контейнеров по имени"""
|
"""Удаление docker контейнеров по имени"""
|
||||||
|
|
@ -75,5 +90,6 @@ def stop_container(
|
||||||
container.stop()
|
container.stop()
|
||||||
container.remove()
|
container.remove()
|
||||||
manager_logger.info(f"Контейнер '{name}' был остановлен")
|
manager_logger.info(f"Контейнер '{name}' был остановлен")
|
||||||
|
change_module_status(module_id, status = "остановлен")
|
||||||
except docker.errors.NotFound:
|
except docker.errors.NotFound:
|
||||||
manager_logger.warning(f"Контейнер '{name}' не найден")
|
manager_logger.warning(f"Контейнер '{name}' не найден")
|
||||||
Loading…
Reference in a new issue