Skip to content

Commit

Permalink
[Fleet] update getPackageInfo to handle uploaded packages (#83854) (#…
Browse files Browse the repository at this point in the history
…83965)

* update getPackgeInfo handler to fetch from install source

* add tests and modify fixtures  to distinguish between registry and uploaded package

* improve error handling

* fix type

* fix test

* remove try/catch

* fix zip file test to have the right number of assets

* fix compressed files
  • Loading branch information
neptunian authored Nov 20, 2020
1 parent a4b9d1e commit d615b70
Show file tree
Hide file tree
Showing 7 changed files with 120 additions and 17 deletions.
19 changes: 13 additions & 6 deletions x-pack/plugins/fleet/common/types/models/epm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -252,12 +252,19 @@ export type PackageList = PackageListItem[];

export type PackageListItem = Installable<RegistrySearchResult>;
export type PackagesGroupedByStatus = Record<ValueOf<InstallationStatus>, PackageList>;
export type PackageInfo = Installable<
// remove the properties we'll be altering/replacing from the base type
Omit<RegistryPackage, keyof PackageAdditions> &
// now add our replacement definitions
PackageAdditions
>;
export type PackageInfo =
| Installable<
// remove the properties we'll be altering/replacing from the base type
Omit<RegistryPackage, keyof PackageAdditions> &
// now add our replacement definitions
PackageAdditions
>
| Installable<
// remove the properties we'll be altering/replacing from the base type
Omit<ArchivePackage, keyof PackageAdditions> &
// now add our replacement definitions
PackageAdditions
>;

export interface Installation extends SavedObjectAttributes {
installed_kibana: KibanaAssetReference[];
Expand Down
12 changes: 10 additions & 2 deletions x-pack/plugins/fleet/server/services/epm/archive/cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@ export interface SharedKey {
}
type SharedKeyString = string;

type ArchiveFilelist = string[];
const archiveFilelistCache: Map<SharedKeyString, ArchiveFilelist> = new Map();
const archiveFilelistCache: Map<SharedKeyString, string[]> = new Map();
export const getArchiveFilelist = (keyArgs: SharedKey) =>
archiveFilelistCache.get(sharedKey(keyArgs));

Expand All @@ -46,6 +45,15 @@ export const getPackageInfo = (args: SharedKey) => {
}
};

export const getArchivePackage = (args: SharedKey) => {
const packageInfo = getPackageInfo(args);
const paths = getArchiveFilelist(args);
return {
paths,
packageInfo,
};
};

export const setPackageInfo = ({
name,
version,
Expand Down
45 changes: 38 additions & 7 deletions x-pack/plugins/fleet/server/services/epm/packages/get.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@
import { SavedObjectsClientContract, SavedObjectsFindOptions } from 'src/core/server';
import { isPackageLimited, installationStatuses } from '../../../../common';
import { PACKAGES_SAVED_OBJECT_TYPE } from '../../../constants';
import { ValueOf } from '../../../../common/types';
import { ArchivePackage, InstallSource, RegistryPackage, ValueOf } from '../../../../common/types';
import { Installation, InstallationStatus, PackageInfo, KibanaAssetType } from '../../../types';
import * as Registry from '../registry';
import { createInstallableFrom, isRequiredPackage } from './index';
import { getArchivePackage } from '../archive';

export { fetchFile as getFile, SearchParams } from '../registry';

Expand Down Expand Up @@ -109,23 +110,53 @@ export async function getPackageInfo(options: {
pkgVersion: string;
}): Promise<PackageInfo> {
const { savedObjectsClient, pkgName, pkgVersion } = options;
const [savedObject, latestPackage, { paths: assets, packageInfo: item }] = await Promise.all([
const [savedObject, latestPackage] = await Promise.all([
getInstallationObject({ savedObjectsClient, pkgName }),
Registry.fetchFindLatestPackage(pkgName),
Registry.getRegistryPackage(pkgName, pkgVersion),
]);

// add properties that aren't (or aren't yet) on Registry response
const getPackageRes = await getPackageFromSource({
pkgName,
pkgVersion,
pkgInstallSource: savedObject?.attributes.install_source,
});
const paths = getPackageRes.paths;
const packageInfo = getPackageRes.packageInfo;

// add properties that aren't (or aren't yet) on the package
const updated = {
...item,
...packageInfo,
latestVersion: latestPackage.version,
title: item.title || nameAsTitle(item.name),
assets: Registry.groupPathsByService(assets || []),
title: packageInfo.title || nameAsTitle(packageInfo.name),
assets: Registry.groupPathsByService(paths || []),
removable: !isRequiredPackage(pkgName),
};
return createInstallableFrom(updated, savedObject);
}

// gets package from install_source if it exists otherwise gets from registry
export async function getPackageFromSource(options: {
pkgName: string;
pkgVersion: string;
pkgInstallSource?: InstallSource;
}): Promise<{ paths: string[] | undefined; packageInfo: RegistryPackage | ArchivePackage }> {
const { pkgName, pkgVersion, pkgInstallSource } = options;
// TODO: Check package storage before checking registry
let res;
if (pkgInstallSource === 'upload') {
res = getArchivePackage({
name: pkgName,
version: pkgVersion,
installSource: pkgInstallSource,
});
if (!res.packageInfo)
throw new Error(`installed package ${pkgName}-${pkgVersion} does not exist in cache`);
} else {
res = await Registry.getRegistryPackage(pkgName, pkgVersion);
}
return res;
}

export async function getInstallationObject(options: {
savedObjectsClient: SavedObjectsClientContract;
pkgName: string;
Expand Down
59 changes: 58 additions & 1 deletion x-pack/test/fleet_api_integration/apis/epm/get.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,73 @@
* you may not use this file except in compliance with the Elastic License.
*/

import expect from '@kbn/expect';
import fs from 'fs';
import path from 'path';
import { FtrProviderContext } from '../../../api_integration/ftr_provider_context';
import { warnAndSkipTest } from '../../helpers';

export default function ({ getService }: FtrProviderContext) {
export default function (providerContext: FtrProviderContext) {
const { getService } = providerContext;
const log = getService('log');
const supertest = getService('supertest');
const dockerServers = getService('dockerServers');
const server = dockerServers.get('registry');

const testPkgKey = 'apache-0.1.4';

const uninstallPackage = async (pkg: string) => {
await supertest.delete(`/api/fleet/epm/packages/${pkg}`).set('kbn-xsrf', 'xxxx');
};
const installPackage = async (pkg: string) => {
await supertest
.post(`/api/fleet/epm/packages/${pkg}`)
.set('kbn-xsrf', 'xxxx')
.send({ force: true });
};

const testPkgArchiveZip = path.join(
path.dirname(__filename),
'../fixtures/direct_upload_packages/apache_0.1.4.zip'
);

describe('EPM - get', () => {
it('returns package info from the registry if it was installed from the registry', async function () {
if (server.enabled) {
// this will install through the registry by default
await installPackage(testPkgKey);
const res = await supertest.get(`/api/fleet/epm/packages/${testPkgKey}`).expect(200);
const packageInfo = res.body.response;
// the uploaded version will have this description
expect(packageInfo.description).to.not.equal('Apache Uploaded Test Integration');
// download property should exist
expect(packageInfo.download).to.not.equal(undefined);
await uninstallPackage(testPkgKey);
} else {
warnAndSkipTest(this, log);
}
});
it('returns correct package info if it was installed by upload', async function () {
if (server.enabled) {
const buf = fs.readFileSync(testPkgArchiveZip);
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/${testPkgKey}`).expect(200);
const packageInfo = res.body.response;
// the uploaded version will have this description
expect(packageInfo.description).to.equal('Apache Uploaded Test Integration');
// download property should not exist on uploaded packages
expect(packageInfo.download).to.equal(undefined);
await uninstallPackage(testPkgKey);
} else {
warnAndSkipTest(this, log);
}
});
it('returns a 500 for a package key without a proper name', async function () {
if (server.enabled) {
await supertest.get('/api/fleet/epm/packages/-0.1.0').expect(500);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ export default function (providerContext: FtrProviderContext) {
.type('application/zip')
.send(buf)
.expect(200);
expect(res.body.response.length).to.be(18);
expect(res.body.response.length).to.be(23);
});

it('should throw an error if the archive is zip but content type is gzip', async function () {
Expand Down
Binary file not shown.
Binary file not shown.

0 comments on commit d615b70

Please sign in to comment.