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: 3306Single 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).
cd /path/to/prego-ansibleansible-playbook -i inventory/inventory.yml playbook.yml \ -e tenant_id=YOUR_TENANT_ID \ -e db_root_password=YOUR_DB_ROOT_PASSWORDWith company name and abbr (after billing lookup in workflow):
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 inartifacts/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):
cd /path/to/Pregoexport ZUPLO_ACCOUNT_NAME=your-accountexport ZUPLO_BUCKET_NAME=your-bucketexport ZUPLO_API_KEY=...
npx tsx infra/zuplo_sync.ts YOUR_TENANT_ID --api-key-file /path/to/tenant_api_key.txtExample right after running prego-ansible:
npx tsx infra/zuplo_sync.ts YOUR_TENANT_ID --api-key-file ../prego-ansible/artifacts/tenant_api_key.txtOr pass the key directly:
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:
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.status → Completed, tenants_master.status → Active, 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:
| Plan | Limit (example) |
|---|---|
| Free | 100 req/min |
| Basic | 300 req/min |
| Professional | 1,000 req/min |
| Enterprise | 5,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):
| Input | Required | Description |
|---|---|---|
| job_id | Yes | provision_jobs.job_id |
| tenant_id | Yes | Tenant ID. site_name = canonical_hostname (tenant-{short_id}.pregoi.com). User URL = {subdomain_slug}.pregoi.com. Tenant subdomain DNS design |
| region | Yes | sg / us / eu |
| target_server_id | No | nodes.node_id when reusing a node (skip Pulumi) |
| create_new_server | No | 1 = new Pulumi up then Ansible |
| subdomain_slug | No | User 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_servers와 prego_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_id | 예 | provision_jobs.job_id |
| tenant_id | 예 | 테넌트 ID. site_name = canonical_hostname. tenant-subdomain-dns-design 참조. |
| region | 예 | sg / 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 등.