Skip to content

Cloud auto-registration, per-company requests and the cutover freeze (Workstream O) - #52

Open
roncodes wants to merge 1 commit into
release/v0.2.0from
feat/cloud-cutover
Open

roncodes wants to merge 1 commit into
release/v0.2.0from
feat/cloud-cutover

Conversation

@roncodes

Copy link
Copy Markdown
Member

Phase 5, Workstream O (cloud migration): the cloud console's side of the cutover. Service side and runbook: fleetbase/registry (docs/cutover.md); infra: fleetbase/registry-infra#2.

Cloud instance identity

  • With REGISTRY_CLOUD_AUTO_REGISTER=true and REGISTRY_CLOUD_PLATFORM_SECRET set, the API registers itself with the service as the one cloud instance: on boot (registry:init, which deploy scripts already run), every five minutes from the scheduler, and on demand with registry:cloud-register [--force] [--json]. The request is signed with the platform secret (X-Registry-Timestamp, X-Registry-Nonce, X-Registry-Signature: v1=<HMAC-SHA256 of "{ts}.{nonce}.{body}">).
  • Idempotent across restarts and replicas: a stored token the service still accepts is kept and nothing is sent; one process registers at a time (cache lock, then the settings are read again, so a replica that waited finds the token the first one stored); when a token is needed the service rotates the same instance (D17: the stored token, else same organization and host). An unreachable service or a 5xx never triggers a registration. registry:init never fails the boot.
  • The instance kind is cloud whenever auto-registration is on.

Per-company requests

  • On a cloud instance every instance request carries X-Registry-Tenant (the session's company, or the installer job's company via RegistryClient::forCompany()), so Purchased, Installed, counts, install reports and checkout belong to that company's organization on the service. Instance state is cached per company; the public catalog is still cached once. The company's name goes along so the service can name an organization for a new company (looked up through a resolver the provider sets, so support classes stay database-free).
  • Install reports name the installing company; on the cloud instance every uninstall releases that company's seat (self-hosted keeps the shared-seat behaviour).
  • registry:cloud-sync-installs [--dry-run]: the cutover step that records locally (registry_service_installs) what each company had installed, from the service's import (GET /v1/instances/me/tenant-installs). Without it, cloud consoles would stop loading every engine installed before the move: v0.2.0 reads installed engines only from that table, and nothing filled it from the old installs.

Maintenance freeze

  • php artisan registry:maintenance on|off|status [--message=] (a stored setting that reaches every worker on its next request) or REGISTRY_MAINTENANCE=true: checkout, install, update and uninstall from the console answer 503 with the message. The server CLI is not frozen, so operators can still fix things.
  • The context endpoint carries maintenance, checkout is reported unavailable while frozen, and every Extensions page shows a banner (RegistryMaintenanceBanner, an InfoBlock) with the message; the installer and purchase services say why instead of opening their modals. Copy in four locales.

Tests

  • Pest: 210 pass (22 new: registration signed and stored, rotation onto the imported instance, an accepted token kept, a refused token re-registered with previous_token, no registration while the service is down, two replicas registering once, --force, disabled without both settings, refusal fails the command but not the boot; tenant headers, per-company caching, reports and seats, the install sync with pagination and unknown companies, the freeze settings and command). Fixtures recorded from the service (record_cloud.py, README updated). php-cs-fixer clean on the changed files.
  • Ember (ember test --filter "/registry-maintenance-banner|registry-context|extension-installer|extension-purchase/"): 30 of 31 pass, including the 4 new tests (banner, context getters, installer and purchase refusals). The one failure, modals/extension-purchase-status: each phase after the checkout redirect, is pre-existing and unrelated: the test sets options without receiptUrl and then asserts the receipt link (from 991ca5a); neither the component nor its test is touched here.
  • eslint and template-lint clean on the changed files.
  • Not run: a full cloud console against the service (the runbook's qa step covers it).

Fleetbase Cloud's API registers itself with the Registry Service as the one cloud instance and
acts for each company, and the console can be frozen for the cutover window.

- REGISTRY_CLOUD_AUTO_REGISTER=true with REGISTRY_CLOUD_PLATFORM_SECRET: registry:init (boot), the
  scheduler (every five minutes) and registry:cloud-register register this API through
  POST /v1/instances/register/cloud, signed with the platform secret. Idempotent across restarts
  and replicas: a stored token the service accepts is kept, one process registers at a time (cache
  lock, then a fresh read of the settings), the service rotates the same instance (D17), and an
  unreachable service never triggers a registration. registry:init never fails the boot.
- The instance kind is cloud whenever auto-registration is on. On a cloud instance every instance
  request names the company (X-Registry-Tenant: the session's company, or the installer job's), and
  instance state is cached per company; the public catalog is still cached once.
- Install reports are for the installing company, and on the cloud instance every uninstall
  releases that company's seat.
- registry:cloud-sync-installs: after the cutover import, record locally what each company had
  installed (GET /v1/instances/me/tenant-installs), so consoles keep loading their engines.
- registry:maintenance on|off|status (stored setting) or REGISTRY_MAINTENANCE=true: checkout,
  install, update and uninstall from the console answer 503 with the message, and the Extensions
  pages show it as a banner (four locales). The server CLI is not frozen.
- Fixtures recorded from the service (record_cloud.py).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant