kibana/src/cli/cluster/base_path_proxy.js
Spencer c65da14d7c
[optimizer] extract plugin discovery (#14745)
* [plugins] extract plugin discover from the kibana server

* integrate plugin discovery module with server

* [pluginDiscovery] fully extend config before checking enabled status

* [pluginDiscovery] limit arbitrary defaults in PluginSpec

* [ui/navLink] fix tests

* [ui/injectedVars] fix tests

* [ui/app] fix tests

* [server/plugins] convert init to callPluginHook tests

* [build/verifyTranslations] update verify logic

* [pluginDiscovery] remove rx utils

* fix i18n transaltion key name

* [pluginDiscovery] do kibana version checks as a part of discovery

* [pluginDiscovery/createPacksInDirectory$] clarify error handling

* [eslint] fix lint errors

* [uiApp/modules] ensure load order matches master

* [uiBundle] use known uiExport type for providers

* [uiExports] use the `home` export type

* [uiExports] validate that all uiExport types are known

* [timelion] remove archaic/broken bwc check

* revert some stragler changes

* [pluginSpecs] reformat comments

* [uiBundle] rebel and use more fcb 😬

* correct comment

* [server/waitForPluginsInit] describe queues var

* [server/plugins] prevent multiple calls to next() by using single then()

* [uiApp] remove archaic deprecation warning

* [uiApp] tighten up tests

* [pluginDiscovery/errors] remove $ from symbol var

* [pluginDiscovery/reduceExportSpecs] update docs

* [pluginDiscovery/findPluginSpecs] rightVersion -> isRightVersion

* [pluginDiscovery/findPluginSpecs] fix typos

* [uiApps/getById] use Map() rather than memoize

* save

* [savedObjects/mappings] use uiExports.savedObjectMappings

* [server/mapping/indexMapping] update tests, addRootProperties method removed

* [uiExports] "embeddableHandlers" -> "embeddableFactories"

* [pluginDiscovery] fix pluralization of invalidVersionSpec$

* [pluginDiscover] add README

* [pluginDiscovery/reduceExportSpecs] don't ignore fasly spec values, just undefined

* [ui/exportTypes] use better reducer names

* [ui/uiExports] add README

* fix links

* [pluginDiscovery/readme] expand examples

* [pluginDiscovery/readme] clean up reduceExportSpecs() doc

* [ui/uiExports/readme] cleanup example

* [pluginDiscovery] remove needless use of lodash

* [pluginDiscovery/waitForComplete] use better name

* [pluginDiscovery/findPluginSpecs] use fixtures rather than core_plugins

* [pluginDiscovery/stubSchema] use deafult: false

* [plguinDiscovery/pluginConfig] add tests

* typo

* [uiExports/readme] fix link

* [pluginDiscovery/packAtPath] fail with InvalidPackError if path is not a string

* [pluginDiscovery/packAtPath] rely on error.code to detect missing package.json file

* [pluginDiscovery/packAtPath] only attempt to get pack when observable is subscribed

* [pluginDiscovery/packAtPath] add tests

* [pluginDiscovery/pluginPack] move absolute path checks into fs lib

* [pluginDiscovery/packsInDirectory] fix error type check

* [pluginDiscovery/pluginPack/tests] share some utils

* [pluginDiscovery/packsInDirectory] add tests

* [pluginDiscovery/pluginPack] only cast undefined to array

* [pluginDiscovery/pluginPack] add tests

* [pluginDiscovery/pluginSpec/isVersionCompatible] add tests

* [pluginDiscovery/InvalidPluginError] be less redundant

* [pluginDiscovery/pluginSpec] verify config service is passed to isEnabled()

* [pluginDiscovery/pluginSpec] add tests

* fix "existent" spelling
2017-12-05 18:11:50 -07:00

133 lines
4 KiB
JavaScript

import { Server } from 'hapi';
import { notFound } from 'boom';
import { map, sample } from 'lodash';
import { format as formatUrl } from 'url';
import { map as promiseMap, fromNode } from 'bluebird';
import { Agent as HttpsAgent } from 'https';
import { readFileSync } from 'fs';
import { Config } from '../../server/config/config';
import setupConnection from '../../server/http/setup_connection';
import registerHapiPlugins from '../../server/http/register_hapi_plugins';
import setupLogging from '../../server/logging';
import { transformDeprecations } from '../../server/config/transform_deprecations';
const alphabet = 'abcdefghijklmnopqrztuvwxyz'.split('');
export default class BasePathProxy {
constructor(clusterManager, userSettings) {
this.clusterManager = clusterManager;
this.server = new Server();
const settings = transformDeprecations(userSettings);
const config = Config.withDefaultSchema(settings);
this.targetPort = config.get('dev.basePathProxyTarget');
this.basePath = config.get('server.basePath');
const sslEnabled = config.get('server.ssl.enabled');
if (sslEnabled) {
this.proxyAgent = new HttpsAgent({
key: readFileSync(config.get('server.ssl.key')),
passphrase: config.get('server.ssl.keyPassphrase'),
cert: readFileSync(config.get('server.ssl.certificate')),
ca: map(config.get('server.ssl.certificateAuthorities'), readFileSync),
rejectUnauthorized: false
});
}
if (!this.basePath) {
this.basePath = `/${sample(alphabet, 3).join('')}`;
config.set('server.basePath', this.basePath);
}
const ONE_GIGABYTE = 1024 * 1024 * 1024;
config.set('server.maxPayloadBytes', ONE_GIGABYTE);
setupLogging(null, this.server, config);
setupConnection(null, this.server, config);
registerHapiPlugins(null, this.server, config);
this.setupRoutes();
}
setupRoutes() {
const { clusterManager, server, basePath, targetPort } = this;
server.route({
method: 'GET',
path: '/',
handler(req, reply) {
return reply.redirect(basePath);
}
});
server.route({
method: '*',
path: `${basePath}/{kbnPath*}`,
config: {
pre: [
(req, reply) => {
promiseMap(clusterManager.workers, worker => {
if (worker.type === 'server' && !worker.listening && !worker.crashed) {
return fromNode(cb => {
const done = () => {
worker.removeListener('listening', done);
worker.removeListener('crashed', done);
cb();
};
worker.on('listening', done);
worker.on('crashed', done);
});
}
})
.return(undefined)
.nodeify(reply);
}
],
},
handler: {
proxy: {
passThrough: true,
xforward: true,
agent: this.proxyAgent,
mapUri(req, callback) {
callback(null, formatUrl({
protocol: server.info.protocol,
hostname: server.info.host,
port: targetPort,
pathname: req.params.kbnPath,
query: req.query,
}));
}
}
}
});
server.route({
method: '*',
path: `/{oldBasePath}/{kbnPath*}`,
handler(req, reply) {
const { oldBasePath, kbnPath = '' } = req.params;
const isGet = req.method === 'get';
const isBasePath = oldBasePath.length === 3;
const isApp = kbnPath.startsWith('app/');
const isKnownShortPath = ['login', 'logout', 'status'].includes(kbnPath);
if (isGet && isBasePath && (isApp || isKnownShortPath)) {
return reply.redirect(`${basePath}/${kbnPath}`);
}
return reply(notFound());
}
});
}
async listen() {
await fromNode(cb => this.server.start(cb));
this.server.log(['listening', 'info'], `basePath Proxy running at ${this.server.info.uri}${this.basePath}`);
}
}