diff --git a/x-pack/plugins/fleet/server/services/epm/kibana/assets/install.ts b/x-pack/plugins/fleet/server/services/epm/kibana/assets/install.ts index 23327a2253f866..27be17ef2a1702 100644 --- a/x-pack/plugins/fleet/server/services/epm/kibana/assets/install.ts +++ b/x-pack/plugins/fleet/server/services/epm/kibana/assets/install.ts @@ -32,7 +32,11 @@ import type { PackageSpecTags, } from '../../../../types'; import { savedObjectTypes } from '../../packages'; -import { indexPatternTypes, getIndexPatternSavedObjects } from '../index_pattern/install'; +import { + indexPatternTypes, + getIndexPatternSavedObjects, + makeManagedIndexPatternsGlobal, +} from '../index_pattern/install'; import { saveKibanaAssetsRefs } from '../../packages/install'; import { deleteKibanaSavedObjectsAssets } from '../../packages/remove'; import { KibanaSOReferenceError } from '../../../../errors'; @@ -114,12 +118,14 @@ export function createSavedObjectKibanaAsset(asset: ArchiveAsset): SavedObjectTo } export async function installKibanaAssets(options: { + savedObjectsClient: SavedObjectsClientContract; savedObjectsImporter: SavedObjectsImporterContract; logger: Logger; pkgName: string; kibanaAssets: Record; }): Promise { - const { kibanaAssets, savedObjectsImporter, logger } = options; + const { kibanaAssets, savedObjectsClient, savedObjectsImporter, logger } = options; + const assetsToInstall = Object.entries(kibanaAssets).flatMap(([assetType, assets]) => { if (!validKibanaAssetTypes.has(assetType as KibanaAssetType)) { return []; @@ -152,6 +158,8 @@ export async function installKibanaAssets(options: { managed: true, }); + await makeManagedIndexPatternsGlobal(savedObjectsClient); + const installedAssets = await installKibanaSavedObjects({ logger, savedObjectsImporter, @@ -196,6 +204,7 @@ export async function installKibanaAssetsAndReferences({ ); const importedAssets = await installKibanaAssets({ + savedObjectsClient, logger, savedObjectsImporter, pkgName, diff --git a/x-pack/plugins/fleet/server/services/epm/kibana/index_pattern/install.test.ts b/x-pack/plugins/fleet/server/services/epm/kibana/index_pattern/install.test.ts new file mode 100644 index 00000000000000..9e826d7f126ae3 --- /dev/null +++ b/x-pack/plugins/fleet/server/services/epm/kibana/index_pattern/install.test.ts @@ -0,0 +1,54 @@ +/* + * 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-saved-objects-api-server'; +import { savedObjectsClientMock } from '@kbn/core-saved-objects-api-server-mocks'; + +import { createAppContextStartContractMock } from '../../../../mocks'; + +import { appContextService } from '../../../app_context'; + +import { makeManagedIndexPatternsGlobal } from './install'; + +describe('Fleet index patterns', () => { + let mockSoClient: jest.Mocked; + let mockContract: ReturnType; + + beforeEach(() => { + mockSoClient = savedObjectsClientMock.create(); + mockContract = createAppContextStartContractMock(); + appContextService.start(mockContract); + }); + + afterEach(() => { + appContextService.stop(); + }); + + describe('makeManagedIndexPatternsGlobal', () => { + it('should call updateObjectsSpaces with the correct params', async () => { + const result = await makeManagedIndexPatternsGlobal(mockSoClient); + + for (const pattern of ['logs-*', 'metrics-*']) { + expect(mockSoClient.updateObjectsSpaces).toHaveBeenCalledWith( + [{ id: pattern, type: 'index-pattern' }], + ['*'], + [] + ); + } + + expect(result).toHaveLength(2); + }); + + it('handles errors from updateObjectsSpaces', async () => { + mockSoClient.updateObjectsSpaces.mockRejectedValue(new Error('foo')); + + const result = await makeManagedIndexPatternsGlobal(mockSoClient); + + expect(result).toHaveLength(0); + }); + }); +}); diff --git a/x-pack/plugins/fleet/server/services/epm/kibana/index_pattern/install.ts b/x-pack/plugins/fleet/server/services/epm/kibana/index_pattern/install.ts index 91e603e80aee2f..6f1390f5e17cd0 100644 --- a/x-pack/plugins/fleet/server/services/epm/kibana/index_pattern/install.ts +++ b/x-pack/plugins/fleet/server/services/epm/kibana/index_pattern/install.ts @@ -28,6 +28,30 @@ export function getIndexPatternSavedObjects() { })); } +export async function makeManagedIndexPatternsGlobal( + savedObjectsClient: SavedObjectsClientContract +) { + const logger = appContextService.getLogger(); + + const results = []; + + for (const indexPatternType of indexPatternTypes) { + try { + const result = await savedObjectsClient.updateObjectsSpaces( + [{ id: `${indexPatternType}-*`, type: INDEX_PATTERN_SAVED_OBJECT_TYPE }], + ['*'], + [] + ); + + results.push(result); + } catch (error) { + logger.error(`Error making managed index patterns global: ${error.message}`); + } + } + + return results; +} + export async function removeUnusedIndexPatterns(savedObjectsClient: SavedObjectsClientContract) { const logger = appContextService.getLogger(); // get all user installed packages diff --git a/x-pack/test/fleet_api_integration/apis/epm/data_views.ts b/x-pack/test/fleet_api_integration/apis/epm/data_views.ts index 1fc5e660dbc578..5a0753fb321b44 100644 --- a/x-pack/test/fleet_api_integration/apis/epm/data_views.ts +++ b/x-pack/test/fleet_api_integration/apis/epm/data_views.ts @@ -51,6 +51,24 @@ export default function (providerContext: FtrProviderContext) { await Promise.all(testPkgs.map((pkg) => uninstallPackage(pkg.name, pkg.version))); }); + describe('with single integration installation', async () => { + it('creates global data views for logs-* and metrics-*', async () => { + await installPackage(testPkgs[0].name, testPkgs[0].version); + const dataViews: any[] = await listDataViews(); + + expect(dataViews).to.have.length(2); + const logsDataView = dataViews.find(({ title }) => title === 'logs-*'); + const metricsDataView = dataViews.find(({ title }) => title === 'metrics-*'); + + expect(logsDataView).to.be.ok(); + expect(metricsDataView).to.be.ok(); + + // Each data view should be available in all spaces + expect(logsDataView.namespaces).to.contain('*'); + expect(metricsDataView.namespaces).to.contain('*'); + }); + }); + describe('with subsequent integration installation', async () => { it('does not recreate managed data views', async () => { await installPackage(testPkgs[0].name, testPkgs[0].version);