Skip to content

Commit

Permalink
Merge branch 'master' into move-kbn-apm-config-loader-into-bazel
Browse files Browse the repository at this point in the history
  • Loading branch information
kibanamachine authored Apr 26, 2021
2 parents 8b927da + e3d52fc commit 4a1d86b
Show file tree
Hide file tree
Showing 87 changed files with 1,187 additions and 383 deletions.
1 change: 1 addition & 0 deletions docs/developer/getting-started/monorepo-packages.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ yarn kbn watch-bazel
- @kbn/babel-code-parser
- @kbn/babel-preset
- @kbn/config-schema
- @kbn/expect
- @kbn/std
- @kbn/tinymath
- @kbn/utility-types
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [kibana-plugin-core-server](./kibana-plugin-core-server.md) &gt; [CustomHttpResponseOptions](./kibana-plugin-core-server.customhttpresponseoptions.md) &gt; [bypassErrorFormat](./kibana-plugin-core-server.customhttpresponseoptions.bypasserrorformat.md)

## CustomHttpResponseOptions.bypassErrorFormat property

Bypass the default error formatting

<b>Signature:</b>

```typescript
bypassErrorFormat?: boolean;
```
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export interface CustomHttpResponseOptions<T extends HttpResponsePayload | Respo
| Property | Type | Description |
| --- | --- | --- |
| [body](./kibana-plugin-core-server.customhttpresponseoptions.body.md) | <code>T</code> | HTTP message to send to the client |
| [bypassErrorFormat](./kibana-plugin-core-server.customhttpresponseoptions.bypasserrorformat.md) | <code>boolean</code> | Bypass the default error formatting |
| [headers](./kibana-plugin-core-server.customhttpresponseoptions.headers.md) | <code>ResponseHeaders</code> | HTTP Headers with additional information about response |
| [statusCode](./kibana-plugin-core-server.customhttpresponseoptions.statuscode.md) | <code>number</code> | |

Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [kibana-plugin-core-server](./kibana-plugin-core-server.md) &gt; [HttpResponseOptions](./kibana-plugin-core-server.httpresponseoptions.md) &gt; [bypassErrorFormat](./kibana-plugin-core-server.httpresponseoptions.bypasserrorformat.md)

## HttpResponseOptions.bypassErrorFormat property

Bypass the default error formatting

<b>Signature:</b>

```typescript
bypassErrorFormat?: boolean;
```
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,6 @@ export interface HttpResponseOptions
| Property | Type | Description |
| --- | --- | --- |
| [body](./kibana-plugin-core-server.httpresponseoptions.body.md) | <code>HttpResponsePayload</code> | HTTP message to send to the client |
| [bypassErrorFormat](./kibana-plugin-core-server.httpresponseoptions.bypasserrorformat.md) | <code>boolean</code> | Bypass the default error formatting |
| [headers](./kibana-plugin-core-server.httpresponseoptions.headers.md) | <code>ResponseHeaders</code> | HTTP Headers with additional information about response |

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@
"dependencies": {
"@elastic/apm-rum": "^5.6.1",
"@elastic/apm-rum-react": "^1.2.5",
"@elastic/charts": "29.0.0",
"@elastic/charts": "29.1.0",
"@elastic/datemath": "link:bazel-bin/packages/elastic-datemath/npm_module",
"@elastic/elasticsearch": "npm:@elastic/elasticsearch-canary@^8.0.0-canary.4",
"@elastic/ems-client": "7.13.0",
Expand Down Expand Up @@ -446,7 +446,7 @@
"@kbn/es-archiver": "link:packages/kbn-es-archiver",
"@kbn/eslint-import-resolver-kibana": "link:packages/kbn-eslint-import-resolver-kibana",
"@kbn/eslint-plugin-eslint": "link:packages/kbn-eslint-plugin-eslint",
"@kbn/expect": "link:packages/kbn-expect",
"@kbn/expect": "link:bazel-bin/packages/kbn-expect/npm_module",
"@kbn/optimizer": "link:packages/kbn-optimizer",
"@kbn/plugin-generator": "link:packages/kbn-plugin-generator",
"@kbn/plugin-helpers": "link:packages/kbn-plugin-helpers",
Expand Down
1 change: 1 addition & 0 deletions packages/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ filegroup(
"//packages/kbn-babel-code-parser:build",
"//packages/kbn-babel-preset:build",
"//packages/kbn-config-schema:build",
"//packages/kbn-expect:build",
"//packages/kbn-std:build",
"//packages/kbn-tinymath:build",
"//packages/kbn-utility-types:build",
Expand Down
46 changes: 46 additions & 0 deletions packages/kbn-expect/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
load("@build_bazel_rules_nodejs//:index.bzl", "js_library", "pkg_npm")

PKG_BASE_NAME = "kbn-expect"
PKG_REQUIRE_NAME = "@kbn/expect"

SOURCE_FILES = glob([
"expect.js",
"expect.js.d.ts",
])

SRCS = SOURCE_FILES

filegroup(
name = "srcs",
srcs = SRCS,
)

NPM_MODULE_EXTRA_FILES = [
"LICENSE.txt",
"package.json",
"README.md",
]

js_library(
name = PKG_BASE_NAME,
srcs = NPM_MODULE_EXTRA_FILES + [
":srcs",
],
package_name = PKG_REQUIRE_NAME,
visibility = ["//visibility:public"],
)

pkg_npm(
name = "npm_module",
deps = [
":%s" % PKG_BASE_NAME,
]
)

filegroup(
name = "build",
srcs = [
":npm_module",
],
visibility = ["//visibility:public"],
)
2 changes: 1 addition & 1 deletion packages/kbn-expect/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"tsBuildInfoFile": "../../build/tsbuildinfo/packages/kbn-expect"
"incremental": false,
},
"include": [
"expect.js.d.ts"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export async function runKibanaServer({ procs, config, options }) {
...extendNodeOptions(installDir),
},
cwd: installDir || KIBANA_ROOT,
wait: /http server running/,
wait: /\[Kibana\]\[http\] http server running/,
});
}

Expand Down
9 changes: 9 additions & 0 deletions packages/kbn-test/src/kbn_client/kbn_client_requester.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ const isConcliftOnGetError = (error: any) => {
);
};

const isIgnorableError = (error: any, ignorableErrors: number[] = []) => {
return isAxiosResponseError(error) && ignorableErrors.includes(error.response.status);
};

export const uriencode = (
strings: TemplateStringsArray,
...values: Array<string | number | boolean>
Expand Down Expand Up @@ -53,6 +57,7 @@ export interface ReqOptions {
body?: any;
retries?: number;
headers?: Record<string, string>;
ignoreErrors?: number[];
responseType?: ResponseType;
}

Expand Down Expand Up @@ -125,6 +130,10 @@ export class KbnClientRequester {
const requestedRetries = options.retries !== undefined;
const failedToGetResponse = isAxiosRequestError(error);

if (isIgnorableError(error, options.ignoreErrors)) {
return error.response;
}

let errorMessage;
if (conflictOnGet) {
errorMessage = `Conflict on GET (path=${options.path}, attempt=${attempt}/${maxAttempts})`;
Expand Down
2 changes: 2 additions & 0 deletions packages/kbn-test/src/kbn_client/kbn_client_status.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ export class KbnClientStatus {
const { data } = await this.requester.request<ApiResponseStatus>({
method: 'GET',
path: 'api/status',
// Status endpoint returns 503 if any services are in an unavailable state
ignoreErrors: [503],
});
return data;
}
Expand Down
34 changes: 34 additions & 0 deletions src/core/server/http/http_server.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,40 @@ test('log listening address after started when configured with BasePath and rewr
`);
});

test('does not allow router registration after server is listening', async () => {
expect(server.isListening()).toBe(false);

const { registerRouter } = await server.setup(config);

const router1 = new Router('/foo', logger, enhanceWithContext);
expect(() => registerRouter(router1)).not.toThrowError();

await server.start();

expect(server.isListening()).toBe(true);

const router2 = new Router('/bar', logger, enhanceWithContext);
expect(() => registerRouter(router2)).toThrowErrorMatchingInlineSnapshot(
`"Routers can be registered only when HTTP server is stopped."`
);
});

test('allows router registration after server is listening via `registerRouterAfterListening`', async () => {
expect(server.isListening()).toBe(false);

const { registerRouterAfterListening } = await server.setup(config);

const router1 = new Router('/foo', logger, enhanceWithContext);
expect(() => registerRouterAfterListening(router1)).not.toThrowError();

await server.start();

expect(server.isListening()).toBe(true);

const router2 = new Router('/bar', logger, enhanceWithContext);
expect(() => registerRouterAfterListening(router2)).not.toThrowError();
});

test('valid params', async () => {
const router = new Router('/foo', logger, enhanceWithContext);

Expand Down
102 changes: 63 additions & 39 deletions src/core/server/http/http_server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import {
KibanaRouteOptions,
KibanaRequestState,
isSafeMethod,
RouterRoute,
} from './router';
import {
SessionStorageCookieOptions,
Expand All @@ -52,6 +53,13 @@ export interface HttpServerSetup {
* @param router {@link IRouter} - a router with registered route handlers.
*/
registerRouter: (router: IRouter) => void;
/**
* Add all the routes registered with `router` to HTTP server request listeners.
* Unlike `registerRouter`, this function allows routes to be registered even after the server
* has started listening for requests.
* @param router {@link IRouter} - a router with registered route handlers.
*/
registerRouterAfterListening: (router: IRouter) => void;
registerStaticDir: (path: string, dirPath: string) => void;
basePath: HttpServiceSetup['basePath'];
csp: HttpServiceSetup['csp'];
Expand Down Expand Up @@ -114,6 +122,17 @@ export class HttpServer {
this.registeredRouters.add(router);
}

private registerRouterAfterListening(router: IRouter) {
if (this.isListening()) {
for (const route of router.getRoutes()) {
this.configureRoute(route);
}
} else {
// Not listening yet, add to set of registeredRouters so that it can be added after listening has started.
this.registeredRouters.add(router);
}
}

public async setup(config: HttpConfig): Promise<HttpServerSetup> {
const serverOptions = getServerOptions(config);
const listenerOptions = getListenerOptions(config);
Expand All @@ -130,6 +149,7 @@ export class HttpServer {

return {
registerRouter: this.registerRouter.bind(this),
registerRouterAfterListening: this.registerRouterAfterListening.bind(this),
registerStaticDir: this.registerStaticDir.bind(this),
registerOnPreRouting: this.registerOnPreRouting.bind(this),
registerOnPreAuth: this.registerOnPreAuth.bind(this),
Expand Down Expand Up @@ -170,45 +190,7 @@ export class HttpServer {

for (const router of this.registeredRouters) {
for (const route of router.getRoutes()) {
this.log.debug(`registering route handler for [${route.path}]`);
// Hapi does not allow payload validation to be specified for 'head' or 'get' requests
const validate = isSafeMethod(route.method) ? undefined : { payload: true };
const { authRequired, tags, body = {}, timeout } = route.options;
const { accepts: allow, maxBytes, output, parse } = body;

const kibanaRouteOptions: KibanaRouteOptions = {
xsrfRequired: route.options.xsrfRequired ?? !isSafeMethod(route.method),
};

this.server.route({
handler: route.handler,
method: route.method,
path: route.path,
options: {
auth: this.getAuthOption(authRequired),
app: kibanaRouteOptions,
tags: tags ? Array.from(tags) : undefined,
// TODO: This 'validate' section can be removed once the legacy platform is completely removed.
// We are telling Hapi that NP routes can accept any payload, so that it can bypass the default
// validation applied in ./http_tools#getServerOptions
// (All NP routes are already required to specify their own validation in order to access the payload)
validate,
// @ts-expect-error Types are outdated and doesn't allow `payload.multipart` to be `true`
payload: [allow, maxBytes, output, parse, timeout?.payload].some((x) => x !== undefined)
? {
allow,
maxBytes,
output,
parse,
timeout: timeout?.payload,
multipart: true,
}
: undefined,
timeout: {
socket: timeout?.idleSocket ?? this.config!.socketTimeout,
},
},
});
this.configureRoute(route);
}
}

Expand Down Expand Up @@ -486,4 +468,46 @@ export class HttpServer {
options: { auth: false },
});
}

private configureRoute(route: RouterRoute) {
this.log.debug(`registering route handler for [${route.path}]`);
// Hapi does not allow payload validation to be specified for 'head' or 'get' requests
const validate = isSafeMethod(route.method) ? undefined : { payload: true };
const { authRequired, tags, body = {}, timeout } = route.options;
const { accepts: allow, maxBytes, output, parse } = body;

const kibanaRouteOptions: KibanaRouteOptions = {
xsrfRequired: route.options.xsrfRequired ?? !isSafeMethod(route.method),
};

this.server!.route({
handler: route.handler,
method: route.method,
path: route.path,
options: {
auth: this.getAuthOption(authRequired),
app: kibanaRouteOptions,
tags: tags ? Array.from(tags) : undefined,
// TODO: This 'validate' section can be removed once the legacy platform is completely removed.
// We are telling Hapi that NP routes can accept any payload, so that it can bypass the default
// validation applied in ./http_tools#getServerOptions
// (All NP routes are already required to specify their own validation in order to access the payload)
validate,
// @ts-expect-error Types are outdated and doesn't allow `payload.multipart` to be `true`
payload: [allow, maxBytes, output, parse, timeout?.payload].some((x) => x !== undefined)
? {
allow,
maxBytes,
output,
parse,
timeout: timeout?.payload,
multipart: true,
}
: undefined,
timeout: {
socket: timeout?.idleSocket ?? this.config!.socketTimeout,
},
},
});
}
}
Loading

0 comments on commit 4a1d86b

Please sign in to comment.