Merge pull request 'master' (#48) from master into prod

Reviewed-on: #48
This commit is contained in:
emmatveev 2025-06-12 01:58:33 +03:00
commit 911c6225dc
4 changed files with 94 additions and 78 deletions

View File

@ -15,6 +15,7 @@ services:
- /var/run/docker.sock:/var/run/docker.sock - /var/run/docker.sock:/var/run/docker.sock
networks: networks:
- configurator - configurator
- queues-development
deploy: deploy:
mode: replicated mode: replicated
restart_policy: restart_policy:
@ -28,3 +29,5 @@ services:
networks: networks:
configurator: configurator:
external: true external: true
queues-development:
external: true

View File

@ -15,6 +15,7 @@ services:
- /var/run/docker.sock:/var/run/docker.sock - /var/run/docker.sock:/var/run/docker.sock
networks: networks:
- configurator - configurator
- queues
deploy: deploy:
mode: replicated mode: replicated
restart_policy: restart_policy:
@ -28,3 +29,5 @@ services:
networks: networks:
configurator: configurator:
external: true external: true
queues:
external: true

116
main.py
View File

@ -3,6 +3,8 @@ import io
import os import os
import subprocess import subprocess
import time import time
from requests import post
from configurator import configurator from configurator import configurator
from mongo import mongo from mongo import mongo
from blob import minio from blob import minio
@ -14,60 +16,92 @@ class Response:
err: str err: str
def send_notification(text: str):
post(
"http://queues:1239/api/v1/put",
headers={"queue": "botalka_mailbox"},
json={
"payload": {
"project": "notifications-bot",
"name": "telegram-bot",
"body": {
"text": text,
"chat_id": 84367486,
},
},
"seconds_to_execute": 1,
"delay": None,
},
)
def call(command: str) -> Response: def call(command: str) -> Response:
p = subprocess.Popen(command, stderr=subprocess.PIPE, stdout=subprocess.PIPE, shell=True) p = subprocess.Popen(
command, stderr=subprocess.PIPE, stdout=subprocess.PIPE, shell=True
)
resp = p.wait() resp = p.wait()
response = Response() response = Response()
response.code = resp response.code = resp
response.out, response.err = p.stdout.read().decode('utf-8'), p.stderr.read().decode('utf-8') response.out, response.err = p.stdout.read().decode(
"utf-8"
), p.stderr.read().decode("utf-8")
return response return response
def get_hosts() -> list[str]: def get_hosts() -> list[str]:
if os.getenv("STAGE") == "development": if os.getenv("STAGE") == "development":
return list(set(list(configurator.get_config("hosts")) + ["platform.develop.sprinthub.ru"])) return list(set(list(configurator.get_config("hosts"))))
else: else:
return list(set(list(configurator.get_config("hosts")) + ["platform.sprinthub.ru"])) return list(set(list(configurator.get_config("hosts"))))
def update_host(host: str) -> bool: def update_host(host: str) -> str | None:
if os.getenv("STAGE") == "development": if os.getenv("STAGE") == "development":
container_id_run = call(f"echo $(docker ps -q -f name=infra-development_nginx)") container_id_run = call("echo $(docker ps -q -f name=infra-development_nginx)")
else: else:
container_id_run = call(f"echo $(docker ps -q -f name=infra_nginx)") container_id_run = call("echo $(docker ps -q -f name=infra_nginx)")
if container_id_run.code != 0: if container_id_run.code != 0:
print(f"something wrong {container_id_run.err}") return container_id_run.err
return False
container_name = container_id_run.out.strip() container_name = container_id_run.out.strip()
if not container_name: if not container_name:
print("No nginx container") return "no nginx container"
return False
gen_command = f"docker exec {container_name} certbot --nginx --email emmtvv@gmail.com --agree-tos --non-interactive -d \"{host}\"" gen_command = f'docker exec {container_name} certbot --nginx --email emmtvv@gmail.com --agree-tos --non-interactive -d "{host}"'
print(gen_command)
gen_cert = call(gen_command) gen_cert = call(gen_command)
if gen_cert.code != 0: if gen_cert.code != 0:
print(f"failed generating certificate: {gen_cert.err}") log = call(
print("Here is the log") f"docker exec {container_name} cat /var/log/letsencrypt/letsencrypt.log"
print(call(f"docker exec {container_name} cat /var/log/letsencrypt/letsencrypt.log").out) ).out
return False return f"failed generating certificate: {log}"
fullchain_command = call(f"docker exec {container_name} cat /etc/letsencrypt/live/{host}/fullchain.pem") fullchain_command = call(
f"docker exec {container_name} cat /etc/letsencrypt/live/{host}/fullchain.pem"
)
if fullchain_command.code != 0: if fullchain_command.code != 0:
print(f"failed getting fullchain: {fullchain_command.err}") return f"failed getting fullchain: {fullchain_command.err}"
return True
privkey_command = call(f"docker exec {container_name} cat /etc/letsencrypt/live/{host}/privkey.pem") privkey_command = call(
f"docker exec {container_name} cat /etc/letsencrypt/live/{host}/privkey.pem"
)
if privkey_command.code != 0: if privkey_command.code != 0:
print(f"failed getting fullchain: {privkey_command.err}") return f"failed getting fullchain: {privkey_command.err}"
return True
fullchain = fullchain_command.out.encode("utf-8") fullchain = fullchain_command.out.encode("utf-8")
privkey = privkey_command.out.encode("utf-8") privkey = privkey_command.out.encode("utf-8")
minio.put_object("certupdater", f"certificates/{host}/fullchain.pem", io.BytesIO(fullchain), len(fullchain)) minio.put_object(
minio.put_object("certupdater", f"certificates/{host}/privkey.pem", io.BytesIO(privkey), len(privkey)) "certupdater",
return True f"certificates/{host}/fullchain.pem",
io.BytesIO(fullchain),
len(fullchain),
)
minio.put_object(
"certupdater",
f"certificates/{host}/privkey.pem",
io.BytesIO(privkey),
len(privkey),
)
return None
while True: while True:
@ -75,18 +109,36 @@ while True:
mongo_hosts = mongo.hosts mongo_hosts = mongo.hosts
updated = False updated = False
for host in get_hosts(): for host in get_hosts():
if now + datetime.timedelta(days=14) > mongo_hosts.get(host, {"expire_time": datetime.datetime.fromtimestamp(1)})["expire_time"]: if (
now + datetime.timedelta(days=14)
> mongo_hosts.get(
host, {"expire_time": datetime.datetime.fromtimestamp(1)}
)["expire_time"]
):
success = update_host(host) success = update_host(host)
if success: if success:
print(f"Host {host} updated") send_notification(
f"host {host} was not updated with an error: {success}"
)
else:
mongo.update_date(host) mongo.update_date(host)
updated = True updated = True
send_notification(f"host {host} updated")
if updated: if updated:
if os.getenv("STAGE") == "development": if os.getenv("STAGE") == "development":
container_id_run = call(f"echo $(docker ps -q -f name=infra-development_nginx)") container_id_run = call(
result = call(f"docker restart {container_id_run.out}") "echo $(docker ps -q -f name=infra-development_nginx)"
)
else: else:
result = call("docker service update --force infra_nginx") container_id_run = call("echo $(docker ps -q -f name=infra_nginx)")
print(container_id_run.code, container_id_run.out, container_id_run.err)
command = f"docker exec {container_id_run.out.strip()} ./refre.sh"
print(command)
restart = call(command)
print(restart.code, restart.out, restart.err)
send_notification(f"Balancer for {os.getenv("STAGE")} was restarted")
print(result.err, result.out)
time.sleep(30) time.sleep(30)

View File

@ -1,42 +0,0 @@
from cachetools import TTLCache
import os
from utils.mongo import mongo
CACHE_SIZE = int(os.getenv("CACHE_SIZE", 1000))
CACHE_TTL = int(os.getenv("CACHE_TTL", 3600))
cache = TTLCache(CACHE_SIZE, CACHE_TTL)
def get_chat_info(chat_id: int) -> dict:
cached_info = cache.get(chat_id)
if cached_info is not None:
return cached_info
mongo_info = mongo.chats_collection.find_one({"chat_id": chat_id})
if mongo_info is not None:
cache[chat_id] = mongo_info
return mongo_info
chat_info = {"chat_id": chat_id, "state": "default", "probability": 100}
mongo.chats_collection.insert_one(chat_info)
cache[chat_id] = chat_info
return chat_info
def set_values(chat_id: int, **values):
cached_info = cache.get(chat_id)
if cached_info is None:
mongo_info = mongo.chats_collection.find_one({"chat_id": chat_id})
if mongo_info is None:
chat_info = {"chat_id": chat_id, "state": "default", "probability": 100}
chat_info.update(values)
mongo.chats_collection.insert_one(chat_info)
cache[chat_id] = chat_info
else:
mongo.chats_collection.update_one({"chat_id": chat_id}, {"$set": values})
mongo_info = dict(mongo_info)
mongo_info.update(values)
cache[chat_id] = mongo_info
else:
cached_info.update(values)
mongo.chats_collection.update_one({"chat_id": chat_id}, {"$set": values})