Skip to content

Commit

Permalink
Add IndexTemplateV2 to MetaData (elastic#53753)
Browse files Browse the repository at this point in the history
* Add IndexTemplateV2 to MetaData

This adds the `IndexTemplateV2` and `IndexTemplateV2Metadata` class to be used for the new
implementation of index templates. The new metadata is stored as a `MetaData.Custom` implementation.

Relates to elastic#53101

* Add ITV2Metadata unit tests

Co-authored-by: Elastic Machine <[email protected]>
  • Loading branch information
dakrone and elasticmachine committed Mar 19, 2020
1 parent 2c77c0d commit 8e8f7e5
Show file tree
Hide file tree
Showing 8 changed files with 680 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import org.elasticsearch.cluster.metadata.ComponentTemplateMetadata;
import org.elasticsearch.cluster.metadata.IndexGraveyard;
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
import org.elasticsearch.cluster.metadata.IndexTemplateV2Metadata;
import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.cluster.metadata.MetaDataDeleteIndexService;
import org.elasticsearch.cluster.metadata.MetaDataIndexAliasesService;
Expand Down Expand Up @@ -133,6 +134,8 @@ public static List<Entry> getNamedWriteables() {
PersistentTasksCustomMetaData::readDiffFrom);
registerMetaDataCustom(entries, ComponentTemplateMetadata.TYPE, ComponentTemplateMetadata::new,
ComponentTemplateMetadata::readDiffFrom);
registerMetaDataCustom(entries, IndexTemplateV2Metadata.TYPE, IndexTemplateV2Metadata::new,
IndexTemplateV2Metadata::readDiffFrom);
// Task Status (not Diffable)
entries.add(new Entry(Task.Status.class, PersistentTasksNodeService.Status.NAME, PersistentTasksNodeService.Status::new));
return entries;
Expand Down Expand Up @@ -182,6 +185,8 @@ public static List<NamedXContentRegistry.Entry> getNamedXWriteables() {
PersistentTasksCustomMetaData::fromXContent));
entries.add(new NamedXContentRegistry.Entry(MetaData.Custom.class, new ParseField(ComponentTemplateMetadata.TYPE),
ComponentTemplateMetadata::fromXContent));
entries.add(new NamedXContentRegistry.Entry(MetaData.Custom.class, new ParseField(IndexTemplateV2Metadata.TYPE),
IndexTemplateV2Metadata::fromXContent));
return entries;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package org.elasticsearch.cluster.metadata;

import org.elasticsearch.cluster.AbstractDiffable;
import org.elasticsearch.cluster.Diff;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
import org.elasticsearch.common.xcontent.ToXContentObject;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;

import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
* An index template is comprised of a set of index patterns, an optional template, and a list of
* ids corresponding to component templates that should be composed in order when creating a new
* index.
*/
public class IndexTemplateV2 extends AbstractDiffable<IndexTemplateV2> implements ToXContentObject {
private static final ParseField INDEX_PATTERNS = new ParseField("index_patterns");
private static final ParseField TEMPLATE = new ParseField("template");
private static final ParseField PRIORITY = new ParseField("priority");
private static final ParseField COMPOSED_OF = new ParseField("composed_of");
private static final ParseField VERSION = new ParseField("version");
private static final ParseField METADATA = new ParseField("_meta");

@SuppressWarnings("unchecked")
private static final ConstructingObjectParser<IndexTemplateV2, Void> PARSER = new ConstructingObjectParser<>("index_template", false,
a -> new IndexTemplateV2((List<String>) a[0],
(Template) a[1],
(List<String>) a[2],
(Long) a[3],
(Long) a[4],
(Map<String, Object>) a[5]));

static {
PARSER.declareStringArray(ConstructingObjectParser.constructorArg(), INDEX_PATTERNS);
PARSER.declareObject(ConstructingObjectParser.optionalConstructorArg(), Template.PARSER, TEMPLATE);
PARSER.declareStringArray(ConstructingObjectParser.optionalConstructorArg(), COMPOSED_OF);
PARSER.declareLong(ConstructingObjectParser.optionalConstructorArg(), PRIORITY);
PARSER.declareLong(ConstructingObjectParser.optionalConstructorArg(), VERSION);
PARSER.declareObject(ConstructingObjectParser.optionalConstructorArg(), (p, c) -> p.map(), METADATA);
}

private final List<String> indexPatterns;
@Nullable
private final Template template;
@Nullable
private final List<String> componentTemplates;
@Nullable
private final Long priority;
@Nullable
private final Long version;
@Nullable
private final Map<String, Object> metadata;

static Diff<IndexTemplateV2> readITV2DiffFrom(StreamInput in) throws IOException {
return AbstractDiffable.readDiffFrom(IndexTemplateV2::new, in);
}

public static IndexTemplateV2 parse(XContentParser parser) throws IOException {
return PARSER.parse(parser, null);
}

public IndexTemplateV2(List<String> indexPatterns, @Nullable Template template, @Nullable List<String> componentTemplates,
@Nullable Long priority, @Nullable Long version, @Nullable Map<String, Object> metadata) {
this.indexPatterns = indexPatterns;
this.template = template;
this.componentTemplates = componentTemplates;
this.priority = priority;
this.version = version;
this.metadata = metadata;
}

public IndexTemplateV2(StreamInput in) throws IOException {
this.indexPatterns = in.readStringList();
if (in.readBoolean()) {
this.template = new Template(in);
} else {
this.template = null;
}
this.componentTemplates = in.readOptionalStringList();
this.priority = in.readOptionalVLong();
this.version = in.readOptionalVLong();
this.metadata = in.readMap();
}

public List<String> indexPatterns() {
return indexPatterns;
}

public Template template() {
return template;
}

public List<String> composedOf() {
return componentTemplates;
}

public Long priority() {
return priority;
}

public Long version() {
return version;
}

public Map<String, Object> metadata() {
return metadata;
}

@Override
public void writeTo(StreamOutput out) throws IOException {
out.writeStringCollection(this.indexPatterns);
if (this.template == null) {
out.writeBoolean(false);
} else {
out.writeBoolean(true);
this.template.writeTo(out);
}
out.writeOptionalStringCollection(this.componentTemplates);
out.writeOptionalVLong(this.priority);
out.writeOptionalVLong(this.version);
out.writeMap(this.metadata);
}

@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();
builder.field(INDEX_PATTERNS.getPreferredName(), this.indexPatterns);
if (this.template != null) {
builder.field(TEMPLATE.getPreferredName(), this.template);
}
if (this.componentTemplates != null) {
builder.field(COMPOSED_OF.getPreferredName(), this.componentTemplates);
}
if (this.priority != null) {
builder.field(PRIORITY.getPreferredName(), priority);
}
if (this.version != null) {
builder.field(VERSION.getPreferredName(), version);
}
if (this.metadata != null) {
builder.field(METADATA.getPreferredName(), metadata);
}
builder.endObject();
return builder;
}

@Override
public int hashCode() {
return Objects.hash(this.indexPatterns, this.template, this.componentTemplates, this.priority, this.version, this.metadata);
}

@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
IndexTemplateV2 other = (IndexTemplateV2) obj;
return Objects.equals(this.indexPatterns, other.indexPatterns) &&
Objects.equals(this.template, other.template) &&
Objects.equals(this.componentTemplates, other.componentTemplates) &&
Objects.equals(this.priority, other.priority) &&
Objects.equals(this.version, other.version) &&
Objects.equals(this.metadata, other.metadata);
}

@Override
public String toString() {
return Strings.toString(this);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package org.elasticsearch.cluster.metadata;

import org.elasticsearch.Version;
import org.elasticsearch.cluster.Diff;
import org.elasticsearch.cluster.DiffableUtils;
import org.elasticsearch.cluster.NamedDiff;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;

import java.io.IOException;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
* The {@link IndexTemplateV2Metadata} class is a custom {@link MetaData.Custom} implementation that
* stores a map of ids to {@link IndexTemplateV2} templates.
*/
public class IndexTemplateV2Metadata implements MetaData.Custom {
public static final String TYPE = "index_template";
private static final ParseField INDEX_TEMPLATE = new ParseField("index_template");
@SuppressWarnings("unchecked")
private static final ConstructingObjectParser<IndexTemplateV2Metadata, Void> PARSER = new ConstructingObjectParser<>(TYPE, false,
a -> new IndexTemplateV2Metadata((Map<String, IndexTemplateV2>) a[0]));

static {
PARSER.declareObject(ConstructingObjectParser.constructorArg(), (p, c) -> {
Map<String, IndexTemplateV2> templates = new HashMap<>();
while (p.nextToken() != XContentParser.Token.END_OBJECT) {
String name = p.currentName();
templates.put(name, IndexTemplateV2.parse(p));
}
return templates;
}, INDEX_TEMPLATE);
}

private final Map<String, IndexTemplateV2> indexTemplates;

public IndexTemplateV2Metadata(Map<String, IndexTemplateV2> templates) {
this.indexTemplates = templates;
}

public IndexTemplateV2Metadata(StreamInput in) throws IOException {
this.indexTemplates = in.readMap(StreamInput::readString, IndexTemplateV2::new);
}

public static IndexTemplateV2Metadata fromXContent(XContentParser parser) throws IOException {
return PARSER.parse(parser, null);
}

public Map<String, IndexTemplateV2> indexTemplates() {
return indexTemplates;
}

@Override
public EnumSet<MetaData.XContentContext> context() {
return MetaData.ALL_CONTEXTS;
}

@Override
public Diff<MetaData.Custom> diff(MetaData.Custom before) {
return new IndexTemplateV2MetadataDiff((IndexTemplateV2Metadata) before, this);
}

public static NamedDiff<MetaData.Custom> readDiffFrom(StreamInput in) throws IOException {
return new IndexTemplateV2MetadataDiff(in);
}

@Override
public String getWriteableName() {
return TYPE;
}

@Override
public Version getMinimalSupportedVersion() {
// TODO: update this once backported
return Version.V_8_0_0;
}

@Override
public void writeTo(StreamOutput out) throws IOException {
out.writeMap(this.indexTemplates, StreamOutput::writeString, (outstream, val) -> val.writeTo(outstream));
}

@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject(INDEX_TEMPLATE.getPreferredName());
for (Map.Entry<String, IndexTemplateV2> template : indexTemplates.entrySet()) {
builder.field(template.getKey(), template.getValue());
}
builder.endObject();
return builder;
}

@Override
public int hashCode() {
return Objects.hash(this.indexTemplates);
}

@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
IndexTemplateV2Metadata other = (IndexTemplateV2Metadata) obj;
return Objects.equals(this.indexTemplates, other.indexTemplates);
}

@Override
public String toString() {
return Strings.toString(this);
}

static class IndexTemplateV2MetadataDiff implements NamedDiff<MetaData.Custom> {

final Diff<Map<String, IndexTemplateV2>> indexTemplateDiff;

IndexTemplateV2MetadataDiff(IndexTemplateV2Metadata before, IndexTemplateV2Metadata after) {
this.indexTemplateDiff = DiffableUtils.diff(before.indexTemplates, after.indexTemplates,
DiffableUtils.getStringKeySerializer());
}

IndexTemplateV2MetadataDiff(StreamInput in) throws IOException {
this.indexTemplateDiff = DiffableUtils.readJdkMapDiff(in, DiffableUtils.getStringKeySerializer(),
IndexTemplateV2::new, IndexTemplateV2::readITV2DiffFrom);
}

@Override
public MetaData.Custom apply(MetaData.Custom part) {
return new IndexTemplateV2Metadata(indexTemplateDiff.apply(((IndexTemplateV2Metadata) part).indexTemplates));
}

@Override
public void writeTo(StreamOutput out) throws IOException {
indexTemplateDiff.writeTo(out);
}

@Override
public String getWriteableName() {
return TYPE;
}
}
}
Loading

0 comments on commit 8e8f7e5

Please sign in to comment.