Skip to content

Commit 8bfb248

Browse files
authored
[Ingest Manager] Add route for package installation by upload (#77044) (#77438)
* Add route to accept a direct package upload. * Only accept application/zip or application/gzip * Use better name for response containing only a message. * Add integration test for direct package upload.
1 parent 9065242 commit 8bfb248

File tree

9 files changed

+113
-12
lines changed

9 files changed

+113
-12
lines changed

x-pack/plugins/ingest_manager/common/constants/routes.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ export const EPM_API_ROUTES = {
2121
LIST_PATTERN: EPM_PACKAGES_MANY,
2222
LIMITED_LIST_PATTERN: `${EPM_PACKAGES_MANY}/limited`,
2323
INFO_PATTERN: EPM_PACKAGES_ONE,
24-
INSTALL_PATTERN: EPM_PACKAGES_ONE,
24+
INSTALL_FROM_REGISTRY_PATTERN: EPM_PACKAGES_ONE,
25+
INSTALL_BY_UPLOAD_PATTERN: EPM_PACKAGES_MANY,
2526
DELETE_PATTERN: EPM_PACKAGES_ONE,
2627
FILEPATH_PATTERN: `${EPM_PACKAGES_FILE}/{filePath*}`,
2728
CATEGORIES_PATTERN: `${EPM_API_ROOT}/categories`,

x-pack/plugins/ingest_manager/common/services/routes.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,10 @@ export const epmRouteService = {
4040
},
4141

4242
getInstallPath: (pkgkey: string) => {
43-
return EPM_API_ROUTES.INSTALL_PATTERN.replace('{pkgkey}', pkgkey).replace(/\/$/, ''); // trim trailing slash
43+
return EPM_API_ROUTES.INSTALL_FROM_REGISTRY_PATTERN.replace('{pkgkey}', pkgkey).replace(
44+
/\/$/,
45+
''
46+
); // trim trailing slash
4447
},
4548

4649
getRemovePath: (pkgkey: string) => {

x-pack/plugins/ingest_manager/common/types/rest_spec/epm.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,10 @@ export interface InstallPackageResponse {
7171
response: AssetReference[];
7272
}
7373

74+
export interface MessageResponse {
75+
response: string;
76+
}
77+
7478
export interface DeletePackageRequest {
7579
params: {
7680
pkgkey: string;

x-pack/plugins/ingest_manager/server/routes/epm/handlers.ts

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { appContextService } from '../../services';
99
import {
1010
GetInfoResponse,
1111
InstallPackageResponse,
12+
MessageResponse,
1213
DeletePackageResponse,
1314
GetCategoriesResponse,
1415
GetPackagesResponse,
@@ -19,7 +20,8 @@ import {
1920
GetPackagesRequestSchema,
2021
GetFileRequestSchema,
2122
GetInfoRequestSchema,
22-
InstallPackageRequestSchema,
23+
InstallPackageFromRegistryRequestSchema,
24+
InstallPackageByUploadRequestSchema,
2325
DeletePackageRequestSchema,
2426
} from '../../types';
2527
import {
@@ -129,10 +131,10 @@ export const getInfoHandler: RequestHandler<TypeOf<typeof GetInfoRequestSchema.p
129131
}
130132
};
131133

132-
export const installPackageHandler: RequestHandler<
133-
TypeOf<typeof InstallPackageRequestSchema.params>,
134+
export const installPackageFromRegistryHandler: RequestHandler<
135+
TypeOf<typeof InstallPackageFromRegistryRequestSchema.params>,
134136
undefined,
135-
TypeOf<typeof InstallPackageRequestSchema.body>
137+
TypeOf<typeof InstallPackageFromRegistryRequestSchema.body>
136138
> = async (context, request, response) => {
137139
const logger = appContextService.getLogger();
138140
const savedObjectsClient = context.core.savedObjects.client;
@@ -183,6 +185,17 @@ export const installPackageHandler: RequestHandler<
183185
}
184186
};
185187

188+
export const installPackageByUploadHandler: RequestHandler<
189+
undefined,
190+
undefined,
191+
TypeOf<typeof InstallPackageByUploadRequestSchema.body>
192+
> = async (context, request, response) => {
193+
const body: MessageResponse = {
194+
response: 'package upload was received ok, but not installed (not implemented yet)',
195+
};
196+
return response.ok({ body });
197+
};
198+
186199
export const deletePackageHandler: RequestHandler<TypeOf<
187200
typeof DeletePackageRequestSchema.params
188201
>> = async (context, request, response) => {

x-pack/plugins/ingest_manager/server/routes/epm/index.ts

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,22 @@ import {
1111
getLimitedListHandler,
1212
getFileHandler,
1313
getInfoHandler,
14-
installPackageHandler,
14+
installPackageFromRegistryHandler,
15+
installPackageByUploadHandler,
1516
deletePackageHandler,
1617
} from './handlers';
1718
import {
1819
GetCategoriesRequestSchema,
1920
GetPackagesRequestSchema,
2021
GetFileRequestSchema,
2122
GetInfoRequestSchema,
22-
InstallPackageRequestSchema,
23+
InstallPackageFromRegistryRequestSchema,
24+
InstallPackageByUploadRequestSchema,
2325
DeletePackageRequestSchema,
2426
} from '../../types';
2527

28+
const MAX_FILE_SIZE_BYTES = 104857600; // 100MB
29+
2630
export const registerRoutes = (router: IRouter) => {
2731
router.get(
2832
{
@@ -71,11 +75,27 @@ export const registerRoutes = (router: IRouter) => {
7175

7276
router.post(
7377
{
74-
path: EPM_API_ROUTES.INSTALL_PATTERN,
75-
validate: InstallPackageRequestSchema,
78+
path: EPM_API_ROUTES.INSTALL_FROM_REGISTRY_PATTERN,
79+
validate: InstallPackageFromRegistryRequestSchema,
7680
options: { tags: [`access:${PLUGIN_ID}-all`] },
7781
},
78-
installPackageHandler
82+
installPackageFromRegistryHandler
83+
);
84+
85+
router.post(
86+
{
87+
path: EPM_API_ROUTES.INSTALL_BY_UPLOAD_PATTERN,
88+
validate: InstallPackageByUploadRequestSchema,
89+
options: {
90+
tags: [`access:${PLUGIN_ID}-all`],
91+
body: {
92+
accepts: ['application/gzip', 'application/zip'],
93+
parse: false,
94+
maxBytes: MAX_FILE_SIZE_BYTES,
95+
},
96+
},
97+
},
98+
installPackageByUploadHandler
7999
);
80100

81101
router.delete(

x-pack/plugins/ingest_manager/server/types/rest_spec/epm.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ export const GetInfoRequestSchema = {
3232
}),
3333
};
3434

35-
export const InstallPackageRequestSchema = {
35+
export const InstallPackageFromRegistryRequestSchema = {
3636
params: schema.object({
3737
pkgkey: schema.string(),
3838
}),
@@ -43,6 +43,10 @@ export const InstallPackageRequestSchema = {
4343
),
4444
};
4545

46+
export const InstallPackageByUploadRequestSchema = {
47+
body: schema.buffer(),
48+
};
49+
4650
export const DeletePackageRequestSchema = {
4751
params: schema.object({
4852
pkgkey: schema.string(),

x-pack/test/ingest_manager_api_integration/apis/epm/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ export default function loadTests({ loadTestFile }) {
1111
loadTestFile(require.resolve('./file'));
1212
//loadTestFile(require.resolve('./template'));
1313
loadTestFile(require.resolve('./ilm'));
14+
loadTestFile(require.resolve('./install_by_upload'));
1415
loadTestFile(require.resolve('./install_overrides'));
1516
loadTestFile(require.resolve('./install_prerelease'));
1617
loadTestFile(require.resolve('./install_remove_assets'));
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License;
4+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
7+
import fs from 'fs';
8+
import path from 'path';
9+
import expect from '@kbn/expect';
10+
11+
import { FtrProviderContext } from '../../../api_integration/ftr_provider_context';
12+
import { warnAndSkipTest } from '../../helpers';
13+
14+
export default function ({ getService }: FtrProviderContext) {
15+
const supertest = getService('supertest');
16+
const dockerServers = getService('dockerServers');
17+
const log = getService('log');
18+
19+
const testPkgArchiveTgz = path.join(
20+
path.dirname(__filename),
21+
'../fixtures/direct_upload_packages/apache_0.1.4.tar.gz'
22+
);
23+
const testPkgKey = 'apache-0.14';
24+
const server = dockerServers.get('registry');
25+
26+
const deletePackage = async (pkgkey: string) => {
27+
await supertest.delete(`/api/ingest_manager/epm/packages/${pkgkey}`).set('kbn-xsrf', 'xxxx');
28+
};
29+
30+
describe('installs packages from direct upload', async () => {
31+
after(async () => {
32+
if (server.enabled) {
33+
// remove the package just in case it being installed will affect other tests
34+
await deletePackage(testPkgKey);
35+
}
36+
});
37+
38+
it('should install a tar archive correctly', async function () {
39+
if (server.enabled) {
40+
const buf = fs.readFileSync(testPkgArchiveTgz);
41+
const res = await supertest
42+
.post(`/api/ingest_manager/epm/packages`)
43+
.set('kbn-xsrf', 'xxxx')
44+
.type('application/gzip')
45+
.send(buf)
46+
.expect(200);
47+
expect(res.body.response).to.equal(
48+
'package upload was received ok, but not installed (not implemented yet)'
49+
);
50+
} else {
51+
warnAndSkipTest(this, log);
52+
}
53+
});
54+
});
55+
}

0 commit comments

Comments
 (0)