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/runsAddEditSiteForm.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_dateis today, and the retention date defaults to today plus 365 days. Non-administrators get the protected-field treatment (see 18 — Form fields). Atemplateparameter applies a saved create template (core/.../service/site_templates.py, HUI-02).PUT/PATCH /sites/<space>/<site>/runspre_initialize_edit_form, which attaches change validators so thatowner,site_type,monitored, andresource_limitschange only for platform administrators, and preservesregistered_byandregistered_date.- The
forcequery parameter (upgrade routes, both versions) accepts onlytrueorfalse; 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, andenabled_only(thepageconstant is declared but never read); a non-decimallimitoroffsetanswers 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
MasterTokenthrough 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.