diff --git a/.deploy/deploy-dev.yaml b/.deploy/deploy-dev.yaml index 6549e29..aa87cc6 100644 --- a/.deploy/deploy-dev.yaml +++ b/.deploy/deploy-dev.yaml @@ -6,15 +6,21 @@ services: image: mathwave/sprint-repo:certupdater command: worker environment: + MINIO_HOST: "minio.develop.sprinthub.ru" + MINIO_SECRET_KEY: $MINIO_SECRET_KEY_DEV MONGO_HOST: "mongo.develop.sprinthub.ru" MONGO_PASSWORD: $MONGO_PASSWORD_DEV STAGE: "development" + volumes: + - /var/run/docker.sock:/var/run/docker.sock networks: - configurator deploy: mode: replicated restart_policy: condition: any + placement: + constraints: [node.labels.stage == development] update_config: parallelism: 1 order: start-first diff --git a/.deploy/deploy-prod.yaml b/.deploy/deploy-prod.yaml index d4fe2b4..245b25f 100644 --- a/.deploy/deploy-prod.yaml +++ b/.deploy/deploy-prod.yaml @@ -2,44 +2,29 @@ version: "3.4" services: - worker: - image: mathwave/sprint-repo:pizda-bot + certupdater: + image: mathwave/sprint-repo:certupdater command: worker environment: + MINIO_HOST: "minio.sprinthub.ru" + MINIO_SECRET_KEY: $MINIO_SECRET_KEY_PROD MONGO_HOST: "mongo.sprinthub.ru" MONGO_PASSWORD: $MONGO_PASSWORD_PROD STAGE: "production" + volumes: + - /var/run/docker.sock:/var/run/docker.sock networks: - - queues - configurator deploy: mode: replicated restart_policy: condition: any - update_config: - parallelism: 1 - order: start-first - - pizda-bot-nginx: - image: mathwave/sprint-repo:pizda-bot - command: api - environment: - MONGO_HOST: "mongo.sprinthub.ru" - MONGO_PASSWORD: $MONGO_PASSWORD_PROD - networks: - - common-infra-nginx - deploy: - mode: replicated - restart_policy: - condition: any + placement: + constraints: [node.labels.stage == production] update_config: parallelism: 1 order: start-first networks: - common-infra-nginx: - external: true - queues: - external: true configurator: external: true diff --git a/.gitea/workflows/deploy-dev.yaml b/.gitea/workflows/deploy-dev.yaml index 9515a0c..cb40437 100644 --- a/.gitea/workflows/deploy-dev.yaml +++ b/.gitea/workflows/deploy-dev.yaml @@ -18,14 +18,14 @@ jobs: with: ref: dev - name: build - run: docker build -t mathwave/sprint-repo:pizda-bot . + run: docker build -t mathwave/sprint-repo:certupdater . push: name: Push runs-on: [ dev ] needs: build steps: - name: push - run: docker push mathwave/sprint-repo:pizda-bot + run: docker push mathwave/sprint-repo:certupdater deploy-dev: name: Deploy dev runs-on: [prod] @@ -40,4 +40,5 @@ jobs: - name: deploy env: MONGO_PASSWORD_DEV: ${{ secrets.MONGO_PASSWORD_DEV }} - run: docker stack deploy --with-registry-auth -c ./.deploy/deploy-dev.yaml pizda-bot-development + MINIO_SECRET_KEY_DEV: ${{ secrets.MINIO_SECRET_KEY_DEV }} + run: docker stack deploy --with-registry-auth -c ./.deploy/deploy-dev.yaml certupdater-development diff --git a/.gitea/workflows/deploy-prod.yaml b/.gitea/workflows/deploy-prod.yaml index cd6e772..e487206 100644 --- a/.gitea/workflows/deploy-prod.yaml +++ b/.gitea/workflows/deploy-prod.yaml @@ -40,4 +40,5 @@ jobs: - name: deploy env: MONGO_PASSWORD_PROD: ${{ secrets.MONGO_PASSWORD_PROD }} - run: docker stack deploy --with-registry-auth -c ./.deploy/deploy-prod.yaml pizda-bot + MINIO_SECRET_KEY_PROD: ${{ secrets.MINIO_SECRET_KEY_PROD }} + run: docker stack deploy --with-registry-auth -c ./.deploy/deploy-prod.yaml certupdater diff --git a/Dockerfile b/Dockerfile index 274578f..7f1ddd7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,8 +2,14 @@ FROM docker:dind ENV PYTHONUNBUFFERED=1 RUN apk add --update --no-cache python3 py3-pip && ln -sf python3 /usr/bin/python +RUN mkdir /code +WORKDIR /code RUN python3 -m venv venv RUN venv/bin/python3 -m ensurepip RUN venv/bin/pip3 install --no-cache --upgrade pip setuptools +COPY requirements.txt requirements.txt +RUN venv/bin/pip3 install -r requirements.txt +COPY . . + ENTRYPOINT [ "venv/bin/python3", "main.py" ] \ No newline at end of file diff --git a/main.py b/main.py index fac52d2..b46e7dc 100644 --- a/main.py +++ b/main.py @@ -1,4 +1,6 @@ import datetime +import io +import os import subprocess import time from configurator import configurator @@ -22,23 +24,66 @@ def call(command: str) -> Response: def get_hosts() -> list[str]: - return list(set(configurator.get_config("hosts") + ["platform.chocomarsh.com"])) + return list(set(configurator.get_config("hosts") + ["platform.develop.sprinthub.ru"])) -def update_host(host: str): - gen_cert = call(f"docker exec $(docker ps -q -f name=infra_nginx) certbot --nginx --email emmtvv@gmail.com --agree-tos -d \"{host}\"") - if gen_cert.code != 0: - print("failed generating certificate") - return +def update_host(host: str) -> bool: + if os.getenv("STAGE") == "development": + container_id_run = call(f"echo $(docker ps -q -f name=infra-development_nginx)") + else: + container_id_run = call(f"echo $(docker ps -q -f name=infra_nginx)") + if container_id_run.code != 0: + print(f"something wrong {container_id_run.err}") + return False + container_name = container_id_run.out.strip() + if not container_name: + print("No nginx container") + return False + 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) + if gen_cert.code != 0: + print(f"failed generating certificate: {gen_cert.err}") + print("Here is the log") + print(call(f"docker exec {container_name} cat /var/log/letsencrypt/letsencrypt.log").out) + return False + + fullchain_command = call(f"docker exec {container_name} cat /etc/letsencrypt/live/{host}/fullchain.pem") + if fullchain_command.code != 0: + print(f"failed getting fullchain: {fullchain_command.err}") + return True + + privkey_command = call(f"docker exec {container_name} cat /etc/letsencrypt/live/{host}/privkey.pem") + if privkey_command.code != 0: + print(f"failed getting fullchain: {privkey_command.err}") + return True + + fullchain = fullchain_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("certupdater", f"certificates/{host}/privkey.pem", io.BytesIO(privkey), len(privkey)) + return True while True: now = datetime.datetime.now() mongo_hosts = mongo.hosts + updated = False for host in get_hosts(): - if now() + datetime.timedelta(days=14) > mongo_hosts[host]["expire_time"]: - update_host(host) - print(f"Host {host} updated") - minio.put_object("certupdater", "nginx.conf", ) - time.sleep(5 * 60) \ No newline at end of file + if now + datetime.timedelta(days=14) > mongo_hosts.get(host, {"expire_time": datetime.datetime.fromtimestamp(1)})["expire_time"]: + success = update_host(host) + if success: + print(f"Host {host} updated") + mongo.update_date(host) + updated = True + if updated: + if os.getenv("STAGE") == "development": + container_id_run = call(f"echo $(docker ps -q -f name=infra-development_nginx)") + result = call(f"docker restart {container_id_run.out}") + else: + result = call("docker service update --force infra_nginx") + + print(result.err, result.out) + time.sleep(30) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..ef6527f --- /dev/null +++ b/requirements.txt @@ -0,0 +1,14 @@ +argon2-cffi==23.1.0 +argon2-cffi-bindings==21.2.0 +certifi==2025.4.26 +cffi==1.17.1 +charset-normalizer==3.4.2 +dnspython==2.7.0 +idna==3.10 +minio==7.2.15 +pycparser==2.22 +pycryptodome==3.23.0 +pymongo==4.13.0 +requests==2.32.3 +typing_extensions==4.13.2 +urllib3==2.4.0