ReviewOS

stacks/ts-cloud

No primitive for moving a deployed site between servers (#167 operation 2 is still absent in 0.12.7)

#190
Closed glennmichael123 opened this 17 days ago · 0 comments
17 days ago

#167 was closed as completed, but operation 2 of the three it described - move a deployed app between servers - has no primitive in the published package. This splits it out so it can be tracked on its own, with the evidence.

What is actually in 0.12.7

Grepped with word boundaries over the whole published dist (the word boundaries matter: my earlier claim that moveSite existed came from a substring match on removeSiteFromCloudConfig and moveSiteInput inside RemoveSiteInput):

$ grep -rohE '\b(moveSite|migrateSite|transferSite|relocateSite|moveApp|consolidateServer|attachSite|detachSite|renameServer|deleteServer|listServers)\b' package/dist/ | sort | uniq -c
  23 listServers
  10 deleteServer
   4 renameServer

Against #167's three operations:

#167 operation0.12.7Status
1. Attach an app to an existing server as a siteattachTo, attachToComputeInfrastructure, ensureAttachModeDatabase, allowStateOnlyworks, guardrails landed in #168/#169
2. Move a deployed app between serversnothingabsent
3. Rename a server in placeHetznerClient.renameServer(id, name)provider call only, no orchestration

renameServer is reachable (via the exported HetznerClient), but it is the raw Hetzner API call. Nothing updates the ts-cloud/* labels, the state file, or the inventory record alongside it, so calling it leaves the box named one thing and labelled another. Worth noting rename is the cheap one: install paths key off siteInstallBase(slug, site) and DNS points at the IP, so the server name is only load-bearing for box lookup.

Why a move cannot be composed from what exists

An attach deploy already stands a site up on a target box, so most of "arrive" is solved. What has no primitive is carrying the state and draining the source. From the layout ts-cloud itself defines, a move has to carry:

  • the release tree at siteInstallBase(slug, site) (/var/www/<slug>-<site>), or re-deploy into it
  • persistent state outside the release tree (/var/www/<slug>-shared/…, e.g. the SQLite file the deploy symlinks there)
  • the database role and schema that ensureAttachModeDatabase provisions inside the host's Postgres
  • the systemd units: <slug>-<site>@<sha>.service, plus -queue-<i> and -daemon-<name>
  • the rpx registry fragment /etc/rpx/sites.d/<slug>.json, and the certificates in /etc/rpx/certs
  • the owner stamp <base>/.ts-cloud/owner and the deploy history log beside it
  • DNS, last, and reversibly

Every one of those is a concept ts-cloud owns. What is missing is the operation that sequences them, and specifically the data-carrying step, which no redeploy can substitute for.

Where the plan should live

stacksjs/stacks#2342 asks buddy's --dry-run to print "the plan ts-cloud produced". For move that seems right: it is the operation whose plan is genuinely non-obvious (what is copied, what is recreated, what DNS changes, what is deleted and when), and the plan is a property of the operation, not of the CLI that calls it. For attach / destroy / rename, buddy can compose a plan from existing primitives without one upstream.

If that is the wrong split, it is worth saying so on #2342 before the CLI side commits to a shape.

Sign in to comment on this issue.