[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:
Jean-Louis Leysens 2020-08-21 12:20:46 +02:00 committed by GitHub
parent 506bf6c764
commit 7376e4ca3d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
25 changed files with 451 additions and 164 deletions

View file

@ -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);
}

View file

@ -1,4 +0,0 @@
{
"name": "console_legacy",
"version": "kibana"
}

View 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;
}

View file

@ -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);

View file

@ -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(),

View file

@ -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>;
}

View 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.

View file

@ -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,

View 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',
});
},
};
};

View file

@ -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);

View 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';

View file

@ -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,
});

View 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 };

View file

@ -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,
};
};

View file

@ -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'));

View file

@ -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'],
}),
},
})
);

View file

@ -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();
}
}

View file

@ -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 });
});
};

View file

@ -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;

View file

@ -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)
);
};

View file

@ -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({

View 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);
};

View file

@ -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;
}
}

View file

@ -17,4 +17,6 @@
* under the License.
*/
export { EsLegacyConfigService } from './es_legacy_config_service';
export { SpecDefinitionsService } from './spec_definitions_service';

View file

@ -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;