Skip to content

Site actions, credentials, and requests

How the Hub creates, updates, upgrades, restarts, and archives sites, manages site credentials, and dispatches governance requests. The authorization rules are in Authentication and authorization.

Request handling and validation

Every body-bearing API request binds the same form classes that the UI uses, from JSON or form data, and validates them before any write (hub/.../app/api/request_models.py). On a validation failure, the Hub answers 400 and each message is prefixed with the [field] token that the create modal uses to mark the field (core/tests/test_add_edit_site_form.py covers the form rules; hub/tests/test_api_request_validation.py covers the request binding). Key rules:

  • POST /sites/ runs AddEditSiteForm.pre_initialize_add_form: the owner, registered-by user, fresh master token, and fresh Site ID default to the caller and to generated values, registered_date is today, and the retention date defaults to today plus 365 days. Non-administrators get the protected-field treatment (see 18 — Form fields). A template parameter applies a saved create template (core/.../service/site_templates.py, HUI-02).
  • PUT/PATCH /sites/<space>/<site>/ runs pre_initialize_edit_form, which attaches change validators so that owner, site_type, monitored, and resource_limits change only for platform administrators, and preserves registered_by and registered_date.
  • The force query parameter (upgrade routes, both versions) accepts only true or false; a repeated or other value answers 400 with a [force] message.
  • List routes parse name, type, q, space, owner, sort_by, order_by, limit, offset, continuation_token, and enabled_only (the page constant is declared but never read); a non-decimal limit or offset answers 400 with the field name. The search/pagination form used by the UI table fragment is not used by API routes.

Site actions

Site creation and updates build one Site model from form or API input. The Hub writes the model as the Site custom resource. Upgrade actions rebuild applications with upgrade=true, which updates built-in images and preserves custom images. Restart actions delete the site pods directly through the Kubernetes API, selected by the Site's labels, with the configured termination grace period; the StatefulSet recreates them without an operator pass.

The bulk and single-site upgrade endpoints accept ?force=true for platform administrators. It defaults to false; invalid or repeated values return HTTP 400. Both v1 and v2 support it. A force request on a single Site from a caller who is not a platform administrator returns 403; a Site administrator role is still required. The Hub administration page has Force Upgrade All Sites, which is available even when no new application version is available. For platform administrators, the site page Actions menu has Force Upgrade Site. Both force actions in the interface ask for confirmation. The force option writes a new sites.ecmwf.int/upgrade-request annotation with a fresh UUID to each Site; the operator treats the add or change of that annotation as a full update trigger, so repeated forced upgrades are possible. It includes archived Sites without enabling them. The bulk API response confirms queueing, not completion. The Hub logs each failed site upgrade and a summary with the success and failure counts. A Redis lock (sites-bulk-upgrade, 30-minute expiry as a safety net) allows only one bulk upgrade at a time; a second request returns HTTP 409 until all queued upgrades complete or the lock expires. Bulk restart has no lock and no result tracking: each restart runs on the thread pool and the response reports that the round was dispatched.

Toggle actions change spec.configuration.enabled. The PATCH /retention-date/ action extends the retention date to one year from today and takes no body; arbitrary retention dates go through the normal Site update. The operator scales disabled Sites to zero and keeps the route, which answers with HTTP 302 to the Hub 410 error page (see 14-routing).

Editing a public Site that still carries a custom application image reverts the Site to private (site_type_reverted), applies the default view users and groups when no access lists exist, and says so in the response message (hub/tests/test_edit_site_reverted.py). Audit entries record URL, owner, and type changes.

Large platform actions use the Hub's thread pool (core/.../threading/pool.py): one general pool for per-Site work (bulk upgrade, bulk restart, Site health probes) and a single-worker FIFO queue for report generation. The HTTP response reports that the action was accepted while per-Site work continues. The Site resource and operator status are the source of truth for the result.

Site credentials and URL endpoints

The credential endpoints that the Site stores inside its own volume (HTTP access tokens, signed URLs, session URLs) are proxied by the Hub to the Site API with the Site master token (core/.../misc/requests_utils.py); the Hub never stores them (07-site-api, token semantics in 10-security). Shared rules for these handlers:

  • the caller must be a Site administrator (or platform administrator);
  • on an archived Site, token create/delete/history and signed/session URL creation answer 410;
  • a failed call to the Site API answers 500 with the Site's message;
  • the master token itself lives in the Site resource: GET returns it, and the regenerate action on an enabled Site writes a new MasterToken through the normal Site update. On an archived Site the regenerate action answers 200 with a null token and an "archived" message.

Governance and access requests

The three request endpoints (access/, requests/publish/, requests/storage/) notify people through the notification integration. All three first check notifications_dispatcher.is_enabled(); without an active provider they answer 503 with "Requests are not available" (hub/tests/test_notifications_required.py). The dispatch runs inside the request; a failed dispatch answers 500.

Request Caller Body Assignee
Request access (access/) any logged-in caller who cannot already access the Site (403 otherwise); an anonymous caller is refused none the Site owner, broadcast
Publish request (requests/publish/, v2) Site administrator comment (required) jobs.notification_default_assignee
Storage request (requests/storage/, v2) Site administrator quota (default 600 GB) and comment (required) jobs.notification_default_assignee

A publish request on an already-public Site answers 400. Each request renders a Jinja notification template from core/.../notifications/templates/ and carries an md5 digest of summary, Site path, assignee, and reporter as its duplicate key.