From 6b53cfbaddca90031c55ab5f4cb21b1ec969b58d Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Mon, 22 Apr 2019 15:51:24 -0400 Subject: [PATCH 01/68] crude test updates --- x-pack/plugins/security/index.d.ts | 11 ++ x-pack/plugins/spaces/index.ts | 137 +++++++++--------- .../server/lib/create_default_space.test.ts | 41 ++++-- .../spaces/server/lib/create_default_space.ts | 17 ++- .../server/lib/create_spaces_service.test.ts | 74 ---------- .../server/lib/create_spaces_service.ts | 50 ------- .../lib/get_spaces_usage_collector.test.ts | 28 +++- .../server/lib/get_spaces_usage_collector.ts | 34 ++++- .../server/lib/request_inteceptors/index.ts | 20 ++- .../on_post_auth_interceptor.test.ts | 86 ++++++++--- .../on_post_auth_interceptor.ts | 49 +++---- .../on_request_interceptor.test.ts | 44 +++++- .../on_request_interceptor.ts | 8 +- .../server/lib/route_pre_check_license.ts | 10 +- .../saved_objects_client_wrapper_factory.ts | 4 +- .../spaces_saved_objects_client.test.ts | 80 ++++++---- .../spaces_saved_objects_client.ts | 4 +- .../spaces_tutorial_context_factory.test.ts | 60 +++++++- .../lib/spaces_tutorial_context_factory.ts | 4 +- .../spaces/server/new_platform/index.ts | 12 ++ .../spaces/server/new_platform/plugin.ts | 111 ++++++++++++++ .../new_platform/spaces_service/index.ts | 7 + .../spaces_service/spaces_service.ts | 103 +++++++++++++ .../api/__fixtures__/create_test_handler.ts | 76 +++++++--- .../spaces/server/routes/api/public/delete.ts | 15 +- .../spaces/server/routes/api/public/get.ts | 31 ++-- .../spaces/server/routes/api/public/index.ts | 35 ++++- .../spaces/server/routes/api/public/post.ts | 21 +-- .../spaces/server/routes/api/public/put.ts | 15 +- .../spaces/server/routes/api/v1/index.ts | 31 +++- .../spaces/server/routes/api/v1/spaces.ts | 18 +-- x-pack/typings/hapi.d.ts | 2 + 32 files changed, 830 insertions(+), 408 deletions(-) create mode 100644 x-pack/plugins/security/index.d.ts delete mode 100644 x-pack/plugins/spaces/server/lib/create_spaces_service.test.ts delete mode 100644 x-pack/plugins/spaces/server/lib/create_spaces_service.ts create mode 100644 x-pack/plugins/spaces/server/new_platform/index.ts create mode 100644 x-pack/plugins/spaces/server/new_platform/plugin.ts create mode 100644 x-pack/plugins/spaces/server/new_platform/spaces_service/index.ts create mode 100644 x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts diff --git a/x-pack/plugins/security/index.d.ts b/x-pack/plugins/security/index.d.ts new file mode 100644 index 0000000000000..4d0eeae0e5aaa --- /dev/null +++ b/x-pack/plugins/security/index.d.ts @@ -0,0 +1,11 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { AuthorizationService } from './server/lib/authorization/service'; + +export interface SecurityPlugin { + authorization: AuthorizationService; +} diff --git a/x-pack/plugins/spaces/index.ts b/x-pack/plugins/spaces/index.ts index 3a05e246ddd5d..b9928356f2462 100644 --- a/x-pack/plugins/spaces/index.ts +++ b/x-pack/plugins/spaces/index.ts @@ -7,27 +7,49 @@ import { resolve } from 'path'; import { SavedObjectsService } from 'src/legacy/server/saved_objects'; +import { PluginInitializerContext, HttpServiceSetup } from 'src/core/server'; +// @ts-ignore +import KbnServer, { Server } from 'src/legacy/server/kbn_server'; +import { ElasticsearchPlugin } from 'src/legacy/core_plugins/elasticsearch'; // @ts-ignore import { AuditLogger } from '../../server/lib/audit_logger'; // @ts-ignore import { watchStatusAndLicenseToInitialize } from '../../server/lib/watch_status_and_license_to_initialize'; import mappings from './mappings.json'; -import { SpacesAuditLogger } from './server/lib/audit_logger'; -import { checkLicense } from './server/lib/check_license'; -import { createDefaultSpace } from './server/lib/create_default_space'; -import { createSpacesService } from './server/lib/create_spaces_service'; import { wrapError } from './server/lib/errors'; import { getActiveSpace } from './server/lib/get_active_space'; import { getSpaceSelectorUrl } from './server/lib/get_space_selector_url'; -import { getSpacesUsageCollector } from './server/lib/get_spaces_usage_collector'; import { migrateToKibana660 } from './server/lib/migrations'; -import { initSpacesRequestInterceptors } from './server/lib/request_inteceptors'; -import { spacesSavedObjectsClientWrapperFactory } from './server/lib/saved_objects_client/saved_objects_client_wrapper_factory'; -import { SpacesClient } from './server/lib/spaces_client'; -import { createSpacesTutorialContextFactory } from './server/lib/spaces_tutorial_context_factory'; import { toggleUICapabilities } from './server/lib/toggle_ui_capabilities'; -import { initPublicSpacesApi } from './server/routes/api/public'; -import { initPrivateApis } from './server/routes/api/v1'; +import { plugin } from './server/new_platform'; +import { XPackMainPlugin } from '../xpack_main/xpack_main'; +import { SecurityPlugin } from '../security'; +import { SpacesPlugin } from './types'; + +export interface SpacesCoreSetup { + http: HttpServiceSetup; + xpackMain: XPackMainPlugin; + security: SecurityPlugin; + savedObjects: SavedObjectsService; + spaces: SpacesPlugin; + elasticsearch: ElasticsearchPlugin; + usage: { + collectorSet: { + register: (collector: any) => void; + }; + }; + tutorial: { + addScopedTutorialContextFactory: (factory: any) => void; + }; +} + +export interface SpacesConfig { + get: (key: string) => string; +} + +export interface SpacesInitializerContext extends PluginInitializerContext { + legacyConfig: SpacesConfig; +} export const spaces = (kibana: Record) => new kibana.Plugin({ @@ -86,7 +108,7 @@ export const spaces = (kibana: Record) => request: Record, server: Record ) { - const spacesClient = server.plugins.spaces.spacesClient.getScopedClient(request); + const spacesClient = server.plugins.spaces.spacesClient.scopedClient(request); try { vars.activeSpace = { valid: true, @@ -116,69 +138,40 @@ export const spaces = (kibana: Record) => }, }, - async init(server: any) { - const thisPlugin = this; - const xpackMainPlugin = server.plugins.xpack_main; - - watchStatusAndLicenseToInitialize(xpackMainPlugin, thisPlugin, async () => { - await createDefaultSpace(server); - }); - - // Register a function that is called whenever the xpack info changes, - // to re-compute the license check results for this plugin. - xpackMainPlugin.info - .feature(thisPlugin.id) - .registerLicenseCheckResultsGenerator(checkLicense); - - const spacesService = createSpacesService(server); - server.expose('getSpaceId', (request: any) => spacesService.getSpaceId(request)); - - const config = server.config(); - - const spacesAuditLogger = new SpacesAuditLogger(config, new AuditLogger(server, 'spaces')); - - server.expose('spacesClient', { - getScopedClient: (request: Record) => { - const adminCluster = server.plugins.elasticsearch.getCluster('admin'); - const { callWithRequest, callWithInternalUser } = adminCluster; - const callCluster = (...args: any[]) => callWithRequest(request, ...args); - const { savedObjects } = server; - const internalRepository = savedObjects.getSavedObjectsRepository(callWithInternalUser); - const callWithRequestRepository = savedObjects.getSavedObjectsRepository(callCluster); - const authorization = server.plugins.security - ? server.plugins.security.authorization - : null; - return new SpacesClient( - spacesAuditLogger, - (message: string) => { - server.log(['spaces', 'debug'], message); - }, - authorization, - callWithRequestRepository, - server.config(), - internalRepository, - request - ); + async init(server: Server) { + const kbnServer = (server as unknown) as KbnServer; + const initializerContext = ({ + legacyConfig: server.config(), + logger: { + get: (context: string) => ({ + debug: (message: any) => server.log([context, 'debug'], message), + info: (message: any) => server.log([context, 'info'], message), + warning: (message: any) => server.log([context, 'warning'], message), + error: (message: any) => server.log([context, 'error'], message), + }), }, - }); - - const { - addScopedSavedObjectsClientWrapperFactory, - types, - } = server.savedObjects as SavedObjectsService; - addScopedSavedObjectsClientWrapperFactory( - Number.MAX_VALUE, - spacesSavedObjectsClientWrapperFactory(spacesService, types) - ); - - server.addScopedTutorialContextFactory(createSpacesTutorialContextFactory(spacesService)); + } as unknown) as SpacesInitializerContext; + + const core = { + http: kbnServer.newPlatform.setup.core.http, + elasticsearch: server.plugins.elasticsearch, + xpackMain: server.plugins.xpack_main, + spaces: this, + security: server.plugins.security, + savedObjects: server.savedObjects, + usage: (server as any).usage, + tutorial: { + addScopedTutorialContextFactory: (server as any).addScopedTutorialContextFactory, + }, + } as SpacesCoreSetup; - initPrivateApis(server); - initPublicSpacesApi(server); + // Need legacy because of `setup_base_path_provider` + // (request.getBasePath and request.setBasePath) + core.http.server = kbnServer as any; - initSpacesRequestInterceptors(server); + const { spacesService } = await plugin(initializerContext).setup(core); - // Register a function with server to manage the collection of usage stats - server.usage.collectorSet.register(getSpacesUsageCollector(server)); + server.expose('getSpaceId', (request: any) => spacesService.getSpaceId(request)); + server.expose('spacesClient', spacesService); }, }); diff --git a/x-pack/plugins/spaces/server/lib/create_default_space.test.ts b/x-pack/plugins/spaces/server/lib/create_default_space.test.ts index 11ab5e71a0ea4..6e88d3a7929eb 100644 --- a/x-pack/plugins/spaces/server/lib/create_default_space.test.ts +++ b/x-pack/plugins/spaces/server/lib/create_default_space.test.ts @@ -11,6 +11,8 @@ import Boom from 'boom'; // @ts-ignore import { getClient } from '../../../../server/lib/get_client_shield'; import { createDefaultSpace } from './create_default_space'; +import { ElasticsearchPlugin } from 'src/legacy/core_plugins/elasticsearch'; +import { SavedObjectsService } from 'src/legacy/server/kbn_server'; let mockCallWithRequest; beforeEach(() => { @@ -26,7 +28,7 @@ interface MockServerSettings { simulateConflict?: boolean; [invalidKeys: string]: any; } -const createMockServer = (settings: MockServerSettings = {}) => { +const createMockDeps = (settings: MockServerSettings = {}) => { const { defaultExists = false, simulateGetErrorCondition = false, @@ -80,17 +82,26 @@ const createMockServer = (settings: MockServerSettings = {}) => { return settings[key]; }); - return mockServer; + return { + config: mockServer.config(), + savedObjects: (mockServer.savedObjects as unknown) as SavedObjectsService, + elasticsearch: ({ + getCluster: jest.fn().mockReturnValue({ + callWithRequest: jest.fn(), + callWithInternalUser: jest.fn(), + }), + } as unknown) as ElasticsearchPlugin, + }; }; test(`it creates the default space when one does not exist`, async () => { - const server = createMockServer({ + const deps = createMockDeps({ defaultExists: false, }); - await createDefaultSpace(server); + await createDefaultSpace(deps); - const repository = server.savedObjects.getSavedObjectsRepository(); + const repository = deps.savedObjects.getSavedObjectsRepository(); expect(repository.get).toHaveBeenCalledTimes(1); expect(repository.create).toHaveBeenCalledTimes(1); @@ -108,46 +119,46 @@ test(`it creates the default space when one does not exist`, async () => { }); test(`it does not attempt to recreate the default space if it already exists`, async () => { - const server = createMockServer({ + const deps = createMockDeps({ defaultExists: true, }); - await createDefaultSpace(server); + await createDefaultSpace(deps); - const repository = server.savedObjects.getSavedObjectsRepository(); + const repository = deps.savedObjects.getSavedObjectsRepository(); expect(repository.get).toHaveBeenCalledTimes(1); expect(repository.create).toHaveBeenCalledTimes(0); }); test(`it throws all other errors from the saved objects client when checking for the default space`, async () => { - const server = createMockServer({ + const deps = createMockDeps({ defaultExists: true, simulateGetErrorCondition: true, }); - expect(createDefaultSpace(server)).rejects.toThrowErrorMatchingSnapshot(); + expect(createDefaultSpace(deps)).rejects.toThrowErrorMatchingSnapshot(); }); test(`it ignores conflict errors if the default space already exists`, async () => { - const server = createMockServer({ + const deps = createMockDeps({ defaultExists: false, simulateConflict: true, }); - await createDefaultSpace(server); + await createDefaultSpace(deps); - const repository = server.savedObjects.getSavedObjectsRepository(); + const repository = deps.savedObjects.getSavedObjectsRepository(); expect(repository.get).toHaveBeenCalledTimes(1); expect(repository.create).toHaveBeenCalledTimes(1); }); test(`it throws other errors if there is an error creating the default space`, async () => { - const server = createMockServer({ + const deps = createMockDeps({ defaultExists: false, simulateCreateErrorCondition: true, }); - expect(createDefaultSpace(server)).rejects.toThrowErrorMatchingSnapshot(); + expect(createDefaultSpace(deps)).rejects.toThrowErrorMatchingSnapshot(); }); diff --git a/x-pack/plugins/spaces/server/lib/create_default_space.ts b/x-pack/plugins/spaces/server/lib/create_default_space.ts index fdcdbb1ef72b4..17a8dcf6da6bb 100644 --- a/x-pack/plugins/spaces/server/lib/create_default_space.ts +++ b/x-pack/plugins/spaces/server/lib/create_default_space.ts @@ -5,16 +5,21 @@ */ import { i18n } from '@kbn/i18n'; + +import { SavedObjectsService } from 'src/legacy/server/kbn_server'; // @ts-ignore -import { getClient } from '../../../../server/lib/get_client_shield'; +import { ElasticsearchPlugin } from 'src/legacy/core_plugins/elasticsearch'; import { DEFAULT_SPACE_ID } from '../../common/constants'; -export async function createDefaultSpace(server: any) { - const { callWithInternalUser: callCluster } = getClient(server); - - const { getSavedObjectsRepository, SavedObjectsClient } = server.savedObjects; +interface Deps { + elasticsearch: ElasticsearchPlugin; + savedObjects: SavedObjectsService; +} - const savedObjectsRepository = getSavedObjectsRepository(callCluster); +export async function createDefaultSpace({ elasticsearch, savedObjects }: Deps) { + const { getSavedObjectsRepository, SavedObjectsClient } = savedObjects; + const { callWithInternalUser } = elasticsearch.getCluster('admin'); + const savedObjectsRepository = getSavedObjectsRepository(callWithInternalUser); const defaultSpaceExists = await doesDefaultSpaceExist( SavedObjectsClient, diff --git a/x-pack/plugins/spaces/server/lib/create_spaces_service.test.ts b/x-pack/plugins/spaces/server/lib/create_spaces_service.test.ts deleted file mode 100644 index 23e4a3dd8c214..0000000000000 --- a/x-pack/plugins/spaces/server/lib/create_spaces_service.test.ts +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { DEFAULT_SPACE_ID } from '../../common/constants'; -import { createSpacesService } from './create_spaces_service'; - -const createRequest = (spaceId?: string, serverBasePath = '') => ({ - getBasePath: () => - spaceId && spaceId !== DEFAULT_SPACE_ID ? `${serverBasePath}/s/${spaceId}` : serverBasePath, -}); - -const createMockServer = (config: any) => { - return { - config: jest.fn(() => { - return { - get: jest.fn((key: string) => { - return config[key]; - }), - }; - }), - }; -}; - -test('returns the default space ID', () => { - const server = createMockServer({ - 'server.basePath': '', - }); - - const service = createSpacesService(server); - expect(service.getSpaceId(createRequest())).toEqual(DEFAULT_SPACE_ID); -}); - -test('returns the id for the current space', () => { - const request = createRequest('my-space-context'); - const server = createMockServer({ - 'server.basePath': '', - }); - - const service = createSpacesService(server); - expect(service.getSpaceId(request)).toEqual('my-space-context'); -}); - -test(`returns the id for the current space when a server basepath is defined`, () => { - const request = createRequest('my-space-context', '/foo'); - const server = createMockServer({ - 'server.basePath': '/foo', - }); - - const service = createSpacesService(server); - expect(service.getSpaceId(request)).toEqual('my-space-context'); -}); - -test(`returns true if the current space is the default one`, () => { - const request = createRequest(DEFAULT_SPACE_ID, '/foo'); - const server = createMockServer({ - 'server.basePath': '/foo', - }); - - const service = createSpacesService(server); - expect(service.isInDefaultSpace(request)).toEqual(true); -}); - -test(`returns false if the current space is not the default one`, () => { - const request = createRequest('my-space-context', '/foo'); - const server = createMockServer({ - 'server.basePath': '/foo', - }); - - const service = createSpacesService(server); - expect(service.isInDefaultSpace(request)).toEqual(false); -}); diff --git a/x-pack/plugins/spaces/server/lib/create_spaces_service.ts b/x-pack/plugins/spaces/server/lib/create_spaces_service.ts deleted file mode 100644 index 2e45d57639fd8..0000000000000 --- a/x-pack/plugins/spaces/server/lib/create_spaces_service.ts +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { DEFAULT_SPACE_ID } from '../../common/constants'; -import { getSpaceIdFromPath } from './spaces_url_parser'; - -export interface SpacesService { - isInDefaultSpace: (req: any) => boolean; - getSpaceId: (req: any) => string; -} - -export function createSpacesService(server: any): SpacesService { - const serverBasePath = server.config().get('server.basePath'); - - const contextCache = new WeakMap(); - - function getSpaceId(request: any) { - if (!contextCache.has(request)) { - populateCache(request); - } - - const { spaceId } = contextCache.get(request); - return spaceId; - } - - function isInDefaultSpace(request: any) { - if (!contextCache.has(request)) { - populateCache(request); - } - - return contextCache.get(request).isInDefaultSpace; - } - - function populateCache(request: any) { - const spaceId = getSpaceIdFromPath(request.getBasePath(), serverBasePath); - - contextCache.set(request, { - spaceId, - isInDefaultSpace: spaceId === DEFAULT_SPACE_ID, - }); - } - - return { - getSpaceId, - isInDefaultSpace, - }; -} diff --git a/x-pack/plugins/spaces/server/lib/get_spaces_usage_collector.test.ts b/x-pack/plugins/spaces/server/lib/get_spaces_usage_collector.test.ts index ef4cb9b01ec1e..eab43dbb4a073 100644 --- a/x-pack/plugins/spaces/server/lib/get_spaces_usage_collector.test.ts +++ b/x-pack/plugins/spaces/server/lib/get_spaces_usage_collector.test.ts @@ -84,7 +84,12 @@ test('sets enabled to false when spaces is turned off', async () => { }); const serverMock = getServerMock({ config: () => ({ get: mockConfigGet }) }); const callClusterMock = jest.fn(); - const { fetch: getSpacesUsage } = getSpacesUsageCollector(serverMock); + const { fetch: getSpacesUsage } = getSpacesUsageCollector({ + config: serverMock.config(), + savedObjects: serverMock.savedObjects, + usage: serverMock.usage, + xpackMain: serverMock.plugins.xpack_main, + }); const usageStats: UsageStats = await getSpacesUsage(callClusterMock); expect(usageStats.enabled).toBe(false); }); @@ -97,7 +102,12 @@ describe('with a basic license', async () => { .fn() .mockReturnValue('basic'); const callClusterMock = jest.fn(() => Promise.resolve({})); - const { fetch: getSpacesUsage } = getSpacesUsageCollector(serverWithBasicLicenseMock); + const { fetch: getSpacesUsage } = getSpacesUsageCollector({ + config: serverWithBasicLicenseMock.config(), + savedObjects: serverWithBasicLicenseMock.savedObjects, + usage: serverWithBasicLicenseMock.usage, + xpackMain: serverWithBasicLicenseMock.plugins.xpack_main, + }); usageStats = await getSpacesUsage(callClusterMock); }); @@ -120,7 +130,12 @@ describe('with no license', async () => { const serverWithNoLicenseMock = getServerMock(); serverWithNoLicenseMock.plugins.xpack_main.info.isAvailable = jest.fn().mockReturnValue(false); const callClusterMock = jest.fn(() => Promise.resolve({})); - const { fetch: getSpacesUsage } = getSpacesUsageCollector(serverWithNoLicenseMock); + const { fetch: getSpacesUsage } = getSpacesUsageCollector({ + config: serverWithNoLicenseMock.config(), + savedObjects: serverWithNoLicenseMock.savedObjects, + usage: serverWithNoLicenseMock.usage, + xpackMain: serverWithNoLicenseMock.plugins.xpack_main, + }); usageStats = await getSpacesUsage(callClusterMock); }); @@ -145,7 +160,12 @@ describe('with platinum license', async () => { .fn() .mockReturnValue('platinum'); const callClusterMock = jest.fn(() => Promise.resolve({})); - const { fetch: getSpacesUsage } = getSpacesUsageCollector(serverWithPlatinumLicenseMock); + const { fetch: getSpacesUsage } = getSpacesUsageCollector({ + config: serverWithPlatinumLicenseMock.config(), + savedObjects: serverWithPlatinumLicenseMock.savedObjects, + usage: serverWithPlatinumLicenseMock.usage, + xpackMain: serverWithPlatinumLicenseMock.plugins.xpack_main, + }); usageStats = await getSpacesUsage(callClusterMock); }); diff --git a/x-pack/plugins/spaces/server/lib/get_spaces_usage_collector.ts b/x-pack/plugins/spaces/server/lib/get_spaces_usage_collector.ts index bc34b69416121..83d31c9c223a0 100644 --- a/x-pack/plugins/spaces/server/lib/get_spaces_usage_collector.ts +++ b/x-pack/plugins/spaces/server/lib/get_spaces_usage_collector.ts @@ -3,6 +3,9 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ + +import { SavedObjectsService } from 'src/legacy/server/kbn_server'; +import { XPackMainPlugin } from '../../../xpack_main/xpack_main'; // @ts-ignore import { KIBANA_STATS_TYPE_MONITORING } from '../../../monitoring/common/constants'; import { KIBANA_SPACES_STATS_TYPE } from '../../common/constants'; @@ -15,12 +18,16 @@ import { KIBANA_SPACES_STATS_TYPE } from '../../common/constants'; * @param withinDayRange * @return {ReportingUsageStats} */ -async function getSpacesUsage(callCluster: any, server: any, spacesAvailable: boolean) { +async function getSpacesUsage( + callCluster: any, + savedObjects: SavedObjectsService, + spacesAvailable: boolean +) { if (!spacesAvailable) { return {}; } - const { getSavedObjectsRepository } = server.savedObjects; + const { getSavedObjectsRepository } = savedObjects; const savedObjectsRepository = getSavedObjectsRepository(callCluster); @@ -36,22 +43,33 @@ export interface UsageStats { enabled: boolean; count?: number; } + +interface CollectorDeps { + config: any; + usage: { collectorSet: any }; + savedObjects: SavedObjectsService; + xpackMain: XPackMainPlugin; +} + /* * @param {Object} server * @return {Object} kibana usage stats type collection object */ -export function getSpacesUsageCollector(server: any) { - const { collectorSet } = server.usage; +export function getSpacesUsageCollector(deps: CollectorDeps) { + const { collectorSet } = deps.usage; return collectorSet.makeUsageCollector({ type: KIBANA_SPACES_STATS_TYPE, fetch: async (callCluster: any) => { - const xpackInfo = server.plugins.xpack_main.info; - const config = server.config(); + const xpackInfo = deps.xpackMain.info; const available = xpackInfo && xpackInfo.isAvailable(); // some form of spaces is available for all valid licenses - const enabled = config.get('xpack.spaces.enabled'); + const enabled = deps.config.get('xpack.spaces.enabled'); const spacesAvailableAndEnabled = available && enabled; - const usageStats = await getSpacesUsage(callCluster, server, spacesAvailableAndEnabled); + const usageStats = await getSpacesUsage( + callCluster, + deps.savedObjects, + spacesAvailableAndEnabled + ); return { available, diff --git a/x-pack/plugins/spaces/server/lib/request_inteceptors/index.ts b/x-pack/plugins/spaces/server/lib/request_inteceptors/index.ts index 2687a2c16295d..d5969958a0da2 100644 --- a/x-pack/plugins/spaces/server/lib/request_inteceptors/index.ts +++ b/x-pack/plugins/spaces/server/lib/request_inteceptors/index.ts @@ -4,10 +4,22 @@ * you may not use this file except in compliance with the Elastic License. */ -import { initSpacesOnPostAuthRequestInterceptor } from './on_post_auth_interceptor'; +import { HttpServiceSetup, Logger } from 'src/core/server'; +import { SpacesConfig } from '../../..'; +import { XPackMainPlugin } from '../../../../xpack_main/xpack_main'; import { initSpacesOnRequestInterceptor } from './on_request_interceptor'; +import { initSpacesOnPostAuthRequestInterceptor } from './on_post_auth_interceptor'; +import { SpacesServiceSetup } from '../../new_platform/spaces_service/spaces_service'; + +export interface InterceptorDeps { + config: SpacesConfig; + http: HttpServiceSetup; + xpackMain: XPackMainPlugin; + spacesService: SpacesServiceSetup; + log: Logger; +} -export function initSpacesRequestInterceptors(server: any) { - initSpacesOnRequestInterceptor(server); - initSpacesOnPostAuthRequestInterceptor(server); +export function initSpacesRequestInterceptors(deps: InterceptorDeps) { + initSpacesOnRequestInterceptor(deps); + initSpacesOnPostAuthRequestInterceptor(deps); } diff --git a/x-pack/plugins/spaces/server/lib/request_inteceptors/on_post_auth_interceptor.test.ts b/x-pack/plugins/spaces/server/lib/request_inteceptors/on_post_auth_interceptor.test.ts index 0e6585ee48922..0bf849a21c01a 100644 --- a/x-pack/plugins/spaces/server/lib/request_inteceptors/on_post_auth_interceptor.test.ts +++ b/x-pack/plugins/spaces/server/lib/request_inteceptors/on_post_auth_interceptor.test.ts @@ -12,6 +12,11 @@ import { Feature } from '../../../../xpack_main/types'; import { convertSavedObjectToSpace } from '../../routes/lib'; import { initSpacesOnPostAuthRequestInterceptor } from './on_post_auth_interceptor'; import { initSpacesOnRequestInterceptor } from './on_request_interceptor'; +import { SpacesService } from '../../new_platform/spaces_service'; +import { ElasticsearchPlugin } from 'src/legacy/core_plugins/elasticsearch'; +import { SecurityPlugin } from '../../../../security'; +import { SpacesAuditLogger } from '../audit_logger'; +import { SpacesServiceSetup } from '../../new_platform/spaces_service/spaces_service'; describe('onPostAuthRequestInterceptor', () => { const sandbox = sinon.sandbox.create(); @@ -21,6 +26,7 @@ describe('onPostAuthRequestInterceptor', () => { }; let server: any; let request: any; + let spacesService: SpacesServiceSetup; const serverBasePath = '/'; const defaultRoute = '/app/custom-app'; @@ -77,9 +83,15 @@ describe('onPostAuthRequestInterceptor', () => { }; server.plugins = { + elasticsearch: { + getCluster: jest.fn().mockReturnValue({ + callWithInternalUser: jest.fn(), + callWithRequest: jest.fn(), + }), + }, spaces: { spacesClient: { - getScopedClient: jest.fn(), + scopedClient: jest.fn(), }, }, xpack_main: { @@ -115,11 +127,54 @@ describe('onPostAuthRequestInterceptor', () => { basePath = newPath; }); + const log = { + log: jest.fn(), + trace: jest.fn(), + debug: jest.fn(), + info: jest.fn(), + warn: jest.fn(), + error: jest.fn(), + fatal: jest.fn(), + }; + + const service = new SpacesService(log, server.config()); + spacesService = await service.setup({ + elasticsearch: server.plugins.elasticsearch as ElasticsearchPlugin, + savedObjects: server.savedObjects, + security: {} as SecurityPlugin, + spacesAuditLogger: {} as SpacesAuditLogger, + }); + + spacesService.scopedClient = jest.fn().mockReturnValue({ + getAll() { + return spaces.map(convertSavedObjectToSpace); + }, + get(spaceId: string) { + const space = spaces.find(s => s.id === spaceId); + if (!space) { + throw new Error('space not found'); + } + return convertSavedObjectToSpace(space); + }, + }); + // The onRequest interceptor is also included here because the onPostAuth interceptor requires the onRequest // interceptor to parse out the space id and rewrite the request's URL. Rather than duplicating that logic, // we are including the already tested interceptor here in the test chain. - initSpacesOnRequestInterceptor(server); - initSpacesOnPostAuthRequestInterceptor(server); + initSpacesOnRequestInterceptor({ + config: server.config(), + http: { server } as any, + log, + xpackMain: server.plugins.xpack_main, + spacesService, + }); + initSpacesOnPostAuthRequestInterceptor({ + config: server.config(), + http: { server } as any, + log, + xpackMain: server.plugins.xpack_main, + spacesService, + }); server.route([ { @@ -147,19 +202,6 @@ describe('onPostAuthRequestInterceptor', () => { teardowns.push(() => server.stop()); - server.plugins.spaces.spacesClient.getScopedClient.mockReturnValue({ - getAll() { - return spaces.map(convertSavedObjectToSpace); - }, - get(spaceId: string) { - const space = spaces.find(s => s.id === spaceId); - if (!space) { - throw new Error('space not found'); - } - return convertSavedObjectToSpace(space); - }, - }); - await setupFn(server); return await server.inject({ @@ -245,7 +287,7 @@ describe('onPostAuthRequestInterceptor', () => { expect(response.statusCode).toEqual(302); expect(response.headers.location).toEqual(`${serverBasePath}/s/a-space${defaultRoute}`); - expect(server.plugins.spaces.spacesClient.getScopedClient).toHaveBeenCalledWith( + expect(spacesService.scopedClient).toHaveBeenCalledWith( expect.objectContaining({ headers: expect.objectContaining({ authorization: headers.authorization, @@ -273,7 +315,7 @@ describe('onPostAuthRequestInterceptor', () => { expect(response.statusCode).toEqual(302); expect(response.headers.location).toEqual(`${serverBasePath}${defaultRoute}`); - expect(server.plugins.spaces.spacesClient.getScopedClient).toHaveBeenCalledWith( + expect(spacesService.scopedClient).toHaveBeenCalledWith( expect.objectContaining({ headers: expect.objectContaining({ authorization: headers.authorization, @@ -298,7 +340,7 @@ describe('onPostAuthRequestInterceptor', () => { expect(response.statusCode).toEqual(200); - expect(server.plugins.spaces.spacesClient.getScopedClient).toHaveBeenCalledWith( + expect(spacesService.scopedClient).toHaveBeenCalledWith( expect.objectContaining({ headers: expect.objectContaining({ authorization: headers.authorization, @@ -323,7 +365,7 @@ describe('onPostAuthRequestInterceptor', () => { expect(response.statusCode).toEqual(200); - expect(server.plugins.spaces.spacesClient.getScopedClient).toHaveBeenCalledWith( + expect(spacesService.scopedClient).toHaveBeenCalledWith( expect.objectContaining({ headers: expect.objectContaining({ authorization: headers.authorization, @@ -348,7 +390,7 @@ describe('onPostAuthRequestInterceptor', () => { expect(response.statusCode).toEqual(404); - expect(server.plugins.spaces.spacesClient.getScopedClient).toHaveBeenCalledWith( + expect(spacesService.scopedClient).toHaveBeenCalledWith( expect.objectContaining({ headers: expect.objectContaining({ authorization: headers.authorization, @@ -392,7 +434,7 @@ describe('onPostAuthRequestInterceptor', () => { expect(getHiddenUiAppHandler).toHaveBeenCalledTimes(1); expect(getHiddenUiAppHandler).toHaveBeenCalledWith('space_selector'); - expect(server.plugins.spaces.spacesClient.getScopedClient).toHaveBeenCalledWith( + expect(spacesService.scopedClient).toHaveBeenCalledWith( expect.objectContaining({ headers: expect.objectContaining({ authorization: headers.authorization, diff --git a/x-pack/plugins/spaces/server/lib/request_inteceptors/on_post_auth_interceptor.ts b/x-pack/plugins/spaces/server/lib/request_inteceptors/on_post_auth_interceptor.ts index c5aaded074c34..f506d77940f0e 100644 --- a/x-pack/plugins/spaces/server/lib/request_inteceptors/on_post_auth_interceptor.ts +++ b/x-pack/plugins/spaces/server/lib/request_inteceptors/on_post_auth_interceptor.ts @@ -4,36 +4,36 @@ * you may not use this file except in compliance with the Elastic License. */ import Boom from 'boom'; -import { Server } from 'hapi'; import { Space } from '../../../common/model/space'; import { wrapError } from '../errors'; import { getSpaceSelectorUrl } from '../get_space_selector_url'; -import { SpacesClient } from '../spaces_client'; import { addSpaceIdToPath, getSpaceIdFromPath } from '../spaces_url_parser'; - -interface KbnServer extends Server { - getHiddenUiAppById: (appId: string) => any; -} - -export function initSpacesOnPostAuthRequestInterceptor(server: KbnServer) { - const serverBasePath: string = server.config().get('server.basePath'); - const xpackMainPlugin = server.plugins.xpack_main; - - server.ext('onPostAuth', async function spacesOnPostAuthHandler(request: any, h: any) { +import { InterceptorDeps } from '.'; + +export function initSpacesOnPostAuthRequestInterceptor({ + config, + http, + xpackMain, + spacesService, + log, +}: InterceptorDeps) { + const serverBasePath: string = config.get('server.basePath'); + + http.server.ext('onPostAuth', async function spacesOnPostAuthHandler(request: any, h: any) { const path = request.path; const isRequestingKibanaRoot = path === '/'; const isRequestingApplication = path.startsWith('/app'); + const spacesClient = spacesService.scopedClient(request); + // if requesting the application root, then show the Space Selector UI to allow the user to choose which space // they wish to visit. This is done "onPostAuth" to allow the Saved Objects Client to use the request's auth scope, // which is not available at the time of "onRequest". if (isRequestingKibanaRoot) { try { - const spacesClient = server.plugins.spaces.spacesClient.getScopedClient(request); const spaces = await spacesClient.getAll(); - const config = server.config(); const basePath: string = config.get('server.basePath'); const defaultRoute: string = config.get('server.defaultRoute'); @@ -48,7 +48,7 @@ export function initSpacesOnPostAuthRequestInterceptor(server: KbnServer) { if (spaces.length > 0) { // render spaces selector instead of home page - const app = server.getHiddenUiAppById('space_selector'); + const app = http.server.getHiddenUiAppById('space_selector'); return (await h.renderApp(app, { spaces })).takeover(); } } catch (error) { @@ -62,30 +62,26 @@ export function initSpacesOnPostAuthRequestInterceptor(server: KbnServer) { let spaceId: string = ''; let space: Space; try { - const spacesClient: SpacesClient = server.plugins.spaces.spacesClient.getScopedClient( - request - ); spaceId = getSpaceIdFromPath(request.getBasePath(), serverBasePath); - server.log(['spaces', 'debug'], `Verifying access to space "${spaceId}"`); + log.debug(`Verifying access to space "${spaceId}"`); space = await spacesClient.get(spaceId); } catch (error) { - server.log( - ['spaces', 'error'], + log.error( `Unable to navigate to space "${spaceId}", redirecting to Space Selector. ${error}` ); // Space doesn't exist, or user not authorized for space, or some other issue retrieving the active space. - return h.redirect(getSpaceSelectorUrl(server.config())).takeover(); + return h.redirect(getSpaceSelectorUrl(config)).takeover(); } // Verify application is available in this space // The management page is always visible, so we shouldn't be restricting access to the kibana application in any situation. const appId = path.split('/', 3)[2]; if (appId !== 'kibana' && space && space.disabledFeatures.length > 0) { - server.log(['spaces', 'debug'], `Verifying application is available: "${appId}"`); + log.debug(`Verifying application is available: "${appId}"`); - const allFeatures = xpackMainPlugin.getFeatures(); + const allFeatures = xpackMain.getFeatures(); const isRegisteredApp = allFeatures.some(feature => feature.app.includes(appId)); if (isRegisteredApp) { @@ -95,10 +91,7 @@ export function initSpacesOnPostAuthRequestInterceptor(server: KbnServer) { const isAvailableInSpace = enabledFeatures.some(feature => feature.app.includes(appId)); if (!isAvailableInSpace) { - server.log( - ['spaces', 'error'], - `App ${appId} is not enabled within space "${spaceId}".` - ); + log.error(`App ${appId} is not enabled within space "${spaceId}".`); return Boom.notFound(); } } diff --git a/x-pack/plugins/spaces/server/lib/request_inteceptors/on_request_interceptor.test.ts b/x-pack/plugins/spaces/server/lib/request_inteceptors/on_request_interceptor.test.ts index a8868f805049f..29bc66b5d074b 100644 --- a/x-pack/plugins/spaces/server/lib/request_inteceptors/on_request_interceptor.test.ts +++ b/x-pack/plugins/spaces/server/lib/request_inteceptors/on_request_interceptor.test.ts @@ -8,6 +8,12 @@ import { Server } from 'hapi'; import sinon from 'sinon'; import { initSpacesOnRequestInterceptor } from './on_request_interceptor'; +import { SpacesService } from '../../new_platform/spaces_service'; +import { XPackMainPlugin } from '../../../../xpack_main/xpack_main'; +import { ElasticsearchPlugin } from 'src/legacy/core_plugins/elasticsearch'; +import { SecurityPlugin } from '../../../../security'; +import { SpacesAuditLogger } from '../audit_logger'; +import { SpacesServiceSetup } from '../../new_platform/spaces_service/spaces_service'; describe('onRequestInterceptor', () => { const sandbox = sinon.sandbox.create(); @@ -67,14 +73,48 @@ describe('onRequestInterceptor', () => { }; server.plugins = { + elasticsearch: { + getCluster: jest.fn().mockReturnValue({ + callWithInternalUser: jest.fn(), + callWithRequest: jest.fn(), + }), + }, spaces: { spacesClient: { - getScopedClient: jest.fn(), + scopedClient: jest.fn(), }, }, }; - initSpacesOnRequestInterceptor(server); + const log = { + log: jest.fn(), + trace: jest.fn(), + debug: jest.fn(), + info: jest.fn(), + warn: jest.fn(), + error: jest.fn(), + fatal: jest.fn(), + }; + + const spacesService = new SpacesService(log, server.config()); + await spacesService.setup({ + elasticsearch: server.plugins.elasticsearch as ElasticsearchPlugin, + savedObjects: server.savedObjects, + security: {} as SecurityPlugin, + spacesAuditLogger: {} as SpacesAuditLogger, + }); + + initSpacesOnRequestInterceptor({ + config: server.config(), + http: { server } as any, + log, + xpackMain: {} as XPackMainPlugin, + spacesService: { + scopedClient: jest.fn(), + getSpaceId: jest.fn(), + isInDefaultSpace: jest.fn(), + } as SpacesServiceSetup, + }); server.route([ { diff --git a/x-pack/plugins/spaces/server/lib/request_inteceptors/on_request_interceptor.ts b/x-pack/plugins/spaces/server/lib/request_inteceptors/on_request_interceptor.ts index 9a5161eeab5f6..928d67d9220c2 100644 --- a/x-pack/plugins/spaces/server/lib/request_inteceptors/on_request_interceptor.ts +++ b/x-pack/plugins/spaces/server/lib/request_inteceptors/on_request_interceptor.ts @@ -3,14 +3,14 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { Server } from 'hapi'; import { DEFAULT_SPACE_ID } from '../../../common/constants'; import { getSpaceIdFromPath } from '../spaces_url_parser'; +import { InterceptorDeps } from '.'; -export function initSpacesOnRequestInterceptor(server: Server) { - const serverBasePath: string = server.config().get('server.basePath'); +export function initSpacesOnRequestInterceptor({ config, http }: InterceptorDeps) { + const serverBasePath: string = config.get('server.basePath'); - server.ext('onRequest', async function spacesOnRequestHandler(request: any, h: any) { + http.server.ext('onRequest', async function spacesOnRequestHandler(request: any, h: any) { const path = request.path; // If navigating within the context of a space, then we store the Space's URL Context on the request, diff --git a/x-pack/plugins/spaces/server/lib/route_pre_check_license.ts b/x-pack/plugins/spaces/server/lib/route_pre_check_license.ts index f7f12ffa36fbc..b29f55d6669aa 100644 --- a/x-pack/plugins/spaces/server/lib/route_pre_check_license.ts +++ b/x-pack/plugins/spaces/server/lib/route_pre_check_license.ts @@ -5,12 +5,16 @@ */ import Boom from 'boom'; +import { XPackMainPlugin } from '../../../xpack_main/xpack_main'; -export function routePreCheckLicense(server: any) { - const xpackMainPlugin = server.plugins.xpack_main; +interface LicenseCheckDeps { + xpackMain: XPackMainPlugin; +} + +export function routePreCheckLicense({ xpackMain }: LicenseCheckDeps) { const pluginId = 'spaces'; return function forbidApiAccess(request: any) { - const licenseCheckResults = xpackMainPlugin.info.feature(pluginId).getLicenseCheckResults(); + const licenseCheckResults = xpackMain.info.feature(pluginId).getLicenseCheckResults(); if (!licenseCheckResults.showSpaces) { return Boom.forbidden(licenseCheckResults.linksMessage); } else { diff --git a/x-pack/plugins/spaces/server/lib/saved_objects_client/saved_objects_client_wrapper_factory.ts b/x-pack/plugins/spaces/server/lib/saved_objects_client/saved_objects_client_wrapper_factory.ts index a10b98625225c..40808379a9389 100644 --- a/x-pack/plugins/spaces/server/lib/saved_objects_client/saved_objects_client_wrapper_factory.ts +++ b/x-pack/plugins/spaces/server/lib/saved_objects_client/saved_objects_client_wrapper_factory.ts @@ -5,11 +5,11 @@ */ import { SavedObjectsClientWrapperFactory } from 'src/legacy/server/saved_objects'; -import { SpacesService } from '../create_spaces_service'; import { SpacesSavedObjectsClient } from './spaces_saved_objects_client'; +import { SpacesServiceSetup } from '../../new_platform/spaces_service/spaces_service'; export function spacesSavedObjectsClientWrapperFactory( - spacesService: SpacesService, + spacesService: SpacesServiceSetup, types: string[] ): SavedObjectsClientWrapperFactory { return ({ client, request }) => diff --git a/x-pack/plugins/spaces/server/lib/saved_objects_client/spaces_saved_objects_client.test.ts b/x-pack/plugins/spaces/server/lib/saved_objects_client/spaces_saved_objects_client.test.ts index b4064052736d1..51dd1a3b95761 100644 --- a/x-pack/plugins/spaces/server/lib/saved_objects_client/spaces_saved_objects_client.test.ts +++ b/x-pack/plugins/spaces/server/lib/saved_objects_client/spaces_saved_objects_client.test.ts @@ -6,8 +6,12 @@ import { DEFAULT_SPACE_ID } from '../../../common/constants'; import { Space } from '../../../common/model/space'; -import { createSpacesService } from '../create_spaces_service'; import { SpacesSavedObjectsClient } from './spaces_saved_objects_client'; +import { SpacesService } from '../../new_platform/spaces_service'; +import { ElasticsearchPlugin } from 'src/legacy/core_plugins/elasticsearch'; +import { SavedObjectsService } from 'src/legacy/server/kbn_server'; +import { SecurityPlugin } from '../../../../security'; +import { SpacesAuditLogger } from '../audit_logger'; const config: any = { 'server.basePath': '/', @@ -23,6 +27,18 @@ const server = { }), }; +const log = { + log: jest.fn(), + trace: jest.fn(), + debug: jest.fn(), + info: jest.fn(), + warn: jest.fn(), + error: jest.fn(), + fatal: jest.fn(), +}; + +const service = new SpacesService(log, server.config()); + const createMockRequest = (space: Partial) => ({ getBasePath: () => (space.id !== DEFAULT_SPACE_ID ? `/s/${space.id}` : ''), }); @@ -42,6 +58,20 @@ const createMockClient = () => { }; }; +const createSpacesService = async () => { + return service.setup({ + elasticsearch: ({ + getCluster: jest.fn().mockReturnValue({ + callWithRequest: jest.fn(), + callWithInternalUser: jest.fn(), + }), + } as unknown) as ElasticsearchPlugin, + savedObjects: {} as SavedObjectsService, + security: {} as SecurityPlugin, + spacesAuditLogger: {} as SpacesAuditLogger, + }); +}; + [ { id: DEFAULT_SPACE_ID, expectedNamespace: undefined }, { id: 'space_1', expectedNamespace: 'space_1' }, @@ -51,7 +81,7 @@ const createMockClient = () => { test(`throws error if options.namespace is specified`, async () => { const request = createMockRequest({ id: currentSpace.id }); const baseClient = createMockClient(); - const spacesService = createSpacesService(server); + const spacesService = await createSpacesService(); const client = new SpacesSavedObjectsClient({ request, @@ -68,7 +98,7 @@ const createMockClient = () => { test(`throws error if type is space`, async () => { const request = createMockRequest({ id: currentSpace.id }); const baseClient = createMockClient(); - const spacesService = createSpacesService(server); + const spacesService = await createSpacesService(); const client = new SpacesSavedObjectsClient({ request, @@ -85,7 +115,7 @@ const createMockClient = () => { const baseClient = createMockClient(); const expectedReturnValue = Symbol(); baseClient.get.mockReturnValue(expectedReturnValue); - const spacesService = createSpacesService(server); + const spacesService = await createSpacesService(); const client = new SpacesSavedObjectsClient({ request, @@ -111,7 +141,7 @@ const createMockClient = () => { test(`throws error if options.namespace is specified`, async () => { const request = createMockRequest({ id: currentSpace.id }); const baseClient = createMockClient(); - const spacesService = createSpacesService(server); + const spacesService = await createSpacesService(); const client = new SpacesSavedObjectsClient({ request, @@ -128,7 +158,7 @@ const createMockClient = () => { test(`throws error if objects type is space`, async () => { const request = createMockRequest({ id: currentSpace.id }); const baseClient = createMockClient(); - const spacesService = createSpacesService(server); + const spacesService = await createSpacesService(); const client = new SpacesSavedObjectsClient({ request, @@ -147,7 +177,7 @@ const createMockClient = () => { const baseClient = createMockClient(); const expectedReturnValue = Symbol(); baseClient.bulkGet.mockReturnValue(expectedReturnValue); - const spacesService = createSpacesService(server); + const spacesService = await createSpacesService(); const client = new SpacesSavedObjectsClient({ request, @@ -173,7 +203,7 @@ const createMockClient = () => { test(`throws error if options.namespace is specified`, async () => { const request = createMockRequest({ id: currentSpace.id }); const baseClient = createMockClient(); - const spacesService = createSpacesService(server); + const spacesService = await createSpacesService(); const client = new SpacesSavedObjectsClient({ request, @@ -190,7 +220,7 @@ const createMockClient = () => { const baseClient = createMockClient(); const expectedReturnValue = Symbol(); baseClient.find.mockReturnValue(expectedReturnValue); - const spacesService = createSpacesService(server); + const spacesService = await createSpacesService(); const client = new SpacesSavedObjectsClient({ request, @@ -207,7 +237,7 @@ const createMockClient = () => { const baseClient = createMockClient(); const expectedReturnValue = Symbol(); baseClient.find.mockReturnValue(expectedReturnValue); - const spacesService = createSpacesService(server); + const spacesService = await createSpacesService(); const client = new SpacesSavedObjectsClient({ request, @@ -231,7 +261,7 @@ const createMockClient = () => { const baseClient = createMockClient(); const expectedReturnValue = Symbol(); baseClient.find.mockReturnValue(expectedReturnValue); - const spacesService = createSpacesService(server); + const spacesService = await createSpacesService(); const client = new SpacesSavedObjectsClient({ request, @@ -250,7 +280,7 @@ const createMockClient = () => { const baseClient = createMockClient(); const expectedReturnValue = Symbol(); baseClient.find.mockReturnValue(expectedReturnValue); - const spacesService = createSpacesService(server); + const spacesService = await createSpacesService(); const client = new SpacesSavedObjectsClient({ request, @@ -269,7 +299,7 @@ const createMockClient = () => { const baseClient = createMockClient(); const expectedReturnValue = Symbol(); baseClient.find.mockReturnValue(expectedReturnValue); - const spacesService = createSpacesService(server); + const spacesService = await createSpacesService(); const client = new SpacesSavedObjectsClient({ request, @@ -293,7 +323,7 @@ const createMockClient = () => { test(`throws error if options.namespace is specified`, async () => { const request = createMockRequest({ id: currentSpace.id }); const baseClient = createMockClient(); - const spacesService = createSpacesService(server); + const spacesService = await createSpacesService(); const client = new SpacesSavedObjectsClient({ request, @@ -310,7 +340,7 @@ const createMockClient = () => { test(`throws error if type is space`, async () => { const request = createMockRequest({ id: currentSpace.id }); const baseClient = createMockClient(); - const spacesService = createSpacesService(server); + const spacesService = await createSpacesService(); const client = new SpacesSavedObjectsClient({ request, @@ -327,7 +357,7 @@ const createMockClient = () => { const baseClient = createMockClient(); const expectedReturnValue = Symbol(); baseClient.create.mockReturnValue(expectedReturnValue); - const spacesService = createSpacesService(server); + const spacesService = await createSpacesService(); const client = new SpacesSavedObjectsClient({ request, @@ -354,7 +384,7 @@ const createMockClient = () => { test(`throws error if options.namespace is specified`, async () => { const request = createMockRequest({ id: currentSpace.id }); const baseClient = createMockClient(); - const spacesService = createSpacesService(server); + const spacesService = await createSpacesService(); const client = new SpacesSavedObjectsClient({ request, @@ -371,7 +401,7 @@ const createMockClient = () => { test(`throws error if objects type is space`, async () => { const request = createMockRequest({ id: currentSpace.id }); const baseClient = createMockClient(); - const spacesService = createSpacesService(server); + const spacesService = await createSpacesService(); const client = new SpacesSavedObjectsClient({ request, @@ -393,7 +423,7 @@ const createMockClient = () => { const baseClient = createMockClient(); const expectedReturnValue = Symbol(); baseClient.bulkCreate.mockReturnValue(expectedReturnValue); - const spacesService = createSpacesService(server); + const spacesService = await createSpacesService(); const client = new SpacesSavedObjectsClient({ request, @@ -419,7 +449,7 @@ const createMockClient = () => { test(`throws error if options.namespace is specified`, async () => { const request = createMockRequest({ id: currentSpace.id }); const baseClient = createMockClient(); - const spacesService = createSpacesService(server); + const spacesService = await createSpacesService(); const client = new SpacesSavedObjectsClient({ request, @@ -437,7 +467,7 @@ const createMockClient = () => { test(`throws error if type is space`, async () => { const request = createMockRequest({ id: currentSpace.id }); const baseClient = createMockClient(); - const spacesService = createSpacesService(server); + const spacesService = await createSpacesService(); const client = new SpacesSavedObjectsClient({ request, @@ -454,7 +484,7 @@ const createMockClient = () => { const baseClient = createMockClient(); const expectedReturnValue = Symbol(); baseClient.update.mockReturnValue(expectedReturnValue); - const spacesService = createSpacesService(server); + const spacesService = await createSpacesService(); const client = new SpacesSavedObjectsClient({ request, @@ -482,7 +512,7 @@ const createMockClient = () => { test(`throws error if options.namespace is specified`, async () => { const request = createMockRequest({ id: currentSpace.id }); const baseClient = createMockClient(); - const spacesService = createSpacesService(server); + const spacesService = await createSpacesService(); const client = new SpacesSavedObjectsClient({ request, @@ -500,7 +530,7 @@ const createMockClient = () => { test(`throws error if type is space`, async () => { const request = createMockRequest({ id: currentSpace.id }); const baseClient = createMockClient(); - const spacesService = createSpacesService(server); + const spacesService = await createSpacesService(); const client = new SpacesSavedObjectsClient({ request, @@ -517,7 +547,7 @@ const createMockClient = () => { const baseClient = createMockClient(); const expectedReturnValue = Symbol(); baseClient.delete.mockReturnValue(expectedReturnValue); - const spacesService = createSpacesService(server); + const spacesService = await createSpacesService(); const client = new SpacesSavedObjectsClient({ request, diff --git a/x-pack/plugins/spaces/server/lib/saved_objects_client/spaces_saved_objects_client.ts b/x-pack/plugins/spaces/server/lib/saved_objects_client/spaces_saved_objects_client.ts index b7326e1f344a4..84412d87e320b 100644 --- a/x-pack/plugins/spaces/server/lib/saved_objects_client/spaces_saved_objects_client.ts +++ b/x-pack/plugins/spaces/server/lib/saved_objects_client/spaces_saved_objects_client.ts @@ -15,12 +15,12 @@ import { UpdateOptions, } from 'src/legacy/server/saved_objects/service/saved_objects_client'; import { DEFAULT_SPACE_ID } from '../../../common/constants'; -import { SpacesService } from '../create_spaces_service'; +import { SpacesServiceSetup } from '../../new_platform/spaces_service/spaces_service'; interface SpacesSavedObjectsClientOptions { baseClient: SavedObjectsClient; request: any; - spacesService: SpacesService; + spacesService: SpacesServiceSetup; types: string[]; } diff --git a/x-pack/plugins/spaces/server/lib/spaces_tutorial_context_factory.test.ts b/x-pack/plugins/spaces/server/lib/spaces_tutorial_context_factory.test.ts index fc97fc8d3cb48..54e79caf8534f 100644 --- a/x-pack/plugins/spaces/server/lib/spaces_tutorial_context_factory.test.ts +++ b/x-pack/plugins/spaces/server/lib/spaces_tutorial_context_factory.test.ts @@ -5,8 +5,12 @@ */ import { DEFAULT_SPACE_ID } from '../../common/constants'; -import { createSpacesService } from './create_spaces_service'; import { createSpacesTutorialContextFactory } from './spaces_tutorial_context_factory'; +import { SpacesService } from '../new_platform/spaces_service'; +import { ElasticsearchPlugin } from 'src/legacy/core_plugins/elasticsearch'; +import { SavedObjectsService } from 'src/legacy/server/kbn_server'; +import { SecurityPlugin } from '../../../security'; +import { SpacesAuditLogger } from './audit_logger'; const server = { config: () => { @@ -21,14 +25,46 @@ const server = { }, }; +const log = { + log: jest.fn(), + trace: jest.fn(), + debug: jest.fn(), + info: jest.fn(), + warn: jest.fn(), + error: jest.fn(), + fatal: jest.fn(), +}; + +const service = new SpacesService(log, server.config()); + describe('createSpacesTutorialContextFactory', () => { - it('should create a valid context factory', () => { - const spacesService = createSpacesService(server); + it('should create a valid context factory', async () => { + const spacesService = await service.setup({ + elasticsearch: ({ + getCluster: jest.fn().mockReturnValue({ + callWithRequest: jest.fn(), + callWithInternalUser: jest.fn(), + }), + } as unknown) as ElasticsearchPlugin, + savedObjects: {} as SavedObjectsService, + security: {} as SecurityPlugin, + spacesAuditLogger: {} as SpacesAuditLogger, + }); expect(typeof createSpacesTutorialContextFactory(spacesService)).toEqual('function'); }); - it('should create context with the current space id for space my-space-id', () => { - const spacesService = createSpacesService(server); + it('should create context with the current space id for space my-space-id', async () => { + const spacesService = await service.setup({ + elasticsearch: ({ + getCluster: jest.fn().mockReturnValue({ + callWithRequest: jest.fn(), + callWithInternalUser: jest.fn(), + }), + } as unknown) as ElasticsearchPlugin, + savedObjects: {} as SavedObjectsService, + security: {} as SecurityPlugin, + spacesAuditLogger: {} as SpacesAuditLogger, + }); const contextFactory = createSpacesTutorialContextFactory(spacesService); const request = { @@ -41,8 +77,18 @@ describe('createSpacesTutorialContextFactory', () => { }); }); - it('should create context with the current space id for the default space', () => { - const spacesService = createSpacesService(server); + it('should create context with the current space id for the default space', async () => { + const spacesService = await service.setup({ + elasticsearch: ({ + getCluster: jest.fn().mockReturnValue({ + callWithRequest: jest.fn(), + callWithInternalUser: jest.fn(), + }), + } as unknown) as ElasticsearchPlugin, + savedObjects: {} as SavedObjectsService, + security: {} as SecurityPlugin, + spacesAuditLogger: {} as SpacesAuditLogger, + }); const contextFactory = createSpacesTutorialContextFactory(spacesService); const request = { diff --git a/x-pack/plugins/spaces/server/lib/spaces_tutorial_context_factory.ts b/x-pack/plugins/spaces/server/lib/spaces_tutorial_context_factory.ts index 0681c5437b919..770294840f1c6 100644 --- a/x-pack/plugins/spaces/server/lib/spaces_tutorial_context_factory.ts +++ b/x-pack/plugins/spaces/server/lib/spaces_tutorial_context_factory.ts @@ -4,9 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { SpacesService } from './create_spaces_service'; +import { SpacesServiceSetup } from '../new_platform/spaces_service/spaces_service'; -export function createSpacesTutorialContextFactory(spacesService: SpacesService) { +export function createSpacesTutorialContextFactory(spacesService: SpacesServiceSetup) { return function spacesTutorialContextFactory(request: any) { return { spaceId: spacesService.getSpaceId(request), diff --git a/x-pack/plugins/spaces/server/new_platform/index.ts b/x-pack/plugins/spaces/server/new_platform/index.ts new file mode 100644 index 0000000000000..cc36a09bde1a5 --- /dev/null +++ b/x-pack/plugins/spaces/server/new_platform/index.ts @@ -0,0 +1,12 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { Plugin } from './plugin'; +import { SpacesInitializerContext } from '../..'; + +export function plugin(initializerContext: SpacesInitializerContext) { + return new Plugin(initializerContext); +} diff --git a/x-pack/plugins/spaces/server/new_platform/plugin.ts b/x-pack/plugins/spaces/server/new_platform/plugin.ts new file mode 100644 index 0000000000000..0426339874e9f --- /dev/null +++ b/x-pack/plugins/spaces/server/new_platform/plugin.ts @@ -0,0 +1,111 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { Logger } from 'src/core/server'; +import { XPackMainPlugin } from '../../../xpack_main/xpack_main'; +import { createDefaultSpace } from '../lib/create_default_space'; +import { SpacesCoreSetup, SpacesInitializerContext, SpacesConfig } from '../../index'; +// @ts-ignore +import { AuditLogger } from '../../../../server/lib/audit_logger'; +// @ts-ignore +import { watchStatusAndLicenseToInitialize } from '../../../../server/lib/watch_status_and_license_to_initialize'; +import { checkLicense } from '../lib/check_license'; +import { spacesSavedObjectsClientWrapperFactory } from '../lib/saved_objects_client/saved_objects_client_wrapper_factory'; +import { SpacesAuditLogger } from '../lib/audit_logger'; +import { createSpacesTutorialContextFactory } from '../lib/spaces_tutorial_context_factory'; +import { initPrivateApis } from '../routes/api/v1'; +import { initPublicSpacesApi } from '../routes/api/public'; +import { initSpacesRequestInterceptors } from '../lib/request_inteceptors'; +import { getSpacesUsageCollector } from '../lib/get_spaces_usage_collector'; +import { SpacesService } from './spaces_service'; + +export class Plugin { + private readonly pluginId = 'spaces'; + + private config: SpacesConfig; + + private log: Logger; + + constructor(initializerContext: SpacesInitializerContext) { + this.config = initializerContext.legacyConfig; + this.log = initializerContext.logger.get('spaces'); + } + + public async setup(core: SpacesCoreSetup) { + const xpackMainPlugin: XPackMainPlugin = core.xpackMain; + watchStatusAndLicenseToInitialize(xpackMainPlugin, core.spaces, async () => { + await createDefaultSpace({ + elasticsearch: core.elasticsearch, + savedObjects: core.savedObjects, + }); + }); + + // Register a function that is called whenever the xpack info changes, + // to re-compute the license check results for this plugin. + xpackMainPlugin.info.feature(this.pluginId).registerLicenseCheckResultsGenerator(checkLicense); + + const spacesAuditLogger = new SpacesAuditLogger( + this.config, + new AuditLogger(core.http.server, 'spaces') + ); + + const service = new SpacesService(this.log, this.config); + const spacesService = await service.setup({ + elasticsearch: core.elasticsearch, + savedObjects: core.savedObjects, + security: core.security, + spacesAuditLogger, + }); + + const { addScopedSavedObjectsClientWrapperFactory, types } = core.savedObjects; + addScopedSavedObjectsClientWrapperFactory( + Number.MAX_VALUE, + spacesSavedObjectsClientWrapperFactory(spacesService, types) + ); + + core.tutorial.addScopedTutorialContextFactory( + createSpacesTutorialContextFactory(spacesService) + ); + + initPrivateApis({ + http: core.http, + config: this.config, + savedObjects: core.savedObjects, + spacesService, + xpackMain: xpackMainPlugin, + }); + + initPublicSpacesApi({ + http: core.http, + log: this.log, + savedObjects: core.savedObjects, + spacesService, + xpackMain: xpackMainPlugin, + }); + + initSpacesRequestInterceptors({ + config: this.config, + http: core.http, + log: this.log, + spacesService, + xpackMain: xpackMainPlugin, + }); + + // Register a function with server to manage the collection of usage stats + core.usage.collectorSet.register( + getSpacesUsageCollector({ + config: this.config, + savedObjects: core.savedObjects, + usage: core.usage, + xpackMain: xpackMainPlugin, + }) + ); + + return { + spacesService, + }; + } +} diff --git a/x-pack/plugins/spaces/server/new_platform/spaces_service/index.ts b/x-pack/plugins/spaces/server/new_platform/spaces_service/index.ts new file mode 100644 index 0000000000000..e37d1db3f85bb --- /dev/null +++ b/x-pack/plugins/spaces/server/new_platform/spaces_service/index.ts @@ -0,0 +1,7 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export { SpacesService } from './spaces_service'; diff --git a/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts b/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts new file mode 100644 index 0000000000000..1c81b62257605 --- /dev/null +++ b/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts @@ -0,0 +1,103 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { Request } from 'hapi'; +import { Logger } from 'src/core/server'; +import { SavedObjectsService } from 'src/legacy/server/kbn_server'; +import { ElasticsearchPlugin } from 'src/legacy/core_plugins/elasticsearch'; +import { DEFAULT_SPACE_ID } from '../../../common/constants'; +import { SecurityPlugin } from '../../../../security'; +import { SpacesConfig } from '../../..'; +import { SpacesClient } from '../../lib/spaces_client'; +import { getSpaceIdFromPath } from '../../lib/spaces_url_parser'; + +export interface SpacesServiceSetup { + scopedClient(request: Record): SpacesClient; + + getSpaceId(request: Record): string; + + isInDefaultSpace(request: Record): boolean; +} + +interface CacheEntry { + spaceId: string; + isInDefaultSpace: boolean; +} + +interface SpacesServiceDeps { + elasticsearch: ElasticsearchPlugin; + savedObjects: SavedObjectsService; + security: SecurityPlugin; + spacesAuditLogger: any; +} + +export class SpacesService { + private readonly serverBasePath: string; + + private readonly contextCache: WeakMap; + + constructor(private readonly log: Logger, private readonly config: SpacesConfig) { + this.serverBasePath = config.get('server.basePath'); + + this.contextCache = new WeakMap(); + } + + public async setup({ + elasticsearch, + savedObjects, + security, + spacesAuditLogger, + }: SpacesServiceDeps): Promise { + const adminClient = elasticsearch.getCluster('admin'); + return { + getSpaceId: (request: Record) => { + if (!this.contextCache.has(request)) { + this.populateCache(request); + } + + const { spaceId } = this.contextCache.get(request) as CacheEntry; + return spaceId; + }, + isInDefaultSpace: (request: any) => { + if (!this.contextCache.has(request)) { + this.populateCache(request); + } + + return this.contextCache.get(request)!.isInDefaultSpace; + }, + scopedClient: (request: Request) => { + const { callWithRequest, callWithInternalUser } = adminClient; + + const internalRepository = savedObjects.getSavedObjectsRepository(callWithInternalUser); + const callWithRequestRepository = savedObjects.getSavedObjectsRepository( + (endpoint: string, params: any, options?: any) => + callWithRequest(request, endpoint, params, options) + ); + const authorization = security ? security.authorization : null; + + return new SpacesClient( + spacesAuditLogger, + (message: string) => { + this.log.debug(message); + }, + authorization, + callWithRequestRepository, + this.config, + internalRepository, + request + ); + }, + }; + } + + private populateCache(request: Record) { + const spaceId = getSpaceIdFromPath(request.getBasePath(), this.serverBasePath); + + this.contextCache.set(request, { + spaceId, + isInDefaultSpace: spaceId === DEFAULT_SPACE_ID, + }); + } +} diff --git a/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_test_handler.ts b/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_test_handler.ts index 3b92cd2151b2b..0788d3dbba746 100644 --- a/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_test_handler.ts +++ b/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_test_handler.ts @@ -7,8 +7,14 @@ // @ts-ignore import { Server } from 'hapi'; import { Legacy } from 'kibana'; +import { HttpServiceSetup } from 'src/core/server'; +import { SecurityPlugin } from '../../../../../security'; import { SpacesClient } from '../../../lib/spaces_client'; import { createSpaces } from './create_spaces'; +import { PublicRouteDeps } from '../public'; +import { SpacesService } from '../../../new_platform/spaces_service'; +import { SpacesAuditLogger } from '../../../lib/audit_logger'; +import { PrivateRouteDeps } from '../v1'; interface KibanaServer extends Legacy.Server { savedObjects: any; @@ -47,7 +53,7 @@ const baseConfig: TestConfig = { 'xpack.spaces.maxSpaces': 1000, }; -export function createTestHandler(initApiFn: (server: any, preCheckLicenseImpl: any) => void) { +export function createTestHandler(initApiFn: (deps: PublicRouteDeps & PrivateRouteDeps) => void) { const teardowns: TeardownFn[] = []; const spaces = createSpaces(); @@ -87,8 +93,6 @@ export function createTestHandler(initApiFn: (server: any, preCheckLicenseImpl: server.decorate('server', 'config', jest.fn(() => mockConfig)); - initApiFn(server, pre); - server.decorate('request', 'getBasePath', jest.fn()); server.decorate('request', 'setBasePath', jest.fn()); @@ -133,22 +137,56 @@ export function createTestHandler(initApiFn: (server: any, preCheckLicenseImpl: }, }; - server.plugins.spaces = { - spacesClient: { - getScopedClient: jest.fn((req: any) => { - return new SpacesClient( - null as any, - () => null, - null, - mockSavedObjectsRepository, - mockConfig, - mockSavedObjectsRepository, - req - ); - }), - }, + server.plugins.elasticsearch = { + createCluster: jest.fn(), + waitUntilReady: jest.fn(), + getCluster: jest.fn().mockReturnValue({ + callWithRequest: jest.fn(), + callWithInternalUser: jest.fn(), + }), }; + const log = { + log: jest.fn(), + trace: jest.fn(), + debug: jest.fn(), + info: jest.fn(), + warn: jest.fn(), + error: jest.fn(), + fatal: jest.fn(), + }; + + const service = new SpacesService(log, server.config()); + const spacesService = await service.setup({ + elasticsearch: server.plugins.elasticsearch, + savedObjects: server.savedObjects, + security: {} as SecurityPlugin, + spacesAuditLogger: {} as SpacesAuditLogger, + }); + + spacesService.scopedClient = jest.fn((req: any) => { + return new SpacesClient( + null as any, + () => null, + null, + mockSavedObjectsRepository, + mockConfig, + mockSavedObjectsRepository, + req + ); + }); + + initApiFn({ + http: ({ + server, + } as unknown) as HttpServiceSetup, + routePreCheckLicenseFn: pre, + savedObjects: server.savedObjects, + spacesService, + log, + config: mockConfig, + }); + teardowns.push(() => server.stop()); const headers = { @@ -170,7 +208,7 @@ export function createTestHandler(initApiFn: (server: any, preCheckLicenseImpl: } if (expectSpacesClientCall) { - expect(server.plugins.spaces.spacesClient.getScopedClient).toHaveBeenCalledWith( + expect(spacesService.scopedClient).toHaveBeenCalledWith( expect.objectContaining({ headers: expect.objectContaining({ authorization: headers.authorization, @@ -178,7 +216,7 @@ export function createTestHandler(initApiFn: (server: any, preCheckLicenseImpl: }) ); } else { - expect(server.plugins.spaces.spacesClient.getScopedClient).not.toHaveBeenCalled(); + expect(spacesService.scopedClient).not.toHaveBeenCalled(); } return response; diff --git a/x-pack/plugins/spaces/server/routes/api/public/delete.ts b/x-pack/plugins/spaces/server/routes/api/public/delete.ts index c9536ab2c9782..92e68632bddbb 100644 --- a/x-pack/plugins/spaces/server/routes/api/public/delete.ts +++ b/x-pack/plugins/spaces/server/routes/api/public/delete.ts @@ -7,16 +7,17 @@ import Boom from 'boom'; import { wrapError } from '../../../lib/errors'; import { SpacesClient } from '../../../lib/spaces_client'; +import { PublicRouteDeps } from '.'; -export function initDeleteSpacesApi(server: any, routePreCheckLicenseFn: any) { - server.route({ +export function initDeleteSpacesApi(deps: PublicRouteDeps) { + const { http, savedObjects, spacesService, routePreCheckLicenseFn } = deps; + + http.server.route({ method: 'DELETE', path: '/api/spaces/space/{id}', async handler(request: any, h: any) { - const { SavedObjectsClient } = server.savedObjects; - const spacesClient: SpacesClient = server.plugins.spaces.spacesClient.getScopedClient( - request - ); + const { SavedObjectsClient } = savedObjects; + const spacesClient: SpacesClient = spacesService.scopedClient(request); const id = request.params.id; @@ -33,7 +34,7 @@ export function initDeleteSpacesApi(server: any, routePreCheckLicenseFn: any) { return h.response(result).code(204); }, - config: { + options: { pre: [routePreCheckLicenseFn], }, }); diff --git a/x-pack/plugins/spaces/server/routes/api/public/get.ts b/x-pack/plugins/spaces/server/routes/api/public/get.ts index 36bd518c09ad8..f0cfd0aa42b47 100644 --- a/x-pack/plugins/spaces/server/routes/api/public/get.ts +++ b/x-pack/plugins/spaces/server/routes/api/public/get.ts @@ -8,46 +8,45 @@ import Boom from 'boom'; import { Space } from '../../../../common/model/space'; import { wrapError } from '../../../lib/errors'; import { SpacesClient } from '../../../lib/spaces_client'; +import { PublicRouteDeps } from '.'; -export function initGetSpacesApi(server: any, routePreCheckLicenseFn: any) { - server.route({ +export function initGetSpacesApi(deps: PublicRouteDeps) { + const { http, log, spacesService, savedObjects, routePreCheckLicenseFn } = deps; + + http.server.route({ method: 'GET', path: '/api/spaces/space', async handler(request: any) { - server.log(['spaces', 'debug'], `Inside GET /api/spaces/space`); + log.debug(`Inside GET /api/spaces/space`); - const spacesClient: SpacesClient = server.plugins.spaces.spacesClient.getScopedClient( - request - ); + const spacesClient: SpacesClient = spacesService.scopedClient(request); let spaces: Space[]; try { - server.log(['spaces', 'debug'], `Attempting to retrieve all spaces`); + log.debug(`Attempting to retrieve all spaces`); spaces = await spacesClient.getAll(); - server.log(['spaces', 'debug'], `Retrieved ${spaces.length} spaces`); + log.debug(`Retrieved ${spaces.length} spaces`); } catch (error) { - server.log(['spaces', 'debug'], `Error retrieving spaces: ${error}`); + log.debug(`Error retrieving spaces: ${error}`); return wrapError(error); } return spaces; }, - config: { + options: { pre: [routePreCheckLicenseFn], }, }); - server.route({ + http.server.route({ method: 'GET', path: '/api/spaces/space/{id}', async handler(request: any) { const spaceId = request.params.id; - const { SavedObjectsClient } = server.savedObjects; - const spacesClient: SpacesClient = server.plugins.spaces.spacesClient.getScopedClient( - request - ); + const { SavedObjectsClient } = savedObjects; + const spacesClient: SpacesClient = spacesService.scopedClient(request); try { return await spacesClient.get(spaceId); @@ -58,7 +57,7 @@ export function initGetSpacesApi(server: any, routePreCheckLicenseFn: any) { return wrapError(error); } }, - config: { + options: { pre: [routePreCheckLicenseFn], }, }); diff --git a/x-pack/plugins/spaces/server/routes/api/public/index.ts b/x-pack/plugins/spaces/server/routes/api/public/index.ts index 602b62ab26d06..7f8977b8580b7 100644 --- a/x-pack/plugins/spaces/server/routes/api/public/index.ts +++ b/x-pack/plugins/spaces/server/routes/api/public/index.ts @@ -4,17 +4,40 @@ * you may not use this file except in compliance with the Elastic License. */ +import { HttpServiceSetup, Logger } from 'src/core/server'; +import { SavedObjectsService } from 'src/legacy/server/kbn_server'; +import { XPackMainPlugin } from '../../../../../xpack_main/xpack_main'; import { routePreCheckLicense } from '../../../lib/route_pre_check_license'; import { initDeleteSpacesApi } from './delete'; import { initGetSpacesApi } from './get'; import { initPostSpacesApi } from './post'; import { initPutSpacesApi } from './put'; +import { SpacesServiceSetup } from '../../../new_platform/spaces_service/spaces_service'; -export function initPublicSpacesApi(server: any) { - const routePreCheckLicenseFn = routePreCheckLicense(server); +type InterfaceExcept = Pick>; - initDeleteSpacesApi(server, routePreCheckLicenseFn); - initGetSpacesApi(server, routePreCheckLicenseFn); - initPostSpacesApi(server, routePreCheckLicenseFn); - initPutSpacesApi(server, routePreCheckLicenseFn); +interface RouteDeps { + xpackMain: XPackMainPlugin; + http: HttpServiceSetup; + savedObjects: SavedObjectsService; + spacesService: SpacesServiceSetup; + log: Logger; +} + +export interface PublicRouteDeps extends InterfaceExcept { + routePreCheckLicenseFn: any; +} + +export function initPublicSpacesApi({ xpackMain, ...rest }: RouteDeps) { + const routePreCheckLicenseFn = routePreCheckLicense({ xpackMain }); + + const deps: PublicRouteDeps = { + ...rest, + routePreCheckLicenseFn, + }; + + initDeleteSpacesApi(deps); + initGetSpacesApi(deps); + initPostSpacesApi(deps); + initPutSpacesApi(deps); } diff --git a/x-pack/plugins/spaces/server/routes/api/public/post.ts b/x-pack/plugins/spaces/server/routes/api/public/post.ts index 668e9af9ef835..fb5961e549ff0 100644 --- a/x-pack/plugins/spaces/server/routes/api/public/post.ts +++ b/x-pack/plugins/spaces/server/routes/api/public/post.ts @@ -8,32 +8,33 @@ import Boom from 'boom'; import { wrapError } from '../../../lib/errors'; import { spaceSchema } from '../../../lib/space_schema'; import { SpacesClient } from '../../../lib/spaces_client'; +import { PublicRouteDeps } from '.'; -export function initPostSpacesApi(server: any, routePreCheckLicenseFn: any) { - server.route({ +export function initPostSpacesApi(deps: PublicRouteDeps) { + const { http, log, spacesService, savedObjects, routePreCheckLicenseFn } = deps; + + http.server.route({ method: 'POST', path: '/api/spaces/space', async handler(request: any) { - server.log(['spaces', 'debug'], `Inside POST /api/spaces/space`); - const { SavedObjectsClient } = server.savedObjects; - const spacesClient: SpacesClient = server.plugins.spaces.spacesClient.getScopedClient( - request - ); + log.debug(`Inside POST /api/spaces/space`); + const { SavedObjectsClient } = savedObjects; + const spacesClient: SpacesClient = spacesService.scopedClient(request); const space = request.payload; try { - server.log(['spaces', 'debug'], `Attempting to create space`); + log.debug(`Attempting to create space`); return await spacesClient.create(space); } catch (error) { if (SavedObjectsClient.errors.isConflictError(error)) { return Boom.conflict(`A space with the identifier ${space.id} already exists.`); } - server.log(['spaces', 'debug'], `Error creating space: ${error}`); + log.debug(`Error creating space: ${error}`); return wrapError(error); } }, - config: { + options: { validate: { payload: spaceSchema, }, diff --git a/x-pack/plugins/spaces/server/routes/api/public/put.ts b/x-pack/plugins/spaces/server/routes/api/public/put.ts index 08d6646db90f6..b503b3f99eef8 100644 --- a/x-pack/plugins/spaces/server/routes/api/public/put.ts +++ b/x-pack/plugins/spaces/server/routes/api/public/put.ts @@ -9,16 +9,17 @@ import { Space } from '../../../../common/model/space'; import { wrapError } from '../../../lib/errors'; import { spaceSchema } from '../../../lib/space_schema'; import { SpacesClient } from '../../../lib/spaces_client'; +import { PublicRouteDeps } from '.'; -export function initPutSpacesApi(server: any, routePreCheckLicenseFn: any) { - server.route({ +export function initPutSpacesApi(deps: PublicRouteDeps) { + const { http, spacesService, savedObjects, routePreCheckLicenseFn } = deps; + + http.server.route({ method: 'PUT', path: '/api/spaces/space/{id}', async handler(request: any) { - const { SavedObjectsClient } = server.savedObjects; - const spacesClient: SpacesClient = server.plugins.spaces.spacesClient.getScopedClient( - request - ); + const { SavedObjectsClient } = savedObjects; + const spacesClient: SpacesClient = spacesService.scopedClient(request); const space: Space = request.payload; const id = request.params.id; @@ -35,7 +36,7 @@ export function initPutSpacesApi(server: any, routePreCheckLicenseFn: any) { return result; }, - config: { + options: { validate: { payload: spaceSchema, }, diff --git a/x-pack/plugins/spaces/server/routes/api/v1/index.ts b/x-pack/plugins/spaces/server/routes/api/v1/index.ts index 75659c14c03ae..f764776d071d8 100644 --- a/x-pack/plugins/spaces/server/routes/api/v1/index.ts +++ b/x-pack/plugins/spaces/server/routes/api/v1/index.ts @@ -4,10 +4,35 @@ * you may not use this file except in compliance with the Elastic License. */ +import { HttpServiceSetup } from 'src/core/server'; +import { SavedObjectsService } from 'src/legacy/server/kbn_server'; +import { XPackMainPlugin } from '../../../../../xpack_main/xpack_main'; +import { SpacesConfig } from '../../../..'; import { routePreCheckLicense } from '../../../lib/route_pre_check_license'; import { initPrivateSpacesApi } from './spaces'; +import { SpacesServiceSetup } from '../../../new_platform/spaces_service/spaces_service'; -export function initPrivateApis(server: any) { - const routePreCheckLicenseFn = routePreCheckLicense(server); - initPrivateSpacesApi(server, routePreCheckLicenseFn); +type InterfaceExcept = Pick>; + +interface RouteDeps { + xpackMain: XPackMainPlugin; + http: HttpServiceSetup; + savedObjects: SavedObjectsService; + spacesService: SpacesServiceSetup; + config: SpacesConfig; +} + +export interface PrivateRouteDeps extends InterfaceExcept { + routePreCheckLicenseFn: any; +} + +export function initPrivateApis({ xpackMain, ...rest }: RouteDeps) { + const routePreCheckLicenseFn = routePreCheckLicense({ xpackMain }); + + const deps: PrivateRouteDeps = { + ...rest, + routePreCheckLicenseFn, + }; + + initPrivateSpacesApi(deps); } diff --git a/x-pack/plugins/spaces/server/routes/api/v1/spaces.ts b/x-pack/plugins/spaces/server/routes/api/v1/spaces.ts index 427878e2caf2f..6f8f74017a6a2 100644 --- a/x-pack/plugins/spaces/server/routes/api/v1/spaces.ts +++ b/x-pack/plugins/spaces/server/routes/api/v1/spaces.ts @@ -10,17 +10,17 @@ import { wrapError } from '../../../lib/errors'; import { SpacesClient } from '../../../lib/spaces_client'; import { addSpaceIdToPath } from '../../../lib/spaces_url_parser'; import { getSpaceById } from '../../lib'; +import { PrivateRouteDeps } from '.'; -export function initPrivateSpacesApi(server: any, routePreCheckLicenseFn: any) { - server.route({ +export function initPrivateSpacesApi(deps: PrivateRouteDeps) { + const { http, config, spacesService, savedObjects, routePreCheckLicenseFn } = deps; + + http.server.route({ method: 'POST', path: '/api/spaces/v1/space/{id}/select', async handler(request: any) { - const { SavedObjectsClient } = server.savedObjects; - const spacesClient: SpacesClient = server.plugins.spaces.spacesClient.getScopedClient( - request - ); - + const { SavedObjectsClient } = savedObjects; + const spacesClient: SpacesClient = spacesService.scopedClient(request); const id = request.params.id; try { @@ -33,8 +33,6 @@ export function initPrivateSpacesApi(server: any, routePreCheckLicenseFn: any) { return Boom.notFound(); } - const config = server.config(); - return { location: addSpaceIdToPath( config.get('server.basePath'), @@ -46,7 +44,7 @@ export function initPrivateSpacesApi(server: any, routePreCheckLicenseFn: any) { return wrapError(error); } }, - config: { + options: { pre: [routePreCheckLicenseFn], }, }); diff --git a/x-pack/typings/hapi.d.ts b/x-pack/typings/hapi.d.ts index 2b7564f998b10..a0914593dbd9c 100644 --- a/x-pack/typings/hapi.d.ts +++ b/x-pack/typings/hapi.d.ts @@ -6,6 +6,7 @@ import 'hapi'; +import { SecurityPlugin } from '../plugins/security'; import { CloudPlugin } from '../plugins/cloud'; import { XPackMainPlugin } from '../plugins/xpack_main/xpack_main'; @@ -13,5 +14,6 @@ declare module 'hapi' { interface PluginProperties { cloud?: CloudPlugin; xpack_main: XPackMainPlugin; + security: SecurityPlugin; } } From 0de048e09126e5ddfa7dbf5b07feab6eecdb80a5 Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Mon, 22 Apr 2019 15:57:13 -0400 Subject: [PATCH 02/68] remove custom server typedef --- .../routes/api/public/privileges/get.test.ts | 23 ++++--------------- 1 file changed, 5 insertions(+), 18 deletions(-) diff --git a/x-pack/plugins/security/server/routes/api/public/privileges/get.test.ts b/x-pack/plugins/security/server/routes/api/public/privileges/get.test.ts index e83116365a0fe..b0fce26a3f2bf 100644 --- a/x-pack/plugins/security/server/routes/api/public/privileges/get.test.ts +++ b/x-pack/plugins/security/server/routes/api/public/privileges/get.test.ts @@ -4,23 +4,10 @@ * you may not use this file except in compliance with the Elastic License. */ import Boom from 'boom'; -import { PluginProperties, Server } from 'hapi'; +import { Server } from 'hapi'; import { RawKibanaPrivileges } from '../../../../../common/model'; import { initGetPrivilegesApi } from './get'; - -interface KibanaPluginProperties extends PluginProperties { - security: { - authorization: { - privileges: { - get: () => RawKibanaPrivileges; - }; - }; - }; -} - -interface KibanaServer extends Server { - plugins: KibanaPluginProperties; -} +import { AuthorizationService } from '../../../../lib/authorization/service'; const createRawKibanaPrivileges: () => RawKibanaPrivileges = () => { return { @@ -48,16 +35,16 @@ const createRawKibanaPrivileges: () => RawKibanaPrivileges = () => { }; const createMockServer = () => { - const mockServer: KibanaServer = new Server({ debug: false, port: 8080 }) as KibanaServer; + const mockServer = new Server({ debug: false, port: 8080 }); mockServer.plugins.security = { - authorization: { + authorization: ({ privileges: { get: jest.fn().mockImplementation(() => { return createRawKibanaPrivileges(); }), }, - }, + } as unknown) as AuthorizationService, }; return mockServer; }; From 1a56ee61f147991babd083306bd95a1917c3dc68 Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Wed, 24 Apr 2019 13:48:48 -0400 Subject: [PATCH 03/68] allow spaces to aquire security plugin after init --- x-pack/plugins/spaces/index.ts | 4 ++-- .../on_post_auth_interceptor.test.ts | 2 +- .../on_request_interceptor.test.ts | 2 +- .../spaces_saved_objects_client.test.ts | 2 +- .../lib/spaces_tutorial_context_factory.test.ts | 6 +++--- .../plugins/spaces/server/new_platform/plugin.ts | 2 +- .../new_platform/spaces_service/spaces_service.ts | 15 +++++++++------ .../api/__fixtures__/create_test_handler.ts | 2 +- 8 files changed, 19 insertions(+), 16 deletions(-) diff --git a/x-pack/plugins/spaces/index.ts b/x-pack/plugins/spaces/index.ts index b9928356f2462..cdbd59a920f23 100644 --- a/x-pack/plugins/spaces/index.ts +++ b/x-pack/plugins/spaces/index.ts @@ -29,7 +29,7 @@ import { SpacesPlugin } from './types'; export interface SpacesCoreSetup { http: HttpServiceSetup; xpackMain: XPackMainPlugin; - security: SecurityPlugin; + getSecurity: () => SecurityPlugin; savedObjects: SavedObjectsService; spaces: SpacesPlugin; elasticsearch: ElasticsearchPlugin; @@ -157,7 +157,7 @@ export const spaces = (kibana: Record) => elasticsearch: server.plugins.elasticsearch, xpackMain: server.plugins.xpack_main, spaces: this, - security: server.plugins.security, + getSecurity: () => server.plugins.security, savedObjects: server.savedObjects, usage: (server as any).usage, tutorial: { diff --git a/x-pack/plugins/spaces/server/lib/request_inteceptors/on_post_auth_interceptor.test.ts b/x-pack/plugins/spaces/server/lib/request_inteceptors/on_post_auth_interceptor.test.ts index 0bf849a21c01a..7304d0130417a 100644 --- a/x-pack/plugins/spaces/server/lib/request_inteceptors/on_post_auth_interceptor.test.ts +++ b/x-pack/plugins/spaces/server/lib/request_inteceptors/on_post_auth_interceptor.test.ts @@ -141,7 +141,7 @@ describe('onPostAuthRequestInterceptor', () => { spacesService = await service.setup({ elasticsearch: server.plugins.elasticsearch as ElasticsearchPlugin, savedObjects: server.savedObjects, - security: {} as SecurityPlugin, + getSecurity: () => ({} as SecurityPlugin), spacesAuditLogger: {} as SpacesAuditLogger, }); diff --git a/x-pack/plugins/spaces/server/lib/request_inteceptors/on_request_interceptor.test.ts b/x-pack/plugins/spaces/server/lib/request_inteceptors/on_request_interceptor.test.ts index 29bc66b5d074b..1d7e2ff8b1177 100644 --- a/x-pack/plugins/spaces/server/lib/request_inteceptors/on_request_interceptor.test.ts +++ b/x-pack/plugins/spaces/server/lib/request_inteceptors/on_request_interceptor.test.ts @@ -100,7 +100,7 @@ describe('onRequestInterceptor', () => { await spacesService.setup({ elasticsearch: server.plugins.elasticsearch as ElasticsearchPlugin, savedObjects: server.savedObjects, - security: {} as SecurityPlugin, + getSecurity: () => ({} as SecurityPlugin), spacesAuditLogger: {} as SpacesAuditLogger, }); diff --git a/x-pack/plugins/spaces/server/lib/saved_objects_client/spaces_saved_objects_client.test.ts b/x-pack/plugins/spaces/server/lib/saved_objects_client/spaces_saved_objects_client.test.ts index 51dd1a3b95761..4f42af00d5c75 100644 --- a/x-pack/plugins/spaces/server/lib/saved_objects_client/spaces_saved_objects_client.test.ts +++ b/x-pack/plugins/spaces/server/lib/saved_objects_client/spaces_saved_objects_client.test.ts @@ -67,7 +67,7 @@ const createSpacesService = async () => { }), } as unknown) as ElasticsearchPlugin, savedObjects: {} as SavedObjectsService, - security: {} as SecurityPlugin, + getSecurity: () => ({} as SecurityPlugin), spacesAuditLogger: {} as SpacesAuditLogger, }); }; diff --git a/x-pack/plugins/spaces/server/lib/spaces_tutorial_context_factory.test.ts b/x-pack/plugins/spaces/server/lib/spaces_tutorial_context_factory.test.ts index 54e79caf8534f..5ed8319cc75b6 100644 --- a/x-pack/plugins/spaces/server/lib/spaces_tutorial_context_factory.test.ts +++ b/x-pack/plugins/spaces/server/lib/spaces_tutorial_context_factory.test.ts @@ -47,7 +47,7 @@ describe('createSpacesTutorialContextFactory', () => { }), } as unknown) as ElasticsearchPlugin, savedObjects: {} as SavedObjectsService, - security: {} as SecurityPlugin, + getSecurity: () => ({} as SecurityPlugin), spacesAuditLogger: {} as SpacesAuditLogger, }); expect(typeof createSpacesTutorialContextFactory(spacesService)).toEqual('function'); @@ -62,7 +62,7 @@ describe('createSpacesTutorialContextFactory', () => { }), } as unknown) as ElasticsearchPlugin, savedObjects: {} as SavedObjectsService, - security: {} as SecurityPlugin, + getSecurity: () => ({} as SecurityPlugin), spacesAuditLogger: {} as SpacesAuditLogger, }); const contextFactory = createSpacesTutorialContextFactory(spacesService); @@ -86,7 +86,7 @@ describe('createSpacesTutorialContextFactory', () => { }), } as unknown) as ElasticsearchPlugin, savedObjects: {} as SavedObjectsService, - security: {} as SecurityPlugin, + getSecurity: () => ({} as SecurityPlugin), spacesAuditLogger: {} as SpacesAuditLogger, }); const contextFactory = createSpacesTutorialContextFactory(spacesService); diff --git a/x-pack/plugins/spaces/server/new_platform/plugin.ts b/x-pack/plugins/spaces/server/new_platform/plugin.ts index 0426339874e9f..d71ef25c673cd 100644 --- a/x-pack/plugins/spaces/server/new_platform/plugin.ts +++ b/x-pack/plugins/spaces/server/new_platform/plugin.ts @@ -56,7 +56,7 @@ export class Plugin { const spacesService = await service.setup({ elasticsearch: core.elasticsearch, savedObjects: core.savedObjects, - security: core.security, + getSecurity: core.getSecurity, spacesAuditLogger, }); diff --git a/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts b/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts index 1c81b62257605..b77845c33c199 100644 --- a/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts +++ b/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts @@ -29,7 +29,7 @@ interface CacheEntry { interface SpacesServiceDeps { elasticsearch: ElasticsearchPlugin; savedObjects: SavedObjectsService; - security: SecurityPlugin; + getSecurity: () => SecurityPlugin; spacesAuditLogger: any; } @@ -47,7 +47,7 @@ export class SpacesService { public async setup({ elasticsearch, savedObjects, - security, + getSecurity, spacesAuditLogger, }: SpacesServiceDeps): Promise { const adminClient = elasticsearch.getCluster('admin'); @@ -71,10 +71,13 @@ export class SpacesService { const { callWithRequest, callWithInternalUser } = adminClient; const internalRepository = savedObjects.getSavedObjectsRepository(callWithInternalUser); - const callWithRequestRepository = savedObjects.getSavedObjectsRepository( - (endpoint: string, params: any, options?: any) => - callWithRequest(request, endpoint, params, options) - ); + + const callCluster = (endpoint: string, ...args: any[]) => + callWithRequest(request, endpoint, ...args); + + const callWithRequestRepository = savedObjects.getSavedObjectsRepository(callCluster); + + const security = getSecurity(); const authorization = security ? security.authorization : null; return new SpacesClient( diff --git a/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_test_handler.ts b/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_test_handler.ts index 0788d3dbba746..b0412e4e61d67 100644 --- a/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_test_handler.ts +++ b/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_test_handler.ts @@ -160,7 +160,7 @@ export function createTestHandler(initApiFn: (deps: PublicRouteDeps & PrivateRou const spacesService = await service.setup({ elasticsearch: server.plugins.elasticsearch, savedObjects: server.savedObjects, - security: {} as SecurityPlugin, + getSecurity: () => ({} as SecurityPlugin), spacesAuditLogger: {} as SpacesAuditLogger, }); From d89f32085c627f2422e88b6527ba544fdfe558dd Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Wed, 24 Apr 2019 14:16:05 -0400 Subject: [PATCH 04/68] split CoreSetup into CoreSetup and PluginsSetup --- x-pack/plugins/spaces/index.ts | 31 ++++++++++++------- .../server/lib/request_inteceptors/index.ts | 4 +-- .../spaces/server/new_platform/plugin.ts | 13 ++++---- .../spaces_service/spaces_service.ts | 5 ++- 4 files changed, 30 insertions(+), 23 deletions(-) diff --git a/x-pack/plugins/spaces/index.ts b/x-pack/plugins/spaces/index.ts index cdbd59a920f23..5f8ef7ef2883b 100644 --- a/x-pack/plugins/spaces/index.ts +++ b/x-pack/plugins/spaces/index.ts @@ -9,7 +9,7 @@ import { resolve } from 'path'; import { SavedObjectsService } from 'src/legacy/server/saved_objects'; import { PluginInitializerContext, HttpServiceSetup } from 'src/core/server'; // @ts-ignore -import KbnServer, { Server } from 'src/legacy/server/kbn_server'; +import KbnServer, { Server, KibanaConfig } from 'src/legacy/server/kbn_server'; import { ElasticsearchPlugin } from 'src/legacy/core_plugins/elasticsearch'; // @ts-ignore import { AuditLogger } from '../../server/lib/audit_logger'; @@ -24,14 +24,11 @@ import { toggleUICapabilities } from './server/lib/toggle_ui_capabilities'; import { plugin } from './server/new_platform'; import { XPackMainPlugin } from '../xpack_main/xpack_main'; import { SecurityPlugin } from '../security'; -import { SpacesPlugin } from './types'; +import { SpacesServiceSetup } from './server/new_platform/spaces_service/spaces_service'; export interface SpacesCoreSetup { http: HttpServiceSetup; - xpackMain: XPackMainPlugin; - getSecurity: () => SecurityPlugin; savedObjects: SavedObjectsService; - spaces: SpacesPlugin; elasticsearch: ElasticsearchPlugin; usage: { collectorSet: { @@ -43,12 +40,19 @@ export interface SpacesCoreSetup { }; } -export interface SpacesConfig { - get: (key: string) => string; +export interface PluginsSetup { + getSecurity: () => SecurityPlugin; + xpackMain: XPackMainPlugin; + // TODO: this is temporary for `watchLicenseAndStatusToInitialize` + spaces: any; +} + +export interface SpacesPluginSetup { + spacesService: SpacesServiceSetup; } export interface SpacesInitializerContext extends PluginInitializerContext { - legacyConfig: SpacesConfig; + legacyConfig: KibanaConfig; } export const spaces = (kibana: Record) => @@ -155,9 +159,6 @@ export const spaces = (kibana: Record) => const core = { http: kbnServer.newPlatform.setup.core.http, elasticsearch: server.plugins.elasticsearch, - xpackMain: server.plugins.xpack_main, - spaces: this, - getSecurity: () => server.plugins.security, savedObjects: server.savedObjects, usage: (server as any).usage, tutorial: { @@ -165,11 +166,17 @@ export const spaces = (kibana: Record) => }, } as SpacesCoreSetup; + const plugins = { + xpackMain: server.plugins.xpack_main, + getSecurity: () => server.plugins.security, + spaces: this, + }; + // Need legacy because of `setup_base_path_provider` // (request.getBasePath and request.setBasePath) core.http.server = kbnServer as any; - const { spacesService } = await plugin(initializerContext).setup(core); + const { spacesService } = await plugin(initializerContext).setup(core, plugins); server.expose('getSpaceId', (request: any) => spacesService.getSpaceId(request)); server.expose('spacesClient', spacesService); diff --git a/x-pack/plugins/spaces/server/lib/request_inteceptors/index.ts b/x-pack/plugins/spaces/server/lib/request_inteceptors/index.ts index d5969958a0da2..154c9765767ae 100644 --- a/x-pack/plugins/spaces/server/lib/request_inteceptors/index.ts +++ b/x-pack/plugins/spaces/server/lib/request_inteceptors/index.ts @@ -5,14 +5,14 @@ */ import { HttpServiceSetup, Logger } from 'src/core/server'; -import { SpacesConfig } from '../../..'; +import { KibanaConfig } from 'src/legacy/server/kbn_server'; import { XPackMainPlugin } from '../../../../xpack_main/xpack_main'; import { initSpacesOnRequestInterceptor } from './on_request_interceptor'; import { initSpacesOnPostAuthRequestInterceptor } from './on_post_auth_interceptor'; import { SpacesServiceSetup } from '../../new_platform/spaces_service/spaces_service'; export interface InterceptorDeps { - config: SpacesConfig; + config: KibanaConfig; http: HttpServiceSetup; xpackMain: XPackMainPlugin; spacesService: SpacesServiceSetup; diff --git a/x-pack/plugins/spaces/server/new_platform/plugin.ts b/x-pack/plugins/spaces/server/new_platform/plugin.ts index d71ef25c673cd..e76c64e0a0e3d 100644 --- a/x-pack/plugins/spaces/server/new_platform/plugin.ts +++ b/x-pack/plugins/spaces/server/new_platform/plugin.ts @@ -5,9 +5,10 @@ */ import { Logger } from 'src/core/server'; +import { KibanaConfig } from 'src/legacy/server/kbn_server'; import { XPackMainPlugin } from '../../../xpack_main/xpack_main'; import { createDefaultSpace } from '../lib/create_default_space'; -import { SpacesCoreSetup, SpacesInitializerContext, SpacesConfig } from '../../index'; +import { SpacesCoreSetup, SpacesInitializerContext, PluginsSetup } from '../../index'; // @ts-ignore import { AuditLogger } from '../../../../server/lib/audit_logger'; // @ts-ignore @@ -25,7 +26,7 @@ import { SpacesService } from './spaces_service'; export class Plugin { private readonly pluginId = 'spaces'; - private config: SpacesConfig; + private config: KibanaConfig; private log: Logger; @@ -34,9 +35,9 @@ export class Plugin { this.log = initializerContext.logger.get('spaces'); } - public async setup(core: SpacesCoreSetup) { - const xpackMainPlugin: XPackMainPlugin = core.xpackMain; - watchStatusAndLicenseToInitialize(xpackMainPlugin, core.spaces, async () => { + public async setup(core: SpacesCoreSetup, plugins: PluginsSetup) { + const xpackMainPlugin: XPackMainPlugin = plugins.xpackMain; + watchStatusAndLicenseToInitialize(xpackMainPlugin, plugins.spaces, async () => { await createDefaultSpace({ elasticsearch: core.elasticsearch, savedObjects: core.savedObjects, @@ -56,7 +57,7 @@ export class Plugin { const spacesService = await service.setup({ elasticsearch: core.elasticsearch, savedObjects: core.savedObjects, - getSecurity: core.getSecurity, + getSecurity: plugins.getSecurity, spacesAuditLogger, }); diff --git a/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts b/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts index b77845c33c199..1c0d04c5bb963 100644 --- a/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts +++ b/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts @@ -5,11 +5,10 @@ */ import { Request } from 'hapi'; import { Logger } from 'src/core/server'; -import { SavedObjectsService } from 'src/legacy/server/kbn_server'; +import { SavedObjectsService, KibanaConfig } from 'src/legacy/server/kbn_server'; import { ElasticsearchPlugin } from 'src/legacy/core_plugins/elasticsearch'; import { DEFAULT_SPACE_ID } from '../../../common/constants'; import { SecurityPlugin } from '../../../../security'; -import { SpacesConfig } from '../../..'; import { SpacesClient } from '../../lib/spaces_client'; import { getSpaceIdFromPath } from '../../lib/spaces_url_parser'; @@ -38,7 +37,7 @@ export class SpacesService { private readonly contextCache: WeakMap; - constructor(private readonly log: Logger, private readonly config: SpacesConfig) { + constructor(private readonly log: Logger, private readonly config: KibanaConfig) { this.serverBasePath = config.get('server.basePath'); this.contextCache = new WeakMap(); From d5cae9f6643f39baee1d1329d40370c9b96375dc Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Wed, 24 Apr 2019 14:20:22 -0400 Subject: [PATCH 05/68] move interfaces to new plugin --- x-pack/plugins/spaces/index.ts | 44 +++---------------- .../spaces/server/new_platform/plugin.ts | 36 +++++++++++++-- 2 files changed, 38 insertions(+), 42 deletions(-) diff --git a/x-pack/plugins/spaces/index.ts b/x-pack/plugins/spaces/index.ts index 5f8ef7ef2883b..52ef84bdc5a3c 100644 --- a/x-pack/plugins/spaces/index.ts +++ b/x-pack/plugins/spaces/index.ts @@ -5,12 +5,9 @@ */ import { resolve } from 'path'; - -import { SavedObjectsService } from 'src/legacy/server/saved_objects'; -import { PluginInitializerContext, HttpServiceSetup } from 'src/core/server'; // @ts-ignore import KbnServer, { Server, KibanaConfig } from 'src/legacy/server/kbn_server'; -import { ElasticsearchPlugin } from 'src/legacy/core_plugins/elasticsearch'; +import { HttpServerInfo } from 'src/core/server/http'; // @ts-ignore import { AuditLogger } from '../../server/lib/audit_logger'; // @ts-ignore @@ -22,38 +19,7 @@ import { getSpaceSelectorUrl } from './server/lib/get_space_selector_url'; import { migrateToKibana660 } from './server/lib/migrations'; import { toggleUICapabilities } from './server/lib/toggle_ui_capabilities'; import { plugin } from './server/new_platform'; -import { XPackMainPlugin } from '../xpack_main/xpack_main'; -import { SecurityPlugin } from '../security'; -import { SpacesServiceSetup } from './server/new_platform/spaces_service/spaces_service'; - -export interface SpacesCoreSetup { - http: HttpServiceSetup; - savedObjects: SavedObjectsService; - elasticsearch: ElasticsearchPlugin; - usage: { - collectorSet: { - register: (collector: any) => void; - }; - }; - tutorial: { - addScopedTutorialContextFactory: (factory: any) => void; - }; -} - -export interface PluginsSetup { - getSecurity: () => SecurityPlugin; - xpackMain: XPackMainPlugin; - // TODO: this is temporary for `watchLicenseAndStatusToInitialize` - spaces: any; -} - -export interface SpacesPluginSetup { - spacesService: SpacesServiceSetup; -} - -export interface SpacesInitializerContext extends PluginInitializerContext { - legacyConfig: KibanaConfig; -} +import { SpacesInitializerContext, SpacesCoreSetup } from './server/new_platform/plugin'; export const spaces = (kibana: Record) => new kibana.Plugin({ @@ -156,15 +122,15 @@ export const spaces = (kibana: Record) => }, } as unknown) as SpacesInitializerContext; - const core = { - http: kbnServer.newPlatform.setup.core.http, + const core: SpacesCoreSetup = { + http: kbnServer.newPlatform.setup.core.http as HttpServerInfo, elasticsearch: server.plugins.elasticsearch, savedObjects: server.savedObjects, usage: (server as any).usage, tutorial: { addScopedTutorialContextFactory: (server as any).addScopedTutorialContextFactory, }, - } as SpacesCoreSetup; + }; const plugins = { xpackMain: server.plugins.xpack_main, diff --git a/x-pack/plugins/spaces/server/new_platform/plugin.ts b/x-pack/plugins/spaces/server/new_platform/plugin.ts index e76c64e0a0e3d..6e110f2a3aa4a 100644 --- a/x-pack/plugins/spaces/server/new_platform/plugin.ts +++ b/x-pack/plugins/spaces/server/new_platform/plugin.ts @@ -4,11 +4,11 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Logger } from 'src/core/server'; -import { KibanaConfig } from 'src/legacy/server/kbn_server'; +import { Logger, HttpServiceSetup, PluginInitializerContext } from 'src/core/server'; +import { KibanaConfig, SavedObjectsService } from 'src/legacy/server/kbn_server'; +import { ElasticsearchPlugin } from 'src/legacy/core_plugins/elasticsearch'; import { XPackMainPlugin } from '../../../xpack_main/xpack_main'; import { createDefaultSpace } from '../lib/create_default_space'; -import { SpacesCoreSetup, SpacesInitializerContext, PluginsSetup } from '../../index'; // @ts-ignore import { AuditLogger } from '../../../../server/lib/audit_logger'; // @ts-ignore @@ -22,7 +22,37 @@ import { initPublicSpacesApi } from '../routes/api/public'; import { initSpacesRequestInterceptors } from '../lib/request_inteceptors'; import { getSpacesUsageCollector } from '../lib/get_spaces_usage_collector'; import { SpacesService } from './spaces_service'; +import { SecurityPlugin } from '../../../security'; +import { SpacesServiceSetup } from './spaces_service/spaces_service'; + +export interface SpacesCoreSetup { + http: HttpServiceSetup; + savedObjects: SavedObjectsService; + elasticsearch: ElasticsearchPlugin; + usage: { + collectorSet: { + register: (collector: any) => void; + }; + }; + tutorial: { + addScopedTutorialContextFactory: (factory: any) => void; + }; +} + +export interface PluginsSetup { + getSecurity: () => SecurityPlugin; + xpackMain: XPackMainPlugin; + // TODO: this is temporary for `watchLicenseAndStatusToInitialize` + spaces: any; +} +export interface SpacesPluginSetup { + spacesService: SpacesServiceSetup; +} + +export interface SpacesInitializerContext extends PluginInitializerContext { + legacyConfig: KibanaConfig; +} export class Plugin { private readonly pluginId = 'spaces'; From 929cf7bb473919432a462af9a9af9c2529c12d65 Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Wed, 24 Apr 2019 14:43:22 -0400 Subject: [PATCH 06/68] init interceptors in legacy plugin --- x-pack/plugins/spaces/index.ts | 29 ++++++++++++++++--- .../server/lib/request_inteceptors/index.ts | 6 ++-- .../on_post_auth_interceptor.test.ts | 4 +-- .../on_post_auth_interceptor.ts | 6 ++-- .../on_request_interceptor.test.ts | 2 +- .../on_request_interceptor.ts | 4 +-- .../spaces/server/new_platform/plugin.ts | 20 ++++++------- .../api/__fixtures__/create_test_handler.ts | 5 ++-- .../spaces/server/routes/api/public/delete.ts | 2 +- .../spaces/server/routes/api/public/get.ts | 4 +-- .../spaces/server/routes/api/public/index.ts | 5 ++-- .../spaces/server/routes/api/public/post.ts | 2 +- .../spaces/server/routes/api/public/put.ts | 2 +- 13 files changed, 56 insertions(+), 35 deletions(-) diff --git a/x-pack/plugins/spaces/index.ts b/x-pack/plugins/spaces/index.ts index 52ef84bdc5a3c..f650238cf4ae1 100644 --- a/x-pack/plugins/spaces/index.ts +++ b/x-pack/plugins/spaces/index.ts @@ -19,7 +19,12 @@ import { getSpaceSelectorUrl } from './server/lib/get_space_selector_url'; import { migrateToKibana660 } from './server/lib/migrations'; import { toggleUICapabilities } from './server/lib/toggle_ui_capabilities'; import { plugin } from './server/new_platform'; -import { SpacesInitializerContext, SpacesCoreSetup } from './server/new_platform/plugin'; +import { + SpacesInitializerContext, + SpacesCoreSetup, + SpacesHttpServiceSetup, +} from './server/new_platform/plugin'; +import { initSpacesRequestInterceptors } from './server/lib/request_inteceptors'; export const spaces = (kibana: Record) => new kibana.Plugin({ @@ -122,8 +127,13 @@ export const spaces = (kibana: Record) => }, } as unknown) as SpacesInitializerContext; + const spacesHttpService: SpacesHttpServiceSetup = { + ...(kbnServer.newPlatform.setup.core.http as HttpServerInfo), + route: server.route.bind(server), + }; + const core: SpacesCoreSetup = { - http: kbnServer.newPlatform.setup.core.http as HttpServerInfo, + http: spacesHttpService, elasticsearch: server.plugins.elasticsearch, savedObjects: server.savedObjects, usage: (server as any).usage, @@ -140,9 +150,20 @@ export const spaces = (kibana: Record) => // Need legacy because of `setup_base_path_provider` // (request.getBasePath and request.setBasePath) - core.http.server = kbnServer as any; + // core.http.server = kbnServer as any; + + // @ts-ignore core.http.route does not exist yet. + core.http.route = server.route; + + const { spacesService, log } = await plugin(initializerContext).setup(core, plugins); - const { spacesService } = await plugin(initializerContext).setup(core, plugins); + initSpacesRequestInterceptors({ + config: initializerContext.legacyConfig, + legacyServer: server, + log, + spacesService, + xpackMain: plugins.xpackMain, + }); server.expose('getSpaceId', (request: any) => spacesService.getSpaceId(request)); server.expose('spacesClient', spacesService); diff --git a/x-pack/plugins/spaces/server/lib/request_inteceptors/index.ts b/x-pack/plugins/spaces/server/lib/request_inteceptors/index.ts index 154c9765767ae..4d47df42351f5 100644 --- a/x-pack/plugins/spaces/server/lib/request_inteceptors/index.ts +++ b/x-pack/plugins/spaces/server/lib/request_inteceptors/index.ts @@ -4,8 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -import { HttpServiceSetup, Logger } from 'src/core/server'; -import { KibanaConfig } from 'src/legacy/server/kbn_server'; +import { Logger } from 'src/core/server'; +import { KibanaConfig, Server } from 'src/legacy/server/kbn_server'; import { XPackMainPlugin } from '../../../../xpack_main/xpack_main'; import { initSpacesOnRequestInterceptor } from './on_request_interceptor'; import { initSpacesOnPostAuthRequestInterceptor } from './on_post_auth_interceptor'; @@ -13,7 +13,7 @@ import { SpacesServiceSetup } from '../../new_platform/spaces_service/spaces_ser export interface InterceptorDeps { config: KibanaConfig; - http: HttpServiceSetup; + legacyServer: Server; xpackMain: XPackMainPlugin; spacesService: SpacesServiceSetup; log: Logger; diff --git a/x-pack/plugins/spaces/server/lib/request_inteceptors/on_post_auth_interceptor.test.ts b/x-pack/plugins/spaces/server/lib/request_inteceptors/on_post_auth_interceptor.test.ts index 7304d0130417a..c0ecc5fc939af 100644 --- a/x-pack/plugins/spaces/server/lib/request_inteceptors/on_post_auth_interceptor.test.ts +++ b/x-pack/plugins/spaces/server/lib/request_inteceptors/on_post_auth_interceptor.test.ts @@ -163,14 +163,14 @@ describe('onPostAuthRequestInterceptor', () => { // we are including the already tested interceptor here in the test chain. initSpacesOnRequestInterceptor({ config: server.config(), - http: { server } as any, + legacyServer: server, log, xpackMain: server.plugins.xpack_main, spacesService, }); initSpacesOnPostAuthRequestInterceptor({ config: server.config(), - http: { server } as any, + legacyServer: server, log, xpackMain: server.plugins.xpack_main, spacesService, diff --git a/x-pack/plugins/spaces/server/lib/request_inteceptors/on_post_auth_interceptor.ts b/x-pack/plugins/spaces/server/lib/request_inteceptors/on_post_auth_interceptor.ts index f506d77940f0e..834431081fb88 100644 --- a/x-pack/plugins/spaces/server/lib/request_inteceptors/on_post_auth_interceptor.ts +++ b/x-pack/plugins/spaces/server/lib/request_inteceptors/on_post_auth_interceptor.ts @@ -12,14 +12,14 @@ import { InterceptorDeps } from '.'; export function initSpacesOnPostAuthRequestInterceptor({ config, - http, + legacyServer, xpackMain, spacesService, log, }: InterceptorDeps) { const serverBasePath: string = config.get('server.basePath'); - http.server.ext('onPostAuth', async function spacesOnPostAuthHandler(request: any, h: any) { + legacyServer.ext('onPostAuth', async function spacesOnPostAuthHandler(request: any, h: any) { const path = request.path; const isRequestingKibanaRoot = path === '/'; @@ -48,7 +48,7 @@ export function initSpacesOnPostAuthRequestInterceptor({ if (spaces.length > 0) { // render spaces selector instead of home page - const app = http.server.getHiddenUiAppById('space_selector'); + const app = legacyServer.getHiddenUiAppById('space_selector'); return (await h.renderApp(app, { spaces })).takeover(); } } catch (error) { diff --git a/x-pack/plugins/spaces/server/lib/request_inteceptors/on_request_interceptor.test.ts b/x-pack/plugins/spaces/server/lib/request_inteceptors/on_request_interceptor.test.ts index 1d7e2ff8b1177..c94f3653a12b9 100644 --- a/x-pack/plugins/spaces/server/lib/request_inteceptors/on_request_interceptor.test.ts +++ b/x-pack/plugins/spaces/server/lib/request_inteceptors/on_request_interceptor.test.ts @@ -106,7 +106,7 @@ describe('onRequestInterceptor', () => { initSpacesOnRequestInterceptor({ config: server.config(), - http: { server } as any, + legacyServer: server, log, xpackMain: {} as XPackMainPlugin, spacesService: { diff --git a/x-pack/plugins/spaces/server/lib/request_inteceptors/on_request_interceptor.ts b/x-pack/plugins/spaces/server/lib/request_inteceptors/on_request_interceptor.ts index 928d67d9220c2..55153cf508864 100644 --- a/x-pack/plugins/spaces/server/lib/request_inteceptors/on_request_interceptor.ts +++ b/x-pack/plugins/spaces/server/lib/request_inteceptors/on_request_interceptor.ts @@ -7,10 +7,10 @@ import { DEFAULT_SPACE_ID } from '../../../common/constants'; import { getSpaceIdFromPath } from '../spaces_url_parser'; import { InterceptorDeps } from '.'; -export function initSpacesOnRequestInterceptor({ config, http }: InterceptorDeps) { +export function initSpacesOnRequestInterceptor({ config, legacyServer }: InterceptorDeps) { const serverBasePath: string = config.get('server.basePath'); - http.server.ext('onRequest', async function spacesOnRequestHandler(request: any, h: any) { + legacyServer.ext('onRequest', async function spacesOnRequestHandler(request: any, h: any) { const path = request.path; // If navigating within the context of a space, then we store the Space's URL Context on the request, diff --git a/x-pack/plugins/spaces/server/new_platform/plugin.ts b/x-pack/plugins/spaces/server/new_platform/plugin.ts index 6e110f2a3aa4a..e2d266d1c4c4f 100644 --- a/x-pack/plugins/spaces/server/new_platform/plugin.ts +++ b/x-pack/plugins/spaces/server/new_platform/plugin.ts @@ -7,6 +7,7 @@ import { Logger, HttpServiceSetup, PluginInitializerContext } from 'src/core/server'; import { KibanaConfig, SavedObjectsService } from 'src/legacy/server/kbn_server'; import { ElasticsearchPlugin } from 'src/legacy/core_plugins/elasticsearch'; +import { ServerRoute } from 'hapi'; import { XPackMainPlugin } from '../../../xpack_main/xpack_main'; import { createDefaultSpace } from '../lib/create_default_space'; // @ts-ignore @@ -19,14 +20,16 @@ import { SpacesAuditLogger } from '../lib/audit_logger'; import { createSpacesTutorialContextFactory } from '../lib/spaces_tutorial_context_factory'; import { initPrivateApis } from '../routes/api/v1'; import { initPublicSpacesApi } from '../routes/api/public'; -import { initSpacesRequestInterceptors } from '../lib/request_inteceptors'; import { getSpacesUsageCollector } from '../lib/get_spaces_usage_collector'; import { SpacesService } from './spaces_service'; import { SecurityPlugin } from '../../../security'; import { SpacesServiceSetup } from './spaces_service/spaces_service'; +export interface SpacesHttpServiceSetup extends HttpServiceSetup { + route(route: ServerRoute | ServerRoute[]): void; +} export interface SpacesCoreSetup { - http: HttpServiceSetup; + http: SpacesHttpServiceSetup; savedObjects: SavedObjectsService; elasticsearch: ElasticsearchPlugin; usage: { @@ -48,6 +51,8 @@ export interface PluginsSetup { export interface SpacesPluginSetup { spacesService: SpacesServiceSetup; + // TODO: this is temporary, required by request interceptors which are initialized in legacy plugin + log: Logger; } export interface SpacesInitializerContext extends PluginInitializerContext { @@ -65,7 +70,7 @@ export class Plugin { this.log = initializerContext.logger.get('spaces'); } - public async setup(core: SpacesCoreSetup, plugins: PluginsSetup) { + public async setup(core: SpacesCoreSetup, plugins: PluginsSetup): Promise { const xpackMainPlugin: XPackMainPlugin = plugins.xpackMain; watchStatusAndLicenseToInitialize(xpackMainPlugin, plugins.spaces, async () => { await createDefaultSpace({ @@ -117,14 +122,6 @@ export class Plugin { xpackMain: xpackMainPlugin, }); - initSpacesRequestInterceptors({ - config: this.config, - http: core.http, - log: this.log, - spacesService, - xpackMain: xpackMainPlugin, - }); - // Register a function with server to manage the collection of usage stats core.usage.collectorSet.register( getSpacesUsageCollector({ @@ -137,6 +134,7 @@ export class Plugin { return { spacesService, + log: this.log, }; } } diff --git a/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_test_handler.ts b/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_test_handler.ts index b0412e4e61d67..55ddf9174abf9 100644 --- a/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_test_handler.ts +++ b/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_test_handler.ts @@ -7,7 +7,6 @@ // @ts-ignore import { Server } from 'hapi'; import { Legacy } from 'kibana'; -import { HttpServiceSetup } from 'src/core/server'; import { SecurityPlugin } from '../../../../../security'; import { SpacesClient } from '../../../lib/spaces_client'; import { createSpaces } from './create_spaces'; @@ -15,6 +14,7 @@ import { PublicRouteDeps } from '../public'; import { SpacesService } from '../../../new_platform/spaces_service'; import { SpacesAuditLogger } from '../../../lib/audit_logger'; import { PrivateRouteDeps } from '../v1'; +import { SpacesHttpServiceSetup } from '../../../new_platform/plugin'; interface KibanaServer extends Legacy.Server { savedObjects: any; @@ -179,7 +179,8 @@ export function createTestHandler(initApiFn: (deps: PublicRouteDeps & PrivateRou initApiFn({ http: ({ server, - } as unknown) as HttpServiceSetup, + route: server.route.bind(server), + } as unknown) as SpacesHttpServiceSetup, routePreCheckLicenseFn: pre, savedObjects: server.savedObjects, spacesService, diff --git a/x-pack/plugins/spaces/server/routes/api/public/delete.ts b/x-pack/plugins/spaces/server/routes/api/public/delete.ts index 92e68632bddbb..5edb0a775362f 100644 --- a/x-pack/plugins/spaces/server/routes/api/public/delete.ts +++ b/x-pack/plugins/spaces/server/routes/api/public/delete.ts @@ -12,7 +12,7 @@ import { PublicRouteDeps } from '.'; export function initDeleteSpacesApi(deps: PublicRouteDeps) { const { http, savedObjects, spacesService, routePreCheckLicenseFn } = deps; - http.server.route({ + http.route({ method: 'DELETE', path: '/api/spaces/space/{id}', async handler(request: any, h: any) { diff --git a/x-pack/plugins/spaces/server/routes/api/public/get.ts b/x-pack/plugins/spaces/server/routes/api/public/get.ts index f0cfd0aa42b47..1d0f50c85a86d 100644 --- a/x-pack/plugins/spaces/server/routes/api/public/get.ts +++ b/x-pack/plugins/spaces/server/routes/api/public/get.ts @@ -13,7 +13,7 @@ import { PublicRouteDeps } from '.'; export function initGetSpacesApi(deps: PublicRouteDeps) { const { http, log, spacesService, savedObjects, routePreCheckLicenseFn } = deps; - http.server.route({ + http.route({ method: 'GET', path: '/api/spaces/space', async handler(request: any) { @@ -39,7 +39,7 @@ export function initGetSpacesApi(deps: PublicRouteDeps) { }, }); - http.server.route({ + http.route({ method: 'GET', path: '/api/spaces/space/{id}', async handler(request: any) { diff --git a/x-pack/plugins/spaces/server/routes/api/public/index.ts b/x-pack/plugins/spaces/server/routes/api/public/index.ts index 7f8977b8580b7..176b6b41ff012 100644 --- a/x-pack/plugins/spaces/server/routes/api/public/index.ts +++ b/x-pack/plugins/spaces/server/routes/api/public/index.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { HttpServiceSetup, Logger } from 'src/core/server'; +import { Logger } from 'src/core/server'; import { SavedObjectsService } from 'src/legacy/server/kbn_server'; import { XPackMainPlugin } from '../../../../../xpack_main/xpack_main'; import { routePreCheckLicense } from '../../../lib/route_pre_check_license'; @@ -13,12 +13,13 @@ import { initGetSpacesApi } from './get'; import { initPostSpacesApi } from './post'; import { initPutSpacesApi } from './put'; import { SpacesServiceSetup } from '../../../new_platform/spaces_service/spaces_service'; +import { SpacesHttpServiceSetup } from '../../../new_platform/plugin'; type InterfaceExcept = Pick>; interface RouteDeps { xpackMain: XPackMainPlugin; - http: HttpServiceSetup; + http: SpacesHttpServiceSetup; savedObjects: SavedObjectsService; spacesService: SpacesServiceSetup; log: Logger; diff --git a/x-pack/plugins/spaces/server/routes/api/public/post.ts b/x-pack/plugins/spaces/server/routes/api/public/post.ts index fb5961e549ff0..e04da42bb52a5 100644 --- a/x-pack/plugins/spaces/server/routes/api/public/post.ts +++ b/x-pack/plugins/spaces/server/routes/api/public/post.ts @@ -13,7 +13,7 @@ import { PublicRouteDeps } from '.'; export function initPostSpacesApi(deps: PublicRouteDeps) { const { http, log, spacesService, savedObjects, routePreCheckLicenseFn } = deps; - http.server.route({ + http.route({ method: 'POST', path: '/api/spaces/space', async handler(request: any) { diff --git a/x-pack/plugins/spaces/server/routes/api/public/put.ts b/x-pack/plugins/spaces/server/routes/api/public/put.ts index b503b3f99eef8..779a032184e0f 100644 --- a/x-pack/plugins/spaces/server/routes/api/public/put.ts +++ b/x-pack/plugins/spaces/server/routes/api/public/put.ts @@ -14,7 +14,7 @@ import { PublicRouteDeps } from '.'; export function initPutSpacesApi(deps: PublicRouteDeps) { const { http, spacesService, savedObjects, routePreCheckLicenseFn } = deps; - http.server.route({ + http.route({ method: 'PUT', path: '/api/spaces/space/{id}', async handler(request: any) { From 751e4a76f2fb748a196cbe5c823560d26761b4ae Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Wed, 24 Apr 2019 14:48:35 -0400 Subject: [PATCH 07/68] fix import --- x-pack/plugins/spaces/server/new_platform/index.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/x-pack/plugins/spaces/server/new_platform/index.ts b/x-pack/plugins/spaces/server/new_platform/index.ts index cc36a09bde1a5..cc0b8911b3791 100644 --- a/x-pack/plugins/spaces/server/new_platform/index.ts +++ b/x-pack/plugins/spaces/server/new_platform/index.ts @@ -4,8 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Plugin } from './plugin'; -import { SpacesInitializerContext } from '../..'; +import { Plugin, SpacesInitializerContext } from './plugin'; export function plugin(initializerContext: SpacesInitializerContext) { return new Plugin(initializerContext); From ae7850a780379204817448016a2b495818e6a4fa Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Wed, 24 Apr 2019 14:49:57 -0400 Subject: [PATCH 08/68] add placeholder kibana.json --- x-pack/plugins/spaces/kibana.json | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 x-pack/plugins/spaces/kibana.json diff --git a/x-pack/plugins/spaces/kibana.json b/x-pack/plugins/spaces/kibana.json new file mode 100644 index 0000000000000..285ddf048d02a --- /dev/null +++ b/x-pack/plugins/spaces/kibana.json @@ -0,0 +1,11 @@ +{ + "id": "spaces", + "version": "0.0.1", + "kibanaVersion": "kibana", + "configPath": [ + "xpack", + "spaces" + ], + "server": true, + "ui": true +} \ No newline at end of file From 1e4cd9551bc0d8bfb2103ca5a99e0c9464c33e84 Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Wed, 24 Apr 2019 15:37:19 -0400 Subject: [PATCH 09/68] use NP Elasticsearch service instead of legacy ES Plugin --- x-pack/plugins/spaces/index.ts | 9 +---- .../server/lib/create_default_space.test.ts | 11 +++--- .../spaces/server/lib/create_default_space.ts | 12 ++++--- .../on_post_auth_interceptor.test.ts | 13 +++++-- .../on_request_interceptor.test.ts | 12 +++++-- .../spaces_saved_objects_client.test.ts | 18 +++++----- .../spaces_tutorial_context_factory.test.ts | 36 +++++++++++-------- .../spaces/server/new_platform/plugin.ts | 10 ++++-- .../spaces_service/spaces_service.ts | 14 ++++---- .../api/__fixtures__/create_test_handler.ts | 15 ++++++-- .../spaces/server/routes/api/v1/index.ts | 9 +++-- .../spaces/server/routes/api/v1/spaces.ts | 2 +- 12 files changed, 96 insertions(+), 65 deletions(-) diff --git a/x-pack/plugins/spaces/index.ts b/x-pack/plugins/spaces/index.ts index f650238cf4ae1..bc5241fdfb053 100644 --- a/x-pack/plugins/spaces/index.ts +++ b/x-pack/plugins/spaces/index.ts @@ -134,7 +134,7 @@ export const spaces = (kibana: Record) => const core: SpacesCoreSetup = { http: spacesHttpService, - elasticsearch: server.plugins.elasticsearch, + elasticsearch: kbnServer.newPlatform.setup.core.elasticsearch, savedObjects: server.savedObjects, usage: (server as any).usage, tutorial: { @@ -148,13 +148,6 @@ export const spaces = (kibana: Record) => spaces: this, }; - // Need legacy because of `setup_base_path_provider` - // (request.getBasePath and request.setBasePath) - // core.http.server = kbnServer as any; - - // @ts-ignore core.http.route does not exist yet. - core.http.route = server.route; - const { spacesService, log } = await plugin(initializerContext).setup(core, plugins); initSpacesRequestInterceptors({ diff --git a/x-pack/plugins/spaces/server/lib/create_default_space.test.ts b/x-pack/plugins/spaces/server/lib/create_default_space.test.ts index 6e88d3a7929eb..ab38d52f1b91f 100644 --- a/x-pack/plugins/spaces/server/lib/create_default_space.test.ts +++ b/x-pack/plugins/spaces/server/lib/create_default_space.test.ts @@ -6,13 +6,13 @@ jest.mock('../../../../server/lib/get_client_shield', () => ({ getClient: jest.fn(), })); - +import * as Rx from 'rxjs'; import Boom from 'boom'; // @ts-ignore import { getClient } from '../../../../server/lib/get_client_shield'; import { createDefaultSpace } from './create_default_space'; -import { ElasticsearchPlugin } from 'src/legacy/core_plugins/elasticsearch'; import { SavedObjectsService } from 'src/legacy/server/kbn_server'; +import { ElasticsearchServiceSetup } from 'src/core/server'; let mockCallWithRequest; beforeEach(() => { @@ -86,11 +86,10 @@ const createMockDeps = (settings: MockServerSettings = {}) => { config: mockServer.config(), savedObjects: (mockServer.savedObjects as unknown) as SavedObjectsService, elasticsearch: ({ - getCluster: jest.fn().mockReturnValue({ - callWithRequest: jest.fn(), - callWithInternalUser: jest.fn(), + dataClient$: Rx.of({ + callAsInternalUser: jest.fn(), }), - } as unknown) as ElasticsearchPlugin, + } as unknown) as ElasticsearchServiceSetup, }; }; diff --git a/x-pack/plugins/spaces/server/lib/create_default_space.ts b/x-pack/plugins/spaces/server/lib/create_default_space.ts index 17a8dcf6da6bb..4a229ede0e443 100644 --- a/x-pack/plugins/spaces/server/lib/create_default_space.ts +++ b/x-pack/plugins/spaces/server/lib/create_default_space.ts @@ -7,19 +7,21 @@ import { i18n } from '@kbn/i18n'; import { SavedObjectsService } from 'src/legacy/server/kbn_server'; -// @ts-ignore -import { ElasticsearchPlugin } from 'src/legacy/core_plugins/elasticsearch'; +import { ElasticsearchServiceSetup } from 'src/core/server'; +import { first } from 'rxjs/operators'; import { DEFAULT_SPACE_ID } from '../../common/constants'; interface Deps { - elasticsearch: ElasticsearchPlugin; + elasticsearch: ElasticsearchServiceSetup; savedObjects: SavedObjectsService; } export async function createDefaultSpace({ elasticsearch, savedObjects }: Deps) { const { getSavedObjectsRepository, SavedObjectsClient } = savedObjects; - const { callWithInternalUser } = elasticsearch.getCluster('admin'); - const savedObjectsRepository = getSavedObjectsRepository(callWithInternalUser); + + const client = await elasticsearch.dataClient$.pipe(first()).toPromise(); + + const savedObjectsRepository = getSavedObjectsRepository(client.callAsInternalUser); const defaultSpaceExists = await doesDefaultSpaceExist( SavedObjectsClient, diff --git a/x-pack/plugins/spaces/server/lib/request_inteceptors/on_post_auth_interceptor.test.ts b/x-pack/plugins/spaces/server/lib/request_inteceptors/on_post_auth_interceptor.test.ts index c0ecc5fc939af..ba138f05871f3 100644 --- a/x-pack/plugins/spaces/server/lib/request_inteceptors/on_post_auth_interceptor.test.ts +++ b/x-pack/plugins/spaces/server/lib/request_inteceptors/on_post_auth_interceptor.test.ts @@ -6,17 +6,17 @@ import { Server } from 'hapi'; import sinon from 'sinon'; - +import * as Rx from 'rxjs'; import { SavedObject } from 'src/legacy/server/saved_objects'; import { Feature } from '../../../../xpack_main/types'; import { convertSavedObjectToSpace } from '../../routes/lib'; import { initSpacesOnPostAuthRequestInterceptor } from './on_post_auth_interceptor'; import { initSpacesOnRequestInterceptor } from './on_request_interceptor'; import { SpacesService } from '../../new_platform/spaces_service'; -import { ElasticsearchPlugin } from 'src/legacy/core_plugins/elasticsearch'; import { SecurityPlugin } from '../../../../security'; import { SpacesAuditLogger } from '../audit_logger'; import { SpacesServiceSetup } from '../../new_platform/spaces_service/spaces_service'; +import { ElasticsearchServiceSetup } from 'src/core/server'; describe('onPostAuthRequestInterceptor', () => { const sandbox = sinon.sandbox.create(); @@ -139,7 +139,14 @@ describe('onPostAuthRequestInterceptor', () => { const service = new SpacesService(log, server.config()); spacesService = await service.setup({ - elasticsearch: server.plugins.elasticsearch as ElasticsearchPlugin, + elasticsearch: ({ + adminClient$: Rx.of({ + callAsInternalUser: jest.fn(), + asScoped: jest.fn(req => ({ + callWithRequest: jest.fn(), + })), + }), + } as unknown) as ElasticsearchServiceSetup, savedObjects: server.savedObjects, getSecurity: () => ({} as SecurityPlugin), spacesAuditLogger: {} as SpacesAuditLogger, diff --git a/x-pack/plugins/spaces/server/lib/request_inteceptors/on_request_interceptor.test.ts b/x-pack/plugins/spaces/server/lib/request_inteceptors/on_request_interceptor.test.ts index c94f3653a12b9..495174ef3682d 100644 --- a/x-pack/plugins/spaces/server/lib/request_inteceptors/on_request_interceptor.test.ts +++ b/x-pack/plugins/spaces/server/lib/request_inteceptors/on_request_interceptor.test.ts @@ -6,7 +6,7 @@ import { Server } from 'hapi'; import sinon from 'sinon'; - +import * as Rx from 'rxjs'; import { initSpacesOnRequestInterceptor } from './on_request_interceptor'; import { SpacesService } from '../../new_platform/spaces_service'; import { XPackMainPlugin } from '../../../../xpack_main/xpack_main'; @@ -14,6 +14,7 @@ import { ElasticsearchPlugin } from 'src/legacy/core_plugins/elasticsearch'; import { SecurityPlugin } from '../../../../security'; import { SpacesAuditLogger } from '../audit_logger'; import { SpacesServiceSetup } from '../../new_platform/spaces_service/spaces_service'; +import { ElasticsearchServiceSetup } from 'src/core/server'; describe('onRequestInterceptor', () => { const sandbox = sinon.sandbox.create(); @@ -98,7 +99,14 @@ describe('onRequestInterceptor', () => { const spacesService = new SpacesService(log, server.config()); await spacesService.setup({ - elasticsearch: server.plugins.elasticsearch as ElasticsearchPlugin, + elasticsearch: ({ + adminClient$: Rx.of({ + callAsInternalUser: jest.fn(), + asScoped: jest.fn(req => ({ + callWithRequest: jest.fn(), + })), + }), + } as unknown) as ElasticsearchServiceSetup, savedObjects: server.savedObjects, getSecurity: () => ({} as SecurityPlugin), spacesAuditLogger: {} as SpacesAuditLogger, diff --git a/x-pack/plugins/spaces/server/lib/saved_objects_client/spaces_saved_objects_client.test.ts b/x-pack/plugins/spaces/server/lib/saved_objects_client/spaces_saved_objects_client.test.ts index 4f42af00d5c75..30907aae5a926 100644 --- a/x-pack/plugins/spaces/server/lib/saved_objects_client/spaces_saved_objects_client.test.ts +++ b/x-pack/plugins/spaces/server/lib/saved_objects_client/spaces_saved_objects_client.test.ts @@ -3,15 +3,15 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ - +import * as Rx from 'rxjs'; import { DEFAULT_SPACE_ID } from '../../../common/constants'; import { Space } from '../../../common/model/space'; import { SpacesSavedObjectsClient } from './spaces_saved_objects_client'; import { SpacesService } from '../../new_platform/spaces_service'; -import { ElasticsearchPlugin } from 'src/legacy/core_plugins/elasticsearch'; -import { SavedObjectsService } from 'src/legacy/server/kbn_server'; +import { SavedObjectsService, KibanaConfig } from 'src/legacy/server/kbn_server'; import { SecurityPlugin } from '../../../../security'; import { SpacesAuditLogger } from '../audit_logger'; +import { ElasticsearchServiceSetup } from 'src/core/server'; const config: any = { 'server.basePath': '/', @@ -37,7 +37,7 @@ const log = { fatal: jest.fn(), }; -const service = new SpacesService(log, server.config()); +const service = new SpacesService(log, server.config() as KibanaConfig); const createMockRequest = (space: Partial) => ({ getBasePath: () => (space.id !== DEFAULT_SPACE_ID ? `/s/${space.id}` : ''), @@ -61,11 +61,13 @@ const createMockClient = () => { const createSpacesService = async () => { return service.setup({ elasticsearch: ({ - getCluster: jest.fn().mockReturnValue({ - callWithRequest: jest.fn(), - callWithInternalUser: jest.fn(), + adminClient$: Rx.of({ + callAsInternalUser: jest.fn(), + asScoped: jest.fn(req => ({ + callWithRequest: jest.fn(), + })), }), - } as unknown) as ElasticsearchPlugin, + } as unknown) as ElasticsearchServiceSetup, savedObjects: {} as SavedObjectsService, getSecurity: () => ({} as SecurityPlugin), spacesAuditLogger: {} as SpacesAuditLogger, diff --git a/x-pack/plugins/spaces/server/lib/spaces_tutorial_context_factory.test.ts b/x-pack/plugins/spaces/server/lib/spaces_tutorial_context_factory.test.ts index 5ed8319cc75b6..118bd686ab507 100644 --- a/x-pack/plugins/spaces/server/lib/spaces_tutorial_context_factory.test.ts +++ b/x-pack/plugins/spaces/server/lib/spaces_tutorial_context_factory.test.ts @@ -4,13 +4,15 @@ * you may not use this file except in compliance with the Elastic License. */ +import * as Rx from 'rxjs'; import { DEFAULT_SPACE_ID } from '../../common/constants'; import { createSpacesTutorialContextFactory } from './spaces_tutorial_context_factory'; import { SpacesService } from '../new_platform/spaces_service'; import { ElasticsearchPlugin } from 'src/legacy/core_plugins/elasticsearch'; -import { SavedObjectsService } from 'src/legacy/server/kbn_server'; +import { SavedObjectsService, KibanaConfig } from 'src/legacy/server/kbn_server'; import { SecurityPlugin } from '../../../security'; import { SpacesAuditLogger } from './audit_logger'; +import { ElasticsearchServiceSetup } from 'src/core/server'; const server = { config: () => { @@ -35,17 +37,19 @@ const log = { fatal: jest.fn(), }; -const service = new SpacesService(log, server.config()); +const service = new SpacesService(log, server.config() as KibanaConfig); describe('createSpacesTutorialContextFactory', () => { it('should create a valid context factory', async () => { const spacesService = await service.setup({ elasticsearch: ({ - getCluster: jest.fn().mockReturnValue({ - callWithRequest: jest.fn(), - callWithInternalUser: jest.fn(), + adminClient$: Rx.of({ + callAsInternalUser: jest.fn(), + asScoped: jest.fn(req => ({ + callWithRequest: jest.fn(), + })), }), - } as unknown) as ElasticsearchPlugin, + } as unknown) as ElasticsearchServiceSetup, savedObjects: {} as SavedObjectsService, getSecurity: () => ({} as SecurityPlugin), spacesAuditLogger: {} as SpacesAuditLogger, @@ -56,11 +60,13 @@ describe('createSpacesTutorialContextFactory', () => { it('should create context with the current space id for space my-space-id', async () => { const spacesService = await service.setup({ elasticsearch: ({ - getCluster: jest.fn().mockReturnValue({ - callWithRequest: jest.fn(), - callWithInternalUser: jest.fn(), + adminClient$: Rx.of({ + callAsInternalUser: jest.fn(), + asScoped: jest.fn(req => ({ + callWithRequest: jest.fn(), + })), }), - } as unknown) as ElasticsearchPlugin, + } as unknown) as ElasticsearchServiceSetup, savedObjects: {} as SavedObjectsService, getSecurity: () => ({} as SecurityPlugin), spacesAuditLogger: {} as SpacesAuditLogger, @@ -80,11 +86,13 @@ describe('createSpacesTutorialContextFactory', () => { it('should create context with the current space id for the default space', async () => { const spacesService = await service.setup({ elasticsearch: ({ - getCluster: jest.fn().mockReturnValue({ - callWithRequest: jest.fn(), - callWithInternalUser: jest.fn(), + adminClient$: Rx.of({ + callAsInternalUser: jest.fn(), + asScoped: jest.fn(req => ({ + callWithRequest: jest.fn(), + })), }), - } as unknown) as ElasticsearchPlugin, + } as unknown) as ElasticsearchServiceSetup, savedObjects: {} as SavedObjectsService, getSecurity: () => ({} as SecurityPlugin), spacesAuditLogger: {} as SpacesAuditLogger, diff --git a/x-pack/plugins/spaces/server/new_platform/plugin.ts b/x-pack/plugins/spaces/server/new_platform/plugin.ts index e2d266d1c4c4f..f010e617dfb50 100644 --- a/x-pack/plugins/spaces/server/new_platform/plugin.ts +++ b/x-pack/plugins/spaces/server/new_platform/plugin.ts @@ -4,9 +4,13 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Logger, HttpServiceSetup, PluginInitializerContext } from 'src/core/server'; +import { + Logger, + HttpServiceSetup, + PluginInitializerContext, + ElasticsearchServiceSetup, +} from 'src/core/server'; import { KibanaConfig, SavedObjectsService } from 'src/legacy/server/kbn_server'; -import { ElasticsearchPlugin } from 'src/legacy/core_plugins/elasticsearch'; import { ServerRoute } from 'hapi'; import { XPackMainPlugin } from '../../../xpack_main/xpack_main'; import { createDefaultSpace } from '../lib/create_default_space'; @@ -31,7 +35,7 @@ export interface SpacesHttpServiceSetup extends HttpServiceSetup { export interface SpacesCoreSetup { http: SpacesHttpServiceSetup; savedObjects: SavedObjectsService; - elasticsearch: ElasticsearchPlugin; + elasticsearch: ElasticsearchServiceSetup; usage: { collectorSet: { register: (collector: any) => void; diff --git a/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts b/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts index 1c0d04c5bb963..207c8769e731b 100644 --- a/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts +++ b/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts @@ -4,9 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ import { Request } from 'hapi'; -import { Logger } from 'src/core/server'; +import { Logger, ElasticsearchServiceSetup } from 'src/core/server'; import { SavedObjectsService, KibanaConfig } from 'src/legacy/server/kbn_server'; -import { ElasticsearchPlugin } from 'src/legacy/core_plugins/elasticsearch'; +import { first } from 'rxjs/operators'; import { DEFAULT_SPACE_ID } from '../../../common/constants'; import { SecurityPlugin } from '../../../../security'; import { SpacesClient } from '../../lib/spaces_client'; @@ -26,7 +26,7 @@ interface CacheEntry { } interface SpacesServiceDeps { - elasticsearch: ElasticsearchPlugin; + elasticsearch: ElasticsearchServiceSetup; savedObjects: SavedObjectsService; getSecurity: () => SecurityPlugin; spacesAuditLogger: any; @@ -49,7 +49,7 @@ export class SpacesService { getSecurity, spacesAuditLogger, }: SpacesServiceDeps): Promise { - const adminClient = elasticsearch.getCluster('admin'); + const adminClient = await elasticsearch.adminClient$.pipe(first()).toPromise(); return { getSpaceId: (request: Record) => { if (!this.contextCache.has(request)) { @@ -67,12 +67,12 @@ export class SpacesService { return this.contextCache.get(request)!.isInDefaultSpace; }, scopedClient: (request: Request) => { - const { callWithRequest, callWithInternalUser } = adminClient; + const { asScoped, callAsInternalUser } = adminClient; - const internalRepository = savedObjects.getSavedObjectsRepository(callWithInternalUser); + const internalRepository = savedObjects.getSavedObjectsRepository(callAsInternalUser); const callCluster = (endpoint: string, ...args: any[]) => - callWithRequest(request, endpoint, ...args); + asScoped(request).callAsCurrentUser(endpoint, ...args); const callWithRequestRepository = savedObjects.getSavedObjectsRepository(callCluster); diff --git a/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_test_handler.ts b/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_test_handler.ts index 55ddf9174abf9..50c69a95c99f4 100644 --- a/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_test_handler.ts +++ b/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_test_handler.ts @@ -4,9 +4,11 @@ * you may not use this file except in compliance with the Elastic License. */ -// @ts-ignore +import * as Rx from 'rxjs'; import { Server } from 'hapi'; import { Legacy } from 'kibana'; +import { ElasticsearchServiceSetup } from 'src/core/server'; +import { KibanaConfig } from 'src/legacy/server/kbn_server'; import { SecurityPlugin } from '../../../../../security'; import { SpacesClient } from '../../../lib/spaces_client'; import { createSpaces } from './create_spaces'; @@ -158,7 +160,14 @@ export function createTestHandler(initApiFn: (deps: PublicRouteDeps & PrivateRou const service = new SpacesService(log, server.config()); const spacesService = await service.setup({ - elasticsearch: server.plugins.elasticsearch, + elasticsearch: ({ + adminClient$: Rx.of({ + callAsInternalUser: jest.fn(), + asScoped: jest.fn(req => ({ + callWithRequest: jest.fn(), + })), + }), + } as unknown) as ElasticsearchServiceSetup, savedObjects: server.savedObjects, getSecurity: () => ({} as SecurityPlugin), spacesAuditLogger: {} as SpacesAuditLogger, @@ -185,7 +194,7 @@ export function createTestHandler(initApiFn: (deps: PublicRouteDeps & PrivateRou savedObjects: server.savedObjects, spacesService, log, - config: mockConfig, + config: mockConfig as KibanaConfig, }); teardowns.push(() => server.stop()); diff --git a/x-pack/plugins/spaces/server/routes/api/v1/index.ts b/x-pack/plugins/spaces/server/routes/api/v1/index.ts index f764776d071d8..cab8b98c56902 100644 --- a/x-pack/plugins/spaces/server/routes/api/v1/index.ts +++ b/x-pack/plugins/spaces/server/routes/api/v1/index.ts @@ -4,22 +4,21 @@ * you may not use this file except in compliance with the Elastic License. */ -import { HttpServiceSetup } from 'src/core/server'; -import { SavedObjectsService } from 'src/legacy/server/kbn_server'; +import { SavedObjectsService, KibanaConfig } from 'src/legacy/server/kbn_server'; import { XPackMainPlugin } from '../../../../../xpack_main/xpack_main'; -import { SpacesConfig } from '../../../..'; import { routePreCheckLicense } from '../../../lib/route_pre_check_license'; import { initPrivateSpacesApi } from './spaces'; import { SpacesServiceSetup } from '../../../new_platform/spaces_service/spaces_service'; +import { SpacesHttpServiceSetup } from '../../../new_platform/plugin'; type InterfaceExcept = Pick>; interface RouteDeps { xpackMain: XPackMainPlugin; - http: HttpServiceSetup; + http: SpacesHttpServiceSetup; savedObjects: SavedObjectsService; spacesService: SpacesServiceSetup; - config: SpacesConfig; + config: KibanaConfig; } export interface PrivateRouteDeps extends InterfaceExcept { diff --git a/x-pack/plugins/spaces/server/routes/api/v1/spaces.ts b/x-pack/plugins/spaces/server/routes/api/v1/spaces.ts index 6f8f74017a6a2..61b8a9a2b30ae 100644 --- a/x-pack/plugins/spaces/server/routes/api/v1/spaces.ts +++ b/x-pack/plugins/spaces/server/routes/api/v1/spaces.ts @@ -15,7 +15,7 @@ import { PrivateRouteDeps } from '.'; export function initPrivateSpacesApi(deps: PrivateRouteDeps) { const { http, config, spacesService, savedObjects, routePreCheckLicenseFn } = deps; - http.server.route({ + http.route({ method: 'POST', path: '/api/spaces/v1/space/{id}/select', async handler(request: any) { From de357981e431166d7f2a918c59a076feffa52000 Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Wed, 24 Apr 2019 15:44:45 -0400 Subject: [PATCH 10/68] cleanup imports --- .../lib/request_inteceptors/on_request_interceptor.test.ts | 1 - .../spaces/server/lib/spaces_tutorial_context_factory.test.ts | 1 - 2 files changed, 2 deletions(-) diff --git a/x-pack/plugins/spaces/server/lib/request_inteceptors/on_request_interceptor.test.ts b/x-pack/plugins/spaces/server/lib/request_inteceptors/on_request_interceptor.test.ts index 495174ef3682d..972002fc23638 100644 --- a/x-pack/plugins/spaces/server/lib/request_inteceptors/on_request_interceptor.test.ts +++ b/x-pack/plugins/spaces/server/lib/request_inteceptors/on_request_interceptor.test.ts @@ -10,7 +10,6 @@ import * as Rx from 'rxjs'; import { initSpacesOnRequestInterceptor } from './on_request_interceptor'; import { SpacesService } from '../../new_platform/spaces_service'; import { XPackMainPlugin } from '../../../../xpack_main/xpack_main'; -import { ElasticsearchPlugin } from 'src/legacy/core_plugins/elasticsearch'; import { SecurityPlugin } from '../../../../security'; import { SpacesAuditLogger } from '../audit_logger'; import { SpacesServiceSetup } from '../../new_platform/spaces_service/spaces_service'; diff --git a/x-pack/plugins/spaces/server/lib/spaces_tutorial_context_factory.test.ts b/x-pack/plugins/spaces/server/lib/spaces_tutorial_context_factory.test.ts index 118bd686ab507..48814e9dd9e63 100644 --- a/x-pack/plugins/spaces/server/lib/spaces_tutorial_context_factory.test.ts +++ b/x-pack/plugins/spaces/server/lib/spaces_tutorial_context_factory.test.ts @@ -8,7 +8,6 @@ import * as Rx from 'rxjs'; import { DEFAULT_SPACE_ID } from '../../common/constants'; import { createSpacesTutorialContextFactory } from './spaces_tutorial_context_factory'; import { SpacesService } from '../new_platform/spaces_service'; -import { ElasticsearchPlugin } from 'src/legacy/core_plugins/elasticsearch'; import { SavedObjectsService, KibanaConfig } from 'src/legacy/server/kbn_server'; import { SecurityPlugin } from '../../../security'; import { SpacesAuditLogger } from './audit_logger'; From a0bd3787566b0ade33b64f30927611d459a4f214 Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Wed, 24 Apr 2019 16:48:16 -0400 Subject: [PATCH 11/68] don't destructure the es client --- .../server/new_platform/spaces_service/spaces_service.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts b/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts index 207c8769e731b..7cb03e583878c 100644 --- a/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts +++ b/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts @@ -67,12 +67,12 @@ export class SpacesService { return this.contextCache.get(request)!.isInDefaultSpace; }, scopedClient: (request: Request) => { - const { asScoped, callAsInternalUser } = adminClient; - - const internalRepository = savedObjects.getSavedObjectsRepository(callAsInternalUser); + const internalRepository = savedObjects.getSavedObjectsRepository( + adminClient.callAsInternalUser + ); const callCluster = (endpoint: string, ...args: any[]) => - asScoped(request).callAsCurrentUser(endpoint, ...args); + adminClient.asScoped(request).callAsCurrentUser(endpoint, ...args); const callWithRequestRepository = savedObjects.getSavedObjectsRepository(callCluster); From 5d27c184d3959bfae0360ddd8c71e60c4de47fe4 Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Mon, 29 Apr 2019 10:33:19 -0400 Subject: [PATCH 12/68] introduce request facade --- .../spaces_service/spaces_service.ts | 23 +++++++++++-------- .../spaces/server/routes/api/public/delete.ts | 4 ++-- .../spaces/server/routes/api/public/get.ts | 6 ++--- .../spaces/server/routes/api/public/index.ts | 9 +++++++- .../spaces/server/routes/api/public/post.ts | 7 +++--- .../spaces/server/routes/api/public/put.ts | 6 ++--- 6 files changed, 34 insertions(+), 21 deletions(-) diff --git a/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts b/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts index 7cb03e583878c..e37ec83bd4601 100644 --- a/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts +++ b/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts @@ -3,8 +3,8 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { Request } from 'hapi'; -import { Logger, ElasticsearchServiceSetup } from 'src/core/server'; + +import { Logger, ElasticsearchServiceSetup, Headers } from 'src/core/server'; import { SavedObjectsService, KibanaConfig } from 'src/legacy/server/kbn_server'; import { first } from 'rxjs/operators'; import { DEFAULT_SPACE_ID } from '../../../common/constants'; @@ -12,12 +12,17 @@ import { SecurityPlugin } from '../../../../security'; import { SpacesClient } from '../../lib/spaces_client'; import { getSpaceIdFromPath } from '../../lib/spaces_url_parser'; +interface RequestFacade { + headers?: Headers; + getBasePath: () => string; +} + export interface SpacesServiceSetup { - scopedClient(request: Record): SpacesClient; + scopedClient(request: RequestFacade): SpacesClient; - getSpaceId(request: Record): string; + getSpaceId(request: RequestFacade): string; - isInDefaultSpace(request: Record): boolean; + isInDefaultSpace(request: RequestFacade): boolean; } interface CacheEntry { @@ -51,7 +56,7 @@ export class SpacesService { }: SpacesServiceDeps): Promise { const adminClient = await elasticsearch.adminClient$.pipe(first()).toPromise(); return { - getSpaceId: (request: Record) => { + getSpaceId: (request: RequestFacade) => { if (!this.contextCache.has(request)) { this.populateCache(request); } @@ -59,14 +64,14 @@ export class SpacesService { const { spaceId } = this.contextCache.get(request) as CacheEntry; return spaceId; }, - isInDefaultSpace: (request: any) => { + isInDefaultSpace: (request: RequestFacade) => { if (!this.contextCache.has(request)) { this.populateCache(request); } return this.contextCache.get(request)!.isInDefaultSpace; }, - scopedClient: (request: Request) => { + scopedClient: (request: RequestFacade) => { const internalRepository = savedObjects.getSavedObjectsRepository( adminClient.callAsInternalUser ); @@ -94,7 +99,7 @@ export class SpacesService { }; } - private populateCache(request: Record) { + private populateCache(request: RequestFacade) { const spaceId = getSpaceIdFromPath(request.getBasePath(), this.serverBasePath); this.contextCache.set(request, { diff --git a/x-pack/plugins/spaces/server/routes/api/public/delete.ts b/x-pack/plugins/spaces/server/routes/api/public/delete.ts index 5edb0a775362f..42a01e13199cd 100644 --- a/x-pack/plugins/spaces/server/routes/api/public/delete.ts +++ b/x-pack/plugins/spaces/server/routes/api/public/delete.ts @@ -7,7 +7,7 @@ import Boom from 'boom'; import { wrapError } from '../../../lib/errors'; import { SpacesClient } from '../../../lib/spaces_client'; -import { PublicRouteDeps } from '.'; +import { PublicRouteDeps, PublicRouteRequestFacade } from '.'; export function initDeleteSpacesApi(deps: PublicRouteDeps) { const { http, savedObjects, spacesService, routePreCheckLicenseFn } = deps; @@ -15,7 +15,7 @@ export function initDeleteSpacesApi(deps: PublicRouteDeps) { http.route({ method: 'DELETE', path: '/api/spaces/space/{id}', - async handler(request: any, h: any) { + async handler(request: PublicRouteRequestFacade, h: any) { const { SavedObjectsClient } = savedObjects; const spacesClient: SpacesClient = spacesService.scopedClient(request); diff --git a/x-pack/plugins/spaces/server/routes/api/public/get.ts b/x-pack/plugins/spaces/server/routes/api/public/get.ts index 1d0f50c85a86d..566e2826710fe 100644 --- a/x-pack/plugins/spaces/server/routes/api/public/get.ts +++ b/x-pack/plugins/spaces/server/routes/api/public/get.ts @@ -8,7 +8,7 @@ import Boom from 'boom'; import { Space } from '../../../../common/model/space'; import { wrapError } from '../../../lib/errors'; import { SpacesClient } from '../../../lib/spaces_client'; -import { PublicRouteDeps } from '.'; +import { PublicRouteDeps, PublicRouteRequestFacade } from '.'; export function initGetSpacesApi(deps: PublicRouteDeps) { const { http, log, spacesService, savedObjects, routePreCheckLicenseFn } = deps; @@ -16,7 +16,7 @@ export function initGetSpacesApi(deps: PublicRouteDeps) { http.route({ method: 'GET', path: '/api/spaces/space', - async handler(request: any) { + async handler(request: PublicRouteRequestFacade) { log.debug(`Inside GET /api/spaces/space`); const spacesClient: SpacesClient = spacesService.scopedClient(request); @@ -42,7 +42,7 @@ export function initGetSpacesApi(deps: PublicRouteDeps) { http.route({ method: 'GET', path: '/api/spaces/space/{id}', - async handler(request: any) { + async handler(request: PublicRouteRequestFacade) { const spaceId = request.params.id; const { SavedObjectsClient } = savedObjects; diff --git a/x-pack/plugins/spaces/server/routes/api/public/index.ts b/x-pack/plugins/spaces/server/routes/api/public/index.ts index 176b6b41ff012..a9a7287caa456 100644 --- a/x-pack/plugins/spaces/server/routes/api/public/index.ts +++ b/x-pack/plugins/spaces/server/routes/api/public/index.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Logger } from 'src/core/server'; +import { Logger, Headers } from 'src/core/server'; import { SavedObjectsService } from 'src/legacy/server/kbn_server'; import { XPackMainPlugin } from '../../../../../xpack_main/xpack_main'; import { routePreCheckLicense } from '../../../lib/route_pre_check_license'; @@ -29,6 +29,13 @@ export interface PublicRouteDeps extends InterfaceExcept routePreCheckLicenseFn: any; } +export interface PublicRouteRequestFacade { + headers?: Headers; + params: Record; + payload: Record; + getBasePath: () => string; +} + export function initPublicSpacesApi({ xpackMain, ...rest }: RouteDeps) { const routePreCheckLicenseFn = routePreCheckLicense({ xpackMain }); diff --git a/x-pack/plugins/spaces/server/routes/api/public/post.ts b/x-pack/plugins/spaces/server/routes/api/public/post.ts index e04da42bb52a5..3d432455e0010 100644 --- a/x-pack/plugins/spaces/server/routes/api/public/post.ts +++ b/x-pack/plugins/spaces/server/routes/api/public/post.ts @@ -5,10 +5,11 @@ */ import Boom from 'boom'; +import { Space } from '../../../../common/model/space'; import { wrapError } from '../../../lib/errors'; import { spaceSchema } from '../../../lib/space_schema'; import { SpacesClient } from '../../../lib/spaces_client'; -import { PublicRouteDeps } from '.'; +import { PublicRouteDeps, PublicRouteRequestFacade } from '.'; export function initPostSpacesApi(deps: PublicRouteDeps) { const { http, log, spacesService, savedObjects, routePreCheckLicenseFn } = deps; @@ -16,12 +17,12 @@ export function initPostSpacesApi(deps: PublicRouteDeps) { http.route({ method: 'POST', path: '/api/spaces/space', - async handler(request: any) { + async handler(request: PublicRouteRequestFacade) { log.debug(`Inside POST /api/spaces/space`); const { SavedObjectsClient } = savedObjects; const spacesClient: SpacesClient = spacesService.scopedClient(request); - const space = request.payload; + const space = request.payload as Space; try { log.debug(`Attempting to create space`); diff --git a/x-pack/plugins/spaces/server/routes/api/public/put.ts b/x-pack/plugins/spaces/server/routes/api/public/put.ts index 779a032184e0f..f52f62e66d1ee 100644 --- a/x-pack/plugins/spaces/server/routes/api/public/put.ts +++ b/x-pack/plugins/spaces/server/routes/api/public/put.ts @@ -9,7 +9,7 @@ import { Space } from '../../../../common/model/space'; import { wrapError } from '../../../lib/errors'; import { spaceSchema } from '../../../lib/space_schema'; import { SpacesClient } from '../../../lib/spaces_client'; -import { PublicRouteDeps } from '.'; +import { PublicRouteDeps, PublicRouteRequestFacade } from '.'; export function initPutSpacesApi(deps: PublicRouteDeps) { const { http, spacesService, savedObjects, routePreCheckLicenseFn } = deps; @@ -17,11 +17,11 @@ export function initPutSpacesApi(deps: PublicRouteDeps) { http.route({ method: 'PUT', path: '/api/spaces/space/{id}', - async handler(request: any) { + async handler(request: PublicRouteRequestFacade) { const { SavedObjectsClient } = savedObjects; const spacesClient: SpacesClient = spacesService.scopedClient(request); - const space: Space = request.payload; + const space: Space = request.payload as Space; const id = request.params.id; let result: Space; From 661fe9973bc8b0251b1b78c9e02fe3ada355d31f Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Mon, 29 Apr 2019 11:59:45 -0400 Subject: [PATCH 13/68] document reason for getSecurity --- x-pack/plugins/spaces/server/new_platform/plugin.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/x-pack/plugins/spaces/server/new_platform/plugin.ts b/x-pack/plugins/spaces/server/new_platform/plugin.ts index f010e617dfb50..f41067d158165 100644 --- a/x-pack/plugins/spaces/server/new_platform/plugin.ts +++ b/x-pack/plugins/spaces/server/new_platform/plugin.ts @@ -47,6 +47,8 @@ export interface SpacesCoreSetup { } export interface PluginsSetup { + // TODO: Spaces has a circular dependency with Security right now. + // Security is not yet available when init runs, so this is wrapped in a function for the time being. getSecurity: () => SecurityPlugin; xpackMain: XPackMainPlugin; // TODO: this is temporary for `watchLicenseAndStatusToInitialize` From 0ce0e474b1331bf2466ebe31b60508abcd713406 Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Mon, 29 Apr 2019 12:11:49 -0400 Subject: [PATCH 14/68] prefer relative imports from src/core --- .../plugins/spaces/server/lib/create_default_space.test.ts | 4 ++-- x-pack/plugins/spaces/server/lib/create_default_space.ts | 4 ++-- .../plugins/spaces/server/lib/get_spaces_usage_collector.ts | 2 +- .../plugins/spaces/server/lib/request_inteceptors/index.ts | 4 ++-- .../request_inteceptors/on_post_auth_interceptor.test.ts | 4 ++-- .../lib/request_inteceptors/on_request_interceptor.test.ts | 2 +- .../saved_objects_client_wrapper_factory.ts | 2 +- .../spaces_saved_objects_client.test.ts | 4 ++-- .../lib/saved_objects_client/spaces_saved_objects_client.ts | 2 +- .../server/lib/spaces_tutorial_context_factory.test.ts | 4 ++-- x-pack/plugins/spaces/server/new_platform/plugin.ts | 6 +++--- .../server/new_platform/spaces_service/spaces_service.ts | 4 ++-- .../server/routes/api/__fixtures__/create_test_handler.ts | 4 ++-- x-pack/plugins/spaces/server/routes/api/public/index.ts | 4 ++-- x-pack/plugins/spaces/server/routes/api/v1/index.ts | 5 ++++- 15 files changed, 29 insertions(+), 26 deletions(-) diff --git a/x-pack/plugins/spaces/server/lib/create_default_space.test.ts b/x-pack/plugins/spaces/server/lib/create_default_space.test.ts index ab38d52f1b91f..994d9486bccc8 100644 --- a/x-pack/plugins/spaces/server/lib/create_default_space.test.ts +++ b/x-pack/plugins/spaces/server/lib/create_default_space.test.ts @@ -11,8 +11,8 @@ import Boom from 'boom'; // @ts-ignore import { getClient } from '../../../../server/lib/get_client_shield'; import { createDefaultSpace } from './create_default_space'; -import { SavedObjectsService } from 'src/legacy/server/kbn_server'; -import { ElasticsearchServiceSetup } from 'src/core/server'; +import { SavedObjectsService } from '../../../../../src/legacy/server/kbn_server'; +import { ElasticsearchServiceSetup } from '../../../../../src/core/server'; let mockCallWithRequest; beforeEach(() => { diff --git a/x-pack/plugins/spaces/server/lib/create_default_space.ts b/x-pack/plugins/spaces/server/lib/create_default_space.ts index 4a229ede0e443..7807ba37d6438 100644 --- a/x-pack/plugins/spaces/server/lib/create_default_space.ts +++ b/x-pack/plugins/spaces/server/lib/create_default_space.ts @@ -6,9 +6,9 @@ import { i18n } from '@kbn/i18n'; -import { SavedObjectsService } from 'src/legacy/server/kbn_server'; -import { ElasticsearchServiceSetup } from 'src/core/server'; import { first } from 'rxjs/operators'; +import { SavedObjectsService } from '../../../../../src/legacy/server/kbn_server'; +import { ElasticsearchServiceSetup } from '../../../../../src/core/server'; import { DEFAULT_SPACE_ID } from '../../common/constants'; interface Deps { diff --git a/x-pack/plugins/spaces/server/lib/get_spaces_usage_collector.ts b/x-pack/plugins/spaces/server/lib/get_spaces_usage_collector.ts index 83d31c9c223a0..1562cfd5318c6 100644 --- a/x-pack/plugins/spaces/server/lib/get_spaces_usage_collector.ts +++ b/x-pack/plugins/spaces/server/lib/get_spaces_usage_collector.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { SavedObjectsService } from 'src/legacy/server/kbn_server'; +import { SavedObjectsService } from '../../../../../src/legacy/server/kbn_server'; import { XPackMainPlugin } from '../../../xpack_main/xpack_main'; // @ts-ignore import { KIBANA_STATS_TYPE_MONITORING } from '../../../monitoring/common/constants'; diff --git a/x-pack/plugins/spaces/server/lib/request_inteceptors/index.ts b/x-pack/plugins/spaces/server/lib/request_inteceptors/index.ts index 4d47df42351f5..1b1d9dc38e812 100644 --- a/x-pack/plugins/spaces/server/lib/request_inteceptors/index.ts +++ b/x-pack/plugins/spaces/server/lib/request_inteceptors/index.ts @@ -4,8 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Logger } from 'src/core/server'; -import { KibanaConfig, Server } from 'src/legacy/server/kbn_server'; +import { Logger } from '../../../../../../src/core/server'; +import { KibanaConfig, Server } from '../../../../../../src/legacy/server/kbn_server'; import { XPackMainPlugin } from '../../../../xpack_main/xpack_main'; import { initSpacesOnRequestInterceptor } from './on_request_interceptor'; import { initSpacesOnPostAuthRequestInterceptor } from './on_post_auth_interceptor'; diff --git a/x-pack/plugins/spaces/server/lib/request_inteceptors/on_post_auth_interceptor.test.ts b/x-pack/plugins/spaces/server/lib/request_inteceptors/on_post_auth_interceptor.test.ts index ba138f05871f3..c87b2087c0500 100644 --- a/x-pack/plugins/spaces/server/lib/request_inteceptors/on_post_auth_interceptor.test.ts +++ b/x-pack/plugins/spaces/server/lib/request_inteceptors/on_post_auth_interceptor.test.ts @@ -7,7 +7,7 @@ import { Server } from 'hapi'; import sinon from 'sinon'; import * as Rx from 'rxjs'; -import { SavedObject } from 'src/legacy/server/saved_objects'; +import { SavedObject } from '../../../../../../src/legacy/server/saved_objects'; import { Feature } from '../../../../xpack_main/types'; import { convertSavedObjectToSpace } from '../../routes/lib'; import { initSpacesOnPostAuthRequestInterceptor } from './on_post_auth_interceptor'; @@ -16,7 +16,7 @@ import { SpacesService } from '../../new_platform/spaces_service'; import { SecurityPlugin } from '../../../../security'; import { SpacesAuditLogger } from '../audit_logger'; import { SpacesServiceSetup } from '../../new_platform/spaces_service/spaces_service'; -import { ElasticsearchServiceSetup } from 'src/core/server'; +import { ElasticsearchServiceSetup } from '../../../../../../src/core/server'; describe('onPostAuthRequestInterceptor', () => { const sandbox = sinon.sandbox.create(); diff --git a/x-pack/plugins/spaces/server/lib/request_inteceptors/on_request_interceptor.test.ts b/x-pack/plugins/spaces/server/lib/request_inteceptors/on_request_interceptor.test.ts index 972002fc23638..fd72310eddadf 100644 --- a/x-pack/plugins/spaces/server/lib/request_inteceptors/on_request_interceptor.test.ts +++ b/x-pack/plugins/spaces/server/lib/request_inteceptors/on_request_interceptor.test.ts @@ -13,7 +13,7 @@ import { XPackMainPlugin } from '../../../../xpack_main/xpack_main'; import { SecurityPlugin } from '../../../../security'; import { SpacesAuditLogger } from '../audit_logger'; import { SpacesServiceSetup } from '../../new_platform/spaces_service/spaces_service'; -import { ElasticsearchServiceSetup } from 'src/core/server'; +import { ElasticsearchServiceSetup } from '../../../../../../src/core/server'; describe('onRequestInterceptor', () => { const sandbox = sinon.sandbox.create(); diff --git a/x-pack/plugins/spaces/server/lib/saved_objects_client/saved_objects_client_wrapper_factory.ts b/x-pack/plugins/spaces/server/lib/saved_objects_client/saved_objects_client_wrapper_factory.ts index 40808379a9389..870be5b0c9133 100644 --- a/x-pack/plugins/spaces/server/lib/saved_objects_client/saved_objects_client_wrapper_factory.ts +++ b/x-pack/plugins/spaces/server/lib/saved_objects_client/saved_objects_client_wrapper_factory.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { SavedObjectsClientWrapperFactory } from 'src/legacy/server/saved_objects'; +import { SavedObjectsClientWrapperFactory } from '../../../../../../src/legacy/server/saved_objects'; import { SpacesSavedObjectsClient } from './spaces_saved_objects_client'; import { SpacesServiceSetup } from '../../new_platform/spaces_service/spaces_service'; diff --git a/x-pack/plugins/spaces/server/lib/saved_objects_client/spaces_saved_objects_client.test.ts b/x-pack/plugins/spaces/server/lib/saved_objects_client/spaces_saved_objects_client.test.ts index 30907aae5a926..bcff082e3641c 100644 --- a/x-pack/plugins/spaces/server/lib/saved_objects_client/spaces_saved_objects_client.test.ts +++ b/x-pack/plugins/spaces/server/lib/saved_objects_client/spaces_saved_objects_client.test.ts @@ -8,10 +8,10 @@ import { DEFAULT_SPACE_ID } from '../../../common/constants'; import { Space } from '../../../common/model/space'; import { SpacesSavedObjectsClient } from './spaces_saved_objects_client'; import { SpacesService } from '../../new_platform/spaces_service'; -import { SavedObjectsService, KibanaConfig } from 'src/legacy/server/kbn_server'; +import { SavedObjectsService, KibanaConfig } from '../../../../../../src/legacy/server/kbn_server'; import { SecurityPlugin } from '../../../../security'; import { SpacesAuditLogger } from '../audit_logger'; -import { ElasticsearchServiceSetup } from 'src/core/server'; +import { ElasticsearchServiceSetup } from '../../../../../../src/core/server'; const config: any = { 'server.basePath': '/', diff --git a/x-pack/plugins/spaces/server/lib/saved_objects_client/spaces_saved_objects_client.ts b/x-pack/plugins/spaces/server/lib/saved_objects_client/spaces_saved_objects_client.ts index 84412d87e320b..2b9bd2dcfb827 100644 --- a/x-pack/plugins/spaces/server/lib/saved_objects_client/spaces_saved_objects_client.ts +++ b/x-pack/plugins/spaces/server/lib/saved_objects_client/spaces_saved_objects_client.ts @@ -13,7 +13,7 @@ import { SavedObjectAttributes, SavedObjectsClient, UpdateOptions, -} from 'src/legacy/server/saved_objects/service/saved_objects_client'; +} from '../../../../../../src/legacy/server/saved_objects/service/saved_objects_client'; import { DEFAULT_SPACE_ID } from '../../../common/constants'; import { SpacesServiceSetup } from '../../new_platform/spaces_service/spaces_service'; diff --git a/x-pack/plugins/spaces/server/lib/spaces_tutorial_context_factory.test.ts b/x-pack/plugins/spaces/server/lib/spaces_tutorial_context_factory.test.ts index 48814e9dd9e63..1dff381b96be5 100644 --- a/x-pack/plugins/spaces/server/lib/spaces_tutorial_context_factory.test.ts +++ b/x-pack/plugins/spaces/server/lib/spaces_tutorial_context_factory.test.ts @@ -8,10 +8,10 @@ import * as Rx from 'rxjs'; import { DEFAULT_SPACE_ID } from '../../common/constants'; import { createSpacesTutorialContextFactory } from './spaces_tutorial_context_factory'; import { SpacesService } from '../new_platform/spaces_service'; -import { SavedObjectsService, KibanaConfig } from 'src/legacy/server/kbn_server'; +import { SavedObjectsService, KibanaConfig } from '../../../../../src/legacy/server/kbn_server'; import { SecurityPlugin } from '../../../security'; import { SpacesAuditLogger } from './audit_logger'; -import { ElasticsearchServiceSetup } from 'src/core/server'; +import { ElasticsearchServiceSetup } from '../../../../../src/core/server'; const server = { config: () => { diff --git a/x-pack/plugins/spaces/server/new_platform/plugin.ts b/x-pack/plugins/spaces/server/new_platform/plugin.ts index f41067d158165..423bf2ff56be5 100644 --- a/x-pack/plugins/spaces/server/new_platform/plugin.ts +++ b/x-pack/plugins/spaces/server/new_platform/plugin.ts @@ -4,14 +4,14 @@ * you may not use this file except in compliance with the Elastic License. */ +import { ServerRoute } from 'hapi'; +import { KibanaConfig, SavedObjectsService } from '../../../../../src/legacy/server/kbn_server'; import { Logger, HttpServiceSetup, PluginInitializerContext, ElasticsearchServiceSetup, -} from 'src/core/server'; -import { KibanaConfig, SavedObjectsService } from 'src/legacy/server/kbn_server'; -import { ServerRoute } from 'hapi'; +} from '../../../../../src/core/server'; import { XPackMainPlugin } from '../../../xpack_main/xpack_main'; import { createDefaultSpace } from '../lib/create_default_space'; // @ts-ignore diff --git a/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts b/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts index e37ec83bd4601..4913ea1f4f9aa 100644 --- a/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts +++ b/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts @@ -4,9 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Logger, ElasticsearchServiceSetup, Headers } from 'src/core/server'; -import { SavedObjectsService, KibanaConfig } from 'src/legacy/server/kbn_server'; import { first } from 'rxjs/operators'; +import { SavedObjectsService, KibanaConfig } from '../../../../../../src/legacy/server/kbn_server'; +import { Logger, ElasticsearchServiceSetup, Headers } from '../../../../../../src/core/server'; import { DEFAULT_SPACE_ID } from '../../../common/constants'; import { SecurityPlugin } from '../../../../security'; import { SpacesClient } from '../../lib/spaces_client'; diff --git a/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_test_handler.ts b/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_test_handler.ts index 50c69a95c99f4..4c163987e0ddf 100644 --- a/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_test_handler.ts +++ b/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_test_handler.ts @@ -7,8 +7,8 @@ import * as Rx from 'rxjs'; import { Server } from 'hapi'; import { Legacy } from 'kibana'; -import { ElasticsearchServiceSetup } from 'src/core/server'; -import { KibanaConfig } from 'src/legacy/server/kbn_server'; +import { ElasticsearchServiceSetup } from '../../../../../../../src/core/server'; +import { KibanaConfig } from '../../../../../../../src/legacy/server/kbn_server'; import { SecurityPlugin } from '../../../../../security'; import { SpacesClient } from '../../../lib/spaces_client'; import { createSpaces } from './create_spaces'; diff --git a/x-pack/plugins/spaces/server/routes/api/public/index.ts b/x-pack/plugins/spaces/server/routes/api/public/index.ts index a9a7287caa456..3cd9c50d19b05 100644 --- a/x-pack/plugins/spaces/server/routes/api/public/index.ts +++ b/x-pack/plugins/spaces/server/routes/api/public/index.ts @@ -4,8 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Logger, Headers } from 'src/core/server'; -import { SavedObjectsService } from 'src/legacy/server/kbn_server'; +import { Logger, Headers } from '../../../../../../../src/core/server'; +import { SavedObjectsService } from '../../../../../../../src/legacy/server/kbn_server'; import { XPackMainPlugin } from '../../../../../xpack_main/xpack_main'; import { routePreCheckLicense } from '../../../lib/route_pre_check_license'; import { initDeleteSpacesApi } from './delete'; diff --git a/x-pack/plugins/spaces/server/routes/api/v1/index.ts b/x-pack/plugins/spaces/server/routes/api/v1/index.ts index cab8b98c56902..3ab1d9a781646 100644 --- a/x-pack/plugins/spaces/server/routes/api/v1/index.ts +++ b/x-pack/plugins/spaces/server/routes/api/v1/index.ts @@ -4,7 +4,10 @@ * you may not use this file except in compliance with the Elastic License. */ -import { SavedObjectsService, KibanaConfig } from 'src/legacy/server/kbn_server'; +import { + SavedObjectsService, + KibanaConfig, +} from '../../../../../../../src/legacy/server/kbn_server'; import { XPackMainPlugin } from '../../../../../xpack_main/xpack_main'; import { routePreCheckLicense } from '../../../lib/route_pre_check_license'; import { initPrivateSpacesApi } from './spaces'; From d7ca4bafa1ca52e277292faa6720dcbfa8968660 Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Mon, 29 Apr 2019 12:13:52 -0400 Subject: [PATCH 15/68] fix typo in filename: inteceptors --> interceptors --- x-pack/plugins/spaces/index.ts | 2 +- .../lib/{request_inteceptors => request_interceptors}/index.ts | 0 .../on_post_auth_interceptor.test.ts | 0 .../on_post_auth_interceptor.ts | 0 .../on_request_interceptor.test.ts | 0 .../on_request_interceptor.ts | 0 6 files changed, 1 insertion(+), 1 deletion(-) rename x-pack/plugins/spaces/server/lib/{request_inteceptors => request_interceptors}/index.ts (100%) rename x-pack/plugins/spaces/server/lib/{request_inteceptors => request_interceptors}/on_post_auth_interceptor.test.ts (100%) rename x-pack/plugins/spaces/server/lib/{request_inteceptors => request_interceptors}/on_post_auth_interceptor.ts (100%) rename x-pack/plugins/spaces/server/lib/{request_inteceptors => request_interceptors}/on_request_interceptor.test.ts (100%) rename x-pack/plugins/spaces/server/lib/{request_inteceptors => request_interceptors}/on_request_interceptor.ts (100%) diff --git a/x-pack/plugins/spaces/index.ts b/x-pack/plugins/spaces/index.ts index bc5241fdfb053..df9c8d4454002 100644 --- a/x-pack/plugins/spaces/index.ts +++ b/x-pack/plugins/spaces/index.ts @@ -24,7 +24,7 @@ import { SpacesCoreSetup, SpacesHttpServiceSetup, } from './server/new_platform/plugin'; -import { initSpacesRequestInterceptors } from './server/lib/request_inteceptors'; +import { initSpacesRequestInterceptors } from './server/lib/request_interceptors'; export const spaces = (kibana: Record) => new kibana.Plugin({ diff --git a/x-pack/plugins/spaces/server/lib/request_inteceptors/index.ts b/x-pack/plugins/spaces/server/lib/request_interceptors/index.ts similarity index 100% rename from x-pack/plugins/spaces/server/lib/request_inteceptors/index.ts rename to x-pack/plugins/spaces/server/lib/request_interceptors/index.ts diff --git a/x-pack/plugins/spaces/server/lib/request_inteceptors/on_post_auth_interceptor.test.ts b/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts similarity index 100% rename from x-pack/plugins/spaces/server/lib/request_inteceptors/on_post_auth_interceptor.test.ts rename to x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts diff --git a/x-pack/plugins/spaces/server/lib/request_inteceptors/on_post_auth_interceptor.ts b/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.ts similarity index 100% rename from x-pack/plugins/spaces/server/lib/request_inteceptors/on_post_auth_interceptor.ts rename to x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.ts diff --git a/x-pack/plugins/spaces/server/lib/request_inteceptors/on_request_interceptor.test.ts b/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.test.ts similarity index 100% rename from x-pack/plugins/spaces/server/lib/request_inteceptors/on_request_interceptor.test.ts rename to x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.test.ts diff --git a/x-pack/plugins/spaces/server/lib/request_inteceptors/on_request_interceptor.ts b/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.ts similarity index 100% rename from x-pack/plugins/spaces/server/lib/request_inteceptors/on_request_interceptor.ts rename to x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.ts From 600a33a3405d12d679c3fd651b0a929355c56834 Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Mon, 29 Apr 2019 12:16:26 -0400 Subject: [PATCH 16/68] fix imports; remove stray ts-ignore --- x-pack/plugins/spaces/index.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/spaces/index.ts b/x-pack/plugins/spaces/index.ts index df9c8d4454002..4f98775122314 100644 --- a/x-pack/plugins/spaces/index.ts +++ b/x-pack/plugins/spaces/index.ts @@ -5,9 +5,8 @@ */ import { resolve } from 'path'; -// @ts-ignore -import KbnServer, { Server, KibanaConfig } from 'src/legacy/server/kbn_server'; -import { HttpServerInfo } from 'src/core/server/http'; +import KbnServer, { Server } from '../../../src/legacy/server/kbn_server'; +import { HttpServiceSetup } from '../../../src/core/server'; // @ts-ignore import { AuditLogger } from '../../server/lib/audit_logger'; // @ts-ignore @@ -128,7 +127,7 @@ export const spaces = (kibana: Record) => } as unknown) as SpacesInitializerContext; const spacesHttpService: SpacesHttpServiceSetup = { - ...(kbnServer.newPlatform.setup.core.http as HttpServerInfo), + ...(kbnServer.newPlatform.setup.core.http as HttpServiceSetup), route: server.route.bind(server), }; From c5a8656aa1ad7f44fb30b4a59ddf8a344f009170 Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Mon, 29 Apr 2019 13:19:45 -0400 Subject: [PATCH 17/68] improve typings for spaces client --- .../spaces/server/lib/spaces_client.test.ts | 87 +++++++++++-------- .../spaces/server/lib/spaces_client.ts | 36 +++++--- 2 files changed, 73 insertions(+), 50 deletions(-) diff --git a/x-pack/plugins/spaces/server/lib/spaces_client.test.ts b/x-pack/plugins/spaces/server/lib/spaces_client.test.ts index 92213bd5dce16..833b17f59d78a 100644 --- a/x-pack/plugins/spaces/server/lib/spaces_client.test.ts +++ b/x-pack/plugins/spaces/server/lib/spaces_client.test.ts @@ -5,6 +5,8 @@ */ import { SpacesClient } from './spaces_client'; +import { AuthorizationService } from '../../../security/server/lib/authorization/service'; +import { actionsFactory } from '../../../security/server/lib/authorization/actions'; const createMockAuditLogger = () => { return { @@ -17,17 +19,30 @@ const createMockDebugLogger = () => { return jest.fn(); }; +interface MockedAuthorization extends AuthorizationService { + mode: { + useRbacForRequest: jest.Mock; + }; +} const createMockAuthorization = () => { const mockCheckPrivilegesAtSpace = jest.fn(); const mockCheckPrivilegesAtSpaces = jest.fn(); const mockCheckPrivilegesGlobally = jest.fn(); - const mockAuthorization = { - actions: { - login: 'action:login', - space: { - manage: 'space:manage', - }, + // mocking base path + const mockConfig = { get: jest.fn().mockReturnValue('/') }; + const mockAuthorization: MockedAuthorization = { + actions: actionsFactory(mockConfig), + application: '', + checkPrivilegesDynamicallyWithRequest: jest.fn().mockImplementation(() => { + throw new Error( + 'checkPrivilegesDynamicallyWithRequest should not be called from this test suite' + ); + }), + privileges: { + get: jest.fn().mockImplementation(() => { + throw new Error('privileges.get() should not be called from this test suite'); + }), }, checkPrivilegesWithRequest: jest.fn(() => ({ atSpaces: mockCheckPrivilegesAtSpaces, @@ -105,7 +120,7 @@ describe('#getAll', () => { mockCallWithRequestRepository.find.mockReturnValue({ saved_objects: savedObjects, }); - const request = Symbol(); + const request = Symbol() as any; const maxSpaces = 1234; const mockConfig = createMockConfig({ 'xpack.spaces.maxSpaces': 1234, @@ -149,7 +164,7 @@ describe('#getAll', () => { const mockConfig = createMockConfig({ 'xpack.spaces.maxSpaces': 1234, }); - const request = Symbol(); + const request = Symbol() as any; const client = new SpacesClient( mockAuditLogger as any, @@ -202,7 +217,7 @@ describe('#getAll', () => { saved_objects: savedObjects, }), }; - const request = Symbol(); + const request = Symbol() as any; const client = new SpacesClient( mockAuditLogger as any, @@ -257,7 +272,7 @@ describe('#getAll', () => { const mockConfig = createMockConfig({ 'xpack.spaces.maxSpaces': 1234, }); - const request = Symbol(); + const request = Symbol() as any; const client = new SpacesClient( mockAuditLogger as any, @@ -297,7 +312,7 @@ describe('#canEnumerateSpaces', () => { const mockAuditLogger = createMockAuditLogger(); const mockDebugLogger = createMockDebugLogger(); const authorization = null; - const request = Symbol(); + const request = Symbol() as any; const client = new SpacesClient( mockAuditLogger as any, @@ -322,7 +337,7 @@ describe('#canEnumerateSpaces', () => { const mockDebugLogger = createMockDebugLogger(); const { mockAuthorization } = createMockAuthorization(); mockAuthorization.mode.useRbacForRequest.mockReturnValue(false); - const request = Symbol(); + const request = Symbol() as any; const client = new SpacesClient( mockAuditLogger as any, @@ -352,7 +367,7 @@ describe('#canEnumerateSpaces', () => { username, hasAllRequested: false, }); - const request = Symbol(); + const request = Symbol() as any; const client = new SpacesClient( mockAuditLogger as any, @@ -386,7 +401,7 @@ describe('#canEnumerateSpaces', () => { username, hasAllRequested: true, }); - const request = Symbol(); + const request = Symbol() as any; const client = new SpacesClient( mockAuditLogger as any, @@ -437,7 +452,7 @@ describe('#get', () => { const mockCallWithRequestRepository = { get: jest.fn().mockReturnValue(savedObject), }; - const request = Symbol(); + const request = Symbol() as any; const client = new SpacesClient( mockAuditLogger as any, @@ -467,7 +482,7 @@ describe('#get', () => { const mockCallWithRequestRepository = { get: jest.fn().mockReturnValue(savedObject), }; - const request = Symbol(); + const request = Symbol() as any; const client = new SpacesClient( mockAuditLogger as any, @@ -500,7 +515,7 @@ describe('#get', () => { username, hasAllRequested: false, }); - const request = Symbol(); + const request = Symbol() as any; const client = new SpacesClient( mockAuditLogger as any, @@ -533,7 +548,7 @@ describe('#get', () => { username, hasAllRequested: true, }); - const request = Symbol(); + const request = Symbol() as any; const mockInternalRepository = { get: jest.fn().mockReturnValue(savedObject), }; @@ -615,7 +630,7 @@ describe('#create', () => { const mockConfig = createMockConfig({ 'xpack.spaces.maxSpaces': maxSpaces, }); - const request = Symbol(); + const request = Symbol() as any; const client = new SpacesClient( mockAuditLogger as any, @@ -656,7 +671,7 @@ describe('#create', () => { const mockConfig = createMockConfig({ 'xpack.spaces.maxSpaces': maxSpaces, }); - const request = Symbol(); + const request = Symbol() as any; const client = new SpacesClient( mockAuditLogger as any, @@ -697,7 +712,7 @@ describe('#create', () => { const mockConfig = createMockConfig({ 'xpack.spaces.maxSpaces': maxSpaces, }); - const request = Symbol(); + const request = Symbol() as any; const client = new SpacesClient( mockAuditLogger as any, @@ -740,7 +755,7 @@ describe('#create', () => { const mockConfig = createMockConfig({ 'xpack.spaces.maxSpaces': maxSpaces, }); - const request = Symbol(); + const request = Symbol() as any; const client = new SpacesClient( mockAuditLogger as any, @@ -777,7 +792,7 @@ describe('#create', () => { username, hasAllRequested: false, }); - const request = Symbol(); + const request = Symbol() as any; const client = new SpacesClient( mockAuditLogger as any, @@ -820,7 +835,7 @@ describe('#create', () => { const mockConfig = createMockConfig({ 'xpack.spaces.maxSpaces': maxSpaces, }); - const request = Symbol(); + const request = Symbol() as any; const client = new SpacesClient( mockAuditLogger as any, @@ -872,7 +887,7 @@ describe('#create', () => { const mockConfig = createMockConfig({ 'xpack.spaces.maxSpaces': maxSpaces, }); - const request = Symbol(); + const request = Symbol() as any; const client = new SpacesClient( mockAuditLogger as any, @@ -949,7 +964,7 @@ describe('#update', () => { update: jest.fn(), get: jest.fn().mockReturnValue(savedObject), }; - const request = Symbol(); + const request = Symbol() as any; const client = new SpacesClient( mockAuditLogger as any, @@ -980,7 +995,7 @@ describe('#update', () => { update: jest.fn(), get: jest.fn().mockReturnValue(savedObject), }; - const request = Symbol(); + const request = Symbol() as any; const client = new SpacesClient( mockAuditLogger as any, @@ -1014,7 +1029,7 @@ describe('#update', () => { username, }); mockAuthorization.mode.useRbacForRequest.mockReturnValue(true); - const request = Symbol(); + const request = Symbol() as any; const client = new SpacesClient( mockAuditLogger as any, @@ -1051,7 +1066,7 @@ describe('#update', () => { update: jest.fn(), get: jest.fn().mockReturnValue(savedObject), }; - const request = Symbol(); + const request = Symbol() as any; const client = new SpacesClient( mockAuditLogger as any, @@ -1109,7 +1124,7 @@ describe('#delete', () => { const mockCallWithRequestRepository = { get: jest.fn().mockReturnValue(reservedSavedObject), }; - const request = Symbol(); + const request = Symbol() as any; const client = new SpacesClient( mockAuditLogger as any, @@ -1138,7 +1153,7 @@ describe('#delete', () => { deleteByNamespace: jest.fn(), }; - const request = Symbol(); + const request = Symbol() as any; const client = new SpacesClient( mockAuditLogger as any, @@ -1169,7 +1184,7 @@ describe('#delete', () => { const mockCallWithRequestRepository = { get: jest.fn().mockReturnValue(reservedSavedObject), }; - const request = Symbol(); + const request = Symbol() as any; const client = new SpacesClient( mockAuditLogger as any, @@ -1200,7 +1215,7 @@ describe('#delete', () => { deleteByNamespace: jest.fn(), }; - const request = Symbol(); + const request = Symbol() as any; const client = new SpacesClient( mockAuditLogger as any, @@ -1234,7 +1249,7 @@ describe('#delete', () => { username, hasAllRequested: false, }); - const request = Symbol(); + const request = Symbol() as any; const client = new SpacesClient( mockAuditLogger as any, mockDebugLogger, @@ -1269,7 +1284,7 @@ describe('#delete', () => { const mockInternalRepository = { get: jest.fn().mockReturnValue(reservedSavedObject), }; - const request = Symbol(); + const request = Symbol() as any; const client = new SpacesClient( mockAuditLogger as any, mockDebugLogger, @@ -1308,7 +1323,7 @@ describe('#delete', () => { deleteByNamespace: jest.fn(), }; - const request = Symbol(); + const request = Symbol() as any; const client = new SpacesClient( mockAuditLogger as any, mockDebugLogger, diff --git a/x-pack/plugins/spaces/server/lib/spaces_client.ts b/x-pack/plugins/spaces/server/lib/spaces_client.ts index 5d14cb99447c1..609c2d4f462db 100644 --- a/x-pack/plugins/spaces/server/lib/spaces_client.ts +++ b/x-pack/plugins/spaces/server/lib/spaces_client.ts @@ -5,26 +5,31 @@ */ import Boom from 'boom'; import { omit } from 'lodash'; +import { Headers } from '../../../../../src/core/server'; +import { AuthorizationService } from '../../../security/server/lib/authorization/service'; import { isReservedSpace } from '../../common/is_reserved_space'; import { Space } from '../../common/model/space'; import { SpacesAuditLogger } from './audit_logger'; +interface SpacesClientRequestFacade { + headers: Headers; +} export class SpacesClient { constructor( private readonly auditLogger: SpacesAuditLogger, private readonly debugLogger: (message: string) => void, - private readonly authorization: any, + private readonly authorization: AuthorizationService | null, private readonly callWithRequestSavedObjectRepository: any, private readonly config: any, private readonly internalSavedObjectRepository: any, - private readonly request: any + private readonly request: SpacesClientRequestFacade ) {} public async canEnumerateSpaces(): Promise { if (this.useRbac()) { - const checkPrivileges = this.authorization.checkPrivilegesWithRequest(this.request); + const checkPrivileges = this.authorization!.checkPrivilegesWithRequest(this.request); const { hasAllRequested } = await checkPrivileges.globally( - this.authorization.actions.space.manage + this.authorization!.actions.space.manage ); this.debugLogger(`SpacesClient.canEnumerateSpaces, using RBAC. Result: ${hasAllRequested}`); return hasAllRequested; @@ -49,14 +54,14 @@ export class SpacesClient { const spaces = saved_objects.map(this.transformSavedObjectToSpace); const spaceIds = spaces.map((space: Space) => space.id); - const checkPrivileges = this.authorization.checkPrivilegesWithRequest(this.request); + const checkPrivileges = this.authorization!.checkPrivilegesWithRequest(this.request); const { username, spacePrivileges } = await checkPrivileges.atSpaces( spaceIds, - this.authorization.actions.login + this.authorization!.actions.login ); const authorized = Object.keys(spacePrivileges).filter(spaceId => { - return spacePrivileges[spaceId][this.authorization.actions.login]; + return spacePrivileges[spaceId][this.authorization!.actions.login]; }); this.debugLogger( @@ -103,7 +108,7 @@ export class SpacesClient { if (this.useRbac()) { await this.ensureAuthorizedAtSpace( id, - this.authorization.actions.login, + this.authorization!.actions.login, 'get', `Unauthorized to get ${id} space` ); @@ -121,7 +126,7 @@ export class SpacesClient { this.debugLogger(`SpacesClient.create(), using RBAC. Checking if authorized globally`); await this.ensureAuthorizedGlobally( - this.authorization.actions.space.manage, + this.authorization!.actions.space.manage, 'create', 'Unauthorized to create spaces' ); @@ -157,7 +162,7 @@ export class SpacesClient { public async update(id: string, space: Space) { if (this.useRbac()) { await this.ensureAuthorizedGlobally( - this.authorization.actions.space.manage, + this.authorization!.actions.space.manage, 'update', 'Unauthorized to update spaces' ); @@ -175,7 +180,7 @@ export class SpacesClient { public async delete(id: string) { if (this.useRbac()) { await this.ensureAuthorizedGlobally( - this.authorization.actions.space.manage, + this.authorization!.actions.space.manage, 'delete', 'Unauthorized to delete spaces' ); @@ -196,11 +201,14 @@ export class SpacesClient { } private useRbac(): boolean { - return this.authorization && this.authorization.mode.useRbacForRequest(this.request); + // TODO: remove "as any" once Security is updated to NP conventions + return ( + this.authorization != null && this.authorization.mode.useRbacForRequest(this.request as any) + ); } private async ensureAuthorizedGlobally(action: string, method: string, forbiddenMessage: string) { - const checkPrivileges = this.authorization.checkPrivilegesWithRequest(this.request); + const checkPrivileges = this.authorization!.checkPrivilegesWithRequest(this.request); const { username, hasAllRequested } = await checkPrivileges.globally(action); if (hasAllRequested) { @@ -218,7 +226,7 @@ export class SpacesClient { method: string, forbiddenMessage: string ) { - const checkPrivileges = this.authorization.checkPrivilegesWithRequest(this.request); + const checkPrivileges = this.authorization!.checkPrivilegesWithRequest(this.request); const { username, hasAllRequested } = await checkPrivileges.atSpace(spaceId, action); if (hasAllRequested) { From c6afefc5bcf833db111f548e4679511848d19615 Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Mon, 29 Apr 2019 13:27:15 -0400 Subject: [PATCH 18/68] rename InterfaceExcept --> Omit --- x-pack/plugins/spaces/server/routes/api/public/index.ts | 4 ++-- x-pack/plugins/spaces/server/routes/api/v1/index.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/spaces/server/routes/api/public/index.ts b/x-pack/plugins/spaces/server/routes/api/public/index.ts index 3cd9c50d19b05..ba1e31eace0c0 100644 --- a/x-pack/plugins/spaces/server/routes/api/public/index.ts +++ b/x-pack/plugins/spaces/server/routes/api/public/index.ts @@ -15,7 +15,7 @@ import { initPutSpacesApi } from './put'; import { SpacesServiceSetup } from '../../../new_platform/spaces_service/spaces_service'; import { SpacesHttpServiceSetup } from '../../../new_platform/plugin'; -type InterfaceExcept = Pick>; +type Omit = Pick>; interface RouteDeps { xpackMain: XPackMainPlugin; @@ -25,7 +25,7 @@ interface RouteDeps { log: Logger; } -export interface PublicRouteDeps extends InterfaceExcept { +export interface PublicRouteDeps extends Omit { routePreCheckLicenseFn: any; } diff --git a/x-pack/plugins/spaces/server/routes/api/v1/index.ts b/x-pack/plugins/spaces/server/routes/api/v1/index.ts index 3ab1d9a781646..1484460118aca 100644 --- a/x-pack/plugins/spaces/server/routes/api/v1/index.ts +++ b/x-pack/plugins/spaces/server/routes/api/v1/index.ts @@ -14,7 +14,7 @@ import { initPrivateSpacesApi } from './spaces'; import { SpacesServiceSetup } from '../../../new_platform/spaces_service/spaces_service'; import { SpacesHttpServiceSetup } from '../../../new_platform/plugin'; -type InterfaceExcept = Pick>; +type Omit = Pick>; interface RouteDeps { xpackMain: XPackMainPlugin; @@ -24,7 +24,7 @@ interface RouteDeps { config: KibanaConfig; } -export interface PrivateRouteDeps extends InterfaceExcept { +export interface PrivateRouteDeps extends Omit { routePreCheckLicenseFn: any; } From f67ccc6bb4090d721ec88f74d840fd64472fec54 Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Mon, 29 Apr 2019 14:32:11 -0400 Subject: [PATCH 19/68] don't use legacy config in NP --- .../on_post_auth_interceptor.test.ts | 2 + .../on_request_interceptor.test.ts | 2 + .../spaces_saved_objects_client.test.ts | 6 +- .../spaces/server/lib/spaces_client.test.ts | 94 +++++++++++-------- .../spaces/server/lib/spaces_client.ts | 11 ++- .../spaces_tutorial_context_factory.test.ts | 8 +- .../spaces/server/new_platform/config.ts | 20 ++++ .../spaces/server/new_platform/plugin.ts | 20 ++-- .../spaces_service/spaces_service.ts | 31 ++++-- .../api/__fixtures__/create_test_handler.ts | 7 +- 10 files changed, 135 insertions(+), 66 deletions(-) create mode 100644 x-pack/plugins/spaces/server/new_platform/config.ts diff --git a/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts b/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts index c87b2087c0500..f146ba5180f3e 100644 --- a/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts +++ b/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts @@ -17,6 +17,7 @@ import { SecurityPlugin } from '../../../../security'; import { SpacesAuditLogger } from '../audit_logger'; import { SpacesServiceSetup } from '../../new_platform/spaces_service/spaces_service'; import { ElasticsearchServiceSetup } from '../../../../../../src/core/server'; +import { SpacesConfig } from '../../new_platform/config'; describe('onPostAuthRequestInterceptor', () => { const sandbox = sinon.sandbox.create(); @@ -150,6 +151,7 @@ describe('onPostAuthRequestInterceptor', () => { savedObjects: server.savedObjects, getSecurity: () => ({} as SecurityPlugin), spacesAuditLogger: {} as SpacesAuditLogger, + config$: Rx.of(new SpacesConfig({ maxSpaces: 1000 })), }); spacesService.scopedClient = jest.fn().mockReturnValue({ diff --git a/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.test.ts b/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.test.ts index fd72310eddadf..58a91a95d6958 100644 --- a/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.test.ts +++ b/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.test.ts @@ -14,6 +14,7 @@ import { SecurityPlugin } from '../../../../security'; import { SpacesAuditLogger } from '../audit_logger'; import { SpacesServiceSetup } from '../../new_platform/spaces_service/spaces_service'; import { ElasticsearchServiceSetup } from '../../../../../../src/core/server'; +import { SpacesConfig } from '../../new_platform/config'; describe('onRequestInterceptor', () => { const sandbox = sinon.sandbox.create(); @@ -109,6 +110,7 @@ describe('onRequestInterceptor', () => { savedObjects: server.savedObjects, getSecurity: () => ({} as SecurityPlugin), spacesAuditLogger: {} as SpacesAuditLogger, + config$: Rx.of(new SpacesConfig({ maxSpaces: 1000 })), }); initSpacesOnRequestInterceptor({ diff --git a/x-pack/plugins/spaces/server/lib/saved_objects_client/spaces_saved_objects_client.test.ts b/x-pack/plugins/spaces/server/lib/saved_objects_client/spaces_saved_objects_client.test.ts index bcff082e3641c..babb83f16d8b4 100644 --- a/x-pack/plugins/spaces/server/lib/saved_objects_client/spaces_saved_objects_client.test.ts +++ b/x-pack/plugins/spaces/server/lib/saved_objects_client/spaces_saved_objects_client.test.ts @@ -8,10 +8,11 @@ import { DEFAULT_SPACE_ID } from '../../../common/constants'; import { Space } from '../../../common/model/space'; import { SpacesSavedObjectsClient } from './spaces_saved_objects_client'; import { SpacesService } from '../../new_platform/spaces_service'; -import { SavedObjectsService, KibanaConfig } from '../../../../../../src/legacy/server/kbn_server'; +import { SavedObjectsService } from '../../../../../../src/legacy/server/kbn_server'; import { SecurityPlugin } from '../../../../security'; import { SpacesAuditLogger } from '../audit_logger'; import { ElasticsearchServiceSetup } from '../../../../../../src/core/server'; +import { SpacesConfig } from '../../new_platform/config'; const config: any = { 'server.basePath': '/', @@ -37,7 +38,7 @@ const log = { fatal: jest.fn(), }; -const service = new SpacesService(log, server.config() as KibanaConfig); +const service = new SpacesService(log, server.config().get('server.basePath')); const createMockRequest = (space: Partial) => ({ getBasePath: () => (space.id !== DEFAULT_SPACE_ID ? `/s/${space.id}` : ''), @@ -71,6 +72,7 @@ const createSpacesService = async () => { savedObjects: {} as SavedObjectsService, getSecurity: () => ({} as SecurityPlugin), spacesAuditLogger: {} as SpacesAuditLogger, + config$: Rx.of(new SpacesConfig({ maxSpaces: 1000 })), }); }; diff --git a/x-pack/plugins/spaces/server/lib/spaces_client.test.ts b/x-pack/plugins/spaces/server/lib/spaces_client.test.ts index 833b17f59d78a..fa8abf7538ccb 100644 --- a/x-pack/plugins/spaces/server/lib/spaces_client.test.ts +++ b/x-pack/plugins/spaces/server/lib/spaces_client.test.ts @@ -7,6 +7,8 @@ import { SpacesClient } from './spaces_client'; import { AuthorizationService } from '../../../security/server/lib/authorization/service'; import { actionsFactory } from '../../../security/server/lib/authorization/actions'; +import { SpacesConfig } from '../new_platform/config'; +import { TypeOf } from '@kbn/config-schema'; const createMockAuditLogger = () => { return { @@ -62,16 +64,8 @@ const createMockAuthorization = () => { }; }; -const createMockConfig = (settings: { [key: string]: any } = {}) => { - const mockConfig = { - get: jest.fn(), - }; - - mockConfig.get.mockImplementation(key => { - return settings[key]; - }); - - return mockConfig; +const createMockConfig = (config: TypeOf = { maxSpaces: 1000 }) => { + return new SpacesConfig(config); }; describe('#getAll', () => { @@ -123,7 +117,7 @@ describe('#getAll', () => { const request = Symbol() as any; const maxSpaces = 1234; const mockConfig = createMockConfig({ - 'xpack.spaces.maxSpaces': 1234, + maxSpaces: 1234, }); const client = new SpacesClient( @@ -162,7 +156,7 @@ describe('#getAll', () => { }; const maxSpaces = 1234; const mockConfig = createMockConfig({ - 'xpack.spaces.maxSpaces': 1234, + maxSpaces: 1234, }); const request = Symbol() as any; @@ -210,7 +204,7 @@ describe('#getAll', () => { }); const maxSpaces = 1234; const mockConfig = createMockConfig({ - 'xpack.spaces.maxSpaces': 1234, + maxSpaces: 1234, }); const mockInternalRepository = { find: jest.fn().mockReturnValue({ @@ -270,7 +264,7 @@ describe('#getAll', () => { }; const maxSpaces = 1234; const mockConfig = createMockConfig({ - 'xpack.spaces.maxSpaces': 1234, + maxSpaces: 1234, }); const request = Symbol() as any; @@ -311,6 +305,7 @@ describe('#canEnumerateSpaces', () => { test(`returns true`, async () => { const mockAuditLogger = createMockAuditLogger(); const mockDebugLogger = createMockDebugLogger(); + const mockConfig = createMockConfig(); const authorization = null; const request = Symbol() as any; @@ -319,7 +314,7 @@ describe('#canEnumerateSpaces', () => { mockDebugLogger, authorization, null, - null, + mockConfig, null, request ); @@ -335,6 +330,7 @@ describe('#canEnumerateSpaces', () => { test(`returns true`, async () => { const mockAuditLogger = createMockAuditLogger(); const mockDebugLogger = createMockDebugLogger(); + const mockConfig = createMockConfig(); const { mockAuthorization } = createMockAuthorization(); mockAuthorization.mode.useRbacForRequest.mockReturnValue(false); const request = Symbol() as any; @@ -344,7 +340,7 @@ describe('#canEnumerateSpaces', () => { mockDebugLogger, mockAuthorization, null, - null, + mockConfig, null, request ); @@ -361,6 +357,7 @@ describe('#canEnumerateSpaces', () => { const username = Symbol(); const mockAuditLogger = createMockAuditLogger(); const mockDebugLogger = createMockDebugLogger(); + const mockConfig = createMockConfig(); const { mockAuthorization, mockCheckPrivilegesGlobally } = createMockAuthorization(); mockAuthorization.mode.useRbacForRequest.mockReturnValue(true); mockCheckPrivilegesGlobally.mockReturnValue({ @@ -374,7 +371,7 @@ describe('#canEnumerateSpaces', () => { mockDebugLogger, mockAuthorization, null, - null, + mockConfig, null, request ); @@ -395,6 +392,7 @@ describe('#canEnumerateSpaces', () => { const username = Symbol(); const mockAuditLogger = createMockAuditLogger(); const mockDebugLogger = createMockDebugLogger(); + const mockConfig = createMockConfig(); const { mockAuthorization, mockCheckPrivilegesGlobally } = createMockAuthorization(); mockAuthorization.mode.useRbacForRequest.mockReturnValue(true); mockCheckPrivilegesGlobally.mockReturnValue({ @@ -408,7 +406,7 @@ describe('#canEnumerateSpaces', () => { mockDebugLogger, mockAuthorization, null, - null, + mockConfig, null, request ); @@ -448,6 +446,7 @@ describe('#get', () => { test(`gets space using callWithRequestRepository`, async () => { const mockAuditLogger = createMockAuditLogger(); const mockDebugLogger = createMockDebugLogger(); + const mockConfig = createMockConfig(); const authorization = null; const mockCallWithRequestRepository = { get: jest.fn().mockReturnValue(savedObject), @@ -459,7 +458,7 @@ describe('#get', () => { mockDebugLogger, authorization, mockCallWithRequestRepository, - null, + mockConfig, null, request ); @@ -477,6 +476,7 @@ describe('#get', () => { test(`gets space using callWithRequestRepository`, async () => { const mockAuditLogger = createMockAuditLogger(); const mockDebugLogger = createMockDebugLogger(); + const mockConfig = createMockConfig(); const { mockAuthorization } = createMockAuthorization(); mockAuthorization.mode.useRbacForRequest.mockReturnValue(false); const mockCallWithRequestRepository = { @@ -489,7 +489,7 @@ describe('#get', () => { mockDebugLogger, mockAuthorization, mockCallWithRequestRepository, - null, + mockConfig, null, request ); @@ -509,6 +509,7 @@ describe('#get', () => { const username = Symbol(); const mockAuditLogger = createMockAuditLogger(); const mockDebugLogger = createMockDebugLogger(); + const mockConfig = createMockConfig(); const { mockAuthorization, mockCheckPrivilegesAtSpace } = createMockAuthorization(); mockAuthorization.mode.useRbacForRequest.mockReturnValue(true); mockCheckPrivilegesAtSpace.mockReturnValue({ @@ -522,7 +523,7 @@ describe('#get', () => { mockDebugLogger, mockAuthorization, null, - null, + mockConfig, null, request ); @@ -542,6 +543,7 @@ describe('#get', () => { const username = Symbol(); const mockAuditLogger = createMockAuditLogger(); const mockDebugLogger = createMockDebugLogger(); + const mockConfig = createMockConfig(); const { mockAuthorization, mockCheckPrivilegesAtSpace } = createMockAuthorization(); mockAuthorization.mode.useRbacForRequest.mockReturnValue(true); mockCheckPrivilegesAtSpace.mockReturnValue({ @@ -558,7 +560,7 @@ describe('#get', () => { mockDebugLogger, mockAuthorization, null, - null, + mockConfig, mockInternalRepository, request ); @@ -628,7 +630,7 @@ describe('#create', () => { }), }; const mockConfig = createMockConfig({ - 'xpack.spaces.maxSpaces': maxSpaces, + maxSpaces, }); const request = Symbol() as any; @@ -669,7 +671,7 @@ describe('#create', () => { }), }; const mockConfig = createMockConfig({ - 'xpack.spaces.maxSpaces': maxSpaces, + maxSpaces, }); const request = Symbol() as any; @@ -710,7 +712,7 @@ describe('#create', () => { }), }; const mockConfig = createMockConfig({ - 'xpack.spaces.maxSpaces': maxSpaces, + maxSpaces, }); const request = Symbol() as any; @@ -753,7 +755,7 @@ describe('#create', () => { }), }; const mockConfig = createMockConfig({ - 'xpack.spaces.maxSpaces': maxSpaces, + maxSpaces, }); const request = Symbol() as any; @@ -786,6 +788,7 @@ describe('#create', () => { const username = Symbol(); const mockAuditLogger = createMockAuditLogger(); const mockDebugLogger = createMockDebugLogger(); + const mockConfig = createMockConfig(); const { mockAuthorization, mockCheckPrivilegesGlobally } = createMockAuthorization(); mockAuthorization.mode.useRbacForRequest.mockReturnValue(true); mockCheckPrivilegesGlobally.mockReturnValue({ @@ -799,7 +802,7 @@ describe('#create', () => { mockDebugLogger, mockAuthorization, null, - null, + mockConfig, null, request ); @@ -833,7 +836,7 @@ describe('#create', () => { }), }; const mockConfig = createMockConfig({ - 'xpack.spaces.maxSpaces': maxSpaces, + maxSpaces, }); const request = Symbol() as any; @@ -885,7 +888,7 @@ describe('#create', () => { }), }; const mockConfig = createMockConfig({ - 'xpack.spaces.maxSpaces': maxSpaces, + maxSpaces, }); const request = Symbol() as any; @@ -959,6 +962,7 @@ describe('#update', () => { test(`updates space using callWithRequestRepository`, async () => { const mockAuditLogger = createMockAuditLogger(); const mockDebugLogger = createMockDebugLogger(); + const mockConfig = createMockConfig(); const authorization = null; const mockCallWithRequestRepository = { update: jest.fn(), @@ -971,7 +975,7 @@ describe('#update', () => { mockDebugLogger, authorization, mockCallWithRequestRepository, - null, + mockConfig, null, request ); @@ -989,6 +993,7 @@ describe('#update', () => { test(`updates space using callWithRequestRepository`, async () => { const mockAuditLogger = createMockAuditLogger(); const mockDebugLogger = createMockDebugLogger(); + const mockConfig = createMockConfig(); const { mockAuthorization } = createMockAuthorization(); mockAuthorization.mode.useRbacForRequest.mockReturnValue(false); const mockCallWithRequestRepository = { @@ -1002,7 +1007,7 @@ describe('#update', () => { mockDebugLogger, mockAuthorization, mockCallWithRequestRepository, - null, + mockConfig, null, request ); @@ -1023,6 +1028,7 @@ describe('#update', () => { const username = Symbol(); const mockAuditLogger = createMockAuditLogger(); const mockDebugLogger = createMockDebugLogger(); + const mockConfig = createMockConfig(); const { mockAuthorization, mockCheckPrivilegesGlobally } = createMockAuthorization(); mockCheckPrivilegesGlobally.mockReturnValue({ hasAllRequested: false, @@ -1036,7 +1042,7 @@ describe('#update', () => { mockDebugLogger, mockAuthorization, null, - null, + mockConfig, null, request ); @@ -1056,6 +1062,7 @@ describe('#update', () => { const username = Symbol(); const mockAuditLogger = createMockAuditLogger(); const mockDebugLogger = createMockDebugLogger(); + const mockConfig = createMockConfig(); const { mockAuthorization, mockCheckPrivilegesGlobally } = createMockAuthorization(); mockCheckPrivilegesGlobally.mockReturnValue({ hasAllRequested: true, @@ -1073,7 +1080,7 @@ describe('#update', () => { mockDebugLogger, mockAuthorization, null, - null, + mockConfig, mockInternalRepository, request ); @@ -1120,6 +1127,7 @@ describe('#delete', () => { test(`throws bad request when the space is reserved`, async () => { const mockAuditLogger = createMockAuditLogger(); const mockDebugLogger = createMockDebugLogger(); + const mockConfig = createMockConfig(); const authorization = null; const mockCallWithRequestRepository = { get: jest.fn().mockReturnValue(reservedSavedObject), @@ -1131,7 +1139,7 @@ describe('#delete', () => { mockDebugLogger, authorization, mockCallWithRequestRepository, - null, + mockConfig, null, request ); @@ -1146,6 +1154,7 @@ describe('#delete', () => { test(`deletes space using callWithRequestRepository when space isn't reserved`, async () => { const mockAuditLogger = createMockAuditLogger(); const mockDebugLogger = createMockDebugLogger(); + const mockConfig = createMockConfig(); const authorization = null; const mockCallWithRequestRepository = { get: jest.fn().mockReturnValue(notReservedSavedObject), @@ -1160,7 +1169,7 @@ describe('#delete', () => { mockDebugLogger, authorization, mockCallWithRequestRepository, - null, + mockConfig, null, request ); @@ -1179,6 +1188,7 @@ describe('#delete', () => { test(`throws bad request when the space is reserved`, async () => { const mockAuditLogger = createMockAuditLogger(); const mockDebugLogger = createMockDebugLogger(); + const mockConfig = createMockConfig(); const { mockAuthorization } = createMockAuthorization(); mockAuthorization.mode.useRbacForRequest.mockReturnValue(false); const mockCallWithRequestRepository = { @@ -1191,7 +1201,7 @@ describe('#delete', () => { mockDebugLogger, mockAuthorization, mockCallWithRequestRepository, - null, + mockConfig, null, request ); @@ -1207,6 +1217,7 @@ describe('#delete', () => { test(`deletes space using callWithRequestRepository when space isn't reserved`, async () => { const mockAuditLogger = createMockAuditLogger(); const mockDebugLogger = createMockDebugLogger(); + const mockConfig = createMockConfig(); const { mockAuthorization } = createMockAuthorization(); mockAuthorization.mode.useRbacForRequest.mockReturnValue(false); const mockCallWithRequestRepository = { @@ -1222,7 +1233,7 @@ describe('#delete', () => { mockDebugLogger, mockAuthorization, mockCallWithRequestRepository, - null, + mockConfig, null, request ); @@ -1243,6 +1254,7 @@ describe('#delete', () => { const username = Symbol(); const mockAuditLogger = createMockAuditLogger(); const mockDebugLogger = createMockDebugLogger(); + const mockConfig = createMockConfig(); const { mockAuthorization, mockCheckPrivilegesGlobally } = createMockAuthorization(); mockAuthorization.mode.useRbacForRequest.mockReturnValue(true); mockCheckPrivilegesGlobally.mockReturnValue({ @@ -1255,7 +1267,7 @@ describe('#delete', () => { mockDebugLogger, mockAuthorization, null, - null, + mockConfig, null, request ); @@ -1275,6 +1287,7 @@ describe('#delete', () => { const username = Symbol(); const mockAuditLogger = createMockAuditLogger(); const mockDebugLogger = createMockDebugLogger(); + const mockConfig = createMockConfig(); const { mockAuthorization, mockCheckPrivilegesGlobally } = createMockAuthorization(); mockAuthorization.mode.useRbacForRequest.mockReturnValue(true); mockCheckPrivilegesGlobally.mockReturnValue({ @@ -1290,7 +1303,7 @@ describe('#delete', () => { mockDebugLogger, mockAuthorization, null, - null, + mockConfig, mockInternalRepository, request ); @@ -1311,6 +1324,7 @@ describe('#delete', () => { const username = Symbol(); const mockAuditLogger = createMockAuditLogger(); const mockDebugLogger = createMockDebugLogger(); + const mockConfig = createMockConfig(); const { mockAuthorization, mockCheckPrivilegesGlobally } = createMockAuthorization(); mockAuthorization.mode.useRbacForRequest.mockReturnValue(true); mockCheckPrivilegesGlobally.mockReturnValue({ @@ -1329,7 +1343,7 @@ describe('#delete', () => { mockDebugLogger, mockAuthorization, null, - null, + mockConfig, mockInternalRepository, request ); diff --git a/x-pack/plugins/spaces/server/lib/spaces_client.ts b/x-pack/plugins/spaces/server/lib/spaces_client.ts index 609c2d4f462db..41e73543e5073 100644 --- a/x-pack/plugins/spaces/server/lib/spaces_client.ts +++ b/x-pack/plugins/spaces/server/lib/spaces_client.ts @@ -10,9 +10,10 @@ import { AuthorizationService } from '../../../security/server/lib/authorization import { isReservedSpace } from '../../common/is_reserved_space'; import { Space } from '../../common/model/space'; import { SpacesAuditLogger } from './audit_logger'; +import { SpacesConfig } from '../new_platform/config'; interface SpacesClientRequestFacade { - headers: Headers; + headers?: Headers; } export class SpacesClient { constructor( @@ -20,7 +21,7 @@ export class SpacesClient { private readonly debugLogger: (message: string) => void, private readonly authorization: AuthorizationService | null, private readonly callWithRequestSavedObjectRepository: any, - private readonly config: any, + private readonly config: SpacesConfig, private readonly internalSavedObjectRepository: any, private readonly request: SpacesClientRequestFacade ) {} @@ -45,7 +46,7 @@ export class SpacesClient { const { saved_objects } = await this.internalSavedObjectRepository.find({ type: 'space', page: 1, - perPage: this.config.get('xpack.spaces.maxSpaces'), + perPage: this.config.maxSpaces, sortField: 'name.keyword', }); @@ -92,7 +93,7 @@ export class SpacesClient { const { saved_objects } = await this.callWithRequestSavedObjectRepository.find({ type: 'space', page: 1, - perPage: this.config.get('xpack.spaces.maxSpaces'), + perPage: this.config.maxSpaces, sortField: 'name.keyword', }); @@ -142,7 +143,7 @@ export class SpacesClient { page: 1, perPage: 0, }); - if (total >= this.config.get('xpack.spaces.maxSpaces')) { + if (total >= this.config.maxSpaces) { throw Boom.badRequest( 'Unable to create Space, this exceeds the maximum number of spaces set by the xpack.spaces.maxSpaces setting' ); diff --git a/x-pack/plugins/spaces/server/lib/spaces_tutorial_context_factory.test.ts b/x-pack/plugins/spaces/server/lib/spaces_tutorial_context_factory.test.ts index 1dff381b96be5..7af1d999447ff 100644 --- a/x-pack/plugins/spaces/server/lib/spaces_tutorial_context_factory.test.ts +++ b/x-pack/plugins/spaces/server/lib/spaces_tutorial_context_factory.test.ts @@ -8,10 +8,11 @@ import * as Rx from 'rxjs'; import { DEFAULT_SPACE_ID } from '../../common/constants'; import { createSpacesTutorialContextFactory } from './spaces_tutorial_context_factory'; import { SpacesService } from '../new_platform/spaces_service'; -import { SavedObjectsService, KibanaConfig } from '../../../../../src/legacy/server/kbn_server'; +import { SavedObjectsService } from '../../../../../src/legacy/server/kbn_server'; import { SecurityPlugin } from '../../../security'; import { SpacesAuditLogger } from './audit_logger'; import { ElasticsearchServiceSetup } from '../../../../../src/core/server'; +import { SpacesConfig } from '../new_platform/config'; const server = { config: () => { @@ -36,7 +37,7 @@ const log = { fatal: jest.fn(), }; -const service = new SpacesService(log, server.config() as KibanaConfig); +const service = new SpacesService(log, server.config().get('server.basePath')); describe('createSpacesTutorialContextFactory', () => { it('should create a valid context factory', async () => { @@ -52,6 +53,7 @@ describe('createSpacesTutorialContextFactory', () => { savedObjects: {} as SavedObjectsService, getSecurity: () => ({} as SecurityPlugin), spacesAuditLogger: {} as SpacesAuditLogger, + config$: Rx.of(new SpacesConfig({ maxSpaces: 1000 })), }); expect(typeof createSpacesTutorialContextFactory(spacesService)).toEqual('function'); }); @@ -69,6 +71,7 @@ describe('createSpacesTutorialContextFactory', () => { savedObjects: {} as SavedObjectsService, getSecurity: () => ({} as SecurityPlugin), spacesAuditLogger: {} as SpacesAuditLogger, + config$: Rx.of(new SpacesConfig({ maxSpaces: 1000 })), }); const contextFactory = createSpacesTutorialContextFactory(spacesService); @@ -95,6 +98,7 @@ describe('createSpacesTutorialContextFactory', () => { savedObjects: {} as SavedObjectsService, getSecurity: () => ({} as SecurityPlugin), spacesAuditLogger: {} as SpacesAuditLogger, + config$: Rx.of(new SpacesConfig({ maxSpaces: 1000 })), }); const contextFactory = createSpacesTutorialContextFactory(spacesService); diff --git a/x-pack/plugins/spaces/server/new_platform/config.ts b/x-pack/plugins/spaces/server/new_platform/config.ts new file mode 100644 index 0000000000000..80f5f419235de --- /dev/null +++ b/x-pack/plugins/spaces/server/new_platform/config.ts @@ -0,0 +1,20 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { schema, TypeOf } from '@kbn/config-schema'; + +/** @internal */ +export class SpacesConfig { + public static schema = schema.object({ + maxSpaces: schema.number({ defaultValue: 1000 }), + }); + + public readonly maxSpaces: number; + + constructor(config: TypeOf) { + this.maxSpaces = config.maxSpaces; + } +} diff --git a/x-pack/plugins/spaces/server/new_platform/plugin.ts b/x-pack/plugins/spaces/server/new_platform/plugin.ts index 423bf2ff56be5..38048d5018a40 100644 --- a/x-pack/plugins/spaces/server/new_platform/plugin.ts +++ b/x-pack/plugins/spaces/server/new_platform/plugin.ts @@ -5,6 +5,7 @@ */ import { ServerRoute } from 'hapi'; +import { Observable } from 'rxjs'; import { KibanaConfig, SavedObjectsService } from '../../../../../src/legacy/server/kbn_server'; import { Logger, @@ -28,6 +29,7 @@ import { getSpacesUsageCollector } from '../lib/get_spaces_usage_collector'; import { SpacesService } from './spaces_service'; import { SecurityPlugin } from '../../../security'; import { SpacesServiceSetup } from './spaces_service/spaces_service'; +import { SpacesConfig } from './config'; export interface SpacesHttpServiceSetup extends HttpServiceSetup { route(route: ServerRoute | ServerRoute[]): void; @@ -67,12 +69,12 @@ export interface SpacesInitializerContext extends PluginInitializerContext { export class Plugin { private readonly pluginId = 'spaces'; - private config: KibanaConfig; + private config$: Observable; private log: Logger; - constructor(initializerContext: SpacesInitializerContext) { - this.config = initializerContext.legacyConfig; + constructor(private readonly initializerContext: SpacesInitializerContext) { + this.config$ = initializerContext.config.create(SpacesConfig); this.log = initializerContext.logger.get('spaces'); } @@ -90,16 +92,20 @@ export class Plugin { xpackMainPlugin.info.feature(this.pluginId).registerLicenseCheckResultsGenerator(checkLicense); const spacesAuditLogger = new SpacesAuditLogger( - this.config, + this.initializerContext.config, new AuditLogger(core.http.server, 'spaces') ); - const service = new SpacesService(this.log, this.config); + const service = new SpacesService( + this.log, + this.initializerContext.legacyConfig.get('server.basePath') + ); const spacesService = await service.setup({ elasticsearch: core.elasticsearch, savedObjects: core.savedObjects, getSecurity: plugins.getSecurity, spacesAuditLogger, + config$: this.config$, }); const { addScopedSavedObjectsClientWrapperFactory, types } = core.savedObjects; @@ -114,7 +120,7 @@ export class Plugin { initPrivateApis({ http: core.http, - config: this.config, + config: this.initializerContext.legacyConfig, savedObjects: core.savedObjects, spacesService, xpackMain: xpackMainPlugin, @@ -131,7 +137,7 @@ export class Plugin { // Register a function with server to manage the collection of usage stats core.usage.collectorSet.register( getSpacesUsageCollector({ - config: this.config, + config: this.initializerContext.legacyConfig, savedObjects: core.savedObjects, usage: core.usage, xpackMain: xpackMainPlugin, diff --git a/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts b/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts index 4913ea1f4f9aa..9fd241ecb169f 100644 --- a/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts +++ b/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts @@ -5,12 +5,14 @@ */ import { first } from 'rxjs/operators'; -import { SavedObjectsService, KibanaConfig } from '../../../../../../src/legacy/server/kbn_server'; +import { Observable, Subscription } from 'rxjs'; +import { SavedObjectsService } from '../../../../../../src/legacy/server/kbn_server'; import { Logger, ElasticsearchServiceSetup, Headers } from '../../../../../../src/core/server'; import { DEFAULT_SPACE_ID } from '../../../common/constants'; import { SecurityPlugin } from '../../../../security'; import { SpacesClient } from '../../lib/spaces_client'; import { getSpaceIdFromPath } from '../../lib/spaces_url_parser'; +import { SpacesConfig } from '../config'; interface RequestFacade { headers?: Headers; @@ -34,17 +36,16 @@ interface SpacesServiceDeps { elasticsearch: ElasticsearchServiceSetup; savedObjects: SavedObjectsService; getSecurity: () => SecurityPlugin; + config$: Observable; spacesAuditLogger: any; } export class SpacesService { - private readonly serverBasePath: string; + private configSubscription$?: Subscription; - private readonly contextCache: WeakMap; - - constructor(private readonly log: Logger, private readonly config: KibanaConfig) { - this.serverBasePath = config.get('server.basePath'); + private readonly contextCache: WeakMap = new WeakMap(); + constructor(private readonly log: Logger, private readonly serverBasePath: string) { this.contextCache = new WeakMap(); } @@ -52,8 +53,17 @@ export class SpacesService { elasticsearch, savedObjects, getSecurity, + config$, spacesAuditLogger, }: SpacesServiceDeps): Promise { + let config: SpacesConfig = await config$.pipe(first()).toPromise(); + + this.configSubscription$ = config$.subscribe({ + next: updatedConfig => { + config = updatedConfig; + }, + }); + const adminClient = await elasticsearch.adminClient$.pipe(first()).toPromise(); return { getSpaceId: (request: RequestFacade) => { @@ -91,7 +101,7 @@ export class SpacesService { }, authorization, callWithRequestRepository, - this.config, + config, internalRepository, request ); @@ -99,6 +109,13 @@ export class SpacesService { }; } + public async stop() { + if (this.configSubscription$) { + this.configSubscription$.unsubscribe(); + this.configSubscription$ = undefined; + } + } + private populateCache(request: RequestFacade) { const spaceId = getSpaceIdFromPath(request.getBasePath(), this.serverBasePath); diff --git a/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_test_handler.ts b/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_test_handler.ts index 4c163987e0ddf..9a18c6773d11b 100644 --- a/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_test_handler.ts +++ b/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_test_handler.ts @@ -17,6 +17,7 @@ import { SpacesService } from '../../../new_platform/spaces_service'; import { SpacesAuditLogger } from '../../../lib/audit_logger'; import { PrivateRouteDeps } from '../v1'; import { SpacesHttpServiceSetup } from '../../../new_platform/plugin'; +import { SpacesConfig } from '../../../new_platform/config'; interface KibanaServer extends Legacy.Server { savedObjects: any; @@ -52,7 +53,6 @@ export const defaultPreCheckLicenseImpl = (request: any) => ''; const baseConfig: TestConfig = { 'server.basePath': '', - 'xpack.spaces.maxSpaces': 1000, }; export function createTestHandler(initApiFn: (deps: PublicRouteDeps & PrivateRouteDeps) => void) { @@ -158,7 +158,7 @@ export function createTestHandler(initApiFn: (deps: PublicRouteDeps & PrivateRou fatal: jest.fn(), }; - const service = new SpacesService(log, server.config()); + const service = new SpacesService(log, server.config().get('server.basePath')); const spacesService = await service.setup({ elasticsearch: ({ adminClient$: Rx.of({ @@ -171,6 +171,7 @@ export function createTestHandler(initApiFn: (deps: PublicRouteDeps & PrivateRou savedObjects: server.savedObjects, getSecurity: () => ({} as SecurityPlugin), spacesAuditLogger: {} as SpacesAuditLogger, + config$: Rx.of(new SpacesConfig({ maxSpaces: 1000 })), }); spacesService.scopedClient = jest.fn((req: any) => { @@ -179,7 +180,7 @@ export function createTestHandler(initApiFn: (deps: PublicRouteDeps & PrivateRou () => null, null, mockSavedObjectsRepository, - mockConfig, + new SpacesConfig({ maxSpaces: 1000 }), mockSavedObjectsRepository, req ); From dbf39e04493c4e64b4d632d92fb584759f704584 Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Mon, 29 Apr 2019 14:37:01 -0400 Subject: [PATCH 20/68] additional comment --- x-pack/plugins/spaces/index.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/x-pack/plugins/spaces/index.ts b/x-pack/plugins/spaces/index.ts index 4f98775122314..fa63bd1a300e5 100644 --- a/x-pack/plugins/spaces/index.ts +++ b/x-pack/plugins/spaces/index.ts @@ -143,6 +143,8 @@ export const spaces = (kibana: Record) => const plugins = { xpackMain: server.plugins.xpack_main, + // TODO: Spaces has a circular dependency with Security right now. + // Security is not yet available when init runs, so this is wrapped in a function for the time being. getSecurity: () => server.plugins.security, spaces: this, }; From 68e7f25ccb8ac41b1c98200d0bd410db7d09927b Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Mon, 29 Apr 2019 15:36:48 -0400 Subject: [PATCH 21/68] shim NP config service --- x-pack/plugins/spaces/index.ts | 11 +++++++++++ x-pack/plugins/spaces/server/new_platform/plugin.ts | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/spaces/index.ts b/x-pack/plugins/spaces/index.ts index fa63bd1a300e5..7cfd33d241b54 100644 --- a/x-pack/plugins/spaces/index.ts +++ b/x-pack/plugins/spaces/index.ts @@ -4,6 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ +import * as Rx from 'rxjs'; import { resolve } from 'path'; import KbnServer, { Server } from '../../../src/legacy/server/kbn_server'; import { HttpServiceSetup } from '../../../src/core/server'; @@ -24,6 +25,7 @@ import { SpacesHttpServiceSetup, } from './server/new_platform/plugin'; import { initSpacesRequestInterceptors } from './server/lib/request_interceptors'; +import { SpacesConfig } from './server/new_platform/config'; export const spaces = (kibana: Record) => new kibana.Plugin({ @@ -116,6 +118,15 @@ export const spaces = (kibana: Record) => const kbnServer = (server as unknown) as KbnServer; const initializerContext = ({ legacyConfig: server.config(), + config: { + create: (ConfigClass: typeof SpacesConfig) => { + return Rx.of( + new ConfigClass({ + maxSpaces: server.config().get('xpack.spaces.maxSpaces'), + }) + ); + }, + }, logger: { get: (context: string) => ({ debug: (message: any) => server.log([context, 'debug'], message), diff --git a/x-pack/plugins/spaces/server/new_platform/plugin.ts b/x-pack/plugins/spaces/server/new_platform/plugin.ts index 38048d5018a40..f14e9032fb4b1 100644 --- a/x-pack/plugins/spaces/server/new_platform/plugin.ts +++ b/x-pack/plugins/spaces/server/new_platform/plugin.ts @@ -92,7 +92,7 @@ export class Plugin { xpackMainPlugin.info.feature(this.pluginId).registerLicenseCheckResultsGenerator(checkLicense); const spacesAuditLogger = new SpacesAuditLogger( - this.initializerContext.config, + this.initializerContext.legacyConfig, new AuditLogger(core.http.server, 'spaces') ); From 18bda1b017775adfa459806c027bf31cb07c9d84 Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Fri, 3 May 2019 15:33:19 -0400 Subject: [PATCH 22/68] fix merge from master --- x-pack/plugins/spaces/index.ts | 1 + x-pack/plugins/spaces/server/new_platform/plugin.ts | 10 +++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/spaces/index.ts b/x-pack/plugins/spaces/index.ts index 7cfd33d241b54..40915aa117a61 100644 --- a/x-pack/plugins/spaces/index.ts +++ b/x-pack/plugins/spaces/index.ts @@ -150,6 +150,7 @@ export const spaces = (kibana: Record) => tutorial: { addScopedTutorialContextFactory: (server as any).addScopedTutorialContextFactory, }, + legacyServer: server, }; const plugins = { diff --git a/x-pack/plugins/spaces/server/new_platform/plugin.ts b/x-pack/plugins/spaces/server/new_platform/plugin.ts index a00449393331c..f60238f099796 100644 --- a/x-pack/plugins/spaces/server/new_platform/plugin.ts +++ b/x-pack/plugins/spaces/server/new_platform/plugin.ts @@ -6,6 +6,7 @@ import { ServerRoute } from 'hapi'; import { Observable } from 'rxjs'; +import { Legacy } from 'kibana'; import { KibanaConfig, SavedObjectsService } from '../../../../../src/legacy/server/kbn_server'; import { Logger, @@ -46,6 +47,8 @@ export interface SpacesCoreSetup { tutorial: { addScopedTutorialContextFactory: (factory: any) => void; }; + // TODO: Required for shared AuditLogger base class + legacyServer: Legacy.Server; } export interface PluginsSetup { @@ -92,7 +95,12 @@ export class Plugin { xpackMainPlugin.info.feature(this.pluginId).registerLicenseCheckResultsGenerator(checkLicense); const spacesAuditLogger = new SpacesAuditLogger( - new AuditLogger(server, 'spaces', this.initializerContext.legacyConfig, xpackMainPlugin.info) + new AuditLogger( + core.legacyServer, + 'spaces', + this.initializerContext.legacyConfig, + xpackMainPlugin.info + ) ); const service = new SpacesService( From 21febb804892926e8b77470a2c8d1b2d9f98e241 Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Tue, 7 May 2019 09:36:53 -0400 Subject: [PATCH 23/68] revert relative imports into src/core and src/legacy --- x-pack/plugins/spaces/index.ts | 4 ++-- x-pack/plugins/spaces/server/lib/create_default_space.test.ts | 4 ++-- x-pack/plugins/spaces/server/lib/create_default_space.ts | 4 ++-- .../plugins/spaces/server/lib/get_spaces_usage_collector.ts | 2 +- .../plugins/spaces/server/lib/request_interceptors/index.ts | 4 ++-- .../lib/request_interceptors/on_post_auth_interceptor.test.ts | 4 ++-- .../lib/request_interceptors/on_request_interceptor.test.ts | 2 +- .../saved_objects_client_wrapper_factory.ts | 2 +- .../saved_objects_client/spaces_saved_objects_client.test.ts | 4 ++-- .../lib/saved_objects_client/spaces_saved_objects_client.ts | 2 +- x-pack/plugins/spaces/server/lib/spaces_client.ts | 2 +- .../spaces/server/lib/spaces_tutorial_context_factory.test.ts | 4 ++-- x-pack/plugins/spaces/server/new_platform/plugin.ts | 4 ++-- .../server/new_platform/spaces_service/spaces_service.ts | 4 ++-- .../server/routes/api/__fixtures__/create_test_handler.ts | 4 ++-- x-pack/plugins/spaces/server/routes/api/public/index.ts | 4 ++-- x-pack/plugins/spaces/server/routes/api/v1/index.ts | 2 +- 17 files changed, 28 insertions(+), 28 deletions(-) diff --git a/x-pack/plugins/spaces/index.ts b/x-pack/plugins/spaces/index.ts index 40915aa117a61..cdead9583d33c 100644 --- a/x-pack/plugins/spaces/index.ts +++ b/x-pack/plugins/spaces/index.ts @@ -6,8 +6,8 @@ import * as Rx from 'rxjs'; import { resolve } from 'path'; -import KbnServer, { Server } from '../../../src/legacy/server/kbn_server'; -import { HttpServiceSetup } from '../../../src/core/server'; +import KbnServer, { Server } from 'src/legacy/server/kbn_server'; +import { HttpServiceSetup } from 'src/core/server'; // @ts-ignore import { AuditLogger } from '../../server/lib/audit_logger'; // @ts-ignore diff --git a/x-pack/plugins/spaces/server/lib/create_default_space.test.ts b/x-pack/plugins/spaces/server/lib/create_default_space.test.ts index 250b67ce2f102..7c92e1930ff1f 100644 --- a/x-pack/plugins/spaces/server/lib/create_default_space.test.ts +++ b/x-pack/plugins/spaces/server/lib/create_default_space.test.ts @@ -10,8 +10,8 @@ import * as Rx from 'rxjs'; import Boom from 'boom'; import { getClient } from '../../../../server/lib/get_client_shield'; import { createDefaultSpace } from './create_default_space'; -import { SavedObjectsService } from '../../../../../src/legacy/server/kbn_server'; -import { ElasticsearchServiceSetup } from '../../../../../src/core/server'; +import { SavedObjectsService } from 'src/legacy/server/kbn_server'; +import { ElasticsearchServiceSetup } from 'src/core/server'; let mockCallWithRequest; beforeEach(() => { diff --git a/x-pack/plugins/spaces/server/lib/create_default_space.ts b/x-pack/plugins/spaces/server/lib/create_default_space.ts index 7807ba37d6438..35507ad9bf694 100644 --- a/x-pack/plugins/spaces/server/lib/create_default_space.ts +++ b/x-pack/plugins/spaces/server/lib/create_default_space.ts @@ -7,8 +7,8 @@ import { i18n } from '@kbn/i18n'; import { first } from 'rxjs/operators'; -import { SavedObjectsService } from '../../../../../src/legacy/server/kbn_server'; -import { ElasticsearchServiceSetup } from '../../../../../src/core/server'; +import { SavedObjectsService } from 'src/legacy/server/kbn_server'; +import { ElasticsearchServiceSetup } from 'src/core/server'; import { DEFAULT_SPACE_ID } from '../../common/constants'; interface Deps { diff --git a/x-pack/plugins/spaces/server/lib/get_spaces_usage_collector.ts b/x-pack/plugins/spaces/server/lib/get_spaces_usage_collector.ts index 1562cfd5318c6..83d31c9c223a0 100644 --- a/x-pack/plugins/spaces/server/lib/get_spaces_usage_collector.ts +++ b/x-pack/plugins/spaces/server/lib/get_spaces_usage_collector.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { SavedObjectsService } from '../../../../../src/legacy/server/kbn_server'; +import { SavedObjectsService } from 'src/legacy/server/kbn_server'; import { XPackMainPlugin } from '../../../xpack_main/xpack_main'; // @ts-ignore import { KIBANA_STATS_TYPE_MONITORING } from '../../../monitoring/common/constants'; diff --git a/x-pack/plugins/spaces/server/lib/request_interceptors/index.ts b/x-pack/plugins/spaces/server/lib/request_interceptors/index.ts index 1b1d9dc38e812..4d47df42351f5 100644 --- a/x-pack/plugins/spaces/server/lib/request_interceptors/index.ts +++ b/x-pack/plugins/spaces/server/lib/request_interceptors/index.ts @@ -4,8 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Logger } from '../../../../../../src/core/server'; -import { KibanaConfig, Server } from '../../../../../../src/legacy/server/kbn_server'; +import { Logger } from 'src/core/server'; +import { KibanaConfig, Server } from 'src/legacy/server/kbn_server'; import { XPackMainPlugin } from '../../../../xpack_main/xpack_main'; import { initSpacesOnRequestInterceptor } from './on_request_interceptor'; import { initSpacesOnPostAuthRequestInterceptor } from './on_post_auth_interceptor'; diff --git a/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts b/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts index f146ba5180f3e..02e4b851d4629 100644 --- a/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts +++ b/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts @@ -7,7 +7,7 @@ import { Server } from 'hapi'; import sinon from 'sinon'; import * as Rx from 'rxjs'; -import { SavedObject } from '../../../../../../src/legacy/server/saved_objects'; +import { SavedObject } from 'src/legacy/server/saved_objects'; import { Feature } from '../../../../xpack_main/types'; import { convertSavedObjectToSpace } from '../../routes/lib'; import { initSpacesOnPostAuthRequestInterceptor } from './on_post_auth_interceptor'; @@ -16,7 +16,7 @@ import { SpacesService } from '../../new_platform/spaces_service'; import { SecurityPlugin } from '../../../../security'; import { SpacesAuditLogger } from '../audit_logger'; import { SpacesServiceSetup } from '../../new_platform/spaces_service/spaces_service'; -import { ElasticsearchServiceSetup } from '../../../../../../src/core/server'; +import { ElasticsearchServiceSetup } from 'src/core/server'; import { SpacesConfig } from '../../new_platform/config'; describe('onPostAuthRequestInterceptor', () => { diff --git a/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.test.ts b/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.test.ts index 58a91a95d6958..c59800088d248 100644 --- a/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.test.ts +++ b/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.test.ts @@ -13,7 +13,7 @@ import { XPackMainPlugin } from '../../../../xpack_main/xpack_main'; import { SecurityPlugin } from '../../../../security'; import { SpacesAuditLogger } from '../audit_logger'; import { SpacesServiceSetup } from '../../new_platform/spaces_service/spaces_service'; -import { ElasticsearchServiceSetup } from '../../../../../../src/core/server'; +import { ElasticsearchServiceSetup } from 'src/core/server'; import { SpacesConfig } from '../../new_platform/config'; describe('onRequestInterceptor', () => { diff --git a/x-pack/plugins/spaces/server/lib/saved_objects_client/saved_objects_client_wrapper_factory.ts b/x-pack/plugins/spaces/server/lib/saved_objects_client/saved_objects_client_wrapper_factory.ts index 870be5b0c9133..40808379a9389 100644 --- a/x-pack/plugins/spaces/server/lib/saved_objects_client/saved_objects_client_wrapper_factory.ts +++ b/x-pack/plugins/spaces/server/lib/saved_objects_client/saved_objects_client_wrapper_factory.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { SavedObjectsClientWrapperFactory } from '../../../../../../src/legacy/server/saved_objects'; +import { SavedObjectsClientWrapperFactory } from 'src/legacy/server/saved_objects'; import { SpacesSavedObjectsClient } from './spaces_saved_objects_client'; import { SpacesServiceSetup } from '../../new_platform/spaces_service/spaces_service'; diff --git a/x-pack/plugins/spaces/server/lib/saved_objects_client/spaces_saved_objects_client.test.ts b/x-pack/plugins/spaces/server/lib/saved_objects_client/spaces_saved_objects_client.test.ts index babb83f16d8b4..34c334f0b36b8 100644 --- a/x-pack/plugins/spaces/server/lib/saved_objects_client/spaces_saved_objects_client.test.ts +++ b/x-pack/plugins/spaces/server/lib/saved_objects_client/spaces_saved_objects_client.test.ts @@ -8,10 +8,10 @@ import { DEFAULT_SPACE_ID } from '../../../common/constants'; import { Space } from '../../../common/model/space'; import { SpacesSavedObjectsClient } from './spaces_saved_objects_client'; import { SpacesService } from '../../new_platform/spaces_service'; -import { SavedObjectsService } from '../../../../../../src/legacy/server/kbn_server'; +import { SavedObjectsService } from 'src/legacy/server/kbn_server'; import { SecurityPlugin } from '../../../../security'; import { SpacesAuditLogger } from '../audit_logger'; -import { ElasticsearchServiceSetup } from '../../../../../../src/core/server'; +import { ElasticsearchServiceSetup } from 'src/core/server'; import { SpacesConfig } from '../../new_platform/config'; const config: any = { diff --git a/x-pack/plugins/spaces/server/lib/saved_objects_client/spaces_saved_objects_client.ts b/x-pack/plugins/spaces/server/lib/saved_objects_client/spaces_saved_objects_client.ts index 2b9bd2dcfb827..84412d87e320b 100644 --- a/x-pack/plugins/spaces/server/lib/saved_objects_client/spaces_saved_objects_client.ts +++ b/x-pack/plugins/spaces/server/lib/saved_objects_client/spaces_saved_objects_client.ts @@ -13,7 +13,7 @@ import { SavedObjectAttributes, SavedObjectsClient, UpdateOptions, -} from '../../../../../../src/legacy/server/saved_objects/service/saved_objects_client'; +} from 'src/legacy/server/saved_objects/service/saved_objects_client'; import { DEFAULT_SPACE_ID } from '../../../common/constants'; import { SpacesServiceSetup } from '../../new_platform/spaces_service/spaces_service'; diff --git a/x-pack/plugins/spaces/server/lib/spaces_client.ts b/x-pack/plugins/spaces/server/lib/spaces_client.ts index 41e73543e5073..de687ac70d53d 100644 --- a/x-pack/plugins/spaces/server/lib/spaces_client.ts +++ b/x-pack/plugins/spaces/server/lib/spaces_client.ts @@ -5,7 +5,7 @@ */ import Boom from 'boom'; import { omit } from 'lodash'; -import { Headers } from '../../../../../src/core/server'; +import { Headers } from 'src/core/server'; import { AuthorizationService } from '../../../security/server/lib/authorization/service'; import { isReservedSpace } from '../../common/is_reserved_space'; import { Space } from '../../common/model/space'; diff --git a/x-pack/plugins/spaces/server/lib/spaces_tutorial_context_factory.test.ts b/x-pack/plugins/spaces/server/lib/spaces_tutorial_context_factory.test.ts index 7af1d999447ff..4a5947d92a469 100644 --- a/x-pack/plugins/spaces/server/lib/spaces_tutorial_context_factory.test.ts +++ b/x-pack/plugins/spaces/server/lib/spaces_tutorial_context_factory.test.ts @@ -8,10 +8,10 @@ import * as Rx from 'rxjs'; import { DEFAULT_SPACE_ID } from '../../common/constants'; import { createSpacesTutorialContextFactory } from './spaces_tutorial_context_factory'; import { SpacesService } from '../new_platform/spaces_service'; -import { SavedObjectsService } from '../../../../../src/legacy/server/kbn_server'; +import { SavedObjectsService } from 'src/legacy/server/kbn_server'; import { SecurityPlugin } from '../../../security'; import { SpacesAuditLogger } from './audit_logger'; -import { ElasticsearchServiceSetup } from '../../../../../src/core/server'; +import { ElasticsearchServiceSetup } from 'src/core/server'; import { SpacesConfig } from '../new_platform/config'; const server = { diff --git a/x-pack/plugins/spaces/server/new_platform/plugin.ts b/x-pack/plugins/spaces/server/new_platform/plugin.ts index f60238f099796..8ba547f068e9d 100644 --- a/x-pack/plugins/spaces/server/new_platform/plugin.ts +++ b/x-pack/plugins/spaces/server/new_platform/plugin.ts @@ -7,13 +7,13 @@ import { ServerRoute } from 'hapi'; import { Observable } from 'rxjs'; import { Legacy } from 'kibana'; -import { KibanaConfig, SavedObjectsService } from '../../../../../src/legacy/server/kbn_server'; +import { KibanaConfig, SavedObjectsService } from 'src/legacy/server/kbn_server'; import { Logger, HttpServiceSetup, PluginInitializerContext, ElasticsearchServiceSetup, -} from '../../../../../src/core/server'; +} from 'src/core/server'; import { XPackMainPlugin } from '../../../xpack_main/xpack_main'; import { createDefaultSpace } from '../lib/create_default_space'; // @ts-ignore diff --git a/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts b/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts index 7cacc9591809f..f4ed7d9ff3573 100644 --- a/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts +++ b/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts @@ -6,8 +6,8 @@ import { first } from 'rxjs/operators'; import { Observable, Subscription } from 'rxjs'; -import { SavedObjectsService } from '../../../../../../src/legacy/server/kbn_server'; -import { Logger, ElasticsearchServiceSetup, Headers } from '../../../../../../src/core/server'; +import { SavedObjectsService } from 'src/legacy/server/kbn_server'; +import { Logger, ElasticsearchServiceSetup, Headers } from 'src/core/server'; import { DEFAULT_SPACE_ID } from '../../../common/constants'; import { SecurityPlugin } from '../../../../security'; import { SpacesClient } from '../../lib/spaces_client'; diff --git a/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_test_handler.ts b/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_test_handler.ts index 9a18c6773d11b..d11f7fafc1d64 100644 --- a/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_test_handler.ts +++ b/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_test_handler.ts @@ -7,8 +7,8 @@ import * as Rx from 'rxjs'; import { Server } from 'hapi'; import { Legacy } from 'kibana'; -import { ElasticsearchServiceSetup } from '../../../../../../../src/core/server'; -import { KibanaConfig } from '../../../../../../../src/legacy/server/kbn_server'; +import { ElasticsearchServiceSetup } from 'src/core/server'; +import { KibanaConfig } from 'src/legacy/server/kbn_server'; import { SecurityPlugin } from '../../../../../security'; import { SpacesClient } from '../../../lib/spaces_client'; import { createSpaces } from './create_spaces'; diff --git a/x-pack/plugins/spaces/server/routes/api/public/index.ts b/x-pack/plugins/spaces/server/routes/api/public/index.ts index ba1e31eace0c0..fcea02b7eaf88 100644 --- a/x-pack/plugins/spaces/server/routes/api/public/index.ts +++ b/x-pack/plugins/spaces/server/routes/api/public/index.ts @@ -4,8 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Logger, Headers } from '../../../../../../../src/core/server'; -import { SavedObjectsService } from '../../../../../../../src/legacy/server/kbn_server'; +import { Logger, Headers } from 'src/core/server'; +import { SavedObjectsService } from 'src/legacy/server/kbn_server'; import { XPackMainPlugin } from '../../../../../xpack_main/xpack_main'; import { routePreCheckLicense } from '../../../lib/route_pre_check_license'; import { initDeleteSpacesApi } from './delete'; diff --git a/x-pack/plugins/spaces/server/routes/api/v1/index.ts b/x-pack/plugins/spaces/server/routes/api/v1/index.ts index 1484460118aca..6f1de9f3efab2 100644 --- a/x-pack/plugins/spaces/server/routes/api/v1/index.ts +++ b/x-pack/plugins/spaces/server/routes/api/v1/index.ts @@ -7,7 +7,7 @@ import { SavedObjectsService, KibanaConfig, -} from '../../../../../../../src/legacy/server/kbn_server'; +} from 'src/legacy/server/kbn_server'; import { XPackMainPlugin } from '../../../../../xpack_main/xpack_main'; import { routePreCheckLicense } from '../../../lib/route_pre_check_license'; import { initPrivateSpacesApi } from './spaces'; From 4f1821ef07edcd270490d6eb867b854f80279c7d Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Tue, 7 May 2019 10:10:38 -0400 Subject: [PATCH 24/68] shim capabilities modifier into new platform --- x-pack/plugins/spaces/index.ts | 21 +++-------------- .../spaces/server/new_platform/plugin.ts | 23 ++++++++++++++++++- 2 files changed, 25 insertions(+), 19 deletions(-) diff --git a/x-pack/plugins/spaces/index.ts b/x-pack/plugins/spaces/index.ts index fc5d3789c5168..723559a7ec09c 100644 --- a/x-pack/plugins/spaces/index.ts +++ b/x-pack/plugins/spaces/index.ts @@ -17,7 +17,6 @@ import { wrapError } from './server/lib/errors'; import { getActiveSpace } from './server/lib/get_active_space'; import { getSpaceSelectorUrl } from './server/lib/get_space_selector_url'; import { migrateToKibana660 } from './server/lib/migrations'; -import { toggleUICapabilities } from './server/lib/toggle_ui_capabilities'; import { plugin } from './server/new_platform'; import { SpacesInitializerContext, @@ -26,7 +25,6 @@ import { } from './server/new_platform/plugin'; import { initSpacesRequestInterceptors } from './server/lib/request_interceptors'; import { SpacesConfig } from './server/new_platform/config'; - export const spaces = (kibana: Record) => new kibana.Plugin({ id: 'spaces', @@ -144,6 +142,9 @@ export const spaces = (kibana: Record) => tutorial: { addScopedTutorialContextFactory: (server as any).addScopedTutorialContextFactory, }, + capabilities: { + registerCapabilitiesModifier: server.registerCapabilitiesModifier, + }, legacyServer: server, }; @@ -167,21 +168,5 @@ export const spaces = (kibana: Record) => server.expose('getSpaceId', (request: any) => spacesService.getSpaceId(request)); server.expose('spacesClient', spacesService); - - server.registerCapabilitiesModifier(async (request, uiCapabilities) => { - const spacesClient = spacesService.scopedClient(request); - try { - const activeSpace = await getActiveSpace( - spacesClient, - request.getBasePath(), - initializerContext.legacyConfig.get('server.basePath') - ); - - const features = plugins.xpackMain.getFeatures(); - return toggleUICapabilities(features, uiCapabilities, activeSpace); - } catch (e) { - return uiCapabilities; - } - }); }, }); diff --git a/x-pack/plugins/spaces/server/new_platform/plugin.ts b/x-pack/plugins/spaces/server/new_platform/plugin.ts index 8ba547f068e9d..b05db43bf7d03 100644 --- a/x-pack/plugins/spaces/server/new_platform/plugin.ts +++ b/x-pack/plugins/spaces/server/new_platform/plugin.ts @@ -14,6 +14,7 @@ import { PluginInitializerContext, ElasticsearchServiceSetup, } from 'src/core/server'; +import { CapabilitiesModifier } from 'src/legacy/server/capabilities'; import { XPackMainPlugin } from '../../../xpack_main/xpack_main'; import { createDefaultSpace } from '../lib/create_default_space'; // @ts-ignore @@ -31,6 +32,8 @@ import { SpacesService } from './spaces_service'; import { SecurityPlugin } from '../../../security'; import { SpacesServiceSetup } from './spaces_service/spaces_service'; import { SpacesConfig } from './config'; +import { getActiveSpace } from '../lib/get_active_space'; +import { toggleUICapabilities } from '../lib/toggle_ui_capabilities'; export interface SpacesHttpServiceSetup extends HttpServiceSetup { route(route: ServerRoute | ServerRoute[]): void; @@ -47,6 +50,9 @@ export interface SpacesCoreSetup { tutorial: { addScopedTutorialContextFactory: (factory: any) => void; }; + capabilities: { + registerCapabilitiesModifier: (provider: CapabilitiesModifier) => void; + }; // TODO: Required for shared AuditLogger base class legacyServer: Legacy.Server; } @@ -125,6 +131,22 @@ export class Plugin { createSpacesTutorialContextFactory(spacesService) ); + core.capabilities.registerCapabilitiesModifier(async (request, uiCapabilities) => { + const spacesClient = spacesService.scopedClient(request); + try { + const activeSpace = await getActiveSpace( + spacesClient, + request.getBasePath(), + this.initializerContext.legacyConfig.get('server.basePath') + ); + + const features = plugins.xpackMain.getFeatures(); + return toggleUICapabilities(features, uiCapabilities, activeSpace); + } catch (e) { + return uiCapabilities; + } + }); + initPrivateApis({ http: core.http, config: this.initializerContext.legacyConfig, @@ -145,7 +167,6 @@ export class Plugin { core.usage.collectorSet.register( getSpacesUsageCollector({ config: this.initializerContext.legacyConfig, - savedObjects: core.savedObjects, usage: core.usage, xpackMain: xpackMainPlugin, }) From 167cc74cd0b3d0994de5739ecb214f3dcd2dd544 Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Tue, 7 May 2019 10:20:11 -0400 Subject: [PATCH 25/68] removing placeholder kibana.json --- x-pack/plugins/spaces/kibana.json | 11 ----------- 1 file changed, 11 deletions(-) delete mode 100644 x-pack/plugins/spaces/kibana.json diff --git a/x-pack/plugins/spaces/kibana.json b/x-pack/plugins/spaces/kibana.json deleted file mode 100644 index 285ddf048d02a..0000000000000 --- a/x-pack/plugins/spaces/kibana.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "id": "spaces", - "version": "0.0.1", - "kibanaVersion": "kibana", - "configPath": [ - "xpack", - "spaces" - ], - "server": true, - "ui": true -} \ No newline at end of file From 25627c5239c8e01f7a8bfce39cbb321e5920b8e7 Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Tue, 7 May 2019 11:34:48 -0400 Subject: [PATCH 26/68] fix prettier problem --- x-pack/plugins/spaces/server/routes/api/v1/index.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/x-pack/plugins/spaces/server/routes/api/v1/index.ts b/x-pack/plugins/spaces/server/routes/api/v1/index.ts index 6f1de9f3efab2..10b333d59e6d9 100644 --- a/x-pack/plugins/spaces/server/routes/api/v1/index.ts +++ b/x-pack/plugins/spaces/server/routes/api/v1/index.ts @@ -4,10 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { - SavedObjectsService, - KibanaConfig, -} from 'src/legacy/server/kbn_server'; +import { SavedObjectsService, KibanaConfig } from 'src/legacy/server/kbn_server'; import { XPackMainPlugin } from '../../../../../xpack_main/xpack_main'; import { routePreCheckLicense } from '../../../lib/route_pre_check_license'; import { initPrivateSpacesApi } from './spaces'; From 9b5623334a208336a3f45da1af1937eb87a70ab0 Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Wed, 8 May 2019 08:31:08 -0400 Subject: [PATCH 27/68] temporary: patch NP 'setUrl' --- src/core/server/http/lifecycle/on_request.ts | 21 ++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/core/server/http/lifecycle/on_request.ts b/src/core/server/http/lifecycle/on_request.ts index 168b4f513400f..e36524008a448 100644 --- a/src/core/server/http/lifecycle/on_request.ts +++ b/src/core/server/http/lifecycle/on_request.ts @@ -92,9 +92,26 @@ export function adoptToHapiOnRequestFormat(fn: OnRequestHandler) { redirected: OnRequestResult.redirected, rejected: OnRequestResult.rejected, setUrl: (newUrl: string | Url) => { - request.setUrl(newUrl); + if (typeof newUrl === 'string') { + request.setUrl({ + ...request.url, + pathname: newUrl, + path: newUrl, + href: newUrl, + }); + } else { + request.setUrl(newUrl); + } + // We should update raw request as well since it can be proxied to the old platform - request.raw.req.url = typeof newUrl === 'string' ? newUrl : newUrl.href; + let rawUrl; + if (typeof newUrl === 'string') { + rawUrl = newUrl + (request.url.search || ''); + } else { + rawUrl = newUrl.href; + } + + request.raw.req.url = rawUrl; }, }); if (OnRequestResult.isValidResult(result)) { From f8b974f076af6da71e450ec8dff379502b037415 Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Wed, 8 May 2019 08:39:49 -0400 Subject: [PATCH 28/68] migrate onRequest interceptor to NP, without tests --- .../server/http/setup_base_path_provider.js | 5 ----- x-pack/plugins/spaces/index.ts | 1 + .../server/lib/request_interceptors/index.ts | 2 ++ .../on_post_auth_interceptor.test.ts | 3 ++- .../on_request_interceptor.test.ts | 16 +++++++++++++- .../on_request_interceptor.ts | 22 +++++++++---------- 6 files changed, 30 insertions(+), 19 deletions(-) diff --git a/src/legacy/server/http/setup_base_path_provider.js b/src/legacy/server/http/setup_base_path_provider.js index 8cf6cc1fde512..60b651b4657ac 100644 --- a/src/legacy/server/http/setup_base_path_provider.js +++ b/src/legacy/server/http/setup_base_path_provider.js @@ -18,11 +18,6 @@ */ export function setupBasePathProvider(kbnServer) { - kbnServer.server.decorate('request', 'setBasePath', function (basePath) { - const request = this; - kbnServer.newPlatform.setup.core.http.setBasePathFor(request, basePath); - }); - kbnServer.server.decorate('request', 'getBasePath', function () { const request = this; return kbnServer.newPlatform.setup.core.http.getBasePathFor(request); diff --git a/x-pack/plugins/spaces/index.ts b/x-pack/plugins/spaces/index.ts index 723559a7ec09c..11150e098624b 100644 --- a/x-pack/plugins/spaces/index.ts +++ b/x-pack/plugins/spaces/index.ts @@ -160,6 +160,7 @@ export const spaces = (kibana: Record) => initSpacesRequestInterceptors({ config: initializerContext.legacyConfig, + http: core.http, legacyServer: server, log, spacesService, diff --git a/x-pack/plugins/spaces/server/lib/request_interceptors/index.ts b/x-pack/plugins/spaces/server/lib/request_interceptors/index.ts index 4d47df42351f5..1a772e41fa9e1 100644 --- a/x-pack/plugins/spaces/server/lib/request_interceptors/index.ts +++ b/x-pack/plugins/spaces/server/lib/request_interceptors/index.ts @@ -10,10 +10,12 @@ import { XPackMainPlugin } from '../../../../xpack_main/xpack_main'; import { initSpacesOnRequestInterceptor } from './on_request_interceptor'; import { initSpacesOnPostAuthRequestInterceptor } from './on_post_auth_interceptor'; import { SpacesServiceSetup } from '../../new_platform/spaces_service/spaces_service'; +import { SpacesHttpServiceSetup } from '../../new_platform/plugin'; export interface InterceptorDeps { config: KibanaConfig; legacyServer: Server; + http: SpacesHttpServiceSetup; xpackMain: XPackMainPlugin; spacesService: SpacesServiceSetup; log: Logger; diff --git a/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts b/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts index 02e4b851d4629..b945177e1b7ef 100644 --- a/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts +++ b/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts @@ -19,7 +19,8 @@ import { SpacesServiceSetup } from '../../new_platform/spaces_service/spaces_ser import { ElasticsearchServiceSetup } from 'src/core/server'; import { SpacesConfig } from '../../new_platform/config'; -describe('onPostAuthRequestInterceptor', () => { +// TODO: re-implement on NP +describe.skip('onPostAuthRequestInterceptor', () => { const sandbox = sinon.sandbox.create(); const teardowns: Array<() => void> = []; const headers = { diff --git a/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.test.ts b/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.test.ts index c59800088d248..48c6048c16965 100644 --- a/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.test.ts +++ b/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.test.ts @@ -15,8 +15,10 @@ import { SpacesAuditLogger } from '../audit_logger'; import { SpacesServiceSetup } from '../../new_platform/spaces_service/spaces_service'; import { ElasticsearchServiceSetup } from 'src/core/server'; import { SpacesConfig } from '../../new_platform/config'; +import { SpacesHttpServiceSetup } from '../../new_platform/plugin'; -describe('onRequestInterceptor', () => { +// TODO: re-implement on NP +describe.skip('onRequestInterceptor', () => { const sandbox = sinon.sandbox.create(); const teardowns: Array<() => void> = []; const headers = { @@ -113,11 +115,23 @@ describe('onRequestInterceptor', () => { config$: Rx.of(new SpacesConfig({ maxSpaces: 1000 })), }); + const httpService: SpacesHttpServiceSetup = { + route: jest.fn(), + server: null as any, + options: null as any, + registerAuth: null as any, + registerRouter: null as any, + registerOnRequest: jest.fn(), + getBasePathFor: jest.fn(), + setBasePathFor: jest.fn(), + }; + initSpacesOnRequestInterceptor({ config: server.config(), legacyServer: server, log, xpackMain: {} as XPackMainPlugin, + http: httpService, spacesService: { scopedClient: jest.fn(), getSpaceId: jest.fn(), diff --git a/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.ts b/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.ts index 55153cf508864..fe649c8246881 100644 --- a/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.ts +++ b/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.ts @@ -3,14 +3,18 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ +import { KibanaRequest, OnRequestToolkit } from 'src/core/server'; import { DEFAULT_SPACE_ID } from '../../../common/constants'; import { getSpaceIdFromPath } from '../spaces_url_parser'; import { InterceptorDeps } from '.'; -export function initSpacesOnRequestInterceptor({ config, legacyServer }: InterceptorDeps) { +export function initSpacesOnRequestInterceptor({ config, legacyServer, http }: InterceptorDeps) { const serverBasePath: string = config.get('server.basePath'); - legacyServer.ext('onRequest', async function spacesOnRequestHandler(request: any, h: any) { + http.registerOnRequest(async function spacesOnRequestHandler( + request: KibanaRequest, + toolkit: OnRequestToolkit + ) { const path = request.path; // If navigating within the context of a space, then we store the Space's URL Context on the request, @@ -19,20 +23,14 @@ export function initSpacesOnRequestInterceptor({ config, legacyServer }: Interce if (spaceId !== DEFAULT_SPACE_ID) { const reqBasePath = `/s/${spaceId}`; - request.setBasePath(reqBasePath); - const newLocation = path.substr(reqBasePath.length) || '/'; + http.setBasePathFor(request, reqBasePath); - const newUrl = { - ...request.url, - path: newLocation, - pathname: newLocation, - href: newLocation, - }; + const newLocation = path.substr(reqBasePath.length) || '/'; - request.setUrl(newUrl); + toolkit.setUrl(newLocation); } - return h.continue; + return toolkit.next(); }); } From a83f2f87ebafda14ce72e43c503b90ad585e8094 Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Wed, 8 May 2019 09:57:57 -0400 Subject: [PATCH 29/68] fix ts error --- .../lib/request_interceptors/on_post_auth_interceptor.test.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts b/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts index b945177e1b7ef..266eab9ee2a61 100644 --- a/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts +++ b/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts @@ -174,6 +174,7 @@ describe.skip('onPostAuthRequestInterceptor', () => { initSpacesOnRequestInterceptor({ config: server.config(), legacyServer: server, + http: null as any, log, xpackMain: server.plugins.xpack_main, spacesService, @@ -181,6 +182,7 @@ describe.skip('onPostAuthRequestInterceptor', () => { initSpacesOnPostAuthRequestInterceptor({ config: server.config(), legacyServer: server, + http: null as any, log, xpackMain: server.plugins.xpack_main, spacesService, From 98f50b6b878c7e428526c94d2c450889bf10df29 Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Thu, 9 May 2019 10:07:02 -0400 Subject: [PATCH 30/68] testing and deps cleanup for onRequestInterceptor --- .../server/lib/request_interceptors/index.ts | 21 +- .../on_post_auth_interceptor.test.ts | 4 - .../on_post_auth_interceptor.ts | 16 +- .../on_request_interceptor.test.ts | 428 +++++++++--------- .../on_request_interceptor.ts | 10 +- 5 files changed, 251 insertions(+), 228 deletions(-) diff --git a/x-pack/plugins/spaces/server/lib/request_interceptors/index.ts b/x-pack/plugins/spaces/server/lib/request_interceptors/index.ts index 1a772e41fa9e1..b26b67d99dbc7 100644 --- a/x-pack/plugins/spaces/server/lib/request_interceptors/index.ts +++ b/x-pack/plugins/spaces/server/lib/request_interceptors/index.ts @@ -4,22 +4,13 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Logger } from 'src/core/server'; -import { KibanaConfig, Server } from 'src/legacy/server/kbn_server'; -import { XPackMainPlugin } from '../../../../xpack_main/xpack_main'; -import { initSpacesOnRequestInterceptor } from './on_request_interceptor'; -import { initSpacesOnPostAuthRequestInterceptor } from './on_post_auth_interceptor'; -import { SpacesServiceSetup } from '../../new_platform/spaces_service/spaces_service'; -import { SpacesHttpServiceSetup } from '../../new_platform/plugin'; +import { initSpacesOnRequestInterceptor, OnRequestInterceptorDeps } from './on_request_interceptor'; +import { + initSpacesOnPostAuthRequestInterceptor, + OnPostAuthInterceptorDeps, +} from './on_post_auth_interceptor'; -export interface InterceptorDeps { - config: KibanaConfig; - legacyServer: Server; - http: SpacesHttpServiceSetup; - xpackMain: XPackMainPlugin; - spacesService: SpacesServiceSetup; - log: Logger; -} +export type InterceptorDeps = OnRequestInterceptorDeps & OnPostAuthInterceptorDeps; export function initSpacesRequestInterceptors(deps: InterceptorDeps) { initSpacesOnRequestInterceptor(deps); diff --git a/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts b/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts index 266eab9ee2a61..6ed1acd68b44d 100644 --- a/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts +++ b/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts @@ -173,11 +173,7 @@ describe.skip('onPostAuthRequestInterceptor', () => { // we are including the already tested interceptor here in the test chain. initSpacesOnRequestInterceptor({ config: server.config(), - legacyServer: server, http: null as any, - log, - xpackMain: server.plugins.xpack_main, - spacesService, }); initSpacesOnPostAuthRequestInterceptor({ config: server.config(), diff --git a/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.ts b/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.ts index 834431081fb88..4d4f739499488 100644 --- a/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.ts +++ b/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.ts @@ -4,11 +4,23 @@ * you may not use this file except in compliance with the Elastic License. */ import Boom from 'boom'; +import { KibanaConfig, Server } from 'src/legacy/server/kbn_server'; +import { HttpServiceSetup, Logger } from 'src/core/server'; import { Space } from '../../../common/model/space'; import { wrapError } from '../errors'; import { getSpaceSelectorUrl } from '../get_space_selector_url'; import { addSpaceIdToPath, getSpaceIdFromPath } from '../spaces_url_parser'; -import { InterceptorDeps } from '.'; +import { XPackMainPlugin } from '../../../../xpack_main/xpack_main'; +import { SpacesServiceSetup } from '../../new_platform/spaces_service/spaces_service'; + +export interface OnPostAuthInterceptorDeps { + config: KibanaConfig; + legacyServer: Server; + http: HttpServiceSetup; + xpackMain: XPackMainPlugin; + spacesService: SpacesServiceSetup; + log: Logger; +} export function initSpacesOnPostAuthRequestInterceptor({ config, @@ -16,7 +28,7 @@ export function initSpacesOnPostAuthRequestInterceptor({ xpackMain, spacesService, log, -}: InterceptorDeps) { +}: OnPostAuthInterceptorDeps) { const serverBasePath: string = config.get('server.basePath'); legacyServer.ext('onPostAuth', async function spacesOnPostAuthHandler(request: any, h: any) { diff --git a/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.test.ts b/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.test.ts index 48c6048c16965..9c267fb79103e 100644 --- a/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.test.ts +++ b/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.test.ts @@ -4,253 +4,273 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Server } from 'hapi'; -import sinon from 'sinon'; -import * as Rx from 'rxjs'; +import { Legacy } from 'kibana'; import { initSpacesOnRequestInterceptor } from './on_request_interceptor'; -import { SpacesService } from '../../new_platform/spaces_service'; -import { XPackMainPlugin } from '../../../../xpack_main/xpack_main'; -import { SecurityPlugin } from '../../../../security'; -import { SpacesAuditLogger } from '../audit_logger'; -import { SpacesServiceSetup } from '../../new_platform/spaces_service/spaces_service'; -import { ElasticsearchServiceSetup } from 'src/core/server'; -import { SpacesConfig } from '../../new_platform/config'; -import { SpacesHttpServiceSetup } from '../../new_platform/plugin'; - -// TODO: re-implement on NP -describe.skip('onRequestInterceptor', () => { - const sandbox = sinon.sandbox.create(); - const teardowns: Array<() => void> = []; - const headers = { - authorization: 'foo', - }; - let server: any; - let request: any; - - beforeEach(() => { - teardowns.push(() => sandbox.restore()); - request = async (path: string) => { - server = new Server(); - - interface Config { - [key: string]: any; - } - const config: Config = { - 'server.basePath': '/foo', - }; - - server.decorate( - 'server', - 'config', - jest.fn(() => { - return { - get: jest.fn(key => { - return config[key]; - }), - }; - }) - ); +import { HttpServiceSetup, Router, KibanaRequest } from '../../../../../../src/core/server'; - server.savedObjects = { - SavedObjectsClient: { - errors: { - isNotFoundError: (e: Error) => e.message === 'space not found', - }, - }, - getSavedObjectsRepository: jest.fn().mockImplementation(() => { - return { - get: (type: string, id: string) => { - if (type === 'space') { - if (id === 'not-found') { - throw new Error('space not found'); - } - return { - id, - name: 'test space', - }; - } - }, - create: () => null, - }; - }), - }; - - server.plugins = { - elasticsearch: { - getCluster: jest.fn().mockReturnValue({ - callWithInternalUser: jest.fn(), - callWithRequest: jest.fn(), - }), - }, - spaces: { - spacesClient: { - scopedClient: jest.fn(), - }, - }, - }; - - const log = { - log: jest.fn(), - trace: jest.fn(), - debug: jest.fn(), - info: jest.fn(), - warn: jest.fn(), - error: jest.fn(), - fatal: jest.fn(), - }; - - const spacesService = new SpacesService(log, server.config()); - await spacesService.setup({ - elasticsearch: ({ - adminClient$: Rx.of({ - callAsInternalUser: jest.fn(), - asScoped: jest.fn(req => ({ - callWithRequest: jest.fn(), - })), - }), - } as unknown) as ElasticsearchServiceSetup, - savedObjects: server.savedObjects, - getSecurity: () => ({} as SecurityPlugin), - spacesAuditLogger: {} as SpacesAuditLogger, - config$: Rx.of(new SpacesConfig({ maxSpaces: 1000 })), - }); +import * as kbnTestServer from '../../../../../../src/test_utils/kbn_server'; +import { KibanaConfig } from '../../../../../../src/legacy/server/kbn_server'; - const httpService: SpacesHttpServiceSetup = { - route: jest.fn(), - server: null as any, - options: null as any, - registerAuth: null as any, - registerRouter: null as any, - registerOnRequest: jest.fn(), - getBasePathFor: jest.fn(), - setBasePathFor: jest.fn(), - }; - - initSpacesOnRequestInterceptor({ - config: server.config(), - legacyServer: server, - log, - xpackMain: {} as XPackMainPlugin, - http: httpService, - spacesService: { - scopedClient: jest.fn(), - getSpaceId: jest.fn(), - isInDefaultSpace: jest.fn(), - } as SpacesServiceSetup, - }); +describe('onRequestInterceptor', () => { + let root: ReturnType; - server.route([ - { - method: 'GET', - path: '/', - handler: (req: any) => { - return { path: req.path, url: req.url, basePath: req.getBasePath() }; - }, - }, + beforeEach(async () => { + root = kbnTestServer.createRoot(); + }, 30000); + + afterEach(async () => await root.shutdown()); + + function initKbnServer(http: HttpServiceSetup, routes: 'legacy' | 'new-platform') { + const kbnServer = kbnTestServer.getKbnServer(root); + + if (routes === 'legacy') { + kbnServer.server.route([ { method: 'GET', - path: '/app/kibana', - handler: (req: any) => { - return { path: req.path, url: req.url, basePath: req.getBasePath() }; + path: '/foo', + handler: (req: Legacy.Request, h: Legacy.ResponseToolkit) => { + return h.response({ path: req.path, basePath: http.getBasePathFor(req) }); }, }, { method: 'GET', path: '/some/path/s/foo/bar', - handler: (req: any) => { - return { path: req.path, url: req.url, basePath: req.getBasePath() }; + handler: (req: Legacy.Request, h: Legacy.ResponseToolkit) => { + return h.response({ path: req.path, basePath: http.getBasePathFor(req) }); }, }, { method: 'GET', path: '/i/love/spaces', - handler: (req: any) => { - return { path: req.path, query: req.query, url: req.url, basePath: req.getBasePath() }; + handler: (req: Legacy.Request, h: Legacy.ResponseToolkit) => { + return h.response({ + path: req.path, + basePath: http.getBasePathFor(req), + query: req.query, + }); }, }, + ]); + } + + if (routes === 'new-platform') { + const router = new Router('/'); + + router.get({ path: '/foo', validate: false }, (req: KibanaRequest, h: any) => { + return h.ok({ path: req.path, basePath: http.getBasePathFor(req) }); + }); + + router.get( + { path: '/some/path/s/foo/bar', validate: false }, + (req: KibanaRequest, h: any) => { + return h.ok({ path: req.path, basePath: http.getBasePathFor(req) }); + } + ); + + router.get( { - method: 'GET', - path: '/api/foo', - handler: (req: any) => { - return { path: req.path, url: req.url, basePath: req.getBasePath() }; + path: '/i/love/spaces', + validate: schema => { + return { + query: schema.object({ + queryParam: schema.string({ + defaultValue: 'oh noes, this was not set on the request correctly', + }), + }), + }; }, }, - ]); + (req: KibanaRequest, h: any) => { + return h.ok({ path: req.path, basePath: http.getBasePathFor(req), query: req.query }); + } + ); + + http.registerRouter(router); + } + } + + describe('requests proxied to the legacy platform', () => { + it('handles paths without a space identifier', async () => { + const { http } = await root.setup(); + + const basePath = '/'; + const config = ({ + get: jest.fn().mockReturnValue(basePath), + } as unknown) as KibanaConfig; + + initSpacesOnRequestInterceptor({ config, http }); - let basePath: string | undefined; - server.decorate('request', 'getBasePath', () => basePath); - server.decorate('request', 'setBasePath', (newPath: string) => { - basePath = newPath; + await root.start(); + + initKbnServer(http, 'legacy'); + + const path = '/foo'; + + await kbnTestServer.request.get(root, path).expect(200, { + path, + basePath: '', // no base path set for route within the default space }); + }); + + it('strips the Space URL Context from the request', async () => { + const { http } = await root.setup(); + + const basePath = '/'; + const config = ({ + get: jest.fn().mockReturnValue(basePath), + } as unknown) as KibanaConfig; - teardowns.push(() => server.stop()); + initSpacesOnRequestInterceptor({ config, http }); - return await server.inject({ - method: 'GET', - url: path, - headers, + await root.start(); + + initKbnServer(http, 'legacy'); + + const path = '/s/foo-space/foo'; + + await kbnTestServer.request.get(root, path).expect(200, { + path: '/foo', + basePath: '/s/foo-space', }); - }; - }); + }); - afterEach(async () => { - await Promise.all(teardowns.splice(0).map(fn => fn())); - }); + it('ignores space identifiers in the middle of the path', async () => { + const { http } = await root.setup(); - describe('onRequest', () => { - test('handles paths without a space identifier', async () => { - const response = await request('/'); - - expect(response.statusCode).toEqual(200); - expect(JSON.parse(response.payload)).toMatchObject({ - path: '/', - url: { - path: '/', - pathname: '/', - href: '/', - }, + const basePath = '/'; + const config = ({ + get: jest.fn().mockReturnValue(basePath), + } as unknown) as KibanaConfig; + + initSpacesOnRequestInterceptor({ config, http }); + + await root.start(); + + initKbnServer(http, 'legacy'); + + const path = '/some/path/s/foo/bar'; + + await kbnTestServer.request.get(root, path).expect(200, { + path: '/some/path/s/foo/bar', + basePath: '', // no base path set for route within the default space }); }); - test('strips the Space URL Context from the request', async () => { - const response = await request('/s/foo'); - expect(response.statusCode).toEqual(200); - expect(JSON.parse(response.payload)).toMatchObject({ - path: '/', - url: { - path: '/', - pathname: '/', - href: '/', + it('strips the Space URL Context from the request, maintaining the rest of the path', async () => { + const { http } = await root.setup(); + + const basePath = '/'; + const config = ({ + get: jest.fn().mockReturnValue(basePath), + } as unknown) as KibanaConfig; + + initSpacesOnRequestInterceptor({ config, http }); + + await root.start(); + + initKbnServer(http, 'legacy'); + + const path = '/s/foo/i/love/spaces?queryParam=queryValue'; + + await kbnTestServer.request.get(root, path).expect(200, { + path: '/i/love/spaces', + basePath: '/s/foo', + query: { + queryParam: 'queryValue', }, }); }); + }); + + describe('requests handled completely in the new platform', () => { + it('handles paths without a space identifier', async () => { + const { http } = await root.setup(); + + initKbnServer(http, 'new-platform'); + + const basePath = '/'; + const config = ({ + get: jest.fn().mockReturnValue(basePath), + } as unknown) as KibanaConfig; + + initSpacesOnRequestInterceptor({ config, http }); + + await root.start(); + + const path = '/foo'; + + await kbnTestServer.request.get(root, path).expect(200, { + path, + basePath: '', // no base path set for route within the default space + }); + }); + + it('strips the Space URL Context from the request', async () => { + const { http } = await root.setup(); + + initKbnServer(http, 'new-platform'); + + const basePath = '/'; + const config = ({ + get: jest.fn().mockReturnValue(basePath), + } as unknown) as KibanaConfig; + + initSpacesOnRequestInterceptor({ config, http }); + + await root.start(); + + const path = '/s/foo-space/foo'; + + await kbnTestServer.request.get(root, path).expect(200, { + path: '/foo', + basePath: '/s/foo-space', + }); + }); + + it('ignores space identifiers in the middle of the path', async () => { + const { http } = await root.setup(); + + initKbnServer(http, 'new-platform'); + + const basePath = '/'; + const config = ({ + get: jest.fn().mockReturnValue(basePath), + } as unknown) as KibanaConfig; + + initSpacesOnRequestInterceptor({ config, http }); + + await root.start(); - test('ignores space identifiers in the middle of the path', async () => { - const response = await request('/some/path/s/foo/bar'); - expect(response.statusCode).toEqual(200); - expect(JSON.parse(response.payload)).toMatchObject({ + const path = '/some/path/s/foo/bar'; + + await kbnTestServer.request.get(root, path).expect(200, { path: '/some/path/s/foo/bar', - url: { - path: '/some/path/s/foo/bar', - pathname: '/some/path/s/foo/bar', - href: '/some/path/s/foo/bar', - }, + basePath: '', // no base path set for route within the default space }); }); - test('strips the Space URL Context from the request, maintaining the rest of the path', async () => { - const response = await request('/s/foo/i/love/spaces?queryParam=queryValue'); - expect(response.statusCode).toEqual(200); - expect(JSON.parse(response.payload)).toMatchObject({ + it('strips the Space URL Context from the request, maintaining the rest of the path', async () => { + const { http } = await root.setup(); + + initKbnServer(http, 'new-platform'); + + const basePath = '/'; + const config = ({ + get: jest.fn().mockReturnValue(basePath), + } as unknown) as KibanaConfig; + + initSpacesOnRequestInterceptor({ config, http }); + + await root.start(); + + const path = '/s/foo/i/love/spaces?queryParam=queryValue'; + + await kbnTestServer.request.get(root, path).expect(200, { path: '/i/love/spaces', + basePath: '/s/foo', query: { queryParam: 'queryValue', }, - url: { - path: '/i/love/spaces', - pathname: '/i/love/spaces', - href: '/i/love/spaces', - }, }); }); }); diff --git a/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.ts b/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.ts index fe649c8246881..0cecf39451801 100644 --- a/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.ts +++ b/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.ts @@ -3,12 +3,16 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { KibanaRequest, OnRequestToolkit } from 'src/core/server'; +import { KibanaRequest, OnRequestToolkit, HttpServiceSetup } from 'src/core/server'; +import { KibanaConfig } from 'src/legacy/server/kbn_server'; import { DEFAULT_SPACE_ID } from '../../../common/constants'; import { getSpaceIdFromPath } from '../spaces_url_parser'; -import { InterceptorDeps } from '.'; -export function initSpacesOnRequestInterceptor({ config, legacyServer, http }: InterceptorDeps) { +export interface OnRequestInterceptorDeps { + config: KibanaConfig; + http: HttpServiceSetup; +} +export function initSpacesOnRequestInterceptor({ config, http }: OnRequestInterceptorDeps) { const serverBasePath: string = config.get('server.basePath'); http.registerOnRequest(async function spacesOnRequestHandler( From 2aa35130679f86361010d15363ed0d1950132650 Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Thu, 9 May 2019 13:15:25 -0400 Subject: [PATCH 31/68] replace spaces's usages of request.getBasePath with http.getBasePathFor --- .../on_post_auth_interceptor.test.ts | 37 ++--- .../on_post_auth_interceptor.ts | 3 +- .../spaces_saved_objects_client.test.ts | 151 ++++++------------ .../__snapshots__/spaces_client.test.ts.snap | 0 .../spaces/server/lib/spaces_client/index.ts | 8 + .../lib/spaces_client/spaces_client.mock.ts | 39 +++++ .../{ => spaces_client}/spaces_client.test.ts | 6 +- .../lib/{ => spaces_client}/spaces_client.ts | 10 +- .../spaces_tutorial_context_factory.test.ts | 51 +----- .../spaces/server/new_platform/plugin.ts | 3 +- .../spaces_service/spaces_service.mock.ts | 22 +++ .../spaces_service/spaces_service.ts | 23 +-- .../api/__fixtures__/create_test_handler.ts | 18 +-- .../spaces/server/routes/api/public/index.ts | 10 +- x-pack/typings/index.d.ts | 6 + 15 files changed, 188 insertions(+), 199 deletions(-) rename x-pack/plugins/spaces/server/lib/{ => spaces_client}/__snapshots__/spaces_client.test.ts.snap (100%) create mode 100644 x-pack/plugins/spaces/server/lib/spaces_client/index.ts create mode 100644 x-pack/plugins/spaces/server/lib/spaces_client/spaces_client.mock.ts rename x-pack/plugins/spaces/server/lib/{ => spaces_client}/spaces_client.test.ts (99%) rename x-pack/plugins/spaces/server/lib/{ => spaces_client}/spaces_client.ts (96%) create mode 100644 x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.mock.ts diff --git a/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts b/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts index 6ed1acd68b44d..7630bf63b5c09 100644 --- a/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts +++ b/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts @@ -16,7 +16,7 @@ import { SpacesService } from '../../new_platform/spaces_service'; import { SecurityPlugin } from '../../../../security'; import { SpacesAuditLogger } from '../audit_logger'; import { SpacesServiceSetup } from '../../new_platform/spaces_service/spaces_service'; -import { ElasticsearchServiceSetup } from 'src/core/server'; +import { elasticsearchServiceMock, httpServiceMock } from '../../../../../../src/core/server/mocks'; import { SpacesConfig } from '../../new_platform/config'; // TODO: re-implement on NP @@ -123,12 +123,6 @@ describe.skip('onPostAuthRequestInterceptor', () => { }, }; - let basePath: string | undefined; - server.decorate('request', 'getBasePath', () => basePath); - server.decorate('request', 'setBasePath', (newPath: string) => { - basePath = newPath; - }); - const log = { log: jest.fn(), trace: jest.fn(), @@ -139,16 +133,19 @@ describe.skip('onPostAuthRequestInterceptor', () => { fatal: jest.fn(), }; + let basePath: string | undefined; + + const httpMock = httpServiceMock.createSetupContract(); + + httpMock.getBasePathFor = jest.fn().mockReturnValue(basePath); + httpMock.setBasePathFor = jest.fn().mockImplementation((newPath: string) => { + basePath = newPath; + }); + const service = new SpacesService(log, server.config()); spacesService = await service.setup({ - elasticsearch: ({ - adminClient$: Rx.of({ - callAsInternalUser: jest.fn(), - asScoped: jest.fn(req => ({ - callWithRequest: jest.fn(), - })), - }), - } as unknown) as ElasticsearchServiceSetup, + http: httpMock, + elasticsearch: elasticsearchServiceMock.createSetupContract(), savedObjects: server.savedObjects, getSecurity: () => ({} as SecurityPlugin), spacesAuditLogger: {} as SpacesAuditLogger, @@ -173,12 +170,12 @@ describe.skip('onPostAuthRequestInterceptor', () => { // we are including the already tested interceptor here in the test chain. initSpacesOnRequestInterceptor({ config: server.config(), - http: null as any, + http: httpMock, }); initSpacesOnPostAuthRequestInterceptor({ config: server.config(), legacyServer: server, - http: null as any, + http: httpMock, log, xpackMain: server.plugins.xpack_main, spacesService, @@ -189,21 +186,21 @@ describe.skip('onPostAuthRequestInterceptor', () => { method: 'GET', path: '/', handler: (req: any) => { - return { path: req.path, url: req.url, basePath: req.getBasePath() }; + return { path: req.path, url: req.url, basePath: httpMock.getBasePathFor(req) }; }, }, { method: 'GET', path: '/app/{appId}', handler: (req: any) => { - return { path: req.path, url: req.url, basePath: req.getBasePath() }; + return { path: req.path, url: req.url, basePath: httpMock.getBasePathFor(req) }; }, }, { method: 'GET', path: '/api/foo', handler: (req: any) => { - return { path: req.path, url: req.url, basePath: req.getBasePath() }; + return { path: req.path, url: req.url, basePath: httpMock.getBasePathFor(req) }; }, }, ]); diff --git a/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.ts b/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.ts index 4d4f739499488..6c59f0c17702c 100644 --- a/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.ts +++ b/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.ts @@ -28,6 +28,7 @@ export function initSpacesOnPostAuthRequestInterceptor({ xpackMain, spacesService, log, + http, }: OnPostAuthInterceptorDeps) { const serverBasePath: string = config.get('server.basePath'); @@ -74,7 +75,7 @@ export function initSpacesOnPostAuthRequestInterceptor({ let spaceId: string = ''; let space: Space; try { - spaceId = getSpaceIdFromPath(request.getBasePath(), serverBasePath); + spaceId = getSpaceIdFromPath(http.getBasePathFor(request), serverBasePath); log.debug(`Verifying access to space "${spaceId}"`); diff --git a/x-pack/plugins/spaces/server/lib/saved_objects_client/spaces_saved_objects_client.test.ts b/x-pack/plugins/spaces/server/lib/saved_objects_client/spaces_saved_objects_client.test.ts index 34c334f0b36b8..0e298f4367d4a 100644 --- a/x-pack/plugins/spaces/server/lib/saved_objects_client/spaces_saved_objects_client.test.ts +++ b/x-pack/plugins/spaces/server/lib/saved_objects_client/spaces_saved_objects_client.test.ts @@ -3,46 +3,14 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import * as Rx from 'rxjs'; + import { DEFAULT_SPACE_ID } from '../../../common/constants'; -import { Space } from '../../../common/model/space'; import { SpacesSavedObjectsClient } from './spaces_saved_objects_client'; -import { SpacesService } from '../../new_platform/spaces_service'; -import { SavedObjectsService } from 'src/legacy/server/kbn_server'; -import { SecurityPlugin } from '../../../../security'; -import { SpacesAuditLogger } from '../audit_logger'; -import { ElasticsearchServiceSetup } from 'src/core/server'; -import { SpacesConfig } from '../../new_platform/config'; - -const config: any = { - 'server.basePath': '/', -}; +import { spacesServiceMock } from '../../new_platform/spaces_service/spaces_service.mock'; const types = ['foo', 'bar', 'space']; -const server = { - config: () => ({ - get: (key: string) => { - return config[key]; - }, - }), -}; - -const log = { - log: jest.fn(), - trace: jest.fn(), - debug: jest.fn(), - info: jest.fn(), - warn: jest.fn(), - error: jest.fn(), - fatal: jest.fn(), -}; - -const service = new SpacesService(log, server.config().get('server.basePath')); - -const createMockRequest = (space: Partial) => ({ - getBasePath: () => (space.id !== DEFAULT_SPACE_ID ? `/s/${space.id}` : ''), -}); +const createMockRequest = () => ({}); const createMockClient = () => { const errors = Symbol() as any; @@ -59,21 +27,8 @@ const createMockClient = () => { }; }; -const createSpacesService = async () => { - return service.setup({ - elasticsearch: ({ - adminClient$: Rx.of({ - callAsInternalUser: jest.fn(), - asScoped: jest.fn(req => ({ - callWithRequest: jest.fn(), - })), - }), - } as unknown) as ElasticsearchServiceSetup, - savedObjects: {} as SavedObjectsService, - getSecurity: () => ({} as SecurityPlugin), - spacesAuditLogger: {} as SpacesAuditLogger, - config$: Rx.of(new SpacesConfig({ maxSpaces: 1000 })), - }); +const createSpacesService = async (spaceId: string) => { + return spacesServiceMock.createSetupContract(spaceId); }; [ @@ -83,9 +38,9 @@ const createSpacesService = async () => { describe(`${currentSpace.id} space`, () => { describe('#get', () => { test(`throws error if options.namespace is specified`, async () => { - const request = createMockRequest({ id: currentSpace.id }); + const request = createMockRequest(); const baseClient = createMockClient(); - const spacesService = await createSpacesService(); + const spacesService = await createSpacesService(currentSpace.id); const client = new SpacesSavedObjectsClient({ request, @@ -100,9 +55,9 @@ const createSpacesService = async () => { }); test(`throws error if type is space`, async () => { - const request = createMockRequest({ id: currentSpace.id }); + const request = createMockRequest(); const baseClient = createMockClient(); - const spacesService = await createSpacesService(); + const spacesService = await createSpacesService(currentSpace.id); const client = new SpacesSavedObjectsClient({ request, @@ -115,11 +70,11 @@ const createSpacesService = async () => { }); test(`supplements options with undefined namespace`, async () => { - const request = createMockRequest({ id: currentSpace.id }); + const request = createMockRequest(); const baseClient = createMockClient(); const expectedReturnValue = Symbol(); baseClient.get.mockReturnValue(expectedReturnValue); - const spacesService = await createSpacesService(); + const spacesService = await createSpacesService(currentSpace.id); const client = new SpacesSavedObjectsClient({ request, @@ -143,9 +98,9 @@ const createSpacesService = async () => { describe('#bulkGet', () => { test(`throws error if options.namespace is specified`, async () => { - const request = createMockRequest({ id: currentSpace.id }); + const request = createMockRequest(); const baseClient = createMockClient(); - const spacesService = await createSpacesService(); + const spacesService = await createSpacesService(currentSpace.id); const client = new SpacesSavedObjectsClient({ request, @@ -160,9 +115,9 @@ const createSpacesService = async () => { }); test(`throws error if objects type is space`, async () => { - const request = createMockRequest({ id: currentSpace.id }); + const request = createMockRequest(); const baseClient = createMockClient(); - const spacesService = await createSpacesService(); + const spacesService = await createSpacesService(currentSpace.id); const client = new SpacesSavedObjectsClient({ request, @@ -177,11 +132,11 @@ const createSpacesService = async () => { }); test(`supplements options with undefined namespace`, async () => { - const request = createMockRequest({ id: currentSpace.id }); + const request = createMockRequest(); const baseClient = createMockClient(); const expectedReturnValue = Symbol(); baseClient.bulkGet.mockReturnValue(expectedReturnValue); - const spacesService = await createSpacesService(); + const spacesService = await createSpacesService(currentSpace.id); const client = new SpacesSavedObjectsClient({ request, @@ -205,9 +160,9 @@ const createSpacesService = async () => { describe('#find', () => { test(`throws error if options.namespace is specified`, async () => { - const request = createMockRequest({ id: currentSpace.id }); + const request = createMockRequest(); const baseClient = createMockClient(); - const spacesService = await createSpacesService(); + const spacesService = await createSpacesService(currentSpace.id); const client = new SpacesSavedObjectsClient({ request, @@ -220,11 +175,11 @@ const createSpacesService = async () => { }); test(`throws error if options.type is space`, async () => { - const request = createMockRequest({ id: currentSpace.id }); + const request = createMockRequest(); const baseClient = createMockClient(); const expectedReturnValue = Symbol(); baseClient.find.mockReturnValue(expectedReturnValue); - const spacesService = await createSpacesService(); + const spacesService = await createSpacesService(currentSpace.id); const client = new SpacesSavedObjectsClient({ request, @@ -237,11 +192,11 @@ const createSpacesService = async () => { }); test(`passes options.type to baseClient if valid singular type specified`, async () => { - const request = createMockRequest({ id: currentSpace.id }); + const request = createMockRequest(); const baseClient = createMockClient(); const expectedReturnValue = Symbol(); baseClient.find.mockReturnValue(expectedReturnValue); - const spacesService = await createSpacesService(); + const spacesService = await createSpacesService(currentSpace.id); const client = new SpacesSavedObjectsClient({ request, @@ -261,11 +216,11 @@ const createSpacesService = async () => { }); test(`throws error if options.type is array containing space`, async () => { - const request = createMockRequest({ id: currentSpace.id }); + const request = createMockRequest(); const baseClient = createMockClient(); const expectedReturnValue = Symbol(); baseClient.find.mockReturnValue(expectedReturnValue); - const spacesService = await createSpacesService(); + const spacesService = await createSpacesService(currentSpace.id); const client = new SpacesSavedObjectsClient({ request, @@ -280,11 +235,11 @@ const createSpacesService = async () => { }); test(`if options.type isn't provided specifies options.type based on the types excluding the space`, async () => { - const request = createMockRequest({ id: currentSpace.id }); + const request = createMockRequest(); const baseClient = createMockClient(); const expectedReturnValue = Symbol(); baseClient.find.mockReturnValue(expectedReturnValue); - const spacesService = await createSpacesService(); + const spacesService = await createSpacesService(currentSpace.id); const client = new SpacesSavedObjectsClient({ request, @@ -299,11 +254,11 @@ const createSpacesService = async () => { }); test(`supplements options with undefined namespace`, async () => { - const request = createMockRequest({ id: currentSpace.id }); + const request = createMockRequest(); const baseClient = createMockClient(); const expectedReturnValue = Symbol(); baseClient.find.mockReturnValue(expectedReturnValue); - const spacesService = await createSpacesService(); + const spacesService = await createSpacesService(currentSpace.id); const client = new SpacesSavedObjectsClient({ request, @@ -325,9 +280,9 @@ const createSpacesService = async () => { describe('#create', () => { test(`throws error if options.namespace is specified`, async () => { - const request = createMockRequest({ id: currentSpace.id }); + const request = createMockRequest(); const baseClient = createMockClient(); - const spacesService = await createSpacesService(); + const spacesService = await createSpacesService(currentSpace.id); const client = new SpacesSavedObjectsClient({ request, @@ -342,9 +297,9 @@ const createSpacesService = async () => { }); test(`throws error if type is space`, async () => { - const request = createMockRequest({ id: currentSpace.id }); + const request = createMockRequest(); const baseClient = createMockClient(); - const spacesService = await createSpacesService(); + const spacesService = await createSpacesService(currentSpace.id); const client = new SpacesSavedObjectsClient({ request, @@ -357,11 +312,11 @@ const createSpacesService = async () => { }); test(`supplements options with undefined namespace`, async () => { - const request = createMockRequest({ id: currentSpace.id }); + const request = createMockRequest(); const baseClient = createMockClient(); const expectedReturnValue = Symbol(); baseClient.create.mockReturnValue(expectedReturnValue); - const spacesService = await createSpacesService(); + const spacesService = await createSpacesService(currentSpace.id); const client = new SpacesSavedObjectsClient({ request, @@ -386,9 +341,9 @@ const createSpacesService = async () => { describe('#bulkCreate', () => { test(`throws error if options.namespace is specified`, async () => { - const request = createMockRequest({ id: currentSpace.id }); + const request = createMockRequest(); const baseClient = createMockClient(); - const spacesService = await createSpacesService(); + const spacesService = await createSpacesService(currentSpace.id); const client = new SpacesSavedObjectsClient({ request, @@ -403,9 +358,9 @@ const createSpacesService = async () => { }); test(`throws error if objects type is space`, async () => { - const request = createMockRequest({ id: currentSpace.id }); + const request = createMockRequest(); const baseClient = createMockClient(); - const spacesService = await createSpacesService(); + const spacesService = await createSpacesService(currentSpace.id); const client = new SpacesSavedObjectsClient({ request, @@ -423,11 +378,11 @@ const createSpacesService = async () => { }); test(`supplements options with undefined namespace`, async () => { - const request = createMockRequest({ id: currentSpace.id }); + const request = createMockRequest(); const baseClient = createMockClient(); const expectedReturnValue = Symbol(); baseClient.bulkCreate.mockReturnValue(expectedReturnValue); - const spacesService = await createSpacesService(); + const spacesService = await createSpacesService(currentSpace.id); const client = new SpacesSavedObjectsClient({ request, @@ -451,9 +406,9 @@ const createSpacesService = async () => { describe('#update', () => { test(`throws error if options.namespace is specified`, async () => { - const request = createMockRequest({ id: currentSpace.id }); + const request = createMockRequest(); const baseClient = createMockClient(); - const spacesService = await createSpacesService(); + const spacesService = await createSpacesService(currentSpace.id); const client = new SpacesSavedObjectsClient({ request, @@ -469,9 +424,9 @@ const createSpacesService = async () => { }); test(`throws error if type is space`, async () => { - const request = createMockRequest({ id: currentSpace.id }); + const request = createMockRequest(); const baseClient = createMockClient(); - const spacesService = await createSpacesService(); + const spacesService = await createSpacesService(currentSpace.id); const client = new SpacesSavedObjectsClient({ request, @@ -484,11 +439,11 @@ const createSpacesService = async () => { }); test(`supplements options with undefined namespace`, async () => { - const request = createMockRequest({ id: currentSpace.id }); + const request = createMockRequest(); const baseClient = createMockClient(); const expectedReturnValue = Symbol(); baseClient.update.mockReturnValue(expectedReturnValue); - const spacesService = await createSpacesService(); + const spacesService = await createSpacesService(currentSpace.id); const client = new SpacesSavedObjectsClient({ request, @@ -514,9 +469,9 @@ const createSpacesService = async () => { describe('#delete', () => { test(`throws error if options.namespace is specified`, async () => { - const request = createMockRequest({ id: currentSpace.id }); + const request = createMockRequest(); const baseClient = createMockClient(); - const spacesService = await createSpacesService(); + const spacesService = await createSpacesService(currentSpace.id); const client = new SpacesSavedObjectsClient({ request, @@ -532,9 +487,9 @@ const createSpacesService = async () => { }); test(`throws error if type is space`, async () => { - const request = createMockRequest({ id: currentSpace.id }); + const request = createMockRequest(); const baseClient = createMockClient(); - const spacesService = await createSpacesService(); + const spacesService = await createSpacesService(currentSpace.id); const client = new SpacesSavedObjectsClient({ request, @@ -547,11 +502,11 @@ const createSpacesService = async () => { }); test(`supplements options with undefined namespace`, async () => { - const request = createMockRequest({ id: currentSpace.id }); + const request = createMockRequest(); const baseClient = createMockClient(); const expectedReturnValue = Symbol(); baseClient.delete.mockReturnValue(expectedReturnValue); - const spacesService = await createSpacesService(); + const spacesService = await createSpacesService(currentSpace.id); const client = new SpacesSavedObjectsClient({ request, diff --git a/x-pack/plugins/spaces/server/lib/__snapshots__/spaces_client.test.ts.snap b/x-pack/plugins/spaces/server/lib/spaces_client/__snapshots__/spaces_client.test.ts.snap similarity index 100% rename from x-pack/plugins/spaces/server/lib/__snapshots__/spaces_client.test.ts.snap rename to x-pack/plugins/spaces/server/lib/spaces_client/__snapshots__/spaces_client.test.ts.snap diff --git a/x-pack/plugins/spaces/server/lib/spaces_client/index.ts b/x-pack/plugins/spaces/server/lib/spaces_client/index.ts new file mode 100644 index 0000000000000..3c883241a0ed4 --- /dev/null +++ b/x-pack/plugins/spaces/server/lib/spaces_client/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export { SpacesClient } from './spaces_client'; +export { spacesClientMock } from './spaces_client.mock'; diff --git a/x-pack/plugins/spaces/server/lib/spaces_client/spaces_client.mock.ts b/x-pack/plugins/spaces/server/lib/spaces_client/spaces_client.mock.ts new file mode 100644 index 0000000000000..49cafd7692eb3 --- /dev/null +++ b/x-pack/plugins/spaces/server/lib/spaces_client/spaces_client.mock.ts @@ -0,0 +1,39 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { DEFAULT_SPACE_ID } from '../../../common/constants'; +import { Space } from '../../../common/model/space'; + +const createSpacesClientMock = () => ({ + canEnumerateSpaces: jest.fn().mockResolvedValue(true), + + getAll: jest.fn().mockResolvedValue([ + { + id: DEFAULT_SPACE_ID, + name: 'mock default space', + disabledFeatures: [], + _reserved: true, + }, + ]), + + get: jest.fn().mockImplementation((spaceId: string) => { + return Promise.resolve({ + id: spaceId, + name: `mock space for ${spaceId}`, + disabledFeatures: [], + }); + }), + + create: jest.fn().mockImplementation((space: Space) => Promise.resolve(space)), + + update: jest.fn().mockImplementation((space: Space) => Promise.resolve(space)), + + delete: jest.fn(), +}); + +export const spacesClientMock = { + create: createSpacesClientMock, +}; diff --git a/x-pack/plugins/spaces/server/lib/spaces_client.test.ts b/x-pack/plugins/spaces/server/lib/spaces_client/spaces_client.test.ts similarity index 99% rename from x-pack/plugins/spaces/server/lib/spaces_client.test.ts rename to x-pack/plugins/spaces/server/lib/spaces_client/spaces_client.test.ts index fa8abf7538ccb..0cd36f2eceae7 100644 --- a/x-pack/plugins/spaces/server/lib/spaces_client.test.ts +++ b/x-pack/plugins/spaces/server/lib/spaces_client/spaces_client.test.ts @@ -5,9 +5,9 @@ */ import { SpacesClient } from './spaces_client'; -import { AuthorizationService } from '../../../security/server/lib/authorization/service'; -import { actionsFactory } from '../../../security/server/lib/authorization/actions'; -import { SpacesConfig } from '../new_platform/config'; +import { AuthorizationService } from '../../../../security/server/lib/authorization/service'; +import { actionsFactory } from '../../../../security/server/lib/authorization/actions'; +import { SpacesConfig } from '../../new_platform/config'; import { TypeOf } from '@kbn/config-schema'; const createMockAuditLogger = () => { diff --git a/x-pack/plugins/spaces/server/lib/spaces_client.ts b/x-pack/plugins/spaces/server/lib/spaces_client/spaces_client.ts similarity index 96% rename from x-pack/plugins/spaces/server/lib/spaces_client.ts rename to x-pack/plugins/spaces/server/lib/spaces_client/spaces_client.ts index de687ac70d53d..85c1befed9ec0 100644 --- a/x-pack/plugins/spaces/server/lib/spaces_client.ts +++ b/x-pack/plugins/spaces/server/lib/spaces_client/spaces_client.ts @@ -6,11 +6,11 @@ import Boom from 'boom'; import { omit } from 'lodash'; import { Headers } from 'src/core/server'; -import { AuthorizationService } from '../../../security/server/lib/authorization/service'; -import { isReservedSpace } from '../../common/is_reserved_space'; -import { Space } from '../../common/model/space'; -import { SpacesAuditLogger } from './audit_logger'; -import { SpacesConfig } from '../new_platform/config'; +import { AuthorizationService } from '../../../../security/server/lib/authorization/service'; +import { isReservedSpace } from '../../../common/is_reserved_space'; +import { Space } from '../../../common/model/space'; +import { SpacesAuditLogger } from '../audit_logger'; +import { SpacesConfig } from '../../new_platform/config'; interface SpacesClientRequestFacade { headers?: Headers; diff --git a/x-pack/plugins/spaces/server/lib/spaces_tutorial_context_factory.test.ts b/x-pack/plugins/spaces/server/lib/spaces_tutorial_context_factory.test.ts index 4a5947d92a469..296ccfc786700 100644 --- a/x-pack/plugins/spaces/server/lib/spaces_tutorial_context_factory.test.ts +++ b/x-pack/plugins/spaces/server/lib/spaces_tutorial_context_factory.test.ts @@ -11,8 +11,9 @@ import { SpacesService } from '../new_platform/spaces_service'; import { SavedObjectsService } from 'src/legacy/server/kbn_server'; import { SecurityPlugin } from '../../../security'; import { SpacesAuditLogger } from './audit_logger'; -import { ElasticsearchServiceSetup } from 'src/core/server'; import { SpacesConfig } from '../new_platform/config'; +import { elasticsearchServiceMock, httpServiceMock } from '../../../../../src/core/server/mocks'; +import { spacesServiceMock } from '../new_platform/spaces_service/spaces_service.mock'; const server = { config: () => { @@ -41,43 +42,15 @@ const service = new SpacesService(log, server.config().get('server.basePath')); describe('createSpacesTutorialContextFactory', () => { it('should create a valid context factory', async () => { - const spacesService = await service.setup({ - elasticsearch: ({ - adminClient$: Rx.of({ - callAsInternalUser: jest.fn(), - asScoped: jest.fn(req => ({ - callWithRequest: jest.fn(), - })), - }), - } as unknown) as ElasticsearchServiceSetup, - savedObjects: {} as SavedObjectsService, - getSecurity: () => ({} as SecurityPlugin), - spacesAuditLogger: {} as SpacesAuditLogger, - config$: Rx.of(new SpacesConfig({ maxSpaces: 1000 })), - }); + const spacesService = spacesServiceMock.createSetupContract(); expect(typeof createSpacesTutorialContextFactory(spacesService)).toEqual('function'); }); it('should create context with the current space id for space my-space-id', async () => { - const spacesService = await service.setup({ - elasticsearch: ({ - adminClient$: Rx.of({ - callAsInternalUser: jest.fn(), - asScoped: jest.fn(req => ({ - callWithRequest: jest.fn(), - })), - }), - } as unknown) as ElasticsearchServiceSetup, - savedObjects: {} as SavedObjectsService, - getSecurity: () => ({} as SecurityPlugin), - spacesAuditLogger: {} as SpacesAuditLogger, - config$: Rx.of(new SpacesConfig({ maxSpaces: 1000 })), - }); + const spacesService = spacesServiceMock.createSetupContract('my-space-id'); const contextFactory = createSpacesTutorialContextFactory(spacesService); - const request = { - getBasePath: () => '/foo/s/my-space-id', - }; + const request = {}; expect(contextFactory(request)).toEqual({ spaceId: 'my-space-id', @@ -87,14 +60,8 @@ describe('createSpacesTutorialContextFactory', () => { it('should create context with the current space id for the default space', async () => { const spacesService = await service.setup({ - elasticsearch: ({ - adminClient$: Rx.of({ - callAsInternalUser: jest.fn(), - asScoped: jest.fn(req => ({ - callWithRequest: jest.fn(), - })), - }), - } as unknown) as ElasticsearchServiceSetup, + http: httpServiceMock.createSetupContract(), + elasticsearch: elasticsearchServiceMock.createSetupContract(), savedObjects: {} as SavedObjectsService, getSecurity: () => ({} as SecurityPlugin), spacesAuditLogger: {} as SpacesAuditLogger, @@ -102,9 +69,7 @@ describe('createSpacesTutorialContextFactory', () => { }); const contextFactory = createSpacesTutorialContextFactory(spacesService); - const request = { - getBasePath: () => '/foo', - }; + const request = {}; expect(contextFactory(request)).toEqual({ spaceId: DEFAULT_SPACE_ID, diff --git a/x-pack/plugins/spaces/server/new_platform/plugin.ts b/x-pack/plugins/spaces/server/new_platform/plugin.ts index b05db43bf7d03..29525f4681687 100644 --- a/x-pack/plugins/spaces/server/new_platform/plugin.ts +++ b/x-pack/plugins/spaces/server/new_platform/plugin.ts @@ -114,6 +114,7 @@ export class Plugin { this.initializerContext.legacyConfig.get('server.basePath') ); const spacesService = await service.setup({ + http: core.http, elasticsearch: core.elasticsearch, savedObjects: core.savedObjects, getSecurity: plugins.getSecurity, @@ -136,7 +137,7 @@ export class Plugin { try { const activeSpace = await getActiveSpace( spacesClient, - request.getBasePath(), + core.http.getBasePathFor(request), this.initializerContext.legacyConfig.get('server.basePath') ); diff --git a/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.mock.ts b/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.mock.ts new file mode 100644 index 0000000000000..cef3dd23b02dd --- /dev/null +++ b/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.mock.ts @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { SpacesServiceSetup } from './spaces_service'; +import { spacesClientMock } from '../../lib/spaces_client'; +import { DEFAULT_SPACE_ID } from '../../../common/constants'; + +const createSetupContractMock = (spaceId = DEFAULT_SPACE_ID) => { + const setupContract: SpacesServiceSetup = { + getSpaceId: jest.fn().mockReturnValue(spaceId), + isInDefaultSpace: jest.fn().mockReturnValue(spaceId === DEFAULT_SPACE_ID), + scopedClient: jest.fn().mockReturnValue(spacesClientMock.create()), + }; + return setupContract; +}; + +export const spacesServiceMock = { + createSetupContract: createSetupContractMock, +}; diff --git a/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts b/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts index f4ed7d9ff3573..d3266b188b59e 100644 --- a/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts +++ b/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts @@ -6,18 +6,21 @@ import { first } from 'rxjs/operators'; import { Observable, Subscription } from 'rxjs'; +import { Legacy } from 'kibana'; import { SavedObjectsService } from 'src/legacy/server/kbn_server'; -import { Logger, ElasticsearchServiceSetup, Headers } from 'src/core/server'; +import { + Logger, + ElasticsearchServiceSetup, + HttpServiceSetup, + KibanaRequest, +} from 'src/core/server'; import { DEFAULT_SPACE_ID } from '../../../common/constants'; import { SecurityPlugin } from '../../../../security'; import { SpacesClient } from '../../lib/spaces_client'; import { getSpaceIdFromPath } from '../../lib/spaces_url_parser'; import { SpacesConfig } from '../config'; -interface RequestFacade { - headers?: Headers; - getBasePath: () => string; -} +type RequestFacade = KibanaRequest | Legacy.Request; export interface SpacesServiceSetup { scopedClient(request: RequestFacade): SpacesClient; @@ -33,6 +36,7 @@ interface CacheEntry { } interface SpacesServiceDeps { + http: HttpServiceSetup; elasticsearch: ElasticsearchServiceSetup; savedObjects: SavedObjectsService; getSecurity: () => SecurityPlugin | undefined; @@ -50,6 +54,7 @@ export class SpacesService { } public async setup({ + http, elasticsearch, savedObjects, getSecurity, @@ -68,7 +73,7 @@ export class SpacesService { return { getSpaceId: (request: RequestFacade) => { if (!this.contextCache.has(request)) { - this.populateCache(request); + this.populateCache(http, request); } const { spaceId } = this.contextCache.get(request) as CacheEntry; @@ -76,7 +81,7 @@ export class SpacesService { }, isInDefaultSpace: (request: RequestFacade) => { if (!this.contextCache.has(request)) { - this.populateCache(request); + this.populateCache(http, request); } return this.contextCache.get(request)!.isInDefaultSpace; @@ -116,8 +121,8 @@ export class SpacesService { } } - private populateCache(request: RequestFacade) { - const spaceId = getSpaceIdFromPath(request.getBasePath(), this.serverBasePath); + private populateCache(http: HttpServiceSetup, request: RequestFacade) { + const spaceId = getSpaceIdFromPath(http.getBasePathFor(request), this.serverBasePath); this.contextCache.set(request, { spaceId, diff --git a/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_test_handler.ts b/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_test_handler.ts index d11f7fafc1d64..9f774c06f3584 100644 --- a/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_test_handler.ts +++ b/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_test_handler.ts @@ -7,8 +7,11 @@ import * as Rx from 'rxjs'; import { Server } from 'hapi'; import { Legacy } from 'kibana'; -import { ElasticsearchServiceSetup } from 'src/core/server'; import { KibanaConfig } from 'src/legacy/server/kbn_server'; +import { + httpServiceMock, + elasticsearchServiceMock, +} from '../../../../../../../src/core/server/mocks'; import { SecurityPlugin } from '../../../../../security'; import { SpacesClient } from '../../../lib/spaces_client'; import { createSpaces } from './create_spaces'; @@ -95,9 +98,6 @@ export function createTestHandler(initApiFn: (deps: PublicRouteDeps & PrivateRou server.decorate('server', 'config', jest.fn(() => mockConfig)); - server.decorate('request', 'getBasePath', jest.fn()); - server.decorate('request', 'setBasePath', jest.fn()); - const mockSavedObjectsRepository = { get: jest.fn((type, id) => { const result = spaces.filter(s => s.id === id); @@ -160,14 +160,8 @@ export function createTestHandler(initApiFn: (deps: PublicRouteDeps & PrivateRou const service = new SpacesService(log, server.config().get('server.basePath')); const spacesService = await service.setup({ - elasticsearch: ({ - adminClient$: Rx.of({ - callAsInternalUser: jest.fn(), - asScoped: jest.fn(req => ({ - callWithRequest: jest.fn(), - })), - }), - } as unknown) as ElasticsearchServiceSetup, + http: httpServiceMock.createSetupContract(), + elasticsearch: elasticsearchServiceMock.createSetupContract(), savedObjects: server.savedObjects, getSecurity: () => ({} as SecurityPlugin), spacesAuditLogger: {} as SpacesAuditLogger, diff --git a/x-pack/plugins/spaces/server/routes/api/public/index.ts b/x-pack/plugins/spaces/server/routes/api/public/index.ts index fcea02b7eaf88..83919d8b055a0 100644 --- a/x-pack/plugins/spaces/server/routes/api/public/index.ts +++ b/x-pack/plugins/spaces/server/routes/api/public/index.ts @@ -4,7 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Logger, Headers } from 'src/core/server'; +import { Legacy } from 'kibana'; +import { Logger } from 'src/core/server'; import { SavedObjectsService } from 'src/legacy/server/kbn_server'; import { XPackMainPlugin } from '../../../../../xpack_main/xpack_main'; import { routePreCheckLicense } from '../../../lib/route_pre_check_license'; @@ -29,12 +30,7 @@ export interface PublicRouteDeps extends Omit { routePreCheckLicenseFn: any; } -export interface PublicRouteRequestFacade { - headers?: Headers; - params: Record; - payload: Record; - getBasePath: () => string; -} +export type PublicRouteRequestFacade = Legacy.Request; export function initPublicSpacesApi({ xpackMain, ...rest }: RouteDeps) { const routePreCheckLicenseFn = routePreCheckLicense({ xpackMain }); diff --git a/x-pack/typings/index.d.ts b/x-pack/typings/index.d.ts index 0688ef9e4d8ec..69aa941f57074 100644 --- a/x-pack/typings/index.d.ts +++ b/x-pack/typings/index.d.ts @@ -9,3 +9,9 @@ declare module '*.html' { // eslint-disable-next-line import/no-default-export export default template; } + +type MethodKeysOf = { + [K in keyof T]: T[K] extends (...args: any[]) => any ? K : never +}[keyof T]; + +type PublicMethodsOf = Pick>; From f71a9b1cd49466e61444df5b62e20a61576a6a4b Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Thu, 9 May 2019 15:16:08 -0400 Subject: [PATCH 32/68] add explicit timeouts for jest interceptor tests --- .../on_request_interceptor.test.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.test.ts b/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.test.ts index 9c267fb79103e..9c63c6791dc49 100644 --- a/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.test.ts +++ b/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.test.ts @@ -110,7 +110,7 @@ describe('onRequestInterceptor', () => { path, basePath: '', // no base path set for route within the default space }); - }); + }, 10000); it('strips the Space URL Context from the request', async () => { const { http } = await root.setup(); @@ -132,7 +132,7 @@ describe('onRequestInterceptor', () => { path: '/foo', basePath: '/s/foo-space', }); - }); + }, 10000); it('ignores space identifiers in the middle of the path', async () => { const { http } = await root.setup(); @@ -154,7 +154,7 @@ describe('onRequestInterceptor', () => { path: '/some/path/s/foo/bar', basePath: '', // no base path set for route within the default space }); - }); + }, 10000); it('strips the Space URL Context from the request, maintaining the rest of the path', async () => { const { http } = await root.setup(); @@ -179,7 +179,7 @@ describe('onRequestInterceptor', () => { queryParam: 'queryValue', }, }); - }); + }, 10000); }); describe('requests handled completely in the new platform', () => { @@ -203,7 +203,7 @@ describe('onRequestInterceptor', () => { path, basePath: '', // no base path set for route within the default space }); - }); + }, 10000); it('strips the Space URL Context from the request', async () => { const { http } = await root.setup(); @@ -225,7 +225,7 @@ describe('onRequestInterceptor', () => { path: '/foo', basePath: '/s/foo-space', }); - }); + }, 10000); it('ignores space identifiers in the middle of the path', async () => { const { http } = await root.setup(); @@ -247,7 +247,7 @@ describe('onRequestInterceptor', () => { path: '/some/path/s/foo/bar', basePath: '', // no base path set for route within the default space }); - }); + }, 10000); it('strips the Space URL Context from the request, maintaining the rest of the path', async () => { const { http } = await root.setup(); @@ -272,6 +272,6 @@ describe('onRequestInterceptor', () => { queryParam: 'queryValue', }, }); - }); + }, 10000); }); }); From a3215709b32d535cb1648e801d80925e2b1b7832 Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Thu, 9 May 2019 15:16:32 -0400 Subject: [PATCH 33/68] attempt to fix imports --- .../server/routes/api/__fixtures__/create_test_handler.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_test_handler.ts b/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_test_handler.ts index 9f774c06f3584..a66bf71f61a48 100644 --- a/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_test_handler.ts +++ b/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_test_handler.ts @@ -8,10 +8,7 @@ import * as Rx from 'rxjs'; import { Server } from 'hapi'; import { Legacy } from 'kibana'; import { KibanaConfig } from 'src/legacy/server/kbn_server'; -import { - httpServiceMock, - elasticsearchServiceMock, -} from '../../../../../../../src/core/server/mocks'; +import { httpServiceMock, elasticsearchServiceMock } from 'src/core/server/mocks'; import { SecurityPlugin } from '../../../../../security'; import { SpacesClient } from '../../../lib/spaces_client'; import { createSpaces } from './create_spaces'; From cbd50bb5e99ecef82b412c928666a193aff70165 Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Mon, 20 May 2019 08:26:25 -0400 Subject: [PATCH 34/68] use NP logging instead of faked implementation --- x-pack/plugins/spaces/index.ts | 9 +-------- yarn.lock | 6 +++--- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/x-pack/plugins/spaces/index.ts b/x-pack/plugins/spaces/index.ts index 11150e098624b..e6708491c7342 100644 --- a/x-pack/plugins/spaces/index.ts +++ b/x-pack/plugins/spaces/index.ts @@ -119,14 +119,7 @@ export const spaces = (kibana: Record) => ); }, }, - logger: { - get: (context: string) => ({ - debug: (message: any) => server.log([context, 'debug'], message), - info: (message: any) => server.log([context, 'info'], message), - warning: (message: any) => server.log([context, 'warning'], message), - error: (message: any) => server.log([context, 'error'], message), - }), - }, + logger: kbnServer.newPlatform.coreContext.logger, } as unknown) as SpacesInitializerContext; const spacesHttpService: SpacesHttpServiceSetup = { diff --git a/yarn.lock b/yarn.lock index 2ecf502fa4698..ea83cfb132cea 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8457,9 +8457,9 @@ core-js@^2.5.3, core-js@^2.5.7: integrity sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw== core-js@^2.6.5: - version "2.6.5" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.5.tgz#44bc8d249e7fb2ff5d00e0341a7ffb94fbf67895" - integrity sha512-klh/kDpwX8hryYL14M9w/xei6vrv6sE8gTHDG7/T/+SEovB/G4ejwcfE/CBzO6Edsu+OETZMZ3wcX/EjUkrl5A== + version "2.6.6" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.6.tgz#00eb6d6bf815471cc16d8563edd7d38786dec50b" + integrity sha512-Mt/LaAym54NXnrjEMdo918cT2h70tqb/Yl7T3uPHQHRm5SxVoqlKmerUy4mL11k8saSBDWQ7ULIHxmeFyT3pfg== core-util-is@1.0.2, core-util-is@~1.0.0: version "1.0.2" From 6b0bb66c3c112d04803200483d2845b21bf2d142 Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Mon, 20 May 2019 10:40:11 -0400 Subject: [PATCH 35/68] revert stray yarn.lock change --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index ea83cfb132cea..2ecf502fa4698 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8457,9 +8457,9 @@ core-js@^2.5.3, core-js@^2.5.7: integrity sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw== core-js@^2.6.5: - version "2.6.6" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.6.tgz#00eb6d6bf815471cc16d8563edd7d38786dec50b" - integrity sha512-Mt/LaAym54NXnrjEMdo918cT2h70tqb/Yl7T3uPHQHRm5SxVoqlKmerUy4mL11k8saSBDWQ7ULIHxmeFyT3pfg== + version "2.6.5" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.5.tgz#44bc8d249e7fb2ff5d00e0341a7ffb94fbf67895" + integrity sha512-klh/kDpwX8hryYL14M9w/xei6vrv6sE8gTHDG7/T/+SEovB/G4ejwcfE/CBzO6Edsu+OETZMZ3wcX/EjUkrl5A== core-util-is@1.0.2, core-util-is@~1.0.0: version "1.0.2" From 3d84577c9fd82940290d3633243bc074974fd508 Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Mon, 20 May 2019 16:57:30 -0400 Subject: [PATCH 36/68] attempt to stablize and fix tests --- .../on_request_interceptor.test.ts | 16 ++++++++-------- .../api/__fixtures__/create_test_handler.ts | 5 ++++- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.test.ts b/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.test.ts index 9c63c6791dc49..31a35aa4fd682 100644 --- a/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.test.ts +++ b/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.test.ts @@ -110,7 +110,7 @@ describe('onRequestInterceptor', () => { path, basePath: '', // no base path set for route within the default space }); - }, 10000); + }, 30000); it('strips the Space URL Context from the request', async () => { const { http } = await root.setup(); @@ -132,7 +132,7 @@ describe('onRequestInterceptor', () => { path: '/foo', basePath: '/s/foo-space', }); - }, 10000); + }, 30000); it('ignores space identifiers in the middle of the path', async () => { const { http } = await root.setup(); @@ -154,7 +154,7 @@ describe('onRequestInterceptor', () => { path: '/some/path/s/foo/bar', basePath: '', // no base path set for route within the default space }); - }, 10000); + }, 30000); it('strips the Space URL Context from the request, maintaining the rest of the path', async () => { const { http } = await root.setup(); @@ -179,7 +179,7 @@ describe('onRequestInterceptor', () => { queryParam: 'queryValue', }, }); - }, 10000); + }, 30000); }); describe('requests handled completely in the new platform', () => { @@ -203,7 +203,7 @@ describe('onRequestInterceptor', () => { path, basePath: '', // no base path set for route within the default space }); - }, 10000); + }, 30000); it('strips the Space URL Context from the request', async () => { const { http } = await root.setup(); @@ -225,7 +225,7 @@ describe('onRequestInterceptor', () => { path: '/foo', basePath: '/s/foo-space', }); - }, 10000); + }, 30000); it('ignores space identifiers in the middle of the path', async () => { const { http } = await root.setup(); @@ -247,7 +247,7 @@ describe('onRequestInterceptor', () => { path: '/some/path/s/foo/bar', basePath: '', // no base path set for route within the default space }); - }, 10000); + }, 30000); it('strips the Space URL Context from the request, maintaining the rest of the path', async () => { const { http } = await root.setup(); @@ -272,6 +272,6 @@ describe('onRequestInterceptor', () => { queryParam: 'queryValue', }, }); - }, 10000); + }, 30000); }); }); diff --git a/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_test_handler.ts b/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_test_handler.ts index a66bf71f61a48..9f774c06f3584 100644 --- a/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_test_handler.ts +++ b/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_test_handler.ts @@ -8,7 +8,10 @@ import * as Rx from 'rxjs'; import { Server } from 'hapi'; import { Legacy } from 'kibana'; import { KibanaConfig } from 'src/legacy/server/kbn_server'; -import { httpServiceMock, elasticsearchServiceMock } from 'src/core/server/mocks'; +import { + httpServiceMock, + elasticsearchServiceMock, +} from '../../../../../../../src/core/server/mocks'; import { SecurityPlugin } from '../../../../../security'; import { SpacesClient } from '../../../lib/spaces_client'; import { createSpaces } from './create_spaces'; From c6742b3baaf1f358e84cbbd9dfe991ba3787006a Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Tue, 21 May 2019 12:58:21 -0400 Subject: [PATCH 37/68] update jest config to include src/core/server/mocks --- x-pack/dev-tools/jest/create_jest_config.js | 1 + .../server/routes/api/__fixtures__/create_test_handler.ts | 5 +---- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/x-pack/dev-tools/jest/create_jest_config.js b/x-pack/dev-tools/jest/create_jest_config.js index ad5b2fde1acfe..f8b94987dbff8 100644 --- a/x-pack/dev-tools/jest/create_jest_config.js +++ b/x-pack/dev-tools/jest/create_jest_config.js @@ -22,6 +22,7 @@ export function createJestConfig({ ], moduleNameMapper: { '^ui/(.*)': `${kibanaDirectory}/src/legacy/ui/public/$1`, + '^src/core/(.*)': `${kibanaDirectory}/src/core/$1`, '^plugins/xpack_main/(.*);': `${xPackKibanaDirectory}/plugins/xpack_main/public/$1`, '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': `${kibanaDirectory}/src/dev/jest/mocks/file_mock.js`, diff --git a/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_test_handler.ts b/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_test_handler.ts index 9f774c06f3584..a66bf71f61a48 100644 --- a/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_test_handler.ts +++ b/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_test_handler.ts @@ -8,10 +8,7 @@ import * as Rx from 'rxjs'; import { Server } from 'hapi'; import { Legacy } from 'kibana'; import { KibanaConfig } from 'src/legacy/server/kbn_server'; -import { - httpServiceMock, - elasticsearchServiceMock, -} from '../../../../../../../src/core/server/mocks'; +import { httpServiceMock, elasticsearchServiceMock } from 'src/core/server/mocks'; import { SecurityPlugin } from '../../../../../security'; import { SpacesClient } from '../../../lib/spaces_client'; import { createSpaces } from './create_spaces'; From 0d9b275649ed7b47eaa6fdb3eeb75e3f918261a1 Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Tue, 21 May 2019 13:54:10 -0400 Subject: [PATCH 38/68] fix plugin config typings --- x-pack/plugins/spaces/index.ts | 4 ++-- x-pack/plugins/spaces/server/new_platform/plugin.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/spaces/index.ts b/x-pack/plugins/spaces/index.ts index e6708491c7342..e357d217e3ba4 100644 --- a/x-pack/plugins/spaces/index.ts +++ b/x-pack/plugins/spaces/index.ts @@ -111,9 +111,9 @@ export const spaces = (kibana: Record) => const initializerContext = ({ legacyConfig: server.config(), config: { - create: (ConfigClass: typeof SpacesConfig) => { + create: () => { return Rx.of( - new ConfigClass({ + new SpacesConfig({ maxSpaces: server.config().get('xpack.spaces.maxSpaces'), }) ); diff --git a/x-pack/plugins/spaces/server/new_platform/plugin.ts b/x-pack/plugins/spaces/server/new_platform/plugin.ts index 29525f4681687..999ba8ed1eef5 100644 --- a/x-pack/plugins/spaces/server/new_platform/plugin.ts +++ b/x-pack/plugins/spaces/server/new_platform/plugin.ts @@ -83,7 +83,7 @@ export class Plugin { private log: Logger; constructor(private readonly initializerContext: SpacesInitializerContext) { - this.config$ = initializerContext.config.create(SpacesConfig); + this.config$ = initializerContext.config.create(); this.log = initializerContext.logger.get('spaces'); } From 885764d579643c9607330e743c91d6531e06cc0b Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Tue, 21 May 2019 14:34:30 -0400 Subject: [PATCH 39/68] add service tests --- .../spaces_service/spaces_service.test.ts | 97 +++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.test.ts diff --git a/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.test.ts b/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.test.ts new file mode 100644 index 0000000000000..8ed102d9a50a1 --- /dev/null +++ b/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.test.ts @@ -0,0 +1,97 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import * as Rx from 'rxjs'; +import { SpacesService } from './spaces_service'; +import { httpServiceMock, elasticsearchServiceMock } from 'src/core/server/mocks'; +import { SpacesAuditLogger } from '../../lib/audit_logger'; +import { SpacesConfig } from '../config'; +import { SavedObjectsService } from 'src/legacy/server/kbn_server'; +import { KibanaRequest } from 'src/core/server'; +import { DEFAULT_SPACE_ID } from '../../../common/constants'; +import { getSpaceIdFromPath } from '../../lib/spaces_url_parser'; + +const mockLogger = { + trace: jest.fn(), + debug: jest.fn(), + info: jest.fn(), + warn: jest.fn(), + error: jest.fn(), + fatal: jest.fn(), + log: jest.fn(), +}; + +const createService = async () => { + const spacesService = new SpacesService(mockLogger, '/base-path'); + + const httpSetup = httpServiceMock.createSetupContract(); + httpSetup.getBasePathFor = jest.fn().mockImplementation((request: KibanaRequest) => { + const spaceId = getSpaceIdFromPath(request.path); + + if (spaceId !== DEFAULT_SPACE_ID) { + return `/s/${spaceId}`; + } + return '/'; + }); + + const spacesServiceSetup = await spacesService.setup({ + http: httpSetup, + elasticsearch: elasticsearchServiceMock.createSetupContract(), + config$: Rx.of(new SpacesConfig({ maxSpaces: 10 })), + getSecurity: () => undefined, + savedObjects: ({ + getSavedObjectsRepository: jest.fn().mockReturnValue(null), + } as unknown) as SavedObjectsService, + spacesAuditLogger: new SpacesAuditLogger({}), + }); + + return spacesServiceSetup; +}; + +describe('SpacesService', () => { + describe('#getSpaceId', () => { + it('returns the default space id when no identifier is present', async () => { + const spacesServiceSetup = await createService(); + + const request: KibanaRequest = { + path: '/app/kibana', + } as KibanaRequest; + + expect(spacesServiceSetup.getSpaceId(request)).toEqual(DEFAULT_SPACE_ID); + }); + + it('returns the space id when identifier is present', async () => { + const spacesServiceSetup = await createService(); + + const request: KibanaRequest = { + path: '/s/foo/app/kibana', + } as KibanaRequest; + + expect(spacesServiceSetup.getSpaceId(request)).toEqual('foo'); + }); + }); + + describe('#isInDefaultSpace', () => { + it('returns true when in the default space', async () => { + const spacesServiceSetup = await createService(); + + const request: KibanaRequest = { + path: '/app/kibana', + } as KibanaRequest; + + expect(spacesServiceSetup.isInDefaultSpace(request)).toEqual(true); + }); + + it('returns false when not in the default space', async () => { + const spacesServiceSetup = await createService(); + + const request: KibanaRequest = { + path: '/s/foo/app/kibana', + } as KibanaRequest; + + expect(spacesServiceSetup.isInDefaultSpace(request)).toEqual(false); + }); + }); +}); From 52e21e732a6c1335874220f84f02f012d3f86272 Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Wed, 22 May 2019 18:26:17 -0400 Subject: [PATCH 40/68] fix merge --- .../server/routes/api/__fixtures__/create_test_handler.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_test_handler.ts b/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_test_handler.ts index a66bf71f61a48..e09de4cd663e0 100644 --- a/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_test_handler.ts +++ b/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_test_handler.ts @@ -12,7 +12,7 @@ import { httpServiceMock, elasticsearchServiceMock } from 'src/core/server/mocks import { SecurityPlugin } from '../../../../../security'; import { SpacesClient } from '../../../lib/spaces_client'; import { createSpaces } from './create_spaces'; -import { PublicRouteDeps } from '../public'; +import { PublicRouteDeps } from '../external'; import { SpacesService } from '../../../new_platform/spaces_service'; import { SpacesAuditLogger } from '../../../lib/audit_logger'; import { PrivateRouteDeps } from '../v1'; From 330c316644b7be897106154fef3ef244942b7fb7 Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Wed, 22 May 2019 19:53:53 -0400 Subject: [PATCH 41/68] allow spaces service to also work with legacy requests --- .../server/new_platform/spaces_service/spaces_service.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts b/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts index d3266b188b59e..88ae10365b38f 100644 --- a/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts +++ b/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts @@ -122,7 +122,13 @@ export class SpacesService { } private populateCache(http: HttpServiceSetup, request: RequestFacade) { - const spaceId = getSpaceIdFromPath(http.getBasePathFor(request), this.serverBasePath); + const isLegacyRequest = typeof (request as any).getBasePath === 'function'; + + const basePath = isLegacyRequest + ? (request as Record).getBasePath() + : http.getBasePathFor(request); + + const spaceId = getSpaceIdFromPath(basePath, this.serverBasePath); this.contextCache.set(request, { spaceId, From 26163af4b75fbb1200cce7e96c7dd6a9bf11cbd6 Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Thu, 23 May 2019 06:22:20 -0400 Subject: [PATCH 42/68] update interfaces to confirm to new internal/external API convention --- x-pack/plugins/spaces/server/new_platform/plugin.ts | 4 ++-- .../server/routes/api/__fixtures__/create_test_handler.ts | 8 +++++--- .../plugins/spaces/server/routes/api/external/delete.ts | 6 +++--- x-pack/plugins/spaces/server/routes/api/external/get.ts | 8 ++++---- x-pack/plugins/spaces/server/routes/api/external/index.ts | 6 +++--- x-pack/plugins/spaces/server/routes/api/external/post.ts | 6 +++--- x-pack/plugins/spaces/server/routes/api/external/put.ts | 6 +++--- x-pack/plugins/spaces/server/routes/api/v1/index.ts | 6 +++--- x-pack/plugins/spaces/server/routes/api/v1/spaces.ts | 4 ++-- 9 files changed, 28 insertions(+), 26 deletions(-) diff --git a/x-pack/plugins/spaces/server/new_platform/plugin.ts b/x-pack/plugins/spaces/server/new_platform/plugin.ts index ff36485591e01..9359df9d38649 100644 --- a/x-pack/plugins/spaces/server/new_platform/plugin.ts +++ b/x-pack/plugins/spaces/server/new_platform/plugin.ts @@ -25,7 +25,7 @@ import { checkLicense } from '../lib/check_license'; import { spacesSavedObjectsClientWrapperFactory } from '../lib/saved_objects_client/saved_objects_client_wrapper_factory'; import { SpacesAuditLogger } from '../lib/audit_logger'; import { createSpacesTutorialContextFactory } from '../lib/spaces_tutorial_context_factory'; -import { initPrivateApis } from '../routes/api/v1'; +import { initInternalApis } from '../routes/api/v1'; import { initExternalSpacesApi } from '../routes/api/external'; import { getSpacesUsageCollector } from '../lib/get_spaces_usage_collector'; import { SpacesService } from './spaces_service'; @@ -148,7 +148,7 @@ export class Plugin { } }); - initPrivateApis({ + initInternalApis({ http: core.http, config: this.initializerContext.legacyConfig, savedObjects: core.savedObjects, diff --git a/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_test_handler.ts b/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_test_handler.ts index e09de4cd663e0..4a06506de6ac3 100644 --- a/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_test_handler.ts +++ b/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_test_handler.ts @@ -12,10 +12,10 @@ import { httpServiceMock, elasticsearchServiceMock } from 'src/core/server/mocks import { SecurityPlugin } from '../../../../../security'; import { SpacesClient } from '../../../lib/spaces_client'; import { createSpaces } from './create_spaces'; -import { PublicRouteDeps } from '../external'; +import { ExternalRouteDeps } from '../external'; import { SpacesService } from '../../../new_platform/spaces_service'; import { SpacesAuditLogger } from '../../../lib/audit_logger'; -import { PrivateRouteDeps } from '../v1'; +import { InternalRouteDeps } from '../v1'; import { SpacesHttpServiceSetup } from '../../../new_platform/plugin'; import { SpacesConfig } from '../../../new_platform/config'; @@ -55,7 +55,9 @@ const baseConfig: TestConfig = { 'server.basePath': '', }; -export function createTestHandler(initApiFn: (deps: PublicRouteDeps & PrivateRouteDeps) => void) { +export function createTestHandler( + initApiFn: (deps: ExternalRouteDeps & InternalRouteDeps) => void +) { const teardowns: TeardownFn[] = []; const spaces = createSpaces(); diff --git a/x-pack/plugins/spaces/server/routes/api/external/delete.ts b/x-pack/plugins/spaces/server/routes/api/external/delete.ts index 42a01e13199cd..56c45563588a9 100644 --- a/x-pack/plugins/spaces/server/routes/api/external/delete.ts +++ b/x-pack/plugins/spaces/server/routes/api/external/delete.ts @@ -7,15 +7,15 @@ import Boom from 'boom'; import { wrapError } from '../../../lib/errors'; import { SpacesClient } from '../../../lib/spaces_client'; -import { PublicRouteDeps, PublicRouteRequestFacade } from '.'; +import { ExternalRouteDeps, ExternalRouteRequestFacade } from '.'; -export function initDeleteSpacesApi(deps: PublicRouteDeps) { +export function initDeleteSpacesApi(deps: ExternalRouteDeps) { const { http, savedObjects, spacesService, routePreCheckLicenseFn } = deps; http.route({ method: 'DELETE', path: '/api/spaces/space/{id}', - async handler(request: PublicRouteRequestFacade, h: any) { + async handler(request: ExternalRouteRequestFacade, h: any) { const { SavedObjectsClient } = savedObjects; const spacesClient: SpacesClient = spacesService.scopedClient(request); diff --git a/x-pack/plugins/spaces/server/routes/api/external/get.ts b/x-pack/plugins/spaces/server/routes/api/external/get.ts index 566e2826710fe..6d10b59fa97d6 100644 --- a/x-pack/plugins/spaces/server/routes/api/external/get.ts +++ b/x-pack/plugins/spaces/server/routes/api/external/get.ts @@ -8,15 +8,15 @@ import Boom from 'boom'; import { Space } from '../../../../common/model/space'; import { wrapError } from '../../../lib/errors'; import { SpacesClient } from '../../../lib/spaces_client'; -import { PublicRouteDeps, PublicRouteRequestFacade } from '.'; +import { ExternalRouteDeps, ExternalRouteRequestFacade } from '.'; -export function initGetSpacesApi(deps: PublicRouteDeps) { +export function initGetSpacesApi(deps: ExternalRouteDeps) { const { http, log, spacesService, savedObjects, routePreCheckLicenseFn } = deps; http.route({ method: 'GET', path: '/api/spaces/space', - async handler(request: PublicRouteRequestFacade) { + async handler(request: ExternalRouteRequestFacade) { log.debug(`Inside GET /api/spaces/space`); const spacesClient: SpacesClient = spacesService.scopedClient(request); @@ -42,7 +42,7 @@ export function initGetSpacesApi(deps: PublicRouteDeps) { http.route({ method: 'GET', path: '/api/spaces/space/{id}', - async handler(request: PublicRouteRequestFacade) { + async handler(request: ExternalRouteRequestFacade) { const spaceId = request.params.id; const { SavedObjectsClient } = savedObjects; diff --git a/x-pack/plugins/spaces/server/routes/api/external/index.ts b/x-pack/plugins/spaces/server/routes/api/external/index.ts index 590e6e30ed5c1..14ae6d5df2787 100644 --- a/x-pack/plugins/spaces/server/routes/api/external/index.ts +++ b/x-pack/plugins/spaces/server/routes/api/external/index.ts @@ -26,16 +26,16 @@ interface RouteDeps { log: Logger; } -export interface PublicRouteDeps extends Omit { +export interface ExternalRouteDeps extends Omit { routePreCheckLicenseFn: any; } -export type PublicRouteRequestFacade = Legacy.Request; +export type ExternalRouteRequestFacade = Legacy.Request; export function initExternalSpacesApi({ xpackMain, ...rest }: RouteDeps) { const routePreCheckLicenseFn = routePreCheckLicense({ xpackMain }); - const deps: PublicRouteDeps = { + const deps: ExternalRouteDeps = { ...rest, routePreCheckLicenseFn, }; diff --git a/x-pack/plugins/spaces/server/routes/api/external/post.ts b/x-pack/plugins/spaces/server/routes/api/external/post.ts index 3d432455e0010..fd76297e27f60 100644 --- a/x-pack/plugins/spaces/server/routes/api/external/post.ts +++ b/x-pack/plugins/spaces/server/routes/api/external/post.ts @@ -9,15 +9,15 @@ import { Space } from '../../../../common/model/space'; import { wrapError } from '../../../lib/errors'; import { spaceSchema } from '../../../lib/space_schema'; import { SpacesClient } from '../../../lib/spaces_client'; -import { PublicRouteDeps, PublicRouteRequestFacade } from '.'; +import { ExternalRouteDeps, ExternalRouteRequestFacade } from '.'; -export function initPostSpacesApi(deps: PublicRouteDeps) { +export function initPostSpacesApi(deps: ExternalRouteDeps) { const { http, log, spacesService, savedObjects, routePreCheckLicenseFn } = deps; http.route({ method: 'POST', path: '/api/spaces/space', - async handler(request: PublicRouteRequestFacade) { + async handler(request: ExternalRouteRequestFacade) { log.debug(`Inside POST /api/spaces/space`); const { SavedObjectsClient } = savedObjects; const spacesClient: SpacesClient = spacesService.scopedClient(request); diff --git a/x-pack/plugins/spaces/server/routes/api/external/put.ts b/x-pack/plugins/spaces/server/routes/api/external/put.ts index f52f62e66d1ee..455de78a2a57c 100644 --- a/x-pack/plugins/spaces/server/routes/api/external/put.ts +++ b/x-pack/plugins/spaces/server/routes/api/external/put.ts @@ -9,15 +9,15 @@ import { Space } from '../../../../common/model/space'; import { wrapError } from '../../../lib/errors'; import { spaceSchema } from '../../../lib/space_schema'; import { SpacesClient } from '../../../lib/spaces_client'; -import { PublicRouteDeps, PublicRouteRequestFacade } from '.'; +import { ExternalRouteDeps, ExternalRouteRequestFacade } from '.'; -export function initPutSpacesApi(deps: PublicRouteDeps) { +export function initPutSpacesApi(deps: ExternalRouteDeps) { const { http, spacesService, savedObjects, routePreCheckLicenseFn } = deps; http.route({ method: 'PUT', path: '/api/spaces/space/{id}', - async handler(request: PublicRouteRequestFacade) { + async handler(request: ExternalRouteRequestFacade) { const { SavedObjectsClient } = savedObjects; const spacesClient: SpacesClient = spacesService.scopedClient(request); diff --git a/x-pack/plugins/spaces/server/routes/api/v1/index.ts b/x-pack/plugins/spaces/server/routes/api/v1/index.ts index e2e9d224625e0..464043606494c 100644 --- a/x-pack/plugins/spaces/server/routes/api/v1/index.ts +++ b/x-pack/plugins/spaces/server/routes/api/v1/index.ts @@ -21,14 +21,14 @@ interface RouteDeps { config: KibanaConfig; } -export interface PrivateRouteDeps extends Omit { +export interface InternalRouteDeps extends Omit { routePreCheckLicenseFn: any; } -export function initPrivateApis({ xpackMain, ...rest }: RouteDeps) { +export function initInternalApis({ xpackMain, ...rest }: RouteDeps) { const routePreCheckLicenseFn = routePreCheckLicense({ xpackMain }); - const deps: PrivateRouteDeps = { + const deps: InternalRouteDeps = { ...rest, routePreCheckLicenseFn, }; diff --git a/x-pack/plugins/spaces/server/routes/api/v1/spaces.ts b/x-pack/plugins/spaces/server/routes/api/v1/spaces.ts index 58604839e0d8b..2ef2976abf5b2 100644 --- a/x-pack/plugins/spaces/server/routes/api/v1/spaces.ts +++ b/x-pack/plugins/spaces/server/routes/api/v1/spaces.ts @@ -10,9 +10,9 @@ import { wrapError } from '../../../lib/errors'; import { SpacesClient } from '../../../lib/spaces_client'; import { addSpaceIdToPath } from '../../../lib/spaces_url_parser'; import { getSpaceById } from '../../lib'; -import { PrivateRouteDeps } from '.'; +import { InternalRouteDeps } from '.'; -export function initInternalSpacesApi(deps: PrivateRouteDeps) { +export function initInternalSpacesApi(deps: InternalRouteDeps) { const { http, config, spacesService, savedObjects, routePreCheckLicenseFn } = deps; http.route({ From 6f0ed6871dec473d97ac351bde5ac0c8006bc96e Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Thu, 23 May 2019 08:19:33 -0400 Subject: [PATCH 43/68] re-enable some post auth interceptor tests --- .../on_post_auth_interceptor.test.ts | 169 ++++++++++-------- 1 file changed, 95 insertions(+), 74 deletions(-) diff --git a/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts b/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts index 7630bf63b5c09..2083b6c4b84de 100644 --- a/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts +++ b/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts @@ -4,10 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Server } from 'hapi'; -import sinon from 'sinon'; import * as Rx from 'rxjs'; -import { SavedObject } from 'src/legacy/server/saved_objects'; +import { SavedObject, SavedObjectsService } from 'src/legacy/server/saved_objects'; import { Feature } from '../../../../xpack_main/types'; import { convertSavedObjectToSpace } from '../../routes/lib'; import { initSpacesOnPostAuthRequestInterceptor } from './on_post_auth_interceptor'; @@ -18,29 +16,74 @@ import { SpacesAuditLogger } from '../audit_logger'; import { SpacesServiceSetup } from '../../new_platform/spaces_service/spaces_service'; import { elasticsearchServiceMock, httpServiceMock } from '../../../../../../src/core/server/mocks'; import { SpacesConfig } from '../../new_platform/config'; +import * as kbnTestServer from '../../../../../../src/test_utils/kbn_server'; +import { HttpServiceSetup } from 'src/core/server'; +import { KibanaConfig, Server } from 'src/legacy/server/kbn_server'; +import { XPackMainPlugin } from '../../../../xpack_main/xpack_main'; // TODO: re-implement on NP -describe.skip('onPostAuthRequestInterceptor', () => { - const sandbox = sinon.sandbox.create(); - const teardowns: Array<() => void> = []; +describe('onPostAuthRequestInterceptor', () => { const headers = { authorization: 'foo', }; - let server: any; let request: any; let spacesService: SpacesServiceSetup; const serverBasePath = '/'; const defaultRoute = '/app/custom-app'; + let root: ReturnType; + + function initKbnServer(http: HttpServiceSetup) { + const kbnServer = kbnTestServer.getKbnServer(root); + + kbnServer.server.route([ + { + method: 'GET', + path: '/foo', + handler: (req: any) => { + return { path: req.path, basePath: http.getBasePathFor(req) }; + }, + }, + { + method: 'GET', + path: '/app/kibana', + handler: (req: any) => { + return { path: req.path, basePath: http.getBasePathFor(req) }; + }, + }, + { + method: 'GET', + path: '/app/app-1', + handler: (req: any) => { + return { path: req.path, basePath: http.getBasePathFor(req) }; + }, + }, + { + method: 'GET', + path: '/app/app-2', + handler: (req: any) => { + return { path: req.path, basePath: http.getBasePathFor(req) }; + }, + }, + { + method: 'GET', + path: '/api/test/foo', + handler: (req: any) => { + return { path: req.path, basePath: http.getBasePathFor(req) }; + }, + }, + ]); + } + beforeEach(() => { - teardowns.push(() => sandbox.restore()); + root = kbnTestServer.createRoot(); request = async ( path: string, spaces: SavedObject[], setupFn: (server: Server) => null = () => null ) => { - server = new Server(); + const { http } = await root.setup(); interface Config { [key: string]: any; @@ -50,19 +93,15 @@ describe.skip('onPostAuthRequestInterceptor', () => { 'server.defaultRoute': defaultRoute, }; - server.decorate( - 'server', - 'config', - jest.fn(() => { - return { - get: jest.fn(key => { - return config[key]; - }), - }; - }) - ); + const configFn = jest.fn(() => { + return { + get: jest.fn(key => { + return config[key]; + }), + }; + }); - server.savedObjects = { + const savedObjectsService = { SavedObjectsClient: { errors: { isNotFoundError: (e: Error) => e.message === 'space not found', @@ -84,7 +123,7 @@ describe.skip('onPostAuthRequestInterceptor', () => { }), }; - server.plugins = { + const plugins = { elasticsearch: { getCluster: jest.fn().mockReturnValue({ callWithInternalUser: jest.fn(), @@ -137,16 +176,27 @@ describe.skip('onPostAuthRequestInterceptor', () => { const httpMock = httpServiceMock.createSetupContract(); - httpMock.getBasePathFor = jest.fn().mockReturnValue(basePath); - httpMock.setBasePathFor = jest.fn().mockImplementation((newPath: string) => { + httpMock.getBasePathFor = jest.fn().mockImplementation(() => basePath); + httpMock.setBasePathFor = jest.fn().mockImplementation((req: any, newPath: string) => { basePath = newPath; }); + httpMock.registerOnRequest = jest.fn().mockImplementation(async handler => { + await handler( + { path }, + { + setUrl: jest.fn().mockImplementation(url => { + path = url; + }), + next: jest.fn(), + } + ); + }); - const service = new SpacesService(log, server.config()); + const service = new SpacesService(log, configFn().get('server.basePath')); spacesService = await service.setup({ http: httpMock, elasticsearch: elasticsearchServiceMock.createSetupContract(), - savedObjects: server.savedObjects, + savedObjects: (savedObjectsService as unknown) as SavedObjectsService, getSecurity: () => ({} as SecurityPlugin), spacesAuditLogger: {} as SpacesAuditLogger, config$: Rx.of(new SpacesConfig({ maxSpaces: 1000 })), @@ -169,57 +219,28 @@ describe.skip('onPostAuthRequestInterceptor', () => { // interceptor to parse out the space id and rewrite the request's URL. Rather than duplicating that logic, // we are including the already tested interceptor here in the test chain. initSpacesOnRequestInterceptor({ - config: server.config(), + config: (configFn() as unknown) as KibanaConfig, http: httpMock, }); + + await root.start(); + initSpacesOnPostAuthRequestInterceptor({ - config: server.config(), - legacyServer: server, + config: (configFn() as unknown) as KibanaConfig, + legacyServer: kbnTestServer.getKbnServer(root).server, http: httpMock, log, - xpackMain: server.plugins.xpack_main, + xpackMain: plugins.xpack_main as XPackMainPlugin, spacesService, }); - server.route([ - { - method: 'GET', - path: '/', - handler: (req: any) => { - return { path: req.path, url: req.url, basePath: httpMock.getBasePathFor(req) }; - }, - }, - { - method: 'GET', - path: '/app/{appId}', - handler: (req: any) => { - return { path: req.path, url: req.url, basePath: httpMock.getBasePathFor(req) }; - }, - }, - { - method: 'GET', - path: '/api/foo', - handler: (req: any) => { - return { path: req.path, url: req.url, basePath: httpMock.getBasePathFor(req) }; - }, - }, - ]); + initKbnServer(http); - teardowns.push(() => server.stop()); - - await setupFn(server); - - return await server.inject({ - method: 'GET', - url: path, - headers, - }); + return await kbnTestServer.request.get(root, path); }; - }); + }, 30000); - afterEach(async () => { - await Promise.all(teardowns.splice(0).map(fn => fn())); - }); + afterEach(async () => await root.shutdown()); describe('when accessing an app within a non-existent space', () => { it('redirects to the space selector screen', async () => { @@ -269,13 +290,13 @@ describe.skip('onPostAuthRequestInterceptor', () => { }, ]; - const response = await request('/s/not-found/api/foo', spaces); + const response = await request('/s/not-found/api/test/foo', spaces); expect(response.statusCode).toEqual(200); }); }); - describe('with a single available space', () => { + describe.skip('with a single available space', () => { test('it redirects to the defaultRoute within the context of the single Space when navigating to Kibana root', async () => { const spaces = [ { @@ -405,7 +426,7 @@ describe.skip('onPostAuthRequestInterceptor', () => { }); }); - describe('with multiple available spaces', () => { + describe.skip('with multiple available spaces', () => { test('it redirects to the Space Selector App when navigating to Kibana root', async () => { const spaces = [ { @@ -427,11 +448,11 @@ describe.skip('onPostAuthRequestInterceptor', () => { const getHiddenUiAppHandler = jest.fn(() => '
space selector
'); const response = await request('/', spaces, function setupFn() { - server.decorate('server', 'getHiddenUiAppById', getHiddenUiAppHandler); - server.decorate('toolkit', 'renderApp', function renderAppHandler(app: any) { - // @ts-ignore - return this.response(app); - }); + // server.decorate('server', 'getHiddenUiAppById', getHiddenUiAppHandler); + // server.decorate('toolkit', 'renderApp', function renderAppHandler(app: any) { + // // @ts-ignore + // return this.response(app); + // }); }); expect(response.statusCode).toEqual(200); From 276239ae163f1858f752c972d8591622207d621f Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Thu, 23 May 2019 09:49:57 -0400 Subject: [PATCH 44/68] add explicit timeouts for tests --- .../request_interceptors/on_post_auth_interceptor.test.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts b/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts index 2083b6c4b84de..7b9439bfee6dd 100644 --- a/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts +++ b/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts @@ -258,7 +258,7 @@ describe('onPostAuthRequestInterceptor', () => { expect(response.statusCode).toEqual(302); expect(response.headers.location).toEqual(serverBasePath); - }); + }, 30000); }); it('when accessing the kibana app it always allows the request to continue', async () => { @@ -276,7 +276,7 @@ describe('onPostAuthRequestInterceptor', () => { const response = await request('/s/a-space/app/kibana', spaces); expect(response.statusCode).toEqual(200); - }); + }, 30000); describe('when accessing an API endpoint within a non-existent space', () => { it('allows the request to continue', async () => { @@ -293,7 +293,7 @@ describe('onPostAuthRequestInterceptor', () => { const response = await request('/s/not-found/api/test/foo', spaces); expect(response.statusCode).toEqual(200); - }); + }, 30000); }); describe.skip('with a single available space', () => { From 12417a27b0d35cd2f9588fee4fd1b4877264b9c6 Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Tue, 28 May 2019 14:14:15 -0400 Subject: [PATCH 45/68] prefer modifyUrl instead of manual url modification --- src/core/server/http/lifecycle/on_request.ts | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/core/server/http/lifecycle/on_request.ts b/src/core/server/http/lifecycle/on_request.ts index e36524008a448..36d57b0792ad0 100644 --- a/src/core/server/http/lifecycle/on_request.ts +++ b/src/core/server/http/lifecycle/on_request.ts @@ -17,9 +17,10 @@ * under the License. */ -import { Url } from 'url'; +import { Url, format } from 'url'; import Boom from 'boom'; import { Lifecycle, Request, ResponseToolkit } from 'hapi'; +import { modifyUrl } from '../../../utils'; import { KibanaRequest } from '../router'; enum ResultType { @@ -93,12 +94,14 @@ export function adoptToHapiOnRequestFormat(fn: OnRequestHandler) { rejected: OnRequestResult.rejected, setUrl: (newUrl: string | Url) => { if (typeof newUrl === 'string') { - request.setUrl({ - ...request.url, - pathname: newUrl, - path: newUrl, - href: newUrl, + const originalUrl = format(request.url); + const modifiedUrl = modifyUrl(originalUrl, parts => { + return { + ...parts, + pathname: newUrl, + }; }); + request.setUrl(modifiedUrl); } else { request.setUrl(newUrl); } From 256bb55ac035ab2a94a1ba93f4614b2784afeaca Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Tue, 28 May 2019 14:40:18 -0400 Subject: [PATCH 46/68] update logger shim to conform to PluginInitializerContext --- x-pack/plugins/spaces/index.ts | 10 +++++++++- x-pack/plugins/spaces/server/new_platform/plugin.ts | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/spaces/index.ts b/x-pack/plugins/spaces/index.ts index e357d217e3ba4..9b4921b26665d 100644 --- a/x-pack/plugins/spaces/index.ts +++ b/x-pack/plugins/spaces/index.ts @@ -119,7 +119,15 @@ export const spaces = (kibana: Record) => ); }, }, - logger: kbnServer.newPlatform.coreContext.logger, + logger: { + get(...contextParts: string[]) { + return kbnServer.newPlatform.coreContext.logger.get( + 'plugins', + 'spaces', + ...contextParts + ); + }, + }, } as unknown) as SpacesInitializerContext; const spacesHttpService: SpacesHttpServiceSetup = { diff --git a/x-pack/plugins/spaces/server/new_platform/plugin.ts b/x-pack/plugins/spaces/server/new_platform/plugin.ts index 9359df9d38649..8a8fbcd634942 100644 --- a/x-pack/plugins/spaces/server/new_platform/plugin.ts +++ b/x-pack/plugins/spaces/server/new_platform/plugin.ts @@ -84,7 +84,7 @@ export class Plugin { constructor(private readonly initializerContext: SpacesInitializerContext) { this.config$ = initializerContext.config.create(); - this.log = initializerContext.logger.get('spaces'); + this.log = initializerContext.logger.get(); } public async setup(core: SpacesCoreSetup, plugins: PluginsSetup): Promise { From 1492c4ab901b80927f74999b33ed9c1a67fd251f Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Tue, 28 May 2019 14:56:39 -0400 Subject: [PATCH 47/68] remove spaces ConfigClass --- x-pack/plugins/spaces/index.ts | 9 +++------ .../on_post_auth_interceptor.test.ts | 3 +-- .../lib/spaces_client/spaces_client.test.ts | 7 +++---- .../server/lib/spaces_client/spaces_client.ts | 4 ++-- .../lib/spaces_tutorial_context_factory.test.ts | 3 +-- .../plugins/spaces/server/new_platform/config.ts | 15 +++++---------- .../plugins/spaces/server/new_platform/plugin.ts | 6 +++--- .../spaces_service/spaces_service.test.ts | 3 +-- .../new_platform/spaces_service/spaces_service.ts | 6 +++--- .../api/__fixtures__/create_test_handler.ts | 5 ++--- 10 files changed, 24 insertions(+), 37 deletions(-) diff --git a/x-pack/plugins/spaces/index.ts b/x-pack/plugins/spaces/index.ts index 9b4921b26665d..c8e7aca113a95 100644 --- a/x-pack/plugins/spaces/index.ts +++ b/x-pack/plugins/spaces/index.ts @@ -24,7 +24,6 @@ import { SpacesHttpServiceSetup, } from './server/new_platform/plugin'; import { initSpacesRequestInterceptors } from './server/lib/request_interceptors'; -import { SpacesConfig } from './server/new_platform/config'; export const spaces = (kibana: Record) => new kibana.Plugin({ id: 'spaces', @@ -112,11 +111,9 @@ export const spaces = (kibana: Record) => legacyConfig: server.config(), config: { create: () => { - return Rx.of( - new SpacesConfig({ - maxSpaces: server.config().get('xpack.spaces.maxSpaces'), - }) - ); + return Rx.of({ + maxSpaces: server.config().get('xpack.spaces.maxSpaces'), + }); }, }, logger: { diff --git a/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts b/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts index 7b9439bfee6dd..c76f238dfc140 100644 --- a/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts +++ b/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts @@ -15,7 +15,6 @@ import { SecurityPlugin } from '../../../../security'; import { SpacesAuditLogger } from '../audit_logger'; import { SpacesServiceSetup } from '../../new_platform/spaces_service/spaces_service'; import { elasticsearchServiceMock, httpServiceMock } from '../../../../../../src/core/server/mocks'; -import { SpacesConfig } from '../../new_platform/config'; import * as kbnTestServer from '../../../../../../src/test_utils/kbn_server'; import { HttpServiceSetup } from 'src/core/server'; import { KibanaConfig, Server } from 'src/legacy/server/kbn_server'; @@ -199,7 +198,7 @@ describe('onPostAuthRequestInterceptor', () => { savedObjects: (savedObjectsService as unknown) as SavedObjectsService, getSecurity: () => ({} as SecurityPlugin), spacesAuditLogger: {} as SpacesAuditLogger, - config$: Rx.of(new SpacesConfig({ maxSpaces: 1000 })), + config$: Rx.of({ maxSpaces: 1000 }), }); spacesService.scopedClient = jest.fn().mockReturnValue({ diff --git a/x-pack/plugins/spaces/server/lib/spaces_client/spaces_client.test.ts b/x-pack/plugins/spaces/server/lib/spaces_client/spaces_client.test.ts index 0cd36f2eceae7..2b94259e4e578 100644 --- a/x-pack/plugins/spaces/server/lib/spaces_client/spaces_client.test.ts +++ b/x-pack/plugins/spaces/server/lib/spaces_client/spaces_client.test.ts @@ -7,8 +7,7 @@ import { SpacesClient } from './spaces_client'; import { AuthorizationService } from '../../../../security/server/lib/authorization/service'; import { actionsFactory } from '../../../../security/server/lib/authorization/actions'; -import { SpacesConfig } from '../../new_platform/config'; -import { TypeOf } from '@kbn/config-schema'; +import { SpacesConfigType, config } from '../../new_platform/config'; const createMockAuditLogger = () => { return { @@ -64,8 +63,8 @@ const createMockAuthorization = () => { }; }; -const createMockConfig = (config: TypeOf = { maxSpaces: 1000 }) => { - return new SpacesConfig(config); +const createMockConfig = (mockConfig: SpacesConfigType = { maxSpaces: 1000 }) => { + return config.schema.validate(mockConfig); }; describe('#getAll', () => { diff --git a/x-pack/plugins/spaces/server/lib/spaces_client/spaces_client.ts b/x-pack/plugins/spaces/server/lib/spaces_client/spaces_client.ts index 85c1befed9ec0..5668112fca52e 100644 --- a/x-pack/plugins/spaces/server/lib/spaces_client/spaces_client.ts +++ b/x-pack/plugins/spaces/server/lib/spaces_client/spaces_client.ts @@ -10,7 +10,7 @@ import { AuthorizationService } from '../../../../security/server/lib/authorizat import { isReservedSpace } from '../../../common/is_reserved_space'; import { Space } from '../../../common/model/space'; import { SpacesAuditLogger } from '../audit_logger'; -import { SpacesConfig } from '../../new_platform/config'; +import { SpacesConfigType } from '../../new_platform/config'; interface SpacesClientRequestFacade { headers?: Headers; @@ -21,7 +21,7 @@ export class SpacesClient { private readonly debugLogger: (message: string) => void, private readonly authorization: AuthorizationService | null, private readonly callWithRequestSavedObjectRepository: any, - private readonly config: SpacesConfig, + private readonly config: SpacesConfigType, private readonly internalSavedObjectRepository: any, private readonly request: SpacesClientRequestFacade ) {} diff --git a/x-pack/plugins/spaces/server/lib/spaces_tutorial_context_factory.test.ts b/x-pack/plugins/spaces/server/lib/spaces_tutorial_context_factory.test.ts index 296ccfc786700..412e550579c61 100644 --- a/x-pack/plugins/spaces/server/lib/spaces_tutorial_context_factory.test.ts +++ b/x-pack/plugins/spaces/server/lib/spaces_tutorial_context_factory.test.ts @@ -11,7 +11,6 @@ import { SpacesService } from '../new_platform/spaces_service'; import { SavedObjectsService } from 'src/legacy/server/kbn_server'; import { SecurityPlugin } from '../../../security'; import { SpacesAuditLogger } from './audit_logger'; -import { SpacesConfig } from '../new_platform/config'; import { elasticsearchServiceMock, httpServiceMock } from '../../../../../src/core/server/mocks'; import { spacesServiceMock } from '../new_platform/spaces_service/spaces_service.mock'; @@ -65,7 +64,7 @@ describe('createSpacesTutorialContextFactory', () => { savedObjects: {} as SavedObjectsService, getSecurity: () => ({} as SecurityPlugin), spacesAuditLogger: {} as SpacesAuditLogger, - config$: Rx.of(new SpacesConfig({ maxSpaces: 1000 })), + config$: Rx.of({ maxSpaces: 1000 }), }); const contextFactory = createSpacesTutorialContextFactory(spacesService); diff --git a/x-pack/plugins/spaces/server/new_platform/config.ts b/x-pack/plugins/spaces/server/new_platform/config.ts index 80f5f419235de..fbe8edb14f19b 100644 --- a/x-pack/plugins/spaces/server/new_platform/config.ts +++ b/x-pack/plugins/spaces/server/new_platform/config.ts @@ -6,15 +6,10 @@ import { schema, TypeOf } from '@kbn/config-schema'; -/** @internal */ -export class SpacesConfig { - public static schema = schema.object({ +export const config = { + schema: schema.object({ maxSpaces: schema.number({ defaultValue: 1000 }), - }); + }), +}; - public readonly maxSpaces: number; - - constructor(config: TypeOf) { - this.maxSpaces = config.maxSpaces; - } -} +export type SpacesConfigType = TypeOf; diff --git a/x-pack/plugins/spaces/server/new_platform/plugin.ts b/x-pack/plugins/spaces/server/new_platform/plugin.ts index 8a8fbcd634942..653e4c0fda056 100644 --- a/x-pack/plugins/spaces/server/new_platform/plugin.ts +++ b/x-pack/plugins/spaces/server/new_platform/plugin.ts @@ -31,7 +31,7 @@ import { getSpacesUsageCollector } from '../lib/get_spaces_usage_collector'; import { SpacesService } from './spaces_service'; import { SecurityPlugin } from '../../../security'; import { SpacesServiceSetup } from './spaces_service/spaces_service'; -import { SpacesConfig } from './config'; +import { SpacesConfigType } from './config'; import { getActiveSpace } from '../lib/get_active_space'; import { toggleUICapabilities } from '../lib/toggle_ui_capabilities'; @@ -78,12 +78,12 @@ export interface SpacesInitializerContext extends PluginInitializerContext { export class Plugin { private readonly pluginId = 'spaces'; - private config$: Observable; + private config$: Observable; private log: Logger; constructor(private readonly initializerContext: SpacesInitializerContext) { - this.config$ = initializerContext.config.create(); + this.config$ = initializerContext.config.create(); this.log = initializerContext.logger.get(); } diff --git a/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.test.ts b/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.test.ts index 8ed102d9a50a1..47aaec47aa0dc 100644 --- a/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.test.ts +++ b/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.test.ts @@ -7,7 +7,6 @@ import * as Rx from 'rxjs'; import { SpacesService } from './spaces_service'; import { httpServiceMock, elasticsearchServiceMock } from 'src/core/server/mocks'; import { SpacesAuditLogger } from '../../lib/audit_logger'; -import { SpacesConfig } from '../config'; import { SavedObjectsService } from 'src/legacy/server/kbn_server'; import { KibanaRequest } from 'src/core/server'; import { DEFAULT_SPACE_ID } from '../../../common/constants'; @@ -39,7 +38,7 @@ const createService = async () => { const spacesServiceSetup = await spacesService.setup({ http: httpSetup, elasticsearch: elasticsearchServiceMock.createSetupContract(), - config$: Rx.of(new SpacesConfig({ maxSpaces: 10 })), + config$: Rx.of({ maxSpaces: 10 }), getSecurity: () => undefined, savedObjects: ({ getSavedObjectsRepository: jest.fn().mockReturnValue(null), diff --git a/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts b/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts index 88ae10365b38f..6c76c7914763c 100644 --- a/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts +++ b/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts @@ -18,7 +18,7 @@ import { DEFAULT_SPACE_ID } from '../../../common/constants'; import { SecurityPlugin } from '../../../../security'; import { SpacesClient } from '../../lib/spaces_client'; import { getSpaceIdFromPath } from '../../lib/spaces_url_parser'; -import { SpacesConfig } from '../config'; +import { SpacesConfigType } from '../config'; type RequestFacade = KibanaRequest | Legacy.Request; @@ -40,7 +40,7 @@ interface SpacesServiceDeps { elasticsearch: ElasticsearchServiceSetup; savedObjects: SavedObjectsService; getSecurity: () => SecurityPlugin | undefined; - config$: Observable; + config$: Observable; spacesAuditLogger: any; } @@ -61,7 +61,7 @@ export class SpacesService { config$, spacesAuditLogger, }: SpacesServiceDeps): Promise { - let config: SpacesConfig = await config$.pipe(first()).toPromise(); + let config: SpacesConfigType = await config$.pipe(first()).toPromise(); this.configSubscription$ = config$.subscribe({ next: updatedConfig => { diff --git a/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_test_handler.ts b/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_test_handler.ts index 4a06506de6ac3..14f13e2b5ef00 100644 --- a/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_test_handler.ts +++ b/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_test_handler.ts @@ -17,7 +17,6 @@ import { SpacesService } from '../../../new_platform/spaces_service'; import { SpacesAuditLogger } from '../../../lib/audit_logger'; import { InternalRouteDeps } from '../v1'; import { SpacesHttpServiceSetup } from '../../../new_platform/plugin'; -import { SpacesConfig } from '../../../new_platform/config'; interface KibanaServer extends Legacy.Server { savedObjects: any; @@ -164,7 +163,7 @@ export function createTestHandler( savedObjects: server.savedObjects, getSecurity: () => ({} as SecurityPlugin), spacesAuditLogger: {} as SpacesAuditLogger, - config$: Rx.of(new SpacesConfig({ maxSpaces: 1000 })), + config$: Rx.of({ maxSpaces: 1000 }), }); spacesService.scopedClient = jest.fn((req: any) => { @@ -173,7 +172,7 @@ export function createTestHandler( () => null, null, mockSavedObjectsRepository, - new SpacesConfig({ maxSpaces: 1000 }), + { maxSpaces: 1000 }, mockSavedObjectsRepository, req ); From 9f2bfec31c7030b4eddad872362739b703670390 Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Tue, 28 May 2019 15:08:03 -0400 Subject: [PATCH 48/68] don't weaken type declaration for scoped cluster client calls --- src/core/server/elasticsearch/scoped_cluster_client.ts | 5 ++++- .../server/new_platform/spaces_service/spaces_service.ts | 3 +-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/core/server/elasticsearch/scoped_cluster_client.ts b/src/core/server/elasticsearch/scoped_cluster_client.ts index 6e4075cbfaded..8b24250f6c5ab 100644 --- a/src/core/server/elasticsearch/scoped_cluster_client.ts +++ b/src/core/server/elasticsearch/scoped_cluster_client.ts @@ -43,7 +43,10 @@ export class ScopedClusterClient { private readonly internalAPICaller: APICaller, private readonly scopedAPICaller: APICaller, private readonly headers?: Headers - ) {} + ) { + this.callAsCurrentUser = this.callAsCurrentUser.bind(this); + this.callAsInternalUser = this.callAsInternalUser.bind(this); + } /** * Calls specified `endpoint` with provided `clientParams` on behalf of the diff --git a/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts b/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts index 6c76c7914763c..1c8663879e397 100644 --- a/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts +++ b/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts @@ -91,8 +91,7 @@ export class SpacesService { adminClient.callAsInternalUser ); - const callCluster = (endpoint: string, ...args: any[]) => - adminClient.asScoped(request).callAsCurrentUser(endpoint, ...args); + const callCluster = adminClient.asScoped(request).callAsCurrentUser; const callWithRequestRepository = savedObjects.getSavedObjectsRepository(callCluster); From c2e8b51aaa623b1423a3e3b86114c783f1708ce0 Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Tue, 28 May 2019 16:25:44 -0400 Subject: [PATCH 49/68] remove legacy server from SpacesCoreSetup --- x-pack/plugins/spaces/index.ts | 5 ++++- .../plugins/spaces/server/new_platform/plugin.ts | 15 ++++----------- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/x-pack/plugins/spaces/index.ts b/x-pack/plugins/spaces/index.ts index c8e7aca113a95..b6cd9f4a870ec 100644 --- a/x-pack/plugins/spaces/index.ts +++ b/x-pack/plugins/spaces/index.ts @@ -143,7 +143,10 @@ export const spaces = (kibana: Record) => capabilities: { registerCapabilitiesModifier: server.registerCapabilitiesModifier, }, - legacyServer: server, + auditLogger: { + create: (pluginId: string) => + new AuditLogger(server, pluginId, server.config(), server.plugins.xpack_main.info), + }, }; const plugins = { diff --git a/x-pack/plugins/spaces/server/new_platform/plugin.ts b/x-pack/plugins/spaces/server/new_platform/plugin.ts index 653e4c0fda056..ed976f0790716 100644 --- a/x-pack/plugins/spaces/server/new_platform/plugin.ts +++ b/x-pack/plugins/spaces/server/new_platform/plugin.ts @@ -6,7 +6,6 @@ import { ServerRoute } from 'hapi'; import { Observable } from 'rxjs'; -import { Legacy } from 'kibana'; import { KibanaConfig, SavedObjectsService } from 'src/legacy/server/kbn_server'; import { Logger, @@ -53,8 +52,9 @@ export interface SpacesCoreSetup { capabilities: { registerCapabilitiesModifier: (provider: CapabilitiesModifier) => void; }; - // TODO: Required for shared AuditLogger base class - legacyServer: Legacy.Server; + auditLogger: { + create: (pluginId: string) => AuditLogger; + }; } export interface PluginsSetup { @@ -100,14 +100,7 @@ export class Plugin { // to re-compute the license check results for this plugin. xpackMainPlugin.info.feature(this.pluginId).registerLicenseCheckResultsGenerator(checkLicense); - const spacesAuditLogger = new SpacesAuditLogger( - new AuditLogger( - core.legacyServer, - 'spaces', - this.initializerContext.legacyConfig, - xpackMainPlugin.info - ) - ); + const spacesAuditLogger = new SpacesAuditLogger(core.auditLogger.create(this.pluginId)); const service = new SpacesService( this.log, From 2611e6044d9d3b85b627dcedc35bfd37225f9ebf Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Wed, 29 May 2019 07:51:17 -0400 Subject: [PATCH 50/68] remove spaces service cache --- .../spaces_service/spaces_service.ts | 49 +++++++------------ 1 file changed, 17 insertions(+), 32 deletions(-) diff --git a/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts b/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts index 1c8663879e397..344f7ee1deabc 100644 --- a/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts +++ b/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts @@ -47,11 +47,7 @@ interface SpacesServiceDeps { export class SpacesService { private configSubscription$?: Subscription; - private readonly contextCache: WeakMap = new WeakMap(); - - constructor(private readonly log: Logger, private readonly serverBasePath: string) { - this.contextCache = new WeakMap(); - } + constructor(private readonly log: Logger, private readonly serverBasePath: string) {} public async setup({ http, @@ -70,21 +66,25 @@ export class SpacesService { }); const adminClient = await elasticsearch.adminClient$.pipe(first()).toPromise(); - return { - getSpaceId: (request: RequestFacade) => { - if (!this.contextCache.has(request)) { - this.populateCache(http, request); - } - const { spaceId } = this.contextCache.get(request) as CacheEntry; - return spaceId; - }, + const getSpaceId = (request: RequestFacade) => { + const isLegacyRequest = typeof (request as any).getBasePath === 'function'; + + const basePath = isLegacyRequest + ? (request as Record).getBasePath() + : http.getBasePathFor(request); + + const spaceId = getSpaceIdFromPath(basePath, this.serverBasePath); + + return spaceId; + }; + + return { + getSpaceId, isInDefaultSpace: (request: RequestFacade) => { - if (!this.contextCache.has(request)) { - this.populateCache(http, request); - } + const spaceId = getSpaceId(request); - return this.contextCache.get(request)!.isInDefaultSpace; + return spaceId === DEFAULT_SPACE_ID; }, scopedClient: (request: RequestFacade) => { const internalRepository = savedObjects.getSavedObjectsRepository( @@ -119,19 +119,4 @@ export class SpacesService { this.configSubscription$ = undefined; } } - - private populateCache(http: HttpServiceSetup, request: RequestFacade) { - const isLegacyRequest = typeof (request as any).getBasePath === 'function'; - - const basePath = isLegacyRequest - ? (request as Record).getBasePath() - : http.getBasePathFor(request); - - const spaceId = getSpaceIdFromPath(basePath, this.serverBasePath); - - this.contextCache.set(request, { - spaceId, - isInDefaultSpace: spaceId === DEFAULT_SPACE_ID, - }); - } } From 2c146509c6c560b9d63c55f9671c25ccb4648f04 Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Wed, 29 May 2019 08:05:06 -0400 Subject: [PATCH 51/68] remove legacy server as an interceptor dependency --- x-pack/plugins/spaces/index.ts | 5 ++++- .../on_post_auth_interceptor.test.ts | 5 ++++- .../request_interceptors/on_post_auth_interceptor.ts | 12 +++++++----- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/x-pack/plugins/spaces/index.ts b/x-pack/plugins/spaces/index.ts index b6cd9f4a870ec..6fe4c0060eb78 100644 --- a/x-pack/plugins/spaces/index.ts +++ b/x-pack/plugins/spaces/index.ts @@ -162,7 +162,10 @@ export const spaces = (kibana: Record) => initSpacesRequestInterceptors({ config: initializerContext.legacyConfig, http: core.http, - legacyServer: server, + getHiddenUiAppById: server.getHiddenUiAppById, + onPostAuth: handler => { + server.ext('onPostAuth', handler); + }, log, spacesService, xpackMain: plugins.xpackMain, diff --git a/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts b/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts index c76f238dfc140..f4952fea9d1ea 100644 --- a/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts +++ b/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts @@ -224,9 +224,12 @@ describe('onPostAuthRequestInterceptor', () => { await root.start(); + const legacyServer = kbnTestServer.getKbnServer(root).server; + initSpacesOnPostAuthRequestInterceptor({ config: (configFn() as unknown) as KibanaConfig, - legacyServer: kbnTestServer.getKbnServer(root).server, + onPostAuth: (handler: any) => legacyServer.ext('onPostAuth', handler), + getHiddenUiAppById: (app: string) => null, http: httpMock, log, xpackMain: plugins.xpack_main as XPackMainPlugin, diff --git a/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.ts b/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.ts index 6c59f0c17702c..7106e71d44cce 100644 --- a/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.ts +++ b/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ import Boom from 'boom'; -import { KibanaConfig, Server } from 'src/legacy/server/kbn_server'; +import { KibanaConfig } from 'src/legacy/server/kbn_server'; import { HttpServiceSetup, Logger } from 'src/core/server'; import { Space } from '../../../common/model/space'; import { wrapError } from '../errors'; @@ -15,7 +15,8 @@ import { SpacesServiceSetup } from '../../new_platform/spaces_service/spaces_ser export interface OnPostAuthInterceptorDeps { config: KibanaConfig; - legacyServer: Server; + onPostAuth: (handler: any) => void; + getHiddenUiAppById: (appId: string) => unknown; http: HttpServiceSetup; xpackMain: XPackMainPlugin; spacesService: SpacesServiceSetup; @@ -24,15 +25,16 @@ export interface OnPostAuthInterceptorDeps { export function initSpacesOnPostAuthRequestInterceptor({ config, - legacyServer, xpackMain, spacesService, log, http, + onPostAuth, + getHiddenUiAppById, }: OnPostAuthInterceptorDeps) { const serverBasePath: string = config.get('server.basePath'); - legacyServer.ext('onPostAuth', async function spacesOnPostAuthHandler(request: any, h: any) { + onPostAuth(async function spacesOnPostAuthHandler(request: any, h: any) { const path = request.path; const isRequestingKibanaRoot = path === '/'; @@ -61,7 +63,7 @@ export function initSpacesOnPostAuthRequestInterceptor({ if (spaces.length > 0) { // render spaces selector instead of home page - const app = legacyServer.getHiddenUiAppById('space_selector'); + const app = getHiddenUiAppById('space_selector'); return (await h.renderApp(app, { spaces })).takeover(); } } catch (error) { From d6f8d0781bada1f231b07227e108468a6be63dc1 Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Wed, 29 May 2019 08:14:16 -0400 Subject: [PATCH 52/68] use modifyUrl on the raw request too --- src/core/server/http/lifecycle/on_request.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/core/server/http/lifecycle/on_request.ts b/src/core/server/http/lifecycle/on_request.ts index 36d57b0792ad0..90a6e1c2b2f16 100644 --- a/src/core/server/http/lifecycle/on_request.ts +++ b/src/core/server/http/lifecycle/on_request.ts @@ -109,7 +109,16 @@ export function adoptToHapiOnRequestFormat(fn: OnRequestHandler) { // We should update raw request as well since it can be proxied to the old platform let rawUrl; if (typeof newUrl === 'string') { - rawUrl = newUrl + (request.url.search || ''); + if (request.url.query) { + rawUrl = modifyUrl(newUrl, parts => { + return { + ...parts, + query: request.url.query!, + }; + }); + } else { + rawUrl = newUrl; + } } else { rawUrl = newUrl.href; } From 9680e4bfdc5eb1a4fd18e3dc2eb58d7e5efa00d6 Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Wed, 29 May 2019 08:14:50 -0400 Subject: [PATCH 53/68] remove unused import --- x-pack/plugins/spaces/index.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/x-pack/plugins/spaces/index.ts b/x-pack/plugins/spaces/index.ts index 6fe4c0060eb78..7c8240992d030 100644 --- a/x-pack/plugins/spaces/index.ts +++ b/x-pack/plugins/spaces/index.ts @@ -10,8 +10,6 @@ import KbnServer, { Server } from 'src/legacy/server/kbn_server'; import { HttpServiceSetup } from 'src/core/server'; // @ts-ignore import { AuditLogger } from '../../server/lib/audit_logger'; -// @ts-ignore -import { watchStatusAndLicenseToInitialize } from '../../server/lib/watch_status_and_license_to_initialize'; import mappings from './mappings.json'; import { wrapError } from './server/lib/errors'; import { getActiveSpace } from './server/lib/get_active_space'; From dadd6074fcc9e0497d378a79368a8823d28dce96 Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Wed, 29 May 2019 08:39:39 -0400 Subject: [PATCH 54/68] cleanup typings --- x-pack/plugins/spaces/index.ts | 7 +++---- .../server/new_platform/spaces_service/spaces_service.ts | 5 ----- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/x-pack/plugins/spaces/index.ts b/x-pack/plugins/spaces/index.ts index 7c8240992d030..e6da107b0debe 100644 --- a/x-pack/plugins/spaces/index.ts +++ b/x-pack/plugins/spaces/index.ts @@ -7,7 +7,6 @@ import * as Rx from 'rxjs'; import { resolve } from 'path'; import KbnServer, { Server } from 'src/legacy/server/kbn_server'; -import { HttpServiceSetup } from 'src/core/server'; // @ts-ignore import { AuditLogger } from '../../server/lib/audit_logger'; import mappings from './mappings.json'; @@ -126,7 +125,7 @@ export const spaces = (kibana: Record) => } as unknown) as SpacesInitializerContext; const spacesHttpService: SpacesHttpServiceSetup = { - ...(kbnServer.newPlatform.setup.core.http as HttpServiceSetup), + ...kbnServer.newPlatform.setup.core.http, route: server.route.bind(server), }; @@ -134,9 +133,9 @@ export const spaces = (kibana: Record) => http: spacesHttpService, elasticsearch: kbnServer.newPlatform.setup.core.elasticsearch, savedObjects: server.savedObjects, - usage: (server as any).usage, + usage: server.usage, tutorial: { - addScopedTutorialContextFactory: (server as any).addScopedTutorialContextFactory, + addScopedTutorialContextFactory: server.addScopedTutorialContextFactory, }, capabilities: { registerCapabilitiesModifier: server.registerCapabilitiesModifier, diff --git a/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts b/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts index 344f7ee1deabc..2736259aeb9ee 100644 --- a/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts +++ b/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts @@ -30,11 +30,6 @@ export interface SpacesServiceSetup { isInDefaultSpace(request: RequestFacade): boolean; } -interface CacheEntry { - spaceId: string; - isInDefaultSpace: boolean; -} - interface SpacesServiceDeps { http: HttpServiceSetup; elasticsearch: ElasticsearchServiceSetup; From 0b8ddde46a77484f5f74f7a5a403fa1b90e8a0be Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Wed, 29 May 2019 09:24:27 -0400 Subject: [PATCH 55/68] replace onRequest interceptor with new onPreAuth interceptor --- .../on_request_interceptor.ts | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.ts b/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.ts index 0cecf39451801..f3e6fd9bfbae5 100644 --- a/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.ts +++ b/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.ts @@ -3,8 +3,10 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { KibanaRequest, OnRequestToolkit, HttpServiceSetup } from 'src/core/server'; +import { KibanaRequest, OnPreAuthToolkit, HttpServiceSetup } from 'src/core/server'; import { KibanaConfig } from 'src/legacy/server/kbn_server'; +import { format } from 'url'; +import { modifyUrl } from '../../../../../../src/core/utils'; import { DEFAULT_SPACE_ID } from '../../../common/constants'; import { getSpaceIdFromPath } from '../spaces_url_parser'; @@ -15,9 +17,9 @@ export interface OnRequestInterceptorDeps { export function initSpacesOnRequestInterceptor({ config, http }: OnRequestInterceptorDeps) { const serverBasePath: string = config.get('server.basePath'); - http.registerOnRequest(async function spacesOnRequestHandler( + http.registerOnPreAuth(async function spacesOnPreAuthHandler( request: KibanaRequest, - toolkit: OnRequestToolkit + toolkit: OnPreAuthToolkit ) { const path = request.path; @@ -32,7 +34,14 @@ export function initSpacesOnRequestInterceptor({ config, http }: OnRequestInterc const newLocation = path.substr(reqBasePath.length) || '/'; - toolkit.setUrl(newLocation); + const newUrl = modifyUrl(format(request.url), parts => { + return { + ...parts, + pathname: newLocation, + }; + }); + + return toolkit.redirected(newUrl, { forward: true }); } return toolkit.next(); From 583bff2e8bb237f7b305efc38175697a5400d039 Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Wed, 29 May 2019 10:20:10 -0400 Subject: [PATCH 56/68] fix onPostAuth tests --- .../on_post_auth_interceptor.test.ts | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts b/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts index f4952fea9d1ea..410e57a6f57bf 100644 --- a/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts +++ b/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts @@ -19,6 +19,7 @@ import * as kbnTestServer from '../../../../../../src/test_utils/kbn_server'; import { HttpServiceSetup } from 'src/core/server'; import { KibanaConfig, Server } from 'src/legacy/server/kbn_server'; import { XPackMainPlugin } from '../../../../xpack_main/xpack_main'; +import { parse } from 'url'; // TODO: re-implement on NP describe('onPostAuthRequestInterceptor', () => { @@ -179,16 +180,17 @@ describe('onPostAuthRequestInterceptor', () => { httpMock.setBasePathFor = jest.fn().mockImplementation((req: any, newPath: string) => { basePath = newPath; }); - httpMock.registerOnRequest = jest.fn().mockImplementation(async handler => { - await handler( - { path }, - { - setUrl: jest.fn().mockImplementation(url => { - path = url; - }), - next: jest.fn(), - } - ); + httpMock.registerOnPreAuth = jest.fn().mockImplementation(async handler => { + const preAuthRequest = { + path, + url: parse(path), + }; + await handler(preAuthRequest, { + redirected: jest.fn().mockImplementation(url => { + path = url; + }), + next: jest.fn(), + }); }); const service = new SpacesService(log, configFn().get('server.basePath')); From 8819aa6069c1fb9bb8de48435fd8d970082a4141 Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Thu, 30 May 2019 07:19:53 -0400 Subject: [PATCH 57/68] temporarily copy modifyUrl into spaces plugin --- .../on_request_interceptor.ts | 2 +- .../spaces/server/lib/utils/url.test.ts | 62 +++++++++++++ x-pack/plugins/spaces/server/lib/utils/url.ts | 88 +++++++++++++++++++ 3 files changed, 151 insertions(+), 1 deletion(-) create mode 100644 x-pack/plugins/spaces/server/lib/utils/url.test.ts create mode 100644 x-pack/plugins/spaces/server/lib/utils/url.ts diff --git a/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.ts b/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.ts index f3e6fd9bfbae5..aea657c6df569 100644 --- a/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.ts +++ b/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.ts @@ -6,9 +6,9 @@ import { KibanaRequest, OnPreAuthToolkit, HttpServiceSetup } from 'src/core/server'; import { KibanaConfig } from 'src/legacy/server/kbn_server'; import { format } from 'url'; -import { modifyUrl } from '../../../../../../src/core/utils'; import { DEFAULT_SPACE_ID } from '../../../common/constants'; import { getSpaceIdFromPath } from '../spaces_url_parser'; +import { modifyUrl } from '../utils/url'; export interface OnRequestInterceptorDeps { config: KibanaConfig; diff --git a/x-pack/plugins/spaces/server/lib/utils/url.test.ts b/x-pack/plugins/spaces/server/lib/utils/url.test.ts new file mode 100644 index 0000000000000..b59f2924e6fbb --- /dev/null +++ b/x-pack/plugins/spaces/server/lib/utils/url.test.ts @@ -0,0 +1,62 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +// TEMPORARY UNTIL FIXED! +// DIRECT COPY FROM `src/core/utils/url`, since it's not possible to import from there, +// nor can I re-export from `src/core/server`... + +import { modifyUrl } from './url'; + +describe('modifyUrl()', () => { + test('throws an error with invalid input', () => { + expect(() => modifyUrl(1 as any, () => ({}))).toThrowError(); + expect(() => modifyUrl(undefined as any, () => ({}))).toThrowError(); + expect(() => modifyUrl('http://localhost', undefined as any)).toThrowError(); + }); + + test('supports returning a new url spec', () => { + expect(modifyUrl('http://localhost', () => ({}))).toEqual(''); + }); + + test('supports modifying the passed object', () => { + expect( + modifyUrl('http://localhost', parsed => { + parsed.port = '9999'; + parsed.auth = 'foo:bar'; + return parsed; + }) + ).toEqual('http://foo:bar@localhost:9999/'); + }); + + test('supports changing pathname', () => { + expect( + modifyUrl('http://localhost/some/path', parsed => { + parsed.pathname += '/subpath'; + return parsed; + }) + ).toEqual('http://localhost/some/path/subpath'); + }); + + test('supports changing port', () => { + expect( + modifyUrl('http://localhost:5601', parsed => { + parsed.port = (Number(parsed.port!) + 1).toString(); + return parsed; + }) + ).toEqual('http://localhost:5602/'); + }); + + test('supports changing protocol', () => { + expect( + modifyUrl('http://localhost', parsed => { + parsed.protocol = 'mail'; + parsed.slashes = false; + parsed.pathname = null; + return parsed; + }) + ).toEqual('mail:localhost'); + }); +}); diff --git a/x-pack/plugins/spaces/server/lib/utils/url.ts b/x-pack/plugins/spaces/server/lib/utils/url.ts new file mode 100644 index 0000000000000..a5797c0f87868 --- /dev/null +++ b/x-pack/plugins/spaces/server/lib/utils/url.ts @@ -0,0 +1,88 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +// TEMPORARY UNTIL FIXED! +// DIRECT COPY FROM `src/core/utils/url`, since it's not possible to import from there, +// nor can I re-export from `src/core/server`... + +import { ParsedUrlQuery } from 'querystring'; +import { format as formatUrl, parse as parseUrl, UrlObject } from 'url'; + +export interface URLMeaningfulParts { + auth: string | null; + hash: string | null; + hostname: string | null; + pathname: string | null; + protocol: string | null; + slashes: boolean | null; + port: string | null; + query: ParsedUrlQuery | {}; +} + +/** + * Takes a URL and a function that takes the meaningful parts + * of the URL as a key-value object, modifies some or all of + * the parts, and returns the modified parts formatted again + * as a url. + * + * Url Parts sent: + * - protocol + * - slashes (does the url have the //) + * - auth + * - hostname (just the name of the host, no port or auth information) + * - port + * - pathname (the path after the hostname, no query or hash, starts + * with a slash if there was a path) + * - query (always an object, even when no query on original url) + * - hash + * + * Why? + * - The default url library in node produces several conflicting + * properties on the "parsed" output. Modifying any of these might + * lead to the modifications being ignored (depending on which + * property was modified) + * - It's not always clear whether to use path/pathname, host/hostname, + * so this tries to add helpful constraints + * + * @param url The string url to parse. + * @param urlModifier A function that will modify the parsed url, or return a new one. + * @returns The modified and reformatted url + */ +export function modifyUrl( + url: string, + urlModifier: (urlParts: URLMeaningfulParts) => Partial | undefined +) { + const parsed = parseUrl(url, true) as URLMeaningfulParts; + + // Copy over the most specific version of each property. By default, the parsed url includes several + // conflicting properties (like path and pathname + search, or search and query) and keeping track + // of which property is actually used when they are formatted is harder than necessary. + const meaningfulParts: URLMeaningfulParts = { + auth: parsed.auth, + hash: parsed.hash, + hostname: parsed.hostname, + pathname: parsed.pathname, + port: parsed.port, + protocol: parsed.protocol, + query: parsed.query || {}, + slashes: parsed.slashes, + }; + + // The urlModifier modifies the meaningfulParts object, or returns a new one. + const modifiedParts = urlModifier(meaningfulParts) || meaningfulParts; + + // Format the modified/replaced meaningfulParts back into a url. + return formatUrl({ + auth: modifiedParts.auth, + hash: modifiedParts.hash, + hostname: modifiedParts.hostname, + pathname: modifiedParts.pathname, + port: modifiedParts.port, + protocol: modifiedParts.protocol, + query: modifiedParts.query, + slashes: modifiedParts.slashes, + } as UrlObject); +} From 9f73fd28ecec0cc71a05be450d2b2f83408c65c4 Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Tue, 4 Jun 2019 06:25:34 -0400 Subject: [PATCH 58/68] fix mock export --- x-pack/plugins/spaces/server/lib/spaces_client/index.ts | 1 - .../server/new_platform/spaces_service/spaces_service.mock.ts | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/x-pack/plugins/spaces/server/lib/spaces_client/index.ts b/x-pack/plugins/spaces/server/lib/spaces_client/index.ts index 3c883241a0ed4..54c778ae3839e 100644 --- a/x-pack/plugins/spaces/server/lib/spaces_client/index.ts +++ b/x-pack/plugins/spaces/server/lib/spaces_client/index.ts @@ -5,4 +5,3 @@ */ export { SpacesClient } from './spaces_client'; -export { spacesClientMock } from './spaces_client.mock'; diff --git a/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.mock.ts b/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.mock.ts index cef3dd23b02dd..5866dcb3273ff 100644 --- a/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.mock.ts +++ b/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.mock.ts @@ -5,7 +5,7 @@ */ import { SpacesServiceSetup } from './spaces_service'; -import { spacesClientMock } from '../../lib/spaces_client'; +import { spacesClientMock } from '../../lib/spaces_client/spaces_client.mock'; import { DEFAULT_SPACE_ID } from '../../../common/constants'; const createSetupContractMock = (spaceId = DEFAULT_SPACE_ID) => { From b0a977caeb1363b3bcd62204da2e2e663cc1e04c Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Fri, 7 Jun 2019 06:03:24 -0400 Subject: [PATCH 59/68] fix merge from master --- .../on_request_interceptor.test.ts | 15 +++++++++++---- .../on_request_interceptor.ts | 4 ++-- .../spaces_service/spaces_service.test.ts | 10 +++++----- 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.test.ts b/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.test.ts index 31a35aa4fd682..bf76730f3958b 100644 --- a/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.test.ts +++ b/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.test.ts @@ -57,13 +57,13 @@ describe('onRequestInterceptor', () => { const router = new Router('/'); router.get({ path: '/foo', validate: false }, (req: KibanaRequest, h: any) => { - return h.ok({ path: req.path, basePath: http.getBasePathFor(req) }); + return h.ok({ path: req.url.pathname, basePath: http.getBasePathFor(req) }); }); router.get( { path: '/some/path/s/foo/bar', validate: false }, (req: KibanaRequest, h: any) => { - return h.ok({ path: req.path, basePath: http.getBasePathFor(req) }); + return h.ok({ path: req.url.pathname, basePath: http.getBasePathFor(req) }); } ); @@ -81,7 +81,11 @@ describe('onRequestInterceptor', () => { }, }, (req: KibanaRequest, h: any) => { - return h.ok({ path: req.path, basePath: http.getBasePathFor(req), query: req.query }); + return h.ok({ + path: req.url.pathname, + basePath: http.getBasePathFor(req), + query: req.query, + }); } ); @@ -128,7 +132,10 @@ describe('onRequestInterceptor', () => { const path = '/s/foo-space/foo'; - await kbnTestServer.request.get(root, path).expect(200, { + const resp = await kbnTestServer.request.get(root, path); + + expect(resp.status).toEqual(200); + expect(resp.body).toEqual({ path: '/foo', basePath: '/s/foo-space', }); diff --git a/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.ts b/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.ts index aea657c6df569..8250d63ac1168 100644 --- a/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.ts +++ b/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.ts @@ -21,7 +21,7 @@ export function initSpacesOnRequestInterceptor({ config, http }: OnRequestInterc request: KibanaRequest, toolkit: OnPreAuthToolkit ) { - const path = request.path; + const path = request.url.pathname; // If navigating within the context of a space, then we store the Space's URL Context on the request, // and rewrite the request to not include the space identifier in the URL. @@ -32,7 +32,7 @@ export function initSpacesOnRequestInterceptor({ config, http }: OnRequestInterc http.setBasePathFor(request, reqBasePath); - const newLocation = path.substr(reqBasePath.length) || '/'; + const newLocation = (path && path.substr(reqBasePath.length)) || '/'; const newUrl = modifyUrl(format(request.url), parts => { return { diff --git a/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.test.ts b/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.test.ts index 47aaec47aa0dc..7c593ca450d77 100644 --- a/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.test.ts +++ b/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.test.ts @@ -27,7 +27,7 @@ const createService = async () => { const httpSetup = httpServiceMock.createSetupContract(); httpSetup.getBasePathFor = jest.fn().mockImplementation((request: KibanaRequest) => { - const spaceId = getSpaceIdFromPath(request.path); + const spaceId = getSpaceIdFromPath(request.url.path); if (spaceId !== DEFAULT_SPACE_ID) { return `/s/${spaceId}`; @@ -55,7 +55,7 @@ describe('SpacesService', () => { const spacesServiceSetup = await createService(); const request: KibanaRequest = { - path: '/app/kibana', + url: { path: '/app/kibana' }, } as KibanaRequest; expect(spacesServiceSetup.getSpaceId(request)).toEqual(DEFAULT_SPACE_ID); @@ -65,7 +65,7 @@ describe('SpacesService', () => { const spacesServiceSetup = await createService(); const request: KibanaRequest = { - path: '/s/foo/app/kibana', + url: { path: '/s/foo/app/kibana' }, } as KibanaRequest; expect(spacesServiceSetup.getSpaceId(request)).toEqual('foo'); @@ -77,7 +77,7 @@ describe('SpacesService', () => { const spacesServiceSetup = await createService(); const request: KibanaRequest = { - path: '/app/kibana', + url: { path: '/app/kibana' }, } as KibanaRequest; expect(spacesServiceSetup.isInDefaultSpace(request)).toEqual(true); @@ -87,7 +87,7 @@ describe('SpacesService', () => { const spacesServiceSetup = await createService(); const request: KibanaRequest = { - path: '/s/foo/app/kibana', + url: { path: '/s/foo/app/kibana' }, } as KibanaRequest; expect(spacesServiceSetup.isInDefaultSpace(request)).toEqual(false); From 3a5cc82cdcb90725f6a1019539e430340c6bd471 Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Fri, 7 Jun 2019 11:40:05 -0400 Subject: [PATCH 60/68] spaces scopedClient always uses updated ES client and config --- x-pack/plugins/spaces/index.ts | 2 +- .../on_post_auth_interceptor.test.ts | 2 +- .../on_post_auth_interceptor.ts | 2 +- .../spaces/server/new_platform/plugin.ts | 2 +- .../spaces_service/spaces_service.mock.ts | 2 +- .../spaces_service/spaces_service.ts | 69 +++++++++---------- .../api/__fixtures__/create_test_handler.ts | 18 ++--- .../server/routes/api/external/delete.ts | 2 +- .../spaces/server/routes/api/external/get.ts | 4 +- .../spaces/server/routes/api/external/post.ts | 2 +- .../spaces/server/routes/api/external/put.ts | 2 +- .../spaces/server/routes/api/v1/spaces.ts | 2 +- 12 files changed, 54 insertions(+), 55 deletions(-) diff --git a/x-pack/plugins/spaces/index.ts b/x-pack/plugins/spaces/index.ts index e6da107b0debe..813105f3f9825 100644 --- a/x-pack/plugins/spaces/index.ts +++ b/x-pack/plugins/spaces/index.ts @@ -81,7 +81,7 @@ export const spaces = (kibana: Record) => request: Record, server: Record ) { - const spacesClient = server.plugins.spaces.spacesClient.scopedClient(request); + const spacesClient = await server.plugins.spaces.spacesClient.scopedClient(request); try { vars.activeSpace = { valid: true, diff --git a/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts b/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts index 410e57a6f57bf..11f33b4cfe4ef 100644 --- a/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts +++ b/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts @@ -203,7 +203,7 @@ describe('onPostAuthRequestInterceptor', () => { config$: Rx.of({ maxSpaces: 1000 }), }); - spacesService.scopedClient = jest.fn().mockReturnValue({ + spacesService.scopedClient = jest.fn().mockResolvedValue({ getAll() { return spaces.map(convertSavedObjectToSpace); }, diff --git a/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.ts b/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.ts index 1fd7501a42787..ce2ab453e91ef 100644 --- a/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.ts +++ b/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.ts @@ -40,7 +40,7 @@ export function initSpacesOnPostAuthRequestInterceptor({ const isRequestingKibanaRoot = path === '/'; const isRequestingApplication = path.startsWith('/app'); - const spacesClient = spacesService.scopedClient(request); + const spacesClient = await spacesService.scopedClient(request); // if requesting the application root, then show the Space Selector UI to allow the user to choose which space // they wish to visit. This is done "onPostAuth" to allow the Saved Objects Client to use the request's auth credentials, diff --git a/x-pack/plugins/spaces/server/new_platform/plugin.ts b/x-pack/plugins/spaces/server/new_platform/plugin.ts index ed976f0790716..d7be8b1d89fbb 100644 --- a/x-pack/plugins/spaces/server/new_platform/plugin.ts +++ b/x-pack/plugins/spaces/server/new_platform/plugin.ts @@ -126,7 +126,7 @@ export class Plugin { ); core.capabilities.registerCapabilitiesModifier(async (request, uiCapabilities) => { - const spacesClient = spacesService.scopedClient(request); + const spacesClient = await spacesService.scopedClient(request); try { const activeSpace = await getActiveSpace( spacesClient, diff --git a/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.mock.ts b/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.mock.ts index 5866dcb3273ff..f929e6a8e55b1 100644 --- a/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.mock.ts +++ b/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.mock.ts @@ -12,7 +12,7 @@ const createSetupContractMock = (spaceId = DEFAULT_SPACE_ID) => { const setupContract: SpacesServiceSetup = { getSpaceId: jest.fn().mockReturnValue(spaceId), isInDefaultSpace: jest.fn().mockReturnValue(spaceId === DEFAULT_SPACE_ID), - scopedClient: jest.fn().mockReturnValue(spacesClientMock.create()), + scopedClient: jest.fn().mockResolvedValue(spacesClientMock.create()), }; return setupContract; }; diff --git a/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts b/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts index 2736259aeb9ee..832db7ae4ff18 100644 --- a/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts +++ b/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts @@ -4,8 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -import { first } from 'rxjs/operators'; -import { Observable, Subscription } from 'rxjs'; +import { map, take } from 'rxjs/operators'; +import { Observable, Subscription, combineLatest } from 'rxjs'; import { Legacy } from 'kibana'; import { SavedObjectsService } from 'src/legacy/server/kbn_server'; import { @@ -23,7 +23,7 @@ import { SpacesConfigType } from '../config'; type RequestFacade = KibanaRequest | Legacy.Request; export interface SpacesServiceSetup { - scopedClient(request: RequestFacade): SpacesClient; + scopedClient(request: RequestFacade): Promise; getSpaceId(request: RequestFacade): string; @@ -52,16 +52,6 @@ export class SpacesService { config$, spacesAuditLogger, }: SpacesServiceDeps): Promise { - let config: SpacesConfigType = await config$.pipe(first()).toPromise(); - - this.configSubscription$ = config$.subscribe({ - next: updatedConfig => { - config = updatedConfig; - }, - }); - - const adminClient = await elasticsearch.adminClient$.pipe(first()).toPromise(); - const getSpaceId = (request: RequestFacade) => { const isLegacyRequest = typeof (request as any).getBasePath === 'function'; @@ -81,29 +71,36 @@ export class SpacesService { return spaceId === DEFAULT_SPACE_ID; }, - scopedClient: (request: RequestFacade) => { - const internalRepository = savedObjects.getSavedObjectsRepository( - adminClient.callAsInternalUser - ); - - const callCluster = adminClient.asScoped(request).callAsCurrentUser; - - const callWithRequestRepository = savedObjects.getSavedObjectsRepository(callCluster); - - const security = getSecurity(); - const authorization = security ? security.authorization : null; - - return new SpacesClient( - spacesAuditLogger, - (message: string) => { - this.log.debug(message); - }, - authorization, - callWithRequestRepository, - config, - internalRepository, - request - ); + scopedClient: async (request: RequestFacade) => { + return combineLatest(elasticsearch.adminClient$, config$) + .pipe( + map(([clusterClient, config]) => { + const internalRepository = savedObjects.getSavedObjectsRepository( + clusterClient.callAsInternalUser + ); + + const callCluster = clusterClient.asScoped(request).callAsCurrentUser; + + const callWithRequestRepository = savedObjects.getSavedObjectsRepository(callCluster); + + const security = getSecurity(); + const authorization = security ? security.authorization : null; + + return new SpacesClient( + spacesAuditLogger, + (message: string) => { + this.log.debug(message); + }, + authorization, + callWithRequestRepository, + config, + internalRepository, + request + ); + }), + take(1) + ) + .toPromise(); }, }; } diff --git a/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_test_handler.ts b/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_test_handler.ts index 14f13e2b5ef00..d08cadb27021a 100644 --- a/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_test_handler.ts +++ b/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_test_handler.ts @@ -167,14 +167,16 @@ export function createTestHandler( }); spacesService.scopedClient = jest.fn((req: any) => { - return new SpacesClient( - null as any, - () => null, - null, - mockSavedObjectsRepository, - { maxSpaces: 1000 }, - mockSavedObjectsRepository, - req + return Promise.resolve( + new SpacesClient( + null as any, + () => null, + null, + mockSavedObjectsRepository, + { maxSpaces: 1000 }, + mockSavedObjectsRepository, + req + ) ); }); diff --git a/x-pack/plugins/spaces/server/routes/api/external/delete.ts b/x-pack/plugins/spaces/server/routes/api/external/delete.ts index 56c45563588a9..6e49fc9904c3f 100644 --- a/x-pack/plugins/spaces/server/routes/api/external/delete.ts +++ b/x-pack/plugins/spaces/server/routes/api/external/delete.ts @@ -17,7 +17,7 @@ export function initDeleteSpacesApi(deps: ExternalRouteDeps) { path: '/api/spaces/space/{id}', async handler(request: ExternalRouteRequestFacade, h: any) { const { SavedObjectsClient } = savedObjects; - const spacesClient: SpacesClient = spacesService.scopedClient(request); + const spacesClient: SpacesClient = await spacesService.scopedClient(request); const id = request.params.id; diff --git a/x-pack/plugins/spaces/server/routes/api/external/get.ts b/x-pack/plugins/spaces/server/routes/api/external/get.ts index 6d10b59fa97d6..8da265f2c1939 100644 --- a/x-pack/plugins/spaces/server/routes/api/external/get.ts +++ b/x-pack/plugins/spaces/server/routes/api/external/get.ts @@ -19,7 +19,7 @@ export function initGetSpacesApi(deps: ExternalRouteDeps) { async handler(request: ExternalRouteRequestFacade) { log.debug(`Inside GET /api/spaces/space`); - const spacesClient: SpacesClient = spacesService.scopedClient(request); + const spacesClient: SpacesClient = await spacesService.scopedClient(request); let spaces: Space[]; @@ -46,7 +46,7 @@ export function initGetSpacesApi(deps: ExternalRouteDeps) { const spaceId = request.params.id; const { SavedObjectsClient } = savedObjects; - const spacesClient: SpacesClient = spacesService.scopedClient(request); + const spacesClient: SpacesClient = await spacesService.scopedClient(request); try { return await spacesClient.get(spaceId); diff --git a/x-pack/plugins/spaces/server/routes/api/external/post.ts b/x-pack/plugins/spaces/server/routes/api/external/post.ts index fd76297e27f60..372eb743a93f2 100644 --- a/x-pack/plugins/spaces/server/routes/api/external/post.ts +++ b/x-pack/plugins/spaces/server/routes/api/external/post.ts @@ -20,7 +20,7 @@ export function initPostSpacesApi(deps: ExternalRouteDeps) { async handler(request: ExternalRouteRequestFacade) { log.debug(`Inside POST /api/spaces/space`); const { SavedObjectsClient } = savedObjects; - const spacesClient: SpacesClient = spacesService.scopedClient(request); + const spacesClient: SpacesClient = await spacesService.scopedClient(request); const space = request.payload as Space; diff --git a/x-pack/plugins/spaces/server/routes/api/external/put.ts b/x-pack/plugins/spaces/server/routes/api/external/put.ts index 455de78a2a57c..3e1ac4afec684 100644 --- a/x-pack/plugins/spaces/server/routes/api/external/put.ts +++ b/x-pack/plugins/spaces/server/routes/api/external/put.ts @@ -19,7 +19,7 @@ export function initPutSpacesApi(deps: ExternalRouteDeps) { path: '/api/spaces/space/{id}', async handler(request: ExternalRouteRequestFacade) { const { SavedObjectsClient } = savedObjects; - const spacesClient: SpacesClient = spacesService.scopedClient(request); + const spacesClient: SpacesClient = await spacesService.scopedClient(request); const space: Space = request.payload as Space; const id = request.params.id; diff --git a/x-pack/plugins/spaces/server/routes/api/v1/spaces.ts b/x-pack/plugins/spaces/server/routes/api/v1/spaces.ts index 2ef2976abf5b2..8765bd635a45a 100644 --- a/x-pack/plugins/spaces/server/routes/api/v1/spaces.ts +++ b/x-pack/plugins/spaces/server/routes/api/v1/spaces.ts @@ -20,7 +20,7 @@ export function initInternalSpacesApi(deps: InternalRouteDeps) { path: '/api/spaces/v1/space/{id}/select', async handler(request: any) { const { SavedObjectsClient } = savedObjects; - const spacesClient: SpacesClient = spacesService.scopedClient(request); + const spacesClient: SpacesClient = await spacesService.scopedClient(request); const id = request.params.id; try { From 40df9f5f6909b0068521da7837a6b5a05a5e274a Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Fri, 14 Jun 2019 07:18:38 -0400 Subject: [PATCH 61/68] improve typings for usage collector --- .../server/lib/get_spaces_usage_collector.ts | 24 ++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/spaces/server/lib/get_spaces_usage_collector.ts b/x-pack/plugins/spaces/server/lib/get_spaces_usage_collector.ts index cce9e2cb0f4a2..f4e06116fabd8 100644 --- a/x-pack/plugins/spaces/server/lib/get_spaces_usage_collector.ts +++ b/x-pack/plugins/spaces/server/lib/get_spaces_usage_collector.ts @@ -6,11 +6,29 @@ import { KibanaConfig } from 'src/legacy/server/kbn_server'; import { get } from 'lodash'; +import { CallAPIOptions } from 'src/core/server'; import { XPackMainPlugin } from '../../../xpack_main/xpack_main'; // @ts-ignore import { KIBANA_STATS_TYPE_MONITORING } from '../../../monitoring/common/constants'; import { KIBANA_SPACES_STATS_TYPE } from '../../common/constants'; +type CallCluster = ( + endpoint: string, + clientParams: Record, + options?: CallAPIOptions +) => Promise; + +interface SpacesAggregationResponse { + hits: { + total: { value: number }; + }; + aggregations: { + [aggName: string]: { + buckets: Array<{ key: string; doc_count: number }>; + }; + }; +} + /** * * @param callCluster @@ -19,7 +37,7 @@ import { KIBANA_SPACES_STATS_TYPE } from '../../common/constants'; * @return {UsageStats} */ async function getSpacesUsage( - callCluster: any, + callCluster: CallCluster, kibanaIndex: string, xpackMainPlugin: XPackMainPlugin, spacesAvailable: boolean @@ -30,7 +48,7 @@ async function getSpacesUsage( const knownFeatureIds = xpackMainPlugin.getFeatures().map(feature => feature.id); - const resp = await callCluster('search', { + const resp = await callCluster('search', { index: kibanaIndex, body: { track_total_hits: true, @@ -110,7 +128,7 @@ export function getSpacesUsageCollector(deps: CollectorDeps) { return collectorSet.makeUsageCollector({ type: KIBANA_SPACES_STATS_TYPE, isReady: () => true, - fetch: async (callCluster: any) => { + fetch: async (callCluster: CallCluster) => { const xpackInfo = deps.xpackMain.info; const available = xpackInfo && xpackInfo.isAvailable(); // some form of spaces is available for all valid licenses const enabled = deps.config.get('xpack.spaces.enabled'); From c33880355868f0fadf8733fa3ab94f6e7c223af2 Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Fri, 14 Jun 2019 07:26:52 -0400 Subject: [PATCH 62/68] rename isLegacyRequest -> isFakeRequest --- .../server/new_platform/spaces_service/spaces_service.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts b/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts index 832db7ae4ff18..4766c23adb67a 100644 --- a/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts +++ b/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts @@ -53,9 +53,10 @@ export class SpacesService { spacesAuditLogger, }: SpacesServiceDeps): Promise { const getSpaceId = (request: RequestFacade) => { - const isLegacyRequest = typeof (request as any).getBasePath === 'function'; + // Currently utilized by reporting + const isFakeRequest = typeof (request as any).getBasePath === 'function'; - const basePath = isLegacyRequest + const basePath = isFakeRequest ? (request as Record).getBasePath() : http.getBasePathFor(request); From 454601316227bf23a8cf1964e85cc99402bf30c6 Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Mon, 17 Jun 2019 08:23:38 -0400 Subject: [PATCH 63/68] use updated NP base path API --- .../on_post_auth_interceptor.test.ts | 14 +++++++------- .../on_post_auth_interceptor.ts | 2 +- .../on_request_interceptor.test.ts | 12 ++++++------ .../request_interceptors/on_request_interceptor.ts | 2 +- .../plugins/spaces/server/new_platform/plugin.ts | 2 +- .../spaces_service/spaces_service.test.ts | 2 +- .../new_platform/spaces_service/spaces_service.ts | 2 +- 7 files changed, 18 insertions(+), 18 deletions(-) diff --git a/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts b/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts index 11f33b4cfe4ef..00e45d8272d41 100644 --- a/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts +++ b/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts @@ -42,35 +42,35 @@ describe('onPostAuthRequestInterceptor', () => { method: 'GET', path: '/foo', handler: (req: any) => { - return { path: req.path, basePath: http.getBasePathFor(req) }; + return { path: req.path, basePath: http.basePath.get(req) }; }, }, { method: 'GET', path: '/app/kibana', handler: (req: any) => { - return { path: req.path, basePath: http.getBasePathFor(req) }; + return { path: req.path, basePath: http.basePath.get(req) }; }, }, { method: 'GET', path: '/app/app-1', handler: (req: any) => { - return { path: req.path, basePath: http.getBasePathFor(req) }; + return { path: req.path, basePath: http.basePath.get(req) }; }, }, { method: 'GET', path: '/app/app-2', handler: (req: any) => { - return { path: req.path, basePath: http.getBasePathFor(req) }; + return { path: req.path, basePath: http.basePath.get(req) }; }, }, { method: 'GET', path: '/api/test/foo', handler: (req: any) => { - return { path: req.path, basePath: http.getBasePathFor(req) }; + return { path: req.path, basePath: http.basePath.get(req) }; }, }, ]); @@ -176,8 +176,8 @@ describe('onPostAuthRequestInterceptor', () => { const httpMock = httpServiceMock.createSetupContract(); - httpMock.getBasePathFor = jest.fn().mockImplementation(() => basePath); - httpMock.setBasePathFor = jest.fn().mockImplementation((req: any, newPath: string) => { + httpMock.basePath.get = jest.fn().mockImplementation(() => basePath); + httpMock.basePath.set = jest.fn().mockImplementation((req: any, newPath: string) => { basePath = newPath; }); httpMock.registerOnPreAuth = jest.fn().mockImplementation(async handler => { diff --git a/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.ts b/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.ts index ce2ab453e91ef..dc3f645b4cd5a 100644 --- a/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.ts +++ b/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.ts @@ -77,7 +77,7 @@ export function initSpacesOnPostAuthRequestInterceptor({ let spaceId: string = ''; let space: Space; try { - spaceId = getSpaceIdFromPath(http.getBasePathFor(request), serverBasePath); + spaceId = getSpaceIdFromPath(http.basePath.get(request), serverBasePath); log.debug(`Verifying access to space "${spaceId}"`); diff --git a/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.test.ts b/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.test.ts index bf76730f3958b..5cc6601fc8a35 100644 --- a/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.test.ts +++ b/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.test.ts @@ -29,14 +29,14 @@ describe('onRequestInterceptor', () => { method: 'GET', path: '/foo', handler: (req: Legacy.Request, h: Legacy.ResponseToolkit) => { - return h.response({ path: req.path, basePath: http.getBasePathFor(req) }); + return h.response({ path: req.path, basePath: http.basePath.get(req) }); }, }, { method: 'GET', path: '/some/path/s/foo/bar', handler: (req: Legacy.Request, h: Legacy.ResponseToolkit) => { - return h.response({ path: req.path, basePath: http.getBasePathFor(req) }); + return h.response({ path: req.path, basePath: http.basePath.get(req) }); }, }, { @@ -45,7 +45,7 @@ describe('onRequestInterceptor', () => { handler: (req: Legacy.Request, h: Legacy.ResponseToolkit) => { return h.response({ path: req.path, - basePath: http.getBasePathFor(req), + basePath: http.basePath.get(req), query: req.query, }); }, @@ -57,13 +57,13 @@ describe('onRequestInterceptor', () => { const router = new Router('/'); router.get({ path: '/foo', validate: false }, (req: KibanaRequest, h: any) => { - return h.ok({ path: req.url.pathname, basePath: http.getBasePathFor(req) }); + return h.ok({ path: req.url.pathname, basePath: http.basePath.get(req) }); }); router.get( { path: '/some/path/s/foo/bar', validate: false }, (req: KibanaRequest, h: any) => { - return h.ok({ path: req.url.pathname, basePath: http.getBasePathFor(req) }); + return h.ok({ path: req.url.pathname, basePath: http.basePath.get(req) }); } ); @@ -83,7 +83,7 @@ describe('onRequestInterceptor', () => { (req: KibanaRequest, h: any) => { return h.ok({ path: req.url.pathname, - basePath: http.getBasePathFor(req), + basePath: http.basePath.get(req), query: req.query, }); } diff --git a/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.ts b/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.ts index 8250d63ac1168..b14201bdff2f6 100644 --- a/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.ts +++ b/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.ts @@ -30,7 +30,7 @@ export function initSpacesOnRequestInterceptor({ config, http }: OnRequestInterc if (spaceId !== DEFAULT_SPACE_ID) { const reqBasePath = `/s/${spaceId}`; - http.setBasePathFor(request, reqBasePath); + http.basePath.set(request, reqBasePath); const newLocation = (path && path.substr(reqBasePath.length)) || '/'; diff --git a/x-pack/plugins/spaces/server/new_platform/plugin.ts b/x-pack/plugins/spaces/server/new_platform/plugin.ts index d7be8b1d89fbb..291c1039ff32a 100644 --- a/x-pack/plugins/spaces/server/new_platform/plugin.ts +++ b/x-pack/plugins/spaces/server/new_platform/plugin.ts @@ -130,7 +130,7 @@ export class Plugin { try { const activeSpace = await getActiveSpace( spacesClient, - core.http.getBasePathFor(request), + core.http.basePath.get(request), this.initializerContext.legacyConfig.get('server.basePath') ); diff --git a/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.test.ts b/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.test.ts index 7c593ca450d77..60e02cb420e1b 100644 --- a/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.test.ts +++ b/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.test.ts @@ -26,7 +26,7 @@ const createService = async () => { const spacesService = new SpacesService(mockLogger, '/base-path'); const httpSetup = httpServiceMock.createSetupContract(); - httpSetup.getBasePathFor = jest.fn().mockImplementation((request: KibanaRequest) => { + httpSetup.basePath.get = jest.fn().mockImplementation((request: KibanaRequest) => { const spaceId = getSpaceIdFromPath(request.url.path); if (spaceId !== DEFAULT_SPACE_ID) { diff --git a/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts b/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts index 4766c23adb67a..14d4cf5fe1441 100644 --- a/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts +++ b/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts @@ -58,7 +58,7 @@ export class SpacesService { const basePath = isFakeRequest ? (request as Record).getBasePath() - : http.getBasePathFor(request); + : http.basePath.get(request); const spaceId = getSpaceIdFromPath(basePath, this.serverBasePath); From a1260b582fcdc9d40704531136520e0e47feec27 Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Tue, 18 Jun 2019 06:52:45 -0400 Subject: [PATCH 64/68] remove commented code --- .../request_interceptors/on_post_auth_interceptor.test.ts | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts b/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts index 00e45d8272d41..c0a75474b7c0f 100644 --- a/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts +++ b/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts @@ -451,13 +451,7 @@ describe('onPostAuthRequestInterceptor', () => { const getHiddenUiAppHandler = jest.fn(() => '
space selector
'); - const response = await request('/', spaces, function setupFn() { - // server.decorate('server', 'getHiddenUiAppById', getHiddenUiAppHandler); - // server.decorate('toolkit', 'renderApp', function renderAppHandler(app: any) { - // // @ts-ignore - // return this.response(app); - // }); - }); + const response = await request('/', spaces); expect(response.statusCode).toEqual(200); expect(response.payload).toEqual('
space selector
'); From a0d2d70dbbf6e0007ba0951014265bc3e9895cc3 Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Tue, 18 Jun 2019 06:53:13 -0400 Subject: [PATCH 65/68] only expose scoped spaces client --- x-pack/plugins/spaces/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/spaces/index.ts b/x-pack/plugins/spaces/index.ts index 3ff669ae1a170..fc05cd16cdb9d 100644 --- a/x-pack/plugins/spaces/index.ts +++ b/x-pack/plugins/spaces/index.ts @@ -86,7 +86,7 @@ export const spaces = (kibana: Record) => request: Record, server: Record ) { - const spacesClient = await server.plugins.spaces.spacesClient.scopedClient(request); + const spacesClient = await server.plugins.spaces.getScopedSpacesClient(request); try { vars.activeSpace = { valid: true, @@ -174,6 +174,6 @@ export const spaces = (kibana: Record) => }); server.expose('getSpaceId', (request: any) => spacesService.getSpaceId(request)); - server.expose('spacesClient', spacesService); + server.expose('getScopedSpacesClient', spacesService.scopedClient); }, }); From c245dcaaf6aeb08a9d332e1c81cdedcd2e553e02 Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Tue, 18 Jun 2019 07:32:50 -0400 Subject: [PATCH 66/68] use OptionalPlugin instead of getSecurity --- x-pack/plugins/security/index.js | 2 +- .../check_privileges_dynamically.test.ts | 2 +- .../lib/authorization/check_privileges_dynamically.ts | 2 +- .../security/server/lib/authorization/service.ts | 2 +- x-pack/plugins/spaces/index.ts | 11 +++++++++-- .../on_post_auth_interceptor.test.ts | 3 ++- .../lib/spaces_tutorial_context_factory.test.ts | 4 ++-- x-pack/plugins/spaces/server/new_platform/plugin.ts | 7 ++++--- .../spaces_service/spaces_service.test.ts | 3 ++- .../new_platform/spaces_service/spaces_service.ts | 8 ++++---- .../routes/api/__fixtures__/create_test_handler.ts | 4 ++-- .../lib/__snapshots__/optional_plugin.test.ts.snap | 0 .../security => }/server/lib/optional_plugin.test.ts | 0 .../security => }/server/lib/optional_plugin.ts | 0 14 files changed, 29 insertions(+), 19 deletions(-) rename x-pack/{plugins/security => }/server/lib/__snapshots__/optional_plugin.test.ts.snap (100%) rename x-pack/{plugins/security => }/server/lib/optional_plugin.test.ts (100%) rename x-pack/{plugins/security => }/server/lib/optional_plugin.ts (100%) diff --git a/x-pack/plugins/security/index.js b/x-pack/plugins/security/index.js index 16e12249acd3d..250c8729b5466 100644 --- a/x-pack/plugins/security/index.js +++ b/x-pack/plugins/security/index.js @@ -32,7 +32,7 @@ import { import { watchStatusAndLicenseToInitialize } from '../../server/lib/watch_status_and_license_to_initialize'; import { SecureSavedObjectsClientWrapper } from './server/lib/saved_objects_client/secure_saved_objects_client_wrapper'; import { deepFreeze } from './server/lib/deep_freeze'; -import { createOptionalPlugin } from './server/lib/optional_plugin'; +import { createOptionalPlugin } from '../../server/lib/optional_plugin'; export const security = (kibana) => new kibana.Plugin({ id: 'security', diff --git a/x-pack/plugins/security/server/lib/authorization/check_privileges_dynamically.test.ts b/x-pack/plugins/security/server/lib/authorization/check_privileges_dynamically.test.ts index 282fb99ca330a..b6d91b287dd2e 100644 --- a/x-pack/plugins/security/server/lib/authorization/check_privileges_dynamically.test.ts +++ b/x-pack/plugins/security/server/lib/authorization/check_privileges_dynamically.test.ts @@ -5,7 +5,7 @@ */ import { SpacesPlugin } from '../../../../spaces/types'; -import { OptionalPlugin } from '../optional_plugin'; +import { OptionalPlugin } from '../../../../../server/lib/optional_plugin'; import { checkPrivilegesDynamicallyWithRequestFactory } from './check_privileges_dynamically'; test(`checkPrivileges.atSpace when spaces is enabled`, async () => { diff --git a/x-pack/plugins/security/server/lib/authorization/check_privileges_dynamically.ts b/x-pack/plugins/security/server/lib/authorization/check_privileges_dynamically.ts index 6b348156a5171..5778ccbc76aff 100644 --- a/x-pack/plugins/security/server/lib/authorization/check_privileges_dynamically.ts +++ b/x-pack/plugins/security/server/lib/authorization/check_privileges_dynamically.ts @@ -13,7 +13,7 @@ import { CheckPrivilegesAtResourceResponse, CheckPrivilegesWithRequest } from '. */ import { SpacesPlugin } from '../../../../spaces/types'; -import { OptionalPlugin } from '../optional_plugin'; +import { OptionalPlugin } from '../../../../../server/lib/optional_plugin'; export type CheckPrivilegesDynamically = ( privilegeOrPrivileges: string | string[] diff --git a/x-pack/plugins/security/server/lib/authorization/service.ts b/x-pack/plugins/security/server/lib/authorization/service.ts index 493bbe1ccf387..f0274056e2505 100644 --- a/x-pack/plugins/security/server/lib/authorization/service.ts +++ b/x-pack/plugins/security/server/lib/authorization/service.ts @@ -10,7 +10,7 @@ import { getClient } from '../../../../../server/lib/get_client_shield'; import { SpacesPlugin } from '../../../../spaces/types'; import { XPackFeature, XPackMainPlugin } from '../../../../xpack_main/xpack_main'; import { APPLICATION_PREFIX } from '../../../common/constants'; -import { OptionalPlugin } from '../optional_plugin'; +import { OptionalPlugin } from '../../../../../server/lib/optional_plugin'; import { Actions, actionsFactory } from './actions'; import { CheckPrivilegesWithRequest, checkPrivilegesWithRequestFactory } from './check_privileges'; import { diff --git a/x-pack/plugins/spaces/index.ts b/x-pack/plugins/spaces/index.ts index fc05cd16cdb9d..4b6b238d20136 100644 --- a/x-pack/plugins/spaces/index.ts +++ b/x-pack/plugins/spaces/index.ts @@ -7,6 +7,7 @@ import * as Rx from 'rxjs'; import { resolve } from 'path'; import KbnServer, { Server } from 'src/legacy/server/kbn_server'; +import { createOptionalPlugin } from '../../server/lib/optional_plugin'; // @ts-ignore import { AuditLogger } from '../../server/lib/audit_logger'; import mappings from './mappings.json'; @@ -21,6 +22,7 @@ import { SpacesHttpServiceSetup, } from './server/new_platform/plugin'; import { initSpacesRequestInterceptors } from './server/lib/request_interceptors'; +import { SecurityPlugin } from '../security'; export const spaces = (kibana: Record) => new kibana.Plugin({ id: 'spaces', @@ -154,8 +156,13 @@ export const spaces = (kibana: Record) => const plugins = { xpackMain: server.plugins.xpack_main, // TODO: Spaces has a circular dependency with Security right now. - // Security is not yet available when init runs, so this is wrapped in a function for the time being. - getSecurity: () => server.plugins.security, + // Security is not yet available when init runs, so this is wrapped in an optional function for the time being. + security: createOptionalPlugin( + server.config(), + 'xpack.security', + server.plugins, + 'security' + ), spaces: this, }; diff --git a/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts b/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts index c0a75474b7c0f..e03be16fdea4f 100644 --- a/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts +++ b/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.test.ts @@ -20,6 +20,7 @@ import { HttpServiceSetup } from 'src/core/server'; import { KibanaConfig, Server } from 'src/legacy/server/kbn_server'; import { XPackMainPlugin } from '../../../../xpack_main/xpack_main'; import { parse } from 'url'; +import { OptionalPlugin } from '../../../../../server/lib/optional_plugin'; // TODO: re-implement on NP describe('onPostAuthRequestInterceptor', () => { @@ -198,7 +199,7 @@ describe('onPostAuthRequestInterceptor', () => { http: httpMock, elasticsearch: elasticsearchServiceMock.createSetupContract(), savedObjects: (savedObjectsService as unknown) as SavedObjectsService, - getSecurity: () => ({} as SecurityPlugin), + security: {} as OptionalPlugin, spacesAuditLogger: {} as SpacesAuditLogger, config$: Rx.of({ maxSpaces: 1000 }), }); diff --git a/x-pack/plugins/spaces/server/lib/spaces_tutorial_context_factory.test.ts b/x-pack/plugins/spaces/server/lib/spaces_tutorial_context_factory.test.ts index 412e550579c61..aab032ef06999 100644 --- a/x-pack/plugins/spaces/server/lib/spaces_tutorial_context_factory.test.ts +++ b/x-pack/plugins/spaces/server/lib/spaces_tutorial_context_factory.test.ts @@ -9,10 +9,10 @@ import { DEFAULT_SPACE_ID } from '../../common/constants'; import { createSpacesTutorialContextFactory } from './spaces_tutorial_context_factory'; import { SpacesService } from '../new_platform/spaces_service'; import { SavedObjectsService } from 'src/legacy/server/kbn_server'; -import { SecurityPlugin } from '../../../security'; import { SpacesAuditLogger } from './audit_logger'; import { elasticsearchServiceMock, httpServiceMock } from '../../../../../src/core/server/mocks'; import { spacesServiceMock } from '../new_platform/spaces_service/spaces_service.mock'; +import { createOptionalPlugin } from '../../../../server/lib/optional_plugin'; const server = { config: () => { @@ -62,7 +62,7 @@ describe('createSpacesTutorialContextFactory', () => { http: httpServiceMock.createSetupContract(), elasticsearch: elasticsearchServiceMock.createSetupContract(), savedObjects: {} as SavedObjectsService, - getSecurity: () => ({} as SecurityPlugin), + security: createOptionalPlugin({ get: () => null }, 'xpack.security', {}, 'security'), spacesAuditLogger: {} as SpacesAuditLogger, config$: Rx.of({ maxSpaces: 1000 }), }); diff --git a/x-pack/plugins/spaces/server/new_platform/plugin.ts b/x-pack/plugins/spaces/server/new_platform/plugin.ts index 291c1039ff32a..e55e5ea028538 100644 --- a/x-pack/plugins/spaces/server/new_platform/plugin.ts +++ b/x-pack/plugins/spaces/server/new_platform/plugin.ts @@ -14,6 +14,7 @@ import { ElasticsearchServiceSetup, } from 'src/core/server'; import { CapabilitiesModifier } from 'src/legacy/server/capabilities'; +import { OptionalPlugin } from '../../../../server/lib/optional_plugin'; import { XPackMainPlugin } from '../../../xpack_main/xpack_main'; import { createDefaultSpace } from '../lib/create_default_space'; // @ts-ignore @@ -59,8 +60,8 @@ export interface SpacesCoreSetup { export interface PluginsSetup { // TODO: Spaces has a circular dependency with Security right now. - // Security is not yet available when init runs, so this is wrapped in a function for the time being. - getSecurity: () => SecurityPlugin | undefined; + // Security is not yet available when init runs, so this is wrapped in an optional plugin for the time being. + security: OptionalPlugin; xpackMain: XPackMainPlugin; // TODO: this is temporary for `watchLicenseAndStatusToInitialize` spaces: any; @@ -110,7 +111,7 @@ export class Plugin { http: core.http, elasticsearch: core.elasticsearch, savedObjects: core.savedObjects, - getSecurity: plugins.getSecurity, + security: plugins.security, spacesAuditLogger, config$: this.config$, }); diff --git a/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.test.ts b/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.test.ts index 60e02cb420e1b..472909a96a621 100644 --- a/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.test.ts +++ b/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.test.ts @@ -11,6 +11,7 @@ import { SavedObjectsService } from 'src/legacy/server/kbn_server'; import { KibanaRequest } from 'src/core/server'; import { DEFAULT_SPACE_ID } from '../../../common/constants'; import { getSpaceIdFromPath } from '../../lib/spaces_url_parser'; +import { createOptionalPlugin } from '../../../../../server/lib/optional_plugin'; const mockLogger = { trace: jest.fn(), @@ -39,7 +40,7 @@ const createService = async () => { http: httpSetup, elasticsearch: elasticsearchServiceMock.createSetupContract(), config$: Rx.of({ maxSpaces: 10 }), - getSecurity: () => undefined, + security: createOptionalPlugin({ get: () => null }, 'xpack.security', {}, 'security'), savedObjects: ({ getSavedObjectsRepository: jest.fn().mockReturnValue(null), } as unknown) as SavedObjectsService, diff --git a/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts b/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts index 14d4cf5fe1441..72cafe1d2758f 100644 --- a/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts +++ b/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts @@ -14,6 +14,7 @@ import { HttpServiceSetup, KibanaRequest, } from 'src/core/server'; +import { OptionalPlugin } from '../../../../../server/lib/optional_plugin'; import { DEFAULT_SPACE_ID } from '../../../common/constants'; import { SecurityPlugin } from '../../../../security'; import { SpacesClient } from '../../lib/spaces_client'; @@ -34,7 +35,7 @@ interface SpacesServiceDeps { http: HttpServiceSetup; elasticsearch: ElasticsearchServiceSetup; savedObjects: SavedObjectsService; - getSecurity: () => SecurityPlugin | undefined; + security: OptionalPlugin; config$: Observable; spacesAuditLogger: any; } @@ -48,7 +49,7 @@ export class SpacesService { http, elasticsearch, savedObjects, - getSecurity, + security, config$, spacesAuditLogger, }: SpacesServiceDeps): Promise { @@ -84,8 +85,7 @@ export class SpacesService { const callWithRequestRepository = savedObjects.getSavedObjectsRepository(callCluster); - const security = getSecurity(); - const authorization = security ? security.authorization : null; + const authorization = security.isEnabled ? security.authorization : null; return new SpacesClient( spacesAuditLogger, diff --git a/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_test_handler.ts b/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_test_handler.ts index d08cadb27021a..f84194160971d 100644 --- a/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_test_handler.ts +++ b/x-pack/plugins/spaces/server/routes/api/__fixtures__/create_test_handler.ts @@ -9,7 +9,7 @@ import { Server } from 'hapi'; import { Legacy } from 'kibana'; import { KibanaConfig } from 'src/legacy/server/kbn_server'; import { httpServiceMock, elasticsearchServiceMock } from 'src/core/server/mocks'; -import { SecurityPlugin } from '../../../../../security'; +import { createOptionalPlugin } from '../../../../../../server/lib/optional_plugin'; import { SpacesClient } from '../../../lib/spaces_client'; import { createSpaces } from './create_spaces'; import { ExternalRouteDeps } from '../external'; @@ -161,7 +161,7 @@ export function createTestHandler( http: httpServiceMock.createSetupContract(), elasticsearch: elasticsearchServiceMock.createSetupContract(), savedObjects: server.savedObjects, - getSecurity: () => ({} as SecurityPlugin), + security: createOptionalPlugin({ get: () => null }, 'xpack.security', {}, 'security'), spacesAuditLogger: {} as SpacesAuditLogger, config$: Rx.of({ maxSpaces: 1000 }), }); diff --git a/x-pack/plugins/security/server/lib/__snapshots__/optional_plugin.test.ts.snap b/x-pack/server/lib/__snapshots__/optional_plugin.test.ts.snap similarity index 100% rename from x-pack/plugins/security/server/lib/__snapshots__/optional_plugin.test.ts.snap rename to x-pack/server/lib/__snapshots__/optional_plugin.test.ts.snap diff --git a/x-pack/plugins/security/server/lib/optional_plugin.test.ts b/x-pack/server/lib/optional_plugin.test.ts similarity index 100% rename from x-pack/plugins/security/server/lib/optional_plugin.test.ts rename to x-pack/server/lib/optional_plugin.test.ts diff --git a/x-pack/plugins/security/server/lib/optional_plugin.ts b/x-pack/server/lib/optional_plugin.ts similarity index 100% rename from x-pack/plugins/security/server/lib/optional_plugin.ts rename to x-pack/server/lib/optional_plugin.ts From d0e87a54fc6843b2169cd47ff683669a97b8c7ce Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Tue, 18 Jun 2019 07:52:57 -0400 Subject: [PATCH 67/68] update imports of Saved Objects Service to use new src/core/server location --- src/core/server/index.ts | 1 + .../plugins/spaces/server/lib/create_default_space.test.ts | 2 +- x-pack/plugins/spaces/server/lib/create_default_space.ts | 3 +-- .../spaces/server/lib/spaces_client/spaces_client.ts | 7 +++---- .../server/lib/spaces_tutorial_context_factory.test.ts | 2 +- x-pack/plugins/spaces/server/new_platform/plugin.ts | 3 ++- .../new_platform/spaces_service/spaces_service.test.ts | 3 +-- .../server/new_platform/spaces_service/spaces_service.ts | 2 +- x-pack/plugins/spaces/server/routes/api/external/index.ts | 3 +-- x-pack/plugins/spaces/server/routes/api/v1/index.ts | 3 ++- 10 files changed, 14 insertions(+), 15 deletions(-) diff --git a/src/core/server/index.ts b/src/core/server/index.ts index a826dd8e02818..0695f4c623ba8 100644 --- a/src/core/server/index.ts +++ b/src/core/server/index.ts @@ -91,6 +91,7 @@ export { SavedObjectsClient, SavedObjectsClientContract, SavedObjectsCreateOptions, + SavedObjectsClientWrapperFactory, SavedObjectsErrorHelpers, SavedObjectsFindOptions, SavedObjectsFindResponse, diff --git a/x-pack/plugins/spaces/server/lib/create_default_space.test.ts b/x-pack/plugins/spaces/server/lib/create_default_space.test.ts index 7c92e1930ff1f..0476bf9ba929b 100644 --- a/x-pack/plugins/spaces/server/lib/create_default_space.test.ts +++ b/x-pack/plugins/spaces/server/lib/create_default_space.test.ts @@ -10,7 +10,7 @@ import * as Rx from 'rxjs'; import Boom from 'boom'; import { getClient } from '../../../../server/lib/get_client_shield'; import { createDefaultSpace } from './create_default_space'; -import { SavedObjectsService } from 'src/legacy/server/kbn_server'; +import { SavedObjectsService } from 'src/core/server'; import { ElasticsearchServiceSetup } from 'src/core/server'; let mockCallWithRequest; diff --git a/x-pack/plugins/spaces/server/lib/create_default_space.ts b/x-pack/plugins/spaces/server/lib/create_default_space.ts index 35507ad9bf694..a7b7281ff75bf 100644 --- a/x-pack/plugins/spaces/server/lib/create_default_space.ts +++ b/x-pack/plugins/spaces/server/lib/create_default_space.ts @@ -7,8 +7,7 @@ import { i18n } from '@kbn/i18n'; import { first } from 'rxjs/operators'; -import { SavedObjectsService } from 'src/legacy/server/kbn_server'; -import { ElasticsearchServiceSetup } from 'src/core/server'; +import { ElasticsearchServiceSetup, SavedObjectsService } from 'src/core/server'; import { DEFAULT_SPACE_ID } from '../../common/constants'; interface Deps { diff --git a/x-pack/plugins/spaces/server/lib/spaces_client/spaces_client.ts b/x-pack/plugins/spaces/server/lib/spaces_client/spaces_client.ts index 5668112fca52e..c9ed21c38aaef 100644 --- a/x-pack/plugins/spaces/server/lib/spaces_client/spaces_client.ts +++ b/x-pack/plugins/spaces/server/lib/spaces_client/spaces_client.ts @@ -5,16 +5,15 @@ */ import Boom from 'boom'; import { omit } from 'lodash'; -import { Headers } from 'src/core/server'; +import { Legacy } from 'kibana'; +import { KibanaRequest } from 'src/core/server'; import { AuthorizationService } from '../../../../security/server/lib/authorization/service'; import { isReservedSpace } from '../../../common/is_reserved_space'; import { Space } from '../../../common/model/space'; import { SpacesAuditLogger } from '../audit_logger'; import { SpacesConfigType } from '../../new_platform/config'; -interface SpacesClientRequestFacade { - headers?: Headers; -} +type SpacesClientRequestFacade = Legacy.Request | KibanaRequest; export class SpacesClient { constructor( private readonly auditLogger: SpacesAuditLogger, diff --git a/x-pack/plugins/spaces/server/lib/spaces_tutorial_context_factory.test.ts b/x-pack/plugins/spaces/server/lib/spaces_tutorial_context_factory.test.ts index aab032ef06999..3eb54c6b4e08e 100644 --- a/x-pack/plugins/spaces/server/lib/spaces_tutorial_context_factory.test.ts +++ b/x-pack/plugins/spaces/server/lib/spaces_tutorial_context_factory.test.ts @@ -8,7 +8,7 @@ import * as Rx from 'rxjs'; import { DEFAULT_SPACE_ID } from '../../common/constants'; import { createSpacesTutorialContextFactory } from './spaces_tutorial_context_factory'; import { SpacesService } from '../new_platform/spaces_service'; -import { SavedObjectsService } from 'src/legacy/server/kbn_server'; +import { SavedObjectsService } from 'src/core/server'; import { SpacesAuditLogger } from './audit_logger'; import { elasticsearchServiceMock, httpServiceMock } from '../../../../../src/core/server/mocks'; import { spacesServiceMock } from '../new_platform/spaces_service/spaces_service.mock'; diff --git a/x-pack/plugins/spaces/server/new_platform/plugin.ts b/x-pack/plugins/spaces/server/new_platform/plugin.ts index e55e5ea028538..5689804c125bd 100644 --- a/x-pack/plugins/spaces/server/new_platform/plugin.ts +++ b/x-pack/plugins/spaces/server/new_platform/plugin.ts @@ -6,7 +6,8 @@ import { ServerRoute } from 'hapi'; import { Observable } from 'rxjs'; -import { KibanaConfig, SavedObjectsService } from 'src/legacy/server/kbn_server'; +import { KibanaConfig } from 'src/legacy/server/kbn_server'; +import { SavedObjectsService } from 'src/core/server'; import { Logger, HttpServiceSetup, diff --git a/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.test.ts b/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.test.ts index 472909a96a621..3382234398717 100644 --- a/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.test.ts +++ b/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.test.ts @@ -7,8 +7,7 @@ import * as Rx from 'rxjs'; import { SpacesService } from './spaces_service'; import { httpServiceMock, elasticsearchServiceMock } from 'src/core/server/mocks'; import { SpacesAuditLogger } from '../../lib/audit_logger'; -import { SavedObjectsService } from 'src/legacy/server/kbn_server'; -import { KibanaRequest } from 'src/core/server'; +import { KibanaRequest, SavedObjectsService } from 'src/core/server'; import { DEFAULT_SPACE_ID } from '../../../common/constants'; import { getSpaceIdFromPath } from '../../lib/spaces_url_parser'; import { createOptionalPlugin } from '../../../../../server/lib/optional_plugin'; diff --git a/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts b/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts index 72cafe1d2758f..05ef42c07f745 100644 --- a/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts +++ b/x-pack/plugins/spaces/server/new_platform/spaces_service/spaces_service.ts @@ -7,12 +7,12 @@ import { map, take } from 'rxjs/operators'; import { Observable, Subscription, combineLatest } from 'rxjs'; import { Legacy } from 'kibana'; -import { SavedObjectsService } from 'src/legacy/server/kbn_server'; import { Logger, ElasticsearchServiceSetup, HttpServiceSetup, KibanaRequest, + SavedObjectsService, } from 'src/core/server'; import { OptionalPlugin } from '../../../../../server/lib/optional_plugin'; import { DEFAULT_SPACE_ID } from '../../../common/constants'; diff --git a/x-pack/plugins/spaces/server/routes/api/external/index.ts b/x-pack/plugins/spaces/server/routes/api/external/index.ts index 14ae6d5df2787..141b65062e3f9 100644 --- a/x-pack/plugins/spaces/server/routes/api/external/index.ts +++ b/x-pack/plugins/spaces/server/routes/api/external/index.ts @@ -5,8 +5,7 @@ */ import { Legacy } from 'kibana'; -import { Logger } from 'src/core/server'; -import { SavedObjectsService } from 'src/legacy/server/kbn_server'; +import { Logger, SavedObjectsService } from 'src/core/server'; import { XPackMainPlugin } from '../../../../../xpack_main/xpack_main'; import { routePreCheckLicense } from '../../../lib/route_pre_check_license'; import { initDeleteSpacesApi } from './delete'; diff --git a/x-pack/plugins/spaces/server/routes/api/v1/index.ts b/x-pack/plugins/spaces/server/routes/api/v1/index.ts index 464043606494c..932c3c869af6b 100644 --- a/x-pack/plugins/spaces/server/routes/api/v1/index.ts +++ b/x-pack/plugins/spaces/server/routes/api/v1/index.ts @@ -4,7 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -import { SavedObjectsService, KibanaConfig } from 'src/legacy/server/kbn_server'; +import { KibanaConfig } from 'src/legacy/server/kbn_server'; +import { SavedObjectsService } from 'src/core/server'; import { XPackMainPlugin } from '../../../../../xpack_main/xpack_main'; import { routePreCheckLicense } from '../../../lib/route_pre_check_license'; import { initInternalSpacesApi } from './spaces'; From a04b6ed714e9beccd1db4f98fa234ed922ce60ff Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Tue, 18 Jun 2019 08:46:40 -0400 Subject: [PATCH 68/68] update core docs --- .../core/server/kibana-plugin-server.md | 2 ++ ...server.savedobjectsclientwrapperfactory.md | 11 +++++++++++ ...savedobjectsclientwrapperoptions.client.md | 11 +++++++++++ ...server.savedobjectsclientwrapperoptions.md | 19 +++++++++++++++++++ ...avedobjectsclientwrapperoptions.request.md | 11 +++++++++++ src/core/server/index.ts | 1 + .../server/saved_objects/service/index.ts | 1 + src/core/server/server.api.md | 15 +++++++++++++++ 8 files changed, 71 insertions(+) create mode 100644 docs/development/core/server/kibana-plugin-server.savedobjectsclientwrapperfactory.md create mode 100644 docs/development/core/server/kibana-plugin-server.savedobjectsclientwrapperoptions.client.md create mode 100644 docs/development/core/server/kibana-plugin-server.savedobjectsclientwrapperoptions.md create mode 100644 docs/development/core/server/kibana-plugin-server.savedobjectsclientwrapperoptions.request.md diff --git a/docs/development/core/server/kibana-plugin-server.md b/docs/development/core/server/kibana-plugin-server.md index ac72ad4f6367d..3c0699485d98f 100644 --- a/docs/development/core/server/kibana-plugin-server.md +++ b/docs/development/core/server/kibana-plugin-server.md @@ -53,6 +53,7 @@ The plugin integrates with the core system via lifecycle events: `setup` | [SavedObjectsBulkCreateObject](./kibana-plugin-server.savedobjectsbulkcreateobject.md) | | | [SavedObjectsBulkGetObject](./kibana-plugin-server.savedobjectsbulkgetobject.md) | | | [SavedObjectsBulkResponse](./kibana-plugin-server.savedobjectsbulkresponse.md) | | +| [SavedObjectsClientWrapperOptions](./kibana-plugin-server.savedobjectsclientwrapperoptions.md) | | | [SavedObjectsCreateOptions](./kibana-plugin-server.savedobjectscreateoptions.md) | | | [SavedObjectsFindOptions](./kibana-plugin-server.savedobjectsfindoptions.md) | | | [SavedObjectsFindResponse](./kibana-plugin-server.savedobjectsfindresponse.md) | | @@ -81,4 +82,5 @@ The plugin integrates with the core system via lifecycle events: `setup` | [RecursiveReadonly](./kibana-plugin-server.recursivereadonly.md) | | | [RouteMethod](./kibana-plugin-server.routemethod.md) | The set of common HTTP methods supported by Kibana routing. | | [SavedObjectsClientContract](./kibana-plugin-server.savedobjectsclientcontract.md) | \#\# SavedObjectsClient errorsSince the SavedObjectsClient has its hands in everything we are a little paranoid about the way we present errors back to to application code. Ideally, all errors will be either:1. Caused by bad implementation (ie. undefined is not a function) and as such unpredictable 2. An error that has been classified and decorated appropriately by the decorators in [SavedObjectsErrorHelpers](./kibana-plugin-server.savedobjectserrorhelpers.md)Type 1 errors are inevitable, but since all expected/handle-able errors should be Type 2 the isXYZError() helpers exposed at SavedObjectsErrorHelpers should be used to understand and manage error responses from the SavedObjectsClient.Type 2 errors are decorated versions of the source error, so if the elasticsearch client threw an error it will be decorated based on its type. That means that rather than looking for error.body.error.type or doing substring checks on error.body.error.reason, just use the helpers to understand the meaning of the error:\`\`\`js if (SavedObjectsErrorHelpers.isNotFoundError(error)) { // handle 404 }if (SavedObjectsErrorHelpers.isNotAuthorizedError(error)) { // 401 handling should be automatic, but in case you wanted to know }// always rethrow the error unless you handle it throw error; \`\`\`\#\#\# 404s from missing indexFrom the perspective of application code and APIs the SavedObjectsClient is a black box that persists objects. One of the internal details that users have no control over is that we use an elasticsearch index for persistance and that index might be missing.At the time of writing we are in the process of transitioning away from the operating assumption that the SavedObjects index is always available. Part of this transition is handling errors resulting from an index missing. These used to trigger a 500 error in most cases, and in others cause 404s with different error messages.From my (Spencer) perspective, a 404 from the SavedObjectsApi is a 404; The object the request/call was targeting could not be found. This is why \#14141 takes special care to ensure that 404 errors are generic and don't distinguish between index missing or document missing.\#\#\# 503s from missing indexUnlike all other methods, create requests are supposed to succeed even when the Kibana index does not exist because it will be automatically created by elasticsearch. When that is not the case it is because Elasticsearch's action.auto_create_index setting prevents it from being created automatically so we throw a special 503 with the intention of informing the user that their Elasticsearch settings need to be updated.See [SavedObjectsErrorHelpers](./kibana-plugin-server.savedobjectserrorhelpers.md) | +| [SavedObjectsClientWrapperFactory](./kibana-plugin-server.savedobjectsclientwrapperfactory.md) | | diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectsclientwrapperfactory.md b/docs/development/core/server/kibana-plugin-server.savedobjectsclientwrapperfactory.md new file mode 100644 index 0000000000000..321aefcba0ffd --- /dev/null +++ b/docs/development/core/server/kibana-plugin-server.savedobjectsclientwrapperfactory.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [SavedObjectsClientWrapperFactory](./kibana-plugin-server.savedobjectsclientwrapperfactory.md) + +## SavedObjectsClientWrapperFactory type + +Signature: + +```typescript +export declare type SavedObjectsClientWrapperFactory = (options: SavedObjectsClientWrapperOptions) => SavedObjectsClientContract; +``` diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectsclientwrapperoptions.client.md b/docs/development/core/server/kibana-plugin-server.savedobjectsclientwrapperoptions.client.md new file mode 100644 index 0000000000000..0545901087bb4 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-server.savedobjectsclientwrapperoptions.client.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [SavedObjectsClientWrapperOptions](./kibana-plugin-server.savedobjectsclientwrapperoptions.md) > [client](./kibana-plugin-server.savedobjectsclientwrapperoptions.client.md) + +## SavedObjectsClientWrapperOptions.client property + +Signature: + +```typescript +client: SavedObjectsClientContract; +``` diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectsclientwrapperoptions.md b/docs/development/core/server/kibana-plugin-server.savedobjectsclientwrapperoptions.md new file mode 100644 index 0000000000000..1a096fd9e5264 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-server.savedobjectsclientwrapperoptions.md @@ -0,0 +1,19 @@ + + +[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [SavedObjectsClientWrapperOptions](./kibana-plugin-server.savedobjectsclientwrapperoptions.md) + +## SavedObjectsClientWrapperOptions interface + +Signature: + +```typescript +export interface SavedObjectsClientWrapperOptions +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [client](./kibana-plugin-server.savedobjectsclientwrapperoptions.client.md) | SavedObjectsClientContract | | +| [request](./kibana-plugin-server.savedobjectsclientwrapperoptions.request.md) | Request | | + diff --git a/docs/development/core/server/kibana-plugin-server.savedobjectsclientwrapperoptions.request.md b/docs/development/core/server/kibana-plugin-server.savedobjectsclientwrapperoptions.request.md new file mode 100644 index 0000000000000..0ff75028612d0 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-server.savedobjectsclientwrapperoptions.request.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [SavedObjectsClientWrapperOptions](./kibana-plugin-server.savedobjectsclientwrapperoptions.md) > [request](./kibana-plugin-server.savedobjectsclientwrapperoptions.request.md) + +## SavedObjectsClientWrapperOptions.request property + +Signature: + +```typescript +request: Request; +``` diff --git a/src/core/server/index.ts b/src/core/server/index.ts index 0695f4c623ba8..5df93863833a9 100644 --- a/src/core/server/index.ts +++ b/src/core/server/index.ts @@ -92,6 +92,7 @@ export { SavedObjectsClientContract, SavedObjectsCreateOptions, SavedObjectsClientWrapperFactory, + SavedObjectsClientWrapperOptions, SavedObjectsErrorHelpers, SavedObjectsFindOptions, SavedObjectsFindResponse, diff --git a/src/core/server/saved_objects/service/index.ts b/src/core/server/saved_objects/service/index.ts index 3b146b2b3ada9..697e1d2d41471 100644 --- a/src/core/server/saved_objects/service/index.ts +++ b/src/core/server/saved_objects/service/index.ts @@ -38,6 +38,7 @@ export { SavedObjectsRepository, ScopedSavedObjectsClientProvider, SavedObjectsClientWrapperFactory, + SavedObjectsClientWrapperOptions, SavedObjectsErrorHelpers, } from './lib'; diff --git a/src/core/server/server.api.md b/src/core/server/server.api.md index a5e36cfc92887..34a9731dbdcf4 100644 --- a/src/core/server/server.api.md +++ b/src/core/server/server.api.md @@ -499,6 +499,21 @@ export class SavedObjectsClient { // @public export type SavedObjectsClientContract = Pick; +// Warning: (ae-missing-release-tag) "SavedObjectsClientWrapperFactory" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type SavedObjectsClientWrapperFactory = (options: SavedObjectsClientWrapperOptions) => SavedObjectsClientContract; + +// Warning: (ae-missing-release-tag) "SavedObjectsClientWrapperOptions" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export interface SavedObjectsClientWrapperOptions { + // (undocumented) + client: SavedObjectsClientContract; + // (undocumented) + request: Request; +} + // @public (undocumented) export interface SavedObjectsCreateOptions extends SavedObjectsBaseOptions { id?: string;