mirror of
https://github.com/honeymoose/OpenSearch.git
synced 2025-03-25 09:28:27 +00:00
* Add REST API for ComponentTemplate CRUD This adds the Put/Get/DeleteComponentTemplate APIs that allow inserting, retrieving, and removing ComponentTemplateMetadata into the cluster state metadata. These APIs are currently only available behind a feature flag system property - `es.itv2_feature_flag_registered`. Relates to #53101 Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com> Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
parent
3c5437894e
commit
9c0e846db3
@ -790,7 +790,10 @@ public class RestHighLevelClientTests extends ESTestCase {
|
||||
"indices.get_upgrade",
|
||||
"indices.put_alias",
|
||||
"render_search_template",
|
||||
"scripts_painless_execute"
|
||||
"scripts_painless_execute",
|
||||
"cluster.put_component_template",
|
||||
"cluster.get_component_template",
|
||||
"cluster.delete_component_template"
|
||||
};
|
||||
//These API are not required for high-level client feature completeness
|
||||
String[] notRequiredApi = new String[] {
|
||||
|
@ -1,3 +1,4 @@
|
||||
import org.elasticsearch.gradle.info.BuildParams
|
||||
/*
|
||||
* Licensed to Elasticsearch under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
@ -32,3 +33,9 @@ integTest.runner {
|
||||
systemProperty 'tests.logfile', '--external--'
|
||||
}
|
||||
}
|
||||
|
||||
testClusters.integTest {
|
||||
if (BuildParams.isSnapshotBuild() == false) {
|
||||
systemProperty 'es.itv2_feature_flag_registered', 'true'
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,35 @@
|
||||
{
|
||||
"cluster.delete_component_template":{
|
||||
"documentation":{
|
||||
"url":"https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-component-templates.html",
|
||||
"description":"Deletes a component template"
|
||||
},
|
||||
"stability":"stable",
|
||||
"url":{
|
||||
"paths":[
|
||||
{
|
||||
"path":"/_component_template/{name}",
|
||||
"methods":[
|
||||
"DELETE"
|
||||
],
|
||||
"parts":{
|
||||
"name":{
|
||||
"type":"string",
|
||||
"description":"The name of the template"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"params":{
|
||||
"timeout":{
|
||||
"type":"time",
|
||||
"description":"Explicit operation timeout"
|
||||
},
|
||||
"master_timeout":{
|
||||
"type":"time",
|
||||
"description":"Specify timeout for connection to master"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
{
|
||||
"cluster.get_component_template":{
|
||||
"documentation":{
|
||||
"url":"https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-component-templates.html",
|
||||
"description":"Returns one or more component templates"
|
||||
},
|
||||
"stability":"stable",
|
||||
"url":{
|
||||
"paths":[
|
||||
{
|
||||
"path":"/_component_template",
|
||||
"methods":[
|
||||
"GET"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path":"/_component_template/{name}",
|
||||
"methods":[
|
||||
"GET"
|
||||
],
|
||||
"parts":{
|
||||
"name":{
|
||||
"type":"list",
|
||||
"description":"The comma separated names of the component templates"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"params":{
|
||||
"master_timeout":{
|
||||
"type":"time",
|
||||
"description":"Explicit operation timeout for connection to master node"
|
||||
},
|
||||
"local":{
|
||||
"type":"boolean",
|
||||
"description":"Return local information, do not retrieve the state from master node (default: false)"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
{
|
||||
"cluster.put_component_template":{
|
||||
"documentation":{
|
||||
"url":"https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-component-templates.html",
|
||||
"description":"Creates or updates a component template"
|
||||
},
|
||||
"stability":"stable",
|
||||
"url":{
|
||||
"paths":[
|
||||
{
|
||||
"path":"/_component_template/{name}",
|
||||
"methods":[
|
||||
"PUT",
|
||||
"POST"
|
||||
],
|
||||
"parts":{
|
||||
"name":{
|
||||
"type":"string",
|
||||
"description":"The name of the template"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"params":{
|
||||
"create":{
|
||||
"type":"boolean",
|
||||
"description":"Whether the index template should only be added if new or can also replace an existing one",
|
||||
"default":false
|
||||
},
|
||||
"timeout":{
|
||||
"type":"time",
|
||||
"description":"Explicit operation timeout"
|
||||
},
|
||||
"master_timeout":{
|
||||
"type":"time",
|
||||
"description":"Specify timeout for connection to master"
|
||||
}
|
||||
},
|
||||
"body":{
|
||||
"description":"The template definition",
|
||||
"required":true
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
---
|
||||
"Basic CRUD":
|
||||
- skip:
|
||||
version: " - 7.99.99"
|
||||
reason: not backported yet
|
||||
|
||||
- do:
|
||||
cluster.put_component_template:
|
||||
name: test
|
||||
body:
|
||||
template:
|
||||
settings:
|
||||
number_of_shards: 1
|
||||
number_of_replicas: 0
|
||||
mappings:
|
||||
properties:
|
||||
field:
|
||||
type: keyword
|
||||
aliases:
|
||||
aliasname: {}
|
||||
version: 2
|
||||
_meta:
|
||||
foo: bar
|
||||
baz:
|
||||
eggplant: true
|
||||
|
||||
- do:
|
||||
cluster.get_component_template:
|
||||
name: test
|
||||
|
||||
- match: {component_templates.0.name: test}
|
||||
- match: {component_templates.0.component_template.version: 2}
|
||||
- match: {component_templates.0.component_template._meta: {foo: bar, baz: {eggplant: true}}}
|
||||
- match: {component_templates.0.component_template.template.settings: {index: {number_of_shards: '1', number_of_replicas: '0'}}}
|
||||
- match: {component_templates.0.component_template.template.mappings: {properties: {field: {type: keyword}}}}
|
||||
- match: {component_templates.0.component_template.template.aliases: {aliasname: {}}}
|
||||
|
||||
- do:
|
||||
cluster.delete_component_template:
|
||||
name: test
|
||||
|
||||
- do:
|
||||
catch: missing
|
||||
cluster.get_component_template:
|
||||
name: test
|
||||
|
||||
- is_false: test
|
@ -21,6 +21,7 @@ package org.elasticsearch.action;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.elasticsearch.Build;
|
||||
import org.elasticsearch.action.admin.cluster.allocation.ClusterAllocationExplainAction;
|
||||
import org.elasticsearch.action.admin.cluster.allocation.TransportClusterAllocationExplainAction;
|
||||
import org.elasticsearch.action.admin.cluster.configuration.AddVotingConfigExclusionsAction;
|
||||
@ -147,11 +148,17 @@ import org.elasticsearch.action.admin.indices.shrink.ResizeAction;
|
||||
import org.elasticsearch.action.admin.indices.shrink.TransportResizeAction;
|
||||
import org.elasticsearch.action.admin.indices.stats.IndicesStatsAction;
|
||||
import org.elasticsearch.action.admin.indices.stats.TransportIndicesStatsAction;
|
||||
import org.elasticsearch.action.admin.indices.template.delete.DeleteComponentTemplateAction;
|
||||
import org.elasticsearch.action.admin.indices.template.delete.DeleteIndexTemplateAction;
|
||||
import org.elasticsearch.action.admin.indices.template.delete.TransportDeleteComponentTemplateAction;
|
||||
import org.elasticsearch.action.admin.indices.template.delete.TransportDeleteIndexTemplateAction;
|
||||
import org.elasticsearch.action.admin.indices.template.get.GetComponentTemplateAction;
|
||||
import org.elasticsearch.action.admin.indices.template.get.GetIndexTemplatesAction;
|
||||
import org.elasticsearch.action.admin.indices.template.get.TransportGetComponentTemplateAction;
|
||||
import org.elasticsearch.action.admin.indices.template.get.TransportGetIndexTemplatesAction;
|
||||
import org.elasticsearch.action.admin.indices.template.put.PutComponentTemplateAction;
|
||||
import org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateAction;
|
||||
import org.elasticsearch.action.admin.indices.template.put.TransportPutComponentTemplateAction;
|
||||
import org.elasticsearch.action.admin.indices.template.put.TransportPutIndexTemplateAction;
|
||||
import org.elasticsearch.action.admin.indices.upgrade.get.TransportUpgradeStatusAction;
|
||||
import org.elasticsearch.action.admin.indices.upgrade.get.UpgradeStatusAction;
|
||||
@ -270,11 +277,13 @@ import org.elasticsearch.rest.action.admin.indices.RestAnalyzeAction;
|
||||
import org.elasticsearch.rest.action.admin.indices.RestClearIndicesCacheAction;
|
||||
import org.elasticsearch.rest.action.admin.indices.RestCloseIndexAction;
|
||||
import org.elasticsearch.rest.action.admin.indices.RestCreateIndexAction;
|
||||
import org.elasticsearch.rest.action.admin.indices.RestDeleteComponentTemplateAction;
|
||||
import org.elasticsearch.rest.action.admin.indices.RestDeleteIndexAction;
|
||||
import org.elasticsearch.rest.action.admin.indices.RestDeleteIndexTemplateAction;
|
||||
import org.elasticsearch.rest.action.admin.indices.RestFlushAction;
|
||||
import org.elasticsearch.rest.action.admin.indices.RestForceMergeAction;
|
||||
import org.elasticsearch.rest.action.admin.indices.RestGetAliasesAction;
|
||||
import org.elasticsearch.rest.action.admin.indices.RestGetComponentTemplateAction;
|
||||
import org.elasticsearch.rest.action.admin.indices.RestGetFieldMappingAction;
|
||||
import org.elasticsearch.rest.action.admin.indices.RestGetIndexTemplateAction;
|
||||
import org.elasticsearch.rest.action.admin.indices.RestGetIndicesAction;
|
||||
@ -287,6 +296,7 @@ import org.elasticsearch.rest.action.admin.indices.RestIndicesSegmentsAction;
|
||||
import org.elasticsearch.rest.action.admin.indices.RestIndicesShardStoresAction;
|
||||
import org.elasticsearch.rest.action.admin.indices.RestIndicesStatsAction;
|
||||
import org.elasticsearch.rest.action.admin.indices.RestOpenIndexAction;
|
||||
import org.elasticsearch.rest.action.admin.indices.RestPutComponentTemplateAction;
|
||||
import org.elasticsearch.rest.action.admin.indices.RestPutIndexTemplateAction;
|
||||
import org.elasticsearch.rest.action.admin.indices.RestPutMappingAction;
|
||||
import org.elasticsearch.rest.action.admin.indices.RestRecoveryAction;
|
||||
@ -363,6 +373,24 @@ public class ActionModule extends AbstractModule {
|
||||
private static final Logger logger = LogManager.getLogger(ActionModule.class);
|
||||
|
||||
private final boolean transportClient;
|
||||
|
||||
private static final boolean ITV2_FEATURE_FLAG_REGISTERED;
|
||||
|
||||
static {
|
||||
final String property = System.getProperty("es.itv2_feature_flag_registered");
|
||||
if (Build.CURRENT.isSnapshot() && property != null) {
|
||||
throw new IllegalArgumentException("es.itv2_feature_flag_registered is only supported in non-snapshot builds");
|
||||
}
|
||||
if (Build.CURRENT.isSnapshot() || "true".equals(property)) {
|
||||
ITV2_FEATURE_FLAG_REGISTERED = true;
|
||||
} else if ("false".equals(property) || property == null) {
|
||||
ITV2_FEATURE_FLAG_REGISTERED = false;
|
||||
} else {
|
||||
throw new IllegalArgumentException("expected es.itv2_feature_flag_registered to be unset, true, or false but was [" +
|
||||
property + "]");
|
||||
}
|
||||
}
|
||||
|
||||
private final Settings settings;
|
||||
private final IndexNameExpressionResolver indexNameExpressionResolver;
|
||||
private final IndexScopedSettings indexScopedSettings;
|
||||
@ -497,6 +525,11 @@ public class ActionModule extends AbstractModule {
|
||||
actions.register(PutIndexTemplateAction.INSTANCE, TransportPutIndexTemplateAction.class);
|
||||
actions.register(GetIndexTemplatesAction.INSTANCE, TransportGetIndexTemplatesAction.class);
|
||||
actions.register(DeleteIndexTemplateAction.INSTANCE, TransportDeleteIndexTemplateAction.class);
|
||||
if (ITV2_FEATURE_FLAG_REGISTERED) {
|
||||
actions.register(PutComponentTemplateAction.INSTANCE, TransportPutComponentTemplateAction.class);
|
||||
actions.register(GetComponentTemplateAction.INSTANCE, TransportGetComponentTemplateAction.class);
|
||||
actions.register(DeleteComponentTemplateAction.INSTANCE, TransportDeleteComponentTemplateAction.class);
|
||||
}
|
||||
actions.register(ValidateQueryAction.INSTANCE, TransportValidateQueryAction.class);
|
||||
actions.register(RefreshAction.INSTANCE, TransportRefreshAction.class);
|
||||
actions.register(FlushAction.INSTANCE, TransportFlushAction.class);
|
||||
@ -624,6 +657,11 @@ public class ActionModule extends AbstractModule {
|
||||
registerHandler.accept(new RestGetIndexTemplateAction());
|
||||
registerHandler.accept(new RestPutIndexTemplateAction());
|
||||
registerHandler.accept(new RestDeleteIndexTemplateAction());
|
||||
if (ITV2_FEATURE_FLAG_REGISTERED) {
|
||||
registerHandler.accept(new RestPutComponentTemplateAction());
|
||||
registerHandler.accept(new RestGetComponentTemplateAction());
|
||||
registerHandler.accept(new RestDeleteComponentTemplateAction());
|
||||
}
|
||||
|
||||
registerHandler.accept(new RestPutMappingAction());
|
||||
registerHandler.accept(new RestGetMappingAction());
|
||||
|
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* 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.action.admin.indices.template.delete;
|
||||
|
||||
import org.elasticsearch.action.ActionRequestValidationException;
|
||||
import org.elasticsearch.action.ActionType;
|
||||
import org.elasticsearch.action.support.master.AcknowledgedResponse;
|
||||
import org.elasticsearch.action.support.master.MasterNodeRequest;
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import static org.elasticsearch.action.ValidateActions.addValidationError;
|
||||
|
||||
public class DeleteComponentTemplateAction extends ActionType<AcknowledgedResponse> {
|
||||
|
||||
public static final DeleteComponentTemplateAction INSTANCE = new DeleteComponentTemplateAction();
|
||||
public static final String NAME = "cluster:admin/component_template/delete";
|
||||
|
||||
private DeleteComponentTemplateAction() {
|
||||
super(NAME, AcknowledgedResponse::new);
|
||||
}
|
||||
|
||||
public static class Request extends MasterNodeRequest<Request> {
|
||||
|
||||
private String name;
|
||||
|
||||
public Request(StreamInput in) throws IOException {
|
||||
super(in);
|
||||
name = in.readString();
|
||||
}
|
||||
|
||||
public Request() { }
|
||||
|
||||
/**
|
||||
* Constructs a new delete index request for the specified name.
|
||||
*/
|
||||
public Request(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the index template name to delete.
|
||||
*/
|
||||
public Request name(String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionRequestValidationException validate() {
|
||||
ActionRequestValidationException validationException = null;
|
||||
if (name == null) {
|
||||
validationException = addValidationError("name is missing", validationException);
|
||||
}
|
||||
return validationException;
|
||||
}
|
||||
|
||||
/**
|
||||
* The index template name to delete.
|
||||
*/
|
||||
public String name() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(StreamOutput out) throws IOException {
|
||||
super.writeTo(out);
|
||||
out.writeString(name);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* 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.action.admin.indices.template.delete;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.elasticsearch.action.ActionListener;
|
||||
import org.elasticsearch.action.support.ActionFilters;
|
||||
import org.elasticsearch.action.support.master.AcknowledgedResponse;
|
||||
import org.elasticsearch.action.support.master.TransportMasterNodeAction;
|
||||
import org.elasticsearch.cluster.ClusterState;
|
||||
import org.elasticsearch.cluster.block.ClusterBlockException;
|
||||
import org.elasticsearch.cluster.block.ClusterBlockLevel;
|
||||
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
|
||||
import org.elasticsearch.cluster.metadata.MetaDataIndexTemplateService;
|
||||
import org.elasticsearch.cluster.service.ClusterService;
|
||||
import org.elasticsearch.common.inject.Inject;
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.elasticsearch.transport.TransportService;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class TransportDeleteComponentTemplateAction
|
||||
extends TransportMasterNodeAction<DeleteComponentTemplateAction.Request, AcknowledgedResponse> {
|
||||
|
||||
private static final Logger logger = LogManager.getLogger(TransportDeleteComponentTemplateAction.class);
|
||||
|
||||
private final MetaDataIndexTemplateService indexTemplateService;
|
||||
|
||||
@Inject
|
||||
public TransportDeleteComponentTemplateAction(TransportService transportService, ClusterService clusterService,
|
||||
ThreadPool threadPool, MetaDataIndexTemplateService indexTemplateService,
|
||||
ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver) {
|
||||
super(DeleteComponentTemplateAction.NAME, transportService, clusterService, threadPool, actionFilters,
|
||||
DeleteComponentTemplateAction.Request::new, indexNameExpressionResolver);
|
||||
this.indexTemplateService = indexTemplateService;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String executor() {
|
||||
// we go async right away
|
||||
return ThreadPool.Names.SAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AcknowledgedResponse read(StreamInput in) throws IOException {
|
||||
return new AcknowledgedResponse(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ClusterBlockException checkBlock(DeleteComponentTemplateAction.Request request, ClusterState state) {
|
||||
return state.blocks().globalBlockedException(ClusterBlockLevel.METADATA_WRITE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void masterOperation(final DeleteComponentTemplateAction.Request request, final ClusterState state,
|
||||
final ActionListener<AcknowledgedResponse> listener) {
|
||||
indexTemplateService.removeComponentTemplate(request.name(), request.masterNodeTimeout(), listener);
|
||||
}
|
||||
}
|
@ -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.action.admin.indices.template.get;
|
||||
|
||||
import org.elasticsearch.action.ActionRequestValidationException;
|
||||
import org.elasticsearch.action.ActionResponse;
|
||||
import org.elasticsearch.action.ActionType;
|
||||
import org.elasticsearch.action.support.master.MasterNodeReadRequest;
|
||||
import org.elasticsearch.cluster.metadata.ComponentTemplate;
|
||||
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.ToXContentObject;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import static org.elasticsearch.action.ValidateActions.addValidationError;
|
||||
|
||||
/**
|
||||
* Action to retrieve one or more component templates
|
||||
*/
|
||||
public class GetComponentTemplateAction extends ActionType<GetComponentTemplateAction.Response> {
|
||||
|
||||
public static final GetComponentTemplateAction INSTANCE = new GetComponentTemplateAction();
|
||||
public static final String NAME = "cluster:admin/component_template/get";
|
||||
|
||||
private GetComponentTemplateAction() {
|
||||
super(NAME, GetComponentTemplateAction.Response::new);
|
||||
}
|
||||
|
||||
/**
|
||||
* Request that to retrieve one or more component templates
|
||||
*/
|
||||
public static class Request extends MasterNodeReadRequest<Request> {
|
||||
|
||||
private String[] names;
|
||||
|
||||
public Request() { }
|
||||
|
||||
public Request(String... names) {
|
||||
this.names = names;
|
||||
}
|
||||
|
||||
public Request(StreamInput in) throws IOException {
|
||||
super(in);
|
||||
names = in.readStringArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(StreamOutput out) throws IOException {
|
||||
super.writeTo(out);
|
||||
out.writeStringArray(names);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionRequestValidationException validate() {
|
||||
ActionRequestValidationException validationException = null;
|
||||
if (names == null) {
|
||||
validationException = addValidationError("names is null or empty", validationException);
|
||||
} else {
|
||||
for (String name : names) {
|
||||
if (name == null || Strings.hasText(name) == false) {
|
||||
validationException = addValidationError("name is missing", validationException);
|
||||
}
|
||||
}
|
||||
}
|
||||
return validationException;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the names of the component templates.
|
||||
*/
|
||||
public Request names(String... names) {
|
||||
this.names = names;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* The names of the component templates.
|
||||
*/
|
||||
public String[] names() {
|
||||
return this.names;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Response extends ActionResponse implements ToXContentObject {
|
||||
public static final ParseField NAME = new ParseField("name");
|
||||
public static final ParseField COMPONENT_TEMPLATES = new ParseField("component_templates");
|
||||
public static final ParseField COMPONENT_TEMPLATE = new ParseField("component_template");
|
||||
|
||||
private final Map<String, ComponentTemplate> componentTemplates;
|
||||
|
||||
public Response(StreamInput in) throws IOException {
|
||||
super(in);
|
||||
int size = in.readVInt();
|
||||
componentTemplates = new HashMap<>();
|
||||
for (int i = 0 ; i < size ; i++) {
|
||||
componentTemplates.put(in.readString(), new ComponentTemplate(in));
|
||||
}
|
||||
}
|
||||
|
||||
public Response(Map<String, ComponentTemplate> componentTemplates) {
|
||||
this.componentTemplates = componentTemplates;
|
||||
}
|
||||
|
||||
public Map<String, ComponentTemplate> getComponentTemplates() {
|
||||
return componentTemplates;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(StreamOutput out) throws IOException {
|
||||
out.writeVInt(componentTemplates.size());
|
||||
for (Map.Entry<String, ComponentTemplate> componentTemplate : componentTemplates.entrySet()) {
|
||||
out.writeString(componentTemplate.getKey());
|
||||
componentTemplate.getValue().writeTo(out);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Response that = (Response) o;
|
||||
return Objects.equals(componentTemplates, that.componentTemplates);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(componentTemplates);
|
||||
}
|
||||
|
||||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
builder.startObject();
|
||||
builder.startArray(COMPONENT_TEMPLATES.getPreferredName());
|
||||
for (Map.Entry<String, ComponentTemplate> componentTemplate : this.componentTemplates.entrySet()) {
|
||||
builder.startObject();
|
||||
builder.field(NAME.getPreferredName(), componentTemplate.getKey());
|
||||
builder.field(COMPONENT_TEMPLATE.getPreferredName(), componentTemplate.getValue());
|
||||
builder.endObject();
|
||||
}
|
||||
builder.endArray();
|
||||
builder.endObject();
|
||||
return builder;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,93 @@
|
||||
/*
|
||||
* 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.action.admin.indices.template.get;
|
||||
|
||||
import org.elasticsearch.action.ActionListener;
|
||||
import org.elasticsearch.action.support.ActionFilters;
|
||||
import org.elasticsearch.action.support.master.TransportMasterNodeReadAction;
|
||||
import org.elasticsearch.cluster.ClusterState;
|
||||
import org.elasticsearch.cluster.block.ClusterBlockException;
|
||||
import org.elasticsearch.cluster.block.ClusterBlockLevel;
|
||||
import org.elasticsearch.cluster.metadata.ComponentTemplate;
|
||||
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
|
||||
import org.elasticsearch.cluster.service.ClusterService;
|
||||
import org.elasticsearch.common.inject.Inject;
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.regex.Regex;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.elasticsearch.transport.TransportService;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class TransportGetComponentTemplateAction extends
|
||||
TransportMasterNodeReadAction<GetComponentTemplateAction.Request, GetComponentTemplateAction.Response> {
|
||||
|
||||
@Inject
|
||||
public TransportGetComponentTemplateAction(TransportService transportService, ClusterService clusterService,
|
||||
ThreadPool threadPool, ActionFilters actionFilters,
|
||||
IndexNameExpressionResolver indexNameExpressionResolver) {
|
||||
super(GetComponentTemplateAction.NAME, transportService, clusterService, threadPool, actionFilters,
|
||||
GetComponentTemplateAction.Request::new, indexNameExpressionResolver);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String executor() {
|
||||
return ThreadPool.Names.SAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected GetComponentTemplateAction.Response read(StreamInput in) throws IOException {
|
||||
return new GetComponentTemplateAction.Response(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ClusterBlockException checkBlock(GetComponentTemplateAction.Request request, ClusterState state) {
|
||||
return state.blocks().globalBlockedException(ClusterBlockLevel.METADATA_READ);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void masterOperation(GetComponentTemplateAction.Request request, ClusterState state,
|
||||
ActionListener<GetComponentTemplateAction.Response> listener) {
|
||||
Map<String, ComponentTemplate> allTemplates = state.metaData().componentTemplates();
|
||||
|
||||
// If we did not ask for a specific name, then we return all templates
|
||||
if (request.names().length == 0) {
|
||||
listener.onResponse(new GetComponentTemplateAction.Response(allTemplates));
|
||||
return;
|
||||
}
|
||||
|
||||
final Map<String, ComponentTemplate> results = new HashMap<>();
|
||||
for (String name : request.names()) {
|
||||
if (Regex.isSimpleMatchPattern(name)) {
|
||||
for (Map.Entry<String, ComponentTemplate> entry : allTemplates.entrySet()) {
|
||||
if (Regex.simpleMatch(name, entry.getKey())) {
|
||||
results.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
} else if (allTemplates.containsKey(name)) {
|
||||
results.put(name, allTemplates.get(name));
|
||||
}
|
||||
}
|
||||
|
||||
listener.onResponse(new GetComponentTemplateAction.Response(results));
|
||||
}
|
||||
}
|
@ -0,0 +1,151 @@
|
||||
/*
|
||||
* 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.action.admin.indices.template.put;
|
||||
|
||||
import org.elasticsearch.action.ActionRequestValidationException;
|
||||
import org.elasticsearch.action.ActionType;
|
||||
import org.elasticsearch.action.support.master.AcknowledgedResponse;
|
||||
import org.elasticsearch.action.support.master.MasterNodeRequest;
|
||||
import org.elasticsearch.cluster.metadata.ComponentTemplate;
|
||||
import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import static org.elasticsearch.action.ValidateActions.addValidationError;
|
||||
|
||||
/**
|
||||
* An action for putting a single component template into the cluster state
|
||||
*/
|
||||
public class PutComponentTemplateAction extends ActionType<AcknowledgedResponse> {
|
||||
|
||||
public static final PutComponentTemplateAction INSTANCE = new PutComponentTemplateAction();
|
||||
public static final String NAME = "cluster:admin/component_template/put";
|
||||
|
||||
private PutComponentTemplateAction() {
|
||||
super(NAME, AcknowledgedResponse::new);
|
||||
}
|
||||
|
||||
/**
|
||||
* A request for putting a single component template into the cluster state
|
||||
*/
|
||||
public static class Request extends MasterNodeRequest<Request> {
|
||||
private final String name;
|
||||
@Nullable
|
||||
private String cause;
|
||||
private boolean create;
|
||||
private ComponentTemplate componentTemplate;
|
||||
|
||||
public Request(StreamInput in) throws IOException {
|
||||
super(in);
|
||||
this.name = in.readString();
|
||||
this.cause = in.readOptionalString();
|
||||
this.create = in.readBoolean();
|
||||
this.componentTemplate = new ComponentTemplate(in);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new put component template request with the provided name.
|
||||
*/
|
||||
public Request(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(StreamOutput out) throws IOException {
|
||||
super.writeTo(out);
|
||||
out.writeString(name);
|
||||
out.writeOptionalString(cause);
|
||||
out.writeBoolean(create);
|
||||
this.componentTemplate.writeTo(out);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionRequestValidationException validate() {
|
||||
ActionRequestValidationException validationException = null;
|
||||
if (name == null || Strings.hasText(name) == false) {
|
||||
validationException = addValidationError("name is missing", validationException);
|
||||
}
|
||||
if (componentTemplate == null) {
|
||||
validationException = addValidationError("a component template is required", validationException);
|
||||
}
|
||||
return validationException;
|
||||
}
|
||||
|
||||
/**
|
||||
* The name of the index template.
|
||||
*/
|
||||
public String name() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to {@code true} to force only creation, not an update of an index template. If it already
|
||||
* exists, it will fail with an {@link IllegalArgumentException}.
|
||||
*/
|
||||
public Request create(boolean create) {
|
||||
this.create = create;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean create() {
|
||||
return create;
|
||||
}
|
||||
|
||||
/**
|
||||
* The cause for this index template creation.
|
||||
*/
|
||||
public Request cause(@Nullable String cause) {
|
||||
this.cause = cause;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String cause() {
|
||||
return this.cause;
|
||||
}
|
||||
|
||||
/**
|
||||
* The component template that will be inserted into the cluster state
|
||||
*/
|
||||
public Request componentTemplate(ComponentTemplate template) {
|
||||
this.componentTemplate = template;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ComponentTemplate componentTemplate() {
|
||||
return this.componentTemplate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder("PutComponentRequest[");
|
||||
sb.append("name=").append(name);
|
||||
sb.append(", cause=").append(cause);
|
||||
sb.append(", create=").append(create);
|
||||
sb.append(", component_template=").append(componentTemplate);
|
||||
sb.append("]");
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* 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.action.admin.indices.template.put;
|
||||
|
||||
import org.elasticsearch.action.ActionListener;
|
||||
import org.elasticsearch.action.support.ActionFilters;
|
||||
import org.elasticsearch.action.support.master.AcknowledgedResponse;
|
||||
import org.elasticsearch.action.support.master.TransportMasterNodeAction;
|
||||
import org.elasticsearch.cluster.ClusterState;
|
||||
import org.elasticsearch.cluster.block.ClusterBlockException;
|
||||
import org.elasticsearch.cluster.block.ClusterBlockLevel;
|
||||
import org.elasticsearch.cluster.metadata.ComponentTemplate;
|
||||
import org.elasticsearch.cluster.metadata.IndexMetaData;
|
||||
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
|
||||
import org.elasticsearch.cluster.metadata.MetaDataIndexTemplateService;
|
||||
import org.elasticsearch.cluster.metadata.Template;
|
||||
import org.elasticsearch.cluster.service.ClusterService;
|
||||
import org.elasticsearch.common.inject.Inject;
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.elasticsearch.transport.TransportService;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class TransportPutComponentTemplateAction
|
||||
extends TransportMasterNodeAction<PutComponentTemplateAction.Request, AcknowledgedResponse> {
|
||||
|
||||
private final MetaDataIndexTemplateService indexTemplateService;
|
||||
|
||||
@Inject
|
||||
public TransportPutComponentTemplateAction(TransportService transportService, ClusterService clusterService,
|
||||
ThreadPool threadPool, MetaDataIndexTemplateService indexTemplateService,
|
||||
ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver) {
|
||||
super(PutComponentTemplateAction.NAME, transportService, clusterService, threadPool, actionFilters,
|
||||
PutComponentTemplateAction.Request::new, indexNameExpressionResolver);
|
||||
this.indexTemplateService = indexTemplateService;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String executor() {
|
||||
// we go async right away
|
||||
return ThreadPool.Names.SAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AcknowledgedResponse read(StreamInput in) throws IOException {
|
||||
return new AcknowledgedResponse(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ClusterBlockException checkBlock(PutComponentTemplateAction.Request request, ClusterState state) {
|
||||
return state.blocks().globalBlockedException(ClusterBlockLevel.METADATA_WRITE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void masterOperation(final PutComponentTemplateAction.Request request, final ClusterState state,
|
||||
final ActionListener<AcknowledgedResponse> listener) {
|
||||
ComponentTemplate componentTemplate = request.componentTemplate();
|
||||
Template template = componentTemplate.template();
|
||||
// Normalize the index settings if necessary
|
||||
if (template.settings() != null) {
|
||||
Settings.Builder settings = Settings.builder().put(template.settings()).normalizePrefix(IndexMetaData.INDEX_SETTING_PREFIX);
|
||||
template = new Template(settings.build(), template.mappings(), template.aliases());
|
||||
componentTemplate = new ComponentTemplate(template, componentTemplate.version(), componentTemplate.metadata());
|
||||
}
|
||||
indexTemplateService.putComponentTemplate(request.cause(), request.create(), request.name(), request.masterNodeTimeout(),
|
||||
componentTemplate, listener);
|
||||
}
|
||||
}
|
@ -24,26 +24,19 @@ import org.elasticsearch.cluster.Diff;
|
||||
import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.common.ParseField;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.bytes.BytesArray;
|
||||
import org.elasticsearch.common.compress.CompressedXContent;
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
|
||||
import org.elasticsearch.common.xcontent.ToXContentObject;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.common.xcontent.XContentFactory;
|
||||
import org.elasticsearch.common.xcontent.XContentHelper;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.common.xcontent.XContentType;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A component template is a re-usable template as well as metadata about the template. Each
|
||||
* A component template is a re-usable {@link Template} as well as metadata about the template. Each
|
||||
* component template is expected to be valid on its own. For example, if a component template
|
||||
* contains a field "foo", it's expected to contain all the necessary settings/mappings/etc for the
|
||||
* "foo" field. These component templates make up the individual pieces composing an index template.
|
||||
@ -157,144 +150,4 @@ public class ComponentTemplate extends AbstractDiffable<ComponentTemplate> imple
|
||||
builder.endObject();
|
||||
return builder;
|
||||
}
|
||||
|
||||
static class Template extends AbstractDiffable<Template> implements ToXContentObject {
|
||||
private static final ParseField SETTINGS = new ParseField("settings");
|
||||
private static final ParseField MAPPINGS = new ParseField("mappings");
|
||||
private static final ParseField ALIASES = new ParseField("aliases");
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static final ConstructingObjectParser<Template, Void> PARSER = new ConstructingObjectParser<>("template", false,
|
||||
a -> new Template((Settings) a[0], (CompressedXContent) a[1], (Map<String, AliasMetaData>) a[2]));
|
||||
|
||||
static {
|
||||
PARSER.declareObject(ConstructingObjectParser.optionalConstructorArg(), (p, c) -> Settings.fromXContent(p), SETTINGS);
|
||||
PARSER.declareObject(ConstructingObjectParser.optionalConstructorArg(), (p, c) ->
|
||||
new CompressedXContent(Strings.toString(XContentFactory.jsonBuilder().map(p.mapOrdered()))), MAPPINGS);
|
||||
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);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private final Settings settings;
|
||||
@Nullable
|
||||
private final CompressedXContent mappings;
|
||||
@Nullable
|
||||
private final Map<String, AliasMetaData> aliases;
|
||||
|
||||
Template(@Nullable Settings settings, @Nullable CompressedXContent mappings, @Nullable Map<String, AliasMetaData> aliases) {
|
||||
this.settings = settings;
|
||||
this.mappings = mappings;
|
||||
this.aliases = aliases;
|
||||
}
|
||||
|
||||
Template(StreamInput in) throws IOException {
|
||||
if (in.readBoolean()) {
|
||||
this.settings = Settings.readSettingsFromStream(in);
|
||||
} else {
|
||||
this.settings = null;
|
||||
}
|
||||
if (in.readBoolean()) {
|
||||
this.mappings = CompressedXContent.readCompressedString(in);
|
||||
} else {
|
||||
this.mappings = null;
|
||||
}
|
||||
if (in.readBoolean()) {
|
||||
this.aliases = in.readMap(StreamInput::readString, AliasMetaData::new);
|
||||
} else {
|
||||
this.aliases = null;
|
||||
}
|
||||
}
|
||||
|
||||
public Settings settings() {
|
||||
return settings;
|
||||
}
|
||||
|
||||
public CompressedXContent mappings() {
|
||||
return mappings;
|
||||
}
|
||||
|
||||
public Map<String, AliasMetaData> aliases() {
|
||||
return aliases;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(StreamOutput out) throws IOException {
|
||||
if (this.settings == null) {
|
||||
out.writeBoolean(false);
|
||||
} else {
|
||||
out.writeBoolean(true);
|
||||
Settings.writeSettingsToStream(this.settings, out);
|
||||
}
|
||||
if (this.mappings == null) {
|
||||
out.writeBoolean(false);
|
||||
} else {
|
||||
out.writeBoolean(true);
|
||||
this.mappings.writeTo(out);
|
||||
}
|
||||
if (this.aliases == null) {
|
||||
out.writeBoolean(false);
|
||||
} else {
|
||||
out.writeBoolean(true);
|
||||
out.writeMap(this.aliases, StreamOutput::writeString, (stream, aliasMetaData) -> aliasMetaData.writeTo(stream));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(settings, mappings, aliases);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (obj.getClass() != getClass()) {
|
||||
return false;
|
||||
}
|
||||
Template other = (Template) obj;
|
||||
return Objects.equals(settings, other.settings) &&
|
||||
Objects.equals(mappings, other.mappings) &&
|
||||
Objects.equals(aliases, other.aliases);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return Strings.toString(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
builder.startObject();
|
||||
if (this.settings != null) {
|
||||
builder.startObject(SETTINGS.getPreferredName());
|
||||
this.settings.toXContent(builder, params);
|
||||
builder.endObject();
|
||||
}
|
||||
if (this.mappings != null) {
|
||||
Map<String, Object> uncompressedMapping =
|
||||
XContentHelper.convertToMap(new BytesArray(this.mappings.uncompressed()), true, XContentType.JSON).v2();
|
||||
if (uncompressedMapping.size() > 0) {
|
||||
builder.field(MAPPINGS.getPreferredName());
|
||||
builder.map(uncompressedMapping);
|
||||
}
|
||||
}
|
||||
if (this.aliases != null) {
|
||||
builder.startObject(ALIASES.getPreferredName());
|
||||
for (AliasMetaData alias : this.aliases.values()) {
|
||||
AliasMetaData.Builder.toXContent(alias, builder, params);
|
||||
}
|
||||
builder.endObject();
|
||||
}
|
||||
builder.endObject();
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,9 @@ import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.lucene.util.CollectionUtil;
|
||||
import org.elasticsearch.Version;
|
||||
import org.elasticsearch.action.ActionListener;
|
||||
import org.elasticsearch.action.admin.indices.alias.Alias;
|
||||
import org.elasticsearch.action.support.master.AcknowledgedResponse;
|
||||
import org.elasticsearch.action.support.master.MasterNodeRequest;
|
||||
import org.elasticsearch.cluster.ClusterState;
|
||||
import org.elasticsearch.cluster.ClusterStateUpdateTask;
|
||||
@ -134,6 +136,104 @@ public class MetaDataIndexTemplateService {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the given component template to the cluster state. If {@code create} is true, an
|
||||
* exception will be thrown if the component template already exists
|
||||
*/
|
||||
public void putComponentTemplate(final String cause, final boolean create, final String name, final TimeValue masterTimeout,
|
||||
final ComponentTemplate template, final ActionListener<AcknowledgedResponse> listener) {
|
||||
clusterService.submitStateUpdateTask("create-component-template [" + name + "], cause [" + cause + "]",
|
||||
new ClusterStateUpdateTask(Priority.URGENT) {
|
||||
|
||||
@Override
|
||||
public TimeValue timeout() {
|
||||
return masterTimeout;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(String source, Exception e) {
|
||||
listener.onFailure(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClusterState execute(ClusterState currentState) {
|
||||
return addComponentTemplate(currentState, create, name, template);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clusterStateProcessed(String source, ClusterState oldState, ClusterState newState) {
|
||||
listener.onResponse(new AcknowledgedResponse(true));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Package visible for testing
|
||||
static ClusterState addComponentTemplate(final ClusterState currentState, final boolean create,
|
||||
final String name, final ComponentTemplate template) {
|
||||
if (create && currentState.metaData().componentTemplates().containsKey(name)) {
|
||||
throw new IllegalArgumentException("component template [" + name + "] already exists");
|
||||
}
|
||||
|
||||
// TODO: validation of component template
|
||||
// validateAndAddTemplate(request, templateBuilder, indicesService, xContentRegistry);
|
||||
|
||||
logger.info("adding component template [{}]", name);
|
||||
return ClusterState.builder(currentState)
|
||||
.metaData(MetaData.builder(currentState.metaData()).put(name, template))
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the given component template from the cluster state. The component template name
|
||||
* supports simple regex wildcards for removing multiple component templates at a time.
|
||||
*/
|
||||
public void removeComponentTemplate(final String name, final TimeValue masterTimeout,
|
||||
final ActionListener<AcknowledgedResponse> listener) {
|
||||
clusterService.submitStateUpdateTask("remove-component-template [" + name + "]",
|
||||
new ClusterStateUpdateTask(Priority.URGENT) {
|
||||
|
||||
@Override
|
||||
public TimeValue timeout() {
|
||||
return masterTimeout;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(String source, Exception e) {
|
||||
listener.onFailure(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClusterState execute(ClusterState currentState) {
|
||||
Set<String> templateNames = new HashSet<>();
|
||||
for (String templateName : currentState.metaData().componentTemplates().keySet()) {
|
||||
if (Regex.simpleMatch(name, templateName)) {
|
||||
templateNames.add(templateName);
|
||||
}
|
||||
}
|
||||
if (templateNames.isEmpty()) {
|
||||
// if its a match all pattern, and no templates are found (we have none), don't
|
||||
// fail with index missing...
|
||||
if (Regex.isMatchAllPattern(name)) {
|
||||
return currentState;
|
||||
}
|
||||
// TODO: perhaps introduce a ComponentTemplateMissingException?
|
||||
throw new IndexTemplateMissingException(name);
|
||||
}
|
||||
MetaData.Builder metaData = MetaData.builder(currentState.metaData());
|
||||
for (String templateName : templateNames) {
|
||||
logger.info("removing component template [{}]", templateName);
|
||||
metaData.removeComponentTemplate(templateName);
|
||||
}
|
||||
return ClusterState.builder(currentState).metaData(metaData).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clusterStateProcessed(String source, ClusterState oldState, ClusterState newState) {
|
||||
listener.onResponse(new AcknowledgedResponse(true));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void putTemplate(final PutRequest request, final PutListener listener) {
|
||||
Settings.Builder updatedSettingsBuilder = Settings.builder();
|
||||
updatedSettingsBuilder.put(request.settings).normalizePrefix(IndexMetaData.INDEX_SETTING_PREFIX);
|
||||
|
@ -0,0 +1,187 @@
|
||||
/*
|
||||
* 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.common.Nullable;
|
||||
import org.elasticsearch.common.ParseField;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.bytes.BytesArray;
|
||||
import org.elasticsearch.common.compress.CompressedXContent;
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
|
||||
import org.elasticsearch.common.xcontent.ToXContentObject;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.common.xcontent.XContentFactory;
|
||||
import org.elasticsearch.common.xcontent.XContentHelper;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.common.xcontent.XContentType;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A template consists of optional settings, mappings, or alias configuration for an index, however,
|
||||
* it is entirely independent from an index. It's a building block forming part of a regular index
|
||||
* template and a {@link ComponentTemplate}.
|
||||
*/
|
||||
public class Template extends AbstractDiffable<Template> implements ToXContentObject {
|
||||
private static final ParseField SETTINGS = new ParseField("settings");
|
||||
private static final ParseField MAPPINGS = new ParseField("mappings");
|
||||
private static final ParseField ALIASES = new ParseField("aliases");
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
static final ConstructingObjectParser<Template, Void> PARSER = new ConstructingObjectParser<>("template", false,
|
||||
a -> new Template((Settings) a[0], (CompressedXContent) a[1], (Map<String, AliasMetaData>) a[2]));
|
||||
|
||||
static {
|
||||
PARSER.declareObject(ConstructingObjectParser.optionalConstructorArg(), (p, c) -> Settings.fromXContent(p), SETTINGS);
|
||||
PARSER.declareObject(ConstructingObjectParser.optionalConstructorArg(), (p, c) ->
|
||||
new CompressedXContent(Strings.toString(XContentFactory.jsonBuilder().map(p.mapOrdered()))), MAPPINGS);
|
||||
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);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private final Settings settings;
|
||||
@Nullable
|
||||
private final CompressedXContent mappings;
|
||||
@Nullable
|
||||
private final Map<String, AliasMetaData> aliases;
|
||||
|
||||
public Template(@Nullable Settings settings, @Nullable CompressedXContent mappings, @Nullable Map<String, AliasMetaData> aliases) {
|
||||
this.settings = settings;
|
||||
this.mappings = mappings;
|
||||
this.aliases = aliases;
|
||||
}
|
||||
|
||||
Template(StreamInput in) throws IOException {
|
||||
if (in.readBoolean()) {
|
||||
this.settings = Settings.readSettingsFromStream(in);
|
||||
} else {
|
||||
this.settings = null;
|
||||
}
|
||||
if (in.readBoolean()) {
|
||||
this.mappings = CompressedXContent.readCompressedString(in);
|
||||
} else {
|
||||
this.mappings = null;
|
||||
}
|
||||
if (in.readBoolean()) {
|
||||
this.aliases = in.readMap(StreamInput::readString, AliasMetaData::new);
|
||||
} else {
|
||||
this.aliases = null;
|
||||
}
|
||||
}
|
||||
|
||||
public Settings settings() {
|
||||
return settings;
|
||||
}
|
||||
|
||||
public CompressedXContent mappings() {
|
||||
return mappings;
|
||||
}
|
||||
|
||||
public Map<String, AliasMetaData> aliases() {
|
||||
return aliases;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(StreamOutput out) throws IOException {
|
||||
if (this.settings == null) {
|
||||
out.writeBoolean(false);
|
||||
} else {
|
||||
out.writeBoolean(true);
|
||||
Settings.writeSettingsToStream(this.settings, out);
|
||||
}
|
||||
if (this.mappings == null) {
|
||||
out.writeBoolean(false);
|
||||
} else {
|
||||
out.writeBoolean(true);
|
||||
this.mappings.writeTo(out);
|
||||
}
|
||||
if (this.aliases == null) {
|
||||
out.writeBoolean(false);
|
||||
} else {
|
||||
out.writeBoolean(true);
|
||||
out.writeMap(this.aliases, StreamOutput::writeString, (stream, aliasMetaData) -> aliasMetaData.writeTo(stream));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(settings, mappings, aliases);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (obj.getClass() != getClass()) {
|
||||
return false;
|
||||
}
|
||||
Template other = (Template) obj;
|
||||
return Objects.equals(settings, other.settings) &&
|
||||
Objects.equals(mappings, other.mappings) &&
|
||||
Objects.equals(aliases, other.aliases);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return Strings.toString(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
builder.startObject();
|
||||
if (this.settings != null) {
|
||||
builder.startObject(SETTINGS.getPreferredName());
|
||||
this.settings.toXContent(builder, params);
|
||||
builder.endObject();
|
||||
}
|
||||
if (this.mappings != null) {
|
||||
Map<String, Object> uncompressedMapping =
|
||||
XContentHelper.convertToMap(new BytesArray(this.mappings.uncompressed()), true, XContentType.JSON).v2();
|
||||
if (uncompressedMapping.size() > 0) {
|
||||
builder.field(MAPPINGS.getPreferredName());
|
||||
builder.map(uncompressedMapping);
|
||||
}
|
||||
}
|
||||
if (this.aliases != null) {
|
||||
builder.startObject(ALIASES.getPreferredName());
|
||||
for (AliasMetaData alias : this.aliases.values()) {
|
||||
AliasMetaData.Builder.toXContent(alias, builder, params);
|
||||
}
|
||||
builder.endObject();
|
||||
}
|
||||
builder.endObject();
|
||||
return builder;
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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.rest.action.admin.indices;
|
||||
|
||||
import org.elasticsearch.action.admin.indices.template.delete.DeleteComponentTemplateAction;
|
||||
import org.elasticsearch.client.node.NodeClient;
|
||||
import org.elasticsearch.rest.BaseRestHandler;
|
||||
import org.elasticsearch.rest.RestRequest;
|
||||
import org.elasticsearch.rest.action.RestToXContentListener;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static org.elasticsearch.rest.RestRequest.Method.DELETE;
|
||||
|
||||
public class RestDeleteComponentTemplateAction extends BaseRestHandler {
|
||||
|
||||
@Override
|
||||
public List<Route> routes() {
|
||||
return Collections.singletonList(new Route(DELETE, "/_component_template/{name}"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "delete_component_template_action";
|
||||
}
|
||||
|
||||
@Override
|
||||
public RestChannelConsumer prepareRequest(final RestRequest request, final NodeClient client) throws IOException {
|
||||
|
||||
DeleteComponentTemplateAction.Request deleteReq = new DeleteComponentTemplateAction.Request(request.param("name"));
|
||||
deleteReq.masterNodeTimeout(request.paramAsTime("master_timeout", deleteReq.masterNodeTimeout()));
|
||||
|
||||
return channel -> client.execute(DeleteComponentTemplateAction.INSTANCE, deleteReq, new RestToXContentListener<>(channel));
|
||||
}
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* 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.rest.action.admin.indices;
|
||||
|
||||
import org.elasticsearch.action.admin.indices.template.get.GetComponentTemplateAction;
|
||||
import org.elasticsearch.client.node.NodeClient;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.rest.BaseRestHandler;
|
||||
import org.elasticsearch.rest.RestRequest;
|
||||
import org.elasticsearch.rest.RestStatus;
|
||||
import org.elasticsearch.rest.action.RestToXContentListener;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.elasticsearch.rest.RestRequest.Method.GET;
|
||||
import static org.elasticsearch.rest.RestRequest.Method.HEAD;
|
||||
import static org.elasticsearch.rest.RestStatus.NOT_FOUND;
|
||||
import static org.elasticsearch.rest.RestStatus.OK;
|
||||
|
||||
public class RestGetComponentTemplateAction extends BaseRestHandler {
|
||||
|
||||
@Override
|
||||
public List<Route> routes() {
|
||||
return Arrays.asList(
|
||||
new Route(GET, "/_component_template"),
|
||||
new Route(GET, "/_component_template/{name}"),
|
||||
new Route(HEAD, "/_component_template/{name}"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "get_component_template_action";
|
||||
}
|
||||
|
||||
@Override
|
||||
public RestChannelConsumer prepareRequest(final RestRequest request, final NodeClient client) throws IOException {
|
||||
final String[] names = Strings.splitStringByCommaToArray(request.param("name"));
|
||||
|
||||
final GetComponentTemplateAction.Request getRequest = new GetComponentTemplateAction.Request(names);
|
||||
|
||||
getRequest.local(request.paramAsBoolean("local", getRequest.local()));
|
||||
getRequest.masterNodeTimeout(request.paramAsTime("master_timeout", getRequest.masterNodeTimeout()));
|
||||
|
||||
final boolean implicitAll = getRequest.names().length == 0;
|
||||
|
||||
return channel ->
|
||||
client.execute(GetComponentTemplateAction.INSTANCE, getRequest,
|
||||
new RestToXContentListener<GetComponentTemplateAction.Response>(channel) {
|
||||
@Override
|
||||
protected RestStatus getStatus(final GetComponentTemplateAction.Response response) {
|
||||
final boolean templateExists = response.getComponentTemplates().isEmpty() == false;
|
||||
return (templateExists || implicitAll) ? OK : NOT_FOUND;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Set<String> responseParams() {
|
||||
return Settings.FORMAT_PARAMS;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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.rest.action.admin.indices;
|
||||
|
||||
import org.elasticsearch.action.admin.indices.template.put.PutComponentTemplateAction;
|
||||
import org.elasticsearch.client.node.NodeClient;
|
||||
import org.elasticsearch.cluster.metadata.ComponentTemplate;
|
||||
import org.elasticsearch.rest.BaseRestHandler;
|
||||
import org.elasticsearch.rest.RestRequest;
|
||||
import org.elasticsearch.rest.action.RestToXContentListener;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static org.elasticsearch.rest.RestRequest.Method.POST;
|
||||
import static org.elasticsearch.rest.RestRequest.Method.PUT;
|
||||
|
||||
public class RestPutComponentTemplateAction extends BaseRestHandler {
|
||||
|
||||
@Override
|
||||
public List<Route> routes() {
|
||||
return Arrays.asList(
|
||||
new Route(POST, "/_component_template/{name}"),
|
||||
new Route(PUT, "/_component_template/{name}"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "put_component_template_action";
|
||||
}
|
||||
|
||||
@Override
|
||||
public RestChannelConsumer prepareRequest(final RestRequest request, final NodeClient client) throws IOException {
|
||||
|
||||
PutComponentTemplateAction.Request putRequest = new PutComponentTemplateAction.Request(request.param("name"));
|
||||
putRequest.masterNodeTimeout(request.paramAsTime("master_timeout", putRequest.masterNodeTimeout()));
|
||||
putRequest.create(request.paramAsBoolean("create", false));
|
||||
putRequest.cause(request.param("cause", "api"));
|
||||
putRequest.componentTemplate(ComponentTemplate.parse(request.contentParser()));
|
||||
|
||||
return channel -> client.execute(PutComponentTemplateAction.INSTANCE, putRequest, new RestToXContentListener<>(channel));
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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.action.admin.indices.template.get;
|
||||
|
||||
import org.elasticsearch.cluster.metadata.ComponentTemplate;
|
||||
import org.elasticsearch.cluster.metadata.ComponentTemplateTests;
|
||||
import org.elasticsearch.common.io.stream.Writeable;
|
||||
import org.elasticsearch.test.AbstractWireSerializingTestCase;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class GetComponentTemplateResponseTests extends AbstractWireSerializingTestCase<GetComponentTemplateAction.Response> {
|
||||
@Override
|
||||
protected Writeable.Reader<GetComponentTemplateAction.Response> instanceReader() {
|
||||
return GetComponentTemplateAction.Response::new;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected GetComponentTemplateAction.Response createTestInstance() {
|
||||
if (randomBoolean()) {
|
||||
return new GetComponentTemplateAction.Response(Collections.emptyMap());
|
||||
}
|
||||
Map<String, ComponentTemplate> templates = new HashMap<>();
|
||||
for (int i = 0; i < randomIntBetween(1, 4); i++) {
|
||||
templates.put(randomAlphaOfLength(4), ComponentTemplateTests.randomInstance());
|
||||
}
|
||||
return new GetComponentTemplateAction.Response(templates);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected GetComponentTemplateAction.Response mutateInstance(GetComponentTemplateAction.Response instance) throws IOException {
|
||||
return randomValueOtherThan(instance, this::createTestInstance);
|
||||
}
|
||||
}
|
@ -76,7 +76,7 @@ public class ComponentTemplateTests extends AbstractDiffableSerializationTestCas
|
||||
if (randomBoolean()) {
|
||||
aliases = randomAliases();
|
||||
}
|
||||
ComponentTemplate.Template template = new ComponentTemplate.Template(settings, mappings, aliases);
|
||||
Template template = new Template(settings, mappings, aliases);
|
||||
|
||||
Map<String, Object> meta = null;
|
||||
if (randomBoolean()) {
|
||||
@ -130,21 +130,21 @@ public class ComponentTemplateTests extends AbstractDiffableSerializationTestCas
|
||||
case 0:
|
||||
switch (randomIntBetween(0, 2)) {
|
||||
case 0:
|
||||
ComponentTemplate.Template ot = orig.template();
|
||||
Template ot = orig.template();
|
||||
return new ComponentTemplate(
|
||||
new ComponentTemplate.Template(randomValueOtherThan(ot.settings(), ComponentTemplateTests::randomSettings),
|
||||
new Template(randomValueOtherThan(ot.settings(), ComponentTemplateTests::randomSettings),
|
||||
ot.mappings(), ot.aliases()),
|
||||
orig.version(), orig.metadata());
|
||||
case 1:
|
||||
ComponentTemplate.Template ot2 = orig.template();
|
||||
Template ot2 = orig.template();
|
||||
return new ComponentTemplate(
|
||||
new ComponentTemplate.Template(ot2.settings(),
|
||||
new Template(ot2.settings(),
|
||||
randomValueOtherThan(ot2.mappings(), ComponentTemplateTests::randomMappings), ot2.aliases()),
|
||||
orig.version(), orig.metadata());
|
||||
case 2:
|
||||
ComponentTemplate.Template ot3 = orig.template();
|
||||
Template ot3 = orig.template();
|
||||
return new ComponentTemplate(
|
||||
new ComponentTemplate.Template(ot3.settings(), ot3.mappings(),
|
||||
new Template(ot3.settings(), ot3.mappings(),
|
||||
randomValueOtherThan(ot3.aliases(), ComponentTemplateTests::randomAliases)),
|
||||
orig.version(), orig.metadata());
|
||||
default:
|
||||
|
@ -17,15 +17,10 @@
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package org.elasticsearch.action.admin.indices.template.put;
|
||||
package org.elasticsearch.cluster.metadata;
|
||||
|
||||
import org.elasticsearch.action.admin.indices.alias.Alias;
|
||||
import org.elasticsearch.cluster.ClusterState;
|
||||
import org.elasticsearch.cluster.metadata.AliasValidator;
|
||||
import org.elasticsearch.cluster.metadata.IndexMetaData;
|
||||
import org.elasticsearch.cluster.metadata.IndexTemplateMetaData;
|
||||
import org.elasticsearch.cluster.metadata.MetaDataCreateIndexService;
|
||||
import org.elasticsearch.cluster.metadata.MetaDataIndexTemplateService;
|
||||
import org.elasticsearch.cluster.metadata.MetaDataIndexTemplateService.PutRequest;
|
||||
import org.elasticsearch.cluster.service.ClusterService;
|
||||
import org.elasticsearch.common.Strings;
|
||||
@ -202,6 +197,23 @@ public class MetaDataIndexTemplateServiceTests extends ESSingleNodeTestCase {
|
||||
assertThat(errors.get(0).getMessage(), containsString("global templates may not specify the setting index.hidden"));
|
||||
}
|
||||
|
||||
public void testAddComponentTemplate() {
|
||||
ClusterState state = ClusterState.EMPTY_STATE;
|
||||
ComponentTemplate template = ComponentTemplateTests.randomInstance();
|
||||
state = MetaDataIndexTemplateService.addComponentTemplate(state, false, "foo", template);
|
||||
|
||||
assertNotNull(state.metaData().componentTemplates().get("foo"));
|
||||
assertThat(state.metaData().componentTemplates().get("foo"), equalTo(template));
|
||||
|
||||
final ClusterState throwState = ClusterState.builder(state).build();
|
||||
IllegalArgumentException e = expectThrows(IllegalArgumentException.class,
|
||||
() -> MetaDataIndexTemplateService.addComponentTemplate(throwState, true, "foo", template));
|
||||
assertThat(e.getMessage(), containsString("component template [foo] already exists"));
|
||||
|
||||
state = MetaDataIndexTemplateService.addComponentTemplate(state, randomBoolean(), "bar", template);
|
||||
assertNotNull(state.metaData().componentTemplates().get("bar"));
|
||||
}
|
||||
|
||||
private static List<Throwable> putTemplate(NamedXContentRegistry xContentRegistry, PutRequest request) {
|
||||
MetaDataCreateIndexService createIndexService = new MetaDataCreateIndexService(
|
||||
Settings.EMPTY,
|
@ -124,7 +124,7 @@ public class ToAndFromJsonMetaDataTests extends ESTestCase {
|
||||
.putAlias(newAliasMetaDataBuilder("alias-bar2").filter("{\"term\":{\"user\":\"kimchy\"}}"))
|
||||
.putAlias(newAliasMetaDataBuilder("alias-bar3").routing("routing-bar")))
|
||||
.put("component_template", new ComponentTemplate(
|
||||
new ComponentTemplate.Template(Settings.builder().put("setting", "value").build(),
|
||||
new Template(Settings.builder().put("setting", "value").build(),
|
||||
new CompressedXContent("{\"baz\":\"eggplant\"}"),
|
||||
Collections.singletonMap("alias", AliasMetaData.builder("alias").build())),
|
||||
5L, Collections.singletonMap("my_meta", Collections.singletonMap("foo", "bar"))))
|
||||
@ -320,7 +320,7 @@ public class ToAndFromJsonMetaDataTests extends ESTestCase {
|
||||
assertThat(parsedMetaData.componentTemplates().get("component_template").metadata(),
|
||||
equalTo(Collections.singletonMap("my_meta", Collections.singletonMap("foo", "bar"))));
|
||||
assertThat(parsedMetaData.componentTemplates().get("component_template").template(),
|
||||
equalTo(new ComponentTemplate.Template(Settings.builder().put("setting", "value").build(),
|
||||
equalTo(new Template(Settings.builder().put("setting", "value").build(),
|
||||
new CompressedXContent("{\"baz\":\"eggplant\"}"),
|
||||
Collections.singletonMap("alias", AliasMetaData.builder("alias").build()))));
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user