Add internal org_mover API for organization maintenance

What does this MR do and why?

Adds an internal API for the org-mover control plane to drive an organization's maintenance lifecycle via the Organizations::Stateful state machine, plus state and readiness checks.

New endpoints under /api/v4/internal/org_mover/, authenticated by the gitlab-shell JWT and gated per organization by an ops feature flag (see below):

Method Action Transition
GET maintenance_state reports { state: } (current lifecycle state)
GET maintenance_readiness reports { ready: } (drain status)
POST start_maintenance active → maintenance_initialization
POST confirm_maintenance maintenance_initialization → maintenance
POST cancel_maintenance maintenance_initialization → active
POST exit_maintenance maintenance → active

confirm_maintenance is guarded by Gitlab::Organizations::MaintenanceReadiness, which currently reports false until the drain checks land in the follow-up, so it returns 409 (retryable) until the organization is drained. Transitions run under a row lock and are idempotent (already-in-target returns 204).

Every endpoint is gated by the org_mover_maintenance_api ops feature flag, checked with the target organization as the actor, and returns 404 when the flag is off. The flag is default-off and enabled per organization only for the duration of a move, so the shared gitlab-shell token cannot drive maintenance on an arbitrary organization. A dedicated credential is tracked in the follow-up below.

References

How to set up and validate locally

Run the request specs:

bundle exec rspec spec/requests/api/internal/org_mover_spec.rb

Or exercise the endpoints against a GDK. In the Rails console, enable the ops flag for a test organization, set it active, and mint a gitlab-shell token:

org = Organizations::Organization.create!(name: "T", path: "t-#{SecureRandom.hex(3)}",
  visibility_level: Organizations::Organization::PUBLIC)
org.update!(state: :active)
Feature.enable(:org_mover_maintenance_api, org)
puts JSONWebToken::HMACToken.new(Gitlab::Shell.secret_token)
       .tap { |t| t.issuer = Gitlab::Shell::JWT_ISSUER }.encoded

Then call the endpoints with the org id and token:

curl -s -X POST https://gdk.test:3000/api/v4/internal/org_mover/start_maintenance \
  -H "Gitlab-Shell-Api-Request: $TOK" -H "Content-Type: application/json" \
  -d "{\"organization_id\": $ORG, \"maintenance_reason\": \"migration\"}" -w "\n%{http_code}\n"

Expected: start_maintenance204; confirm_maintenance409 (not ready yet); cancel_maintenance/exit_maintenance204; invalid reason → 400; unknown org or flag disabled → 404; bad JWT → 401.

MR acceptance checklist

Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.

Related to #602822

Edited by Abdul Wadood

Merge request reports

Loading
Loading