Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 82 additions & 0 deletions packages/installer/src/installer/getInstallerPackageData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,9 @@ function getInstallerPackageData(
// Persist critical dappmanager env vars and volume paths across updates
persistDappmanagerSettings(compose, dnpName, isCore);

// Persist critical core env vars and volume paths across updates
persistCoreSettings(compose, dnpName, isCore);

const dockerTimeout = parseTimeoutSeconds(release.manifest.dockerTimeout);

return {
Expand Down Expand Up @@ -197,6 +200,85 @@ export function persistDappmanagerSettings(compose: ComposeEditor, dnpName: stri
}
}

/**
* When updating the core package, certain environment variables and volume
* settings from the currently installed dappmanager compose must be propagated.
* This ensures:
* - DISABLE_HOST_SCRIPTS is present in the core compose environment
* - The /usr/src/dappnode/ volume bind mount uses the correct host path from DAPPNODE_CORE_DIR
*/
export function persistCoreSettings(compose: ComposeEditor, dnpName: string, _isCore: boolean): void {
if (dnpName !== params.coreDnpName) return;

// Read the currently installed dappmanager compose to get env values
let installedDappmanagerCompose: ComposeFileEditor;
try {
installedDappmanagerCompose = new ComposeFileEditor(params.dappmanagerDnpName, true);
} catch (e) {
if (!isNotFoundError(e)) throw e;
logs.info("No installed dappmanager compose found, skipping core settings persistence");
return;
}

const DAPPNODE_CONTAINER_PATH = "/usr/src/dappnode";

// Collect env values from the installed dappmanager compose services
const installedEnvs: Record<string, string> = {};
for (const serviceEditor of Object.values(installedDappmanagerCompose.services())) {
const envs = serviceEditor.getEnvs();
if (envs["DISABLE_HOST_SCRIPTS"] !== undefined && envs["DISABLE_HOST_SCRIPTS"] !== "") {
installedEnvs["DISABLE_HOST_SCRIPTS"] = envs["DISABLE_HOST_SCRIPTS"];
}
if (envs["DAPPNODE_CORE_DIR"] !== undefined && envs["DAPPNODE_CORE_DIR"] !== "") {
installedEnvs["DAPPNODE_CORE_DIR"] = envs["DAPPNODE_CORE_DIR"];
}
}

if (Object.keys(installedEnvs).length === 0) return;

logs.info("Persisting core settings from installed dappmanager compose", installedEnvs);

// Apply persisted envs and volume mapping to new core compose services
for (const serviceEditor of Object.values(compose.services())) {
// Merge DISABLE_HOST_SCRIPTS into the core compose
if (installedEnvs["DISABLE_HOST_SCRIPTS"]) {
serviceEditor.mergeEnvs({ DISABLE_HOST_SCRIPTS: installedEnvs["DISABLE_HOST_SCRIPTS"] });
}

// Remove /etc:/etc volume when DISABLE_HOST_SCRIPTS is enabled.
// This bind mount is not needed when host scripts are disabled and causes
// Docker failures on non-Linux platforms (e.g., macOS) because Docker cannot
// create its internal mountpoints (/etc/hostname, /etc/hosts) inside a bind-mounted /etc
if (installedEnvs["DISABLE_HOST_SCRIPTS"] === "true") {
const service = serviceEditor.get();
if (service.volumes) {
const volumeMappings = parseVolumeMappings(service.volumes);
const filteredVolumes = volumeMappings.filter((vol) => vol.container !== "/etc");
if (filteredVolumes.length !== volumeMappings.length) {
service.volumes = stringifyVolumeMappings(filteredVolumes);
}
}
}

// Update the /usr/src/dappnode/ volume host path to match DAPPNODE_CORE_DIR
if (installedEnvs["DAPPNODE_CORE_DIR"]) {
const dappnodeHostDir = installedEnvs["DAPPNODE_CORE_DIR"];
const service = serviceEditor.get();
if (service.volumes) {
const volumeMappings = parseVolumeMappings(service.volumes);
const updatedVolumes = volumeMappings.map((vol) => {
// Match the volume whose container side is /usr/src/dappnode/
if (vol.container === DAPPNODE_CONTAINER_PATH) {
return { ...vol, host: dappnodeHostDir, name: undefined };
}
return vol;
});
service.volumes = stringifyVolumeMappings(updatedVolumes);
}
}
}
}

/**
* Migrates the user settings from the old service name to the new service name
*
Expand Down
Loading
Loading