Skip to content

English {#english}

Provisioning pipeline (Ansible → Zuplo Sync)

How to run Ansible and then Zuplo Sync manually before the full automation workflow (provision-tenant.yml) is in place.
When using the workflow, db_host is taken from Control Plane GET /internal/db-host (R7, per-region env) if set; otherwise from Pulumi outputs or vars. Ref: DB/Redis scaling policy R7 §5.

Ref: Intelligent automation implementation plan §3.2, §3.3.


Prerequisites

  • Server already provisioned with Pulumi; you know server_ip (or management FQDN).
  • Host is in the inventory and SSH access works.

1. Inventory setup

Ansible code lives in the prego-ansible repo. Copy inventory/inventory.example.yml to inventory/inventory.yml and set ansible_host and db_host.

DB-separated (Phase 1) example:

all:
children:
prego_db_servers:
hosts:
db_01:
ansible_host: DB_SERVER_IP
vars:
ansible_user: root
ansible_ssh_private_key_file: ~/.ssh/prego-admin
prego_nodes:
hosts:
node_01:
ansible_host: APP_SERVER_IP
tenant_id: "YOUR_TENANT_ID"
vars:
ansible_user: root
ansible_ssh_private_key_file: ~/.ssh/prego-admin
db_host: DB_SERVER_IP
db_port: 3306

Single server (App+DB same host): use the same IP for prego_db_servers and prego_nodes, and set db_host to that IP.

Redis separated: add a prego_redis_servers group and set redis_01.ansible_host to the Redis server IP (pulumi stack output redis_server_ip). In prego_nodes vars set redis_host (or let the playbook fill it); at run time pass -e redis_requirepass=... and -e redis_password=.... Ref: Redis migration.


2. Run Ansible

Required vars: tenant_id, db_root_password. Optional: canonical_hostname (defaults to tenant-{first8}.pregoi.com), company_name, abbr (from Control Plane GET /internal/billing).

Terminal window
cd /path/to/prego-ansible
ansible-playbook -i inventory/inventory.yml playbook.yml \
-e tenant_id=YOUR_TENANT_ID \
-e db_root_password=YOUR_DB_ROOT_PASSWORD

With company name and abbr (after billing lookup in workflow):

Terminal window
ansible-playbook -i inventory/inventory.yml playbook.yml \
-e tenant_id=YOUR_TENANT_ID \
-e db_root_password=YOUR_DB_ROOT_PASSWORD \
-e "company_name=Example Inc" \
-e "abbr=Example"
  • Output: API key in artifacts/tenant_api_key.txt; tenant info in artifacts/tenant_info.json (dirs created, gitignored).

If Ansible fails: check SSH (ssh -i ~/.ssh/prego-admin root@<server_ip>), DB connectivity (firewall, MariaDB bind-address), bench logs (docker logs prego-frappe-bench if container mode). To wipe and reinstall: Ansible clean and reinstall.


3. Zuplo Sync

From the Prego repo, set env vars and run (use path to API key from prego-ansible or a copy):

Terminal window
cd /path/to/Prego
export ZUPLO_ACCOUNT_NAME=your-account
export ZUPLO_BUCKET_NAME=your-bucket
export ZUPLO_API_KEY=...
npx tsx infra/zuplo_sync.ts YOUR_TENANT_ID --api-key-file /path/to/tenant_api_key.txt

Example right after running prego-ansible:

Terminal window
npx tsx infra/zuplo_sync.ts YOUR_TENANT_ID --api-key-file ../prego-ansible/artifacts/tenant_api_key.txt

Or pass the key directly:

Terminal window
npx tsx infra/zuplo_sync.ts YOUR_TENANT_ID "$(cat ../prego-ansible/artifacts/tenant_api_key.txt)"

3.5 (Optional) Tenant details and additional_users

§12 onboarding data (admin_email, admin_name, company_name, abbr, additional_users) is stored in Control Plane D1 tenants_master. To use it before/after provisioning (e.g. Frappe users):

  • GET {CONTROL_PLANE_URL}/internal/billing?tenant_id={TENANT_ID} with Authorization: Bearer {INTERNAL_API_KEY}.
  • Response: tenant_id, status, plan_tier, subdomain_slug, company_name, abbr, admin_email, admin_name, admin_phone, additional_users, etc.

Example:

Terminal window
curl -sS -H "Authorization: Bearer $INTERNAL_API_KEY" \
"$CONTROL_PLANE_URL/internal/billing?tenant_id=$TENANT_ID" | jq .

4. (Optional) Control Plane callback

After the pipeline finishes, call Control Plane to update D1: provision_jobs.statusCompleted, tenants_master.statusActive, and write tenant_runtime. URL and payload depend on the implementation; the workflow uses the same logic.


5. Zuplo plan rate limits (R6)

Set per-plan API rate limits in the Zuplo dashboard or policy. Example:

PlanLimit (example)
Free100 req/min
Basic300 req/min
Professional1,000 req/min
Enterprise5,000 req/min

Manual steps: Zuplo dashboard → Key Bucket / Consumer(tenant_id) → check plan_tier via GET /internal/billing → apply the limit. Passing --plan-tier at Zuplo Sync stores it for future automation. Ref: Tenant onboard resource allocation §6.6.


Workflow inputs

Inputs for provision-tenant.yml (or Provision Worker):

InputRequiredDescription
job_idYesprovision_jobs.job_id
tenant_idYesTenant ID. site_name = canonical_hostname (tenant-{short_id}.pregoi.com). User URL = {subdomain_slug}.pregoi.com. Tenant subdomain DNS design
regionYessg / us / eu
target_server_idNonodes.node_id when reusing a node (skip Pulumi)
create_new_serverNo1 = new Pulumi up then Ansible
subdomain_slugNoUser subdomain (e.g. acme → acme.pregoi.com). If set, tenant-dns step creates CNAME in Cloudflare.

Workflow steps: resolve-server → tenant-dns (Cloudflare canonical + user CNAME) → ansible-provision → zuplo-sync → callback. tenant-dns needs CLOUDFLARE_ZONE_ID and CLOUDFLARE_API_TOKEN; if unset the step can fail with continue-on-error so the pipeline continues.

Secrets: HCLOUD_TOKEN_*, PULUMI_ACCESS_TOKEN, CLOUDFLARE_API_TOKEN, CLOUDFLARE_ZONE_ID, ZUPLO_*, CONTROL_PLANE_API_KEY, Ansible PREGO_SSH_PRIVATE_KEY, PREGO_DB_ROOT_PASSWORD. Optional: PREGO_DB_SERVER_IP for existing node DB IP.


flowchart LR
  subgraph Manual
    A[1. Inventory]
    B[2. Ansible]
    C[3. Zuplo Sync]
  end
  D[(Control Plane)]
  E[4. Callback]
  A --> B --> C
  C --> E
  E --> D

한국어 {#korean}

프로비저닝 파이프라인 (Ansible → Zuplo Sync)

전 구간 자동화 워크플로(provision-tenant.yml) 연동 전, 수동으로 Ansible 실행 후 Zuplo Sync까지 수행하는 방법.
워크플로 사용 시 db_host는 Control Plane GET /internal/db-host(R7, region별 env 설정 시) 우선, 미설정 시 Pulumi 출력·vars에서 결정된다. Ref: db-redis-scaling-policy-r7 §5.

Ref: intelligent-automation-implementation-plan §3.2, §3.3.

전제

  • Pulumi로 서버가 이미 프로비저닝되어 있고 server_ip(또는 관리 FQDN)를 알고 있음.
  • 인벤토리에 해당 호스트가 등록되어 있고 SSH 접근 가능.

1. 인벤토리 설정

Ansible 코드는 prego-ansible 레포에 있음. inventory/inventory.example.yml을 복사해 inventory/inventory.yml을 만들고 ansible_host·db_host를 설정.

DB 분리형 (Phase 1 권장) 예시: 위 영문 §1의 yaml 참조. 단일 서버(App+DB 동일)인 경우 prego_db_serversprego_nodes에 같은 IP를 넣고 db_host도 동일 IP로 설정.

Redis 분리 사용 시: prego_redis_servers 그룹 추가, redis_01.ansible_host에 Redis 서버 IP, 실행 시 -e redis_requirepass=... -e redis_password=... 전달. Ref: redis-migration.

2. Ansible 실행

필수 변수: tenant_id, db_root_password. 선택: canonical_hostname, company_name, abbr. 회사명·약어 예: -e "company_name=주식회사 예시" -e "abbr=예시". 출력: artifacts/tenant_api_key.txt, artifacts/tenant_info.json. 실패 시: SSH, DB 연결, bench 로그 확인. 재설치: ansible-clean-and-reinstall.

3. Zuplo Sync

Prego 레포에서 ZUPLO_ACCOUNT_NAME, ZUPLO_BUCKET_NAME, ZUPLO_API_KEY 설정 후 npx tsx infra/zuplo_sync.ts YOUR_TENANT_ID --api-key-file /path/to/tenant_api_key.txt. (예시는 위 영문 §3 참조.)

3.5 (선택) 테넌트 상세·추가 사용자(additional_users) 조회

GET {CONTROL_PLANE_URL}/internal/billing?tenant_id={TENANT_ID}, Authorization: Bearer {INTERNAL_API_KEY}. 응답: tenant_id, status, plan_tier, subdomain_slug, company_name, abbr, admin_email, admin_name, additional_users 등.

4. (선택) Control Plane 콜백

파이프라인 완료 후 D1 갱신: provision_jobs.status → Completed, tenants_master.status → Active, tenant_runtime 기록. 콜백 URL·페이로드는 Control Plane 구현에 따름.

5. Zuplo 플랜별 Rate Limit (R6)

플랜별 한도: Free 100 req/min, Basic 300, Professional 1,000, Enterprise 5,000 (예시). Zuplo 대시보드 → Consumer(tenant_id) → plan_tier 확인 후 정책 적용. Ref: tenant-onboard-resource-allocation-flow-plan §6.6.

워크플로 연동 시 입력

입력필수설명
job_idprovision_jobs.job_id
tenant_id테넌트 ID. site_name = canonical_hostname. tenant-subdomain-dns-design 참조.
regionsg / us / eu
target_server_id아니오기존 노드 배치 시 nodes.node_id
create_new_server아니오1이면 신규 Pulumi up 후 Ansible
subdomain_slug아니오사용자 서브도메인 (예: acme → acme.pregoi.com CNAME).

워크플로 단계: resolve-server → tenant-dns (Cloudflare canonical + 사용자 CNAME) → ansible-provision → zuplo-sync → callback. Secrets: HCLOUD_TOKEN_, PULUMI_ACCESS_TOKEN, CLOUDFLARE_, ZUPLO_*, CONTROL_PLANE_API_KEY, PREGO_SSH_PRIVATE_KEY, PREGO_DB_ROOT_PASSWORD 등.

Help