From cfc09e1a9a40073e9ecbfee55f8468ceccfc232d Mon Sep 17 00:00:00 2001 From: spalger Date: Tue, 26 Sep 2017 13:24:51 -0700 Subject: [PATCH 1/3] [errors/multi.allow_explicit_index] move error handling to browser A part of #14163, this removes the portion of the healthCheck that tries to verify that rest.action.multi.allow_explicit_index is not set to false. Instead, a ui module was created that will check errors from elasticsearch for this specific scenario, and exposes a method that will display a nicer "fatal error" screen that informs the user about what they should do, and navigates away from the now broken app. --- .../lib/ensure_allow_explicit_index.js | 36 ------------------- .../elasticsearch/lib/health_check.js | 2 -- src/ui/public/courier/fetch/call_client.js | 13 ++++--- .../error_allow_explicit_index.html | 19 ++++++++++ .../error_allow_explicit_index.js | 35 ++++++++++++++++++ .../error_allow_explicit_index.less | 3 ++ .../error_allow_explicit_index/index.js | 1 + src/ui/public/promises/promises.js | 2 +- 8 files changed, 68 insertions(+), 43 deletions(-) delete mode 100644 src/core_plugins/elasticsearch/lib/ensure_allow_explicit_index.js create mode 100644 src/ui/public/error_allow_explicit_index/error_allow_explicit_index.html create mode 100644 src/ui/public/error_allow_explicit_index/error_allow_explicit_index.js create mode 100644 src/ui/public/error_allow_explicit_index/error_allow_explicit_index.less create mode 100644 src/ui/public/error_allow_explicit_index/index.js diff --git a/src/core_plugins/elasticsearch/lib/ensure_allow_explicit_index.js b/src/core_plugins/elasticsearch/lib/ensure_allow_explicit_index.js deleted file mode 100644 index 7444b6862721c1..00000000000000 --- a/src/core_plugins/elasticsearch/lib/ensure_allow_explicit_index.js +++ /dev/null @@ -1,36 +0,0 @@ -export async function ensureAllowExplicitIndex(callWithInternalUser, config) { - const resp = await callWithInternalUser('mget', { - ignore: [400], - body: { - docs: [ - { - _index: config.get('kibana.index'), - _type: 'config', - _id: config.get('pkg.version'), - }, - ], - }, - }); - - if (!resp.error) { - return true; - } - - const error = resp.error || {}; - const errorReason = error.reason || ''; - - const isArgError = error.type === 'illegal_argument_exception'; - const isExplicitIndexException = isArgError && errorReason.includes('explicit index'); - - if (isExplicitIndexException) { - throw new Error( - 'Kibana must be able to specify the index within Elasticsearch multi-requests ' + - '(rest.action.multi.allow_explicit_index=true).' - ); - } - - throw new Error( - 'Unable to ensure that rest.action.multi.allow_explicit_index=true: ' + - `[${error.type}] ${errorReason}` - ); -} diff --git a/src/core_plugins/elasticsearch/lib/health_check.js b/src/core_plugins/elasticsearch/lib/health_check.js index 2cc952e1b88309..7e703d693cf4b0 100644 --- a/src/core_plugins/elasticsearch/lib/health_check.js +++ b/src/core_plugins/elasticsearch/lib/health_check.js @@ -6,7 +6,6 @@ import createKibanaIndex from './create_kibana_index'; import kibanaVersion from './kibana_version'; import { ensureEsVersion } from './ensure_es_version'; import { ensureNotTribe } from './ensure_not_tribe'; -import { ensureAllowExplicitIndex } from './ensure_allow_explicit_index'; import { patchKibanaIndex } from './patch_kibana_index'; const NoConnections = elasticsearch.errors.NoConnections; @@ -97,7 +96,6 @@ export default function (plugin, server) { waitForPong(callAdminAsKibanaUser, config.get('elasticsearch.url')) .then(waitForEsVersion) .then(() => ensureNotTribe(callAdminAsKibanaUser)) - .then(() => ensureAllowExplicitIndex(callAdminAsKibanaUser, config)) .then(waitForShards) .then(() => patchKibanaIndex({ callCluster: callAdminAsKibanaUser, diff --git a/src/ui/public/courier/fetch/call_client.js b/src/ui/public/courier/fetch/call_client.js index d8dc0ed3ea5dbf..7d1d544dee32f8 100644 --- a/src/ui/public/courier/fetch/call_client.js +++ b/src/ui/public/courier/fetch/call_client.js @@ -1,11 +1,12 @@ import _ from 'lodash'; +import { ErrorAllowExplicitIndexProvider } from 'ui/error_allow_explicit_index'; import { IsRequestProvider } from './is_request'; import { MergeDuplicatesRequestProvider } from './merge_duplicate_requests'; import { ReqStatusProvider } from './req_status'; export function CallClientProvider(Private, Promise, es) { - + const errorAllowExplicitIndex = Private(ErrorAllowExplicitIndexProvider); const isRequest = Private(IsRequestProvider); const mergeDuplicateRequests = Private(MergeDuplicatesRequestProvider); @@ -121,9 +122,13 @@ export function CallClientProvider(Private, Promise, es) { return strategy.getResponses(clientResp); }) .then(respond) - .catch(function (err) { - if (err === ABORTED) respond(); - else defer.reject(err); + .catch(function (error) { + if (errorAllowExplicitIndex.test(error)) { + return errorAllowExplicitIndex.takeover(); + } + + if (error === ABORTED) respond(); + else defer.reject(error); }); // return our promise, but catch any errors we create and diff --git a/src/ui/public/error_allow_explicit_index/error_allow_explicit_index.html b/src/ui/public/error_allow_explicit_index/error_allow_explicit_index.html new file mode 100644 index 00000000000000..836392832014c7 --- /dev/null +++ b/src/ui/public/error_allow_explicit_index/error_allow_explicit_index.html @@ -0,0 +1,19 @@ +
+

+ Oh no! +

+

+ It looks like your Elasticsearch cluster has the rest.action.multi.allow_explicit_index setting set to false, which prevents Kibana from making search requests. We use this ability to send a single request to Elasticsearch that searches multiple indexes so that when there are many panels on a dashboard they will load quickly and uniformly. +

+ +

+ Unfortunately, until this issue is fixed you won't be able to use certain apps in Kibana, like Discover, Visualize and Dashboard. +

+ +

Ok, how do I fix this?

+
    +
  1. Remove rest.action.multi.allow_explicit_index: false from your Elasticsearch config file.
  2. +
  3. Restart elasticsearch.
  4. +
  5. Use the browser's back button to return to what you were doing.
  6. +
+
diff --git a/src/ui/public/error_allow_explicit_index/error_allow_explicit_index.js b/src/ui/public/error_allow_explicit_index/error_allow_explicit_index.js new file mode 100644 index 00000000000000..e86bf7e97c0de9 --- /dev/null +++ b/src/ui/public/error_allow_explicit_index/error_allow_explicit_index.js @@ -0,0 +1,35 @@ +import { get } from 'lodash'; + +import uiRoutes from 'ui/routes'; +import { KbnUrlProvider } from 'ui/url'; + +import './error_allow_explicit_index.less'; +import template from './error_allow_explicit_index.html'; + +uiRoutes +.when('/error/multi.allow_explicit_index', { template }); + +export function ErrorAllowExplicitIndexProvider(Private, Promise) { + const kbnUrl = Private(KbnUrlProvider); + + return new class ErrorAllowExplicitIndex { + test(error) { + if (!error || error.status !== 400) { + return false; + } + + const type = get(error, 'body.error.type'); + const reason = get(error, 'body.error.reason'); + + return ( + type === 'illegal_argument_exception' && + String(reason).includes('explicit index') + ); + } + + takeover() { + kbnUrl.change('/error/multi.allow_explicit_index'); + return Promise.halt(); + } + }; +} diff --git a/src/ui/public/error_allow_explicit_index/error_allow_explicit_index.less b/src/ui/public/error_allow_explicit_index/error_allow_explicit_index.less new file mode 100644 index 00000000000000..31f7d1f9e38418 --- /dev/null +++ b/src/ui/public/error_allow_explicit_index/error_allow_explicit_index.less @@ -0,0 +1,3 @@ +.error-multi-allow-explicit-index { + padding: 25px; +} diff --git a/src/ui/public/error_allow_explicit_index/index.js b/src/ui/public/error_allow_explicit_index/index.js new file mode 100644 index 00000000000000..eee252ff860ef1 --- /dev/null +++ b/src/ui/public/error_allow_explicit_index/index.js @@ -0,0 +1 @@ +export { ErrorAllowExplicitIndexProvider } from './error_allow_explicit_index'; diff --git a/src/ui/public/promises/promises.js b/src/ui/public/promises/promises.js index ad77030c7c3715..694f2341d898a4 100644 --- a/src/ui/public/promises/promises.js +++ b/src/ui/public/promises/promises.js @@ -64,7 +64,7 @@ module.service('Promise', function ($q, $timeout) { return obj && typeof obj.then === 'function'; }; Promise.halt = _.once(function () { - const promise = new Promise(); + const promise = new Promise(() => {}); promise.then = _.constant(promise); promise.catch = _.constant(promise); return promise; From 2dd3779823999b1acac9eab4b2753f4dace3c127 Mon Sep 17 00:00:00 2001 From: spalger Date: Wed, 27 Sep 2017 07:55:04 -0700 Subject: [PATCH 2/3] [es/healthCheck] remove old test --- .../__tests__/ensure_allow_explicit_index.js | 75 ------------------- 1 file changed, 75 deletions(-) delete mode 100644 src/core_plugins/elasticsearch/lib/__tests__/ensure_allow_explicit_index.js diff --git a/src/core_plugins/elasticsearch/lib/__tests__/ensure_allow_explicit_index.js b/src/core_plugins/elasticsearch/lib/__tests__/ensure_allow_explicit_index.js deleted file mode 100644 index ac86c4ec68ef0e..00000000000000 --- a/src/core_plugins/elasticsearch/lib/__tests__/ensure_allow_explicit_index.js +++ /dev/null @@ -1,75 +0,0 @@ -import sinon from 'sinon'; -import expect from 'expect.js'; - -import { ensureAllowExplicitIndex } from '../ensure_allow_explicit_index'; - -const createStubCallWithInternal = responders => ( - sinon.spy(async (params) => { - if (responders.length) { - return await responders.shift()(params); - } - - throw new Error('Unexpected client.mget call'); - }) -); - -const createStubConfig = () => ({ - get: sinon.spy((key) => { - switch (key) { - case 'kibana.index': return '.kibana'; - case 'pkg.version': return '0.0.0'; - default: throw new Error(`Unexpected config.get('${key}') call`); - } - }) -}); - -describe('ensureAllowExplicitIndex()', () => { - it('attempts an mget with index in request', async () => { - const config = createStubConfig(); - const callWithInternalUser = createStubCallWithInternal([ - () => ({ ok: true }) - ]); - - const resp = await ensureAllowExplicitIndex(callWithInternalUser, config); - expect(resp).to.be(true); - }); - - it(`reports "illegal_argument_exception" that mentions "explicit index"`, async () => { - const config = createStubConfig(); - const callWithInternalUser = createStubCallWithInternal([ - () => ({ - error: { - type: 'illegal_argument_exception', - reason: 'explicit index not supported' - } - }) - ]); - - try { - await ensureAllowExplicitIndex(callWithInternalUser, config); - throw new Error('expected ensureAllowExplicitIndex() to throw error'); - } catch (error) { - expect(error.message).to.contain('rest.action.multi.allow_explicit_index'); - } - }); - - it('reports unexpected errors', async () => { - const config = createStubConfig(); - const callWithInternalUser = createStubCallWithInternal([ - () => ({ - error: { - type: 'foo', - reason: 'bar' - } - }) - ]); - - try { - await ensureAllowExplicitIndex(callWithInternalUser, config); - throw new Error('expected ensureAllowExplicitIndex() to throw error'); - } catch (error) { - expect(error.message).to.contain('[foo]'); - expect(error.message).to.contain('bar'); - } - }); -}); From 28c5c98dbb7c5b85250d241edd04d3449ad84623 Mon Sep 17 00:00:00 2001 From: spalger Date: Tue, 3 Oct 2017 16:48:12 -0700 Subject: [PATCH 3/3] fix typo --- .../error_allow_explicit_index/error_allow_explicit_index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ui/public/error_allow_explicit_index/error_allow_explicit_index.html b/src/ui/public/error_allow_explicit_index/error_allow_explicit_index.html index 836392832014c7..3af52f4ee1720d 100644 --- a/src/ui/public/error_allow_explicit_index/error_allow_explicit_index.html +++ b/src/ui/public/error_allow_explicit_index/error_allow_explicit_index.html @@ -13,7 +13,7 @@

Ok, how do I fix this?

  1. Remove rest.action.multi.allow_explicit_index: false from your Elasticsearch config file.
  2. -
  3. Restart elasticsearch.
  4. +
  5. Restart Elasticsearch.
  6. Use the browser's back button to return to what you were doing.