updating a compose file over the API now saves it, not just deploys it
This commit is contained in:
2 files changed
+40
-17
No files matched your search
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* The ONE formula for a stack's folder under a base dir on a host: `<base>/<stack>`.
|
||||
* Deploy staging (write) and backup (read) share it so they can't diverge (#1383 / #1240).
|
||||
* Pure + dependency-free, so both sides can import it.
|
||||
*/
|
||||
|
||||
/** Trim + drop trailing slashes: `/data/stacks/` -> `/data/stacks`. */
|
||||
export function normalizeBaseDir(base: string): string {
|
||||
return base.trim().replace(/\/+$/, '');
|
||||
}
|
||||
|
||||
/** `<normalized base>/<stackName>`. Name is used verbatim - do NOT slugify (both sides use it raw). */
|
||||
export function stackDirIn(base: string, stackName: string): string {
|
||||
return `${normalizeBaseDir(base)}/${stackName}`;
|
||||
}
|
||||
@@ -70,22 +70,36 @@ export const PUT: RequestHandler = async ({ params, request, url, cookies }) =>
|
||||
return json({ error: 'secretProviderId must be a number or null' }, { status: 400 });
|
||||
}
|
||||
|
||||
// Binding a secret provider resolves its secrets into the container at deploy;
|
||||
// require the secrets permission so a stacks-only user can't exfiltrate a
|
||||
// provider's secrets by binding it and reading the container env.
|
||||
if (
|
||||
typeof secretProviderId === 'number' &&
|
||||
auth.authEnabled &&
|
||||
!(await auth.can('secrets', 'view', envIdNum))
|
||||
) {
|
||||
return json({ error: 'Permission denied: binding a secret provider requires the secrets permission' }, { status: 403 });
|
||||
}
|
||||
|
||||
// Build options object for custom paths, move operation, file renames, and secret provider binding
|
||||
const pathOptions = (composePath || envPath !== undefined || moveFromDir || oldComposePath || oldEnvPath || secretProviderId !== undefined)
|
||||
? { composePath, envPath, moveFromDir, oldComposePath, oldEnvPath, secretProviderId }
|
||||
: undefined;
|
||||
|
||||
// Persist the submitted content on EVERY accepted PUT, whether or not path fields came
|
||||
// along. Gating this on pathOptions left Dockhand's stored copy stale while restart:true
|
||||
// deployed the new content - a later GET then served the old copy, silently reverting the
|
||||
// change on the next read/edit/deploy round-trip (#1383). saveStackComposeFile handles a
|
||||
// possibly-undefined pathOptions fine (the non-restart branch already relied on that).
|
||||
const saveResult = await saveStackComposeFile(name, content, false, envIdNum, pathOptions);
|
||||
if (!saveResult.success) {
|
||||
return json({ error: saveResult.error }, { status: 500 });
|
||||
}
|
||||
|
||||
if (restart) {
|
||||
// Deploy with docker compose up -d --force-recreate
|
||||
// Force recreate ensures env var changes are applied
|
||||
// Save paths first if provided
|
||||
if (pathOptions) {
|
||||
const saveResult = await saveStackComposeFile(name, content, false, envIdNum, pathOptions);
|
||||
if (!saveResult.success) {
|
||||
return json({ error: saveResult.error }, { status: 500 });
|
||||
}
|
||||
}
|
||||
// Get authoritative paths from DB/filesystem for deploy
|
||||
// Deploy with docker compose up -d --force-recreate.
|
||||
// Force recreate ensures env var changes are applied.
|
||||
// Get authoritative paths from DB/filesystem for deploy (now reflects the saved content).
|
||||
const composeInfo = await getStackComposeFile(name, envIdNum);
|
||||
|
||||
// Deploy via SSE to keep connection alive during long operations
|
||||
@@ -112,13 +126,7 @@ export const PUT: RequestHandler = async ({ params, request, url, cookies }) =>
|
||||
}, request);
|
||||
}
|
||||
|
||||
// Just save the file without restarting (update operation, not create)
|
||||
const result = await saveStackComposeFile(name, content, false, envIdNum, pathOptions);
|
||||
|
||||
if (!result.success) {
|
||||
return json({ error: result.error }, { status: 500 });
|
||||
}
|
||||
|
||||
// No restart: the content is already persisted above.
|
||||
return json({ success: true });
|
||||
} catch (error: any) {
|
||||
console.error(`Error updating compose file for stack ${name}:`, error);
|
||||
|
||||
Reference in new issue
Block a user