Skip to content

Commit 00a19f9

Browse files
h4x3rotabclaude
andcommitted
feat(app): wire in-place updates in members (MIG) mode
The 0.3.0-beta.1 guardrail that refused app-level mutable-field updates in members mode is gone. phala_app.Update now propagates every common edit across all slots while preserving slot identity (vm_uuid and name are unchanged across the update). Two complementary execution paths, picked by what changed: 1. Compose-body changes (docker_compose, pre_launch_script, public_*, gateway_enabled, secure_time, env-key list) use the cloud's app-revision endpoint: a. provisionAndApplyComposeFileUpdate on the bootstrap CVM. This provisions the new compose hash AND applies it to the bootstrap, creating the revision row in the app's history. b. Wait for the bootstrap to settle on the new compose_hash. c. Read the new compose_hash back from the bootstrap row. d. findRevisionIDByComposeHash against /apps/{id}/revisions. e. redeployRevisionAcrossCVMs to every other slot via POST /apps/{id}/revisions/{rev}/redeploy with vm_uuids=[others]. f. waitForCVMsOnComposeHash until every CVM lands on the new hash. We split the bootstrap apply from the slot redeploy because /cvms/{id}/compose_file/provision only caches a compose_hash — it does NOT create a revision row. The PATCH /compose_file (or the POST equivalent) is what materializes the revision in the app's history, and the redeploy endpoint requires the revision to already exist in ClickHouse. Reading the new compose_hash off the bootstrap CVM after it settles is the cheapest way to resolve the revision_id without a separate "list revisions and pick the newest" heuristic. 2. Per-CVM mutable fields the cloud doesn't expose at the app level — env values via PATCH /cvms/{uuid}/envs, image via /os-image, size/disk via /resources — get a sequential fan-out over the known vm_uuids list. The app-rooted KMS public key is shared across all CVMs in one app, so we encrypt env once against the bootstrap's pubkey and the same bytes are accepted by every slot. Fail-fast on the first error so partial-apply recovery in Terraform has a clear stop position. ModifyPlan now does only the one structural check: refuse the "removing members from a previously-members-mode app" transition, because that would orphan phala_app_instance slots. All the mutable-field plan-time blocks are gone — those fields work now. Single-CVM apps (no `members`) still use the existing direct-PATCH path against the bootstrap CVM with zero fan-out machinery. Update was restructured into applyMembersModeUpdate vs applySingleCVMUpdate so the two paths are clearly separated without code duplication. Live verification on real Phala Cloud (h4xuser, US-WEST-1) on a 2-slot MIG (`upd-a` bootstrap + `upd-b` instance): - Initial apply: both CVMs come up running with compose_hash 2608b800ef995746dc46ce0418752779e947278aa158eed28709accdeff9a912. - Compose update (docker_compose marker INITIAL → UPDATED): apply succeeded in 2m16s, both vm_uuids preserved (4e0fd1e7-d4b0-4d68-98f3-37f3a011c8a3 and 3307fe7d-f4e3-48db-91ad-891c6783ca53), both CVMs report the new compose_hash 39ef1e5ed81d70c61fc822dfacd7d19b084f3bea103d45306a7f626bdd0125c9, and `docker-compose.yml` on each CVM now serves `MARKER=UPDATED`. - Env-only update (TEST_KEY v1 → v2-updated, no compose change): apply succeeded in 1m10s, both vm_uuids preserved, both CVMs still on the same compose_hash 39ef1e5e... — env path correctly did not trigger a new revision. - Subsequent `terraform plan` against the updated stack: "No changes." - Destroy clean; baseline CVM count restored. Unit tests added in resource_app_members_update_test.go cover: - provision → list-revisions → redeploy chain ordering with both a single-page and a 2-page revision list. - redeploy body shape (vm_uuids array passed through). - 465 on-chain KMS rejection surfaced as "kms = phala only" error. - per-CVM env fan-out sequencing and fail-fast. - waitForCVMsOnComposeHash transitioning across polls. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent e6000ba commit 00a19f9

8 files changed

Lines changed: 951 additions & 389 deletions

File tree

CHANGELOG.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,27 @@ All notable changes to `terraform-provider-phala` are documented in this file.
44

55
## [Unreleased]
66

7+
## [0.3.0-beta.2] - 2026-05-19
8+
9+
In-place updates work in members (MIG) mode for all the fields users actually edit. The release-blocking guardrail from 0.3.0-beta.1 is gone.
10+
11+
### Added
12+
13+
- `phala_app.Update` now propagates changes across every CVM in a members-mode app, preserving slot identity (`vm_uuid` and `name` are unchanged across the update):
14+
- **Compose-body changes** (`docker_compose`, `pre_launch_script`, `public_logs`, `public_sysinfo`, `public_tcbinfo`, `gateway_enabled`, `secure_time`, env-key list) flow through the cloud's app-revision endpoint: provision + apply on the bootstrap CVM (which creates the revision row), then `POST /apps/{id}/revisions/{rev}/redeploy` with `vm_uuids = [other slots]`. Verified end-to-end on a 2-slot MIG: bootstrap update + slot redeploy lands the new `compose_hash` on every CVM with both `vm_uuid`s preserved.
15+
- **Env value changes** (the common "rotate a secret" case) use a per-CVM `PATCH /cvms/{uuid}/envs` fan-out across every slot. The app-rooted KMS public key is shared across all CVMs in one app, so the same encrypted_env bytes are accepted by every slot. `compose_hash` stays unchanged (no new revision).
16+
- **OS image changes** (`image`) fan out per-CVM via `PATCH /cvms/{uuid}/os-image` — the cloud has no app-level analog. Sequential, fail-fast.
17+
- **Size / disk_size changes** fan out per-CVM via `PATCH /cvms/{uuid}/resources`. Same pattern.
18+
19+
### Changed
20+
21+
- `ModifyPlan` no longer blocks app-level mutable-field updates in members mode. The only structural check kept is the "cannot leave members mode in-place" guard, which still requires destroy + recreate when a user removes the `members` attribute from a previously-members-mode app.
22+
- Single-CVM apps (no `members`) follow the same single-CVM update path as before — PATCHes target the bootstrap directly with no fan-out machinery. Zero behavior change for that case.
23+
24+
### Fixed
25+
26+
- The members-mode guardrail's diagnostic message previously suggested workarounds (destroy+recreate, per-slot env) that are no longer needed for `docker_compose` / `env` / `image` / `size` / `disk_size`. Those workarounds were obsolete the moment we wired up the revision and fan-out paths; the message is gone with the guardrail.
27+
728
## [0.3.0-beta.1] - 2026-05-18
829

930
First prerelease of the 0.3 line. The provider's model collapses to:

FEATURE_MATURITY.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Terraform Provider Feature Maturity
22

3-
Last updated: 2026-05-18
3+
Last updated: 2026-05-19
44

55
## Maturity Levels
66

docs/resources/app.md

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -56,17 +56,15 @@ When `members` is set, the provider enforces at plan time that `name` is one of
5656

5757
Downstream `phala_app_instance` resources should set `for_each = toset(phala_app.foo.members)` so the slot list stays a single source of truth.
5858

59-
## In-place updates are blocked in members mode
59+
## In-place updates in members mode
6060

61-
The cloud's per-CVM PATCH endpoints (`/cvms/{id}/docker-compose`, `/envs`, `/os-image`, `/resources`, `/compose_file/provision`) only target a single CVM. Applying them through `phala_app` in members mode would mutate the bootstrap slot and leave every `phala_app_instance` slot on the old revision — divergent compose/env/image across the replica set. Until the cloud exposes an app-revision-aware update endpoint that preserves all named slots, this provider refuses at plan time to update any of these `phala_app` fields when `members` is set:
61+
`phala_app.Update` propagates mutable-field changes across every CVM in a members-mode app while preserving slot identity (`vm_uuid` and `name` are unchanged):
6262

63-
`docker_compose`, `pre_launch_script`, `env`, `encrypted_env`, `env_keys`, `env_compose_hash`, `env_transaction_hash`, `image`, `size`, `disk_size`, `public_logs`, `public_sysinfo`, `public_tcbinfo`, `gateway_enabled`, `secure_time`.
63+
- **Compose-body changes** (`docker_compose`, `pre_launch_script`, `public_*`, `gateway_enabled`, `secure_time`, env-key list changes) go through the cloud's app-revision endpoint. The provider provisions + applies on the bootstrap CVM (creating a new revision row), then `POST /apps/{id}/revisions/{rev}/redeploy` fans the same revision out to every other slot. Each CVM's `compose_hash` flips to the new value; nothing is destroyed and recreated.
64+
- **Env value changes** (the common "rotate a secret" case) use a per-CVM `PATCH /cvms/{uuid}/envs` fan-out. The app-rooted KMS public key is shared across all slots, so the same encrypted_env bytes are accepted by every slot. `compose_hash` stays unchanged (no new revision).
65+
- **OS image, instance size, and disk size changes** fan out via `PATCH /cvms/{uuid}/os-image` and `PATCH /cvms/{uuid}/resources` respectively — the cloud has no app-level analog. Sequential, fail-fast.
6466

65-
Workarounds:
66-
1. Destroy the `phala_app` + matching `phala_app_instance` resources and recreate them with the new compose / env / image.
67-
2. Move per-slot variations to `phala_app_instance.env` (per-slot encrypted env at create time; immutable thereafter).
68-
69-
Adding or removing entries from `members` is still safe (it just spawns or destroys `phala_app_instance` resources). Removing the `members` attribute entirely is **not** safe and is also blocked at plan time — destroy and recreate the app.
67+
The one structural change still blocked is **removing the `members` attribute** from a previously-members-mode app: that would leave the `phala_app_instance` slots orphaned. The provider blocks this at plan time and asks you to destroy and recreate.
7068

7169
## Migration from 0.2.x
7270

internal/provider/cvm_helpers.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,13 @@ type cvmAPIResponse struct {
4646
InstanceType string `json:"instance_type"`
4747
DiskSize *int64 `json:"disk_size"`
4848

49+
// ComposeHash is the SHA-256 of the canonical app compose body the
50+
// cloud believes this CVM is currently running. After the redeploy
51+
// fan-out, each CVM's `compose_hash` flips from the old revision's
52+
// value to the new one — used by waitForCVMsOnComposeHash to detect
53+
// completion of the async update.
54+
ComposeHash string `json:"compose_hash"`
55+
4956
Progress *struct {
5057
Target string `json:"target"`
5158
} `json:"progress"`

0 commit comments

Comments
 (0)