mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
[Serverless] Add internal uiSettings routes and expose public routes in self-managed only (#160499)
Partially addresses https://github.com/elastic/kibana/issues/159590 ## Summary This PR adds an an internal uiSettings API that is a duplicate of the public API and is intended for use by the browser-side uiSettings client. The PR also adds a config settings that is configured in serverless context only and exposes the public uiSettings routes based on the value of this setting (it defaults to false since we don't want to expose the public routes in serverless). **How to test:** I. Verify that in serverless the internal routes are exposed but the public ones aren't: 1. Start Es with `yarn es snapshot` and Kibana with `yarn serverless-{mode}` where `{mode}` can be `es`, `oblt`, or `security` (the public routes should be disabled for all projects). 2. Verify that the public endpoints are not accessible. For example, `curl --user elastic:changeme 'http://localhost:5601/zhb/api/kibana/settings' -X 'GET'` should return `{"statusCode":404,"error":"Not Found","message":"Not Found"}`. 3. Verify that the internal endpoints are accessible. For example, `curl --user elastic:changeme 'http://localhost:5601/zhb/internal/kibana/settings' -X 'GET'` should return `{"settings":{"buildNum":{"userValue":9007199254740991},"isDefaultIndexMigrated":{"userValue":true},"defaultRoute":{"isOverridden":true,"userValue":"/app/elasticsearch"}}}` II. Verify that the both public and internal routes are exposed in self-managed: 1. Start Es with `yarn es snapshot` and Kibana with `yarn start` 2. Verify that the public endpoints are accessible. For example, `curl --user elastic:changeme 'http://localhost:5601/zhb/api/kibana/settings' -X 'GET'` should return `{"settings":{"buildNum":{"userValue":9007199254740991},"isDefaultIndexMigrated":{"userValue":true}}}` 3. Verify that the internal endpoints are accessible. For example, `curl --user elastic:changeme 'http://localhost:5601/zhb/internal/kibana/settings' -X 'GET'` should return `{"settings":{"buildNum":{"userValue":9007199254740991},"isDefaultIndexMigrated":{"userValue":true}}}` III. Verify that the plugins/services that consume the internal uiSettings endpoints work as expected in both self-managed and serverless environment. ### For maintainers - [ ] This was checked for breaking API changes and was [labeled appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
9746a50a01
commit
41056193d9
21 changed files with 451 additions and 51 deletions
|
@ -3,7 +3,7 @@
|
|||
exports[`#batchSet Buffers are always clear of previously buffered changes: two requests, second only sends bar, not foo 1`] = `
|
||||
Array [
|
||||
Array [
|
||||
"/foo/bar/api/kibana/settings",
|
||||
"/foo/bar/internal/kibana/settings",
|
||||
Object {
|
||||
"headers": Object {
|
||||
"accept": "application/json",
|
||||
|
@ -15,7 +15,7 @@ Array [
|
|||
},
|
||||
],
|
||||
Array [
|
||||
"/foo/bar/api/kibana/settings",
|
||||
"/foo/bar/internal/kibana/settings",
|
||||
Object {
|
||||
"headers": Object {
|
||||
"accept": "application/json",
|
||||
|
@ -32,7 +32,7 @@ Array [
|
|||
exports[`#batchSet Overwrites previously buffered values with new values for the same key: two requests, foo=d in final 1`] = `
|
||||
Array [
|
||||
Array [
|
||||
"/foo/bar/api/kibana/settings",
|
||||
"/foo/bar/internal/kibana/settings",
|
||||
Object {
|
||||
"headers": Object {
|
||||
"accept": "application/json",
|
||||
|
@ -44,7 +44,7 @@ Array [
|
|||
},
|
||||
],
|
||||
Array [
|
||||
"/foo/bar/api/kibana/settings",
|
||||
"/foo/bar/internal/kibana/settings",
|
||||
Object {
|
||||
"headers": Object {
|
||||
"accept": "application/json",
|
||||
|
@ -61,7 +61,7 @@ Array [
|
|||
exports[`#batchSet buffers changes while first request is in progress, sends buffered changes after first request completes: final, includes both requests 1`] = `
|
||||
Array [
|
||||
Array [
|
||||
"/foo/bar/api/kibana/settings",
|
||||
"/foo/bar/internal/kibana/settings",
|
||||
Object {
|
||||
"headers": Object {
|
||||
"accept": "application/json",
|
||||
|
@ -73,7 +73,7 @@ Array [
|
|||
},
|
||||
],
|
||||
Array [
|
||||
"/foo/bar/api/kibana/settings",
|
||||
"/foo/bar/internal/kibana/settings",
|
||||
Object {
|
||||
"headers": Object {
|
||||
"accept": "application/json",
|
||||
|
@ -113,7 +113,7 @@ exports[`#batchSet rejects on 500 1`] = `"Request failed with status code: 500"`
|
|||
exports[`#batchSet sends a single change immediately: single change 1`] = `
|
||||
Array [
|
||||
Array [
|
||||
"/foo/bar/api/kibana/settings",
|
||||
"/foo/bar/internal/kibana/settings",
|
||||
Object {
|
||||
"headers": Object {
|
||||
"accept": "application/json",
|
||||
|
@ -130,7 +130,7 @@ Array [
|
|||
exports[`#batchSetGlobal Buffers are always clear of previously buffered changes: two requests, second only sends bar, not foo 1`] = `
|
||||
Array [
|
||||
Array [
|
||||
"/foo/bar/api/kibana/global_settings",
|
||||
"/foo/bar/internal/kibana/global_settings",
|
||||
Object {
|
||||
"headers": Object {
|
||||
"accept": "application/json",
|
||||
|
@ -142,7 +142,7 @@ Array [
|
|||
},
|
||||
],
|
||||
Array [
|
||||
"/foo/bar/api/kibana/global_settings",
|
||||
"/foo/bar/internal/kibana/global_settings",
|
||||
Object {
|
||||
"headers": Object {
|
||||
"accept": "application/json",
|
||||
|
@ -159,7 +159,7 @@ Array [
|
|||
exports[`#batchSetGlobal Overwrites previously buffered values with new values for the same key: two requests, foo=d in final 1`] = `
|
||||
Array [
|
||||
Array [
|
||||
"/foo/bar/api/kibana/global_settings",
|
||||
"/foo/bar/internal/kibana/global_settings",
|
||||
Object {
|
||||
"headers": Object {
|
||||
"accept": "application/json",
|
||||
|
@ -171,7 +171,7 @@ Array [
|
|||
},
|
||||
],
|
||||
Array [
|
||||
"/foo/bar/api/kibana/global_settings",
|
||||
"/foo/bar/internal/kibana/global_settings",
|
||||
Object {
|
||||
"headers": Object {
|
||||
"accept": "application/json",
|
||||
|
@ -188,7 +188,7 @@ Array [
|
|||
exports[`#batchSetGlobal buffers changes while first request is in progress, sends buffered changes after first request completes: final, includes both requests 1`] = `
|
||||
Array [
|
||||
Array [
|
||||
"/foo/bar/api/kibana/global_settings",
|
||||
"/foo/bar/internal/kibana/global_settings",
|
||||
Object {
|
||||
"headers": Object {
|
||||
"accept": "application/json",
|
||||
|
@ -200,7 +200,7 @@ Array [
|
|||
},
|
||||
],
|
||||
Array [
|
||||
"/foo/bar/api/kibana/global_settings",
|
||||
"/foo/bar/internal/kibana/global_settings",
|
||||
Object {
|
||||
"headers": Object {
|
||||
"accept": "application/json",
|
||||
|
@ -240,7 +240,7 @@ exports[`#batchSetGlobal rejects on 500 1`] = `"Request failed with status code:
|
|||
exports[`#batchSetGlobal sends a single change immediately: single change 1`] = `
|
||||
Array [
|
||||
Array [
|
||||
"/foo/bar/api/kibana/global_settings",
|
||||
"/foo/bar/internal/kibana/global_settings",
|
||||
Object {
|
||||
"headers": Object {
|
||||
"accept": "application/json",
|
||||
|
|
|
@ -137,7 +137,8 @@ export class UiSettingsApi {
|
|||
|
||||
try {
|
||||
this.sendInProgress = true;
|
||||
const path = scope === 'namespace' ? '/api/kibana/settings' : '/api/kibana/global_settings';
|
||||
const path =
|
||||
scope === 'namespace' ? '/internal/kibana/settings' : '/internal/kibana/global_settings';
|
||||
changes.callback(
|
||||
undefined,
|
||||
await this.sendRequest('POST', path, {
|
||||
|
|
|
@ -18,3 +18,5 @@ export function registerRoutes(router: InternalUiSettingsRouter) {
|
|||
registerSetRoute(router);
|
||||
registerSetManyRoute(router);
|
||||
}
|
||||
|
||||
export { registerInternalRoutes } from './internal';
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { schema } from '@kbn/config-schema';
|
||||
|
||||
import { SavedObjectsErrorHelpers } from '@kbn/core-saved-objects-server';
|
||||
import { IUiSettingsClient } from '@kbn/core-ui-settings-server';
|
||||
import { KibanaRequest, KibanaResponseFactory } from '@kbn/core-http-server';
|
||||
import type { InternalUiSettingsRouter } from '../../internal_types';
|
||||
import { CannotOverrideError } from '../../ui_settings_errors';
|
||||
import { InternalUiSettingsRequestHandlerContext } from '../../internal_types';
|
||||
|
||||
const validate = {
|
||||
params: schema.object({
|
||||
key: schema.string(),
|
||||
}),
|
||||
};
|
||||
|
||||
export function registerInternalDeleteRoute(router: InternalUiSettingsRouter) {
|
||||
const deleteFromRequest = async (
|
||||
uiSettingsClient: IUiSettingsClient,
|
||||
context: InternalUiSettingsRequestHandlerContext,
|
||||
request: KibanaRequest<Readonly<{} & { key: string }>, unknown, unknown, 'delete'>,
|
||||
response: KibanaResponseFactory
|
||||
) => {
|
||||
try {
|
||||
await uiSettingsClient.remove(request.params.key);
|
||||
|
||||
return response.ok({
|
||||
body: {
|
||||
settings: await uiSettingsClient.getUserProvided(),
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
if (SavedObjectsErrorHelpers.isSavedObjectsClientError(error)) {
|
||||
return response.customError({
|
||||
body: error,
|
||||
statusCode: error.output.statusCode,
|
||||
});
|
||||
}
|
||||
|
||||
if (error instanceof CannotOverrideError) {
|
||||
return response.badRequest({ body: error });
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
router.delete(
|
||||
{ path: '/internal/kibana/settings/{key}', validate, options: { access: 'internal' } },
|
||||
async (context, request, response) => {
|
||||
const uiSettingsClient = (await context.core).uiSettings.client;
|
||||
return await deleteFromRequest(uiSettingsClient, context, request, response);
|
||||
}
|
||||
);
|
||||
router.delete(
|
||||
{ path: '/internal/kibana/global_settings/{key}', validate, options: { access: 'internal' } },
|
||||
async (context, request, response) => {
|
||||
const uiSettingsClient = (await context.core).uiSettings.globalClient;
|
||||
return await deleteFromRequest(uiSettingsClient, context, request, response);
|
||||
}
|
||||
);
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { SavedObjectsErrorHelpers } from '@kbn/core-saved-objects-server';
|
||||
import { IUiSettingsClient } from '@kbn/core-ui-settings-server';
|
||||
import { KibanaRequest, KibanaResponseFactory } from '@kbn/core-http-server';
|
||||
import { InternalUiSettingsRequestHandlerContext } from '../../internal_types';
|
||||
import type { InternalUiSettingsRouter } from '../../internal_types';
|
||||
|
||||
export function registerInternalGetRoute(router: InternalUiSettingsRouter) {
|
||||
const getFromRequest = async (
|
||||
uiSettingsClient: IUiSettingsClient,
|
||||
context: InternalUiSettingsRequestHandlerContext,
|
||||
request: KibanaRequest<unknown, unknown, unknown, 'get'>,
|
||||
response: KibanaResponseFactory
|
||||
) => {
|
||||
try {
|
||||
return response.ok({
|
||||
body: {
|
||||
settings: await uiSettingsClient.getUserProvided(),
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
if (SavedObjectsErrorHelpers.isSavedObjectsClientError(error)) {
|
||||
return response.customError({
|
||||
body: error,
|
||||
statusCode: error.output.statusCode,
|
||||
});
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
router.get(
|
||||
{ path: '/internal/kibana/settings', validate: false, options: { access: 'internal' } },
|
||||
async (context, request, response) => {
|
||||
const uiSettingsClient = (await context.core).uiSettings.client;
|
||||
return await getFromRequest(uiSettingsClient, context, request, response);
|
||||
}
|
||||
);
|
||||
router.get(
|
||||
{ path: '/internal/kibana/global_settings', validate: false, options: { access: 'internal' } },
|
||||
async (context, request, response) => {
|
||||
const uiSettingsClient = (await context.core).uiSettings.globalClient;
|
||||
return await getFromRequest(uiSettingsClient, context, request, response);
|
||||
}
|
||||
);
|
||||
}
|
|
@ -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
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import type { InternalUiSettingsRouter } from '../../internal_types';
|
||||
import { registerInternalDeleteRoute } from './delete';
|
||||
import { registerInternalGetRoute } from './get';
|
||||
import { registerInternalSetManyRoute } from './set_many';
|
||||
import { registerInternalSetRoute } from './set';
|
||||
|
||||
export function registerInternalRoutes(router: InternalUiSettingsRouter) {
|
||||
registerInternalGetRoute(router);
|
||||
registerInternalDeleteRoute(router);
|
||||
registerInternalSetRoute(router);
|
||||
registerInternalSetManyRoute(router);
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { schema, ValidationError } from '@kbn/config-schema';
|
||||
import { KibanaRequest, KibanaResponseFactory } from '@kbn/core-http-server';
|
||||
import { SavedObjectsErrorHelpers } from '@kbn/core-saved-objects-server';
|
||||
import { IUiSettingsClient } from '@kbn/core-ui-settings-server';
|
||||
import type {
|
||||
InternalUiSettingsRequestHandlerContext,
|
||||
InternalUiSettingsRouter,
|
||||
} from '../../internal_types';
|
||||
import { CannotOverrideError } from '../../ui_settings_errors';
|
||||
|
||||
const validate = {
|
||||
params: schema.object({
|
||||
key: schema.string(),
|
||||
}),
|
||||
body: schema.object({
|
||||
value: schema.any(),
|
||||
}),
|
||||
};
|
||||
|
||||
export function registerInternalSetRoute(router: InternalUiSettingsRouter) {
|
||||
const setFromRequest = async (
|
||||
uiSettingsClient: IUiSettingsClient,
|
||||
context: InternalUiSettingsRequestHandlerContext,
|
||||
request: KibanaRequest<
|
||||
Readonly<{} & { key: string }>,
|
||||
unknown,
|
||||
Readonly<{ value?: any } & {}>,
|
||||
'post'
|
||||
>,
|
||||
response: KibanaResponseFactory
|
||||
) => {
|
||||
try {
|
||||
const { key } = request.params;
|
||||
const { value } = request.body;
|
||||
|
||||
await uiSettingsClient.set(key, value);
|
||||
|
||||
return response.ok({
|
||||
body: {
|
||||
settings: await uiSettingsClient.getUserProvided(),
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
if (SavedObjectsErrorHelpers.isSavedObjectsClientError(error)) {
|
||||
return response.customError({
|
||||
body: error,
|
||||
statusCode: error.output.statusCode,
|
||||
});
|
||||
}
|
||||
|
||||
if (error instanceof CannotOverrideError || error instanceof ValidationError) {
|
||||
return response.badRequest({ body: error });
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
router.post(
|
||||
{ path: '/internal/kibana/settings/{key}', validate, options: { access: 'internal' } },
|
||||
async (context, request, response) => {
|
||||
const uiSettingsClient = (await context.core).uiSettings.client;
|
||||
return await setFromRequest(uiSettingsClient, context, request, response);
|
||||
}
|
||||
);
|
||||
router.post(
|
||||
{ path: '/internal/kibana/global_settings/{key}', validate, options: { access: 'internal' } },
|
||||
async (context, request, response) => {
|
||||
const uiSettingsClient = (await context.core).uiSettings.globalClient;
|
||||
return await setFromRequest(uiSettingsClient, context, request, response);
|
||||
}
|
||||
);
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { schema, ValidationError } from '@kbn/config-schema';
|
||||
import { SavedObjectsErrorHelpers } from '@kbn/core-saved-objects-server';
|
||||
import { KibanaRequest, KibanaResponseFactory } from '@kbn/core-http-server';
|
||||
import { IUiSettingsClient } from '@kbn/core-ui-settings-server';
|
||||
import type { InternalUiSettingsRouter } from '../../internal_types';
|
||||
import { CannotOverrideError } from '../../ui_settings_errors';
|
||||
import { InternalUiSettingsRequestHandlerContext } from '../../internal_types';
|
||||
|
||||
const validate = {
|
||||
body: schema.object({
|
||||
changes: schema.object({}, { unknowns: 'allow' }),
|
||||
}),
|
||||
};
|
||||
|
||||
export function registerInternalSetManyRoute(router: InternalUiSettingsRouter) {
|
||||
const setManyFromRequest = async (
|
||||
uiSettingsClient: IUiSettingsClient,
|
||||
context: InternalUiSettingsRequestHandlerContext,
|
||||
request: KibanaRequest<unknown, unknown, Readonly<{} & { changes?: any & {} }>, 'post'>,
|
||||
response: KibanaResponseFactory
|
||||
) => {
|
||||
try {
|
||||
const { changes } = request.body;
|
||||
|
||||
await uiSettingsClient.setMany(changes);
|
||||
|
||||
return response.ok({
|
||||
body: {
|
||||
settings: await uiSettingsClient.getUserProvided(),
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
if (SavedObjectsErrorHelpers.isSavedObjectsClientError(error)) {
|
||||
return response.customError({
|
||||
body: error,
|
||||
statusCode: error.output.statusCode,
|
||||
});
|
||||
}
|
||||
|
||||
if (error instanceof CannotOverrideError || error instanceof ValidationError) {
|
||||
return response.badRequest({ body: error });
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
router.post(
|
||||
{ path: '/internal/kibana/settings', validate, options: { access: 'internal' } },
|
||||
async (context, request, response) => {
|
||||
const uiSettingsClient = (await context.core).uiSettings.client;
|
||||
return await setManyFromRequest(uiSettingsClient, context, request, response);
|
||||
}
|
||||
);
|
||||
|
||||
router.post(
|
||||
{ path: '/internal/kibana/global_settings', validate, options: { access: 'internal' } },
|
||||
async (context, request, response) => {
|
||||
const uiSettingsClient = (await context.core).uiSettings.globalClient;
|
||||
return await setManyFromRequest(uiSettingsClient, context, request, response);
|
||||
}
|
||||
);
|
||||
}
|
|
@ -17,6 +17,12 @@ const deprecations: ConfigDeprecationProvider = ({ unused, renameFromRoot }) =>
|
|||
|
||||
const configSchema = schema.object({
|
||||
overrides: schema.object({}, { unknowns: 'allow' }),
|
||||
publicApiEnabled: schema.conditional(
|
||||
schema.contextRef('serverless'),
|
||||
true,
|
||||
schema.boolean({ defaultValue: false }),
|
||||
schema.never()
|
||||
),
|
||||
});
|
||||
|
||||
export type UiSettingsConfigType = TypeOf<typeof configSchema>;
|
||||
|
|
|
@ -25,7 +25,7 @@ import type {
|
|||
} from './types';
|
||||
import type { InternalUiSettingsRequestHandlerContext } from './internal_types';
|
||||
import { uiSettingsType, uiSettingsGlobalType } from './saved_objects';
|
||||
import { registerRoutes } from './routes';
|
||||
import { registerRoutes, registerInternalRoutes } from './routes';
|
||||
import { getCoreSettings } from './settings';
|
||||
import { UiSettingsDefaultsClient } from './clients/ui_settings_defaults_client';
|
||||
|
||||
|
@ -78,12 +78,18 @@ export class UiSettingsService
|
|||
public async setup({ http, savedObjects }: SetupDeps): Promise<InternalUiSettingsServiceSetup> {
|
||||
this.log.debug('Setting up ui settings service');
|
||||
|
||||
savedObjects.registerType(uiSettingsType);
|
||||
savedObjects.registerType(uiSettingsGlobalType);
|
||||
registerRoutes(http.createRouter<InternalUiSettingsRequestHandlerContext>(''));
|
||||
|
||||
const config = await firstValueFrom(this.config$);
|
||||
this.overrides = config.overrides;
|
||||
savedObjects.registerType(uiSettingsType);
|
||||
savedObjects.registerType(uiSettingsGlobalType);
|
||||
|
||||
const router = http.createRouter<InternalUiSettingsRequestHandlerContext>('');
|
||||
registerInternalRoutes(router);
|
||||
|
||||
// Register public routes by default unless the publicApiEnabled config setting is set to false
|
||||
if (!config.hasOwnProperty('publicApiEnabled') || config.publicApiEnabled === true) {
|
||||
registerRoutes(router);
|
||||
}
|
||||
|
||||
return {
|
||||
register: this.register,
|
||||
|
|
|
@ -47,7 +47,7 @@ export class KbnClientUiSettings {
|
|||
*/
|
||||
async unset(setting: string, { space }: { space?: string } = {}) {
|
||||
const { data } = await this.requester.request<any>({
|
||||
path: pathWithSpace(space)`/api/kibana/settings/${setting}`,
|
||||
path: pathWithSpace(space)`/internal/kibana/settings/${setting}`,
|
||||
method: 'DELETE',
|
||||
});
|
||||
return data;
|
||||
|
@ -76,7 +76,7 @@ export class KbnClientUiSettings {
|
|||
|
||||
await this.requester.request({
|
||||
method: 'POST',
|
||||
path: pathWithSpace(space)`/api/kibana/settings`,
|
||||
path: pathWithSpace(space)`/internal/kibana/settings`,
|
||||
body: { changes },
|
||||
retries,
|
||||
});
|
||||
|
@ -89,7 +89,7 @@ export class KbnClientUiSettings {
|
|||
this.log.debug('applying update to kibana config: %j', updates);
|
||||
|
||||
await this.requester.request({
|
||||
path: pathWithSpace(space)`/api/kibana/settings`,
|
||||
path: pathWithSpace(space)`/internal/kibana/settings`,
|
||||
method: 'POST',
|
||||
body: {
|
||||
changes: updates,
|
||||
|
@ -100,7 +100,7 @@ export class KbnClientUiSettings {
|
|||
|
||||
private async getAll({ space }: { space?: string } = {}) {
|
||||
const { data } = await this.requester.request<UiSettingsApiResponse>({
|
||||
path: pathWithSpace(space)`/api/kibana/settings`,
|
||||
path: pathWithSpace(space)`/internal/kibana/settings`,
|
||||
method: 'GET',
|
||||
});
|
||||
|
||||
|
|
|
@ -58,7 +58,7 @@ describe('default route provider', () => {
|
|||
|
||||
for (const url of invalidRoutes) {
|
||||
await request
|
||||
.post(root, '/api/kibana/settings/defaultRoute')
|
||||
.post(root, '/internal/kibana/settings/defaultRoute')
|
||||
.send({ value: url })
|
||||
.expect(400);
|
||||
}
|
||||
|
@ -72,7 +72,7 @@ describe('default route provider', () => {
|
|||
|
||||
it('consumes valid values', async function () {
|
||||
await request
|
||||
.post(root, '/api/kibana/settings/defaultRoute')
|
||||
.post(root, '/internal/kibana/settings/defaultRoute')
|
||||
.send({ value: '/valid' })
|
||||
.expect(200);
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@ export const docExistsSuite = (savedObjectsIndex: string) => () => {
|
|||
},
|
||||
});
|
||||
|
||||
const { body } = await supertest('get', '/api/kibana/settings').expect(200);
|
||||
const { body } = await supertest('get', '/internal/kibana/settings').expect(200);
|
||||
|
||||
expect(body).toMatchObject({
|
||||
settings: {
|
||||
|
@ -75,7 +75,7 @@ export const docExistsSuite = (savedObjectsIndex: string) => () => {
|
|||
|
||||
const defaultIndex = chance.word();
|
||||
|
||||
const { body } = await supertest('post', '/api/kibana/settings/defaultIndex')
|
||||
const { body } = await supertest('post', '/internal/kibana/settings/defaultIndex')
|
||||
.send({
|
||||
value: defaultIndex,
|
||||
})
|
||||
|
@ -100,7 +100,7 @@ export const docExistsSuite = (savedObjectsIndex: string) => () => {
|
|||
it('returns a 400 if trying to set overridden value', async () => {
|
||||
const { supertest } = await setup();
|
||||
|
||||
const { body } = await supertest('delete', '/api/kibana/settings/foo')
|
||||
const { body } = await supertest('delete', '/internal/kibana/settings/foo')
|
||||
.send({
|
||||
value: 'baz',
|
||||
})
|
||||
|
@ -119,7 +119,7 @@ export const docExistsSuite = (savedObjectsIndex: string) => () => {
|
|||
const { supertest } = await setup();
|
||||
|
||||
const defaultIndex = chance.word();
|
||||
const { body } = await supertest('post', '/api/kibana/settings')
|
||||
const { body } = await supertest('post', '/internal/kibana/settings')
|
||||
.send({
|
||||
changes: {
|
||||
defaultIndex,
|
||||
|
@ -146,7 +146,7 @@ export const docExistsSuite = (savedObjectsIndex: string) => () => {
|
|||
it('returns a 400 if trying to set overridden value', async () => {
|
||||
const { supertest } = await setup();
|
||||
|
||||
const { body } = await supertest('post', '/api/kibana/settings')
|
||||
const { body } = await supertest('post', '/internal/kibana/settings')
|
||||
.send({
|
||||
changes: {
|
||||
foo: 'baz',
|
||||
|
@ -172,7 +172,9 @@ export const docExistsSuite = (savedObjectsIndex: string) => () => {
|
|||
|
||||
expect(await uiSettings.get('defaultIndex')).toBe(defaultIndex);
|
||||
|
||||
const { body } = await supertest('delete', '/api/kibana/settings/defaultIndex').expect(200);
|
||||
const { body } = await supertest('delete', '/internal/kibana/settings/defaultIndex').expect(
|
||||
200
|
||||
);
|
||||
|
||||
expect(body).toMatchObject({
|
||||
settings: {
|
||||
|
@ -189,7 +191,7 @@ export const docExistsSuite = (savedObjectsIndex: string) => () => {
|
|||
it('returns a 400 if deleting overridden value', async () => {
|
||||
const { supertest } = await setup();
|
||||
|
||||
const { body } = await supertest('delete', '/api/kibana/settings/foo').expect(400);
|
||||
const { body } = await supertest('delete', '/internal/kibana/settings/foo').expect(400);
|
||||
|
||||
expect(body).toEqual({
|
||||
error: 'Bad Request',
|
||||
|
@ -210,7 +212,7 @@ export const docExistsSuite = (savedObjectsIndex: string) => () => {
|
|||
},
|
||||
});
|
||||
|
||||
const { body } = await supertest('get', '/api/kibana/global_settings').expect(200);
|
||||
const { body } = await supertest('get', '/internal/kibana/global_settings').expect(200);
|
||||
|
||||
expect(body).toMatchObject({
|
||||
settings: {
|
||||
|
@ -231,7 +233,7 @@ export const docExistsSuite = (savedObjectsIndex: string) => () => {
|
|||
|
||||
const defaultIndex = chance.word();
|
||||
|
||||
const { body } = await supertest('post', '/api/kibana/global_settings/defaultIndex')
|
||||
const { body } = await supertest('post', '/internal/kibana/global_settings/defaultIndex')
|
||||
.send({
|
||||
value: defaultIndex,
|
||||
})
|
||||
|
@ -253,7 +255,7 @@ export const docExistsSuite = (savedObjectsIndex: string) => () => {
|
|||
it.skip('returns a 400 if trying to set overridden value', async () => {
|
||||
const { supertest } = await setup();
|
||||
|
||||
const { body } = await supertest('delete', '/api/kibana/global_settings/foo')
|
||||
const { body } = await supertest('delete', '/internal/kibana/global_settings/foo')
|
||||
.send({
|
||||
value: 'baz',
|
||||
})
|
||||
|
@ -272,7 +274,7 @@ export const docExistsSuite = (savedObjectsIndex: string) => () => {
|
|||
const { supertest } = await setup();
|
||||
|
||||
const defaultIndex = chance.word();
|
||||
const { body } = await supertest('post', '/api/kibana/global_settings')
|
||||
const { body } = await supertest('post', '/internal/kibana/global_settings')
|
||||
.send({
|
||||
changes: {
|
||||
defaultIndex,
|
||||
|
@ -296,7 +298,7 @@ export const docExistsSuite = (savedObjectsIndex: string) => () => {
|
|||
it.skip('returns a 400 if trying to set overridden value', async () => {
|
||||
const { supertest } = await setup();
|
||||
|
||||
const { body } = await supertest('post', '/api/kibana/global_settings')
|
||||
const { body } = await supertest('post', '/internal/kibana/global_settings')
|
||||
.send({
|
||||
changes: {
|
||||
foo: 'baz',
|
||||
|
@ -324,7 +326,7 @@ export const docExistsSuite = (savedObjectsIndex: string) => () => {
|
|||
|
||||
const { body } = await supertest(
|
||||
'delete',
|
||||
'/api/kibana/global_settings/defaultIndex'
|
||||
'/internal/kibana/global_settings/defaultIndex'
|
||||
).expect(200);
|
||||
|
||||
expect(body).toMatchObject({
|
||||
|
@ -339,7 +341,9 @@ export const docExistsSuite = (savedObjectsIndex: string) => () => {
|
|||
it.skip('returns a 400 if deleting overridden value', async () => {
|
||||
const { supertest } = await setup();
|
||||
|
||||
const { body } = await supertest('delete', '/api/kibana/global_settings/foo').expect(400);
|
||||
const { body } = await supertest('delete', '/internal/kibana/global_settings/foo').expect(
|
||||
400
|
||||
);
|
||||
|
||||
expect(body).toEqual({
|
||||
error: 'Bad Request',
|
||||
|
|
|
@ -26,7 +26,7 @@ export const docMissingSuite = (savedObjectsIndex: string) => () => {
|
|||
it('creates doc, returns a 200 with settings', async () => {
|
||||
const { supertest } = getServices();
|
||||
|
||||
const { body } = await supertest('get', '/api/kibana/settings').expect(200);
|
||||
const { body } = await supertest('get', '/internal/kibana/settings').expect(200);
|
||||
|
||||
expect(body).toMatchObject({
|
||||
settings: {
|
||||
|
@ -47,7 +47,7 @@ export const docMissingSuite = (savedObjectsIndex: string) => () => {
|
|||
const { supertest } = getServices();
|
||||
const defaultIndex = chance.word();
|
||||
|
||||
const { body } = await supertest('post', '/api/kibana/settings/defaultIndex')
|
||||
const { body } = await supertest('post', '/internal/kibana/settings/defaultIndex')
|
||||
.send({
|
||||
value: defaultIndex,
|
||||
})
|
||||
|
@ -76,7 +76,7 @@ export const docMissingSuite = (savedObjectsIndex: string) => () => {
|
|||
|
||||
const defaultIndex = chance.word();
|
||||
|
||||
const { body } = await supertest('post', '/api/kibana/settings')
|
||||
const { body } = await supertest('post', '/internal/kibana/settings')
|
||||
.send({
|
||||
changes: { defaultIndex },
|
||||
})
|
||||
|
@ -103,7 +103,9 @@ export const docMissingSuite = (savedObjectsIndex: string) => () => {
|
|||
it('creates doc, returns a 200 with just buildNum', async () => {
|
||||
const { supertest } = getServices();
|
||||
|
||||
const { body } = await supertest('delete', '/api/kibana/settings/defaultIndex').expect(200);
|
||||
const { body } = await supertest('delete', '/internal/kibana/settings/defaultIndex').expect(
|
||||
200
|
||||
);
|
||||
|
||||
expect(body).toMatchObject({
|
||||
settings: {
|
||||
|
|
|
@ -10,7 +10,7 @@ import { schema } from '@kbn/config-schema';
|
|||
import { createRoot, request } from '@kbn/core-test-helpers-kbn-server';
|
||||
|
||||
describe('ui settings service', () => {
|
||||
describe('routes', () => {
|
||||
describe('public routes', () => {
|
||||
let root: ReturnType<typeof createRoot>;
|
||||
beforeAll(async () => {
|
||||
root = createRoot({
|
||||
|
@ -96,4 +96,91 @@ describe('ui settings service', () => {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('internal routes', () => {
|
||||
let root: ReturnType<typeof createRoot>;
|
||||
beforeAll(async () => {
|
||||
root = createRoot({
|
||||
plugins: { initialize: false },
|
||||
elasticsearch: { skipStartupConnectionCheck: true },
|
||||
});
|
||||
|
||||
await root.preboot();
|
||||
const { uiSettings } = await root.setup();
|
||||
uiSettings.register({
|
||||
custom: {
|
||||
value: '42',
|
||||
schema: schema.string(),
|
||||
},
|
||||
});
|
||||
// global uiSettings have to be registerd to be set
|
||||
uiSettings.registerGlobal({
|
||||
custom: {
|
||||
value: '42',
|
||||
schema: schema.string(),
|
||||
},
|
||||
});
|
||||
uiSettings.registerGlobal({
|
||||
foo: {
|
||||
value: 'foo',
|
||||
schema: schema.string(),
|
||||
},
|
||||
});
|
||||
|
||||
await root.start();
|
||||
});
|
||||
afterAll(async () => await root.shutdown());
|
||||
|
||||
describe('set', () => {
|
||||
it('validates value', async () => {
|
||||
const response = await request
|
||||
.post(root, '/internal/kibana/settings/custom')
|
||||
.send({ value: 100 })
|
||||
.expect(400);
|
||||
|
||||
expect(response.body.message).toBe(
|
||||
'[validation [custom]]: expected value of type [string] but got [number]'
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('set many', () => {
|
||||
it('validates value', async () => {
|
||||
const response = await request
|
||||
.post(root, '/internal/kibana/settings')
|
||||
.send({ changes: { custom: 100, foo: 'bar' } })
|
||||
.expect(400);
|
||||
|
||||
expect(response.body.message).toBe(
|
||||
'[validation [custom]]: expected value of type [string] but got [number]'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('global', () => {
|
||||
describe('set', () => {
|
||||
it('validates value', async () => {
|
||||
const response = await request
|
||||
.post(root, '/internal/kibana/global_settings/custom')
|
||||
.send({ value: 100 })
|
||||
.expect(400);
|
||||
|
||||
expect(response.body.message).toBe(
|
||||
'[validation [custom]]: expected value of type [string] but got [number]'
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('set many', () => {
|
||||
it('validates value', async () => {
|
||||
const response = await request
|
||||
.post(root, '/internal/kibana/global_settings')
|
||||
.send({ changes: { custom: 100, foo: 'bar' } })
|
||||
.expect(400);
|
||||
|
||||
expect(response.body.message).toBe(
|
||||
'[validation [custom]]: expected value of type [string] but got [number]'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -122,7 +122,7 @@ Cypress.Commands.add(
|
|||
cy.request({
|
||||
log: false,
|
||||
method: 'POST',
|
||||
url: `${kibanaUrl}/api/kibana/settings`,
|
||||
url: `${kibanaUrl}/internal/kibana/settings`,
|
||||
body: { changes: settings },
|
||||
headers: {
|
||||
'kbn-xsrf': 'e2e_test',
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
export function setUISettings(settingsKey: string, settingsValue: any) {
|
||||
cy.request({
|
||||
method: 'POST',
|
||||
url: '/api/kibana/settings',
|
||||
url: '/internal/kibana/settings',
|
||||
headers: { 'kbn-xsrf': 'xx' },
|
||||
body: {
|
||||
changes: {
|
||||
|
|
|
@ -10,7 +10,7 @@ import { rootRequest } from '../common';
|
|||
const kibanaSettings = (body: Cypress.RequestBody) => {
|
||||
rootRequest({
|
||||
method: 'POST',
|
||||
url: 'api/kibana/settings',
|
||||
url: 'internal/kibana/settings',
|
||||
body,
|
||||
headers: { 'kbn-xsrf': 'cypress-creds' },
|
||||
});
|
||||
|
|
|
@ -471,7 +471,7 @@ export const setKibanaTimezoneToUTC = () =>
|
|||
cy
|
||||
.request({
|
||||
method: 'POST',
|
||||
url: 'api/kibana/settings',
|
||||
url: 'internal/kibana/settings',
|
||||
body: { changes: { 'dateFormat:tz': 'UTC' } },
|
||||
headers: { 'kbn-xsrf': 'set-kibana-timezone-utc' },
|
||||
})
|
||||
|
|
|
@ -52,7 +52,7 @@ export default function featureControlsTests({ getService }: FtrProviderContext)
|
|||
const basePath = spaceId ? `/s/${spaceId}` : '';
|
||||
|
||||
return await supertest
|
||||
.post(`${basePath}/api/kibana/settings`)
|
||||
.post(`${basePath}/internal/kibana/settings`)
|
||||
.auth(username, password)
|
||||
.set('kbn-xsrf', 'foo')
|
||||
.send({ changes: { [CSV_QUOTE_VALUES_SETTING]: null } })
|
||||
|
|
|
@ -21,7 +21,7 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
|
||||
const setSpaceConfig = async (spaceId: string, settings: object) => {
|
||||
return await kibanaServer.request({
|
||||
path: `/s/${spaceId}/api/kibana/settings`,
|
||||
path: `/s/${spaceId}/internal/kibana/settings`,
|
||||
method: 'POST',
|
||||
body: { changes: settings },
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue