-
Notifications
You must be signed in to change notification settings - Fork 8.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Spaces] Create Default Space on startup (#19177)
When Kibana starts, a Default Space will be created if one does not already exist. The Default Space will contain all objects that are not currently assigned to any other space (i.e., objects created prior to Spaces being enabled, or objects created directly within the Default Space). To enable this, this PR also introduces the concept of Reserved Spaces, which is denoted by a `_reserved` property on the `space` object. Reserved Spaces: 1. Cannot be deleted 2. Cannot have their URL Context Changed This PR does not address: 1. Disabling the UI for reserved roles - this will be enabled via #19035 once this PR is merged into it.
- Loading branch information
Showing
12 changed files
with
666 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 const DEFAULT_SPACE_ID = `default`; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
/* | ||
* 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 { get } from 'lodash'; | ||
|
||
/** | ||
* Returns whether the given Space is reserved or not. | ||
* | ||
* @param space the space | ||
* @returns boolean | ||
*/ | ||
export function isReservedSpace(space) { | ||
return get(space, '_reserved', false); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
/* | ||
* 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 { isReservedSpace } from './is_reserved_space'; | ||
|
||
test('it returns true for reserved spaces', () => { | ||
const space = { | ||
_reserved: true | ||
}; | ||
|
||
expect(isReservedSpace(space)).toEqual(true); | ||
}); | ||
|
||
test('it returns false for non-reserved spaces', () => { | ||
const space = {}; | ||
|
||
expect(isReservedSpace(space)).toEqual(false); | ||
}); | ||
|
||
test('it handles empty imput', () => { | ||
expect(isReservedSpace()).toEqual(false); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
/* | ||
* 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 { getClient } from '../../../../server/lib/get_client_shield'; | ||
import { DEFAULT_SPACE_ID } from '../../common/constants'; | ||
|
||
export async function createDefaultSpace(server) { | ||
const { callWithInternalUser: callCluster } = getClient(server); | ||
|
||
const savedObjectsClient = server.savedObjectsClientFactory({ callCluster }); | ||
|
||
const defaultSpaceExists = await doesDefaultSpaceExist(savedObjectsClient); | ||
|
||
if (defaultSpaceExists) { | ||
return; | ||
} | ||
|
||
const options = { | ||
id: DEFAULT_SPACE_ID | ||
}; | ||
|
||
await savedObjectsClient.create('space', { | ||
name: 'Default Space', | ||
description: 'This is your Default Space!', | ||
urlContext: '', | ||
_reserved: true | ||
}, options); | ||
} | ||
|
||
async function doesDefaultSpaceExist(savedObjectsClient) { | ||
try { | ||
await savedObjectsClient.get('space', DEFAULT_SPACE_ID); | ||
return true; | ||
} catch (e) { | ||
if (savedObjectsClient.errors.isNotFoundError(e)) { | ||
return false; | ||
} | ||
throw e; | ||
} | ||
} |
98 changes: 98 additions & 0 deletions
98
x-pack/plugins/spaces/server/lib/create_default_space.test.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
/* | ||
* 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 Boom from 'boom'; | ||
import { getClient } from '../../../../server/lib/get_client_shield'; | ||
import { createDefaultSpace } from './create_default_space'; | ||
|
||
jest.mock('../../../../server/lib/get_client_shield', () => ({ | ||
getClient: jest.fn() | ||
})); | ||
|
||
let mockCallWithRequest; | ||
beforeEach(() => { | ||
mockCallWithRequest = jest.fn(); | ||
getClient.mockReturnValue({ | ||
callWithRequest: mockCallWithRequest | ||
}); | ||
}); | ||
|
||
const createMockServer = (settings = {}) => { | ||
|
||
const { | ||
defaultExists = false | ||
} = settings; | ||
|
||
const mockServer = { | ||
config: jest.fn().mockReturnValue({ | ||
get: jest.fn() | ||
}), | ||
savedObjectsClientFactory: jest.fn().mockReturnValue({ | ||
get: jest.fn().mockImplementation(() => { | ||
if (defaultExists) { | ||
return; | ||
} | ||
throw Boom.notFound('unit test: default space not found'); | ||
}), | ||
create: jest.fn().mockReturnValue(), | ||
errors: { | ||
isNotFoundError: (e) => e.message === 'unit test: default space not found' | ||
} | ||
}) | ||
}; | ||
|
||
mockServer.config().get.mockImplementation(key => { | ||
return settings[key]; | ||
}); | ||
|
||
return mockServer; | ||
}; | ||
|
||
test(`it creates the default space when one does not exist`, async () => { | ||
const server = createMockServer({ | ||
defaultExists: false | ||
}); | ||
|
||
await createDefaultSpace(server); | ||
|
||
const client = server.savedObjectsClientFactory(); | ||
|
||
expect(client.get).toHaveBeenCalledTimes(1); | ||
expect(client.create).toHaveBeenCalledTimes(1); | ||
expect(client.create).toHaveBeenCalledWith( | ||
'space', | ||
{ "_reserved": true, "description": "This is your Default Space!", "name": "Default Space", "urlContext": "" }, | ||
{ "id": "default" } | ||
); | ||
}); | ||
|
||
test(`it does not attempt to recreate the default space if it already exists`, async () => { | ||
const server = createMockServer({ | ||
defaultExists: true | ||
}); | ||
|
||
await createDefaultSpace(server); | ||
|
||
const client = server.savedObjectsClientFactory(); | ||
|
||
expect(client.get).toHaveBeenCalledTimes(1); | ||
expect(client.create).toHaveBeenCalledTimes(0); | ||
}); | ||
|
||
test(`it throws all other errors from the saved objects client`, async () => { | ||
const server = createMockServer({ | ||
defaultExists: true, | ||
}); | ||
|
||
const client = server.savedObjectsClientFactory(); | ||
client.get = () => { throw new Error('unit test: unexpected exception condition'); }; | ||
|
||
try { | ||
await createDefaultSpace(server); | ||
throw new Error(`Expected error to be thrown!`); | ||
} catch (e) { | ||
expect(e.message).toEqual('unit test: unexpected exception condition'); | ||
} | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.