Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Deprecations] Logs Sources settings in all spaces #203042

Merged
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
0f800e6
[Deprecations] Logs Sources settings in all spaces
afharo Dec 5, 2024
4721ac5
Add TSDocs
afharo Dec 5, 2024
08c00be
Fix i18n labels
afharo Dec 5, 2024
61489d8
Fix types (mocks)
afharo Dec 5, 2024
08bf159
Fix types (mocks)
afharo Dec 5, 2024
79969b2
[Deprecations] Logs Sources settings in all spaces
afharo Dec 5, 2024
8e2dde0
Add TSDocs
afharo Dec 5, 2024
2ca3ce9
Fix i18n labels
afharo Dec 5, 2024
cac8be0
Fix types (mocks)
afharo Dec 5, 2024
acf77fd
Fix types (mocks)
afharo Dec 5, 2024
88ce365
Merge branch 'deprecations/log-sources-check-in-all-spaces' of github…
afharo Dec 10, 2024
6dae433
Merge branch 'main' of github.com:elastic/kibana into deprecations/lo…
afharo Dec 10, 2024
032f3b8
Fix docs + add unit tests
afharo Dec 10, 2024
b2bf260
Fix types
afharo Dec 10, 2024
cb0176b
Merge branch 'main' of github.com:elastic/kibana into deprecations/lo…
afharo Dec 10, 2024
dc649a8
Merge branch 'main' of github.com:elastic/kibana into deprecations/lo…
afharo Dec 11, 2024
cf9687e
Use `spaces.getAll()` API instead of new one from core
afharo Dec 11, 2024
1e5777d
[CI] Auto-commit changed files from 'node scripts/notice'
kibanamachine Dec 11, 2024
212ea7d
[CI] Auto-commit changed files from 'node scripts/yarn_deduplicate'
kibanamachine Dec 11, 2024
d759cbd
Fix types
afharo Dec 11, 2024
024bb68
Fix mock
afharo Dec 11, 2024
11716b9
Fix mock
afharo Dec 12, 2024
b0ad7c1
Fix another mock
afharo Dec 12, 2024
7776e31
Merge branch 'main' into deprecations/log-sources-check-in-all-spaces
afharo Dec 12, 2024
339a047
Merge branch 'main' into deprecations/log-sources-check-in-all-spaces
afharo Dec 16, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import type {
DeprecationsRequestHandlerContext,
DeprecationsClient,
} from '@kbn/core-deprecations-server';
import type { KibanaRequest } from '@kbn/core-http-server';
import type { InternalDeprecationsServiceStart } from './deprecations_service';

/**
Expand All @@ -25,14 +26,16 @@ export class CoreDeprecationsRouteHandlerContext implements DeprecationsRequestH
constructor(
private readonly deprecationsStart: InternalDeprecationsServiceStart,
private readonly elasticsearchRouterHandlerContext: CoreElasticsearchRouteHandlerContext,
private readonly savedObjectsRouterHandlerContext: CoreSavedObjectsRouteHandlerContext
private readonly savedObjectsRouterHandlerContext: CoreSavedObjectsRouteHandlerContext,
private readonly request: KibanaRequest
) {}

public get client() {
if (this.#client == null) {
this.#client = this.deprecationsStart.asScopedToClient(
this.elasticsearchRouterHandlerContext.client,
this.savedObjectsRouterHandlerContext.client
this.savedObjectsRouterHandlerContext.client,
this.request
);
}
return this.#client;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
registerConfigDeprecationsInfoMock,
} from './deprecations_service.test.mocks';
import { mockCoreContext } from '@kbn/core-base-server-mocks';
import { httpServiceMock } from '@kbn/core-http-server-mocks';
import { httpServerMock, httpServiceMock } from '@kbn/core-http-server-mocks';
import { coreUsageDataServiceMock } from '@kbn/core-usage-data-server-mocks';
import { configServiceMock } from '@kbn/config-mocks';
import { savedObjectsClientMock } from '@kbn/core-saved-objects-api-server-mocks';
Expand Down Expand Up @@ -83,12 +83,13 @@ describe('DeprecationsService', () => {
it('returns client with #getAllDeprecations method', async () => {
const esClient = elasticsearchServiceMock.createScopedClusterClient();
const savedObjectsClient = savedObjectsClientMock.create();
const request = httpServerMock.createKibanaRequest();
const deprecationsService = new DeprecationsService(coreContext);

await deprecationsService.setup(deprecationsCoreSetupDeps);

const start = deprecationsService.start();
const deprecationsClient = start.asScopedToClient(esClient, savedObjectsClient);
const deprecationsClient = start.asScopedToClient(esClient, savedObjectsClient, request);

expect(deprecationsClient.getAllDeprecations).toBeDefined();
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import type {
DeprecationsClient,
} from '@kbn/core-deprecations-server';
import { InternalCoreUsageDataSetup } from '@kbn/core-usage-data-base-server-internal';
import type { KibanaRequest } from '@kbn/core-http-server';
import { DeprecationsFactory } from './deprecations_factory';
import { registerRoutes } from './routes';
import { config as deprecationConfig, DeprecationConfigType } from './deprecation_config';
Expand All @@ -32,7 +33,8 @@ export interface InternalDeprecationsServiceStart {
*/
asScopedToClient(
esClient: IScopedClusterClient,
savedObjectsClient: SavedObjectsClientContract
savedObjectsClient: SavedObjectsClientContract,
request: KibanaRequest
): DeprecationsClient;
}

Expand Down Expand Up @@ -113,13 +115,19 @@ export class DeprecationsService

private createScopedDeprecations(): (
esClient: IScopedClusterClient,
savedObjectsClient: SavedObjectsClientContract
savedObjectsClient: SavedObjectsClientContract,
request: KibanaRequest
) => DeprecationsClient {
return (esClient: IScopedClusterClient, savedObjectsClient: SavedObjectsClientContract) => {
return (
esClient: IScopedClusterClient,
savedObjectsClient: SavedObjectsClientContract,
request: KibanaRequest
) => {
return {
getAllDeprecations: this.deprecationsFactory!.getAllDeprecations.bind(null, {
savedObjectsClient,
esClient,
request,
}),
};
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import type { MaybePromise } from '@kbn/utility-types';
import type { DeprecationsDetails } from '@kbn/core-deprecations-common';
import type { IScopedClusterClient } from '@kbn/core-elasticsearch-server';
import type { SavedObjectsClientContract } from '@kbn/core-saved-objects-api-server';
import type { KibanaRequest } from '@kbn/core-http-server';

/**
* The deprecations service provides a way for the Kibana platform to communicate deprecated
Expand Down Expand Up @@ -103,6 +104,7 @@ export interface RegisterDeprecationsConfig {
export interface GetDeprecationsContext {
esClient: IScopedClusterClient;
savedObjectsClient: SavedObjectsClientContract;
request: KibanaRequest;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"@kbn/core-deprecations-common",
"@kbn/core-elasticsearch-server",
"@kbn/core-saved-objects-api-server",
"@kbn/core-http-server",
],
"exclude": [
"target/**/*",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,8 @@ export class CoreRouteHandlerContext implements CoreRequestHandlerContext {
this.#deprecations = new CoreDeprecationsRouteHandlerContext(
this.coreStart.deprecations,
this.elasticsearch,
this.savedObjects
this.savedObjects,
this.request
);
}
return this.#deprecations;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,24 +15,23 @@ import {

import { SavedObjectsRepository } from './repository';
import { loggerMock } from '@kbn/logging-mocks';
import { SavedObjectsSerializer } from '@kbn/core-saved-objects-base-server-internal';
import { kibanaMigratorMock } from '../mocks';
import { elasticsearchClientMock } from '@kbn/core-elasticsearch-client-server-mocks';

import {
mockTimestamp,
mappings,
createRegistry,
createDocumentMigrator,
createSpySerializer,
} from '../test_helpers/repository.test.common';
import type { ISavedObjectsRepository } from '@kbn/core-saved-objects-api-server';
import { ISavedObjectsSpacesExtension } from '@kbn/core-saved-objects-server';
import { savedObjectsExtensionsMock } from '../mocks/saved_objects_extensions.mock';

describe('SavedObjectsRepository', () => {
let client: ReturnType<typeof elasticsearchClientMock.createElasticsearchClient>;
let repository: SavedObjectsRepository;
let repository: ISavedObjectsRepository;
let migrator: ReturnType<typeof kibanaMigratorMock.create>;
let logger: ReturnType<typeof loggerMock.create>;
let serializer: jest.Mocked<SavedObjectsSerializer>;

const registry = createRegistry();
const documentMigrator = createDocumentMigrator(registry);
Expand All @@ -46,23 +45,13 @@ describe('SavedObjectsRepository', () => {
migrator.runMigrations = jest.fn().mockResolvedValue([{ status: 'skipped' }]);
logger = loggerMock.create();

// create a mock serializer "shim" so we can track function calls, but use the real serializer's implementation
serializer = createSpySerializer(registry);

const allTypes = registry.getAllTypes().map((type) => type.name);
const allowedTypes = [...new Set(allTypes.filter((type) => !registry.isHidden(type)))];

// @ts-expect-error must use the private constructor to use the mocked serializer
repository = new SavedObjectsRepository({
index: '.kibana-test',
mappings,
client,
repository = SavedObjectsRepository.createRepository(
migrator,
typeRegistry: registry,
serializer,
allowedTypes,
logger,
});
registry,
'.kibana-test',
client,
logger
);

mockGetCurrentTime.mockReturnValue(mockTimestamp);
mockGetSearchDsl.mockClear();
Expand All @@ -87,4 +76,60 @@ describe('SavedObjectsRepository', () => {
expect(repository.getCurrentNamespace('space-a')).toBe('space-a');
});
});

describe('#asScopedToNamespace', () => {
it('returns a new client with undefined spacesExtensions (not available)', () => {
const scopedRepository = repository.asScopedToNamespace('space-a');
expect(scopedRepository).toBeInstanceOf(SavedObjectsRepository);
expect(scopedRepository).not.toStrictEqual(repository);

// Checking extensions.spacesExtension are both undefined
// @ts-expect-error type is ISavedObjectsRepository, but in reality is SavedObjectsRepository
expect(repository.extensions.spacesExtension).toBeUndefined();
// @ts-expect-error type is ISavedObjectsRepository, but in reality is SavedObjectsRepository
expect(scopedRepository.extensions.spacesExtension).toBeUndefined();
// @ts-expect-error type is ISavedObjectsRepository, but in reality is SavedObjectsRepository
expect(scopedRepository.extensions.spacesExtension).toStrictEqual(
// @ts-expect-error type is ISavedObjectsRepository, but in reality is SavedObjectsRepository
repository.extensions.spacesExtension
);
});
});

describe('with spacesExtension', () => {
let spacesExtension: jest.Mocked<ISavedObjectsSpacesExtension>;

beforeEach(() => {
spacesExtension = savedObjectsExtensionsMock.createSpacesExtension();
repository = SavedObjectsRepository.createRepository(
migrator,
registry,
'.kibana-test',
client,
logger,
[],
{ spacesExtension }
);
});

describe('#asScopedToNamespace', () => {
it('returns a new client with space-scoped spacesExtensions', () => {
const scopedRepository = repository.asScopedToNamespace('space-a');
expect(scopedRepository).toBeInstanceOf(SavedObjectsRepository);
expect(scopedRepository).not.toStrictEqual(repository);
expect(spacesExtension.asScopedToNamespace).toHaveBeenCalledWith('space-a');

// Checking extensions.spacesExtension are both defined but different
// @ts-expect-error type is ISavedObjectsRepository, but in reality is SavedObjectsRepository
expect(repository.extensions.spacesExtension).not.toBeUndefined();
// @ts-expect-error type is ISavedObjectsRepository, but in reality is SavedObjectsRepository
expect(scopedRepository.extensions.spacesExtension).not.toBeUndefined();
// @ts-expect-error type is ISavedObjectsRepository, but in reality is SavedObjectsRepository
expect(scopedRepository.extensions.spacesExtension).not.toStrictEqual(
// @ts-expect-error type is ISavedObjectsRepository, but in reality is SavedObjectsRepository
repository.extensions.spacesExtension
);
});
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ export class SavedObjectsRepository implements ISavedObjectsRepository {
});
}

private constructor(options: SavedObjectsRepositoryOptions) {
private constructor(private readonly options: SavedObjectsRepositoryOptions) {
const {
index,
mappings,
Expand Down Expand Up @@ -564,4 +564,17 @@ export class SavedObjectsRepository implements ISavedObjectsRepository {
getCurrentNamespace(namespace?: string) {
return this.helpers.common.getCurrentNamespace(namespace);
}

/**
* {@inheritDoc ISavedObjectsRepository.asScopedToNamespace}
*/
asScopedToNamespace(namespace: string) {
return new SavedObjectsRepository({
...this.options,
extensions: {
...this.options.extensions,
spacesExtension: this.extensions.spacesExtension?.asScopedToNamespace(namespace),
},
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ const createRepositoryMock = () => {
collectMultiNamespaceReferences: jest.fn(),
updateObjectsSpaces: jest.fn(),
getCurrentNamespace: jest.fn(),
asScopedToNamespace: jest.fn().mockImplementation(createRepositoryMock),
};

return mock;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ const createSecurityExtension = (): jest.Mocked<ISavedObjectsSecurityExtension>

const createSpacesExtension = (): jest.Mocked<ISavedObjectsSpacesExtension> => ({
getCurrentNamespace: jest.fn(),
getSearchableNamespaces: jest.fn(),
asScopedToNamespace: jest.fn().mockImplementation(createSpacesExtension),
});

const create = () => ({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -335,4 +335,12 @@ describe('SavedObjectsClient', () => {
expect(client.getCurrentNamespace()).toEqual('ns');
expect(mockRepository.getCurrentNamespace).toHaveBeenCalledWith();
});

test('#asScopedToNamespace', () => {
const client = new SavedObjectsClient(mockRepository);

const rescopedClient = client.asScopedToNamespace('ns');
expect(rescopedClient).not.toStrictEqual(client);
expect(mockRepository.asScopedToNamespace).toHaveBeenCalledWith('ns');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -216,4 +216,9 @@ export class SavedObjectsClient implements SavedObjectsClientContract {
getCurrentNamespace() {
return this._repository.getCurrentNamespace();
}

/** {@inheritDoc SavedObjectsClientContract.asScopedToNamespace} */
asScopedToNamespace(namespace: string) {
return new SavedObjectsClient(this._repository.asScopedToNamespace(namespace));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const create = () => {
collectMultiNamespaceReferences: jest.fn(),
updateObjectsSpaces: jest.fn(),
getCurrentNamespace: jest.fn(),
asScopedToNamespace: jest.fn().mockImplementation(create),
};

mock.createPointInTimeFinder = savedObjectsPointInTimeFinderMock.create({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,10 @@
*/

import type { SavedObjectsClientContract } from '@kbn/core-saved-objects-api-server';
import { SavedObjectsErrorHelpers } from '@kbn/core-saved-objects-server';
import { savedObjectsPointInTimeFinderMock } from './point_in_time_finder.mock';

const create = () => {
const mock = {
errors: SavedObjectsErrorHelpers,
const mock: jest.Mocked<SavedObjectsClientContract> = {
create: jest.fn(),
bulkCreate: jest.fn(),
checkConflicts: jest.fn(),
Expand All @@ -33,7 +31,8 @@ const create = () => {
collectMultiNamespaceReferences: jest.fn(),
updateObjectsSpaces: jest.fn(),
getCurrentNamespace: jest.fn(),
} as unknown as jest.Mocked<SavedObjectsClientContract>;
asScopedToNamespace: jest.fn().mockImplementation(create),
};

mock.createPointInTimeFinder = savedObjectsPointInTimeFinderMock.create({
savedObjectsMock: mock,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ const createSecurityExtension = (): jest.Mocked<ISavedObjectsSecurityExtension>

const createSpacesExtension = (): jest.Mocked<ISavedObjectsSpacesExtension> => ({
getCurrentNamespace: jest.fn(),
getSearchableNamespaces: jest.fn(),
asScopedToNamespace: jest.fn().mockImplementation(createSpacesExtension),
});

const create = (): jest.Mocked<SavedObjectsExtensions> => ({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -427,4 +427,10 @@ export interface SavedObjectsClientContract {
* Returns the namespace associated with the client. If the namespace is the default one, this method returns `undefined`.
*/
getCurrentNamespace(): string | undefined;

/**
* Returns a clone of the current Saved Objects client but scoped to the specified namespace.
* @param namespace Space to which the client should be scoped to.
*/
asScopedToNamespace(namespace: string): SavedObjectsClientContract;
}
Original file line number Diff line number Diff line change
Expand Up @@ -552,4 +552,10 @@ export interface ISavedObjectsRepository {
* namespace.
*/
getCurrentNamespace(namespace?: string): string | undefined;

/**
* Returns a new Saved Objects repository scoped to the specified namespace.
* @param namespace Space to which the repository should be scoped to.
*/
asScopedToNamespace(namespace: string): ISavedObjectsRepository;
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ export interface ISavedObjectsSpacesExtension {
*/
getCurrentNamespace: (namespace: string | undefined) => string | undefined;
/**
* Given a list of namespace strings, returns a subset that the user is authorized to search in.
* If a wildcard '*' is used, it is expanded to an explicit list of namespace strings.
* Returns a new Saved Objects Spaces Extension scoped to the specified namespace.
* @param namespace Space to which the extension should be scoped to.
*/
getSearchableNamespaces: (namespaces: string[] | undefined) => Promise<string[]>;
asScopedToNamespace(namespace: string): ISavedObjectsSpacesExtension;
}
Loading