mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
[Console] Get ES Config from core (#75406)
* Server side changes - removed console_legacy plugin! - added new es_config endpoint that returns server side es config at the moment this is just the first value in hosts - Slight refactor to how routes are registered to bring them more in line with other ES UI plugins * Client side update - Updated the client to not get es host from injected metadata. Instead use the new endpoint created server side that returns this value - Added a small README.md regarding the hooks lib and need to refactor use of jQuery in console - Write code to init the es host value on the client once at start up in a non-blocking way. If this fails we just use the default value of http://localhost:9200 as this powers non-essential console functionality (i.e., copy as cURL). * fix type issue and jest tests * fix another type issue * simplify proxy assignment in proxy handler mock Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
parent
506bf6c764
commit
7376e4ca3d
25 changed files with 451 additions and 164 deletions
|
@ -1,49 +0,0 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { first } from 'rxjs/operators';
|
||||
import { head } from 'lodash';
|
||||
import url from 'url';
|
||||
|
||||
// TODO: Remove this hack once we can get the ES config we need for Console proxy a better way.
|
||||
let _legacyEsConfig: any;
|
||||
export const readLegacyEsConfig = () => {
|
||||
return _legacyEsConfig;
|
||||
};
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export default function (kibana: any) {
|
||||
return new kibana.Plugin({
|
||||
id: 'console_legacy',
|
||||
|
||||
async init(server: any) {
|
||||
_legacyEsConfig = await server.newPlatform.__internals.elasticsearch.legacy.config$
|
||||
.pipe(first())
|
||||
.toPromise();
|
||||
},
|
||||
|
||||
uiExports: {
|
||||
injectDefaultVars: () => ({
|
||||
elasticsearchUrl: url.format(
|
||||
Object.assign(url.parse(head(_legacyEsConfig.hosts) as any), { auth: false })
|
||||
),
|
||||
}),
|
||||
},
|
||||
} as any);
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
{
|
||||
"name": "console_legacy",
|
||||
"version": "kibana"
|
||||
}
|
29
src/plugins/console/common/types/api_responses.ts
Normal file
29
src/plugins/console/common/types/api_responses.ts
Normal file
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
export interface EsConfigApiResponse {
|
||||
/**
|
||||
* This is the first host in the hosts array that Kibana is configured to use
|
||||
* to communicate with ES.
|
||||
*
|
||||
* At the moment this is used to power the copy as cURL functionality in Console
|
||||
* to complete the host portion of the URL.
|
||||
*/
|
||||
host?: string;
|
||||
}
|
|
@ -67,9 +67,8 @@ const inputId = 'ConAppInputTextarea';
|
|||
|
||||
function EditorUI({ initialTextValue }: EditorProps) {
|
||||
const {
|
||||
services: { history, notifications, settings: settingsService },
|
||||
services: { history, notifications, settings: settingsService, esHostService },
|
||||
docLinkVersion,
|
||||
elasticsearchUrl,
|
||||
} = useServicesContext();
|
||||
|
||||
const { settings } = useEditorReadContext();
|
||||
|
@ -232,7 +231,7 @@ function EditorUI({ initialTextValue }: EditorProps) {
|
|||
<EuiFlexItem>
|
||||
<ConsoleMenu
|
||||
getCurl={() => {
|
||||
return editorInstanceRef.current!.getRequestsAsCURL(elasticsearchUrl);
|
||||
return editorInstanceRef.current!.getRequestsAsCURL(esHostService.getHost());
|
||||
}}
|
||||
getDocumentation={() => {
|
||||
return getDocumentation(editorInstanceRef.current!, docLinkVersion);
|
||||
|
|
|
@ -17,21 +17,27 @@
|
|||
* under the License.
|
||||
*/
|
||||
import { notificationServiceMock } from '../../../../../core/public/mocks';
|
||||
import { httpServiceMock } from '../../../../../core/public/mocks';
|
||||
|
||||
import { HistoryMock } from '../../services/history.mock';
|
||||
import { SettingsMock } from '../../services/settings.mock';
|
||||
import { StorageMock } from '../../services/storage.mock';
|
||||
import { createApi, createEsHostService } from '../lib';
|
||||
|
||||
import { ContextValue } from './services_context';
|
||||
|
||||
export const serviceContextMock = {
|
||||
create: (): ContextValue => {
|
||||
const storage = new StorageMock({} as any, 'test');
|
||||
const http = httpServiceMock.createSetupContract();
|
||||
const api = createApi({ http });
|
||||
const esHostService = createEsHostService({ api });
|
||||
(storage.keys as jest.Mock).mockImplementation(() => []);
|
||||
return {
|
||||
elasticsearchUrl: 'test',
|
||||
services: {
|
||||
trackUiMetric: { count: () => {}, load: () => {} },
|
||||
storage,
|
||||
esHostService,
|
||||
settings: new SettingsMock(storage),
|
||||
history: new HistoryMock(storage),
|
||||
notifications: notificationServiceMock.createSetupContract(),
|
||||
|
|
|
@ -17,22 +17,25 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import React, { createContext, useContext } from 'react';
|
||||
import React, { createContext, useContext, useEffect } from 'react';
|
||||
import { NotificationsSetup } from 'kibana/public';
|
||||
import { History, Storage, Settings } from '../../services';
|
||||
import { History, Settings, Storage } from '../../services';
|
||||
import { ObjectStorageClient } from '../../../common/types';
|
||||
import { MetricsTracker } from '../../types';
|
||||
import { EsHostService } from '../lib';
|
||||
|
||||
interface ContextServices {
|
||||
history: History;
|
||||
storage: Storage;
|
||||
settings: Settings;
|
||||
notifications: NotificationsSetup;
|
||||
objectStorageClient: ObjectStorageClient;
|
||||
trackUiMetric: MetricsTracker;
|
||||
esHostService: EsHostService;
|
||||
}
|
||||
|
||||
export interface ContextValue {
|
||||
services: {
|
||||
history: History;
|
||||
storage: Storage;
|
||||
settings: Settings;
|
||||
notifications: NotificationsSetup;
|
||||
objectStorageClient: ObjectStorageClient;
|
||||
trackUiMetric: MetricsTracker;
|
||||
};
|
||||
elasticsearchUrl: string;
|
||||
services: ContextServices;
|
||||
docLinkVersion: string;
|
||||
}
|
||||
|
||||
|
@ -44,6 +47,11 @@ interface ContextProps {
|
|||
const ServicesContext = createContext<ContextValue>(null as any);
|
||||
|
||||
export function ServicesContextProvider({ children, value }: ContextProps) {
|
||||
useEffect(() => {
|
||||
// Fire and forget, we attempt to init the host service once.
|
||||
value.services.esHostService.init();
|
||||
}, [value.services.esHostService]);
|
||||
|
||||
return <ServicesContext.Provider value={value}>{children}</ServicesContext.Provider>;
|
||||
}
|
||||
|
||||
|
|
5
src/plugins/console/public/application/hooks/README.md
Normal file
5
src/plugins/console/public/application/hooks/README.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
## Notes
|
||||
|
||||
* Do not add any code directly to this directory. This code should be moved to the neighbouring `lib` directory to be in line with future ES UI plugin patterns.
|
||||
|
||||
* The `es.send` method uses $.ajax under the hood and needs to be refactored to use the new platform-provided http client.
|
|
@ -19,19 +19,20 @@
|
|||
|
||||
import React from 'react';
|
||||
import { render, unmountComponentAtNode } from 'react-dom';
|
||||
import { NotificationsSetup } from 'src/core/public';
|
||||
import { HttpSetup, NotificationsSetup } from 'src/core/public';
|
||||
import { ServicesContextProvider, EditorContextProvider, RequestContextProvider } from './contexts';
|
||||
import { Main } from './containers';
|
||||
import { createStorage, createHistory, createSettings } from '../services';
|
||||
import * as localStorageObjectClient from '../lib/local_storage_object_client';
|
||||
import { createUsageTracker } from '../services/tracker';
|
||||
import { UsageCollectionSetup } from '../../../usage_collection/public';
|
||||
import { createApi, createEsHostService } from './lib';
|
||||
|
||||
export interface BootDependencies {
|
||||
http: HttpSetup;
|
||||
docLinkVersion: string;
|
||||
I18nContext: any;
|
||||
notifications: NotificationsSetup;
|
||||
elasticsearchUrl: string;
|
||||
usageCollection?: UsageCollectionSetup;
|
||||
element: HTMLElement;
|
||||
}
|
||||
|
@ -40,9 +41,9 @@ export function renderApp({
|
|||
I18nContext,
|
||||
notifications,
|
||||
docLinkVersion,
|
||||
elasticsearchUrl,
|
||||
usageCollection,
|
||||
element,
|
||||
http,
|
||||
}: BootDependencies) {
|
||||
const trackUiMetric = createUsageTracker(usageCollection);
|
||||
trackUiMetric.load('opened_app');
|
||||
|
@ -54,14 +55,16 @@ export function renderApp({
|
|||
const history = createHistory({ storage });
|
||||
const settings = createSettings({ storage });
|
||||
const objectStorageClient = localStorageObjectClient.create(storage);
|
||||
const api = createApi({ http });
|
||||
const esHostService = createEsHostService({ api });
|
||||
|
||||
render(
|
||||
<I18nContext>
|
||||
<ServicesContextProvider
|
||||
value={{
|
||||
elasticsearchUrl,
|
||||
docLinkVersion,
|
||||
services: {
|
||||
esHostService,
|
||||
storage,
|
||||
history,
|
||||
settings,
|
||||
|
|
39
src/plugins/console/public/application/lib/api.ts
Normal file
39
src/plugins/console/public/application/lib/api.ts
Normal file
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { HttpSetup } from 'kibana/public';
|
||||
import { EsConfigApiResponse } from '../../../common/types/api_responses';
|
||||
import { sendRequest } from '../../shared_imports';
|
||||
|
||||
interface Dependencies {
|
||||
http: HttpSetup;
|
||||
}
|
||||
|
||||
export type Api = ReturnType<typeof createApi>;
|
||||
|
||||
export const createApi = ({ http }: Dependencies) => {
|
||||
return {
|
||||
getEsConfig: () => {
|
||||
return sendRequest<EsConfigApiResponse>(http, {
|
||||
path: '/api/console/es_config',
|
||||
method: 'get',
|
||||
});
|
||||
},
|
||||
};
|
||||
};
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { Api } from './api';
|
||||
|
||||
/**
|
||||
* Very simple state for holding the current ES host.
|
||||
*
|
||||
* This is used to power the copy as cURL functionality.
|
||||
*/
|
||||
export class EsHostService {
|
||||
private host = 'http://localhost:9200';
|
||||
|
||||
constructor(private readonly api: Api) {}
|
||||
|
||||
private setHost(host: string): void {
|
||||
this.host = host;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the host value based on the value set on the server.
|
||||
*
|
||||
* This call is necessary because this value can only be retrieved at
|
||||
* runtime.
|
||||
*/
|
||||
public async init() {
|
||||
const { data } = await this.api.getEsConfig();
|
||||
if (data && data.host) {
|
||||
this.setHost(data.host);
|
||||
}
|
||||
}
|
||||
|
||||
public getHost(): string {
|
||||
return this.host;
|
||||
}
|
||||
}
|
||||
|
||||
export const createEsHostService = ({ api }: { api: Api }) => new EsHostService(api);
|
21
src/plugins/console/public/application/lib/index.ts
Normal file
21
src/plugins/console/public/application/lib/index.ts
Normal file
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
export { createApi, Api } from './api';
|
||||
export { createEsHostService, EsHostService } from './es_host_service';
|
|
@ -25,7 +25,7 @@ import { AppSetupUIPluginDependencies } from './types';
|
|||
|
||||
export class ConsoleUIPlugin implements Plugin<void, void, AppSetupUIPluginDependencies> {
|
||||
public setup(
|
||||
{ notifications, getStartServices }: CoreSetup,
|
||||
{ notifications, getStartServices, http }: CoreSetup,
|
||||
{ devTools, home, usageCollection }: AppSetupUIPluginDependencies
|
||||
) {
|
||||
home.featureCatalogue.register({
|
||||
|
@ -53,23 +53,17 @@ export class ConsoleUIPlugin implements Plugin<void, void, AppSetupUIPluginDepen
|
|||
const [core] = await getStartServices();
|
||||
|
||||
const {
|
||||
injectedMetadata,
|
||||
i18n: { Context: I18nContext },
|
||||
docLinks: { DOC_LINK_VERSION },
|
||||
} = core;
|
||||
|
||||
const { renderApp } = await import('./application');
|
||||
|
||||
const elasticsearchUrl = injectedMetadata.getInjectedVar(
|
||||
'elasticsearchUrl',
|
||||
'http://localhost:9200'
|
||||
) as string;
|
||||
|
||||
return renderApp({
|
||||
http,
|
||||
docLinkVersion: DOC_LINK_VERSION,
|
||||
I18nContext,
|
||||
notifications,
|
||||
elasticsearchUrl,
|
||||
usageCollection,
|
||||
element,
|
||||
});
|
||||
|
|
22
src/plugins/console/public/shared_imports.ts
Normal file
22
src/plugins/console/public/shared_imports.ts
Normal file
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { sendRequest } from '../../es_ui_shared/public';
|
||||
|
||||
export { sendRequest };
|
|
@ -23,22 +23,44 @@ jest.mock('../../lib/proxy_request', () => ({
|
|||
|
||||
import { duration } from 'moment';
|
||||
import { ProxyConfigCollection } from '../../lib';
|
||||
import { CreateHandlerDependencies } from '../../routes/api/console/proxy/create_handler';
|
||||
import { coreMock } from '../../../../../core/server/mocks';
|
||||
import { RouteDependencies, ProxyDependencies } from '../../routes';
|
||||
import { EsLegacyConfigService, SpecDefinitionsService } from '../../services';
|
||||
import { coreMock, httpServiceMock } from '../../../../../core/server/mocks';
|
||||
|
||||
export const getProxyRouteHandlerDeps = ({
|
||||
proxyConfigCollection = new ProxyConfigCollection([]),
|
||||
pathFilters = [/.*/],
|
||||
readLegacyESConfig = () => ({
|
||||
const defaultProxyValue = Object.freeze({
|
||||
readLegacyESConfig: async () => ({
|
||||
requestTimeout: duration(30000),
|
||||
customHeaders: {},
|
||||
requestHeadersWhitelist: [],
|
||||
hosts: ['http://localhost:9200'],
|
||||
}),
|
||||
log = coreMock.createPluginInitializerContext().logger.get(),
|
||||
}: Partial<CreateHandlerDependencies>): CreateHandlerDependencies => ({
|
||||
proxyConfigCollection,
|
||||
pathFilters,
|
||||
readLegacyESConfig,
|
||||
log,
|
||||
pathFilters: [/.*/],
|
||||
proxyConfigCollection: new ProxyConfigCollection([]),
|
||||
});
|
||||
|
||||
interface MockDepsArgument extends Partial<Omit<RouteDependencies, 'proxy'>> {
|
||||
proxy?: Partial<ProxyDependencies>;
|
||||
}
|
||||
|
||||
export const getProxyRouteHandlerDeps = ({
|
||||
proxy,
|
||||
log = coreMock.createPluginInitializerContext().logger.get(),
|
||||
router = httpServiceMock.createSetupContract().createRouter(),
|
||||
}: MockDepsArgument): RouteDependencies => {
|
||||
const services: RouteDependencies['services'] = {
|
||||
esLegacyConfigService: new EsLegacyConfigService(),
|
||||
specDefinitionService: new SpecDefinitionsService(),
|
||||
};
|
||||
|
||||
return {
|
||||
services,
|
||||
router,
|
||||
proxy: proxy
|
||||
? {
|
||||
...defaultProxyValue,
|
||||
...proxy,
|
||||
}
|
||||
: defaultProxyValue,
|
||||
log,
|
||||
};
|
||||
};
|
||||
|
|
|
@ -36,7 +36,7 @@ describe('Console Proxy Route', () => {
|
|||
describe('no matches', () => {
|
||||
it('rejects with 403', async () => {
|
||||
handler = createHandler(
|
||||
getProxyRouteHandlerDeps({ pathFilters: [/^\/foo\//, /^\/bar\//] })
|
||||
getProxyRouteHandlerDeps({ proxy: { pathFilters: [/^\/foo\//, /^\/bar\//] } })
|
||||
);
|
||||
|
||||
const { status } = await handler(
|
||||
|
@ -51,7 +51,7 @@ describe('Console Proxy Route', () => {
|
|||
describe('one match', () => {
|
||||
it('allows the request', async () => {
|
||||
handler = createHandler(
|
||||
getProxyRouteHandlerDeps({ pathFilters: [/^\/foo\//, /^\/bar\//] })
|
||||
getProxyRouteHandlerDeps({ proxy: { pathFilters: [/^\/foo\//, /^\/bar\//] } })
|
||||
);
|
||||
|
||||
(requestModule.proxyRequest as jest.Mock).mockResolvedValue(createResponseStub('foo'));
|
||||
|
@ -68,7 +68,9 @@ describe('Console Proxy Route', () => {
|
|||
});
|
||||
describe('all match', () => {
|
||||
it('allows the request', async () => {
|
||||
handler = createHandler(getProxyRouteHandlerDeps({ pathFilters: [/^\/foo\//] }));
|
||||
handler = createHandler(
|
||||
getProxyRouteHandlerDeps({ proxy: { pathFilters: [/^\/foo\//] } })
|
||||
);
|
||||
|
||||
(requestModule.proxyRequest as jest.Mock).mockResolvedValue(createResponseStub('foo'));
|
||||
|
||||
|
|
|
@ -38,12 +38,14 @@ describe('Console Proxy Route', () => {
|
|||
|
||||
const handler = createHandler(
|
||||
getProxyRouteHandlerDeps({
|
||||
readLegacyESConfig: () => ({
|
||||
requestTimeout: duration(30000),
|
||||
customHeaders: {},
|
||||
requestHeadersWhitelist: [],
|
||||
hosts: ['http://localhost:9201', 'http://localhost:9202', 'http://localhost:9203'],
|
||||
}),
|
||||
proxy: {
|
||||
readLegacyESConfig: async () => ({
|
||||
requestTimeout: duration(30000),
|
||||
customHeaders: {},
|
||||
requestHeadersWhitelist: [],
|
||||
hosts: ['http://localhost:9201', 'http://localhost:9202', 'http://localhost:9203'],
|
||||
}),
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
|
|
|
@ -19,13 +19,12 @@
|
|||
import { first } from 'rxjs/operators';
|
||||
import { CoreSetup, Logger, Plugin, PluginInitializerContext } from 'kibana/server';
|
||||
|
||||
import { readLegacyEsConfig } from '../../../legacy/core_plugins/console_legacy';
|
||||
|
||||
import { ProxyConfigCollection } from './lib';
|
||||
import { SpecDefinitionsService } from './services';
|
||||
import { SpecDefinitionsService, EsLegacyConfigService } from './services';
|
||||
import { ConfigType } from './config';
|
||||
import { registerProxyRoute } from './routes/api/console/proxy';
|
||||
import { registerSpecDefinitionsRoute } from './routes/api/console/spec_definitions';
|
||||
|
||||
import { registerRoutes } from './routes';
|
||||
|
||||
import { ESConfigForProxy, ConsoleSetup, ConsoleStart } from './types';
|
||||
|
||||
export class ConsoleServerPlugin implements Plugin<ConsoleSetup, ConsoleStart> {
|
||||
|
@ -33,11 +32,13 @@ export class ConsoleServerPlugin implements Plugin<ConsoleSetup, ConsoleStart> {
|
|||
|
||||
specDefinitionsService = new SpecDefinitionsService();
|
||||
|
||||
esLegacyConfigService = new EsLegacyConfigService();
|
||||
|
||||
constructor(private readonly ctx: PluginInitializerContext<ConfigType>) {
|
||||
this.log = this.ctx.logger.get();
|
||||
}
|
||||
|
||||
async setup({ http, capabilities, getStartServices }: CoreSetup) {
|
||||
async setup({ http, capabilities, getStartServices, elasticsearch }: CoreSetup) {
|
||||
capabilities.registerProvider(() => ({
|
||||
dev_tools: {
|
||||
show: true,
|
||||
|
@ -46,30 +47,31 @@ export class ConsoleServerPlugin implements Plugin<ConsoleSetup, ConsoleStart> {
|
|||
}));
|
||||
|
||||
const config = await this.ctx.config.create().pipe(first()).toPromise();
|
||||
|
||||
const { elasticsearch } = await this.ctx.config.legacy.globalConfig$.pipe(first()).toPromise();
|
||||
|
||||
const globalConfig = await this.ctx.config.legacy.globalConfig$.pipe(first()).toPromise();
|
||||
const proxyPathFilters = config.proxyFilter.map((str: string) => new RegExp(str));
|
||||
|
||||
this.esLegacyConfigService.setup(elasticsearch.legacy.config$);
|
||||
|
||||
const router = http.createRouter();
|
||||
|
||||
registerProxyRoute({
|
||||
registerRoutes({
|
||||
router,
|
||||
log: this.log,
|
||||
proxyConfigCollection: new ProxyConfigCollection(config.proxyConfig),
|
||||
readLegacyESConfig: (): ESConfigForProxy => {
|
||||
const legacyConfig = readLegacyEsConfig();
|
||||
return {
|
||||
...elasticsearch,
|
||||
...legacyConfig,
|
||||
};
|
||||
services: {
|
||||
esLegacyConfigService: this.esLegacyConfigService,
|
||||
specDefinitionService: this.specDefinitionsService,
|
||||
},
|
||||
proxy: {
|
||||
proxyConfigCollection: new ProxyConfigCollection(config.proxyConfig),
|
||||
readLegacyESConfig: async (): Promise<ESConfigForProxy> => {
|
||||
const legacyConfig = await this.esLegacyConfigService.readConfig();
|
||||
return {
|
||||
...globalConfig.elasticsearch,
|
||||
...legacyConfig,
|
||||
};
|
||||
},
|
||||
pathFilters: proxyPathFilters,
|
||||
},
|
||||
pathFilters: proxyPathFilters,
|
||||
router,
|
||||
});
|
||||
|
||||
registerSpecDefinitionsRoute({
|
||||
router,
|
||||
services: { specDefinitions: this.specDefinitionsService },
|
||||
});
|
||||
|
||||
return {
|
||||
|
@ -82,4 +84,8 @@ export class ConsoleServerPlugin implements Plugin<ConsoleSetup, ConsoleStart> {
|
|||
...this.specDefinitionsService.start(),
|
||||
};
|
||||
}
|
||||
|
||||
stop() {
|
||||
this.esLegacyConfigService.stop();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { EsConfigApiResponse } from '../../../../../common/types/api_responses';
|
||||
import { RouteDependencies } from '../../../';
|
||||
|
||||
export const registerEsConfigRoute = ({ router, services }: RouteDependencies): void => {
|
||||
router.get({ path: '/api/console/es_config', validate: false }, async (ctx, req, res) => {
|
||||
const {
|
||||
hosts: [host],
|
||||
} = await services.esLegacyConfigService.readConfig();
|
||||
|
||||
const body: EsConfigApiResponse = { host };
|
||||
|
||||
return res.ok({ body });
|
||||
});
|
||||
};
|
|
@ -21,7 +21,7 @@ import { Agent, IncomingMessage } from 'http';
|
|||
import * as url from 'url';
|
||||
import { pick, trimStart, trimEnd } from 'lodash';
|
||||
|
||||
import { KibanaRequest, Logger, RequestHandler } from 'kibana/server';
|
||||
import { KibanaRequest, RequestHandler } from 'kibana/server';
|
||||
|
||||
import { ESConfigForProxy } from '../../../../types';
|
||||
import {
|
||||
|
@ -31,19 +31,14 @@ import {
|
|||
setHeaders,
|
||||
} from '../../../../lib';
|
||||
|
||||
import { Body, Query } from './validation_config';
|
||||
|
||||
// TODO: find a better way to get information from the request like remoteAddress and remotePort
|
||||
// for forwarding.
|
||||
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
|
||||
import { ensureRawRequest } from '../../../../../../../core/server/http/router';
|
||||
|
||||
export interface CreateHandlerDependencies {
|
||||
log: Logger;
|
||||
readLegacyESConfig: () => ESConfigForProxy;
|
||||
pathFilters: RegExp[];
|
||||
proxyConfigCollection: ProxyConfigCollection;
|
||||
}
|
||||
import { RouteDependencies } from '../../../';
|
||||
|
||||
import { Body, Query } from './validation_config';
|
||||
|
||||
function toURL(base: string, path: string) {
|
||||
const urlResult = new url.URL(`${trimEnd(base, '/')}/${trimStart(path, '/')}`);
|
||||
|
@ -120,14 +115,8 @@ function getProxyHeaders(req: KibanaRequest) {
|
|||
|
||||
export const createHandler = ({
|
||||
log,
|
||||
readLegacyESConfig,
|
||||
pathFilters,
|
||||
proxyConfigCollection,
|
||||
}: CreateHandlerDependencies): RequestHandler<unknown, Query, Body> => async (
|
||||
ctx,
|
||||
request,
|
||||
response
|
||||
) => {
|
||||
proxy: { readLegacyESConfig, pathFilters, proxyConfigCollection },
|
||||
}: RouteDependencies): RequestHandler<unknown, Query, Body> => async (ctx, request, response) => {
|
||||
const { body, query } = request;
|
||||
const { path, method } = query;
|
||||
|
||||
|
@ -140,7 +129,7 @@ export const createHandler = ({
|
|||
});
|
||||
}
|
||||
|
||||
const legacyConfig = readLegacyESConfig();
|
||||
const legacyConfig = await readLegacyESConfig();
|
||||
const { hosts } = legacyConfig;
|
||||
let esIncomingMessage: IncomingMessage;
|
||||
|
||||
|
|
|
@ -17,17 +17,13 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { IRouter } from 'kibana/server';
|
||||
import { routeValidationConfig } from './validation_config';
|
||||
import { createHandler, CreateHandlerDependencies } from './create_handler';
|
||||
import { createHandler } from './create_handler';
|
||||
|
||||
export const registerProxyRoute = (
|
||||
deps: {
|
||||
router: IRouter;
|
||||
} & CreateHandlerDependencies
|
||||
) => {
|
||||
const { router, ...handlerDeps } = deps;
|
||||
router.post(
|
||||
import { RouteDependencies } from '../../../';
|
||||
|
||||
export const registerProxyRoute = (deps: RouteDependencies) => {
|
||||
deps.router.post(
|
||||
{
|
||||
path: '/api/console/proxy',
|
||||
options: {
|
||||
|
@ -39,6 +35,6 @@ export const registerProxyRoute = (
|
|||
},
|
||||
validate: routeValidationConfig,
|
||||
},
|
||||
createHandler(handlerDeps)
|
||||
createHandler(deps)
|
||||
);
|
||||
};
|
||||
|
|
|
@ -16,8 +16,8 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { IRouter, RequestHandler } from 'kibana/server';
|
||||
import { SpecDefinitionsService } from '../../../../services';
|
||||
import { RequestHandler } from 'kibana/server';
|
||||
import { RouteDependencies } from '../../../';
|
||||
|
||||
interface SpecDefinitionsRouteResponse {
|
||||
es: {
|
||||
|
@ -27,16 +27,10 @@ interface SpecDefinitionsRouteResponse {
|
|||
};
|
||||
}
|
||||
|
||||
export const registerSpecDefinitionsRoute = ({
|
||||
router,
|
||||
services,
|
||||
}: {
|
||||
router: IRouter;
|
||||
services: { specDefinitions: SpecDefinitionsService };
|
||||
}) => {
|
||||
export const registerSpecDefinitionsRoute = ({ router, services }: RouteDependencies) => {
|
||||
const handler: RequestHandler = async (ctx, request, response) => {
|
||||
const specResponse: SpecDefinitionsRouteResponse = {
|
||||
es: services.specDefinitions.asJson(),
|
||||
es: services.specDefinitionService.asJson(),
|
||||
};
|
||||
|
||||
return response.ok({
|
||||
|
|
50
src/plugins/console/server/routes/index.ts
Normal file
50
src/plugins/console/server/routes/index.ts
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { IRouter, Logger } from 'kibana/server';
|
||||
|
||||
import { EsLegacyConfigService, SpecDefinitionsService } from '../services';
|
||||
import { ESConfigForProxy } from '../types';
|
||||
import { ProxyConfigCollection } from '../lib';
|
||||
|
||||
import { registerEsConfigRoute } from './api/console/es_config';
|
||||
import { registerProxyRoute } from './api/console/proxy';
|
||||
import { registerSpecDefinitionsRoute } from './api/console/spec_definitions';
|
||||
|
||||
export interface ProxyDependencies {
|
||||
readLegacyESConfig: () => Promise<ESConfigForProxy>;
|
||||
pathFilters: RegExp[];
|
||||
proxyConfigCollection: ProxyConfigCollection;
|
||||
}
|
||||
|
||||
export interface RouteDependencies {
|
||||
router: IRouter;
|
||||
log: Logger;
|
||||
proxy: ProxyDependencies;
|
||||
services: {
|
||||
esLegacyConfigService: EsLegacyConfigService;
|
||||
specDefinitionService: SpecDefinitionsService;
|
||||
};
|
||||
}
|
||||
|
||||
export const registerRoutes = (dependencies: RouteDependencies) => {
|
||||
registerEsConfigRoute(dependencies);
|
||||
registerProxyRoute(dependencies);
|
||||
registerSpecDefinitionsRoute(dependencies);
|
||||
};
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { Observable, Subscription } from 'rxjs';
|
||||
import { first } from 'rxjs/operators';
|
||||
import { ElasticsearchConfig } from 'kibana/server';
|
||||
|
||||
export class EsLegacyConfigService {
|
||||
/**
|
||||
* The elasticsearch config value at a given point in time.
|
||||
*/
|
||||
private config?: ElasticsearchConfig;
|
||||
|
||||
/**
|
||||
* An observable that emits elasticsearch config.
|
||||
*/
|
||||
private config$?: Observable<ElasticsearchConfig>;
|
||||
|
||||
/**
|
||||
* A reference to the subscription to the elasticsearch observable
|
||||
*/
|
||||
private configSub?: Subscription;
|
||||
|
||||
setup(config$: Observable<ElasticsearchConfig>) {
|
||||
this.config$ = config$;
|
||||
this.configSub = this.config$.subscribe((config) => {
|
||||
this.config = config;
|
||||
});
|
||||
}
|
||||
|
||||
stop() {
|
||||
if (this.configSub) {
|
||||
this.configSub.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
async readConfig(): Promise<ElasticsearchConfig> {
|
||||
if (!this.config$) {
|
||||
throw new Error('Could not read elasticsearch config, this service has not been setup!');
|
||||
}
|
||||
|
||||
if (!this.config) {
|
||||
return this.config$.pipe(first()).toPromise();
|
||||
}
|
||||
|
||||
return this.config;
|
||||
}
|
||||
}
|
|
@ -17,4 +17,6 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
export { EsLegacyConfigService } from './es_legacy_config_service';
|
||||
|
||||
export { SpecDefinitionsService } from './spec_definitions_service';
|
||||
|
|
|
@ -38,8 +38,8 @@ export interface ESConfigForProxy {
|
|||
requestTimeout: Duration;
|
||||
ssl?: {
|
||||
verificationMode: 'none' | 'certificate' | 'full';
|
||||
certificateAuthorities: string[] | string;
|
||||
alwaysPresentCertificate: boolean;
|
||||
certificateAuthorities?: string[];
|
||||
certificate?: string;
|
||||
key?: string;
|
||||
keyPassphrase?: string;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue