Skip to content

Commit

Permalink
Adds error from es call to nodes.info to the nodes version compatibil…
Browse files Browse the repository at this point in the history
…ity response message (elastic#100005)

Co-authored-by: Kibana Machine <[email protected]>
  • Loading branch information
TinaHeiligers and kibanamachine committed May 14, 2021
1 parent 8df5efa commit da27f23
Show file tree
Hide file tree
Showing 10 changed files with 295 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,6 @@ export interface ElasticsearchStatusMeta
| Property | Type | Description |
| --- | --- | --- |
| [incompatibleNodes](./kibana-plugin-core-server.elasticsearchstatusmeta.incompatiblenodes.md) | <code>NodesVersionCompatibility['incompatibleNodes']</code> | |
| [nodesInfoRequestError](./kibana-plugin-core-server.elasticsearchstatusmeta.nodesinforequesterror.md) | <code>NodesVersionCompatibility['nodesInfoRequestError']</code> | |
| [warningNodes](./kibana-plugin-core-server.elasticsearchstatusmeta.warningnodes.md) | <code>NodesVersionCompatibility['warningNodes']</code> | |

Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<!-- 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; [ElasticsearchStatusMeta](./kibana-plugin-core-server.elasticsearchstatusmeta.md) &gt; [nodesInfoRequestError](./kibana-plugin-core-server.elasticsearchstatusmeta.nodesinforequesterror.md)

## ElasticsearchStatusMeta.nodesInfoRequestError property

<b>Signature:</b>

```typescript
nodesInfoRequestError?: NodesVersionCompatibility['nodesInfoRequestError'];
```
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,6 @@ export interface NodesVersionCompatibility
| [isCompatible](./kibana-plugin-core-server.nodesversioncompatibility.iscompatible.md) | <code>boolean</code> | |
| [kibanaVersion](./kibana-plugin-core-server.nodesversioncompatibility.kibanaversion.md) | <code>string</code> | |
| [message](./kibana-plugin-core-server.nodesversioncompatibility.message.md) | <code>string</code> | |
| [nodesInfoRequestError](./kibana-plugin-core-server.nodesversioncompatibility.nodesinforequesterror.md) | <code>Error</code> | |
| [warningNodes](./kibana-plugin-core-server.nodesversioncompatibility.warningnodes.md) | <code>NodeInfo[]</code> | |

Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<!-- 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; [NodesVersionCompatibility](./kibana-plugin-core-server.nodesversioncompatibility.md) &gt; [nodesInfoRequestError](./kibana-plugin-core-server.nodesversioncompatibility.nodesinforequesterror.md)

## NodesVersionCompatibility.nodesInfoRequestError property

<b>Signature:</b>

```typescript
nodesInfoRequestError?: Error;
```
115 changes: 114 additions & 1 deletion src/core/server/elasticsearch/status.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ describe('calculateStatus', () => {
});
});

it('changes to available with a differemnt message when isCompatible and warningNodes present', async () => {
it('changes to available with a different message when isCompatible and warningNodes present', async () => {
expect(
await calculateStatus$(
of({
Expand Down Expand Up @@ -204,4 +204,117 @@ describe('calculateStatus', () => {
]
`);
});

it('emits status updates when node info request error changes', () => {
const nodeCompat$ = new Subject<NodesVersionCompatibility>();

const statusUpdates: ServiceStatus[] = [];
const subscription = calculateStatus$(nodeCompat$).subscribe((status) =>
statusUpdates.push(status)
);

nodeCompat$.next({
isCompatible: false,
kibanaVersion: '1.1.1',
incompatibleNodes: [],
warningNodes: [],
message: 'Unable to retrieve version info. connect ECONNREFUSED',
nodesInfoRequestError: new Error('connect ECONNREFUSED'),
});
nodeCompat$.next({
isCompatible: false,
kibanaVersion: '1.1.1',
incompatibleNodes: [],
warningNodes: [],
message: 'Unable to retrieve version info. security_exception',
nodesInfoRequestError: new Error('security_exception'),
});

subscription.unsubscribe();
expect(statusUpdates).toMatchInlineSnapshot(`
Array [
Object {
"level": unavailable,
"meta": Object {
"incompatibleNodes": Array [],
"warningNodes": Array [],
},
"summary": "Waiting for Elasticsearch",
},
Object {
"level": critical,
"meta": Object {
"incompatibleNodes": Array [],
"nodesInfoRequestError": [Error: connect ECONNREFUSED],
"warningNodes": Array [],
},
"summary": "Unable to retrieve version info. connect ECONNREFUSED",
},
Object {
"level": critical,
"meta": Object {
"incompatibleNodes": Array [],
"nodesInfoRequestError": [Error: security_exception],
"warningNodes": Array [],
},
"summary": "Unable to retrieve version info. security_exception",
},
]
`);
});

it('changes to available when a request error is resolved', () => {
const nodeCompat$ = new Subject<NodesVersionCompatibility>();

const statusUpdates: ServiceStatus[] = [];
const subscription = calculateStatus$(nodeCompat$).subscribe((status) =>
statusUpdates.push(status)
);

nodeCompat$.next({
isCompatible: false,
kibanaVersion: '1.1.1',
incompatibleNodes: [],
warningNodes: [],
message: 'Unable to retrieve version info. security_exception',
nodesInfoRequestError: new Error('security_exception'),
});
nodeCompat$.next({
isCompatible: true,
kibanaVersion: '1.1.1',
warningNodes: [],
incompatibleNodes: [],
});

subscription.unsubscribe();
expect(statusUpdates).toMatchInlineSnapshot(`
Array [
Object {
"level": unavailable,
"meta": Object {
"incompatibleNodes": Array [],
"warningNodes": Array [],
},
"summary": "Waiting for Elasticsearch",
},
Object {
"level": critical,
"meta": Object {
"incompatibleNodes": Array [],
"nodesInfoRequestError": [Error: security_exception],
"warningNodes": Array [],
},
"summary": "Unable to retrieve version info. security_exception",
},
Object {
"level": available,
"meta": Object {
"incompatibleNodes": Array [],
"warningNodes": Array [],
},
"summary": "Elasticsearch is available",
},
]
`);
});
});
7 changes: 6 additions & 1 deletion src/core/server/elasticsearch/status.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export const calculateStatus$ = (
message,
incompatibleNodes,
warningNodes,
nodesInfoRequestError,
}): ServiceStatus<ElasticsearchStatusMeta> => {
if (!isCompatible) {
return {
Expand All @@ -40,7 +41,11 @@ export const calculateStatus$ = (
// Message should always be present, but this is a safe fallback
message ??
`Some Elasticsearch nodes are not compatible with this version of Kibana`,
meta: { warningNodes, incompatibleNodes },
meta: {
warningNodes,
incompatibleNodes,
...(nodesInfoRequestError && { nodesInfoRequestError }),
},
};
} else if (warningNodes.length > 0) {
return {
Expand Down
1 change: 1 addition & 0 deletions src/core/server/elasticsearch/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ export type InternalElasticsearchServiceStart = ElasticsearchServiceStart;
export interface ElasticsearchStatusMeta {
warningNodes: NodesVersionCompatibility['warningNodes'];
incompatibleNodes: NodesVersionCompatibility['incompatibleNodes'];
nodesInfoRequestError?: NodesVersionCompatibility['nodesInfoRequestError'];
}

/**
Expand Down
123 changes: 120 additions & 3 deletions src/core/server/elasticsearch/version_check/ensure_es_version.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ const mockLogger = mockLoggerFactory.get('mock logger');
const KIBANA_VERSION = '5.1.0';

const createEsSuccess = elasticsearchClientMock.createSuccessTransportRequestPromise;
const createEsError = elasticsearchClientMock.createErrorTransportRequestPromise;
const createEsErrorReturn = (err: any) =>
elasticsearchClientMock.createErrorTransportRequestPromise(err);

function createNodes(...versions: string[]): NodesInfo {
const nodes = {} as any;
Expand Down Expand Up @@ -102,6 +103,28 @@ describe('mapNodesVersionCompatibility', () => {
`"You're running Kibana 5.1.0 with some different versions of Elasticsearch. Update Kibana or Elasticsearch to the same version to prevent compatibility issues: v5.1.1 @ http_address (ip)"`
);
});

it('returns isCompatible=false without an extended message when a nodesInfoRequestError is not provided', async () => {
const result = mapNodesVersionCompatibility({ nodes: {} }, KIBANA_VERSION, false);
expect(result.isCompatible).toBe(false);
expect(result.nodesInfoRequestError).toBeUndefined();
expect(result.message).toMatchInlineSnapshot(
`"Unable to retrieve version information from Elasticsearch nodes."`
);
});

it('returns isCompatible=false with an extended message when a nodesInfoRequestError is present', async () => {
const result = mapNodesVersionCompatibility(
{ nodes: {}, nodesInfoRequestError: new Error('connection refused') },
KIBANA_VERSION,
false
);
expect(result.isCompatible).toBe(false);
expect(result.nodesInfoRequestError).toBeTruthy();
expect(result.message).toMatchInlineSnapshot(
`"Unable to retrieve version information from Elasticsearch nodes. connection refused"`
);
});
});

describe('pollEsNodesVersion', () => {
Expand All @@ -119,10 +142,10 @@ describe('pollEsNodesVersion', () => {
internalClient.nodes.info.mockImplementationOnce(() => createEsSuccess(infos));
};
const nodeInfosErrorOnce = (error: any) => {
internalClient.nodes.info.mockImplementationOnce(() => createEsError(error));
internalClient.nodes.info.mockImplementationOnce(() => createEsErrorReturn(new Error(error)));
};

it('returns iscCompatible=false and keeps polling when a poll request throws', (done) => {
it('returns isCompatible=false and keeps polling when a poll request throws', (done) => {
expect.assertions(3);
const expectedCompatibilityResults = [false, false, true];
jest.clearAllMocks();
Expand All @@ -148,6 +171,100 @@ describe('pollEsNodesVersion', () => {
});
});

it('returns the error from a failed nodes.info call when a poll request throws', (done) => {
expect.assertions(2);
const expectedCompatibilityResults = [false];
const expectedMessageResults = [
'Unable to retrieve version information from Elasticsearch nodes. mock request error',
];
jest.clearAllMocks();

nodeInfosErrorOnce('mock request error');

pollEsNodesVersion({
internalClient,
esVersionCheckInterval: 1,
ignoreVersionMismatch: false,
kibanaVersion: KIBANA_VERSION,
log: mockLogger,
})
.pipe(take(1))
.subscribe({
next: (result) => {
expect(result.isCompatible).toBe(expectedCompatibilityResults.shift());
expect(result.message).toBe(expectedMessageResults.shift());
},
complete: done,
error: done,
});
});

it('only emits if the error from a failed nodes.info call changed from the previous poll', (done) => {
expect.assertions(4);
const expectedCompatibilityResults = [false, false];
const expectedMessageResults = [
'Unable to retrieve version information from Elasticsearch nodes. mock request error',
'Unable to retrieve version information from Elasticsearch nodes. mock request error 2',
];
jest.clearAllMocks();

nodeInfosErrorOnce('mock request error'); // emit
nodeInfosErrorOnce('mock request error'); // ignore, same error message
nodeInfosErrorOnce('mock request error 2'); // emit

pollEsNodesVersion({
internalClient,
esVersionCheckInterval: 1,
ignoreVersionMismatch: false,
kibanaVersion: KIBANA_VERSION,
log: mockLogger,
})
.pipe(take(2))
.subscribe({
next: (result) => {
expect(result.message).toBe(expectedMessageResults.shift());
expect(result.isCompatible).toBe(expectedCompatibilityResults.shift());
},
complete: done,
error: done,
});
});

it('returns isCompatible=false and keeps polling when a poll request throws, only responding again if the error message has changed', (done) => {
expect.assertions(8);
const expectedCompatibilityResults = [false, false, true, false];
const expectedMessageResults = [
'This version of Kibana (v5.1.0) is incompatible with the following Elasticsearch nodes in your cluster: v5.0.0 @ http_address (ip)',
'Unable to retrieve version information from Elasticsearch nodes. mock request error',
"You're running Kibana 5.1.0 with some different versions of Elasticsearch. Update Kibana or Elasticsearch to the same version to prevent compatibility issues: v5.2.0 @ http_address (ip), v5.1.1-Beta1 @ http_address (ip)",
'Unable to retrieve version information from Elasticsearch nodes. mock request error',
];
jest.clearAllMocks();

nodeInfosSuccessOnce(createNodes('5.1.0', '5.2.0', '5.0.0')); // emit
nodeInfosErrorOnce('mock request error'); // emit
nodeInfosErrorOnce('mock request error'); // ignore
nodeInfosSuccessOnce(createNodes('5.1.0', '5.2.0', '5.1.1-Beta1')); // emit
nodeInfosErrorOnce('mock request error'); // emit

pollEsNodesVersion({
internalClient,
esVersionCheckInterval: 1,
ignoreVersionMismatch: false,
kibanaVersion: KIBANA_VERSION,
log: mockLogger,
})
.pipe(take(4))
.subscribe({
next: (result) => {
expect(result.isCompatible).toBe(expectedCompatibilityResults.shift());
expect(result.message).toBe(expectedMessageResults.shift());
},
complete: done,
error: done,
});
});

it('returns compatibility results', (done) => {
expect.assertions(1);
const nodes = createNodes('5.1.0', '5.2.0', '5.0.0');
Expand Down
Loading

0 comments on commit da27f23

Please sign in to comment.