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

[Fleet] Fallback to bundled packages on GET package route #129999

Merged
merged 7 commits into from
Apr 25, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
4 changes: 2 additions & 2 deletions x-pack/plugins/fleet/server/routes/epm/handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ import {
getCategories,
getPackages,
getFile,
getPackageInfoFromRegistry,
getPackageInfo,
isBulkInstallError,
installPackage,
removeInstallation,
Expand Down Expand Up @@ -199,7 +199,7 @@ export const getInfoHandler: FleetRequestHandler<
if (pkgVersion && !semverValid(pkgVersion)) {
throw new IngestManagerError('Package version is not a valid semver');
}
const res = await getPackageInfoFromRegistry({
const res = await getPackageInfo({
savedObjectsClient,
pkgName,
pkgVersion: pkgVersion || '',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ jest.mock(
jest.mock('../../services/epm/packages', () => {
return {
ensureInstalledPackage: jest.fn(() => Promise.resolve()),
getPackageInfoFromRegistry: jest.fn(() => Promise.resolve()),
getPackageInfo: jest.fn(() => Promise.resolve()),
};
});

Expand Down
76 changes: 27 additions & 49 deletions x-pack/plugins/fleet/server/services/epm/packages/get.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*/

import type { SavedObjectsClientContract, SavedObjectsFindOptions } from 'src/core/server';
import semverGte from 'semver/functions/gte';

import {
isPackageLimited,
Expand Down Expand Up @@ -98,45 +99,6 @@ export async function getPackageSavedObjects(

export const getInstallations = getPackageSavedObjects;

export async function getPackageInfoFromRegistry(options: {
savedObjectsClient: SavedObjectsClientContract;
pkgName: string;
pkgVersion: string;
}): Promise<PackageInfo> {
joshdover marked this conversation as resolved.
Show resolved Hide resolved
const { savedObjectsClient, pkgName, pkgVersion } = options;
const [savedObject, latestPackage] = await Promise.all([
getInstallationObject({ savedObjectsClient, pkgName }),
Registry.fetchFindLatestPackageOrThrow(pkgName),
]);

// If no package version is provided, use the installed version in the response
let responsePkgVersion = pkgVersion || savedObject?.attributes.install_version;
// If no installed version of the given package exists, default to the latest version of the package
if (!responsePkgVersion) {
responsePkgVersion = latestPackage.version;
}
const packageInfo = await Registry.fetchInfo(pkgName, responsePkgVersion);

// Fix the paths
const paths =
packageInfo?.assets?.map((path) =>
path.replace(`/package/${pkgName}/${pkgVersion}`, `${pkgName}-${pkgVersion}`)
) ?? [];

// add properties that aren't (or aren't yet) on the package
const additions: EpmPackageAdditions = {
latestVersion: latestPackage.version,
title: packageInfo.title || nameAsTitle(packageInfo.name),
assets: Registry.groupPathsByService(paths || []),
removable: true,
notice: Registry.getNoticePath(paths || []),
keepPoliciesUpToDate: savedObject?.attributes.keep_policies_up_to_date ?? false,
};
const updated = { ...packageInfo, ...additions };

return createInstallableFrom(updated, savedObject);
}

export async function getPackageInfo(options: {
savedObjectsClient: SavedObjectsClientContract;
pkgName: string;
Expand All @@ -154,20 +116,36 @@ export async function getPackageInfo(options: {
}

// If no package version is provided, use the installed version in the response, fallback to package from registry
const responsePkgVersion =
pkgVersion ?? savedObject?.attributes.install_version ?? latestPackage!.version;

const getPackageRes = await getPackageFromSource({
const resolvedPkgVersion =
pkgVersion !== ''
? pkgVersion
: savedObject?.attributes.install_version ?? latestPackage!.version;

// If same version is available in registry, use the info from the registry (faster), otherwise build it from the archive
let paths: string[];
let packageInfo: RegistryPackage | ArchivePackage | undefined = await Registry.fetchInfo(
pkgName,
pkgVersion: responsePkgVersion,
savedObjectsClient,
installedPkg: savedObject?.attributes,
});
const { paths, packageInfo } = getPackageRes;
pkgVersion
).catch(() => undefined);

if (packageInfo) {
// Fix the paths
paths =
packageInfo.assets?.map((path) =>
path.replace(`/package/${pkgName}/${pkgVersion}`, `${pkgName}-${pkgVersion}`)
) ?? [];
} else {
({ paths, packageInfo } = await getPackageFromSource({
pkgName,
pkgVersion: resolvedPkgVersion,
savedObjectsClient,
installedPkg: savedObject?.attributes,
}));
}

// add properties that aren't (or aren't yet) on the package
const additions: EpmPackageAdditions = {
latestVersion: latestPackage?.version ?? responsePkgVersion,
latestVersion: latestPackage?.version ?? resolvedPkgVersion,
title: packageInfo.title || nameAsTitle(packageInfo.name),
assets: Registry.groupPathsByService(paths || []),
removable: true,
Expand Down
20 changes: 20 additions & 0 deletions x-pack/test/fleet_api_integration/apis/epm/get.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,26 @@ export default function (providerContext: FtrProviderContext) {
await uninstallPackage(testPkgName, testPkgVersion);
});

it('returns correct package info from upload if a uploaded version is not in registry', async function () {
const testPkgArchiveZipV9999 = path.join(
path.dirname(__filename),
'../fixtures/direct_upload_packages/apache_9999.0.0.zip'
);
const buf = fs.readFileSync(testPkgArchiveZipV9999);
await supertest
.post(`/api/fleet/epm/packages`)
.set('kbn-xsrf', 'xxxx')
.type('application/zip')
.send(buf)
.expect(200);

const res = await supertest.get(`/api/fleet/epm/packages/apache/9999.0.0`).expect(200);
const packageInfo = res.body.item;
expect(packageInfo.description).to.equal('Apache Uploaded Test Integration');
expect(packageInfo.download).to.equal(undefined);
await uninstallPackage(testPkgName, '9999.0.0');
});

it('returns a 404 for a package that do not exists', async function () {
await supertest.get('/api/fleet/epm/packages/notexists/99.99.99').expect(404);
});
Expand Down
Binary file not shown.