Skip to content

Commit

Permalink
[Fleet] Make logs-* and metrics-* data views available across all spa…
Browse files Browse the repository at this point in the history
…ces (#172991)

## Summary

Closes #172009 

Adds a call to `updateObjectsSpaces` with `['*']` as the spaces list
after Fleet's managed data views are created.

Existing data views will be updated to be global whenever
`installKibanaAssets` is called.

### Checklist

- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
  • Loading branch information
kpollich authored Dec 12, 2023
1 parent b51304f commit bd21e30
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 2 deletions.
13 changes: 11 additions & 2 deletions x-pack/plugins/fleet/server/services/epm/kibana/assets/install.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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<KibanaAssetType, ArchiveAsset[]>;
}): Promise<SavedObjectsImportSuccess[]> {
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 [];
Expand Down Expand Up @@ -152,6 +158,8 @@ export async function installKibanaAssets(options: {
managed: true,
});

await makeManagedIndexPatternsGlobal(savedObjectsClient);

const installedAssets = await installKibanaSavedObjects({
logger,
savedObjectsImporter,
Expand Down Expand Up @@ -196,6 +204,7 @@ export async function installKibanaAssetsAndReferences({
);

const importedAssets = await installKibanaAssets({
savedObjectsClient,
logger,
savedObjectsImporter,
pkgName,
Expand Down
Original file line number Diff line number Diff line change
@@ -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<SavedObjectsClientContract>;
let mockContract: ReturnType<typeof createAppContextStartContractMock>;

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);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
18 changes: 18 additions & 0 deletions x-pack/test/fleet_api_integration/apis/epm/data_views.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down

0 comments on commit bd21e30

Please sign in to comment.