Skip to content

Commit

Permalink
[dot-kibana-split] Adapt usages of core.savedObjects.getKibanaIndex
Browse files Browse the repository at this point in the history
… to use the correct index (#155155)

### **this PR is targeting the `dot-kibana-split` feature branch and not
`main`**

## Summary

Part of #154888

In #154888, we're going to split
the `.kibana` savedObject index into multiple ones. For this reason,
calls to `core.savedObjects.getKibanaIndex` will not necessarily return
the correct value (e.g types that were moved out of this index)

This PR introduces the following SO APIs:
- `getDefaultIndex`
- `getIndexForType`
- `getIndicesForTypes`
- `getAllIndices`

And adapt plugins code to replace usages of
`core.savedObjects.getKibanaIndex` with the proper alternative
  • Loading branch information
pgayvallet authored Apr 19, 2023
1 parent 181f1d1 commit 93e96aa
Show file tree
Hide file tree
Showing 55 changed files with 354 additions and 191 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,8 @@ export function createPluginSetupContext<TPlugin, TPluginDependencies>(
setSecurityExtension: deps.savedObjects.setSecurityExtension,
setSpacesExtension: deps.savedObjects.setSpacesExtension,
registerType: deps.savedObjects.registerType,
getKibanaIndex: deps.savedObjects.getKibanaIndex,
getDefaultIndex: deps.savedObjects.getDefaultIndex,
getAllIndices: deps.savedObjects.getAllIndices,
},
status: {
core$: deps.status.core$,
Expand Down Expand Up @@ -313,6 +314,10 @@ export function createPluginStartContext<TPlugin, TPluginDependencies>(
createExporter: deps.savedObjects.createExporter,
createImporter: deps.savedObjects.createImporter,
getTypeRegistry: deps.savedObjects.getTypeRegistry,
getDefaultIndex: deps.savedObjects.getDefaultIndex,
getIndexForType: deps.savedObjects.getIndexForType,
getIndicesForTypes: deps.savedObjects.getIndicesForTypes,
getAllIndices: deps.savedObjects.getAllIndices,
},
metrics: {
collectionInterval: deps.metrics.collectionInterval,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { type RawPackageInfo, Env } from '@kbn/config';
import { ByteSizeValue } from '@kbn/config-schema';
import { REPO_ROOT } from '@kbn/repo-info';
import { getEnvOptions } from '@kbn/config-mocks';
import { SavedObjectsType, MAIN_SAVED_OBJECT_INDEX } from '@kbn/core-saved-objects-server';
import { docLinksServiceMock } from '@kbn/core-doc-links-server-mocks';
import { nodeServiceMock } from '@kbn/core-node-server-mocks';
import { mockCoreContext } from '@kbn/core-base-server-mocks';
Expand Down Expand Up @@ -55,6 +56,14 @@ import { getSavedObjectsDeprecationsProvider } from './deprecations';
jest.mock('./object_types');
jest.mock('./deprecations');

const createType = (parts: Partial<SavedObjectsType>): SavedObjectsType => ({
name: 'test-type',
hidden: false,
namespaceType: 'single',
mappings: { properties: {} },
...parts,
});

describe('SavedObjectsService', () => {
let deprecationsSetup: ReturnType<typeof createDeprecationRegistryProviderMock>;

Expand Down Expand Up @@ -630,5 +639,85 @@ describe('SavedObjectsService', () => {
expect(includedHiddenTypes).toEqual(['someHiddenType']);
});
});

describe('index retrieval APIs', () => {
let soService: SavedObjectsService;

beforeEach(async () => {
const coreContext = createCoreContext({ skipMigration: false });
soService = new SavedObjectsService(coreContext);

typeRegistryInstanceMock.getType.mockImplementation((type: string) => {
if (type === 'dashboard') {
return createType({
name: 'dashboard',
});
} else if (type === 'foo') {
return createType({
name: 'foo',
indexPattern: '.kibana_foo',
});
} else if (type === 'bar') {
return createType({
name: 'bar',
indexPattern: '.kibana_bar',
});
} else if (type === 'bar_too') {
return createType({
name: 'bar_too',
indexPattern: '.kibana_bar',
});
} else {
return undefined;
}
});

await soService.setup(createSetupDeps());
});

describe('#getDefaultIndex', () => {
it('return the default index', async () => {
const { getDefaultIndex } = await soService.start(createStartDeps());
expect(getDefaultIndex()).toEqual(MAIN_SAVED_OBJECT_INDEX);
});
});

describe('#getIndexForType', () => {
it('return the correct index for type specifying its indexPattern', async () => {
const { getIndexForType } = await soService.start(createStartDeps());
expect(getIndexForType('bar')).toEqual('.kibana_bar');
});
it('return the correct index for type not specifying its indexPattern', async () => {
const { getIndexForType } = await soService.start(createStartDeps());
expect(getIndexForType('dashboard')).toEqual(MAIN_SAVED_OBJECT_INDEX);
});
it('return the default index for unknown type', async () => {
const { getIndexForType } = await soService.start(createStartDeps());
expect(getIndexForType('unknown_type')).toEqual(MAIN_SAVED_OBJECT_INDEX);
});
});

describe('#getIndicesForTypes', () => {
it('return the correct indices for specified types', async () => {
const { getIndicesForTypes } = await soService.start(createStartDeps());
expect(getIndicesForTypes(['dashboard', 'foo', 'bar'])).toEqual([
MAIN_SAVED_OBJECT_INDEX,
'.kibana_foo',
'.kibana_bar',
]);
});
it('ignore duplicate indices', async () => {
const { getIndicesForTypes } = await soService.start(createStartDeps());
expect(getIndicesForTypes(['bar', 'bar_too'])).toEqual(['.kibana_bar']);
});
it('return the default index for unknown type', async () => {
const { getIndicesForTypes } = await soService.start(createStartDeps());
expect(getIndicesForTypes(['unknown', 'foo'])).toEqual([
MAIN_SAVED_OBJECT_INDEX,
'.kibana_foo',
]);
});
});
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ import {
import type { InternalCoreUsageDataSetup } from '@kbn/core-usage-data-base-server-internal';
import type { DeprecationRegistryProvider } from '@kbn/core-deprecations-server';
import type { NodeInfo } from '@kbn/core-node-server';
import { MAIN_SAVED_OBJECT_INDEX } from '@kbn/core-saved-objects-server';
import { MAIN_SAVED_OBJECT_INDEX, SavedObjectsIndexPatterns } from '@kbn/core-saved-objects-server';
import { registerRoutes } from './routes';
import { calculateStatus$ } from './status';
import { registerCoreObjectTypes } from './object_types';
Expand Down Expand Up @@ -197,7 +197,8 @@ export class SavedObjectsService
this.typeRegistry.registerType(type);
},
getTypeRegistry: () => this.typeRegistry,
getKibanaIndex: () => MAIN_SAVED_OBJECT_INDEX,
getDefaultIndex: () => MAIN_SAVED_OBJECT_INDEX,
getAllIndices: () => [...SavedObjectsIndexPatterns],
};
}

Expand Down Expand Up @@ -340,6 +341,21 @@ export class SavedObjectsService
importSizeLimit: options?.importSizeLimit ?? this.config!.maxImportExportSize,
}),
getTypeRegistry: () => this.typeRegistry,
getDefaultIndex: () => MAIN_SAVED_OBJECT_INDEX,
getIndexForType: (type: string) => {
const definition = this.typeRegistry.getType(type);
return definition?.indexPattern ?? MAIN_SAVED_OBJECT_INDEX;
},
getIndicesForTypes: (types: string[]) => {
const indices = new Set<string>();
types.forEach((type) => {
const definition = this.typeRegistry.getType(type);
const index = definition?.indexPattern ?? MAIN_SAVED_OBJECT_INDEX;
indices.add(index);
});
return [...indices];
},
getAllIndices: () => [...SavedObjectsIndexPatterns],
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ const createStartContractMock = (typeRegistry?: jest.Mocked<ISavedObjectTypeRegi
createExporter: jest.fn(),
createImporter: jest.fn(),
getTypeRegistry: jest.fn(),
getDefaultIndex: jest.fn(),
getIndexForType: jest.fn(),
getIndicesForTypes: jest.fn(),
getAllIndices: jest.fn(),
};

startContrat.getScopedClient.mockReturnValue(savedObjectsClientMock.create());
Expand All @@ -50,6 +54,10 @@ const createStartContractMock = (typeRegistry?: jest.Mocked<ISavedObjectTypeRegi
startContrat.getTypeRegistry.mockReturnValue(typeRegistry ?? typeRegistryMock.create());
startContrat.createExporter.mockReturnValue(savedObjectsExporterMock.create());
startContrat.createImporter.mockReturnValue(savedObjectsImporterMock.create());
startContrat.getDefaultIndex.mockReturnValue(MAIN_SAVED_OBJECT_INDEX);
startContrat.getIndexForType.mockReturnValue(MAIN_SAVED_OBJECT_INDEX);
startContrat.getIndicesForTypes.mockReturnValue([MAIN_SAVED_OBJECT_INDEX]);
startContrat.getAllIndices.mockReturnValue([MAIN_SAVED_OBJECT_INDEX]);

return startContrat;
};
Expand All @@ -68,10 +76,12 @@ const createSetupContractMock = () => {
setSecurityExtension: jest.fn(),
setSpacesExtension: jest.fn(),
registerType: jest.fn(),
getKibanaIndex: jest.fn(),
getDefaultIndex: jest.fn(),
getAllIndices: jest.fn(),
};

setupContract.getKibanaIndex.mockReturnValue(MAIN_SAVED_OBJECT_INDEX);
setupContract.getDefaultIndex.mockReturnValue(MAIN_SAVED_OBJECT_INDEX);
setupContract.getAllIndices.mockReturnValue([MAIN_SAVED_OBJECT_INDEX]);

return setupContract;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,14 @@ export interface SavedObjectsServiceSetup {
/**
* Returns the default index used for saved objects.
*/
getKibanaIndex: () => string;
getDefaultIndex: () => string;

/**
* Returns all (aliases to) kibana system indices used for saved object storage.
*
* @deprecated use the `start` contract counterpart.
*/
getAllIndices: () => string[];
}

/**
Expand Down Expand Up @@ -209,4 +216,25 @@ export interface SavedObjectsServiceStart {
* {@link SavedObjectsType | saved object types}
*/
getTypeRegistry: () => ISavedObjectTypeRegistry;
/**
* Returns the (alias to the) index that the specified saved object type is stored in.
*
* @param type The SO type to retrieve the index/alias for.
*/
getIndexForType: (type: string) => string;
/**
* Returns the (alias to the) index that the specified saved object type is stored in.
*
* @remark if multiple types are living in the same index, duplicates will be removed.
* @param types The SO types to retrieve the index/alias for.
*/
getIndicesForTypes: (types: string[]) => string[];
/**
* Returns the default index used for saved objects.
*/
getDefaultIndex: () => string;
/**
* Returns all (aliases to) kibana system indices used for saved object storage.
*/
getAllIndices: () => string[];
}
Original file line number Diff line number Diff line change
Expand Up @@ -114,12 +114,14 @@ export function dashboardTaskRunner(logger: Logger, core: CoreSetup, embeddable:
return dashboardData;
};

const kibanaIndex = core.savedObjects.getKibanaIndex();
const dashboardIndex = await core
.getStartServices()
.then(([coreStart]) => coreStart.savedObjects.getIndexForType('dashboard'));
const pageSize = 50;

const searchParams = {
size: pageSize,
index: kibanaIndex,
index: dashboardIndex,
ignore_unavailable: true,
filter_path: ['hits.hits', '_scroll_id'],
body: { query: { bool: { filter: { term: { type: 'dashboard' } } } } },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ export class KqlTelemetryService implements Plugin<void> {

if (usageCollection) {
try {
makeKQLUsageCollector(usageCollection, savedObjects.getKibanaIndex());
const getIndexForType = (type: string) =>
getStartServices().then(([coreStart]) => coreStart.savedObjects.getIndexForType(type));
makeKQLUsageCollector(usageCollection, getIndexForType);
} catch (e) {
this.initializerContext.logger
.get('kql-telemetry')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ function setupMockCallCluster(
describe('makeKQLUsageCollector', () => {
describe('fetch method', () => {
beforeEach(() => {
fetch = fetchProvider('.kibana');
fetch = fetchProvider(() => Promise.resolve('.kibana'));
});

it('should return opt in data from the .kibana/kql-telemetry doc', async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,19 @@ export interface Usage {
defaultQueryLanguage: string;
}

export function fetchProvider(index: string) {
export function fetchProvider(getIndexForType: (type: string) => Promise<string>) {
return async ({ esClient }: CollectorFetchContext): Promise<Usage> => {
const [response, config] = await Promise.all([
esClient.get(
{
index,
index: await getIndexForType('kql-telemetry'),
id: 'kql-telemetry:kql-telemetry',
},
{ ignore: [404] }
),
esClient.search(
{
index,
index: await getIndexForType('config'),
body: { query: { term: { type: 'config' } } },
},
{ ignore: [404] }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import { UsageCollectionSetup } from '@kbn/usage-collection-plugin/server';
describe('makeKQLUsageCollector', () => {
let usageCollectionMock: jest.Mocked<UsageCollectionSetup>;

const getIndexForType = () => Promise.resolve('.kibana');

beforeEach(() => {
usageCollectionMock = {
makeUsageCollector: jest.fn(),
Expand All @@ -20,12 +22,12 @@ describe('makeKQLUsageCollector', () => {
});

it('should call registerCollector', () => {
makeKQLUsageCollector(usageCollectionMock as UsageCollectionSetup, '.kibana');
makeKQLUsageCollector(usageCollectionMock as UsageCollectionSetup, getIndexForType);
expect(usageCollectionMock.registerCollector).toHaveBeenCalledTimes(1);
});

it('should call makeUsageCollector with type = kql', () => {
makeKQLUsageCollector(usageCollectionMock as UsageCollectionSetup, '.kibana');
makeKQLUsageCollector(usageCollectionMock as UsageCollectionSetup, getIndexForType);
expect(usageCollectionMock.makeUsageCollector).toHaveBeenCalledTimes(1);
expect(usageCollectionMock.makeUsageCollector.mock.calls[0][0].type).toBe('kql');
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,13 @@
import { UsageCollectionSetup } from '@kbn/usage-collection-plugin/server';
import { fetchProvider, Usage } from './fetch';

export function makeKQLUsageCollector(usageCollection: UsageCollectionSetup, kibanaIndex: string) {
export function makeKQLUsageCollector(
usageCollection: UsageCollectionSetup,
getIndexForType: (type: string) => Promise<string>
) {
const kqlUsageCollector = usageCollection.makeUsageCollector<Usage>({
type: 'kql',
fetch: fetchProvider(kibanaIndex),
fetch: fetchProvider(getIndexForType),
isReady: () => true,
schema: {
optInCount: { type: 'long' },
Expand Down
5 changes: 3 additions & 2 deletions src/plugins/data/server/search/collectors/search/fetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,12 @@ interface SearchTelemetry {
'search-telemetry': CollectedUsage;
}

export function fetchProvider(kibanaIndex: string) {
export function fetchProvider(getIndexForType: (type: string) => Promise<string>) {
return async ({ esClient }: CollectorFetchContext): Promise<ReportedUsage> => {
const searchIndex = await getIndexForType('search-telemetry');
const esResponse = await esClient.search<SearchTelemetry>(
{
index: kibanaIndex,
index: searchIndex,
body: {
query: { term: { type: { value: 'search-telemetry' } } },
},
Expand Down
7 changes: 5 additions & 2 deletions src/plugins/data/server/search/collectors/search/register.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,15 @@ export interface ReportedUsage {
averageDuration: number | null;
}

export function registerUsageCollector(usageCollection: UsageCollectionSetup, kibanaIndex: string) {
export function registerUsageCollector(
usageCollection: UsageCollectionSetup,
getIndexForType: (type: string) => Promise<string>
) {
try {
const collector = usageCollection.makeUsageCollector<ReportedUsage>({
type: 'search',
isReady: () => true,
fetch: fetchProvider(kibanaIndex),
fetch: fetchProvider(getIndexForType),
schema: {
successCount: { type: 'long' },
errorCount: { type: 'long' },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,13 @@ describe('fetchProvider', () => {

beforeEach(async () => {
const kibanaIndex = '123';
const getIndexForType = () => Promise.resolve(kibanaIndex);
mockLogger = {
warn: jest.fn(),
debug: jest.fn(),
} as any;
esClient = elasticsearchServiceMock.createElasticsearchClient();
fetchFn = fetchProvider(kibanaIndex, mockLogger);
fetchFn = fetchProvider(getIndexForType, mockLogger);
});

test('returns when ES returns no results', async () => {
Expand Down
Loading

0 comments on commit 93e96aa

Please sign in to comment.