diff --git a/x-pack/plugins/ingest_manager/common/constants/routes.ts b/x-pack/plugins/ingest_manager/common/constants/routes.ts index 551a0f7d60164..3e065142ea101 100644 --- a/x-pack/plugins/ingest_manager/common/constants/routes.ts +++ b/x-pack/plugins/ingest_manager/common/constants/routes.ts @@ -21,7 +21,8 @@ export const EPM_API_ROUTES = { LIST_PATTERN: EPM_PACKAGES_MANY, LIMITED_LIST_PATTERN: `${EPM_PACKAGES_MANY}/limited`, INFO_PATTERN: EPM_PACKAGES_ONE, - INSTALL_PATTERN: EPM_PACKAGES_ONE, + INSTALL_FROM_REGISTRY_PATTERN: EPM_PACKAGES_ONE, + INSTALL_BY_UPLOAD_PATTERN: EPM_PACKAGES_MANY, DELETE_PATTERN: EPM_PACKAGES_ONE, FILEPATH_PATTERN: `${EPM_PACKAGES_FILE}/{filePath*}`, CATEGORIES_PATTERN: `${EPM_API_ROOT}/categories`, diff --git a/x-pack/plugins/ingest_manager/common/services/routes.ts b/x-pack/plugins/ingest_manager/common/services/routes.ts index 1d802739a1b86..b7521f95b4f83 100644 --- a/x-pack/plugins/ingest_manager/common/services/routes.ts +++ b/x-pack/plugins/ingest_manager/common/services/routes.ts @@ -40,7 +40,10 @@ export const epmRouteService = { }, getInstallPath: (pkgkey: string) => { - return EPM_API_ROUTES.INSTALL_PATTERN.replace('{pkgkey}', pkgkey).replace(/\/$/, ''); // trim trailing slash + return EPM_API_ROUTES.INSTALL_FROM_REGISTRY_PATTERN.replace('{pkgkey}', pkgkey).replace( + /\/$/, + '' + ); // trim trailing slash }, getRemovePath: (pkgkey: string) => { diff --git a/x-pack/plugins/ingest_manager/common/types/rest_spec/epm.ts b/x-pack/plugins/ingest_manager/common/types/rest_spec/epm.ts index 5fb718f91b876..54e767fee4b22 100644 --- a/x-pack/plugins/ingest_manager/common/types/rest_spec/epm.ts +++ b/x-pack/plugins/ingest_manager/common/types/rest_spec/epm.ts @@ -71,6 +71,10 @@ export interface InstallPackageResponse { response: AssetReference[]; } +export interface MessageResponse { + response: string; +} + export interface DeletePackageRequest { params: { pkgkey: string; diff --git a/x-pack/plugins/ingest_manager/server/routes/epm/handlers.ts b/x-pack/plugins/ingest_manager/server/routes/epm/handlers.ts index 385e256933c12..c40e0e4ac5c0b 100644 --- a/x-pack/plugins/ingest_manager/server/routes/epm/handlers.ts +++ b/x-pack/plugins/ingest_manager/server/routes/epm/handlers.ts @@ -9,6 +9,7 @@ import { appContextService } from '../../services'; import { GetInfoResponse, InstallPackageResponse, + MessageResponse, DeletePackageResponse, GetCategoriesResponse, GetPackagesResponse, @@ -19,7 +20,8 @@ import { GetPackagesRequestSchema, GetFileRequestSchema, GetInfoRequestSchema, - InstallPackageRequestSchema, + InstallPackageFromRegistryRequestSchema, + InstallPackageByUploadRequestSchema, DeletePackageRequestSchema, } from '../../types'; import { @@ -129,10 +131,10 @@ export const getInfoHandler: RequestHandler, +export const installPackageFromRegistryHandler: RequestHandler< + TypeOf, undefined, - TypeOf + TypeOf > = async (context, request, response) => { const logger = appContextService.getLogger(); const savedObjectsClient = context.core.savedObjects.client; @@ -183,6 +185,17 @@ export const installPackageHandler: RequestHandler< } }; +export const installPackageByUploadHandler: RequestHandler< + undefined, + undefined, + TypeOf +> = async (context, request, response) => { + const body: MessageResponse = { + response: 'package upload was received ok, but not installed (not implemented yet)', + }; + return response.ok({ body }); +}; + export const deletePackageHandler: RequestHandler> = async (context, request, response) => { diff --git a/x-pack/plugins/ingest_manager/server/routes/epm/index.ts b/x-pack/plugins/ingest_manager/server/routes/epm/index.ts index b524a7b33923e..9048652f0e8a9 100644 --- a/x-pack/plugins/ingest_manager/server/routes/epm/index.ts +++ b/x-pack/plugins/ingest_manager/server/routes/epm/index.ts @@ -11,7 +11,8 @@ import { getLimitedListHandler, getFileHandler, getInfoHandler, - installPackageHandler, + installPackageFromRegistryHandler, + installPackageByUploadHandler, deletePackageHandler, } from './handlers'; import { @@ -19,10 +20,13 @@ import { GetPackagesRequestSchema, GetFileRequestSchema, GetInfoRequestSchema, - InstallPackageRequestSchema, + InstallPackageFromRegistryRequestSchema, + InstallPackageByUploadRequestSchema, DeletePackageRequestSchema, } from '../../types'; +const MAX_FILE_SIZE_BYTES = 104857600; // 100MB + export const registerRoutes = (router: IRouter) => { router.get( { @@ -71,11 +75,27 @@ export const registerRoutes = (router: IRouter) => { router.post( { - path: EPM_API_ROUTES.INSTALL_PATTERN, - validate: InstallPackageRequestSchema, + path: EPM_API_ROUTES.INSTALL_FROM_REGISTRY_PATTERN, + validate: InstallPackageFromRegistryRequestSchema, options: { tags: [`access:${PLUGIN_ID}-all`] }, }, - installPackageHandler + installPackageFromRegistryHandler + ); + + router.post( + { + path: EPM_API_ROUTES.INSTALL_BY_UPLOAD_PATTERN, + validate: InstallPackageByUploadRequestSchema, + options: { + tags: [`access:${PLUGIN_ID}-all`], + body: { + accepts: ['application/gzip', 'application/zip'], + parse: false, + maxBytes: MAX_FILE_SIZE_BYTES, + }, + }, + }, + installPackageByUploadHandler ); router.delete( diff --git a/x-pack/plugins/ingest_manager/server/types/rest_spec/epm.ts b/x-pack/plugins/ingest_manager/server/types/rest_spec/epm.ts index 191014606f220..d7a801feec34f 100644 --- a/x-pack/plugins/ingest_manager/server/types/rest_spec/epm.ts +++ b/x-pack/plugins/ingest_manager/server/types/rest_spec/epm.ts @@ -32,7 +32,7 @@ export const GetInfoRequestSchema = { }), }; -export const InstallPackageRequestSchema = { +export const InstallPackageFromRegistryRequestSchema = { params: schema.object({ pkgkey: schema.string(), }), @@ -43,6 +43,10 @@ export const InstallPackageRequestSchema = { ), }; +export const InstallPackageByUploadRequestSchema = { + body: schema.buffer(), +}; + export const DeletePackageRequestSchema = { params: schema.object({ pkgkey: schema.string(), diff --git a/x-pack/test/ingest_manager_api_integration/apis/epm/index.js b/x-pack/test/ingest_manager_api_integration/apis/epm/index.js index 8555814245909..28743ee5f43c2 100644 --- a/x-pack/test/ingest_manager_api_integration/apis/epm/index.js +++ b/x-pack/test/ingest_manager_api_integration/apis/epm/index.js @@ -11,6 +11,7 @@ export default function loadTests({ loadTestFile }) { loadTestFile(require.resolve('./file')); //loadTestFile(require.resolve('./template')); loadTestFile(require.resolve('./ilm')); + loadTestFile(require.resolve('./install_by_upload')); loadTestFile(require.resolve('./install_overrides')); loadTestFile(require.resolve('./install_prerelease')); loadTestFile(require.resolve('./install_remove_assets')); diff --git a/x-pack/test/ingest_manager_api_integration/apis/epm/install_by_upload.ts b/x-pack/test/ingest_manager_api_integration/apis/epm/install_by_upload.ts new file mode 100644 index 0000000000000..e6d2affaec0cd --- /dev/null +++ b/x-pack/test/ingest_manager_api_integration/apis/epm/install_by_upload.ts @@ -0,0 +1,55 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import fs from 'fs'; +import path from 'path'; +import expect from '@kbn/expect'; + +import { FtrProviderContext } from '../../../api_integration/ftr_provider_context'; +import { warnAndSkipTest } from '../../helpers'; + +export default function ({ getService }: FtrProviderContext) { + const supertest = getService('supertest'); + const dockerServers = getService('dockerServers'); + const log = getService('log'); + + const testPkgArchiveTgz = path.join( + path.dirname(__filename), + '../fixtures/direct_upload_packages/apache_0.1.4.tar.gz' + ); + const testPkgKey = 'apache-0.14'; + const server = dockerServers.get('registry'); + + const deletePackage = async (pkgkey: string) => { + await supertest.delete(`/api/ingest_manager/epm/packages/${pkgkey}`).set('kbn-xsrf', 'xxxx'); + }; + + describe('installs packages from direct upload', async () => { + after(async () => { + if (server.enabled) { + // remove the package just in case it being installed will affect other tests + await deletePackage(testPkgKey); + } + }); + + it('should install a tar archive correctly', async function () { + if (server.enabled) { + const buf = fs.readFileSync(testPkgArchiveTgz); + const res = await supertest + .post(`/api/ingest_manager/epm/packages`) + .set('kbn-xsrf', 'xxxx') + .type('application/gzip') + .send(buf) + .expect(200); + expect(res.body.response).to.equal( + 'package upload was received ok, but not installed (not implemented yet)' + ); + } else { + warnAndSkipTest(this, log); + } + }); + }); +} diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/direct_upload_packages/apache_0.1.4.tar.gz b/x-pack/test/ingest_manager_api_integration/apis/fixtures/direct_upload_packages/apache_0.1.4.tar.gz new file mode 100644 index 0000000000000..cc983f6ac6d1a Binary files /dev/null and b/x-pack/test/ingest_manager_api_integration/apis/fixtures/direct_upload_packages/apache_0.1.4.tar.gz differ