Nextcloud plugin pipeline¶
This directory holds the per-plugin install + enable + configure pipeline for the addons declared under meta/addons/. 06_plugin.yml reads occ app:list once, plans the work with the filter nextcloud_plugin_plan (filter_plugins/nextcloud_plugin_plan.py) and enters each plugin at the first stage it still needs.
Scope¶
The pipeline owns three responsibilities for one Nextcloud plugin (app):
Install the plugin into the running Nextcloud container.
Enable the plugin so the in-app code paths are active.
Apply plugin-specific configuration keys and run any role-local hook.
Plan¶
Plan list |
Plugins |
Entered at |
|---|---|---|
|
wanted off and enabled right now |
one |
|
wanted on and not installed, or pinned through |
|
|
wanted on, not installed, marked |
01_background.yml, then 02_install.yml after the join |
|
wanted on, installed, not enabled |
|
|
wanted on and already enabled |
The wanted state replays the addons in order: an enabled plugin turns its incompatible_plugins off and itself on, a plugin marked enabled: false turns itself off, and a later entry wins.
Background installs¶
An addon MAY set config.background_install: true. recognize sets it.
After the
disablestep, 01_background.yml startsocc app:installfor each such plugin as an async job, one plugin at a time.The gate prints the async job file (
results_fileof the job) and runs files/php/utils/migration_state.php in the container, which prints the versionsoc_migrationsrecords for the app and the versions its migration folder holds. The filternextcloud_background_gatemaps each poll to a state:State
Poll result
Gate
openthe job ended with an occ exit code, or the folder holds at least one version and exactly the recorded ones
the play continues
killedthe job ended without an occ exit code, with a negative one, with
124or with129-192, or its job file is still missing after 15 pollsthe task fails
waitanything else, including a probe that fails or that
CONTAINER_EXEC_TIMEOUT(60 s for this task) cuts offthe task polls again, and fails after
NEXTCLOUD_PLUGIN_BACKGROUND_ASYNC_TIMEThe gate does not use
occ migrations:status: Nextcloud registers it only withdebugon.The install loop runs while the job finishes.
The
alwayssection of the install block joins every job withasync_status. The filternextcloud_background_lostfails the join on the exit codes of thekilledstate.Each joined plugin runs 02_install.yml:
occ app:installanswersalready installedonce the job placed the app, so the stage enables and configures it. When the job failed before it placed the app, the stage installs it with its own retries.
The job runs in every mode, ASYNC_ENABLED included. Its limit NEXTCLOUD_PLUGIN_BACKGROUND_ASYNC_TIME in vars/main.yml is 7 days, the default of SYS_TIMEOUT_CONTAINER_EXEC.
Pipeline stages¶
Each tasks/02_manager_ops/06_plugin/<step>.yml file owns exactly one OCC stage and one decision about whether to continue.
File |
Stage |
OCC command |
Continues to next stage when |
|---|---|---|---|
install |
|
install result is |
|
enable |
|
enable result is not flagged |
|
configure |
one |
(terminal stage) |
Pinned archives¶
An addon MAY pin a release through config.archive. Before occ app:install, 02_install.yml stages the archive on the node and pipes it into files/shell/utils/replace_pinned_app.sh inside the container:
The script unpacks the archive into
custom_apps/.<app>.stage, a directory Nextcloud skips because of its leading dot, and fails without touching the installed app when the archive lacks<app>/appinfo/info.xml.When
diff -rqfinds the installed app identical to the release, it removes the stage and the task reports no change.Otherwise it renames the installed app to
custom_apps/.<app>.old, moves the release into its place and removes both, so the app directory holds exactly the files of the release and the task reports a change.
occ app:install then answers already installed.
Configure stage¶
04_configure.yml runs once for every queued plugin: first the plugins the install loop enabled, then the background installs, then those the enable loop enabled, then those of the configure plan list.
It loads the addon spec of every queued plugin.
It reads
occ config:listonce and keeps an entry only when Nextcloud does not already hold the exact valueocc config:app:setwould store. Entries with atype, sensitive values thatconfig:listmasks, booleans, floats and structured values are always kept.It writes the kept entries in spec order through one php process: files/php/utils/occ_batch.php boots the occ console the way Nextcloud’s
console.phpdoes and runs oneconfig:app:setper entry, with the arguments the filternextcloud_occ_config_set_batchbuilds. The calls arrive as base64 JSON on stdin, in front of the script. The first failing call stops the process and names itsappid/configkeyon stderr. The task reports changed only whenoccanswersset to.It runs the hook of every queued plugin in queue order.
The keep or drop decision lives in the filter nextcloud_plugin_config_pending (filter_plugins/nextcloud_plugin_config.py).
The classification of “runnable” and “incompatible” is computed by the Jinja filter nextcloud_install_status defined in roles/web-app-nextcloud/filter_plugins/nextcloud_install.py.
The filter inspects rc, stdout, and stderr from the OCC call and returns flags that drive until, failed_when, and when.
Version-compatibility tolerance¶
A plugin MAY ship an appstore release that lags the pinned Nextcloud server major.
In that case OCC emits the marker string is not compatible with this version of the server and exits non-zero.
The pipeline MUST treat this as a non-fatal condition:
02_install.ymlaccepts the install as terminal so the retry loop ends immediately.02_install.ymland03_enable.ymleach emit adebugwarning that the plugin will be skipped for this run.The next stage in the pipeline MUST NOT execute when the previous stage classified the plugin as
incompatible.
Once a compatible release ships, the next deploy run will install + enable + configure the plugin automatically without operator intervention.
Mandatory plugins¶
A plugin entry MAY set mandatory: true. This inverts the tolerance above: when the plugin is enabled for the current deployment but its install result is not runnable (incompatible with the pinned server major, or unavailable on the appstore), 02_install.yml aborts the deployment with ansible.builtin.fail instead of emitting the skip warning.
The OIDC login entry points (oidc_login, sociallogin, user_oidc) are mandatory because they gate SSO login: when one of them is the selected flavor and the system hides the native login form, an un-installed OIDC app leaves the instance with no usable login path. Failing at install time surfaces the version-pin mismatch immediately rather than as a downstream login timeout in the Playwright e2e suite.
Adding configuration for a plugin¶
Per-plugin configuration is keyed by the addon id and rendered by 04_configure.yml. A new plugin requires no changes here when its addon spec and optional hook file are present at the conventional paths.
Configuration keys (optional). Add a
config.plugin_configurationlist tometa/addons/<addon_id>.yml. Each list item MUST containappid,configkey, andconfigvalue.04_configure.ymlloads the addon spec and invokesocc config:app:setfor every entry whose value Nextcloud does not hold yet.Custom logic (optional). Create
tasks/addons/<addon_id>.yml. The hook runs after the configuration of every queued plugin and MAY perform plugin-specific provisioning such as LDAP wiring or REST calls against the live container.
The hook is looked up via the path constant NEXTCLOUD_CNODE_PLUGIN_TASKS_PATH defined in vars/main.yml.
Missing files MUST be tolerated; the corresponding step skips cleanly.
Mutually exclusive plugins¶
An addon under meta/addons/ MAY declare an incompatible_plugins list in its config:.
The plan’s disable list carries every listed plugin that ends up off and still runs, and 02_install.yml disables the listed plugins again before an install attempt.
This guarantees that mutually exclusive integrations such as the OIDC entry points (oidc_login, sociallogin, user_oidc) and the document-editing surfaces (onlyoffice, richdocuments, fileslibreofficeedit) cannot accidentally coexist on the same instance.
Entry point¶
02_manager_ops.yml includes 06_plugin.yml once.
It loops over the NEXTCLOUD_PLUGIN_ITEMS of the background, install and enable plan lists and unpacks the loop variable plugin_item into plugin_key (the OCC app name) and plugin_value (its meta entry), then includes the configure stage once for the queue nextcloud_plugin_configure_keys.