Skip to content

Handle v2 template with index.hidden setting#55015

Merged
andreidan merged 9 commits intoelastic:masterfrom
andreidan:itv2-null-isHidden-flag
Apr 17, 2020
Merged

Handle v2 template with index.hidden setting#55015
andreidan merged 9 commits intoelastic:masterfrom
andreidan:itv2-null-isHidden-flag

Conversation

@andreidan
Copy link
Copy Markdown
Contributor

@andreidan andreidan commented Apr 9, 2020

This validates that if the winner v2 template is a global one, it doesn't specify the
index.hidden setting.

This commit handles the case where the user request doesn't explicitly set
the index as hidden but a mathcing template has the `index.hidden` setting
configured to true. In this case the global templates need to be excluded.
@andreidan andreidan added :Data Management/Indices APIs DO NOT USE. Use ":Distributed/Indices APIs" or ":StorageEngine/Templates" instead. v8.0.0 v7.8.0 labels Apr 9, 2020
@elasticmachine
Copy link
Copy Markdown
Collaborator

Pinging @elastic/es-core-features (:Core/Features/Indices APIs)

@andreidan andreidan requested review from dakrone and probakowski April 9, 2020 15:35
Comment on lines +681 to +682
throw new IllegalStateException("A global index V2 template [" + indexTemplateV2ToNameEntry.getValue() +
"] defined the index hidden setting, which is not allowed");
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

#55010 guards against this when creating a v2 template

Copy link
Copy Markdown
Member

@dakrone dakrone left a comment

Choose a reason for hiding this comment

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

Thanks for addressing this Andrei, I left a comment I think we need to address here too

// then we need to exclude global templates
if (isHidden == null) {
final Optional<Map.Entry<IndexTemplateV2, String>> templateWithHiddenSetting = matchedTemplates.entrySet().stream()
.filter(entry -> IndexMetadata.INDEX_HIDDEN_SETTING.exists(resolveSettings(metadata, entry.getValue()))).findFirst();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

So this brings a question:

  • Should we throw an error (the error below for validation) on index creation for a template that won't actually "win" for the creation?

If the answer is yes, then I think rather than returning only the first one, it would be good to return all templates (in the error message I mean) that exhibit this behavior.

If the answer is no, then we can move this check to be below the candidate sorting and only check the winner template.

What do you think?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

For me the answer is no and we should only be interested in winning template - index can became hidden only by the means of the winner, doesn't matter what is in other templates.
So I'd move the code after winner is selected.
I'd also change sorting to linear min selection to avoid creating new list and sorting candidates that won't win:

IndexTemplateV2 winner = matchedTemplates.keySet().stream().min(Comparator.comparing(IndexTemplateV2::priority,
            Comparator.nullsLast(Comparator.reverseOrder()))).get();

Copy link
Copy Markdown
Contributor Author

@andreidan andreidan Apr 13, 2020

Choose a reason for hiding this comment

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

Great points. Thanks for bringing this up.

I saw this validation as "filter the invalid templates before we find the winner template" (ie. the global templates should not even be considered when finding the winning template).

The other way around, as I understand it, applying this validation on the winner template would be a no-op (since we don't support inheritance anymore, so settings from the global templates cannot be applied) and would look something along the lines of:

  1. the winning template is a global template - no index.hiddne property is allowed on the global templates - so just return it
  2. the winning template is not a global one but it has an index.hidden setting set to true in the resolved settings, but the other templates have a lower priority so just return it
  3. the winning template is not a global one and doesn't have index.hidden set, so just return it

I do agree that having a lower priority (an explicit template) influence and remove a higher priority template (the global one - as illustrated in this test https://github.com/elastic/elasticsearch/pull/55015/files#diff-4e391d69e5a1fe53728ba9530499a6e8R552-R554) from the list of candidates might be (is) counter-intuitive so I think we either go along with this approach or, given the user has the option to override a global template using the priority, we could just issue a warning that a gloabl template is used as the matching one but that it is shadowing explicit templates that try to configure the index as hidden (I do however think this would go unnoticed in the logs, so treating this as expected and dropping this complex use case would also be an option I think)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Ok, we decided to validate only the winner in this particular case. Generally (together with #55010) we will be failing if the index.hidden setting is present in the resolved settings of a global template (regardless of the setting value).

With regards to this particular validation, if the winner is a global template we'll do a sanity check to make sure it doesn't include the index.hidden setting, in which case we'll fail, but otherwise we'll return it as the winner template.

Copy link
Copy Markdown
Contributor

@probakowski probakowski left a comment

Choose a reason for hiding this comment

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

Thanks Andrei, I left few comments

// then we need to exclude global templates
if (isHidden == null) {
final Optional<Map.Entry<IndexTemplateV2, String>> templateWithHiddenSetting = matchedTemplates.entrySet().stream()
.filter(entry -> IndexMetadata.INDEX_HIDDEN_SETTING.exists(resolveSettings(metadata, entry.getValue()))).findFirst();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

For me the answer is no and we should only be interested in winning template - index can became hidden only by the means of the winner, doesn't matter what is in other templates.
So I'd move the code after winner is selected.
I'd also change sorting to linear min selection to avoid creating new list and sorting candidates that won't win:

IndexTemplateV2 winner = matchedTemplates.keySet().stream().min(Comparator.comparing(IndexTemplateV2::priority,
            Comparator.nullsLast(Comparator.reverseOrder()))).get();


// this is complex but if the index is not hidden in the create request but is hidden as the result of template application,
// then we need to exclude global templates
if (isHidden == null) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This can be simplified to something like this:

if (isHidden == null) {
    matchedTemplates.entrySet().stream()
        .filter(entry -> IndexMetadata.INDEX_HIDDEN_SETTING.get(resolveSettings(metadata, entry.getValue())))
        // relies on the fact that default for INDEX_HIDDEN_SETTING is false
        .findAny()
        .ifPresent(indexTemplateV2ToNameEntry -> {
            matchedTemplates.keySet().removeIf(current -> current.indexPatterns().stream().anyMatch(Regex::isMatchAllPattern));
            if (matchedTemplates.containsKey(indexTemplateV2ToNameEntry.getKey()) == false) {
                throw new IllegalStateException("A global index V2 template [" + indexTemplateV2ToNameEntry.getValue() +
                    "] defined the index hidden setting, which is not allowed");
            }
        });
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

On the second iteration on this I think there's a problem (fixed by proposal above): we can have 2 templates one with INDEX_HIDDEN_SETTING=false (explicitly set) and one with INDEX_HIDDEN_SETTING=true, findFirst can pick up false one and skip the whole block despite the fact that there's still one template with true

@andreidan
Copy link
Copy Markdown
Contributor Author

@elasticmachine update branch

@andreidan
Copy link
Copy Markdown
Contributor Author

@dakrone @probakowski Looking at the new code I believe we can drop the isHidden == null check altogether and just do this sanity check regardless of the isHidden value (as the check is only saying "the matching template is a global one, is it valid?")

What do you think?

https://github.com/elastic/elasticsearch/pull/55015/files#diff-115cd2f0fff9dd97acc95e1d29012a15R705-R711

@dakrone
Copy link
Copy Markdown
Member

dakrone commented Apr 16, 2020

@andreidan I think it's reasonable to drop the null check, we're doing everything we can to prevent these templates from being settable. The isHidden parameter is actually whether the index.hidden setting is specified in the create index request itself, so it shouldn't affect anything related to the templates.

Copy link
Copy Markdown
Member

@dakrone dakrone left a comment

Choose a reason for hiding this comment

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

LGTM (with the null check removal), I left one really minor nit


/**
* Add the given component template to the cluster state. If {@code create} is true, an
* Add the given index template to the cluster state. If {@code create} is true, an
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

👍

andreidan and others added 2 commits April 16, 2020 18:00
Co-Authored-By: Lee Hinman <dakrone@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

@probakowski probakowski left a comment

Choose a reason for hiding this comment

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

LGTM, thanks Andrei!

@andreidan
Copy link
Copy Markdown
Contributor Author

@elasticmachine update branch

@andreidan andreidan merged commit 19a97f7 into elastic:master Apr 17, 2020
andreidan added a commit to andreidan/elasticsearch that referenced this pull request Apr 17, 2020
This validates that if the winner v2 template is a global one, it doesn't specify the
index.hidden setting.

(cherry picked from commit 19a97f7)
Signed-off-by: Andrei Dan <andrei.dan@elastic.co>
andreidan added a commit that referenced this pull request Apr 17, 2020
This validates that if the winner v2 template is a global one, it doesn't specify the
index.hidden setting.

(cherry picked from commit 19a97f7)
Signed-off-by: Andrei Dan <andrei.dan@elastic.co>
andreidan added a commit to andreidan/elasticsearch that referenced this pull request Apr 17, 2020
isHidden was a `Boolean` in order to treat a special case identified
with V1 templates where if the create index request didn't specify if
the index should be hidden or not (ie. isHidden was `null`) but the
index matched a template that specified the `index.hidden` setting we
needed to remove the global templates from the templates we'll apply to
the new index (note: this is important with V1 templates as inheritance
is supported).

With V2 templates we match only one template with an index so the
equivalent check did not need to exist (we added a sanity check in
elastic#55015 where we make sure
we don't apply an invalid global template - one that specifes the
`index.hidden` setting, but this is a check we make irrespective of the
user specifying or not if the index should be hidden)

This commit makes `isHidden` when matching V2 templates a boolean
primitive, eliminating the need for the `null` state to exist. Note that
some methods which use the matching V2 templates still work with a
`Boolean` object `isHidden` attribute as they are also matching the V1
templates. These methods will pass in `false` instead of `null` when
finding the V2 templates.
andreidan added a commit that referenced this pull request Apr 19, 2020
isHidden was a `Boolean` in order to treat a special case identified
with V1 templates where if the create index request didn't specify if
the index should be hidden or not (ie. isHidden was `null`) but the
index matched a template that specified the `index.hidden` setting we
needed to remove the global templates from the templates we'll apply to
the new index (note: this is important with V1 templates as inheritance
is supported).

With V2 templates we match only one template with an index so the
equivalent check did not need to exist (we added a sanity check in
#55015 where we make sure
we don't apply an invalid global template - one that specifes the
`index.hidden` setting, but this is a check we make irrespective of the
user specifying or not if the index should be hidden)

This commit makes `isHidden` when matching V2 templates a boolean
primitive, eliminating the need for the `null` state to exist. Note that
some methods which use the matching V2 templates still work with a
`Boolean` object `isHidden` attribute as they are also matching the V1
templates. These methods will pass in `false` instead of `null` when
finding the V2 templates.
andreidan added a commit to andreidan/elasticsearch that referenced this pull request Apr 19, 2020
isHidden was a `Boolean` in order to treat a special case identified
with V1 templates where if the create index request didn't specify if
the index should be hidden or not (ie. isHidden was `null`) but the
index matched a template that specified the `index.hidden` setting we
needed to remove the global templates from the templates we'll apply to
the new index (note: this is important with V1 templates as inheritance
is supported).

With V2 templates we match only one template with an index so the
equivalent check did not need to exist (we added a sanity check in
elastic#55015 where we make sure
we don't apply an invalid global template - one that specifes the
`index.hidden` setting, but this is a check we make irrespective of the
user specifying or not if the index should be hidden)

This commit makes `isHidden` when matching V2 templates a boolean
primitive, eliminating the need for the `null` state to exist. Note that
some methods which use the matching V2 templates still work with a
`Boolean` object `isHidden` attribute as they are also matching the V1
templates. These methods will pass in `false` instead of `null` when
finding the V2 templates.

(cherry picked from commit c5b923a)
Signed-off-by: Andrei Dan <andrei.dan@elastic.co>
andreidan added a commit that referenced this pull request Apr 20, 2020
isHidden was a `Boolean` in order to treat a special case identified
with V1 templates where if the create index request didn't specify if
the index should be hidden or not (ie. isHidden was `null`) but the
index matched a template that specified the `index.hidden` setting we
needed to remove the global templates from the templates we'll apply to
the new index (note: this is important with V1 templates as inheritance
is supported).

With V2 templates we match only one template with an index so the
equivalent check did not need to exist (we added a sanity check in
#55015 where we make sure
we don't apply an invalid global template - one that specifes the
`index.hidden` setting, but this is a check we make irrespective of the
user specifying or not if the index should be hidden)

This commit makes `isHidden` when matching V2 templates a boolean
primitive, eliminating the need for the `null` state to exist. Note that
some methods which use the matching V2 templates still work with a
`Boolean` object `isHidden` attribute as they are also matching the V1
templates. These methods will pass in `false` instead of `null` when
finding the V2 templates.

(cherry picked from commit c5b923a)
Signed-off-by: Andrei Dan <andrei.dan@elastic.co>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

:Data Management/Indices APIs DO NOT USE. Use ":Distributed/Indices APIs" or ":StorageEngine/Templates" instead. >non-issue v7.8.0 v8.0.0-alpha1

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants