mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
* Migrate /api/settings to KP (#77554) # Conflicts: # docs/developer/plugin-list.asciidoc # x-pack/plugins/monitoring/server/kibana_monitoring/collectors/get_settings_collector.ts # x-pack/plugins/xpack_legacy/kibana.json # x-pack/plugins/xpack_legacy/server/plugin.ts * Fix lint Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
parent
79b19894b5
commit
6a42b0d1b5
19 changed files with 258 additions and 88 deletions
|
@ -494,8 +494,8 @@ in their infrastructure.
|
|||
|This plugins adopts some conventions in addition to or in place of conventions in Kibana (at the time of the plugin's creation):
|
||||
|
||||
|
||||
|{kib-repo}blob/{branch}/x-pack/plugins/xpack_legacy[xpackLegacy]
|
||||
|WARNING: Missing README.
|
||||
|{kib-repo}blob/{branch}/x-pack/plugins/xpack_legacy/README.md[xpackLegacy]
|
||||
|Contains HTTP endpoints and UiSettings that are slated for removal.
|
||||
|
||||
|
||||
|===
|
||||
|
|
|
@ -21,9 +21,9 @@ import type { PublicMethodsOf } from '@kbn/utility-types';
|
|||
import { ContextService, ContextSetup } from './context_service';
|
||||
import { contextMock } from '../../utils/context.mock';
|
||||
|
||||
const createSetupContractMock = () => {
|
||||
const createSetupContractMock = (mockContext = {}) => {
|
||||
const setupContract: jest.Mocked<ContextSetup> = {
|
||||
createContextContainer: jest.fn().mockImplementation(() => contextMock.create()),
|
||||
createContextContainer: jest.fn().mockImplementation(() => contextMock.create(mockContext)),
|
||||
};
|
||||
return setupContract;
|
||||
};
|
||||
|
|
|
@ -52,6 +52,7 @@ export { typeRegistryMock as savedObjectsTypeRegistryMock } from './saved_object
|
|||
export { uiSettingsServiceMock } from './ui_settings/ui_settings_service.mock';
|
||||
export { metricsServiceMock } from './metrics/metrics_service.mock';
|
||||
export { renderingMock } from './rendering/rendering_service.mock';
|
||||
export { contextServiceMock } from './context/context_service.mock';
|
||||
|
||||
export function pluginInitializerContextConfigMock<T>(config: T) {
|
||||
const globalConfig: SharedGlobalConfig = {
|
||||
|
|
|
@ -21,15 +21,13 @@ import { IContextContainer } from './context';
|
|||
|
||||
export type ContextContainerMock = jest.Mocked<IContextContainer<any>>;
|
||||
|
||||
const createContextMock = () => {
|
||||
const createContextMock = (mockContext = {}) => {
|
||||
const contextMock: ContextContainerMock = {
|
||||
registerContext: jest.fn(),
|
||||
createHandler: jest.fn((id, handler) => (...args: any[]) =>
|
||||
Promise.resolve(handler({}, ...args))
|
||||
),
|
||||
createHandler: jest.fn(),
|
||||
};
|
||||
contextMock.createHandler.mockImplementation((pluginId, handler) => (...args) =>
|
||||
handler({}, ...args)
|
||||
handler(mockContext, ...args)
|
||||
);
|
||||
return contextMock;
|
||||
};
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
import { resolve } from 'path';
|
||||
import { mirrorPluginStatus } from '../../server/lib/mirror_plugin_status';
|
||||
import { setupXPackMain } from './server/lib/setup_xpack_main';
|
||||
import { xpackInfoRoute, settingsRoute } from './server/routes/api/v1';
|
||||
import { xpackInfoRoute } from './server/routes/api/v1';
|
||||
|
||||
export const xpackMain = (kibana) => {
|
||||
return new kibana.Plugin({
|
||||
|
@ -34,7 +34,6 @@ export const xpackMain = (kibana) => {
|
|||
|
||||
// register routes
|
||||
xpackInfoRoute(server);
|
||||
settingsRoute(server, this.kbnServer);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
|
|
@ -5,4 +5,3 @@
|
|||
*/
|
||||
|
||||
export { xpackInfoRoute } from './xpack_info';
|
||||
export { settingsRoute } from './settings';
|
||||
|
|
|
@ -1,68 +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 { boomify } from 'boom';
|
||||
import { get } from 'lodash';
|
||||
import { KIBANA_SETTINGS_TYPE } from '../../../../../../../plugins/monitoring/common/constants';
|
||||
|
||||
const getClusterUuid = async (callCluster) => {
|
||||
const { cluster_uuid: uuid } = await callCluster('info', { filterPath: 'cluster_uuid' });
|
||||
return uuid;
|
||||
};
|
||||
|
||||
export function settingsRoute(server, kbnServer) {
|
||||
server.route({
|
||||
path: '/api/settings',
|
||||
method: 'GET',
|
||||
async handler(req) {
|
||||
const { server } = req;
|
||||
const { callWithRequest } = server.plugins.elasticsearch.getCluster('data');
|
||||
const callCluster = (...args) => callWithRequest(req, ...args); // All queries from HTTP API must use authentication headers from the request
|
||||
|
||||
try {
|
||||
const { usageCollection } = server.newPlatform.setup.plugins;
|
||||
const settingsCollector = usageCollection.getCollectorByType(KIBANA_SETTINGS_TYPE);
|
||||
|
||||
let settings = await settingsCollector.fetch(callCluster);
|
||||
if (!settings) {
|
||||
settings = settingsCollector.getEmailValueStructure(null);
|
||||
}
|
||||
const uuid = await getClusterUuid(callCluster);
|
||||
|
||||
const snapshotRegex = /-snapshot/i;
|
||||
const config = server.config();
|
||||
const status = kbnServer.status.toJSON();
|
||||
const kibana = {
|
||||
uuid: config.get('server.uuid'),
|
||||
name: config.get('server.name'),
|
||||
index: config.get('kibana.index'),
|
||||
host: config.get('server.host'),
|
||||
port: config.get('server.port'),
|
||||
locale: config.get('i18n.locale'),
|
||||
transport_address: `${config.get('server.host')}:${config.get('server.port')}`,
|
||||
version: kbnServer.version.replace(snapshotRegex, ''),
|
||||
snapshot: snapshotRegex.test(kbnServer.version),
|
||||
status: get(status, 'overall.state'),
|
||||
};
|
||||
|
||||
return {
|
||||
cluster_uuid: uuid,
|
||||
settings: {
|
||||
...settings,
|
||||
kibana,
|
||||
},
|
||||
};
|
||||
} catch (err) {
|
||||
req.log(['error'], err); // FIXME doesn't seem to log anything useful if ES times out
|
||||
if (err.isBoom) {
|
||||
return err;
|
||||
} else {
|
||||
return boomify(err, { statusCode: err.statusCode, message: err.message });
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
|
@ -10,6 +10,7 @@ import { Plugin } from './plugin';
|
|||
import { configSchema } from './config';
|
||||
import { deprecations } from './deprecations';
|
||||
|
||||
export { KibanaSettingsCollector } from './kibana_monitoring/collectors';
|
||||
export { MonitoringConfig } from './config';
|
||||
export const plugin = (initContext: PluginInitializerContext) => new Plugin(initContext);
|
||||
export const config: PluginConfigDescriptor<TypeOf<typeof configSchema>> = {
|
||||
|
|
|
@ -9,9 +9,10 @@ import {
|
|||
XPACK_DEFAULT_ADMIN_EMAIL_UI_SETTING,
|
||||
CLUSTER_ALERTS_ADDRESS_CONFIG_KEY,
|
||||
} from '../../../common/constants';
|
||||
import { Logger } from '../../../../../../src/core/server';
|
||||
import { Collector } from '../../../../../../src/plugins/usage_collection/server';
|
||||
import { MonitoringConfig } from '../../config';
|
||||
import { CoreServices } from '../../core_services';
|
||||
import { Logger } from '../../../../../../src/core/server';
|
||||
|
||||
let loggedDeprecationWarning = false;
|
||||
/*
|
||||
|
@ -65,11 +66,19 @@ export async function checkForEmailValue(
|
|||
}
|
||||
}
|
||||
|
||||
interface EmailSettingData {
|
||||
xpack: { default_admin_email: string | null };
|
||||
}
|
||||
|
||||
export interface KibanaSettingsCollector extends Collector<EmailSettingData | undefined> {
|
||||
getEmailValueStructure(email: string | null): EmailSettingData;
|
||||
}
|
||||
|
||||
export function getSettingsCollector(usageCollection: any, config: MonitoringConfig) {
|
||||
return usageCollection.makeStatsCollector({
|
||||
type: KIBANA_SETTINGS_TYPE,
|
||||
isReady: () => true,
|
||||
async fetch() {
|
||||
async fetch(this: KibanaSettingsCollector) {
|
||||
let kibanaSettingsData;
|
||||
const defaultAdminEmail = await checkForEmailValue(config);
|
||||
|
||||
|
@ -91,7 +100,7 @@ export function getSettingsCollector(usageCollection: any, config: MonitoringCon
|
|||
// returns undefined if there was no result
|
||||
return kibanaSettingsData;
|
||||
},
|
||||
getEmailValueStructure(email: string) {
|
||||
getEmailValueStructure(email: string | null) {
|
||||
return {
|
||||
xpack: {
|
||||
default_admin_email: email,
|
||||
|
|
|
@ -8,6 +8,8 @@ import { UsageCollectionSetup } from 'src/plugins/usage_collection/server';
|
|||
import { getSettingsCollector } from './get_settings_collector';
|
||||
import { MonitoringConfig } from '../../config';
|
||||
|
||||
export { KibanaSettingsCollector } from './get_settings_collector';
|
||||
|
||||
export function registerCollectors(
|
||||
usageCollection: UsageCollectionSetup,
|
||||
config: MonitoringConfig
|
||||
|
|
3
x-pack/plugins/xpack_legacy/README.md
Normal file
3
x-pack/plugins/xpack_legacy/README.md
Normal file
|
@ -0,0 +1,3 @@
|
|||
# Xpack Leagcy
|
||||
|
||||
Contains HTTP endpoints and UiSettings that are slated for removal.
|
|
@ -4,5 +4,7 @@
|
|||
"kibanaVersion": "kibana",
|
||||
"server": true,
|
||||
"ui": false,
|
||||
"requiredPlugins": []
|
||||
"requiredPlugins": [
|
||||
"usageCollection"
|
||||
]
|
||||
}
|
||||
|
|
|
@ -4,19 +4,45 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { first } from 'rxjs/operators';
|
||||
import { schema } from '@kbn/config-schema';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
import {
|
||||
PluginInitializerContext,
|
||||
CoreStart,
|
||||
CoreSetup,
|
||||
Plugin,
|
||||
} from '../../../../src/core/server';
|
||||
import { UsageCollectionSetup } from '../../../../src/plugins/usage_collection/server';
|
||||
import { registerSettingsRoute } from './routes/settings';
|
||||
|
||||
interface SetupPluginDeps {
|
||||
usageCollection: UsageCollectionSetup;
|
||||
}
|
||||
|
||||
export class XpackLegacyPlugin implements Plugin {
|
||||
constructor(_initializerContext: PluginInitializerContext) {}
|
||||
constructor(private readonly initContext: PluginInitializerContext) {}
|
||||
|
||||
public async setup(core: CoreSetup, { usageCollection }: SetupPluginDeps) {
|
||||
const router = core.http.createRouter();
|
||||
const globalConfig = await this.initContext.config.legacy.globalConfig$
|
||||
.pipe(first())
|
||||
.toPromise();
|
||||
const serverInfo = core.http.getServerInfo();
|
||||
|
||||
registerSettingsRoute({
|
||||
router,
|
||||
usageCollection,
|
||||
overallStatus$: core.status.overall$,
|
||||
config: {
|
||||
kibanaIndex: globalConfig.kibana.index,
|
||||
kibanaVersion: this.initContext.env.packageInfo.version,
|
||||
uuid: this.initContext.env.instanceUuid,
|
||||
server: serverInfo,
|
||||
},
|
||||
});
|
||||
|
||||
public setup(core: CoreSetup) {
|
||||
core.uiSettings.register({
|
||||
'xPack:defaultAdminEmail': {
|
||||
name: i18n.translate('xpack.main.uiSettings.adminEmailTitle', {
|
||||
|
|
105
x-pack/plugins/xpack_legacy/server/routes/settings.test.ts
Normal file
105
x-pack/plugins/xpack_legacy/server/routes/settings.test.ts
Normal file
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
* 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 { BehaviorSubject } from 'rxjs';
|
||||
import { UnwrapPromise } from '@kbn/utility-types';
|
||||
import supertest from 'supertest';
|
||||
|
||||
import {
|
||||
LegacyAPICaller,
|
||||
ServiceStatus,
|
||||
ServiceStatusLevels,
|
||||
} from '../../../../../src/core/server';
|
||||
import { contextServiceMock } from '../../../../../src/core/server/mocks';
|
||||
import { createHttpServer } from '../../../../../src/core/server/test_utils';
|
||||
import { registerSettingsRoute } from './settings';
|
||||
|
||||
type HttpService = ReturnType<typeof createHttpServer>;
|
||||
type HttpSetup = UnwrapPromise<ReturnType<HttpService['setup']>>;
|
||||
|
||||
describe('/api/stats', () => {
|
||||
let server: HttpService;
|
||||
let httpSetup: HttpSetup;
|
||||
let overallStatus$: BehaviorSubject<ServiceStatus>;
|
||||
let mockApiCaller: jest.Mocked<LegacyAPICaller>;
|
||||
|
||||
beforeEach(async () => {
|
||||
mockApiCaller = jest.fn().mockResolvedValue({ cluster_uuid: 'yyy-yyyyy' });
|
||||
server = createHttpServer();
|
||||
httpSetup = await server.setup({
|
||||
context: contextServiceMock.createSetupContract({
|
||||
core: {
|
||||
elasticsearch: {
|
||||
legacy: {
|
||||
client: {
|
||||
callAsCurrentUser: mockApiCaller,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
overallStatus$ = new BehaviorSubject<ServiceStatus>({
|
||||
level: ServiceStatusLevels.available,
|
||||
summary: 'everything is working',
|
||||
});
|
||||
|
||||
const usageCollection = {
|
||||
getCollectorByType: jest.fn().mockReturnValue({
|
||||
fetch: jest
|
||||
.fn()
|
||||
.mockReturnValue({ xpack: { default_admin_email: 'kibana-machine@elastic.co' } }),
|
||||
}),
|
||||
} as any;
|
||||
|
||||
const router = httpSetup.createRouter('');
|
||||
registerSettingsRoute({
|
||||
router,
|
||||
overallStatus$,
|
||||
usageCollection,
|
||||
config: {
|
||||
kibanaIndex: '.kibana-test',
|
||||
kibanaVersion: '8.8.8-SNAPSHOT',
|
||||
server: {
|
||||
name: 'mykibana',
|
||||
hostname: 'mykibana.com',
|
||||
port: 1234,
|
||||
},
|
||||
uuid: 'xxx-xxxxx',
|
||||
},
|
||||
});
|
||||
|
||||
await server.start();
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await server.stop();
|
||||
});
|
||||
|
||||
it('successfully returns data', async () => {
|
||||
const response = await supertest(httpSetup.server.listener).get('/api/settings').expect(200);
|
||||
expect(response.body).toMatchObject({
|
||||
cluster_uuid: 'yyy-yyyyy',
|
||||
settings: {
|
||||
xpack: {
|
||||
default_admin_email: 'kibana-machine@elastic.co',
|
||||
},
|
||||
kibana: {
|
||||
uuid: 'xxx-xxxxx',
|
||||
name: 'mykibana',
|
||||
index: '.kibana-test',
|
||||
host: 'mykibana.com',
|
||||
locale: 'en',
|
||||
transport_address: `mykibana.com:1234`,
|
||||
version: '8.8.8',
|
||||
snapshot: true,
|
||||
status: 'green',
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
93
x-pack/plugins/xpack_legacy/server/routes/settings.ts
Normal file
93
x-pack/plugins/xpack_legacy/server/routes/settings.ts
Normal file
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* 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 { i18n } from '@kbn/i18n';
|
||||
import { Observable } from 'rxjs';
|
||||
import { first } from 'rxjs/operators';
|
||||
|
||||
import { IRouter, ServiceStatus, ServiceStatusLevels } from '../../../../../src/core/server';
|
||||
import { UsageCollectionSetup } from '../../../../../src/plugins/usage_collection/server';
|
||||
import { KIBANA_SETTINGS_TYPE } from '../../../monitoring/common/constants';
|
||||
import { KibanaSettingsCollector } from '../../../monitoring/server';
|
||||
|
||||
const SNAPSHOT_REGEX = /-snapshot/i;
|
||||
|
||||
export function registerSettingsRoute({
|
||||
router,
|
||||
usageCollection,
|
||||
overallStatus$,
|
||||
config,
|
||||
}: {
|
||||
router: IRouter;
|
||||
usageCollection: UsageCollectionSetup;
|
||||
overallStatus$: Observable<ServiceStatus>;
|
||||
config: {
|
||||
kibanaIndex: string;
|
||||
kibanaVersion: string;
|
||||
uuid: string;
|
||||
server: {
|
||||
name: string;
|
||||
hostname: string;
|
||||
port: number;
|
||||
};
|
||||
};
|
||||
}) {
|
||||
router.get(
|
||||
{
|
||||
path: '/api/settings',
|
||||
validate: false,
|
||||
},
|
||||
async (context, req, res) => {
|
||||
const { callAsCurrentUser } = context.core.elasticsearch.legacy.client;
|
||||
|
||||
const settingsCollector = usageCollection.getCollectorByType(KIBANA_SETTINGS_TYPE) as
|
||||
| KibanaSettingsCollector
|
||||
| undefined;
|
||||
if (!settingsCollector) {
|
||||
return res.internalError();
|
||||
}
|
||||
|
||||
const settings =
|
||||
(await settingsCollector.fetch(callAsCurrentUser)) ??
|
||||
settingsCollector.getEmailValueStructure(null);
|
||||
const { cluster_uuid: uuid } = await callAsCurrentUser('info', {
|
||||
filterPath: 'cluster_uuid',
|
||||
});
|
||||
|
||||
const overallStatus = await overallStatus$.pipe(first()).toPromise();
|
||||
|
||||
const kibana = {
|
||||
uuid: config.uuid,
|
||||
name: config.server.name,
|
||||
index: config.kibanaIndex,
|
||||
host: config.server.hostname,
|
||||
port: config.server.port,
|
||||
locale: i18n.getLocale(),
|
||||
transport_address: `${config.server.hostname}:${config.server.port}`,
|
||||
version: config.kibanaVersion.replace(SNAPSHOT_REGEX, ''),
|
||||
snapshot: SNAPSHOT_REGEX.test(config.kibanaVersion),
|
||||
status: ServiceStatusToLegacyState[overallStatus.level.toString()],
|
||||
};
|
||||
|
||||
return res.ok({
|
||||
body: {
|
||||
cluster_uuid: uuid,
|
||||
settings: {
|
||||
...settings,
|
||||
kibana,
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
const ServiceStatusToLegacyState: Record<string, string> = {
|
||||
[ServiceStatusLevels.critical.toString()]: 'red',
|
||||
[ServiceStatusLevels.unavailable.toString()]: 'red',
|
||||
[ServiceStatusLevels.degraded.toString()]: 'yellow',
|
||||
[ServiceStatusLevels.available.toString()]: 'green',
|
||||
};
|
|
@ -12,7 +12,7 @@ export default function ({ loadTestFile }) {
|
|||
loadTestFile(require.resolve('./security'));
|
||||
loadTestFile(require.resolve('./spaces'));
|
||||
loadTestFile(require.resolve('./monitoring'));
|
||||
loadTestFile(require.resolve('./xpack_main'));
|
||||
loadTestFile(require.resolve('./xpack_legacy'));
|
||||
loadTestFile(require.resolve('./features'));
|
||||
loadTestFile(require.resolve('./telemetry'));
|
||||
loadTestFile(require.resolve('./logstash'));
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
|
||||
export default function ({ loadTestFile }) {
|
||||
describe('xpack_main', () => {
|
||||
describe('xpack_legacy', () => {
|
||||
loadTestFile(require.resolve('./settings'));
|
||||
});
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue