diff --git a/src/legacy/core_plugins/console_legacy/index.ts b/src/legacy/core_plugins/console_legacy/index.ts deleted file mode 100644 index 82e00a99c6cfd..0000000000000 --- a/src/legacy/core_plugins/console_legacy/index.ts +++ /dev/null @@ -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); -} diff --git a/src/legacy/core_plugins/console_legacy/package.json b/src/legacy/core_plugins/console_legacy/package.json deleted file mode 100644 index b78807daed959..0000000000000 --- a/src/legacy/core_plugins/console_legacy/package.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "name": "console_legacy", - "version": "kibana" -} diff --git a/src/plugins/console/common/types/api_responses.ts b/src/plugins/console/common/types/api_responses.ts new file mode 100644 index 0000000000000..1c8166bbe27f2 --- /dev/null +++ b/src/plugins/console/common/types/api_responses.ts @@ -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; +} diff --git a/src/plugins/console/public/application/containers/editor/legacy/console_editor/editor.tsx b/src/plugins/console/public/application/containers/editor/legacy/console_editor/editor.tsx index 880069d8ebc7a..fc88b31711b23 100644 --- a/src/plugins/console/public/application/containers/editor/legacy/console_editor/editor.tsx +++ b/src/plugins/console/public/application/containers/editor/legacy/console_editor/editor.tsx @@ -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) { { - return editorInstanceRef.current!.getRequestsAsCURL(elasticsearchUrl); + return editorInstanceRef.current!.getRequestsAsCURL(esHostService.getHost()); }} getDocumentation={() => { return getDocumentation(editorInstanceRef.current!, docLinkVersion); diff --git a/src/plugins/console/public/application/contexts/services_context.mock.ts b/src/plugins/console/public/application/contexts/services_context.mock.ts index ae8d15a890782..ba982d3f50cfb 100644 --- a/src/plugins/console/public/application/contexts/services_context.mock.ts +++ b/src/plugins/console/public/application/contexts/services_context.mock.ts @@ -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(), diff --git a/src/plugins/console/public/application/contexts/services_context.tsx b/src/plugins/console/public/application/contexts/services_context.tsx index 3d4ac3291c5ac..e2f01a152b27b 100644 --- a/src/plugins/console/public/application/contexts/services_context.tsx +++ b/src/plugins/console/public/application/contexts/services_context.tsx @@ -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(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 {children}; } diff --git a/src/plugins/console/public/application/hooks/README.md b/src/plugins/console/public/application/hooks/README.md new file mode 100644 index 0000000000000..10057193560e9 --- /dev/null +++ b/src/plugins/console/public/application/hooks/README.md @@ -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. \ No newline at end of file diff --git a/src/plugins/console/public/application/index.tsx b/src/plugins/console/public/application/index.tsx index 051eaea27a7de..0a5a502eb5062 100644 --- a/src/plugins/console/public/application/index.tsx +++ b/src/plugins/console/public/application/index.tsx @@ -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( ; + +export const createApi = ({ http }: Dependencies) => { + return { + getEsConfig: () => { + return sendRequest(http, { + path: '/api/console/es_config', + method: 'get', + }); + }, + }; +}; diff --git a/src/plugins/console/public/application/lib/es_host_service.ts b/src/plugins/console/public/application/lib/es_host_service.ts new file mode 100644 index 0000000000000..887f270a24687 --- /dev/null +++ b/src/plugins/console/public/application/lib/es_host_service.ts @@ -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); diff --git a/src/plugins/console/public/application/lib/index.ts b/src/plugins/console/public/application/lib/index.ts new file mode 100644 index 0000000000000..1ba99cc607269 --- /dev/null +++ b/src/plugins/console/public/application/lib/index.ts @@ -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'; diff --git a/src/plugins/console/public/plugin.ts b/src/plugins/console/public/plugin.ts index 851dc7a063d7b..03b65a8bd145c 100644 --- a/src/plugins/console/public/plugin.ts +++ b/src/plugins/console/public/plugin.ts @@ -25,7 +25,7 @@ import { AppSetupUIPluginDependencies } from './types'; export class ConsoleUIPlugin implements Plugin { 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 ({ 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 => ({ - proxyConfigCollection, - pathFilters, - readLegacyESConfig, - log, + pathFilters: [/.*/], + proxyConfigCollection: new ProxyConfigCollection([]), }); + +interface MockDepsArgument extends Partial> { + proxy?: Partial; +} + +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, + }; +}; diff --git a/src/plugins/console/server/__tests__/proxy_route/params.test.ts b/src/plugins/console/server/__tests__/proxy_route/params.test.ts index 1ab9c3ae789cc..e1c5295f6d30f 100644 --- a/src/plugins/console/server/__tests__/proxy_route/params.test.ts +++ b/src/plugins/console/server/__tests__/proxy_route/params.test.ts @@ -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')); diff --git a/src/plugins/console/server/__tests__/proxy_route/proxy_fallback.test.ts b/src/plugins/console/server/__tests__/proxy_route/proxy_fallback.test.ts index b226bad11a01a..fc5233d0f833d 100644 --- a/src/plugins/console/server/__tests__/proxy_route/proxy_fallback.test.ts +++ b/src/plugins/console/server/__tests__/proxy_route/proxy_fallback.test.ts @@ -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'], + }), + }, }) ); diff --git a/src/plugins/console/server/plugin.ts b/src/plugins/console/server/plugin.ts index eedd1541e8898..a76a35f8146c9 100644 --- a/src/plugins/console/server/plugin.ts +++ b/src/plugins/console/server/plugin.ts @@ -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 { @@ -33,11 +32,13 @@ export class ConsoleServerPlugin implements Plugin { specDefinitionsService = new SpecDefinitionsService(); + esLegacyConfigService = new EsLegacyConfigService(); + constructor(private readonly ctx: PluginInitializerContext) { 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 { })); 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 => { + 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 { ...this.specDefinitionsService.start(), }; } + + stop() { + this.esLegacyConfigService.stop(); + } } diff --git a/src/plugins/console/server/routes/api/console/es_config/index.ts b/src/plugins/console/server/routes/api/console/es_config/index.ts new file mode 100644 index 0000000000000..a115a6b32ad01 --- /dev/null +++ b/src/plugins/console/server/routes/api/console/es_config/index.ts @@ -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 }); + }); +}; diff --git a/src/plugins/console/server/routes/api/console/proxy/create_handler.ts b/src/plugins/console/server/routes/api/console/proxy/create_handler.ts index a16fb1dadfbcf..f6d9bcb77ddda 100644 --- a/src/plugins/console/server/routes/api/console/proxy/create_handler.ts +++ b/src/plugins/console/server/routes/api/console/proxy/create_handler.ts @@ -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 => async ( - ctx, - request, - response -) => { + proxy: { readLegacyESConfig, pathFilters, proxyConfigCollection }, +}: RouteDependencies): RequestHandler => 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; diff --git a/src/plugins/console/server/routes/api/console/proxy/index.ts b/src/plugins/console/server/routes/api/console/proxy/index.ts index 5f7df1d7cf66b..5841671c340bd 100644 --- a/src/plugins/console/server/routes/api/console/proxy/index.ts +++ b/src/plugins/console/server/routes/api/console/proxy/index.ts @@ -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) ); }; diff --git a/src/plugins/console/server/routes/api/console/spec_definitions/index.ts b/src/plugins/console/server/routes/api/console/spec_definitions/index.ts index 5c7e679cd0d35..a179c36364e26 100644 --- a/src/plugins/console/server/routes/api/console/spec_definitions/index.ts +++ b/src/plugins/console/server/routes/api/console/spec_definitions/index.ts @@ -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({ diff --git a/src/plugins/console/server/routes/index.ts b/src/plugins/console/server/routes/index.ts new file mode 100644 index 0000000000000..cbd1cef7b36e3 --- /dev/null +++ b/src/plugins/console/server/routes/index.ts @@ -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; + 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); +}; diff --git a/src/plugins/console/server/services/es_legacy_config_service.ts b/src/plugins/console/server/services/es_legacy_config_service.ts new file mode 100644 index 0000000000000..37928839b1846 --- /dev/null +++ b/src/plugins/console/server/services/es_legacy_config_service.ts @@ -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; + + /** + * A reference to the subscription to the elasticsearch observable + */ + private configSub?: Subscription; + + setup(config$: Observable) { + this.config$ = config$; + this.configSub = this.config$.subscribe((config) => { + this.config = config; + }); + } + + stop() { + if (this.configSub) { + this.configSub.unsubscribe(); + } + } + + async readConfig(): Promise { + 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; + } +} diff --git a/src/plugins/console/server/services/index.ts b/src/plugins/console/server/services/index.ts index c8dfeccd23070..c9d0b8b858150 100644 --- a/src/plugins/console/server/services/index.ts +++ b/src/plugins/console/server/services/index.ts @@ -17,4 +17,6 @@ * under the License. */ +export { EsLegacyConfigService } from './es_legacy_config_service'; + export { SpecDefinitionsService } from './spec_definitions_service'; diff --git a/src/plugins/console/server/types.ts b/src/plugins/console/server/types.ts index 4f026555ada7b..5dc8322c23ea9 100644 --- a/src/plugins/console/server/types.ts +++ b/src/plugins/console/server/types.ts @@ -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;