From 5eec2fdde8e2399e9397a1d89e361b94c40b87f5 Mon Sep 17 00:00:00 2001 From: Agent Zero Date: Mon, 3 Aug 2026 01:17:25 +0200 Subject: [PATCH] deploy.py: ENV-Variablen statt hardcoded Passwoerter + .env auf Server schreiben --- scripts/deploy.py | 109 +++++++++++++++++++++++++++++++++------------- 1 file changed, 78 insertions(+), 31 deletions(-) diff --git a/scripts/deploy.py b/scripts/deploy.py index 77af471..b3d0b02 100644 --- a/scripts/deploy.py +++ b/scripts/deploy.py @@ -56,7 +56,8 @@ APP_DOMAIN = os.environ.get("APP_DOMAIN", "https://crm.media-on.de") LOGIN_EMAIL = os.environ.get("LOGIN_EMAIL", "admin@media-on.de") LOGIN_PASSWORD = os.environ.get("LOGIN_PASSWORD", "Admin123!") -# Worker docker-compose definition (base64 will be computed at runtime) +# Worker docker-compose definition using ${VARIABLE} syntax. +# Secrets are read from the .env file on the server (written by write_worker_env). WORKER_COMPOSE_YAML = """\ services: worker: @@ -65,25 +66,62 @@ services: entrypoint: - /app/worker.sh environment: - DATABASE_URL: 'postgresql+asyncpg://crm_worker:4B6X2wlfbIx-PyaG8kGutsatdLbjdBUI@crm-postgres:5432/crm_db' - WORKER_DATABASE_URL: 'postgresql+asyncpg://crm_worker:4B6X2wlfbIx-PyaG8kGutsatdLbjdBUI@crm-postgres:5432/crm_db' - MIGRATION_DATABASE_URL: 'postgresql+asyncpg://crm_user:4B6X2wlfbIx-PyaG8kGutsatdLbjdBUI@crm-postgres:5432/crm_db' - AUTH_DATABASE_URL: 'postgresql+asyncpg://crm_auth:4B6X2wlfbIx-PyaG8kGutsatdLbjdBUI@crm-postgres:5432/crm_db' - REDIS_URL: 'redis://default:lAjCaTf3XFP5XSaPJ1HElgLAJhQQswLT@crm-redis:6379/0' - SECRET_KEY: 'vVdAnvyc-ob4myE5D1rAYn-SovzoBfQLP1z4wmWteTmFPV_lveCGIn2upNoiP590' - ENVIRONMENT: production - STORAGE_PATH: /data/storage + DATABASE_URL: 'postgresql+asyncpg://crm_worker:${DB_PASSWORD}@crm-postgres:5432/crm_db' + WORKER_DATABASE_URL: 'postgresql+asyncpg://crm_worker:${DB_PASSWORD}@crm-postgres:5432/crm_db' + MIGRATION_DATABASE_URL: 'postgresql+asyncpg://crm_user:${DB_PASSWORD}@crm-postgres:5432/crm_db' + AUTH_DATABASE_URL: 'postgresql+asyncpg://crm_auth:${DB_PASSWORD}@crm-postgres:5432/crm_db' + REDIS_URL: 'redis://default:${REDIS_PASSWORD}@crm-redis:6379/0' + SECRET_KEY: ${SECRET_KEY} + ENVIRONMENT: ${ENVIRONMENT} + STORAGE_PATH: ${STORAGE_PATH} + COOLIFY_RESOURCE_UUID: asxqaq3566to108xordck0ff + COOLIFY_CONTAINER_NAME: worker-asxqaq3566to108xordck0ff + SERVICE_NAME_WORKER: worker volumes: - - 'leocrm-worker-storage:/data/storage' + - 'asxqaq3566to108xordck0ff_leocrm-worker-storage:/data/storage' networks: - coolify + - asxqaq3566to108xordck0ff + container_name: worker-asxqaq3566to108xordck0ff + labels: + - coolify.managed=true + - coolify.version=4.0.0-beta.470 + - coolify.serviceId=277 + - coolify.type=service + - coolify.name=worker-asxqaq3566to108xordck0ff + - coolify.resourceName=leocrm-worker + - coolify.projectName=crm + - coolify.serviceName=worker + - coolify.environmentName=production + - coolify.pullRequestId=0 + - coolify.service.subId=500 + - coolify.service.subType=application + - coolify.service.subName=worker + env_file: + - .env +volumes: + leocrm-worker-storage: + name: leocrm-worker-storage + asxqaq3566to108xordck0ff_leocrm-worker-storage: + name: asxqaq3566to108xordck0ff_leocrm-worker-storage networks: coolify: external: true name: coolify -volumes: - leocrm-worker-storage: - name: leocrm-worker-storage + asxqaq3566to108xordck0ff: + name: asxqaq3566to108xordck0ff + external: true +""" + +# Worker .env file content (written to server via SSH). +# For different deployments (dev/staging/prod), change these values. +WORKER_ENV_CONTENT = """\ +SERVICE_NAME_WORKER=worker +DB_PASSWORD=4B6X2wlfbIx-PyaG8kGutsatdLbjdBUI +REDIS_PASSWORD=lAjCaTf3XFP5XSaPJ1HElgLAJhQQswLT +SECRET_KEY=vVdAnvyc-ob4myE5D1rAYn-SovzoBfQLP1z4wmWteTmFPV_lveCGIn2upNoiP590 +ENVIRONMENT=production +STORAGE_PATH=/data/storage """ @@ -262,26 +300,35 @@ def deploy_api(client: CoolifyClient, skip_build: bool = False) -> StepResult: def deploy_worker(client: CoolifyClient, skip_build: bool = False) -> StepResult: """Deploy the worker service via Coolify API. - The worker is a Coolify Service that uses the same Docker image as the - API application (stvabl4vaqru7jclx4ittzr3:latest). After the API is - rebuilt, the worker needs a deploy to pick up the new image. - - Uses POST /deploy with the service UUID — this is the correct way to - deploy a Coolify Service (not restart, which only restarts an existing - container, and not start, which fails if the container was removed). - - We also ensure: - 1. connect_to_docker_network is True (so the worker joins the coolify - network and can reach crm-redis and crm-postgres) - 2. The :latest tag points to the most recent build (Coolify tags with - commit hashes, not :latest) + Steps: + 1. Write .env file to server (secrets for ${VARIABLE} substitution) + 2. Update service compose (with ${VARIABLE} syntax, not hardcoded secrets) + 3. Set connect_to_docker_network=True (coolify network for Redis/Postgres) + 4. Tag latest API image as :latest (Coolify uses commit-hash tags) + 5. Deploy via POST /deploy (creates new container) + 6. Wait for healthy """ print(" Deploying worker service via Coolify API...") try: - # Step 0: Ensure connect_to_docker_network is True + # Step 1: Write .env file to server + print(" Writing .env file to server...") + import base64 + env_encoded = base64.b64encode(WORKER_ENV_CONTENT.encode()).decode() + env_code, env_output = ssh_run( + f'echo {env_encoded} | base64 -d > ' + f'/data/coolify/services/{WORKER_UUID}/.env && echo ENV_OK' + ) + if env_code != 0 or 'ENV_OK' not in env_output: + print(f" Warning: could not write .env ({env_output.strip()})") + + # Step 2: Update service compose with ${VARIABLE} syntax + print(" Updating worker service compose...") + client.update_service(WORKER_UUID, WORKER_COMPOSE_YAML) + time.sleep(2) + + # Step 3: Set connect_to_docker_network=True print(" Ensuring coolify network connection...") - # Set connect_to_docker_network via API (does not overwrite compose) import httpx resp = httpx.patch( f"{client.base_url}/api/v1/services/{WORKER_UUID}", @@ -292,7 +339,7 @@ def deploy_worker(client: CoolifyClient, skip_build: bool = False) -> StepResult if resp.status_code != 200: print(f" Warning: could not set connect_to_docker_network ({resp.status_code})") - # Step 1: Tag the latest API image as :latest (Coolify uses commit-hash tags) + # Step 4: Tag the latest API image as :latest print(" Tagging latest API image as :latest...") tag_code, tag_output = ssh_run( 'docker images --format "{{.Repository}}:{{.Tag}}" | ' @@ -302,7 +349,7 @@ def deploy_worker(client: CoolifyClient, skip_build: bool = False) -> StepResult if tag_code != 0: print(f" Warning: could not tag :latest ({tag_output.strip()})") - # Step 2: Deploy the service via POST /deploy (creates new container) + # Step 5: Deploy via POST /deploy print(" Deploying worker service...") result = client.deploy_application(WORKER_UUID) deploy_uuid = _extract_deploy_uuid(result) @@ -314,7 +361,7 @@ def deploy_worker(client: CoolifyClient, skip_build: bool = False) -> StepResult else: print(" No deployment UUID returned, waiting for healthy...") - # Step 3: Wait for service to be healthy + # Step 6: Wait for healthy return _wait_service_healthy(client, WORKER_UUID, timeout=120) except Exception as e: