Skip to content

Create data stream aliases from template #73867

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

Merged
merged 27 commits into from
Jul 22, 2021
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
52c9402
wip
danhermann Jun 7, 2021
ebdbce5
fix test compile error
danhermann Jun 7, 2021
cc8c7c4
add missing parser
danhermann Jun 7, 2021
5d21f2f
bwc
danhermann Jun 7, 2021
738b9e6
fix compilation
danhermann Jun 7, 2021
b0848d6
unused import
danhermann Jun 7, 2021
36847c8
fix test
danhermann Jun 7, 2021
0aebdb4
Merge branch 'master' into 66163_create_alias_from_template
elasticmachine Jun 16, 2021
49968e4
Merge branch 'master' into 66163_create_alias_from_template
elasticmachine Jul 13, 2021
001b0d5
fix merge error
danhermann Jul 14, 2021
39973f6
auto-create alias when data stream is created
danhermann Jul 16, 2021
991a36b
Merge branch 'master' into 66163_create_alias_from_template
elasticmachine Jul 16, 2021
e12bd60
remove AliasMetadata::isDataStream
danhermann Jul 19, 2021
1399903
reuse existing alias definitions
danhermann Jul 19, 2021
59e57af
Merge branch 'master' into 66163_create_alias_from_template
danhermann Jul 19, 2021
0f5c6a9
fix NPE
danhermann Jul 19, 2021
43e1d5f
add test
danhermann Jul 19, 2021
45cc1f5
remove a couple more unnecessary flags
danhermann Jul 19, 2021
86dc1f3
another test + minor reformatting
danhermann Jul 20, 2021
f75425b
checkstyle
danhermann Jul 20, 2021
4edd676
fix test
danhermann Jul 20, 2021
3b70768
review comments
danhermann Jul 21, 2021
f3a97c8
missed one spot
danhermann Jul 21, 2021
77e2a32
Merge branch 'master' into 66163_create_alias_from_template
elasticmachine Jul 21, 2021
8d1e1e7
fix merge error
danhermann Jul 21, 2021
33f2359
fix test
danhermann Jul 21, 2021
833677a
review comments
danhermann Jul 22, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import java.util.Set;

import static java.util.Collections.emptySet;
import static org.elasticsearch.cluster.metadata.ComposableIndexTemplate.DataStreamTemplate.DATA_STREAM_ALIAS_VERSION;

public class AliasMetadata extends AbstractDiffable<AliasMetadata> implements ToXContentFragment {

Expand All @@ -51,8 +52,11 @@ public class AliasMetadata extends AbstractDiffable<AliasMetadata> implements To
@Nullable
private final Boolean isHidden;

@Nullable
private final Boolean isDataStream;
Copy link
Member

Choose a reason for hiding this comment

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

I don't think this field is needed? I also don't see that is currently is used in this pr.
In MetadataCreateDataStreamService, data stream aliases can be created without this information? The fact that a DataStreamTemplate is defined should be sufficient?


private AliasMetadata(String alias, CompressedXContent filter, String indexRouting, String searchRouting, Boolean writeIndex,
@Nullable Boolean isHidden) {
@Nullable Boolean isHidden, @Nullable Boolean isDataStream) {
this.alias = alias;
this.filter = filter;
this.indexRouting = indexRouting;
Expand All @@ -64,11 +68,12 @@ private AliasMetadata(String alias, CompressedXContent filter, String indexRouti
}
this.writeIndex = writeIndex;
this.isHidden = isHidden;
this.isDataStream = isDataStream;
}

private AliasMetadata(AliasMetadata aliasMetadata, String alias) {
this(alias, aliasMetadata.filter(), aliasMetadata.indexRouting(), aliasMetadata.searchRouting(), aliasMetadata.writeIndex(),
aliasMetadata.isHidden);
aliasMetadata.isHidden, aliasMetadata.isDataStream);
}

public String alias() {
Expand Down Expand Up @@ -120,6 +125,11 @@ public Boolean isHidden() {
return isHidden;
}

@Nullable
public Boolean isDataStream() {
return isDataStream;
}

public static Builder builder(String alias) {
return new Builder(alias);
}
Expand Down Expand Up @@ -148,6 +158,7 @@ public boolean equals(Object o) {
if (Objects.equals(searchRouting, that.searchRouting) == false) return false;
if (Objects.equals(writeIndex, that.writeIndex) == false) return false;
if (Objects.equals(isHidden, that.isHidden) == false) return false;
if (Objects.equals(isDataStream, that.isDataStream) == false) return false;

return true;
}
Expand All @@ -159,6 +170,7 @@ public int hashCode() {
result = 31 * result + (indexRouting != null ? indexRouting.hashCode() : 0);
result = 31 * result + (searchRouting != null ? searchRouting.hashCode() : 0);
result = 31 * result + (writeIndex != null ? writeIndex.hashCode() : 0);
result = 31 * result + (isDataStream != null ? isDataStream.hashCode() : 0);
return result;
}

Expand All @@ -185,6 +197,9 @@ public void writeTo(StreamOutput out) throws IOException {
}
out.writeOptionalBoolean(writeIndex());
out.writeOptionalBoolean(isHidden);
if (out.getVersion().onOrAfter(DATA_STREAM_ALIAS_VERSION)) {
out.writeOptionalBoolean(isDataStream);
}
}

public AliasMetadata(StreamInput in) throws IOException {
Expand All @@ -208,6 +223,11 @@ public AliasMetadata(StreamInput in) throws IOException {
}
writeIndex = in.readOptionalBoolean();
isHidden = in.readOptionalBoolean();
if (in.getVersion().onOrAfter(DATA_STREAM_ALIAS_VERSION)) {
isDataStream = in.readOptionalBoolean();
} else {
isDataStream = null;
}
}

public static Diff<AliasMetadata> readDiffFrom(StreamInput in) throws IOException {
Expand Down Expand Up @@ -249,6 +269,9 @@ public static class Builder {
@Nullable
private Boolean isHidden;

@Nullable
private Boolean isDataStream;

public Builder(String alias) {
this.alias = alias;
}
Expand Down Expand Up @@ -310,8 +333,13 @@ public Builder isHidden(@Nullable Boolean isHidden) {
return this;
}

public Builder isDataStream(@Nullable Boolean isDataStream) {
this.isDataStream = isDataStream;
return this;
}

public AliasMetadata build() {
return new AliasMetadata(alias, filter, indexRouting, searchRouting, writeIndex, isHidden);
return new AliasMetadata(alias, filter, indexRouting, searchRouting, writeIndex, isHidden, isDataStream);
}

public static void toXContent(AliasMetadata aliasMetadata, XContentBuilder builder, ToXContent.Params params) throws IOException {
Expand Down Expand Up @@ -341,6 +369,10 @@ public static void toXContent(AliasMetadata aliasMetadata, XContentBuilder build
builder.field("is_hidden", aliasMetadata.isHidden());
}

if (aliasMetadata.isDataStream != null) {
builder.field("is_data_stream", aliasMetadata.isDataStream());
}

builder.endObject();
}

Expand Down Expand Up @@ -384,6 +416,8 @@ public static AliasMetadata fromXContent(XContentParser parser) throws IOExcepti
builder.writeIndex(parser.booleanValue());
} else if ("is_hidden".equals(currentFieldName)) {
builder.isHidden(parser.booleanValue());
} else if ("is_data_stream".equals(currentFieldName)) {
builder.isDataStream(parser.booleanValue());
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

package org.elasticsearch.cluster.metadata;

import org.elasticsearch.Version;
import org.elasticsearch.cluster.AbstractDiffable;
import org.elasticsearch.cluster.Diff;
import org.elasticsearch.core.Nullable;
Expand All @@ -23,6 +24,8 @@
import org.elasticsearch.index.mapper.MapperService;

import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
Expand Down Expand Up @@ -256,35 +259,63 @@ public String toString() {

public static class DataStreamTemplate implements Writeable, ToXContentObject {

public static final Version DATA_STREAM_ALIAS_VERSION = Version.V_8_0_0;

private static final ParseField HIDDEN = new ParseField("hidden");
private static final ParseField ALIASES = new ParseField("aliases");
Copy link
Member

Choose a reason for hiding this comment

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

I think changes to this file can be undone as well?


public static final ConstructingObjectParser<DataStreamTemplate, Void> PARSER = new ConstructingObjectParser<>(
"data_stream_template",
false,
a -> new DataStreamTemplate(a[0] != null && (boolean) a[0]));
args -> {
boolean hidden = args[0] != null && (boolean) args[0];
@SuppressWarnings("unchecked")
Map<String, AliasMetadata> aliases = (Map<String, AliasMetadata>) args[1];
return new DataStreamTemplate(hidden, aliases);
}
);

static {
PARSER.declareBoolean(ConstructingObjectParser.optionalConstructorArg(), HIDDEN);
PARSER.declareObject(ConstructingObjectParser.optionalConstructorArg(), (p, c) -> {
Map<String, AliasMetadata> aliasMap = new HashMap<>();
while ((p.nextToken()) != XContentParser.Token.END_OBJECT) {
AliasMetadata alias = AliasMetadata.Builder.fromXContent(p);
aliasMap.put(alias.alias(), alias);
}
return aliasMap;
}, ALIASES);
}

private final boolean hidden;

@Nullable
private final Map<String, AliasMetadata> aliases;
Copy link
Member

Choose a reason for hiding this comment

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

I think we can reuse the alias definitions in ComposableIndexTemplate (defined inside the Template class)?
If a composable index template has a DataStreamTemplate and aliases definitions are present then data stream aliases are created. If just alias definitions are present in composable index template then indices aliases are created.


public DataStreamTemplate() {
this(false);
this(false, null);
}

public DataStreamTemplate(boolean hidden) {
public DataStreamTemplate(boolean hidden, Map<String, AliasMetadata> aliases) {
this.hidden = hidden;
this.aliases = aliases;
}

DataStreamTemplate(StreamInput in) throws IOException {
hidden = in.readBoolean();
aliases = in.getVersion().onOrAfter(DATA_STREAM_ALIAS_VERSION)
? in.readBoolean() ? in.readMap(StreamInput::readString, AliasMetadata::new) : null
: null;
}

public String getTimestampField() {
return FIXED_TIMESTAMP_FIELD;
}

public Collection<AliasMetadata> getAliases() {
return aliases == null ? null : aliases.values();
}

/**
* @return a mapping snippet for a backing index with `_data_stream_timestamp` meta field mapper properly configured.
*/
Expand All @@ -300,12 +331,27 @@ public boolean isHidden() {
@Override
public void writeTo(StreamOutput out) throws IOException {
out.writeBoolean(hidden);
if (out.getVersion().onOrAfter(DATA_STREAM_ALIAS_VERSION)) {
if (aliases != null) {
out.writeBoolean(true);
out.writeMap(aliases, StreamOutput::writeString, (innerOut, alias) -> alias.writeTo(innerOut));
} else {
out.writeBoolean(false);
}
}
}

@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();
builder.field("hidden", hidden);
if (aliases != null) {
builder.startObject("aliases");
for (var alias : aliases.values()) {
alias.toXContent(builder, params);
}
builder.endObject();
}
builder.endObject();
return builder;
}
Expand All @@ -315,12 +361,12 @@ public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
DataStreamTemplate that = (DataStreamTemplate) o;
return hidden == that.hidden;
return hidden == that.hidden && Objects.equals(aliases, that.aliases);
}

@Override
public int hashCode() {
return Objects.hash(hidden);
return Objects.hash(hidden, aliases);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,13 @@ static ClusterState createDataStream(MetadataCreateIndexService metadataCreateIn
logger.info("adding data stream [{}] with write index [{}] and backing indices [{}]", dataStreamName,
Copy link
Member

Choose a reason for hiding this comment

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

maybe enhance this log line with the fact that aliases were created as well (if template has aliases)?

writeIndex.getIndex().getName(),
Strings.arrayToCommaDelimitedString(backingIndices.stream().map(i -> i.getIndex().getName()).toArray()));

if (template.getDataStreamTemplate().getAliases() != null) {
for (var alias : template.getDataStreamTemplate().getAliases()) {
builder.put(alias.getAlias(), dataStreamName, alias.writeIndex());
}
}

return ClusterState.builder(currentState).metadata(builder).build();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1146,10 +1146,10 @@ static List<Map<String, AliasMetadata>> resolveAliases(final ComposableIndexTemp
.map(Template::aliases)
.ifPresent(aliases::add);

// A template that creates data streams can't also create aliases.
// (otherwise we end up with aliases pointing to backing indices of data streams)
// A template that creates data streams may not specify index aliases. Data stream
// aliases are defined separately in the `data_stream` object on the template.
if (aliases.size() > 0 && template.getDataStreamTemplate() != null) {
throw new IllegalArgumentException("template [" + templateName + "] has alias and data stream definitions");
throw new IllegalArgumentException("template [" + templateName + "] may not specify both data streams and index alias(es)");
}

// Aliases are applied in order, but subsequent alias configuration from the same name is
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -705,7 +705,7 @@ clusterService, indicesService, allocationService, new AliasValidator(), shardLi
() -> rolloverService.rolloverClusterState(clusterState, dataStream.getName(), null, createIndexRequest, metConditions,
randomBoolean(), false)
);
assertThat(e.getMessage(), equalTo("template [template] has alias and data stream definitions"));
assertThat(e.getMessage(), equalTo("template [template] may not specify both data streams and index alias(es)"));
} finally {
testThreadPool.shutdown();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ protected DataStreamTemplate createTestInstance() {
}

public static DataStreamTemplate randomInstance() {
return new ComposableIndexTemplate.DataStreamTemplate(randomBoolean());
return new ComposableIndexTemplate.DataStreamTemplate(randomBoolean(), null);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -1219,7 +1219,7 @@ public void testResolveAliasesDataStreams() throws Exception {
.build();
Exception e =
expectThrows(IllegalArgumentException.class, () -> MetadataIndexTemplateService.resolveAliases(state1.metadata(), "1"));
assertThat(e.getMessage(), equalTo("template [1] has alias and data stream definitions"));
assertThat(e.getMessage(), equalTo("template [1] may not specify both data streams and index alias(es)"));

// index template can't have data streams and a component template with an aliases
ComponentTemplate componentTemplate = new ComponentTemplate(new Template(null, null, a1), null, null);
Expand All @@ -1229,7 +1229,7 @@ public void testResolveAliasesDataStreams() throws Exception {
.metadata(Metadata.builder().put("1", it).put("c1", componentTemplate).build())
.build();
e = expectThrows(IllegalArgumentException.class, () -> MetadataIndexTemplateService.resolveAliases(state2.metadata(), "1"));
assertThat(e.getMessage(), equalTo("template [1] has alias and data stream definitions"));
assertThat(e.getMessage(), equalTo("template [1] may not specify both data streams and index alias(es)"));
}

public void testAddInvalidTemplate() throws Exception {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ public void testCalculateUsage() {
new ComposableIndexTemplateMetadata(Collections.singletonMap("mytemplate",
new ComposableIndexTemplate(Collections.singletonList("myds"),
new Template(Settings.builder().put(LifecycleSettings.LIFECYCLE_NAME, "mypolicy").build(), null, null),
null, null, null, null, new ComposableIndexTemplate.DataStreamTemplate(false)))))
null, null, null, null, new ComposableIndexTemplate.DataStreamTemplate(false, null)))))
.build())
.build();
assertThat(LifecyclePolicyUtils.calculateUsage(iner, state, "mypolicy"),
Expand Down Expand Up @@ -133,7 +133,7 @@ public void testCalculateUsage() {
new ComposableIndexTemplateMetadata(Collections.singletonMap("mytemplate",
new ComposableIndexTemplate(Collections.singletonList("myds"),
new Template(Settings.builder().put(LifecycleSettings.LIFECYCLE_NAME, "mypolicy").build(), null, null),
null, null, null, null, new ComposableIndexTemplate.DataStreamTemplate(false)))))
null, null, null, null, new ComposableIndexTemplate.DataStreamTemplate(false, null)))))
.build())
.build();
assertThat(LifecyclePolicyUtils.calculateUsage(iner, state, "mypolicy"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ public void testAddingIndexTemplateWithAliasesAndDataStream() {
String body = "{\"index_patterns\":[\"mypattern*\"],\"data_stream\":{},\"template\":{\"aliases\":{\"my-alias\":{}}}}";
putComposableIndexTemplateRequest.setJsonEntity(body);
Exception e = expectThrows(ResponseException.class, () -> client().performRequest(putComposableIndexTemplateRequest));
assertThat(e.getMessage(), containsString("template [my-template] has alias and data stream definitions"));
assertThat(e.getMessage(), containsString("template [my-template] may not specify both data streams and index alias(es)"));
}

public void testDataStreamAliases() throws Exception {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ private String createDataStream(boolean hidden) throws Exception {
null,
null,
null,
new ComposableIndexTemplate.DataStreamTemplate(hidden),
new ComposableIndexTemplate.DataStreamTemplate(hidden, null),
null
);
assertTrue(
Expand Down