mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
* expose elasticsearch error wrapper * generate docs * Update src/core/server/elasticsearch/errors.ts Co-Authored-By: Rudolf Meijering <skaapgif@gmail.com> * address Oleg comments
This commit is contained in:
parent
d5246141c6
commit
416f21a2ff
12 changed files with 292 additions and 9 deletions
|
@ -0,0 +1,11 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [ElasticsearchError](./kibana-plugin-server.elasticsearcherror.md) > [\[code\]](./kibana-plugin-server.elasticsearcherror.[code].md)
|
||||
|
||||
## ElasticsearchError.\[code\] property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
[code]?: string;
|
||||
```
|
|
@ -0,0 +1,18 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [ElasticsearchError](./kibana-plugin-server.elasticsearcherror.md)
|
||||
|
||||
## ElasticsearchError interface
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export interface ElasticsearchError extends Boom
|
||||
```
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| [\[code\]](./kibana-plugin-server.elasticsearcherror.[code].md) | <code>string</code> | |
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [ElasticsearchErrorHelpers](./kibana-plugin-server.elasticsearcherrorhelpers.md) > [decorateNotAuthorizedError](./kibana-plugin-server.elasticsearcherrorhelpers.decoratenotauthorizederror.md)
|
||||
|
||||
## ElasticsearchErrorHelpers.decorateNotAuthorizedError() method
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
static decorateNotAuthorizedError(error: Error, reason?: string): ElasticsearchError;
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| error | <code>Error</code> | |
|
||||
| reason | <code>string</code> | |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
`ElasticsearchError`
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [ElasticsearchErrorHelpers](./kibana-plugin-server.elasticsearcherrorhelpers.md) > [isNotAuthorizedError](./kibana-plugin-server.elasticsearcherrorhelpers.isnotauthorizederror.md)
|
||||
|
||||
## ElasticsearchErrorHelpers.isNotAuthorizedError() method
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
static isNotAuthorizedError(error: any): error is ElasticsearchError;
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| error | <code>any</code> | |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
`error is ElasticsearchError`
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [ElasticsearchErrorHelpers](./kibana-plugin-server.elasticsearcherrorhelpers.md)
|
||||
|
||||
## ElasticsearchErrorHelpers class
|
||||
|
||||
Helpers provided to simplify future migration away from Boom as internal Error.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export declare class ElasticsearchErrorHelpers
|
||||
```
|
||||
|
||||
## Methods
|
||||
|
||||
| Method | Modifiers | Description |
|
||||
| --- | --- | --- |
|
||||
| [decorateNotAuthorizedError(error, reason)](./kibana-plugin-server.elasticsearcherrorhelpers.decoratenotauthorizederror.md) | <code>static</code> | |
|
||||
| [isNotAuthorizedError(error)](./kibana-plugin-server.elasticsearcherrorhelpers.isnotauthorizederror.md) | <code>static</code> | |
|
||||
|
||||
## Example
|
||||
|
||||
Handle errors
|
||||
|
||||
```js
|
||||
try {
|
||||
await client.callWithRequest(request, '...');
|
||||
} catch (err) {
|
||||
if (ElasticsearchErrorHelpers.isNotAuthorizedError(err)) {
|
||||
const authHeader = err.output.headers['WWW-Authenticate'];
|
||||
}
|
||||
|
||||
```
|
||||
|
|
@ -15,6 +15,7 @@ The plugin integrates with the core system via lifecycle events: `setup`<!-- -->
|
|||
| Class | Description |
|
||||
| --- | --- |
|
||||
| [ClusterClient](./kibana-plugin-server.clusterclient.md) | Represents an Elasticsearch cluster API client and allows to call API on behalf of the internal Kibana user and the actual user that is derived from the request headers (via <code>asScoped(...)</code>). |
|
||||
| [ElasticsearchErrorHelpers](./kibana-plugin-server.elasticsearcherrorhelpers.md) | Helpers provided to simplify future migration away from Boom as internal Error. |
|
||||
| [KibanaRequest](./kibana-plugin-server.kibanarequest.md) | Kibana specific abstraction for an incoming request. |
|
||||
| [Router](./kibana-plugin-server.router.md) | |
|
||||
| [SavedObjectsErrorHelpers](./kibana-plugin-server.savedobjectserrorhelpers.md) | |
|
||||
|
@ -30,6 +31,7 @@ The plugin integrates with the core system via lifecycle events: `setup`<!-- -->
|
|||
| [CoreSetup](./kibana-plugin-server.coresetup.md) | Context passed to the plugins <code>setup</code> method. |
|
||||
| [CoreStart](./kibana-plugin-server.corestart.md) | Context passed to the plugins <code>start</code> method. |
|
||||
| [DiscoveredPlugin](./kibana-plugin-server.discoveredplugin.md) | Small container object used to expose information about discovered plugins that may or may not have been started. |
|
||||
| [ElasticsearchError](./kibana-plugin-server.elasticsearcherror.md) | |
|
||||
| [ElasticsearchServiceSetup](./kibana-plugin-server.elasticsearchservicesetup.md) | |
|
||||
| [FakeRequest](./kibana-plugin-server.fakerequest.md) | Fake request object created manually by Kibana plugins. |
|
||||
| [HttpServiceSetup](./kibana-plugin-server.httpservicesetup.md) | |
|
||||
|
|
|
@ -16,12 +16,11 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import Boom from 'boom';
|
||||
import { Client } from 'elasticsearch';
|
||||
import { get } from 'lodash';
|
||||
import { Request } from 'hapi';
|
||||
|
||||
import { ElasticsearchErrorHelpers } from './errors';
|
||||
import { GetAuthHeaders, isRealRequest } from '../http';
|
||||
import { filterHeaders, KibanaRequest, ensureRawRequest } from '../http/router';
|
||||
import { Logger } from '../logging';
|
||||
|
@ -97,13 +96,7 @@ async function callAPI(
|
|||
throw err;
|
||||
}
|
||||
|
||||
const boomError = Boom.boomify(err, { statusCode: err.statusCode });
|
||||
const wwwAuthHeader: string = get(err, 'body.error.header[WWW-Authenticate]');
|
||||
|
||||
boomError.output.headers['WWW-Authenticate'] =
|
||||
wwwAuthHeader || 'Basic realm="Authorization Required"';
|
||||
|
||||
throw boomError;
|
||||
throw ElasticsearchErrorHelpers.decorateNotAuthorizedError(err);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
70
src/core/server/elasticsearch/errors.test.ts
Normal file
70
src/core/server/elasticsearch/errors.test.ts
Normal file
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* 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 Boom from 'boom';
|
||||
|
||||
import { ElasticsearchErrorHelpers } from './errors';
|
||||
|
||||
describe('ElasticsearchErrorHelpers', () => {
|
||||
describe('NotAuthorized error', () => {
|
||||
describe('decorateNotAuthorizedError', () => {
|
||||
it('returns original object', () => {
|
||||
const error = new Error();
|
||||
expect(ElasticsearchErrorHelpers.decorateNotAuthorizedError(error)).toBe(error);
|
||||
});
|
||||
|
||||
it('makes the error identifiable as a NotAuthorized error', () => {
|
||||
const error = new Error();
|
||||
expect(ElasticsearchErrorHelpers.isNotAuthorizedError(error)).toBe(false);
|
||||
ElasticsearchErrorHelpers.decorateNotAuthorizedError(error);
|
||||
expect(ElasticsearchErrorHelpers.isNotAuthorizedError(error)).toBe(true);
|
||||
});
|
||||
|
||||
it('adds boom properties', () => {
|
||||
const error = ElasticsearchErrorHelpers.decorateNotAuthorizedError(new Error());
|
||||
expect(typeof error.output).toBe('object');
|
||||
expect(error.output.statusCode).toBe(401);
|
||||
});
|
||||
|
||||
it('preserves boom properties of input', () => {
|
||||
const error = Boom.notFound();
|
||||
ElasticsearchErrorHelpers.decorateNotAuthorizedError(error);
|
||||
expect(error.output.statusCode).toBe(404);
|
||||
});
|
||||
|
||||
describe('error.output', () => {
|
||||
it('defaults to message of error', () => {
|
||||
const error = ElasticsearchErrorHelpers.decorateNotAuthorizedError(new Error('foobar'));
|
||||
expect(error.output.payload).toHaveProperty('message', 'foobar');
|
||||
});
|
||||
it('prefixes message with passed reason', () => {
|
||||
const error = ElasticsearchErrorHelpers.decorateNotAuthorizedError(
|
||||
new Error('foobar'),
|
||||
'biz'
|
||||
);
|
||||
expect(error.output.payload).toHaveProperty('message', 'biz: foobar');
|
||||
});
|
||||
it('sets statusCode to 401', () => {
|
||||
const error = ElasticsearchErrorHelpers.decorateNotAuthorizedError(new Error('foo'));
|
||||
expect(error.output).toHaveProperty('statusCode', 401);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
90
src/core/server/elasticsearch/errors.ts
Normal file
90
src/core/server/elasticsearch/errors.ts
Normal file
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* 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 Boom from 'boom';
|
||||
import { get } from 'lodash';
|
||||
|
||||
const code = Symbol('ElasticsearchError');
|
||||
|
||||
enum ErrorCode {
|
||||
NOT_AUTHORIZED = 'Elasticsearch/notAuthorized',
|
||||
}
|
||||
|
||||
export interface ElasticsearchError extends Boom {
|
||||
[code]?: string;
|
||||
}
|
||||
|
||||
function isElasticsearchError(error: any): error is ElasticsearchError {
|
||||
return Boolean(error && error[code]);
|
||||
}
|
||||
|
||||
function decorate(
|
||||
error: Error,
|
||||
errorCode: ErrorCode,
|
||||
statusCode: number,
|
||||
message?: string
|
||||
): ElasticsearchError {
|
||||
if (isElasticsearchError(error)) {
|
||||
return error;
|
||||
}
|
||||
|
||||
const boom = Boom.boomify(error, {
|
||||
statusCode,
|
||||
message,
|
||||
// keep status and messages if Boom error object already has them
|
||||
override: false,
|
||||
}) as ElasticsearchError;
|
||||
|
||||
boom[code] = errorCode;
|
||||
|
||||
return boom;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helpers for working with errors returned from the Elasticsearch service.Since the internal data of
|
||||
* errors are subject to change, consumers of the Elasticsearch service should always use these helpers
|
||||
* to classify errors instead of checking error internals such as `body.error.header[WWW-Authenticate]`
|
||||
* @public
|
||||
*
|
||||
* @example
|
||||
* Handle errors
|
||||
* ```js
|
||||
* try {
|
||||
* await client.asScoped(request).callAsCurrentUser(...);
|
||||
* } catch (err) {
|
||||
* if (ElasticsearchErrorHelpers.isNotAuthorizedError(err)) {
|
||||
* const authHeader = err.output.headers['WWW-Authenticate'];
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
export class ElasticsearchErrorHelpers {
|
||||
public static isNotAuthorizedError(error: any): error is ElasticsearchError {
|
||||
return isElasticsearchError(error) && error[code] === ErrorCode.NOT_AUTHORIZED;
|
||||
}
|
||||
|
||||
public static decorateNotAuthorizedError(error: Error, reason?: string) {
|
||||
const decoratedError = decorate(error, ErrorCode.NOT_AUTHORIZED, 401, reason);
|
||||
const wwwAuthHeader = get<string>(error, 'body.error.header[WWW-Authenticate]');
|
||||
|
||||
decoratedError.output.headers['WWW-Authenticate'] =
|
||||
wwwAuthHeader || 'Basic realm="Authorization Required"';
|
||||
|
||||
return decoratedError;
|
||||
}
|
||||
}
|
|
@ -22,3 +22,4 @@ export { CallAPIOptions, ClusterClient, FakeRequest, LegacyRequest } from './clu
|
|||
export { ScopedClusterClient, Headers, APICaller } from './scoped_cluster_client';
|
||||
export { ElasticsearchClientConfig } from './elasticsearch_client_config';
|
||||
export { config } from './elasticsearch_config';
|
||||
export { ElasticsearchError, ElasticsearchErrorHelpers } from './errors';
|
||||
|
|
|
@ -48,6 +48,8 @@ export {
|
|||
Headers,
|
||||
ScopedClusterClient,
|
||||
ElasticsearchClientConfig,
|
||||
ElasticsearchError,
|
||||
ElasticsearchErrorHelpers,
|
||||
APICaller,
|
||||
FakeRequest,
|
||||
LegacyRequest,
|
||||
|
|
|
@ -122,6 +122,22 @@ export type ElasticsearchClientConfig = Pick<ConfigOptions, 'keepAlive' | 'log'
|
|||
ssl?: Partial<ElasticsearchConfig['ssl']>;
|
||||
};
|
||||
|
||||
// Warning: (ae-missing-release-tag) "ElasticsearchError" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
export interface ElasticsearchError extends Boom {
|
||||
// (undocumented)
|
||||
[code]?: string;
|
||||
}
|
||||
|
||||
// @public
|
||||
export class ElasticsearchErrorHelpers {
|
||||
// (undocumented)
|
||||
static decorateNotAuthorizedError(error: Error, reason?: string): ElasticsearchError;
|
||||
// (undocumented)
|
||||
static isNotAuthorizedError(error: any): error is ElasticsearchError;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
export interface ElasticsearchServiceSetup {
|
||||
// (undocumented)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue