Skip to content

Commit cf5df17

Browse files
committed
Move BasePathProxy to new platform.
1 parent f211410 commit cf5df17

File tree

16 files changed

+599
-351
lines changed

16 files changed

+599
-351
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@
130130
"glob-all": "3.0.1",
131131
"good-squeeze": "2.1.0",
132132
"h2o2": "5.1.1",
133+
"h2o2-latest": "npm:[email protected]",
133134
"handlebars": "4.0.5",
134135
"hapi": "14.2.0",
135136
"hapi-latest": "npm:[email protected]",

src/cli/cluster/base_path_proxy.js

Lines changed: 35 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -18,123 +18,47 @@
1818
*/
1919

2020
import { Server } from 'hapi';
21-
import { notFound } from 'boom';
22-
import { map, sample } from 'lodash';
23-
import { map as promiseMap, fromNode } from 'bluebird';
24-
import { Agent as HttpsAgent } from 'https';
25-
import { readFileSync } from 'fs';
26-
27-
import { setupConnection } from '../../server/http/setup_connection';
28-
import { registerHapiPlugins } from '../../server/http/register_hapi_plugins';
21+
import { createBasePathProxy } from '../../core';
2922
import { setupLogging } from '../../server/logging';
3023

31-
const alphabet = 'abcdefghijklmnopqrztuvwxyz'.split('');
24+
export async function configureBasePathProxy(config) {
25+
// New platform forwards all logs to the legacy platform so we need HapiJS server
26+
// here just for logging purposes and nothing else.
27+
const server = new Server();
28+
setupLogging(server, config);
29+
30+
const basePathProxy = createBasePathProxy({ server, config });
31+
32+
await basePathProxy.configure({
33+
isKibanaPath: (path) => {
34+
const isApp = path.startsWith('app/');
35+
const isKnownShortPath = ['login', 'logout', 'status'].includes(path);
36+
37+
return isApp || isKnownShortPath;
38+
},
39+
40+
blockUntil: () => {
41+
// Wait until `serverWorker either crashes or starts to listen.
42+
// The `serverWorker` property should be set by the ClusterManager
43+
// once it creates the worker.
44+
const serverWorker = basePathProxy.serverWorker;
45+
if (serverWorker.listening || serverWorker.crashed) {
46+
return Promise.resolve();
47+
}
3248

33-
export default class BasePathProxy {
34-
constructor(clusterManager, config) {
35-
this.clusterManager = clusterManager;
36-
this.server = new Server();
49+
return new Promise((resolve) => {
50+
const done = () => {
51+
serverWorker.removeListener('listening', done);
52+
serverWorker.removeListener('crashed', done);
3753

38-
this.targetPort = config.get('dev.basePathProxyTarget');
39-
this.basePath = config.get('server.basePath');
54+
resolve();
55+
};
4056

41-
const sslEnabled = config.get('server.ssl.enabled');
42-
if (sslEnabled) {
43-
this.proxyAgent = new HttpsAgent({
44-
key: readFileSync(config.get('server.ssl.key')),
45-
passphrase: config.get('server.ssl.keyPassphrase'),
46-
cert: readFileSync(config.get('server.ssl.certificate')),
47-
ca: map(config.get('server.ssl.certificateAuthorities'), readFileSync),
48-
rejectUnauthorized: false
57+
serverWorker.on('listening', done);
58+
serverWorker.on('crashed', done);
4959
});
5060
}
61+
});
5162

52-
if (!this.basePath) {
53-
this.basePath = `/${sample(alphabet, 3).join('')}`;
54-
config.set('server.basePath', this.basePath);
55-
}
56-
57-
const ONE_GIGABYTE = 1024 * 1024 * 1024;
58-
config.set('server.maxPayloadBytes', ONE_GIGABYTE);
59-
60-
setupLogging(this.server, config);
61-
setupConnection(this.server, config);
62-
registerHapiPlugins(this.server, config);
63-
64-
this.setupRoutes();
65-
}
66-
67-
setupRoutes() {
68-
const { clusterManager, server, basePath, targetPort } = this;
69-
70-
server.route({
71-
method: 'GET',
72-
path: '/',
73-
handler(req, reply) {
74-
return reply.redirect(basePath);
75-
}
76-
});
77-
78-
server.route({
79-
method: '*',
80-
path: `${basePath}/{kbnPath*}`,
81-
config: {
82-
pre: [
83-
(req, reply) => {
84-
promiseMap(clusterManager.workers, worker => {
85-
if (worker.type === 'server' && !worker.listening && !worker.crashed) {
86-
return fromNode(cb => {
87-
const done = () => {
88-
worker.removeListener('listening', done);
89-
worker.removeListener('crashed', done);
90-
cb();
91-
};
92-
93-
worker.on('listening', done);
94-
worker.on('crashed', done);
95-
});
96-
}
97-
})
98-
.return(undefined)
99-
.nodeify(reply);
100-
}
101-
],
102-
},
103-
handler: {
104-
proxy: {
105-
passThrough: true,
106-
xforward: true,
107-
agent: this.proxyAgent,
108-
protocol: server.info.protocol,
109-
host: server.info.host,
110-
port: targetPort,
111-
}
112-
}
113-
});
114-
115-
server.route({
116-
method: '*',
117-
path: `/{oldBasePath}/{kbnPath*}`,
118-
handler(req, reply) {
119-
const { oldBasePath, kbnPath = '' } = req.params;
120-
121-
const isGet = req.method === 'get';
122-
const isBasePath = oldBasePath.length === 3;
123-
const isApp = kbnPath.startsWith('app/');
124-
const isKnownShortPath = ['login', 'logout', 'status'].includes(kbnPath);
125-
126-
if (isGet && isBasePath && (isApp || isKnownShortPath)) {
127-
return reply.redirect(`${basePath}/${kbnPath}`);
128-
}
129-
130-
return reply(notFound());
131-
}
132-
});
133-
}
134-
135-
async listen() {
136-
await fromNode(cb => this.server.start(cb));
137-
this.server.log(['listening', 'info'], `basePath Proxy running at ${this.server.info.uri}${this.basePath}`);
138-
}
139-
63+
return basePathProxy;
14064
}

src/cli/cluster/cluster_manager.js

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@ import { debounce, invoke, bindAll, once, uniq } from 'lodash';
2222

2323
import Log from '../log';
2424
import Worker from './worker';
25-
import BasePathProxy from './base_path_proxy';
2625
import { Config } from '../../server/config/config';
2726
import { transformDeprecations } from '../../server/config/transform_deprecations';
27+
import { configureBasePathProxy } from './base_path_proxy';
2828

2929
process.env.kbnWorkerType = 'managr';
3030

@@ -33,10 +33,14 @@ export default class ClusterManager {
3333
const transformedSettings = transformDeprecations(settings);
3434
const config = await Config.withDefaultSchema(transformedSettings);
3535

36-
return new ClusterManager(opts, config);
36+
const basePathProxy = opts.basePath
37+
? await configureBasePathProxy(config)
38+
: undefined;
39+
40+
return new ClusterManager(opts, config, basePathProxy);
3741
}
3842

39-
constructor(opts, config) {
43+
constructor(opts, config, basePathProxy) {
4044
this.log = new Log(opts.quiet, opts.silent);
4145
this.addedCount = 0;
4246
this.inReplMode = !!opts.repl;
@@ -47,8 +51,8 @@ export default class ClusterManager {
4751
'--server.autoListen=false',
4852
];
4953

50-
if (opts.basePath) {
51-
this.basePathProxy = new BasePathProxy(this, config);
54+
if (basePathProxy) {
55+
this.basePathProxy = basePathProxy;
5256

5357
optimizerArgv.push(
5458
`--server.basePath=${this.basePathProxy.basePath}`,
@@ -78,6 +82,10 @@ export default class ClusterManager {
7882
})
7983
];
8084

85+
// Pass server worker to the basepath proxy so that it can hold off the
86+
// proxying until server worker is ready.
87+
this.basePathProxy.serverWorker = this.server;
88+
8189
// broker messages between workers
8290
this.workers.forEach((worker) => {
8391
worker.on('broadcast', (msg) => {
@@ -120,7 +128,7 @@ export default class ClusterManager {
120128
this.setupManualRestart();
121129
invoke(this.workers, 'start');
122130
if (this.basePathProxy) {
123-
this.basePathProxy.listen();
131+
this.basePathProxy.start();
124132
}
125133
}
126134

src/core/index.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,7 @@
1717
* under the License.
1818
*/
1919

20-
export { injectIntoKbnServer } from './server/legacy_compat';
20+
export {
21+
injectIntoKbnServer,
22+
createBasePathProxy,
23+
} from './server/legacy_compat';

src/core/server/dev/dev_config.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Licensed to Elasticsearch B.V. under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch B.V. licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
import { schema, TypeOf } from '../config/schema';
21+
22+
const createDevSchema = schema.object({
23+
basePathProxyTarget: schema.number({
24+
defaultValue: 5603,
25+
}),
26+
});
27+
28+
type DevConfigType = TypeOf<typeof createDevSchema>;
29+
30+
export class DevConfig {
31+
/**
32+
* @internal
33+
*/
34+
public static schema = createDevSchema;
35+
36+
public basePathProxyTargetPort: number;
37+
38+
/**
39+
* @internal
40+
*/
41+
constructor(config: DevConfigType) {
42+
this.basePathProxyTargetPort = config.basePathProxyTarget;
43+
}
44+
}

src/core/server/dev/index.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/*
2+
* Licensed to Elasticsearch B.V. under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch B.V. licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
export { DevConfig } from './dev_config';

0 commit comments

Comments
 (0)