Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ensure requirements in packageInstall and not only on fetchDnpRequest #2054

Merged
merged 8 commits into from
Nov 6, 2024
Merged
4 changes: 3 additions & 1 deletion packages/installer/src/calls/packageInstall.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ import {
rollbackPackages,
writeAndValidateFiles,
postInstallClean,
afterInstall
afterInstall,
checkInstallRequirements
} from "../installer/index.js";
import { logs, getLogUi, logUiClear } from "@dappnode/logger";
import { Routes } from "@dappnode/types";
Expand Down Expand Up @@ -53,6 +54,7 @@ export async function packageInstall(
if (!release.signedSafe && !options.BYPASS_SIGNED_RESTRICTION) {
throw Error(`Package ${release.dnpName} is from untrusted origin and is not signed`);
}
if (!release.isCore) await checkInstallRequirements({ manifest: release.manifest });
}

// Gather all data necessary for the install
Expand Down
60 changes: 60 additions & 0 deletions packages/installer/src/installer/checkInstallRequirements.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { listPackages, getDockerVersion } from "@dappnode/dockerapi";
import { params } from "@dappnode/params";
import { Manifest, InstalledPackageData } from "@dappnode/types";
import { valid, gt } from "semver";

/**
* Get the install requirements and throw an error if they are not met
*/
export async function checkInstallRequirements({ manifest }: { manifest: Manifest }): Promise<void> {
const installedPackages = await listPackages();
const packagesRequiredToBeUninstalled = getRequiresUninstallPackages({ manifest, installedPackages });
const requiresCoreUpdate = getRequiresCoreUpdate({ manifest, installedPackages });
const requiresDockerUpdate = await getRequiresDockerUpdate({ manifest });

const errors: string[] = [];
if (packagesRequiredToBeUninstalled.length > 0)
errors.push(`The following packages must be uninstalled: ${packagesRequiredToBeUninstalled.join(", ")}`);
if (requiresCoreUpdate) errors.push("The core package must be updated");
if (requiresDockerUpdate) errors.push("Docker must be updated");
if (errors.length > 0)
throw new Error(`The package cannot be installed because of the following requirements:
${errors.join("\n")}`);
}

function getRequiresUninstallPackages({
manifest,
installedPackages
}: {
manifest: Manifest;
installedPackages: InstalledPackageData[];
}): string[] {
const { notInstalledPackages } = manifest.requirements || {};
if (!notInstalledPackages || notInstalledPackages.length === 0) return [];
return notInstalledPackages.filter((dnpName) => installedPackages.find((dnp) => dnp.dnpName === dnpName));
}

function getRequiresCoreUpdate({
manifest,
installedPackages
}: {
manifest: Manifest;
installedPackages: InstalledPackageData[];
}): boolean {
const coreDnp = installedPackages.find((dnp) => dnp.dnpName === params.coreDnpName);
if (!coreDnp) return false;
const coreVersion = coreDnp.version;
const minDnVersion = manifest.requirements ? manifest.requirements.minimumDappnodeVersion : "";
return Boolean(minDnVersion && valid(minDnVersion) && valid(coreVersion) && gt(minDnVersion, coreVersion));
}
async function getRequiresDockerUpdate({ manifest }: { manifest: Manifest }): Promise<boolean> {
const minDockerVersion = manifest.requirements?.minimumDockerVersion;
if (!minDockerVersion) return false;
const currentDockerVersion = await getDockerVersion();
return Boolean(
minDockerVersion &&
valid(minDockerVersion) &&
valid(currentDockerVersion) &&
gt(minDockerVersion, currentDockerVersion)
);
}
1 change: 1 addition & 0 deletions packages/installer/src/installer/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ export * from "./rollbackPackages.js";
export * from "./runPackages.js";
export * from "./restartPatch.js";
export * from "./writeAndValidateFiles.js";
export * from "./checkInstallRequirements.js";
Loading