-
Notifications
You must be signed in to change notification settings - Fork 8.3k
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] Use index template #14271
[savedObjects] Use index template #14271
Conversation
The elasticsearch plugin currently checks for the Kibana index on each iteration of the healthCheck, and creates it if it does not exist. This removes that step from the healthCheck and instead, before each savedObject is written to elasticsearch, ensures that Elasticsearch has the necessary index template should the write result in index creation. The healthCheck still has the `patchKibanaIndex()` logic, which checks the type in the Kibana index and adds any missing types. This step now does nothing when the Kibana index does not exist, and does what it has always done when it does.
531dec1
to
10e920a
Compare
Looks like the tests are failing for no such index. |
…ana-index-template
(cherry picked from commit b1ef897dafeb6d43fe279776e44a9d793a389dc3)
b1ef897
to
825f2e9
Compare
import kibanaVersion from './kibana_version'; | ||
import { ensureEsVersion } from './ensure_es_version'; | ||
import { ensureNotTribe } from './ensure_not_tribe'; | ||
import { patchKibanaIndex } from './patch_kibana_index'; | ||
import { format } from 'util'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
optional nit: I know it was here before (hence up to you), but it seems the only place it's used in is:
plugin.status.red(format('Unable to connect to Elasticsearch at %s.', url));
that is basically just
plugin.status.red(`Unable to connect to Elasticsearch at ${url}`);
sinon.assert.notCalled(plugin.status.red); | ||
sinon.assert.calledOnce(plugin.status.green); | ||
|
||
expect(plugin.status.green.args[0][0]).to.be('Kibana index ready'); | ||
expect(plugin.status.green.args[0][0]).to.be('Ready'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: calledWith
here and in the test below? :)
@@ -1,25 +0,0 @@ | |||
export default function (server) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
question: I couldn't find any comments about this "feature", but just in general why did we need this previously and why we don't need this anymore? Just for my understanding.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What I call the "saved objects index" used to be the "Kibana index", which needed to be created before the first write or elasticsearch would automatically create the index with automatic (and likely incorrect) mappings.
This part of the health checker was responsible for doing that, and we would run it on an interval, but this new strategy teaches elasticsearch how to automatically create the index correctly instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it, thanks
@@ -25,6 +25,12 @@ export async function patchKibanaIndex(options) { | |||
|
|||
const rootEsType = getRootType(kibanaIndexMappingsDsl); | |||
const currentMappingsDsl = await getCurrentMappings(callCluster, indexName, rootEsType); | |||
|
|||
// patchKibanaIndex() should do nothing if there are no current mappings |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: would you mind adding a simple unit test to make sure we handle 404
properly and don't fail unexpectedly?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@@ -82,6 +82,19 @@ export function isEsUnavailableError(error) { | |||
} | |||
|
|||
|
|||
// 503 - Unable to automatically create index because of action.auto_create_index setting | |||
const CODE_ES_AUTO_CREATE_INDEX_ERROR = 'SavedObjectsClient/autoCreateIndex'; | |||
export function createEsAutoCreateIndexError() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: it seems every error here has a corresponding unit test suit, so it would be great if you can add one for this new error type as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
jenkins, test this |
@@ -30,30 +30,34 @@ export function savedObjectsMixin(kbnServer, server) { | |||
const adminCluster = server.plugins.elasticsearch.getCluster('admin'); | |||
|
|||
try { | |||
await adminCluster.callWithInternalUser('cluster.health', { | |||
timeout: `${server.config().get('savedObjects.indexCheckTimeout')}ms`, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: Seems like indexCheckTimeout
is not used anymore, if so could you please remove it completely? I see it only in the config schema (it looks like it's the only property savedObjects
config node) and in a single test.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
}, | ||
err: { | ||
message: error.message, | ||
stack: error.stack, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: let's be consistent on the trailing commas within this file :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So ready for #14631
index: server.config().get('kibana.index'), | ||
waitForStatus: 'yellow', | ||
const index = server.config().get('kibana.index'); | ||
await adminCluster.callWithInternalUser('indices.putTemplate', { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
question: it must be a dumb question, but why do we want to put this template on every write? As far as I understand server.getKibanaIndexMappingsDsl()
is supposed to return the same thing most of the time (always?) or am I missing something?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not a dumb question. My intention was to ensure that Elasticsearch has the index template before every write so that even if a user deletes the index and index template in elasticsearch, writes will still work (unless the index template is deleted in the tiny amount of time between putting the index template and indexing the document).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the explanation! Then optional nit: maybe you can add this comment to the code or even move this piece of code to a dedicated function like ensureKibanaIndexExists
or something like that to make intention clearer (your comment above still seems to be useful to have there as well)?
@@ -0,0 +1,3 @@ | |||
.error-multi-allow-explicit-index { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: did you mean error-auto-create-index
or something similar?
|
||
return new SavedObjectsClient({ | ||
$http, | ||
basePath: chrome.getBasePath(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: you can probably omit basePath
property since it's the same as default one.
|
||
// loose ISO8601 UTC time with milliseconds validation | ||
expect(resp.body).to.have.property('updated_at').match(/^[\d-]{10}T[\d:\.]{12}Z$/); | ||
|
||
expect(resp.body).to.eql({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
optional nit: not really better, but just another way of using eql
with object that has properties that aren't know upfront:
expect(resp.body).to.eql({
...resp.body,
type: 'visualization',
version: 1,
attributes: {
title: 'My favorite vis'
}
});
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah, I really wanted to list all expected properties
Jenkins, test it Failure:
|
…ana-index-template
Overall, looks good - just a couple things I came across: In x-pack, when ES is unable I get 401 unauthorized
This differs from Have we measured what effect putting the index template before each write has on object imports? Could it be debounced? When starting Kibana without an index:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Couple questions/concerns with x-pack.
I keep coming back to questioning if setting the index template before every write is too heavy, or necessary. What does it prevent against?
|
@tylersmalley I don’t think you should worry about it, the most expensive part of that request is probably serializing the JSON body. Any sort of conditional “do I need to put the index template?” logic would probably just muddy up the super simple implementation. That said, I’ll test the impact on object imports and see if it’s worth fixing |
…ana-index-template
This is the same behavior as master, although I think we should probably ensure it is a 500 instead. |
Ran a test import with 110 saved objects and observed the difference between master/this branch. First thing I noticed is that writes are already "slow" because we wait for index refresh. In master it took 20.31 seconds and in this branch it to 20.11 seconds, the variance is really just random based on the time it takes to refresh the es index. |
@@ -99,6 +99,7 @@ export class UiSettingsService { | |||
try { | |||
await this._savedObjectsClient.update(this._type, this._id, changes); | |||
} catch (error) { | |||
debugger; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did you mean to commit this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nope!
…ana-index-template
c1c6942
to
e593bd9
Compare
…ana-index-template
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
I tested swapping out the kibana.index, and using aliases along with a bunch of general crud operations. I think the template will give us a softer mapping failure in cases when we previously would try to patch, so 👍 to that.
I'm iffy with pushing the template on so many requests but I'm rationalizing it's probably cheaper than the polling health check over time.
* [es][savedObjects/index] put template on each savedObject write The elasticsearch plugin currently checks for the Kibana index on each iteration of the healthCheck, and creates it if it does not exist. This removes that step from the healthCheck and instead, before each savedObject is written to elasticsearch, ensures that Elasticsearch has the necessary index template should the write result in index creation. The healthCheck still has the `patchKibanaIndex()` logic, which checks the type in the Kibana index and adds any missing types. This step now does nothing when the Kibana index does not exist, and does what it has always done when it does. * [ftr] remove unused kibanaIndex service (cherry picked from commit b1ef897dafeb6d43fe279776e44a9d793a389dc3) * [savedObjects/integration] create now creates kibana index * [es/healthCheck] remove use of format() * [es/healthCheck/tests] use sinon assertions * [es/patchKibanaIndex] test for kibana index missing behavior * [savedObjects/errors] add tests for EsAutoCreateIndexError * [savedObjects/config] deprecate and remove savedObjects.indexCheckTimeout config * use dangling commas consistently * [ui/error_auto_create_index] fix class names * [ui/savedObjectsClient] no need to specify basePath * [eslint] fix linting issue
* [es][savedObjects/index] put template on each savedObject write The elasticsearch plugin currently checks for the Kibana index on each iteration of the healthCheck, and creates it if it does not exist. This removes that step from the healthCheck and instead, before each savedObject is written to elasticsearch, ensures that Elasticsearch has the necessary index template should the write result in index creation. The healthCheck still has the `patchKibanaIndex()` logic, which checks the type in the Kibana index and adds any missing types. This step now does nothing when the Kibana index does not exist, and does what it has always done when it does. * [ftr] remove unused kibanaIndex service (cherry picked from commit b1ef897dafeb6d43fe279776e44a9d793a389dc3) * [savedObjects/integration] create now creates kibana index * [es/healthCheck] remove use of format() * [es/healthCheck/tests] use sinon assertions * [es/patchKibanaIndex] test for kibana index missing behavior * [savedObjects/errors] add tests for EsAutoCreateIndexError * [savedObjects/config] deprecate and remove savedObjects.indexCheckTimeout config * use dangling commas consistently * [ui/error_auto_create_index] fix class names * [ui/savedObjectsClient] no need to specify basePath * [eslint] fix linting issue
What about the idea of adding an empty ingest pipeline to .kibana index, to make it future-proof? This could be really cool. We can always help people upgrade their old indices if we had this. |
patchKibanaIndex()
when it existsSavedObjectsClient
'sonBeforeWrite()
handler so that every writePUT
s the index template to elasticsearchSavedObjectsClient#create
fails because ofaction.auto_create_index: false
action.auto_create_index: false
prevents Kibana from being able to saved objects