Skip to content
2 changes: 1 addition & 1 deletion x-pack/plugins/fleet/public/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export const plugin = (initializerContext: PluginInitializerContext) => {
return new FleetPlugin(initializerContext);
};

export type { NewPackagePolicy } from './types';
export type { NewPackagePolicy, KibanaSavedObjectType } from './types';
export type {
AgentDetailsReassignPolicyAction,
AgentPolicyDetailsDeployAgentAction,
Expand Down
1 change: 1 addition & 0 deletions x-pack/plugins/fleet/public/mock/plugin_interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,6 @@ export const createStartMock = (extensionsStorage: UIExtensionsStorage = {}): Mo
writeIntegrationPolicies: true,
},
},
hooks: { epm: { getBulkAssets: jest.fn() } },
};
};
26 changes: 25 additions & 1 deletion x-pack/plugins/fleet/public/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ import type { LicensingPluginStart } from '@kbn/licensing-plugin/public';
import type { CloudSetup } from '@kbn/cloud-plugin/public';
import type { GlobalSearchPluginSetup } from '@kbn/global-search-plugin/public';

import type { SendRequestResponse } from '@kbn/es-ui-shared-plugin/public';

import type { UnifiedSearchPublicPluginStart } from '@kbn/unified-search-plugin/public';
import type { GuidedOnboardingPluginStart } from '@kbn/guided-onboarding-plugin/public';

Expand All @@ -63,13 +65,21 @@ import { createPackageSearchProvider } from './search_provider';
import { TutorialDirectoryHeaderLink, TutorialModuleNotice } from './components/home_integration';
import { createExtensionRegistrationCallback } from './services/ui_extensions';
import { ExperimentalFeaturesService } from './services/experimental_features';
import type { UIExtensionRegistrationCallback, UIExtensionsStorage } from './types';
import type {
UIExtensionRegistrationCallback,
UIExtensionsStorage,
GetBulkAssetsRequest,
GetBulkAssetsResponse,
} from './types';
import { LazyCustomLogsAssetsExtension } from './lazy_custom_logs_assets_extension';

export type { FleetConfigType } from '../common/types';

import { setCustomIntegrations, setCustomIntegrationsStart } from './services/custom_integrations';

import type { RequestError } from './hooks';
import { sendGetBulkAssets } from './hooks';

// We need to provide an object instead of void so that dependent plugins know when Fleet
// is disabled.
// eslint-disable-next-line @typescript-eslint/no-empty-interface
Expand All @@ -83,6 +93,13 @@ export interface FleetStart {
authz: FleetAuthz;
registerExtension: UIExtensionRegistrationCallback;
isInitialized: () => Promise<true>;
hooks: {
epm: {
getBulkAssets: (
body: GetBulkAssetsRequest['body']
) => Promise<SendRequestResponse<GetBulkAssetsResponse, RequestError>>;
};
};
}

export interface FleetSetupDeps {
Expand Down Expand Up @@ -315,6 +332,13 @@ export class FleetPlugin implements Plugin<FleetSetup, FleetStart, FleetSetupDep
}),

registerExtension,

hooks: {
epm: {
// hook exported to be used in monitoring-ui
getBulkAssets: sendGetBulkAssets,
},
},
};
}

Expand Down
1 change: 1 addition & 0 deletions x-pack/plugins/fleet/public/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ export type {
PostRetrieveAgentsByActionsResponse,
GetBulkAssetsRequest,
GetBulkAssetsResponse,
KibanaSavedObjectType,
} from '../../common/types';
export {
entries,
Expand Down
30 changes: 5 additions & 25 deletions x-pack/plugins/fleet/server/routes/epm/handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ import type {
UpdatePackageResponse,
GetVerificationKeyIdResponse,
GetBulkAssetsResponse,
SimpleSOAssetType,
GetInstalledPackagesResponse,
GetEpmDataStreamsResponse,
AssetSOObject,
} from '../../../common/types';
import type {
GetCategoriesRequestSchema,
Expand Down Expand Up @@ -65,6 +65,7 @@ import {
removeInstallation,
getLimitedPackages,
getInstallation,
getBulkAssets,
} from '../../services/epm/packages';
import type { BulkInstallResponse } from '../../services/epm/packages';
import { defaultFleetErrorHandler, fleetErrorToResponseOptions, FleetError } from '../../errors';
Expand All @@ -76,15 +77,12 @@ import { updatePackage } from '../../services/epm/packages/update';
import { getGpgKeyIdOrUndefined } from '../../services/epm/packages/package_verification';
import type {
ReauthorizeTransformRequestSchema,
SimpleSOAssetAttributes,
PackageListItem,
PackageList,
PackageInfo,
InstallationInfo,
} from '../../types';
import type { KibanaSavedObjectType, ElasticsearchAssetType } from '../../../common/types/models';
import { getDataStreams } from '../../services/epm/data_streams';
import { allowedAssetTypesLookup } from '../../../common/constants';

const CACHE_CONTROL_10_MINUTES_HEADER: HttpResponseOptions['headers'] = {
'cache-control': 'max-age=600',
Expand Down Expand Up @@ -317,30 +315,12 @@ export const getBulkAssetsHandler: FleetRequestHandler<
TypeOf<typeof GetBulkAssetsRequestSchema.body>
> = async (context, request, response) => {
try {
const savedObjectsClient = (await context.fleet).internalSoClient;
const { assetIds } = request.body;
const savedObjectsClient = (await context.fleet).internalSoClient;
const assets = await getBulkAssets(savedObjectsClient, assetIds as AssetSOObject[]);
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I refactored this as I was trying to export it with PackageService from /server/plugin, so I decided to keep this change even if it's not strictly related to this PR


const { resolved_objects: resolvedObjects } =
await savedObjectsClient.bulkResolve<SimpleSOAssetAttributes>(assetIds);
const res: SimpleSOAssetType[] = resolvedObjects
.map(({ saved_object: savedObject }) => savedObject)
.filter(
(savedObject) =>
savedObject?.error?.statusCode !== 404 && allowedAssetTypesLookup.has(savedObject.type)
)
.map((obj) => {
return {
id: obj.id,
type: obj.type as unknown as ElasticsearchAssetType | KibanaSavedObjectType,
updatedAt: obj.updated_at,
attributes: {
title: obj.attributes.title,
description: obj.attributes.description,
},
};
});
const body: GetBulkAssetsResponse = {
items: res,
items: assets,
};
return response.ok({ body });
} catch (error) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* 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 type { SavedObjectsClientContract } from '@kbn/core/server';

import type {
AssetSOObject,
ElasticsearchAssetType,
KibanaSavedObjectType,
SimpleSOAssetType,
} from '../../../../common';

import { allowedAssetTypesLookup } from '../../../../common/constants';

import type { SimpleSOAssetAttributes } from '../../../types';

export async function getBulkAssets(
soClient: SavedObjectsClientContract,
assetIds: AssetSOObject[]
) {
const { resolved_objects: resolvedObjects } = await soClient.bulkResolve<SimpleSOAssetAttributes>(
assetIds
);
const res: SimpleSOAssetType[] = resolvedObjects
.map(({ saved_object: savedObject }) => savedObject)
.filter(
(savedObject) =>
savedObject?.error?.statusCode !== 404 && allowedAssetTypesLookup.has(savedObject.type)
)
.map((obj) => {
return {
id: obj.id,
type: obj.type as unknown as ElasticsearchAssetType | KibanaSavedObjectType,
updatedAt: obj.updated_at,
attributes: {
title: obj.attributes.title,
description: obj.attributes.description,
},
};
});
return res;
}
1 change: 1 addition & 0 deletions x-pack/plugins/fleet/server/services/epm/packages/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export {
} from './get';

export { getBundledPackages } from './bundled_packages';
export { getBulkAssets } from './get_bulk_assets';

export type { BulkInstallResponse, IBulkInstallPackageError } from './install';
export { handleInstallPackageFailure, installPackage, ensureInstalledPackage } from './install';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { FormattedMessage } from '@kbn/i18n-react';
import { i18n } from '@kbn/i18n';
import { EuiCallOut, EuiConfirmModal, EuiSpacer } from '@elastic/eui';
import { DashboardStart } from '@kbn/dashboard-plugin/public';
import { FleetStart } from '@kbn/fleet-plugin/public';
import { FleetStart, KibanaSavedObjectType } from '@kbn/fleet-plugin/public';

const INGEST_PIPELINE_DASHBOARD_ID = 'elasticsearch-metrics-ingest-pipelines';

Expand All @@ -25,11 +25,17 @@ const INGEST_PIPELINE_DASHBOARD_ID = 'elasticsearch-metrics-ingest-pipelines';
export const ingestPipelineTabOnClick = async (
services: Partial<CoreStart & { dashboard: DashboardStart; fleet: FleetStart }>
) => {
const dashboard = await services.savedObjects!.client.get(
'dashboard',
INGEST_PIPELINE_DASHBOARD_ID
);
const dashboardFound = !dashboard.error && dashboard.attributes;
const response = await services.fleet?.hooks.epm.getBulkAssets({
assetIds: [
{
id: INGEST_PIPELINE_DASHBOARD_ID,
type: 'dashboard' as KibanaSavedObjectType,
},
],
});
const dashboardFound =
response?.data?.items?.length &&
response.data.items.some((item) => item.id === INGEST_PIPELINE_DASHBOARD_ID);

const navigateToDashboard = () =>
services.dashboard!.locator!.navigate({
Expand Down