Skip to content

Commit

Permalink
ensure requirements in packageInstall and not only on `fetchDnpRequ…
Browse files Browse the repository at this point in the history
…est` (#2054)

* ensure requirements in `packageInstall` and not only on `fetchDnpRequest`

* increase test timeout

* add check type dncore

* skip bypass for testing

* fix linter

* improve error message

* remove bypass install
  • Loading branch information
pablomendezroyo authored Nov 6, 2024
1 parent 63d08cf commit e18ba45
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 2 deletions.
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
68 changes: 68 additions & 0 deletions packages/installer/src/installer/checkInstallRequirements.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
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> {
if (manifest.type === "dncore") return;
const installedPackages = await listPackages();
const packagesRequiredToBeUninstalled = getRequiresUninstallPackages({ manifest, installedPackages });
const requiresCoreUpdate = getRequiresCoreUpdateTo({ manifest, installedPackages });
const requiresDockerUpdate = await getRequiresDockerUpdateTo({ manifest });

const errors: string[] = [];
if (packagesRequiredToBeUninstalled.length > 0)
errors.push(`The following packages must be uninstalled: ${packagesRequiredToBeUninstalled.join(", ")}`);
if (requiresCoreUpdate) errors.push(`Core update required to ${requiresCoreUpdate}`);
if (requiresDockerUpdate) errors.push(`Docker update required to ${requiresDockerUpdate}`);
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 getRequiresCoreUpdateTo({
manifest,
installedPackages
}: {
manifest: Manifest;
installedPackages: InstalledPackageData[];
}): string | null {
const coreVersion = installedPackages.find((dnp) => dnp.dnpName === params.coreDnpName)?.version;
const minDnVersion = manifest.requirements?.minimumDappnodeVersion;

if (!coreVersion || !minDnVersion) return null;

const requiresCoreUpdate = Boolean(valid(minDnVersion) && valid(coreVersion) && gt(minDnVersion, coreVersion));
if (requiresCoreUpdate) return minDnVersion;

return null;
}
async function getRequiresDockerUpdateTo({ manifest }: { manifest: Manifest }): Promise<string | null> {
const minDockerVersion = manifest.requirements?.minimumDockerVersion;
if (!minDockerVersion) return null;
const currentDockerVersion = await getDockerVersion();
const requiresDockerUpdate = Boolean(
minDockerVersion &&
valid(minDockerVersion) &&
valid(currentDockerVersion) &&
gt(minDockerVersion, currentDockerVersion)
);

if (requiresDockerUpdate) return minDockerVersion;
return null;
}
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";
3 changes: 2 additions & 1 deletion packages/schemas/test/unit/validateSchema.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import path from "path";
import { cleanTestDir, testDir } from "../testUtils.js";
import { Manifest, SetupWizard } from "@dappnode/types";

describe("schemaValidation", () => {
describe("schemaValidation", function () {
this.timeout(10000);
describe("manifest", () => {
before(() => {
cleanTestDir();
Expand Down

0 comments on commit e18ba45

Please sign in to comment.