Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[savedObjects] fix error handling when Kibana index is missing #14141

Merged
merged 34 commits into from
Oct 3, 2017

Conversation

spalger
Copy link
Contributor

@spalger spalger commented Sep 23, 2017

Currently when the Kibana index is missing the savedObjectsClient and APIs produce unexpected results. This PR tests and formalizes the following behaviors:

For those unfamiliar, run the API integration tests and dependencies in one go with:

npx grunt test:api

To run the server/runner combo and for debugging run the following two commands in separate tabs:

# start es/kibana, will auto restart on changes
npx grunt test:api:server

# run the ftr once, supports `--debug-brk`, `--inspect`, `--grep` and the like
node scripts/functional_test_runner --config test/api_integration/config.js

@spalger spalger added Team:Core Core services & architecture: plugins, logging, config, saved objects, http, ES client, i18n, etc review v6.0.0 v6.1.0 v7.0.0 labels Sep 23, 2017
Copy link
Contributor

@kimjoar kimjoar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a couple nitpicks, but I'm good with merging as-is. LGTM

}

// 404 might be because document is missing or index is missing,
// don't leak that implementation detail to the user
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be great if we could add an explanation here. (Basically answering the question: Why don't we want to leak this to the user?)

We've got this same comment in multiple places. Not sure if we should add an explanation in one place and "link" there, but it feels like we should make it clear here, at least.

.expect(200)
.then(resp => {
expect(resp.body).to.eql({
saved_objects: [
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be 🎉 to have snapshot tests for these, but that's of course not possible yet

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are basically snapshot tests, no? What would be different with a snapshot test?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

++ Yeah, it's basically the same (I just prefer working with snapshots over large objects, e.g. when changing code etc)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shit, I totally meant to delete my comment, thought it failed, and accidentally deleted yours 😿

});
});

describe('unkown id', () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo, unknown

@@ -25,6 +24,62 @@ export class SavedObjectsClient {
this._unwrappedCallCluster = callCluster;
}

/**
* ## SavedObjectsClient errors
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright, you asked for some docs @kjbekkelund :) I don't think it's bad to have some of these thought written down but let me know if you think I went overboard

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❤️ I like this! It gives tons of context and makes it way easier to understand why we do what we do.

const indexNotFound = response.error && response.error.type === 'index_not_found_exception';
if (docNotFound || indexNotFound) {
// see "404s from missing index" above
throw errors.createGenericNotFoundError();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also fixed the lib/errors module. Including a decorateNotFoundError contradicts the goal of not exposing where NotFound errors come from, so now it has a createGenericNotFoundError() that does the same thing these lines were doing.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@elastic elastic deleted a comment from kimjoar Sep 29, 2017
@spalger
Copy link
Contributor Author

spalger commented Sep 29, 2017

@epixa any more feedback?

Copy link
Member

@azasypkin azasypkin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, just few nits.

* by the decorators in `./lib/errors`
*
* Type 1 errors are inevitable, but since all expected/handle-able errors
* should be Type 2 the `isXYZError()` helpers exposed at `SavedObjectsClient.errors`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo: is this a typo (double mentioning of SavedObjectsClient.errors)?

* ### 404s from missing index
*
* From the perspective of application code and APIs the SavedObjectsClient is
* a black box that persists objects. One of the internal details that the client
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: just for my understanding, that the client has no control over - the client here is the consumer of SavedObjectsClient or the SavedObjectsClient itself?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I use client here to mean SavedObjectsClient and browser/user client. I'll more clearly distinguish those.

*
* At the time of writing we are in the process of transitioning away from the
* operating assumption that the SavedObjects index is always available. Part of
* this transition is handling errors resulting from an index missing. These use
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo: these use to trigger --> these used to trigger?

expect(error.output.payload).to.have.property('message', 'biz: foobar');
it('Uses "Not Found" message', () => {
const error = createGenericNotFoundError();
expect(error.output.payload).to.have.property('message', 'Not Found');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: there is no need to change anything here, just wondering why not to use to.be?

expect(error.output.payload.message).to.be('Not Found')

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the error message shows the properties that do exist, that is all

callAdminCluster.returns({});
callAdminCluster.returns({
result: 'deleted'
});
await savedObjectsClient.delete('index-pattern', 'logstash-*');

expect(callAdminCluster.calledOnce).to.be(true);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: since you're here already :)

sinon.assert.calledOnce(onBeforeWrite);
sinon.assert.calledOnce(callAdminCluster);
sinon.assert.calledWithExactly(callAdminCluster, 'delete', {
	type: 'doc',
	id: 'index-pattern:logstash-*',
	refresh: 'wait_for',
	index: '.kibana-test',
	ignore: [404],
});

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a lot of that in this file, but if you like!

Copy link
Contributor Author

@spalger spalger Oct 2, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pretty sure I'm falling in love with sinon's matcher API. I'm going to merge if the tests pass, but if you wouldn't mind double checking this commit @azasypkin, I would appreciate it

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, thanks!

@@ -55,6 +55,7 @@ module.exports = function (grunt) {
...stdDevArgs,
'--optimize.enabled=false',
'--elasticsearch.url=' + esTestConfig.getUrl(),
'--elasticsearch.healthCheck.delay=360000',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: just curious, why exactly 6 minutes? :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Haha, I'm horrible at math


it('returns generic 404 when kibana index is missing', async () => (
await supertest
.delete(`/api/saved_objects/dashboard/not-a-real-id`)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: maybe not-a-real-id ---> be3733a0-9efe-11e7-acb3-3dab96693fab just to be sure we get 404 because of missing index and not because of non-existing id.

@epixa
Copy link
Contributor

epixa commented Oct 2, 2017

@spalger I don't have anything new to add beyond @azasypkin's latest round of comments.

@spalger spalger force-pushed the fix/savedObjects/mget404 branch from 6852b15 to f98c009 Compare October 2, 2017 22:24
@spalger spalger merged commit e847612 into elastic:master Oct 3, 2017
@spalger spalger removed the v6.0.0 label Oct 3, 2017
@spalger spalger deleted the fix/savedObjects/mget404 branch October 3, 2017 01:52
spalger added a commit that referenced this pull request Oct 3, 2017
* [savedObjects/delete+bulk_get] add failing tests

* [savedObjects/delete+bulk_get] improve 404 handling

* [savedObjects/client] fix mocha tests

* [savedObjects/tests] remove extra test wrapper

* [apiIntegration/kbnServer] basically disable es healthcheck

* [savedObjects/create] add integration test

* [savedObjects/find] add failing integration tests

* [savedObjects/find] fix failing test

* [savedObjects/client] explain reason for generic 404s

* [savedObjects/get] add integration tests

* [savedObjects/find] test request with unkown type

* [savedObjects/find] add some more weird param tests

* [savedObjects/find] test that weird params pass when no index

* [savedObjects/update] use generic 404

* fix typos

* [savedObjects/update] add integration tests

* remove debugging uncomment

* [savedObjects/tests] move backup kibana index delete out of tests

* [savedObjects/tests/esArchives] remove logstash data

* [savedObjects] update test

* [uiSettings] remove detailed previously leaked from API

* [functional/dashboard] wrap check that is only failing on Jenkins

* [savedObjects/error] replace decorateNotFound with createGenericNotFound

* fix typo

* [savedObjectsClient/errors] fix decorateEsError() test

* [savedObjectsClient] fix typos

* [savedObjects/tests/functional] delete document that would normally exist

* [savedObjectsClient/tests] use sinon assertions

* [savedObjects/apiTests] create without index responds with 503 after #14202
@spalger
Copy link
Contributor Author

spalger commented Oct 3, 2017

6.x: ddc1d9c

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
review Team:Core Core services & architecture: plugins, logging, config, saved objects, http, ES client, i18n, etc v6.1.0 v7.0.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants