Remove MLs use of internal Spaces utilities (#46366)

* remove MLs use of internal Spaces utilities

* move logic to SpacesService for testability

* make TS happy

* Apply suggestions from code review

Co-Authored-By: Brandon Kobel <brandon.kobel@gmail.com>
This commit is contained in:
Larry Gregory 2019-09-24 14:50:03 -04:00 committed by GitHub
parent 8356addb44
commit 61d78ae838
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 118 additions and 46 deletions

View file

@ -5,8 +5,7 @@
*/
import { Request } from 'hapi';
import { KibanaConfig } from 'src/legacy/server/kbn_server';
import { getActiveSpace } from '../../../spaces/server/lib/get_active_space';
import { SpacesPlugin } from '../../../spaces';
import { Space } from '../../../spaces/common/model/space';
interface GetActiveSpaceResponse {
@ -14,17 +13,12 @@ interface GetActiveSpaceResponse {
space?: Space;
}
export function spacesUtilsProvider(spacesPlugin: any, request: Request, config: KibanaConfig) {
export function spacesUtilsProvider(spacesPlugin: SpacesPlugin, request: Request) {
async function activeSpace(): Promise<GetActiveSpaceResponse> {
const spacesClient = await spacesPlugin.getScopedSpacesClient(request);
try {
return {
valid: true,
space: await getActiveSpace(
spacesClient,
request.getBasePath(),
config.get('server.basePath')
),
space: await spacesPlugin.getActiveSpace(request),
};
} catch (e) {
return {

View file

@ -23,7 +23,6 @@ export function systemRoutes({
elasticsearchPlugin,
route,
xpackMainPlugin,
config,
spacesPlugin
}) {
const callWithInternalUser = callWithInternalUserFactory(elasticsearchPlugin);
@ -101,7 +100,7 @@ export function systemRoutes({
const ignoreSpaces = request.query && request.query.ignoreSpaces === 'true';
// if spaces is disabled force isMlEnabledInSpace to be true
const { isMlEnabledInSpace } = spacesPlugin !== undefined ?
spacesUtilsProvider(spacesPlugin, request, config) :
spacesUtilsProvider(spacesPlugin, request) :
{ isMlEnabledInSpace: async () => true };
const { getPrivileges } = privilegesProvider(callWithRequest, xpackMainPlugin, isMlEnabledInSpace, ignoreSpaces);

View file

@ -22,6 +22,7 @@ test(`checkPrivileges.atSpace when spaces is enabled`, async () => {
namespaceToSpaceId: jest.fn(),
getBasePath: jest.fn(),
getScopedSpacesClient: jest.fn(),
getActiveSpace: jest.fn(),
} as OptionalPlugin<SpacesPlugin>;
const request = Symbol();
const privilegeOrPrivileges = ['foo', 'bar'];

View file

@ -23,6 +23,7 @@ import { initSpaceSelectorView } from './server/routes/views';
export interface SpacesPlugin {
getSpaceId: SpacesServiceSetup['getSpaceId'];
getActiveSpace: SpacesServiceSetup['getActiveSpace'];
spaceIdToNamespace: SpacesServiceSetup['spaceIdToNamespace'];
namespaceToSpaceId: SpacesServiceSetup['namespaceToSpaceId'];
getBasePath: SpacesServiceSetup['getBasePath'];
@ -183,6 +184,7 @@ export const spaces = (kibana: Record<string, any>) =>
initSpaceSelectorView(server);
server.expose('getSpaceId', (request: any) => spacesService.getSpaceId(request));
server.expose('getActiveSpace', spacesService.getActiveSpace);
server.expose('spaceIdToNamespace', spacesService.spaceIdToNamespace);
server.expose('namespaceToSpaceId', spacesService.namespaceToSpaceId);
server.expose('getBasePath', spacesService.getBasePath);

View file

@ -17,6 +17,7 @@ const createSetupContractMock = (spaceId = DEFAULT_SPACE_ID) => {
scopedClient: jest.fn().mockResolvedValue(spacesClientMock.create()),
namespaceToSpaceId: jest.fn().mockImplementation(namespaceToSpaceId),
spaceIdToNamespace: jest.fn().mockImplementation(spaceIdToNamespace),
getActiveSpace: jest.fn(),
};
return setupContract;
};

View file

@ -7,7 +7,7 @@ import * as Rx from 'rxjs';
import { SpacesService } from './spaces_service';
import { coreMock, elasticsearchServiceMock } from 'src/core/server/mocks';
import { SpacesAuditLogger } from '../../lib/audit_logger';
import { KibanaRequest, SavedObjectsService } from 'src/core/server';
import { KibanaRequest, SavedObjectsService, SavedObjectsErrorHelpers } 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';
@ -29,7 +29,30 @@ const createService = async (serverBasePath: string = '') => {
serverBasePath,
},
savedObjects: ({
getSavedObjectsRepository: jest.fn().mockReturnValue(null),
getSavedObjectsRepository: jest.fn().mockReturnValue({
get: jest.fn().mockImplementation((type, id) => {
if (type === 'space' && id === 'foo') {
return Promise.resolve({
id: 'space:foo',
attributes: {
name: 'Foo Space',
disabledFeatures: [],
},
});
}
if (type === 'space' && id === 'default') {
return Promise.resolve({
id: 'space:default',
attributes: {
name: 'Default Space',
disabledFeatures: [],
_reserved: true,
},
});
}
throw SavedObjectsErrorHelpers.createGenericNotFoundError(type, id);
}),
}),
} as unknown) as SavedObjectsService,
} as LegacyAPI;
@ -149,4 +172,46 @@ describe('SpacesService', () => {
expect(spacesServiceSetup.namespaceToSpaceId('foo')).toEqual('foo');
});
});
describe('#getActiveSpace', () => {
it('returns the default space when in the default space', async () => {
const spacesServiceSetup = await createService();
const request = {
url: { path: 'app/kibana' },
} as KibanaRequest;
const activeSpace = await spacesServiceSetup.getActiveSpace(request);
expect(activeSpace).toEqual({
id: 'space:default',
name: 'Default Space',
disabledFeatures: [],
_reserved: true,
});
});
it('returns the space for the current (non-default) space', async () => {
const spacesServiceSetup = await createService();
const request = {
url: { path: '/s/foo/app/kibana' },
} as KibanaRequest;
const activeSpace = await spacesServiceSetup.getActiveSpace(request);
expect(activeSpace).toEqual({
id: 'space:foo',
name: 'Foo Space',
disabledFeatures: [],
});
});
it('propagates errors from the repository', async () => {
const spacesServiceSetup = await createService();
const request = {
url: { path: '/s/unknown-space/app/kibana' },
} as KibanaRequest;
expect(spacesServiceSetup.getActiveSpace(request)).rejects.toThrowErrorMatchingInlineSnapshot(
`"Saved object [space/unknown-space] not found"`
);
});
});
});

View file

@ -16,6 +16,7 @@ import { getSpaceIdFromPath, addSpaceIdToPath } from '../../lib/spaces_url_parse
import { SpacesConfigType } from '../config';
import { namespaceToSpaceId, spaceIdToNamespace } from '../../lib/utils/namespace';
import { LegacyAPI } from '../plugin';
import { Space } from '../../../common/model/space';
type RequestFacade = KibanaRequest | Legacy.Request;
@ -31,6 +32,8 @@ export interface SpacesServiceSetup {
spaceIdToNamespace(spaceId: string): string | undefined;
namespaceToSpaceId(namespace: string | undefined): string;
getActiveSpace(request: RequestFacade): Promise<Space>;
}
interface SpacesServiceDeps {
@ -66,6 +69,41 @@ export class SpacesService {
return spaceId;
};
const getScopedClient = async (request: RequestFacade) => {
return combineLatest(elasticsearch.adminClient$, config$)
.pipe(
map(([clusterClient, config]) => {
const internalRepository = this.getLegacyAPI().savedObjects.getSavedObjectsRepository(
clusterClient.callAsInternalUser,
['space']
);
const callCluster = clusterClient.asScoped(request).callAsCurrentUser;
const callWithRequestRepository = this.getLegacyAPI().savedObjects.getSavedObjectsRepository(
callCluster,
['space']
);
const authorization = security.isEnabled ? security.authorization : null;
return new SpacesClient(
getSpacesAuditLogger(),
(message: string) => {
this.log.debug(message);
},
authorization,
callWithRequestRepository,
config,
internalRepository,
request
);
}),
take(1)
)
.toPromise();
};
return {
getSpaceId,
getBasePath: (spaceId: string) => {
@ -81,39 +119,11 @@ export class SpacesService {
},
spaceIdToNamespace,
namespaceToSpaceId,
scopedClient: async (request: RequestFacade) => {
return combineLatest(elasticsearch.adminClient$, config$)
.pipe(
map(([clusterClient, config]) => {
const internalRepository = this.getLegacyAPI().savedObjects.getSavedObjectsRepository(
clusterClient.callAsInternalUser,
['space']
);
const callCluster = clusterClient.asScoped(request).callAsCurrentUser;
const callWithRequestRepository = this.getLegacyAPI().savedObjects.getSavedObjectsRepository(
callCluster,
['space']
);
const authorization = security.isEnabled ? security.authorization : null;
return new SpacesClient(
getSpacesAuditLogger(),
(message: string) => {
this.log.debug(message);
},
authorization,
callWithRequestRepository,
config,
internalRepository,
request
);
}),
take(1)
)
.toPromise();
scopedClient: getScopedClient,
getActiveSpace: async (request: RequestFacade) => {
const spaceId = getSpaceId(request);
const spacesClient = await getScopedClient(request);
return spacesClient.get(spaceId);
},
};
}