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

[Ingest Manager] Install uploaded package #77986

Merged
merged 29 commits into from
Oct 5, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
0766159
Refactor: installPackage -> installPackageFromRegistry
skh Sep 21, 2020
6553615
Refactor: factor out source-agnostic installation steps
skh Sep 21, 2020
d5d8dc8
Unpack and cache uploaded zip and tgz files.
skh Sep 22, 2020
d771646
Add basic archive verification and parse manifest.
skh Sep 23, 2020
afa4fcb
Catch error when zip archive is uploaded as gzip.
skh Sep 23, 2020
ca862b0
Add API integration tests.
skh Sep 23, 2020
95e22da
Remove unnecessary use of "package key" concept.
skh Sep 23, 2020
157550c
Add 'install_source' property to saved object epm-packages.
skh Sep 23, 2020
954a89d
Adjust tests.
skh Sep 23, 2020
34d0475
Add API integration test for manifest missing fields.
skh Sep 24, 2020
5284953
Refactor loadArchive -> loadArchivePackage.
skh Sep 24, 2020
0a7cf16
Refactor caching of package archive content
skh Sep 24, 2020
a92d3b3
Get datasets and config templates from manifest files.
skh Sep 28, 2020
c1d97fe
Use file paths from archive instead of asset paths from registry.
skh Sep 29, 2020
bdfec89
Correctly load registry packages into cache
skh Sep 29, 2020
69950cd
Use InstallablePackage instead of RegistryPackage where possible.
skh Sep 29, 2020
e854936
Actually install uploaded package.
skh Sep 30, 2020
f54e3a2
Add missing field to saved objects in tests.
skh Sep 30, 2020
2c30b69
Adjust unit test to pick buffer extractor.
skh Sep 30, 2020
523d8dc
Adjust unit test.
skh Sep 30, 2020
ff2006f
Fix and re-enable getAsset() test.
skh Oct 5, 2020
6169a64
Adjust integration tests.
skh Oct 5, 2020
9fcdc83
Make error message match test.
skh Oct 5, 2020
014b56f
Pick data_stream.dataset from manifest if set.
skh Oct 5, 2020
c91c151
dataset -> data_stream also in comments
skh Oct 5, 2020
d2fef88
Remove unused variable.
skh Oct 5, 2020
df23d82
Use pkgToPkgKey() where appropriate.
skh Oct 5, 2020
f134573
More dataset -> data stream renaming.
skh Oct 5, 2020
7959736
Merge branch 'master' into 70582-direct-package-upload-part-2
kibanamachine Oct 5, 2020
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
20 changes: 15 additions & 5 deletions x-pack/plugins/ingest_manager/common/types/models/epm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export enum InstallStatus {
}

export type InstallType = 'reinstall' | 'reupdate' | 'rollback' | 'update' | 'install';
export type InstallSource = 'registry' | 'upload';

export type EpmPackageInstallStatus = 'installed' | 'installing';

Expand Down Expand Up @@ -49,10 +50,8 @@ export enum AgentAssetType {

export type RegistryRelease = 'ga' | 'beta' | 'experimental';

// from /package/{name}
// type Package struct at https://github.com/elastic/package-registry/blob/master/util/package.go
// https://github.com/elastic/package-registry/blob/master/docs/api/package.json
export interface RegistryPackage {
// Fields common to packages that come from direct upload and the registry
export interface InstallablePackage {
name: string;
title?: string;
version: string;
Expand All @@ -61,14 +60,24 @@ export interface RegistryPackage {
description: string;
type: string;
categories: string[];
requirement: RequirementsByServiceName;
screenshots?: RegistryImage[];
icons?: RegistryImage[];
assets?: string[];
internal?: boolean;
format_version: string;
data_streams?: RegistryDataStream[];
policy_templates?: RegistryPolicyTemplate[];
}

// Uploaded package archives don't have extra fields
// Linter complaint disabled because this extra type is meant for better code readability
// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface ArchivePackage extends InstallablePackage {}

// Registry packages do have extra fields.
// cf. type Package struct at https://github.com/elastic/package-registry/blob/master/util/package.go
export interface RegistryPackage extends InstallablePackage {
requirement: RequirementsByServiceName;
skh marked this conversation as resolved.
Show resolved Hide resolved
download: string;
path: string;
}
Expand Down Expand Up @@ -240,6 +249,7 @@ export interface Installation extends SavedObjectAttributes {
install_status: EpmPackageInstallStatus;
install_version: string;
install_started_at: string;
install_source: InstallSource;
}

export type Installable<T> = Installed<T> | NotInstalled<T>;
Expand Down
20 changes: 20 additions & 0 deletions x-pack/plugins/ingest_manager/server/errors/handlers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
IngestManagerError,
RegistryError,
PackageNotFoundError,
PackageUnsupportedMediaTypeError,
defaultIngestErrorHandler,
} from './index';

Expand Down Expand Up @@ -101,6 +102,25 @@ describe('defaultIngestErrorHandler', () => {
expect(mockContract.logger?.error).toHaveBeenCalledWith(error.message);
});

it('415: PackageUnsupportedMediaType', async () => {
const error = new PackageUnsupportedMediaTypeError('123');
const response = httpServerMock.createResponseFactory();

await defaultIngestErrorHandler({ error, response });

// response
expect(response.ok).toHaveBeenCalledTimes(0);
expect(response.customError).toHaveBeenCalledTimes(1);
expect(response.customError).toHaveBeenCalledWith({
statusCode: 415,
body: { message: error.message },
});

// logging
expect(mockContract.logger?.error).toHaveBeenCalledTimes(1);
expect(mockContract.logger?.error).toHaveBeenCalledWith(error.message);
});

it('404: PackageNotFoundError', async () => {
const error = new PackageNotFoundError('123');
const response = httpServerMock.createResponseFactory();
Expand Down
10 changes: 9 additions & 1 deletion x-pack/plugins/ingest_manager/server/errors/handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,12 @@ import {
} from 'src/core/server';
import { errors as LegacyESErrors } from 'elasticsearch';
import { appContextService } from '../services';
import { IngestManagerError, RegistryError, PackageNotFoundError } from './index';
import {
IngestManagerError,
RegistryError,
PackageNotFoundError,
PackageUnsupportedMediaTypeError,
} from './index';

type IngestErrorHandler = (
params: IngestErrorHandlerParams
Expand Down Expand Up @@ -52,6 +57,9 @@ const getHTTPResponseCode = (error: IngestManagerError): number => {
if (error instanceof PackageNotFoundError) {
return 404; // Not Found
}
if (error instanceof PackageUnsupportedMediaTypeError) {
return 415; // Unsupported Media Type
}

return 400; // Bad Request
};
Expand Down
4 changes: 4 additions & 0 deletions x-pack/plugins/ingest_manager/server/errors/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,7 @@ export class RegistryConnectionError extends RegistryError {}
export class RegistryResponseError extends RegistryError {}
export class PackageNotFoundError extends IngestManagerError {}
export class PackageOutdatedError extends IngestManagerError {}
export class PackageUnsupportedMediaTypeError extends IngestManagerError {}
export class PackageInvalidArchiveError extends IngestManagerError {}
export class PackageCacheError extends IngestManagerError {}
export class PackageOperationNotSupportedError extends IngestManagerError {}
28 changes: 21 additions & 7 deletions x-pack/plugins/ingest_manager/server/routes/epm/handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import { RequestHandler, CustomHttpResponseOptions } from 'src/core/server';
import {
GetInfoResponse,
InstallPackageResponse,
MessageResponse,
DeletePackageResponse,
GetCategoriesResponse,
GetPackagesResponse,
Expand All @@ -35,8 +34,9 @@ import {
getFile,
getPackageInfo,
handleInstallPackageFailure,
installPackage,
isBulkInstallError,
installPackageFromRegistry,
installPackageByUpload,
removeInstallation,
getLimitedPackages,
getInstallationObject,
Expand Down Expand Up @@ -148,7 +148,7 @@ export const installPackageFromRegistryHandler: RequestHandler<
const { pkgName, pkgVersion } = splitPkgKey(pkgkey);
const installedPkg = await getInstallationObject({ savedObjectsClient, pkgName });
try {
const res = await installPackage({
const res = await installPackageFromRegistry({
savedObjectsClient,
pkgkey,
callCluster,
Expand Down Expand Up @@ -212,10 +212,24 @@ export const installPackageByUploadHandler: RequestHandler<
undefined,
TypeOf<typeof InstallPackageByUploadRequestSchema.body>
> = async (context, request, response) => {
const body: MessageResponse = {
response: 'package upload was received ok, but not installed (not implemented yet)',
};
return response.ok({ body });
const savedObjectsClient = context.core.savedObjects.client;
const callCluster = context.core.elasticsearch.legacy.client.callAsCurrentUser;
const contentType = request.headers['content-type'] as string; // from types it could also be string[] or undefined but this is checked later
const archiveBuffer = Buffer.from(request.body);
try {
const res = await installPackageByUpload({
savedObjectsClient,
callCluster,
archiveBuffer,
contentType,
});
const body: InstallPackageResponse = {
response: res,
};
return response.ok({ body });
} catch (error) {
return defaultIngestErrorHandler({ error, response });
}
};

export const deletePackageHandler: RequestHandler<TypeOf<
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,7 @@ const getSavedObjectTypes = (
install_started_at: { type: 'date' },
install_version: { type: 'keyword' },
install_status: { type: 'keyword' },
install_source: { type: 'keyword' },
},
},
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
EnrollmentAPIKey,
Settings,
AgentAction,
Installation,
} from '../../types';

export const migrateAgentToV7100: SavedObjectMigrationFn<
Expand Down Expand Up @@ -134,3 +135,12 @@ export const migrateAgentActionToV7100 = (
}
);
};

export const migrateInstallationToV7100: SavedObjectMigrationFn<
skh marked this conversation as resolved.
Show resolved Hide resolved
Exclude<Installation, 'install_source'>,
Installation
> = (installationDoc) => {
installationDoc.attributes.install_source = 'registry';

return installationDoc;
};
Loading