[Fleet] Remove deprecated epm APIs (#198434)

This commit is contained in:
Nicolas Chaulet 2024-11-06 08:38:26 -05:00 committed by GitHub
parent ce9f6222d8
commit 15c1ceb475
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
31 changed files with 157 additions and 8539 deletions

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -23,19 +23,21 @@ export const LIMITED_CONCURRENCY_ROUTE_TAG = 'ingest:limited-concurrency';
const EPM_PACKAGES_MANY = `${EPM_API_ROOT}/packages`;
const EPM_PACKAGES_INSTALLED = `${EPM_API_ROOT}/packages/installed`;
const EPM_PACKAGES_BULK = `${EPM_PACKAGES_MANY}/_bulk`;
const EPM_PACKAGES_ONE_DEPRECATED = `${EPM_PACKAGES_MANY}/{pkgkey}`;
const EPM_PACKAGES_ONE_WITHOUT_VERSION = `${EPM_PACKAGES_MANY}/{pkgName}`;
const EPM_PACKAGES_ONE = `${EPM_PACKAGES_MANY}/{pkgName}/{pkgVersion}`;
const EPM_PACKAGES_ONE_WITH_OPTIONAL_VERSION = `${EPM_PACKAGES_MANY}/{pkgName}/{pkgVersion?}`;
export const EPM_API_ROUTES = {
BULK_INSTALL_PATTERN: EPM_PACKAGES_BULK,
LIST_PATTERN: EPM_PACKAGES_MANY,
INSTALLED_LIST_PATTERN: EPM_PACKAGES_INSTALLED,
LIMITED_LIST_PATTERN: `${EPM_PACKAGES_MANY}/limited`,
INFO_PATTERN: EPM_PACKAGES_ONE,
INFO_WITHOUT_VERSION_PATTERN: EPM_PACKAGES_ONE_WITHOUT_VERSION,
INFO_PATTERN: EPM_PACKAGES_ONE_WITH_OPTIONAL_VERSION,
DATA_STREAMS_PATTERN: `${EPM_API_ROOT}/data_streams`,
INSTALL_FROM_REGISTRY_PATTERN: EPM_PACKAGES_ONE,
INSTALL_FROM_REGISTRY_PATTERN: EPM_PACKAGES_ONE_WITH_OPTIONAL_VERSION,
INSTALL_BY_UPLOAD_PATTERN: EPM_PACKAGES_MANY,
CUSTOM_INTEGRATIONS_PATTERN: `${EPM_API_ROOT}/custom_integrations`,
DELETE_PATTERN: EPM_PACKAGES_ONE,
DELETE_PATTERN: EPM_PACKAGES_ONE_WITH_OPTIONAL_VERSION,
INSTALL_KIBANA_ASSETS_PATTERN: `${EPM_PACKAGES_ONE}/kibana_assets`,
DELETE_KIBANA_ASSETS_PATTERN: `${EPM_PACKAGES_ONE}/kibana_assets`,
FILEPATH_PATTERN: `${EPM_PACKAGES_ONE}/{filePath*}`,
@ -45,10 +47,6 @@ export const EPM_API_ROUTES = {
BULK_ASSETS_PATTERN: `${EPM_API_ROOT}/bulk_assets`,
INPUTS_PATTERN: `${EPM_API_ROOT}/templates/{pkgName}/{pkgVersion}/inputs`,
INFO_PATTERN_DEPRECATED: EPM_PACKAGES_ONE_DEPRECATED,
INSTALL_FROM_REGISTRY_PATTERN_DEPRECATED: EPM_PACKAGES_ONE_DEPRECATED,
DELETE_PATTERN_DEPRECATED: EPM_PACKAGES_ONE_DEPRECATED,
REAUTHORIZE_TRANSFORMS: `${EPM_PACKAGES_ONE}/transforms/authorize`,
};

View file

@ -0,0 +1,43 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { epmRouteService } from './routes';
describe('Route services', () => {
describe('epmRouteService', () => {
describe('getInfoPath', () => {
it('should generate path with pkgVersion', () => {
expect(epmRouteService.getInfoPath('test', '1.0.0')).toBe(
'/api/fleet/epm/packages/test/1.0.0'
);
});
it('should generate path without pkgVersion', () => {
expect(epmRouteService.getInfoPath('test')).toBe('/api/fleet/epm/packages/test');
});
});
describe('getInstallPath', () => {
it('should generate path with pkgVersion', () => {
expect(epmRouteService.getInstallPath('test', '1.0.0')).toBe(
'/api/fleet/epm/packages/test/1.0.0'
);
});
it('should generate path without pkgVersion', () => {
expect(epmRouteService.getInstallPath('test')).toBe('/api/fleet/epm/packages/test');
});
});
describe('getRemovePath', () => {
it('should generate path with pkgVersion', () => {
expect(epmRouteService.getRemovePath('test', '1.0.0')).toBe(
'/api/fleet/epm/packages/test/1.0.0'
);
});
it('should generate path without pkgVersion', () => {
expect(epmRouteService.getRemovePath('test')).toBe('/api/fleet/epm/packages/test');
});
});
});
});

View file

@ -47,11 +47,14 @@ export const epmRouteService = {
getInfoPath: (pkgName: string, pkgVersion?: string) => {
if (pkgVersion) {
return EPM_API_ROUTES.INFO_PATTERN.replace('{pkgName}', pkgName).replace(
'{pkgVersion}',
'{pkgVersion?}',
pkgVersion
);
} else {
return EPM_API_ROUTES.INFO_PATTERN.replace('{pkgName}', pkgName).replace('/{pkgVersion}', '');
return EPM_API_ROUTES.INFO_PATTERN.replace('{pkgName}', pkgName).replace(
'/{pkgVersion?}',
''
);
}
},
@ -63,20 +66,32 @@ export const epmRouteService = {
return `${EPM_API_ROOT}${filePath.replace('/package', '/packages')}`;
},
getInstallPath: (pkgName: string, pkgVersion: string) => {
return EPM_API_ROUTES.INSTALL_FROM_REGISTRY_PATTERN.replace('{pkgName}', pkgName)
.replace('{pkgVersion}', pkgVersion)
.replace(/\/$/, ''); // trim trailing slash
getInstallPath: (pkgName: string, pkgVersion?: string) => {
if (pkgVersion) {
return EPM_API_ROUTES.INSTALL_FROM_REGISTRY_PATTERN.replace('{pkgName}', pkgName)
.replace('{pkgVersion?}', pkgVersion)
.replace(/\/$/, ''); // trim trailing slash
} else {
return EPM_API_ROUTES.INSTALL_FROM_REGISTRY_PATTERN.replace('{pkgName}', pkgName)
.replace('/{pkgVersion?}', '')
.replace(/\/$/, ''); // trim trailing slash
}
},
getBulkInstallPath: () => {
return EPM_API_ROUTES.BULK_INSTALL_PATTERN;
},
getRemovePath: (pkgName: string, pkgVersion: string) => {
return EPM_API_ROUTES.DELETE_PATTERN.replace('{pkgName}', pkgName)
.replace('{pkgVersion}', pkgVersion)
.replace(/\/$/, ''); // trim trailing slash
getRemovePath: (pkgName: string, pkgVersion?: string) => {
if (pkgVersion) {
return EPM_API_ROUTES.DELETE_PATTERN.replace('{pkgName}', pkgName)
.replace('{pkgVersion?}', pkgVersion)
.replace(/\/$/, ''); // trim trailing slash
} else {
return EPM_API_ROUTES.DELETE_PATTERN.replace('{pkgName}', pkgName)
.replace('/{pkgVersion?}', '')
.replace(/\/$/, ''); // trim trailing slash
}
},
getInstallKibanaAssetsPath: (pkgName: string, pkgVersion: string) => {

View file

@ -546,8 +546,8 @@ export type PackageList = PackageListItem[];
export type PackageListItem = Installable<RegistrySearchResult> & {
id: string;
integration?: string;
installationInfo?: InstallationInfo;
savedObject?: InstallableSavedObject;
installationInfo?: InstallationInfo;
};
export type PackagesGroupedByStatus = Record<ValueOf<InstallationStatus>, PackageList>;
export type PackageInfo =

View file

@ -25,8 +25,6 @@ import type {
export interface GetCategoriesRequest {
query: {
// deprecated in 8.6
experimental?: boolean;
prerelease?: boolean;
include_policy_templates?: boolean;
};
@ -34,15 +32,11 @@ export interface GetCategoriesRequest {
export interface GetCategoriesResponse {
items: CategorySummaryList;
// deprecated in 8.0
response?: CategorySummaryList;
}
export interface GetPackagesRequest {
query: {
category?: string;
// deprecated in 8.6
experimental?: boolean;
prerelease?: boolean;
excludeInstallStatus?: boolean;
};
@ -50,8 +44,6 @@ export interface GetPackagesRequest {
export interface GetPackagesResponse {
items: PackageList;
// deprecated in 8.0
response?: PackageList;
}
export interface InstalledPackage {
@ -79,8 +71,6 @@ export interface GetEpmDataStreamsResponse {
}
export interface GetLimitedPackagesResponse {
items: string[];
// deprecated in 8.0
response?: string[];
}
export interface GetFileRequest {
@ -93,8 +83,6 @@ export interface GetFileRequest {
export interface GetInfoRequest {
params: {
// deprecated in 8.0
pkgkey?: string;
pkgName: string;
pkgVersion: string;
};
@ -103,14 +91,10 @@ export interface GetInfoRequest {
export interface GetInfoResponse {
item: PackageInfo;
metadata?: PackageMetadata;
// deprecated in 8.0
response?: PackageInfo;
}
export interface UpdatePackageRequest {
params: {
// deprecated in 8.0
pkgkey?: string;
pkgName: string;
pkgVersion: string;
};
@ -121,8 +105,6 @@ export interface UpdatePackageRequest {
export interface UpdatePackageResponse {
item: PackageInfo;
// deprecated in 8.0
response?: PackageInfo;
}
export interface GetStatsRequest {
@ -137,8 +119,6 @@ export interface GetStatsResponse {
export interface InstallPackageRequest {
params: {
// deprecated in 8.0
pkgkey?: string;
pkgName: string;
pkgVersion: string;
};
@ -149,8 +129,6 @@ export interface InstallPackageResponse {
_meta: {
install_source: InstallSource;
};
// deprecated in 8.0
response?: AssetReference[];
}
export interface IBulkInstallPackageHTTPError {
@ -175,8 +153,6 @@ export interface BulkInstallPackageInfo {
export interface BulkInstallPackagesResponse {
items: Array<BulkInstallPackageInfo | IBulkInstallPackageHTTPError>;
// deprecated in 8.0
response?: Array<BulkInstallPackageInfo | IBulkInstallPackageHTTPError>;
}
export interface BulkInstallPackagesRequest {
@ -191,8 +167,6 @@ export interface MessageResponse {
export interface DeletePackageRequest {
params: {
// deprecated in 8.0
pkgkey?: string;
pkgName: string;
pkgVersion: string;
};
@ -202,8 +176,6 @@ export interface DeletePackageRequest {
}
export interface DeletePackageResponse {
// deprecated in 8.0
response?: AssetReference[];
items: AssetReference[];
}
export interface GetVerificationKeyIdResponse {

View file

@ -23,8 +23,8 @@ const TutorialModuleNotice: TutorialModuleNoticeComponent = memo(({ moduleName }
const pkgInfo =
!isLoading &&
packagesData?.response &&
packagesData.response.find((pkg) => pkg.name === moduleName && pkg.name !== FLEET_APM_PACKAGE); // APM needs special handling
packagesData?.items &&
packagesData.items.find((pkg) => pkg.name === moduleName && pkg.name !== FLEET_APM_PACKAGE); // APM needs special handling
if (hasIntegrationsPermissions && pkgInfo) {
return (

View file

@ -133,7 +133,7 @@ describe('Package search provider', () => {
test('returns formatted results', () => {
getTestScheduler().run(({ expectObservable, hot }) => {
mockSendGetPackages.mockReturnValue(
hot('--(a|)', { a: { data: { response: testResponse } } })
hot('--(a|)', { a: { data: { items: testResponse } } })
);
setupMock.getStartServices.mockReturnValue(
hot('--(a|)', { a: [coreMock.createStart()] }) as any
@ -217,7 +217,7 @@ describe('Package search provider', () => {
test('calls EPR once only', () => {
getTestScheduler().run(({ hot }) => {
mockSendGetPackages.mockReturnValue(hot('--(a|)', { a: { data: { response: [] } } }));
mockSendGetPackages.mockReturnValue(hot('--(a|)', { a: { data: { items: [] } } }));
setupMock.getStartServices.mockReturnValue(
hot('--(a|)', { a: [coreMock.createStart()] }) as any
);
@ -237,7 +237,7 @@ describe('Package search provider', () => {
test('completes without returning results if aborted', () => {
getTestScheduler().run(({ expectObservable, hot }) => {
mockSendGetPackages.mockReturnValue(hot('--(a|)', { a: { data: { response: [] } } }));
mockSendGetPackages.mockReturnValue(hot('--(a|)', { a: { data: { items: [] } } }));
setupMock.getStartServices.mockReturnValue(
hot('--(a|)', { a: [coreMock.createStart()] }) as any
);
@ -258,7 +258,7 @@ describe('Package search provider', () => {
test('respect maximum results', () => {
getTestScheduler().run(({ hot, expectObservable }) => {
mockSendGetPackages.mockReturnValue(
hot('--(a|)', { a: { data: { response: testResponse } } })
hot('--(a|)', { a: { data: { items: testResponse } } })
);
setupMock.getStartServices.mockReturnValue(
hot('--(a|)', { a: [coreMock.createStart()] }) as any
@ -292,7 +292,7 @@ describe('Package search provider', () => {
test('without packages tag, without search term', () => {
getTestScheduler().run(({ hot, expectObservable }) => {
mockSendGetPackages.mockReturnValue(
hot('--(a|)', { a: { data: { response: testResponse } } })
hot('--(a|)', { a: { data: { items: testResponse } } })
);
setupMock.getStartServices.mockReturnValue(
hot('--(a|)', { a: [coreMock.createStart()] }) as any
@ -314,7 +314,7 @@ describe('Package search provider', () => {
test('with integration tag, with no search term', () => {
getTestScheduler().run(({ hot, expectObservable }) => {
mockSendGetPackages.mockReturnValue(
hot('--(a|)', { a: { data: { response: testResponse } } })
hot('--(a|)', { a: { data: { items: testResponse } } })
);
setupMock.getStartServices.mockReturnValue(
hot('--(a|)', { a: [coreMock.createStart()] }) as any
@ -397,7 +397,7 @@ describe('Package search provider', () => {
test('with integration tag, with search term', () => {
getTestScheduler().run(({ hot, expectObservable }) => {
mockSendGetPackages.mockReturnValue(
hot('--(a|)', { a: { data: { response: testResponse } } })
hot('--(a|)', { a: { data: { items: testResponse } } })
);
setupMock.getStartServices.mockReturnValue(
hot('--(a|)', { a: [coreMock.createStart()] }) as any

View file

@ -30,7 +30,7 @@ const createPackages$ = () =>
if (error) {
throw error;
}
return data?.response ?? [];
return data?.items ?? [];
}),
shareReplay(1)
);
@ -86,7 +86,7 @@ export const createPackageSearchProvider = (core: CoreSetup): GlobalSearchResult
shareReplay(1)
);
let packages$: undefined | Observable<GetPackagesResponse['response']>;
let packages$: undefined | Observable<GetPackagesResponse['items']>;
const getPackages$ = () => {
if (!packages$) {

View file

@ -9,7 +9,7 @@ import type { TypeOf } from '@kbn/config-schema';
import semverValid from 'semver/functions/valid';
import type { HttpResponseOptions } from '@kbn/core/server';
import { pick } from 'lodash';
import { omit, pick } from 'lodash';
import { PACKAGE_POLICY_SAVED_OBJECT_TYPE } from '../../../common';
@ -98,12 +98,11 @@ export const getCategoriesHandler: FleetRequestHandler<
TypeOf<typeof GetCategoriesRequestSchema.query>
> = async (context, request, response) => {
try {
const res = await getCategories({
const items = await getCategories({
...request.query,
});
const body: GetCategoriesResponse = {
items: res,
response: res,
items,
};
return response.ok({ body, headers: { ...CACHE_CONTROL_10_MINUTES_HEADER } });
} catch (error) {
@ -124,7 +123,6 @@ export const getListHandler: FleetRequestHandler<
const flattenedRes = res.map((pkg) => soToInstallationInfo(pkg)) as PackageList;
const body: GetPackagesResponse = {
items: flattenedRes,
response: res,
};
return response.ok({
body,
@ -199,7 +197,6 @@ export const getLimitedListHandler: FleetRequestHandler<
});
const body: GetLimitedPackagesResponse = {
items: res,
response: res,
};
return response.ok({
body,
@ -460,7 +457,6 @@ export const bulkInstallPackagesFromRegistryHandler: FleetRequestHandler<
const payload = bulkInstalledResponses.map(bulkInstallServiceResponseToHttpEntry);
const body: BulkInstallPackagesResponse = {
items: payload,
response: payload,
};
return response.ok({ body });
};
@ -494,7 +490,6 @@ export const installPackageByUploadHandler: FleetRequestHandler<
if (!res.error) {
const body: InstallPackageResponse = {
items: res.assets || [],
response: res.assets || [],
_meta: {
install_source: res.installSource ?? installSource,
},
@ -519,8 +514,7 @@ export const installPackageByUploadHandler: FleetRequestHandler<
export const deletePackageHandler: FleetRequestHandler<
TypeOf<typeof DeletePackageRequestSchema.params>,
TypeOf<typeof DeletePackageRequestSchema.query>,
TypeOf<typeof DeletePackageRequestSchema.body>
TypeOf<typeof DeletePackageRequestSchema.query>
> = async (context, request, response) => {
try {
const { pkgName, pkgVersion } = request.params;
@ -676,8 +670,7 @@ const soToInstallationInfo = (pkg: PackageListItem | PackageInfo) => {
};
return {
// When savedObject gets removed, replace `pkg` with `...omit(pkg, 'savedObject')`
...pkg,
...omit(pkg, 'savedObject'),
installationInfo,
};
}

View file

@ -323,7 +323,6 @@ describe('schema validation', () => {
};
const expectedResponse: GetCategoriesResponse = {
items: [category],
response: [category],
};
(getCategoriesHandler as jest.Mock).mockImplementation((ctx, request, res) => {
return res.ok({ body: expectedResponse });
@ -386,7 +385,6 @@ describe('schema validation', () => {
};
const expectedResponse: GetPackagesResponse = {
items: [packageItem],
response: [packageItem],
};
(getListHandler as jest.Mock).mockImplementation((ctx, request, res) => {
return res.ok({ body: expectedResponse });
@ -444,7 +442,6 @@ describe('schema validation', () => {
it('get limited packages should return valid response', async () => {
const expectedResponse: GetLimitedPackagesResponse = {
items: ['test'],
response: ['test'],
};
(getLimitedListHandler as jest.Mock).mockImplementation((ctx, request, res) => {
return res.ok({ body: expectedResponse });
@ -513,7 +510,6 @@ describe('schema validation', () => {
metadata: {
has_policies: true,
},
response: packageInfo,
};
(getInfoHandler as jest.Mock).mockImplementation((ctx, request, res) => {
return res.ok({ body: expectedResponse });
@ -530,7 +526,6 @@ describe('schema validation', () => {
it('update package should return valid response', async () => {
const expectedResponse: UpdatePackageResponse = {
item: packageInfo,
response: packageInfo,
};
(updatePackageHandler as jest.Mock).mockImplementation((ctx, request, res) => {
return res.ok({ body: expectedResponse });
@ -556,13 +551,6 @@ describe('schema validation', () => {
_meta: {
install_source: 'registry',
},
response: [
{
id: 'test',
type: KibanaSavedObjectType.dashboard,
originId: 'test',
},
],
};
(installPackageFromRegistryHandler as jest.Mock).mockImplementation((ctx, request, res) => {
return res.ok({ body: expectedResponse });
@ -612,7 +600,6 @@ describe('schema validation', () => {
};
const expectedResponse: BulkInstallPackagesResponse = {
items: [item, { name: 'test', statusCode: 400, error: 'test' }],
response: [item],
};
(bulkInstallPackagesFromRegistryHandler as jest.Mock).mockImplementation(
(ctx, request, res) => {

View file

@ -5,8 +5,6 @@
* 2.0.
*/
import type { IKibanaResponse } from '@kbn/core/server';
import { parseExperimentalConfigValue } from '../../../common/experimental_features';
import { API_VERSIONS } from '../../../common/constants';
@ -20,32 +18,20 @@ import {
} from '../../services/security';
import type { FleetAuthzRouteConfig } from '../../services/security/types';
import type {
DeletePackageResponse,
GetInfoResponse,
InstallPackageResponse,
UpdatePackageResponse,
} from '../../../common/types';
import { EPM_API_ROUTES } from '../../constants';
import { splitPkgKey } from '../../services/epm/registry';
import {
GetCategoriesRequestSchema,
GetPackagesRequestSchema,
GetInstalledPackagesRequestSchema,
GetFileRequestSchema,
GetInfoRequestSchema,
GetInfoRequestSchemaDeprecated,
GetBulkAssetsRequestSchema,
InstallPackageFromRegistryRequestSchema,
InstallPackageFromRegistryRequestSchemaDeprecated,
InstallPackageByUploadRequestSchema,
DeletePackageRequestSchema,
DeletePackageRequestSchemaDeprecated,
BulkInstallPackagesFromRegistryRequestSchema,
GetStatsRequestSchema,
UpdatePackageRequestSchema,
UpdatePackageRequestSchemaDeprecated,
ReauthorizeTransformRequestSchema,
GetDataStreamsRequestSchema,
CreateCustomIntegrationRequestSchema,
@ -648,124 +634,6 @@ export const registerRoutes = (router: FleetAuthzRouter, config: FleetConfigType
getBulkAssetsHandler
);
// deprecated since 8.0
// This endpoint should be marked as internal but the router selects this endpoint over the new GET one
// For now keeping it public
router.versioned
.get({
path: EPM_API_ROUTES.INFO_PATTERN_DEPRECATED,
fleetAuthz: (fleetAuthz: FleetAuthz): boolean =>
calculateRouteAuthz(
fleetAuthz,
getRouteRequiredAuthz('get', EPM_API_ROUTES.INFO_PATTERN_DEPRECATED)
).granted,
// @ts-expect-error TODO(https://github.com/elastic/kibana/issues/196095): Replace {RouteDeprecationInfo}
deprecated: true,
})
.addVersion(
{
version: API_VERSIONS.public.v1,
validate: { request: GetInfoRequestSchemaDeprecated },
},
async (context, request, response) => {
const newRequest = { ...request, params: splitPkgKey(request.params.pkgkey) } as any;
const resp: IKibanaResponse<GetInfoResponse> = await getInfoHandler(
context,
newRequest,
response
);
if (resp.payload?.item) {
// returning item as well here, because pkgVersion is optional in new GET endpoint, and if not specified, the router selects the deprecated route
return response.ok({ body: { item: resp.payload.item, response: resp.payload.item } });
}
return resp;
}
);
router.versioned
.put({
path: EPM_API_ROUTES.INFO_PATTERN_DEPRECATED,
fleetAuthz: {
integrations: { writePackageSettings: true },
},
// @ts-expect-error TODO(https://github.com/elastic/kibana/issues/196095): Replace {RouteDeprecationInfo}
deprecated: true,
})
.addVersion(
{
version: API_VERSIONS.public.v1,
validate: { request: UpdatePackageRequestSchemaDeprecated },
},
async (context, request, response) => {
const newRequest = { ...request, params: splitPkgKey(request.params.pkgkey) } as any;
const resp: IKibanaResponse<UpdatePackageResponse> = await updatePackageHandler(
context,
newRequest,
response
);
if (resp.payload?.item) {
return response.ok({ body: { response: resp.payload.item } });
}
return resp;
}
);
// This endpoint should be marked as internal but the router selects this endpoint over the new POST
router.versioned
.post({
path: EPM_API_ROUTES.INSTALL_FROM_REGISTRY_PATTERN_DEPRECATED,
fleetAuthz: INSTALL_PACKAGES_AUTHZ,
// @ts-expect-error TODO(https://github.com/elastic/kibana/issues/196095): Replace {RouteDeprecationInfo}
deprecated: true,
})
.addVersion(
{
version: API_VERSIONS.public.v1,
validate: { request: InstallPackageFromRegistryRequestSchemaDeprecated },
},
async (context, request, response) => {
const newRequest = {
...request,
params: splitPkgKey(request.params.pkgkey),
query: request.query,
} as any;
const resp: IKibanaResponse<InstallPackageResponse> =
await installPackageFromRegistryHandler(context, newRequest, response);
if (resp.payload?.items) {
return response.ok({ body: { ...resp.payload, response: resp.payload.items } });
}
return resp;
}
);
router.versioned
.delete({
path: EPM_API_ROUTES.DELETE_PATTERN_DEPRECATED,
fleetAuthz: {
integrations: { removePackages: true },
},
// @ts-expect-error TODO(https://github.com/elastic/kibana/issues/196095): Replace {RouteDeprecationInfo}
deprecated: true,
})
.addVersion(
{
version: API_VERSIONS.public.v1,
validate: { request: DeletePackageRequestSchemaDeprecated },
},
async (context, request, response) => {
const newRequest = { ...request, params: splitPkgKey(request.params.pkgkey) } as any;
const resp: IKibanaResponse<DeletePackageResponse> = await deletePackageHandler(
context,
newRequest,
response
);
if (resp.payload?.items) {
return response.ok({ body: { response: resp.payload.items } });
}
return resp;
}
);
// Update transforms with es-secondary-authorization headers,
// append authorized_by to transform's _meta, and start transforms
router.versioned

View file

@ -57,14 +57,15 @@ const MAX_ASSETS_TO_DELETE = 1000;
export async function removeInstallation(options: {
savedObjectsClient: SavedObjectsClientContract;
pkgName: string;
pkgVersion: string;
pkgVersion?: string;
esClient: ElasticsearchClient;
force?: boolean;
}): Promise<AssetReference[]> {
const { savedObjectsClient, pkgName, pkgVersion, esClient } = options;
const { savedObjectsClient, pkgName, esClient } = options;
const installation = await getInstallation({ savedObjectsClient, pkgName });
if (!installation) throw new PackageRemovalError(`${pkgName} is not installed`);
if (!installation) {
throw new PackageRemovalError(`${pkgName} is not installed`);
}
const { total, items } = await packagePolicyService.list(
appContextService.getInternalUserSOClientWithoutSpaceExtension(),
{
@ -115,7 +116,7 @@ export async function removeInstallation(options: {
// a fresh copy from the registry
deletePackageCache({
name: pkgName,
version: pkgVersion,
version: installation.version,
});
await removeArchiveEntries({ savedObjectsClient, refs: installation.package_assets });

View file

@ -164,7 +164,7 @@ const ROUTE_AUTHZ_REQUIREMENTS = deepFreeze<Record<string, FleetRouteRequiredAut
},
},
},
[`get:${EPM_API_ROUTES.INFO_PATTERN_DEPRECATED}`]: {
[`get:${EPM_API_ROUTES.INFO_WITHOUT_VERSION_PATTERN}`]: {
any: {
integrations: {
readPackageInfo: true,

View file

@ -12,7 +12,6 @@ import { ExperimentalDataStreamFeaturesSchema } from '../models/package_policy';
export const GetCategoriesRequestSchema = {
query: schema.object({
prerelease: schema.maybe(schema.boolean()),
experimental: schema.maybe(schema.boolean()), // deprecated
include_policy_templates: schema.maybe(schema.boolean()),
}),
};
@ -27,16 +26,12 @@ const CategorySummaryItemSchema = schema.object({
export const GetCategoriesResponseSchema = schema.object({
items: schema.arrayOf(CategorySummaryItemSchema),
response: schema.maybe(
schema.arrayOf(CategorySummaryItemSchema.extends({}, { meta: { deprecated: true } }))
),
});
export const GetPackagesRequestSchema = {
query: schema.object({
category: schema.maybe(schema.string()),
prerelease: schema.maybe(schema.boolean()),
experimental: schema.maybe(schema.boolean()), // deprecated
excludeInstallStatus: schema.maybe(schema.boolean({ defaultValue: false })),
}),
};
@ -142,7 +137,6 @@ const PackageIconSchema = schema.object({
export const PackageInfoSchema = schema
.object({
status: schema.maybe(schema.string()),
savedObject: schema.maybe(schema.any({ meta: { deprecated: true } })),
installationInfo: schema.maybe(InstallationInfoSchema),
name: schema.string(),
version: schema.string(),
@ -216,9 +210,6 @@ export const PackageListItemSchema = PackageInfoSchema.extends({
export const GetPackagesResponseSchema = schema.object({
items: schema.arrayOf(PackageListItemSchema),
response: schema.maybe(
schema.arrayOf(PackageListItemSchema.extends({}, { meta: { deprecated: true } }))
),
});
export const InstalledPackageSchema = schema.object({
@ -254,7 +245,6 @@ export const GetInstalledPackagesResponseSchema = schema.object({
export const GetLimitedPackagesResponseSchema = schema.object({
items: schema.arrayOf(schema.string()),
response: schema.maybe(schema.arrayOf(schema.string(), { meta: { deprecated: true } })),
});
export const GetStatsResponseSchema = schema.object({
@ -327,12 +317,10 @@ export const GetPackageInfoSchema = PackageInfoSchema.extends({
export const GetInfoResponseSchema = schema.object({
item: GetPackageInfoSchema,
metadata: schema.maybe(PackageMetadataSchema),
response: schema.maybe(GetPackageInfoSchema.extends({}, { meta: { deprecated: true } })),
});
export const UpdatePackageResponseSchema = schema.object({
item: GetPackageInfoSchema,
response: schema.maybe(GetPackageInfoSchema.extends({}, { meta: { deprecated: true } })),
});
export const AssetReferenceSchema = schema.oneOf([
@ -345,7 +333,6 @@ export const InstallPackageResponseSchema = schema.object({
_meta: schema.object({
install_source: schema.string(),
}),
response: schema.maybe(schema.arrayOf(AssetReferenceSchema, { meta: { deprecated: true } })),
});
export const InstallKibanaAssetsResponseSchema = schema.object({
@ -375,14 +362,10 @@ export const BulkInstallPackagesResponseItemSchema = schema.oneOf([
export const BulkInstallPackagesFromRegistryResponseSchema = schema.object({
items: schema.arrayOf(BulkInstallPackagesResponseItemSchema),
response: schema.maybe(
schema.arrayOf(BulkInstallPackagesResponseItemSchema, { meta: { deprecated: true } })
),
});
export const DeletePackageResponseSchema = schema.object({
items: schema.arrayOf(AssetReferenceSchema),
response: schema.maybe(schema.arrayOf(AssetReferenceSchema, { meta: { deprecated: true } })),
});
export const GetVerificationKeyIdResponseSchema = schema.object({
@ -494,18 +477,6 @@ export const GetBulkAssetsRequestSchema = {
}),
};
export const GetInfoRequestSchemaDeprecated = {
params: schema.object({
pkgkey: schema.string(),
}),
query: schema.object({
ignoreUnverified: schema.maybe(schema.boolean()),
prerelease: schema.maybe(schema.boolean()),
full: schema.maybe(schema.boolean()),
withMetadata: schema.boolean({ defaultValue: false }),
}),
};
export const UpdatePackageRequestSchema = {
params: schema.object({
pkgName: schema.string(),
@ -516,15 +487,6 @@ export const UpdatePackageRequestSchema = {
}),
};
export const UpdatePackageRequestSchemaDeprecated = {
params: schema.object({
pkgkey: schema.string(),
}),
body: schema.object({
keepPoliciesUpToDate: schema.boolean(),
}),
};
export const GetStatsRequestSchema = {
params: schema.object({
pkgName: schema.string(),
@ -562,22 +524,6 @@ export const ReauthorizeTransformRequestSchema = {
}),
};
export const InstallPackageFromRegistryRequestSchemaDeprecated = {
params: schema.object({
pkgkey: schema.string(),
}),
query: schema.object({
prerelease: schema.maybe(schema.boolean()),
ignoreMappingUpdateErrors: schema.boolean({ defaultValue: false }),
skipDataStreamRollover: schema.boolean({ defaultValue: false }),
}),
body: schema.nullable(
schema.object({
force: schema.boolean(),
})
),
};
export const BulkInstallPackagesFromRegistryRequestSchema = {
query: schema.object({
prerelease: schema.maybe(schema.boolean()),
@ -628,17 +574,11 @@ export const CreateCustomIntegrationRequestSchema = {
export const DeletePackageRequestSchema = {
params: schema.object({
pkgName: schema.string(),
pkgVersion: schema.string(),
pkgVersion: schema.maybe(schema.string()),
}),
query: schema.object({
force: schema.maybe(schema.boolean()),
}),
// body is deprecated on delete request
body: schema.nullable(
schema.object({
force: schema.boolean(),
})
),
};
export const InstallKibanaAssetsRequestSchema = {
@ -661,17 +601,6 @@ export const DeleteKibanaAssetsRequestSchema = {
}),
};
export const DeletePackageRequestSchemaDeprecated = {
params: schema.object({
pkgkey: schema.string(),
}),
body: schema.nullable(
schema.object({
force: schema.boolean(),
})
),
};
export const GetInputsRequestSchema = {
params: schema.object({
pkgName: schema.string(),

View file

@ -154,7 +154,7 @@ export const fleetGetPackageHttpMock = httpHandlerMockFactory<FleetGetPackageHtt
{
id: 'endpointPackage',
method: 'get',
path: EPM_API_ROUTES.INFO_PATTERN_DEPRECATED,
path: EPM_API_ROUTES.INFO_WITHOUT_VERSION_PATTERN,
handler() {
const generator = new EndpointDocGenerator('seed');

View file

@ -48,15 +48,12 @@ export default function (providerContext: FtrProviderContext) {
const packageInfo = await supertest
.get(`/api/fleet/epm/packages/${pkgName}/${pkgVersion}`)
.expect(200);
const packageSOAttributes = packageInfo.body.item.savedObject.attributes;
const installationInfo = packageInfo.body.item.installationInfo;
const { body }: { body: GetBulkAssetsResponse } = await supertest
.post(`/api/fleet/epm/bulk_assets`)
.set('kbn-xsrf', 'xxxx')
.send({
assetIds: [
...packageSOAttributes.installed_es,
...packageSOAttributes.installed_kibana,
],
assetIds: [...installationInfo.installed_es, ...installationInfo.installed_kibana],
})
.expect(200);

View file

@ -73,7 +73,7 @@ export default function (providerContext: FtrProviderContext) {
expect(JSON.parse(goodPkgInfoResponse.text).item.status).to.be('installed');
expect(JSON.parse(goodPkgInfoResponse.text).item.version).to.be('0.1.0');
const latestInstallFailedAttempts =
goodPkgInfoResponse.body.item.savedObject.attributes.latest_install_failed_attempts;
goodPkgInfoResponse.body.item.installationInfo.latest_install_failed_attempts;
expect(latestInstallFailedAttempts).to.have.length(1);
expect(latestInstallFailedAttempts[0].target_version).to.be('0.2.0');
expect(latestInstallFailedAttempts[0].error.message).to.contain(
@ -90,7 +90,7 @@ export default function (providerContext: FtrProviderContext) {
expect(JSON.parse(goodPkgInfoResponse.text).item.status).to.be('installed');
expect(JSON.parse(goodPkgInfoResponse.text).item.version).to.be('0.3.0');
const latestInstallFailedAttempts =
goodPkgInfoResponse.body.item.savedObject.attributes.latest_install_failed_attempts;
goodPkgInfoResponse.body.item.installationInfo.latest_install_failed_attempts;
expect(latestInstallFailedAttempts).to.have.length(0);
});
});

View file

@ -61,8 +61,8 @@ export default function (providerContext: FtrProviderContext) {
({ body } = await supertest
.get(`/api/fleet/epm/packages/endpoint/${latestEndpointVersion}`)
.expect(200));
expect(body.item).to.have.property('savedObject');
expect((body.item as InstalledRegistry).savedObject?.attributes.install_version).to.eql(
expect(body.item).to.have.property('installationInfo');
expect((body.item as InstalledRegistry).installationInfo?.version).to.eql(
latestEndpointVersion
);
});

View file

@ -61,7 +61,7 @@ export default function (providerContext: FtrProviderContext) {
const { body: apiResponse } = await supertest
.get(`/api/fleet/epm/packages?prerelease=true`)
.expect(200);
const installedPackages = apiResponse.response
const installedPackages = apiResponse.items
.filter((p: any) => p.status === 'installed')
.map((p: any) => p.name)
.sort();

View file

@ -0,0 +1,13 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { Agent } from 'supertest';
export async function getInstallationInfo(supertest: Agent, name: string, version: string) {
const res = await supertest.get(`/api/fleet/epm/packages/${name}/${version}`).expect(200);
return res.body.item.installationInfo;
}

View file

@ -8,6 +8,7 @@ import expect from '@kbn/expect';
import { sortBy } from 'lodash';
import { FtrProviderContext } from '../../../api_integration/ftr_provider_context';
import { skipIfNoDockerRegistry } from '../../helpers';
import { getInstallationInfo } from './helper';
const PACKAGE_NAME = 'input_package_upgrade';
const START_VERSION = '1.0.0';
const UPGRADE_VERSION = '1.1.0';
@ -33,11 +34,6 @@ export default function (providerContext: FtrProviderContext) {
.expect(200);
};
const getInstallationSavedObject = async (name: string, version: string) => {
const res = await supertest.get(`/api/fleet/epm/packages/${name}/${version}`).expect(200);
return res.body.item.savedObject.attributes;
};
const createPackagePolicyWithDataset = async (
agentPolicyId: string,
dataset: string,
@ -195,13 +191,13 @@ export default function (providerContext: FtrProviderContext) {
});
it('should not have created any ES assets on install', async () => {
const installation = await getInstallationSavedObject(PACKAGE_NAME, START_VERSION);
const installation = await getInstallationInfo(supertest, PACKAGE_NAME, START_VERSION);
expect(installation.installed_es).to.eql([]);
});
it('should create index templates and update installed_es on package policy creation', async () => {
await createPackagePolicyWithDataset(agentPolicyId, 'dataset1');
const installation = await getInstallationSavedObject(PACKAGE_NAME, START_VERSION);
const installation = await getInstallationInfo(supertest, PACKAGE_NAME, START_VERSION);
expectIdArraysEqual(installation.installed_es, [
{ id: 'logs-dataset1-1.0.0', type: 'ingest_pipeline' },
{ id: 'logs-dataset1', type: 'index_template' },
@ -249,7 +245,7 @@ export default function (providerContext: FtrProviderContext) {
it('should create index templates and update installed_es on second package policy creation', async () => {
await createPackagePolicyWithDataset(agentPolicyId, 'dataset2');
const installation = await getInstallationSavedObject(PACKAGE_NAME, START_VERSION);
const installation = await getInstallationInfo(supertest, PACKAGE_NAME, START_VERSION);
let found = 0;
[
{ id: 'logs-dataset2-1.0.0', type: 'ingest_pipeline' },
@ -268,7 +264,7 @@ export default function (providerContext: FtrProviderContext) {
await createFakeFleetDataStream('dataset3');
await createPackagePolicyWithDataset(agentPolicyId, 'dataset3');
const installation = await getInstallationSavedObject(PACKAGE_NAME, START_VERSION);
const installation = await getInstallationInfo(supertest, PACKAGE_NAME, START_VERSION);
let found = 0;
[
{ id: 'logs-dataset3-1.0.0', type: 'ingest_pipeline' },

View file

@ -8,6 +8,7 @@ import expect from '@kbn/expect';
import { sortBy } from 'lodash';
import { FtrProviderContext } from '../../../api_integration/ftr_provider_context';
import { skipIfNoDockerRegistry } from '../../helpers';
import { getInstallationInfo } from './helper';
const PACKAGE_NAME = 'input_package_upgrade';
const START_VERSION = '1.0.0';
@ -31,11 +32,6 @@ export default function (providerContext: FtrProviderContext) {
.expect(200);
};
const getInstallationSavedObject = async (name: string, version: string) => {
const res = await supertest.get(`/api/fleet/epm/packages/${name}/${version}`).expect(200);
return res.body.item.savedObject.attributes;
};
const getPackage = async (name: string, version: string) => {
const res = await supertest.get(`/api/fleet/epm/packages/${name}/${version}`).expect(200);
return res.body.item;
@ -131,7 +127,7 @@ export default function (providerContext: FtrProviderContext) {
await installPackage(PACKAGE_NAME, START_VERSION);
await createPackagePolicyWithDataset(agentPolicyId, 'test*', 400);
const installation = await getInstallationSavedObject(PACKAGE_NAME, START_VERSION);
const installation = await getInstallationInfo(supertest, PACKAGE_NAME, START_VERSION);
expectIdArraysEqual(installation.installed_es, []);
await uninstallPackage(PACKAGE_NAME, START_VERSION);

View file

@ -15,6 +15,7 @@ import {
enableSecrets,
} from '../../helpers';
import { testUsers } from '../test_users';
import { getInstallationInfo } from './helper';
export default function (providerContext: FtrProviderContext) {
const { getService } = providerContext;
@ -28,11 +29,6 @@ export default function (providerContext: FtrProviderContext) {
expect(sortBy(arr1, 'id')).to.eql(sortBy(arr2, 'id'));
};
const getInstallationSavedObject = async (name: string, version: string) => {
const res = await supertest.get(`/api/fleet/epm/packages/${name}/${version}`).expect(200);
return res.body.item.savedObject.attributes;
};
const getPackagePolicyById = async (id: string) => {
const { body } = await supertest.get(`/api/fleet/package_policies/${id}`);
return body;
@ -935,7 +931,7 @@ export default function (providerContext: FtrProviderContext) {
})
.expect(200);
const installation = await getInstallationSavedObject('integration_to_input', '2.0.0');
const installation = await getInstallationInfo(supertest, 'integration_to_input', '2.0.0');
expectIdArraysEqual(installation.installed_es, [
// assets from version 1.0.0

View file

@ -12,6 +12,7 @@ import {
import { sortBy } from 'lodash';
import { FtrProviderContext } from '../../../api_integration/ftr_provider_context';
import { skipIfNoDockerRegistry } from '../../helpers';
import { getInstallationInfo } from './helper';
const expectIdArraysEqual = (arr1: any[], arr2: any[]) => {
expect(sortBy(arr1, 'id')).to.eql(sortBy(arr2, 'id'));
@ -36,11 +37,6 @@ export default function (providerContext: FtrProviderContext) {
});
}
const getInstallationSavedObject = async (name: string, version: string) => {
const res = await supertest.get(`/api/fleet/epm/packages/${name}/${version}`).expect(200);
return res.body.item.savedObject.attributes;
};
const getComponentTemplate = async (name: string) => {
try {
const { component_templates: templates } = await es.cluster.getComponentTemplate({ name });
@ -1358,7 +1354,11 @@ export default function (providerContext: FtrProviderContext) {
})
.expect(200);
const installation = await getInstallationSavedObject('integration_to_input', '3.0.0');
const installation = await getInstallationInfo(
supertest,
'integration_to_input',
'3.0.0'
);
expectIdArraysEqual(installation.installed_es, expectedAssets);
const expectedComponentTemplates = expectedAssets.filter(

View file

@ -594,12 +594,12 @@ export function MachineLearningTestResourcesProvider(
await retry.tryForTime(10 * 1000, async () => {
const { body, status } = await supertest
.get(`/api/fleet/epm/packages?experimental=true`)
.get(`/api/fleet/epm/packages?prerelease=true`)
.set(getCommonRequestHeader(`${API_VERSIONS.public.v1}`));
mlApi.assertResponseStatusCode(200, status, body);
packageVersion =
body.response.find(
body.items.find(
({ name, version }: { name: string; version: string }) =>
name === packageName && version
)?.version ?? '';

View file

@ -21,9 +21,9 @@ export async function deleteEndpointFleetPackage(supertest: SuperTest.Agent) {
.set('elastic-api-version', '2023-10-31')
.send();
if (resp.status === 200 && resp.body.response.status === 'installed') {
if (resp.status === 200 && resp.body.item.status === 'installed') {
await supertest
.delete(epmRouteService.getRemovePath(ENDPOINT_PACKAGE_NAME, resp.body.response.version))
.delete(epmRouteService.getRemovePath(ENDPOINT_PACKAGE_NAME, resp.body.item.version))
.set('kbn-xsrf', 'true')
.send({ force: true });
}

View file

@ -21,11 +21,9 @@ export async function deletePrebuiltRulesFleetPackage(supertest: SuperTest.Agent
.set('elastic-api-version', '2023-10-31')
.send();
if (resp.status === 200 && resp.body.response.status === 'installed') {
if (resp.status === 200 && resp.body.item.status === 'installed') {
await supertest
.delete(
epmRouteService.getRemovePath(PREBUILT_RULES_PACKAGE_NAME, resp.body.response.version)
)
.delete(epmRouteService.getRemovePath(PREBUILT_RULES_PACKAGE_NAME, resp.body.item.version))
.set('kbn-xsrf', 'true')
.send({ force: true });
}