admin
Administrator endpoints: users, groups, stores, installed apps, templates.
attributelogger= logging.getLogger(__name__)attributestatus_router= APIRouter(route_class=EncryptedRoute)attributerouter= APIRouter(prefix='/api/admin', dependencies=[Depends(verify_admin), Depends(routing.announce_changes)], route_class=EncryptedRoute)attributetemplate_router= APIRouter(prefix='/api/admin', dependencies=[Depends(verify_template_editor), Depends(routing.announce_changes)], route_class=EncryptedRoute)func_gpu_list() -> list[GPUInfo]Return the GPUs sessions can request now, as API models.
Returns
list[app.models.GPUInfo]funcadmin_status(user=Depends(verify_token)) -> dict[str, Any]Return the caller's role, settings, and host statistics.
provider_groups are the groups the identity provider or proxy named,
expires is when a web sign-in ends by the server's own clock, and
storage_used the bytes under the user's storage on this node, for a user
with persistent storage.
paramuserdict[str, Any]= Depends(verify_token)Returns
dict[str, typing.Any]funcget_management_data() -> dict[str, Any]Return users, groups, and server details for the dashboard.
Returns
dict[str, typing.Any]func_require_safe_name(name, kind) -> strValidate a store or template name for use in file paths.
paramnamestrparamkindstrReturns
strfuncget_app_stores() -> list[AppStore]List configured app stores.
Returns
list[app.models.AppStore]funcadd_app_store(decrypted_body=Depends(get_decrypted_request_body)) -> AppStoreAdd an app store.
paramdecrypted_bodydict[str, Any]= Depends(get_decrypted_request_body)Returns
app.models.AppStorefuncdelete_app_store(store_name) -> ResponseRemove an app store.
paramstore_namestrReturns
fastapi.Responsefuncget_available_apps(store_name, url=None, refresh=False) -> list[dict[str, Any]]Return the apps published by a configured store (cached unless refresh).
The store is fetched from the URL saved with it; a url query parameter
is accepted for older clients but must match that saved URL.
paramstore_namestrparamurlstr | None= Noneparamrefreshbool= FalseReturns
list[dict[str, typing.Any]]func_catalog_status(catalog) -> ProotCatalogStatusAttach this node's sync state to a catalog.
paramcatalogProotCatalogReturns
app.models.ProotCatalogStatusfunc_catalog_from(body, catalog_id, revision) -> ProotCatalogValidate the catalog the admin UI sent, without repeats among its apps.
parambodydict[str, Any]paramcatalog_idstrparamrevisionintReturns
app.models.ProotCatalogfunclist_proot_catalogs() -> list[ProotCatalogStatus]List the PRoot Apps catalogs with the state of this node's copy of each.
Returns
list[app.models.ProotCatalogStatus]funclist_proot_remote(remote, refresh=False) -> list[ProotRemoteApp]Return the apps a PRoot Apps remote publishes (see prootapps.Remote).
paramremotestrparamrefreshbool= FalseReturns
list[app.models.ProotRemoteApp]funccreate_proot_catalog(decrypted_body=Depends(get_decrypted_request_body)) -> ProotCatalogStatusCreate a catalog; every node starts fetching its apps.
paramdecrypted_bodydict[str, Any]= Depends(get_decrypted_request_body)Returns
app.models.ProotCatalogStatusfuncupdate_proot_catalog(catalog_id, decrypted_body=Depends(get_decrypted_request_body)) -> ProotCatalogStatusReplace a catalog's name and apps; every node brings its copy along.
paramcatalog_idstrparamdecrypted_bodydict[str, Any]= Depends(get_decrypted_request_body)Returns
app.models.ProotCatalogStatusfuncrefresh_proot_catalog(catalog_id) -> ProotCatalogStatusFetch the catalog's apps again now, on every node, where their packages changed.
paramcatalog_idstrReturns
app.models.ProotCatalogStatusfuncdelete_proot_catalog(catalog_id) -> ResponseDelete a catalog; every node removes its copy. Users assigned to it keep the setting, which then does nothing.
paramcatalog_idstrReturns
fastapi.Responsefunc_save_logo(app_id, logo) -> str | NonePersist a base64 logo as a PNG icon and return the icon URL.
paramapp_idstrApp the icon belongs to.
paramlogostr | NoneBase64 image data, an address the server already serves, a web address, or None.
Returns
str | None/api/app_icon/<id> when data was saved, otherwise logo unchanged.
func_normalise_scripts(provider_config) -> NoneTurn empty autostart script strings into None in place.
paramprovider_configdict[str, Any]Returns
Nonefunc_with_status(app) -> InstalledAppWithStatusAttach image metadata to an installed app.
paramappInstalledAppReturns
app.models.InstalledAppWithStatusfunclist_installed_apps() -> list[InstalledAppWithStatus]List installed apps with image status.
Returns
list[app.models.InstalledAppWithStatus]funcinstall_app(decrypted_body=Depends(get_decrypted_request_body)) -> InstalledAppInstall an app from a store entry sent by the admin UI.
paramdecrypted_bodydict[str, Any]= Depends(get_decrypted_request_body)Returns
app.models.InstalledAppfuncupdate_installed_app(app_id, decrypted_body=Depends(get_decrypted_request_body)) -> InstalledAppReplace an installed app with a full definition.
paramapp_idstrparamdecrypted_bodydict[str, Any]= Depends(get_decrypted_request_body)Returns
app.models.InstalledAppfuncpatch_installed_app(app_id, decrypted_body=Depends(get_decrypted_request_body)) -> InstalledAppPartially update an installed app.
Record fields (users, groups, app_template, auto_update,
home_directories) are applied directly; any other InstalledApp
field is merged into the record's overrides.
paramapp_idstrparamdecrypted_bodydict[str, Any]= Depends(get_decrypted_request_body)Returns
app.models.InstalledAppfuncdelete_installed_app(app_id) -> ResponseUninstall an app (and purge a meta-app's icon and home template).
paramapp_idstrReturns
fastapi.Responsefunccheck_app_update(app_id) -> ImageUpdateCheckResponseCompare the local image digest with the registry.
paramapp_idstrReturns
app.models.ImageUpdateCheckResponsefuncpull_latest_app_image(app_id) -> ImagePullResponsePull the latest image of an app and refresh its autostart cache.
paramapp_idstrReturns
app.models.ImagePullResponsefunccreate_meta_app(decrypted_body=Depends(get_decrypted_request_body)) -> InstalledAppCreate a meta-app: a copy of an installed app with its own home template.
paramdecrypted_bodydict[str, Any]= Depends(get_decrypted_request_body)Returns
app.models.InstalledAppfunc_lab_session(username) -> tuple[str, dict[str, Any]] | NoneReturn the App Laboratory session an administrator has open on this node, if any.
paramusernamestrReturns
tuple[str, dict[str, typing.Any]] | Nonefunclab_session(auth_user=Depends(verify_admin)) -> dict[str, Any]Return the caller's open App Laboratory session, which no session list shows.
paramauth_userdict[str, Any]= Depends(verify_admin)Returns
dict{"session": null}, or the session with app_id, app_name,
func_measure(path) -> dict[str, int]Return the file count and size of a directory.
parampathstrReturns
dict[str, int]funcclose_lab_session(progress_id='', auth_user=Depends(verify_admin)) -> dict[str, Any]Stop the caller's App Laboratory session, which keeps what it changed as the meta-app's template.
With progress_id, a UUID the client chose, the closing reports its
stages to GET /api/launch/progress/{progress_id}: stopping the
session, then saving, which measures the template, then ready with
the template's files and bytes.
paramprogress_idstr= ''paramauth_userdict[str, Any]= Depends(verify_admin)Returns
dict{"files": n, "bytes": n} of the template kept, zeros when no
funclaunch_meta_for_customization(decrypted_body=Depends(get_decrypted_request_body), auth_user=Depends(verify_admin)) -> dict[str, str]Launch a meta-app with its home template mounted read-write.
An administrator of a web sign-in has one such session at a time: a second is refused with 409 until the first is closed.
paramdecrypted_bodydict[str, Any]= Depends(get_decrypted_request_body)paramauth_userdict[str, Any]= Depends(verify_admin)Returns
dict[str, str]func_run_option_settings(template_settings) -> dict[str, str]A template's DOCKER_* and KUBERNETES_* settings, as text.
They become container run options (privileged mode, devices, namespaces, binds) or the pod template a session starts from, and so carry authority over the Docker host or the namespace. Text, since a hand-edited template may hold them as YAML booleans or numbers.
paramtemplate_settingsdict[str, Any]Returns
dict[str, str]func_identity_settings(template_settings) -> dict[str, str]A template's settings that name the session's identity (RESERVED_ENV), as text.
paramtemplate_settingsdict[str, Any]Returns
dict[str, str]funceditor_settings(stored, submitted) -> dict[str, Any]Return the settings a template editor who is not an administrator may save.
The stored template's DOCKER_* and KUBERNETES_* run options and identity
variables stay as they are: one left out keeps its value, and one added or
changed is refused.
paramstoreddict[str, Any]paramsubmitteddict[str, Any]Returns
dict[str, typing.Any]funcget_app_templates() -> list[dict[str, Any]]List app templates.
Returns
list[dict[str, typing.Any]]funcsave_app_template(decrypted_body=Depends(get_decrypted_request_body), user=Depends(verify_template_editor)) -> AppTemplateCreate or replace a template.
A template editor who is not an administrator keeps the template's DOCKER_*
and KUBERNETES_* settings and the session's identity variables as they are
(editor_settings). A PodTemplate the template names must be a valid name.
paramdecrypted_bodydict[str, Any]= Depends(get_decrypted_request_body)paramuserdict[str, Any]= Depends(verify_template_editor)Returns
app.models.AppTemplatefuncdelete_app_template(template_name, user=Depends(verify_template_editor)) -> ResponseDelete a user template; one with DOCKER_* or KUBERNETES_* settings only as an administrator.
paramtemplate_namestrparamuserdict[str, Any]= Depends(verify_template_editor)Returns
fastapi.Responsefuncget_all_sessions(request, user=Depends(verify_admin)) -> list[UserSessionList]List every session on every node grouped by user.
paramrequestRequestparamuserdict[str, Any]= Depends(verify_admin)Returns
list[app.models.UserSessionList]funcstop_any_session(session_id) -> ResponseStop any user's session.
paramsession_idstrReturns
fastapi.Responsefunccreate_admin(decrypted_body=Depends(get_decrypted_request_body)) -> dict[str, Any]Create a key-file administrator; refused where key files are off, since administrators then come from the provider.
paramdecrypted_bodydict[str, Any]= Depends(get_decrypted_request_body)Returns
dict[str, typing.Any]funcdelete_admin(username) -> ResponseDelete an administrator.
paramusernamestrReturns
fastapi.Responsefunccreate_user(decrypted_body=Depends(get_decrypted_request_body)) -> dict[str, Any]Create a user; with key files off, a sign-in-only user, whatever key the request carries.
paramdecrypted_bodydict[str, Any]= Depends(get_decrypted_request_body)Returns
dict[str, typing.Any]funcupdate_user(username, decrypted_body=Depends(get_decrypted_request_body)) -> dict[str, Any]Replace a user's settings.
paramusernamestrparamdecrypted_bodydict[str, Any]= Depends(get_decrypted_request_body)Returns
dict[str, typing.Any]funcapprove_user(username, decrypted_body=Depends(get_decrypted_request_body)) -> dict[str, Any]Let a held user in, placed in the groups the body names; none leaves them in default.
paramusernamestrparamdecrypted_bodydict[str, Any]= Depends(get_decrypted_request_body)Returns
dict[str, typing.Any]funcdelete_user(username) -> ResponseDelete a user and their storage.
paramusernamestrReturns
fastapi.Responsefunc_require_storage_user(username) -> NoneEnsure a user exists and has persistent storage enabled.
paramusernamestrReturns
Nonefunc_require_admin_user(username) -> NoneEnsure username is an administrator.
paramusernamestrReturns
Nonefunclist_user_home_dirs(username) -> dict[str, list[str]]List a user's home directories.
paramusernamestrReturns
dict[str, list[str]]funccreate_user_home_dir(username, decrypted_body=Depends(get_decrypted_request_body)) -> dict[str, str]Create a home directory for a user.
paramusernamestrparamdecrypted_bodydict[str, Any]= Depends(get_decrypted_request_body)Returns
dict[str, str]funcdelete_user_home_dir(username, home_name) -> ResponseDelete a user's home directory.
paramusernamestrparamhome_namestrReturns
fastapi.Responsefunclist_admin_home_dirs(username) -> dict[str, list[str]]List an administrator's home directories.
paramusernamestrReturns
dict[str, list[str]]funccreate_admin_home_dir(username, decrypted_body=Depends(get_decrypted_request_body)) -> dict[str, str]Create a home directory for an administrator.
paramusernamestrparamdecrypted_bodydict[str, Any]= Depends(get_decrypted_request_body)Returns
dict[str, str]funcdelete_admin_home_dir(username, home_name) -> ResponseDelete an administrator's home directory.
paramusernamestrparamhome_namestrReturns
fastapi.Responsefunccreate_group(decrypted_body=Depends(get_decrypted_request_body)) -> dict[str, Any]Create a group.
paramdecrypted_bodydict[str, Any]= Depends(get_decrypted_request_body)Returns
dict[str, typing.Any]funcupdate_group(group_name, decrypted_body=Depends(get_decrypted_request_body)) -> dict[str, Any]Replace a group's settings; default has none to replace.
paramgroup_namestrparamdecrypted_bodydict[str, Any]= Depends(get_decrypted_request_body)Returns
dict[str, typing.Any]funcdelete_group(group_name) -> ResponseDelete a group; default cannot be.
paramgroup_namestrReturns
fastapi.Response