mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
Backport PR #8339
---------
**Commit 1:**
Set minimum aggregation 'Size' input value to 1, because ES will return an error if you provide a size of 0.
- Display feedback if a Dashboard or Visualization is loaded that already violates this constraint.
- Add ElasticsearchError class and isTermSizeZeroError helper.
* Original sha: 4fefae1513
* Authored by CJ Cenizal <cj@cenizal.com> on 2016-09-19T19:02:54Z
This commit is contained in:
parent
0c2ff0f189
commit
cfde9f4750
7 changed files with 147 additions and 4 deletions
|
@ -17,7 +17,7 @@
|
||||||
required
|
required
|
||||||
class="form-control"
|
class="form-control"
|
||||||
type="number"
|
type="number"
|
||||||
min="0"
|
min="1"
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
import sinon from 'auto-release-sinon';
|
||||||
|
import expect from 'expect.js';
|
||||||
|
import ElasticsearchError from '../elasticsearch_error';
|
||||||
|
|
||||||
|
describe('ElasticsearchError', () => {
|
||||||
|
function createError(rootCauses = []) {
|
||||||
|
// Elasticsearch errors are characterized by the resp.error.root_cause array.
|
||||||
|
return {
|
||||||
|
resp: {
|
||||||
|
error: {
|
||||||
|
root_cause: rootCauses.map(rootCause => ({
|
||||||
|
reason: rootCause,
|
||||||
|
})),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('interface', () => {
|
||||||
|
describe('constructor', () => {
|
||||||
|
it('throws an error if instantiated with a non-elasticsearch error', () => {
|
||||||
|
expect(() => new ElasticsearchError({})).to.throwError();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getRootCauses', () => {
|
||||||
|
it(`returns the root_cause array's reason values`, () => {
|
||||||
|
const rootCauses = ['a', 'b'];
|
||||||
|
const error = createError(rootCauses);
|
||||||
|
const esError = new ElasticsearchError(error);
|
||||||
|
expect(esError.getRootCauses()).to.eql(rootCauses);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('hasRootCause', () => {
|
||||||
|
it(`returns true if the cause occurs in the root_cause array's reasons, insensitive to case`, () => {
|
||||||
|
const rootCauses = ['a very detailed error', 'a slightly more detailed error'];
|
||||||
|
const error = createError(rootCauses);
|
||||||
|
const esError = new ElasticsearchError(error);
|
||||||
|
expect(esError.hasRootCause('slightly MORE')).to.be(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`returns false if the cause doesn't occur in the root_cause array's reasons`, () => {
|
||||||
|
const rootCauses = ['a very detailed error', 'a slightly more detailed error'];
|
||||||
|
const error = createError(rootCauses);
|
||||||
|
const esError = new ElasticsearchError(error);
|
||||||
|
expect(esError.hasRootCause('nonexistent error')).to.be(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,33 @@
|
||||||
|
import sinon from 'auto-release-sinon';
|
||||||
|
import expect from 'expect.js';
|
||||||
|
import isTermSizeZeroError from '../is_term_size_zero_error';
|
||||||
|
|
||||||
|
describe('isTermSizeZeroError', () => {
|
||||||
|
const identifyingString = 'size must be positive, got 0';
|
||||||
|
|
||||||
|
it('returns true if it contains the identifying string', () => {
|
||||||
|
const error = {
|
||||||
|
resp: {
|
||||||
|
error: {
|
||||||
|
root_cause: [{
|
||||||
|
reason: `Some crazy Java exception: ${identifyingString}`,
|
||||||
|
}],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
expect(isTermSizeZeroError(error)).to.be(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`returns false if it doesn't contain the identifying string`, () => {
|
||||||
|
const error = {
|
||||||
|
resp: {
|
||||||
|
error: {
|
||||||
|
root_cause: [{
|
||||||
|
reason: `Some crazy Java exception`,
|
||||||
|
}],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
expect(isTermSizeZeroError(error)).to.be(false);
|
||||||
|
});
|
||||||
|
});
|
32
src/ui/public/elasticsearch_errors/elasticsearch_error.js
Normal file
32
src/ui/public/elasticsearch_errors/elasticsearch_error.js
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
import _ from 'lodash';
|
||||||
|
|
||||||
|
export default class ElasticsearchError {
|
||||||
|
constructor(error) {
|
||||||
|
this.error = error;
|
||||||
|
|
||||||
|
this.getRootCauses = this.getRootCauses.bind(this);
|
||||||
|
this.hasRootCause = this.hasRootCause.bind(this);
|
||||||
|
|
||||||
|
if (!this.getRootCauses().length) {
|
||||||
|
throw new Error(
|
||||||
|
'ElasticsearchError must be instantiated with an elasticsearch error, i.e. it must have' +
|
||||||
|
`a resp.error.root_cause property. Instead got ${JSON.stringify(error)}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getRootCauses() {
|
||||||
|
const rootCauses = _.get(this.error, 'resp.error.root_cause');
|
||||||
|
return _.pluck(rootCauses, 'reason');
|
||||||
|
}
|
||||||
|
|
||||||
|
hasRootCause(cause) {
|
||||||
|
const normalizedCause = cause.toLowerCase();
|
||||||
|
const rootCauses = this.getRootCauses();
|
||||||
|
const matchingCauses = rootCauses.filter(rootCause => {
|
||||||
|
const normalizedRootCause = rootCause.toLowerCase();
|
||||||
|
return normalizedRootCause.indexOf(normalizedCause) !== -1;
|
||||||
|
});
|
||||||
|
return matchingCauses.length !== 0;
|
||||||
|
}
|
||||||
|
}
|
7
src/ui/public/elasticsearch_errors/index.js
Normal file
7
src/ui/public/elasticsearch_errors/index.js
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
export {
|
||||||
|
default as ElasticsearchError,
|
||||||
|
} from './elasticsearch_error';
|
||||||
|
|
||||||
|
export {
|
||||||
|
default as isTermSizeZeroError,
|
||||||
|
} from './is_term_size_zero_error';
|
|
@ -0,0 +1,6 @@
|
||||||
|
import ElasticsearchError from './elasticsearch_error';
|
||||||
|
|
||||||
|
export default function isTermSizeZeroError(error) {
|
||||||
|
const esError = new ElasticsearchError(error);
|
||||||
|
return esError.hasRootCause('size must be positive, got 0');
|
||||||
|
}
|
|
@ -8,6 +8,10 @@ import uiModules from 'ui/modules';
|
||||||
import visualizeTemplate from 'ui/visualize/visualize.html';
|
import visualizeTemplate from 'ui/visualize/visualize.html';
|
||||||
import 'angular-sanitize';
|
import 'angular-sanitize';
|
||||||
|
|
||||||
|
import {
|
||||||
|
isTermSizeZeroError,
|
||||||
|
} from '../elasticsearch_errors';
|
||||||
|
|
||||||
uiModules
|
uiModules
|
||||||
.get('kibana/directive', ['ngSanitize'])
|
.get('kibana/directive', ['ngSanitize'])
|
||||||
.directive('visualize', function (Notifier, SavedVis, indexPatterns, Private, config, $timeout) {
|
.directive('visualize', function (Notifier, SavedVis, indexPatterns, Private, config, $timeout) {
|
||||||
|
@ -155,7 +159,17 @@ uiModules
|
||||||
return searchSource.onResults().then(onResults);
|
return searchSource.onResults().then(onResults);
|
||||||
}).catch(notify.fatal);
|
}).catch(notify.fatal);
|
||||||
|
|
||||||
searchSource.onError(notify.error).catch(notify.fatal);
|
searchSource.onError(e => {
|
||||||
|
if (isTermSizeZeroError(e)) {
|
||||||
|
return notify.error(
|
||||||
|
`Your visualization ('${$scope.vis.title}') has an error: it has a term ` +
|
||||||
|
`aggregation with a size of 0. Please set it to a number greater than 0 to resolve ` +
|
||||||
|
`the error.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
notify.error(e);
|
||||||
|
}).catch(notify.fatal);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
$scope.$watch('esResp', prereq(function (resp, prevResp) {
|
$scope.$watch('esResp', prereq(function (resp, prevResp) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue