Apply default env vars at configure-time rather than at save#351
Apply default env vars at configure-time rather than at save#351runleveldev wants to merge 6 commits into
Conversation
There was a problem hiding this comment.
⚠️ Not ready to approve
There are correctness/safety edge cases in the new configure-time env/entrypoint handling (notably around input sanitization and entrypoint deletion semantics) that should be addressed before merging.
Pull request overview
This PR changes container environment variable handling so that only user-defined env vars are stored in the database, while admin/system defaults (plus NVIDIA-derived defaults) are merged at configure-time right before calling the Proxmox API—preventing default values from being revealed in the edit UI and ensuring default changes apply to existing containers on subsequent reconfigures.
Changes:
- Move default env-var merging into
Container.buildLxcEnvConfig()with precedence: system defaults < NVIDIA defaults < user-defined. - Stop persisting merged env/entrypoint values back into the container DB record during create.
- Ensure reconfigure path awaits the now-async env-config builder so existing containers pick up updated defaults.
File summaries
| File | Description |
|---|---|
| create-a-container/routers/api/v1/containers.js | Stops baking NVIDIA defaults into persisted env vars on create. |
| create-a-container/models/container.js | Adds configure-time merging helpers and makes buildLxcEnvConfig() async with default precedence logic. |
| create-a-container/bin/reconfigure-container.js | Updates call site to await async env-config builder. |
| create-a-container/bin/create-container.js | Switches env/entrypoint application to model helper and stops writing merged values back into DB. |
Copilot's findings
Comments suppressed due to low confidence (1)
create-a-container/models/container.js:130
buildLxcEnvConfig()always addsentrypointto the Proxmoxdeletelist whencontainer.entrypointis unset. Sincebin/create-container.jsnow always usesbuildLxcEnvConfig(), creating (or later reconfiguring) a container with no user-provided entrypoint will actively remove any entrypoint already present in the cloned template/image config, which differs from the previous behavior (it preserved the existing entrypoint). Consider adding a way to preserve the current Proxmox entrypoint when the user hasn't explicitly overridden it (e.g., an option/parameter tobuildLxcEnvConfig, or reading current config entrypoint in the job scripts and suppressingdelete=entrypointin that case).
if (this.entrypoint && this.entrypoint.trim()) {
config['entrypoint'] = this.entrypoint.trim();
} else {
deleteList.push('entrypoint');
}
- Files reviewed: 2/4 changed files
- Comments generated: 3
Note
Your feedback helps us improve the quality of this feature.
Please use 👍 or 👎 to tell us whether this assessment is correct.
There was a problem hiding this comment.
⚠️ Not ready to approve
create-time configuration can unintentionally wipe image/template-provided env/entrypoint by applying a delete-only LXC config when the DB record omits those fields.
Copilot's findings
- Files reviewed: 2/4 changed files
- Comments generated: 0 new
Note
Your feedback helps us improve the quality of this feature.
Please use 👍 or 👎 to tell us whether this assessment is correct.
|
Addressed the create-time delete concern in 9135847.
Fix: added a
Per your call, I did not add a hard Verified against the real model with a stubbed-Sequelize harness (18 assertions): create-with-empty now yields an empty config (no |
|
Addressed the reconfigure-surprise concern in 086dfcc. Problem: reconfigure uses Compromise (per discussion): at creation, after the template is cloned, read its LXC config and fold its Still configure-time-only: system defaults (from Settings) and NVIDIA defaults are deliberately not persisted — Net effective precedence a container runs with: Implementation:
Verified against the real model with a stubbed-Sequelize harness (17 assertions): template-under-user precedence, entrypoint fallback to template, null handling, and that |
Admin-defined default environment variables were merged into a container's DB record when the container was created. This froze the defaults to their creation-time values and exposed them in the edit UI. Now the container record stores only user-defined env vars. System defaults (from Settings) and NVIDIA GPU defaults are merged in at configure-time, just before the Proxmox API call, with user-defined values taking precedence. - models/container.js: buildLxcEnvConfig() now merges defaults < NVIDIA defaults < user vars; add getSystemDefaultEnvVars(), parseEnvironmentVars(), and nvidiaDefaultEnvVars() helpers. - bin/create-container.js: merge system defaults at configure-time and stop writing merged env/entrypoint back into the DB record. - bin/reconfigure-container.js: merge system defaults on edit so newly added defaults also reach existing containers. - routers/api/v1/containers.js: stop baking NVIDIA defaults into the saved record on create. Closes #349
Move all environment-variable merge logic into Container#buildLxcEnvConfig so there is exactly one place that determines the env to deploy. The method now loads the admin-defined system defaults itself (it became async) and composes them with the NVIDIA and user-defined values: system defaults < NVIDIA defaults < user-defined values Callers in create-container.js and reconfigure-container.js are reduced to a single `await container.buildLxcEnvConfig()` call and no longer load or pass defaults themselves. getSystemDefaultEnvVars, parseEnvironmentVars and nvidiaDefaultEnvVars are now internal helpers of that method.
… the Proxmox env string Addresses PR review: env var keys were only trimmed, so a key containing '=' or NUL (or a non-string/array value) could corrupt the NUL-separated KEY=value blob sent to Proxmox (splitting one var into many, breaking parsing, or stringifying objects to "[object Object]"). Add Container.normalizeEnvVars() as the single definition of a valid env var: input must be a plain object; keys are trimmed and must match a conventional env-var name (no '=', NUL, or whitespace); values are coerced to strings, with null/undefined, objects/arrays, and NUL-containing values dropped. Apply it at every ingest/load point: - getSystemDefaultEnvVars() and parseEnvironmentVars() normalize their output. - API create/update routes serialize user env vars via a shared serializeUserEnvVars() helper that normalizes before persisting. buildLxcEnvConfig can now trust its inputs, so the per-pair guards are dropped.
buildLxcEnvConfig always added env/entrypoint to Proxmox's `delete` list when the container record had no value. On create the container is freshly cloned from a template that may carry its own env/entrypoint, so emitting `delete` actively wiped those template-provided defaults. Add a deleteMissing option (default false). Proxmox's config PUT is a partial update, so omitting a key leaves it untouched: - create-container.js uses the default (false): empty env/entrypoint are omitted, preserving whatever the cloned template provides. - reconfigure-container.js passes deleteMissing:true so clearing the last env var or removing a custom entrypoint still unsets it on the existing container. The reconfigure restart-detection already ignores the `delete` key, so a pure-delete config does not, by itself, trigger a restart.
Reconfigure uses deleteMissing, so any env/entrypoint that exists only on the cloned template (and was never stored on the container) would be unset on the first reconfigure — surprising the user. We can't re-query the template later: templates are mutable Docker refs that may change or disappear, and we don't cache them. Compromise: at creation, after the template is cloned, read its LXC config and fold its env/entrypoint into the container record as if the user had supplied them (precedence: template < user). This guarantees those values persist across future reconfigures without changing API client expectations. System and NVIDIA defaults are deliberately NOT persisted — they remain configure-time-only (merged by buildLxcEnvConfig) so they aren't frozen into the record or exposed as user values in the edit UI. - models/container.js: add Container.parseLxcEnvString() and Container#persistTemplateDefaults(). - bin/create-container.js: call persistTemplateDefaults() with the cloned template's config before building/applying the LXC env config.
086dfcc to
8787537
Compare
cmyers-mieweb
left a comment
There was a problem hiding this comment.
Looks good for merge
Summary
Fixes #349.
Previously, admin-defined default environment variables were merged into a container's database record when the container was created. This had two undesirable effects:
This PR changes the model so that:
Design notes
There are three "default" sources; they are now handled at configure-time instead of being persisted:
Settings.default_container_env_vars(the main subject of the issue).NVIDIA_VISIBLE_DEVICES,NVIDIA_DRIVER_CAPABILITIES) — derived fromnvidiaRequested; previously baked into the saved record on create.container.environmentVarsand need no special server-side handling.Merge precedence (lowest → highest): system defaults < NVIDIA defaults < user-defined values.
Changes
models/container.jsbuildLxcEnvConfig(defaults = {})now merges defaults (+ NVIDIA defaults) under the user-defined vars at configure-time.static getSystemDefaultEnvVars(),parseEnvironmentVars(),nvidiaDefaultEnvVars().bin/create-container.jsbin/reconfigure-container.jsrouters/api/v1/containers.jsVerification
node --checkpasses on all four modified files.deletehandling, user-only persistence) — all assertions passed. (Temp file, not committed; no backend test framework exists in the repo.)Notes / things to confirm in review
envis fully replaced on each apply (viabuildLxcEnvConfig'sdeletehandling), so admin-removed system defaults now correctly disappear from existing containers on the next reconfigure.