diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/action/TransportActionModule.java b/modules/elasticsearch/src/main/java/org/elasticsearch/action/TransportActionModule.java index d100cf1f522..330fb094c6a 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/action/TransportActionModule.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/action/TransportActionModule.java @@ -32,12 +32,14 @@ import org.elasticsearch.action.admin.cluster.ping.single.TransportSinglePingAct import org.elasticsearch.action.admin.cluster.state.TransportClusterStateAction; import org.elasticsearch.action.admin.indices.alias.TransportIndicesAliasesAction; import org.elasticsearch.action.admin.indices.cache.clear.TransportClearIndicesCacheAction; +import org.elasticsearch.action.admin.indices.close.TransportCloseIndexAction; import org.elasticsearch.action.admin.indices.create.TransportCreateIndexAction; import org.elasticsearch.action.admin.indices.delete.TransportDeleteIndexAction; import org.elasticsearch.action.admin.indices.flush.TransportFlushAction; import org.elasticsearch.action.admin.indices.gateway.snapshot.TransportGatewaySnapshotAction; import org.elasticsearch.action.admin.indices.mapping.delete.TransportDeleteMappingAction; import org.elasticsearch.action.admin.indices.mapping.put.TransportPutMappingAction; +import org.elasticsearch.action.admin.indices.open.TransportOpenIndexAction; import org.elasticsearch.action.admin.indices.optimize.TransportOptimizeAction; import org.elasticsearch.action.admin.indices.refresh.TransportRefreshAction; import org.elasticsearch.action.admin.indices.settings.TransportUpdateSettingsAction; @@ -80,6 +82,8 @@ public class TransportActionModule extends AbstractModule { bind(TransportIndicesStatusAction.class).asEagerSingleton(); bind(TransportCreateIndexAction.class).asEagerSingleton(); bind(TransportDeleteIndexAction.class).asEagerSingleton(); + bind(TransportOpenIndexAction.class).asEagerSingleton(); + bind(TransportCloseIndexAction.class).asEagerSingleton(); bind(TransportPutMappingAction.class).asEagerSingleton(); bind(TransportDeleteMappingAction.class).asEagerSingleton(); bind(TransportIndicesAliasesAction.class).asEagerSingleton(); diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/action/TransportActions.java b/modules/elasticsearch/src/main/java/org/elasticsearch/action/TransportActions.java index 56117ae93bb..4000be63f61 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/action/TransportActions.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/action/TransportActions.java @@ -49,6 +49,8 @@ public class TransportActions { public static class Indices { public static final String CREATE = "indices/createIndex"; public static final String DELETE = "indices/deleteIndex"; + public static final String OPEN = "indices/openIndex"; + public static final String CLOSE = "indices/closeIndex"; public static final String FLUSH = "indices/flush"; public static final String REFRESH = "indices/refresh"; public static final String OPTIMIZE = "indices/optimize"; diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/action/admin/indices/close/CloseIndexRequest.java b/modules/elasticsearch/src/main/java/org/elasticsearch/action/admin/indices/close/CloseIndexRequest.java new file mode 100644 index 00000000000..068074735fd --- /dev/null +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/action/admin/indices/close/CloseIndexRequest.java @@ -0,0 +1,105 @@ +/* + * Licensed to Elastic Search and Shay Banon under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. Elastic Search 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.close; + +import org.elasticsearch.action.ActionRequestValidationException; +import org.elasticsearch.action.support.master.MasterNodeOperationRequest; +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.common.unit.TimeValue; + +import java.io.IOException; + +import static org.elasticsearch.action.Actions.*; +import static org.elasticsearch.common.unit.TimeValue.*; + +/** + * A request to close an index. + * + * @author kimchy (shay.banon) + */ +public class CloseIndexRequest extends MasterNodeOperationRequest { + + private String index; + + private TimeValue timeout = timeValueSeconds(10); + + CloseIndexRequest() { + } + + /** + * Constructs a new delete index request for the specified index. + */ + public CloseIndexRequest(String index) { + this.index = index; + } + + @Override public ActionRequestValidationException validate() { + ActionRequestValidationException validationException = null; + if (index == null) { + validationException = addValidationError("index is missing", validationException); + } + return validationException; + } + + /** + * The index to delete. + */ + String index() { + return index; + } + + /** + * Timeout to wait for the index deletion to be acknowledged by current cluster nodes. Defaults + * to 10s. + */ + TimeValue timeout() { + return timeout; + } + + /** + * Timeout to wait for the index deletion to be acknowledged by current cluster nodes. Defaults + * to 10s. + */ + public CloseIndexRequest timeout(TimeValue timeout) { + this.timeout = timeout; + return this; + } + + /** + * Timeout to wait for the index deletion to be acknowledged by current cluster nodes. Defaults + * to 10s. + */ + public CloseIndexRequest timeout(String timeout) { + return timeout(TimeValue.parseTimeValue(timeout, null)); + } + + @Override public void readFrom(StreamInput in) throws IOException { + super.readFrom(in); + index = in.readUTF(); + timeout = readTimeValue(in); + } + + @Override public void writeTo(StreamOutput out) throws IOException { + super.writeTo(out); + out.writeUTF(index); + timeout.writeTo(out); + } +} \ No newline at end of file diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/action/admin/indices/close/CloseIndexResponse.java b/modules/elasticsearch/src/main/java/org/elasticsearch/action/admin/indices/close/CloseIndexResponse.java new file mode 100644 index 00000000000..ce1524b194c --- /dev/null +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/action/admin/indices/close/CloseIndexResponse.java @@ -0,0 +1,60 @@ +/* + * Licensed to Elastic Search and Shay Banon under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. Elastic Search 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.close; + +import org.elasticsearch.action.ActionResponse; +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.common.io.stream.Streamable; + +import java.io.IOException; + +/** + * A response for a close index action. + * + * @author kimchy (shay.banon) + */ +public class CloseIndexResponse implements ActionResponse, Streamable { + + private boolean acknowledged; + + CloseIndexResponse() { + } + + CloseIndexResponse(boolean acknowledged) { + this.acknowledged = acknowledged; + } + + public boolean acknowledged() { + return acknowledged; + } + + public boolean getAcknowledged() { + return acknowledged(); + } + + @Override public void readFrom(StreamInput in) throws IOException { + acknowledged = in.readBoolean(); + } + + @Override public void writeTo(StreamOutput out) throws IOException { + out.writeBoolean(acknowledged); + } +} diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/action/admin/indices/close/TransportCloseIndexAction.java b/modules/elasticsearch/src/main/java/org/elasticsearch/action/admin/indices/close/TransportCloseIndexAction.java new file mode 100644 index 00000000000..b6a54e55a46 --- /dev/null +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/action/admin/indices/close/TransportCloseIndexAction.java @@ -0,0 +1,100 @@ +/* + * Licensed to Elastic Search and Shay Banon under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. Elastic Search 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.close; + +import org.elasticsearch.ElasticSearchException; +import org.elasticsearch.action.TransportActions; +import org.elasticsearch.action.support.master.TransportMasterNodeOperationAction; +import org.elasticsearch.cluster.ClusterService; +import org.elasticsearch.cluster.ClusterState; +import org.elasticsearch.cluster.block.ClusterBlockLevel; +import org.elasticsearch.cluster.metadata.MetaDataStateIndexService; +import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.threadpool.ThreadPool; +import org.elasticsearch.transport.TransportService; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicReference; + +/** + * Delete index action. + * + * @author kimchy (shay.banon) + */ +public class TransportCloseIndexAction extends TransportMasterNodeOperationAction { + + private final MetaDataStateIndexService stateIndexService; + + @Inject public TransportCloseIndexAction(Settings settings, TransportService transportService, ClusterService clusterService, + ThreadPool threadPool, MetaDataStateIndexService stateIndexService) { + super(settings, transportService, clusterService, threadPool); + this.stateIndexService = stateIndexService; + } + + @Override protected String transportAction() { + return TransportActions.Admin.Indices.CLOSE; + } + + @Override protected CloseIndexRequest newRequest() { + return new CloseIndexRequest(); + } + + @Override protected CloseIndexResponse newResponse() { + return new CloseIndexResponse(); + } + + @Override protected void checkBlock(CloseIndexRequest request, ClusterState state) { + state.blocks().indexBlockedRaiseException(ClusterBlockLevel.METADATA, request.index()); + } + + @Override protected CloseIndexResponse masterOperation(CloseIndexRequest request, ClusterState state) throws ElasticSearchException { + final AtomicReference responseRef = new AtomicReference(); + final AtomicReference failureRef = new AtomicReference(); + final CountDownLatch latch = new CountDownLatch(1); + stateIndexService.closeIndex(new MetaDataStateIndexService.Request(request.index()).timeout(request.timeout()), new MetaDataStateIndexService.Listener() { + @Override public void onResponse(MetaDataStateIndexService.Response response) { + responseRef.set(new CloseIndexResponse(response.acknowledged())); + latch.countDown(); + } + + @Override public void onFailure(Throwable t) { + failureRef.set(t); + latch.countDown(); + } + }); + + try { + latch.await(); + } catch (InterruptedException e) { + failureRef.set(e); + } + + if (failureRef.get() != null) { + if (failureRef.get() instanceof ElasticSearchException) { + throw (ElasticSearchException) failureRef.get(); + } else { + throw new ElasticSearchException(failureRef.get().getMessage(), failureRef.get()); + } + } + + return responseRef.get(); + } +} diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/action/admin/indices/open/OpenIndexRequest.java b/modules/elasticsearch/src/main/java/org/elasticsearch/action/admin/indices/open/OpenIndexRequest.java new file mode 100644 index 00000000000..2052fcb7e93 --- /dev/null +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/action/admin/indices/open/OpenIndexRequest.java @@ -0,0 +1,105 @@ +/* + * Licensed to Elastic Search and Shay Banon under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. Elastic Search 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.open; + +import org.elasticsearch.action.ActionRequestValidationException; +import org.elasticsearch.action.support.master.MasterNodeOperationRequest; +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.common.unit.TimeValue; + +import java.io.IOException; + +import static org.elasticsearch.action.Actions.*; +import static org.elasticsearch.common.unit.TimeValue.*; + +/** + * A request to open an index. + * + * @author kimchy (shay.banon) + */ +public class OpenIndexRequest extends MasterNodeOperationRequest { + + private String index; + + private TimeValue timeout = timeValueSeconds(10); + + OpenIndexRequest() { + } + + /** + * Constructs a new delete index request for the specified index. + */ + public OpenIndexRequest(String index) { + this.index = index; + } + + @Override public ActionRequestValidationException validate() { + ActionRequestValidationException validationException = null; + if (index == null) { + validationException = addValidationError("index is missing", validationException); + } + return validationException; + } + + /** + * The index to delete. + */ + String index() { + return index; + } + + /** + * Timeout to wait for the index deletion to be acknowledged by current cluster nodes. Defaults + * to 10s. + */ + TimeValue timeout() { + return timeout; + } + + /** + * Timeout to wait for the index deletion to be acknowledged by current cluster nodes. Defaults + * to 10s. + */ + public OpenIndexRequest timeout(TimeValue timeout) { + this.timeout = timeout; + return this; + } + + /** + * Timeout to wait for the index deletion to be acknowledged by current cluster nodes. Defaults + * to 10s. + */ + public OpenIndexRequest timeout(String timeout) { + return timeout(TimeValue.parseTimeValue(timeout, null)); + } + + @Override public void readFrom(StreamInput in) throws IOException { + super.readFrom(in); + index = in.readUTF(); + timeout = readTimeValue(in); + } + + @Override public void writeTo(StreamOutput out) throws IOException { + super.writeTo(out); + out.writeUTF(index); + timeout.writeTo(out); + } +} \ No newline at end of file diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/action/admin/indices/open/OpenIndexResponse.java b/modules/elasticsearch/src/main/java/org/elasticsearch/action/admin/indices/open/OpenIndexResponse.java new file mode 100644 index 00000000000..4c928bdd6a3 --- /dev/null +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/action/admin/indices/open/OpenIndexResponse.java @@ -0,0 +1,60 @@ +/* + * Licensed to Elastic Search and Shay Banon under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. Elastic Search 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.open; + +import org.elasticsearch.action.ActionResponse; +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.common.io.stream.Streamable; + +import java.io.IOException; + +/** + * A response for a open index action. + * + * @author kimchy (shay.banon) + */ +public class OpenIndexResponse implements ActionResponse, Streamable { + + private boolean acknowledged; + + OpenIndexResponse() { + } + + OpenIndexResponse(boolean acknowledged) { + this.acknowledged = acknowledged; + } + + public boolean acknowledged() { + return acknowledged; + } + + public boolean getAcknowledged() { + return acknowledged(); + } + + @Override public void readFrom(StreamInput in) throws IOException { + acknowledged = in.readBoolean(); + } + + @Override public void writeTo(StreamOutput out) throws IOException { + out.writeBoolean(acknowledged); + } +} diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/action/admin/indices/open/TransportOpenIndexAction.java b/modules/elasticsearch/src/main/java/org/elasticsearch/action/admin/indices/open/TransportOpenIndexAction.java new file mode 100644 index 00000000000..27feb45a2f0 --- /dev/null +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/action/admin/indices/open/TransportOpenIndexAction.java @@ -0,0 +1,100 @@ +/* + * Licensed to Elastic Search and Shay Banon under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. Elastic Search 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.open; + +import org.elasticsearch.ElasticSearchException; +import org.elasticsearch.action.TransportActions; +import org.elasticsearch.action.support.master.TransportMasterNodeOperationAction; +import org.elasticsearch.cluster.ClusterService; +import org.elasticsearch.cluster.ClusterState; +import org.elasticsearch.cluster.block.ClusterBlockLevel; +import org.elasticsearch.cluster.metadata.MetaDataStateIndexService; +import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.threadpool.ThreadPool; +import org.elasticsearch.transport.TransportService; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicReference; + +/** + * Delete index action. + * + * @author kimchy (shay.banon) + */ +public class TransportOpenIndexAction extends TransportMasterNodeOperationAction { + + private final MetaDataStateIndexService stateIndexService; + + @Inject public TransportOpenIndexAction(Settings settings, TransportService transportService, ClusterService clusterService, + ThreadPool threadPool, MetaDataStateIndexService stateIndexService) { + super(settings, transportService, clusterService, threadPool); + this.stateIndexService = stateIndexService; + } + + @Override protected String transportAction() { + return TransportActions.Admin.Indices.OPEN; + } + + @Override protected OpenIndexRequest newRequest() { + return new OpenIndexRequest(); + } + + @Override protected OpenIndexResponse newResponse() { + return new OpenIndexResponse(); + } + + @Override protected void checkBlock(OpenIndexRequest request, ClusterState state) { + state.blocks().indexBlockedRaiseException(ClusterBlockLevel.METADATA, request.index()); + } + + @Override protected OpenIndexResponse masterOperation(OpenIndexRequest request, ClusterState state) throws ElasticSearchException { + final AtomicReference responseRef = new AtomicReference(); + final AtomicReference failureRef = new AtomicReference(); + final CountDownLatch latch = new CountDownLatch(1); + stateIndexService.openIndex(new MetaDataStateIndexService.Request(request.index()).timeout(request.timeout()), new MetaDataStateIndexService.Listener() { + @Override public void onResponse(MetaDataStateIndexService.Response response) { + responseRef.set(new OpenIndexResponse(response.acknowledged())); + latch.countDown(); + } + + @Override public void onFailure(Throwable t) { + failureRef.set(t); + latch.countDown(); + } + }); + + try { + latch.await(); + } catch (InterruptedException e) { + failureRef.set(e); + } + + if (failureRef.get() != null) { + if (failureRef.get() instanceof ElasticSearchException) { + throw (ElasticSearchException) failureRef.get(); + } else { + throw new ElasticSearchException(failureRef.get().getMessage(), failureRef.get()); + } + } + + return responseRef.get(); + } +} diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/client/IndicesAdminClient.java b/modules/elasticsearch/src/main/java/org/elasticsearch/client/IndicesAdminClient.java index 0c526ce4d93..fe5a6376ed3 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/client/IndicesAdminClient.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/client/IndicesAdminClient.java @@ -25,6 +25,8 @@ import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest; import org.elasticsearch.action.admin.indices.alias.IndicesAliasesResponse; import org.elasticsearch.action.admin.indices.cache.clear.ClearIndicesCacheRequest; import org.elasticsearch.action.admin.indices.cache.clear.ClearIndicesCacheResponse; +import org.elasticsearch.action.admin.indices.close.CloseIndexRequest; +import org.elasticsearch.action.admin.indices.close.CloseIndexResponse; import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; import org.elasticsearch.action.admin.indices.create.CreateIndexResponse; import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest; @@ -37,6 +39,8 @@ import org.elasticsearch.action.admin.indices.mapping.delete.DeleteMappingReques import org.elasticsearch.action.admin.indices.mapping.delete.DeleteMappingResponse; import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest; import org.elasticsearch.action.admin.indices.mapping.put.PutMappingResponse; +import org.elasticsearch.action.admin.indices.open.OpenIndexRequest; +import org.elasticsearch.action.admin.indices.open.OpenIndexResponse; import org.elasticsearch.action.admin.indices.optimize.OptimizeRequest; import org.elasticsearch.action.admin.indices.optimize.OptimizeResponse; import org.elasticsearch.action.admin.indices.refresh.RefreshRequest; @@ -47,12 +51,14 @@ import org.elasticsearch.action.admin.indices.status.IndicesStatusRequest; import org.elasticsearch.action.admin.indices.status.IndicesStatusResponse; import org.elasticsearch.client.action.admin.indices.alias.IndicesAliasesRequestBuilder; import org.elasticsearch.client.action.admin.indices.cache.clear.ClearIndicesCacheRequestBuilder; +import org.elasticsearch.client.action.admin.indices.close.CloseIndexRequestBuilder; import org.elasticsearch.client.action.admin.indices.create.CreateIndexRequestBuilder; import org.elasticsearch.client.action.admin.indices.delete.DeleteIndexRequestBuilder; import org.elasticsearch.client.action.admin.indices.flush.FlushRequestBuilder; import org.elasticsearch.client.action.admin.indices.gateway.snapshot.GatewaySnapshotRequestBuilder; import org.elasticsearch.client.action.admin.indices.mapping.delete.DeleteMappingRequestBuilder; import org.elasticsearch.client.action.admin.indices.mapping.put.PutMappingRequestBuilder; +import org.elasticsearch.client.action.admin.indices.open.OpenIndexRequestBuilder; import org.elasticsearch.client.action.admin.indices.optimize.OptimizeRequestBuilder; import org.elasticsearch.client.action.admin.indices.refresh.RefreshRequestBuilder; import org.elasticsearch.client.action.admin.indices.settings.UpdateSettingsRequestBuilder; @@ -139,6 +145,56 @@ public interface IndicesAdminClient { */ DeleteIndexRequestBuilder prepareDelete(String index); + /** + * Closes an index based on the index name. + * + * @param request The close index request + * @return The result future + * @see org.elasticsearch.client.Requests#closeIndexRequest(String) + */ + ActionFuture close(CloseIndexRequest request); + + /** + * Closes an index based on the index name. + * + * @param request The close index request + * @param listener A listener to be notified with a result + * @see org.elasticsearch.client.Requests#closeIndexRequest(String) + */ + void close(CloseIndexRequest request, ActionListener listener); + + /** + * Closes an index based on the index name. + * + * @param index The index name to close + */ + CloseIndexRequestBuilder prepareClose(String index); + + /** + * OPen an index based on the index name. + * + * @param request The close index request + * @return The result future + * @see org.elasticsearch.client.Requests#openIndexRequest(String) + */ + ActionFuture open(OpenIndexRequest request); + + /** + * Open an index based on the index name. + * + * @param request The close index request + * @param listener A listener to be notified with a result + * @see org.elasticsearch.client.Requests#openIndexRequest(String) + */ + void open(OpenIndexRequest request, ActionListener listener); + + /** + * Opens an index based on the index name. + * + * @param index The index name to close + */ + OpenIndexRequestBuilder prepareOpen(String index); + /** * Explicitly refresh one or more indices (making the content indexed since the last refresh searchable). * diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/client/Requests.java b/modules/elasticsearch/src/main/java/org/elasticsearch/client/Requests.java index 578fde0a8e7..159e7540a87 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/client/Requests.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/client/Requests.java @@ -30,12 +30,14 @@ import org.elasticsearch.action.admin.cluster.ping.single.SinglePingRequest; import org.elasticsearch.action.admin.cluster.state.ClusterStateRequest; import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest; import org.elasticsearch.action.admin.indices.cache.clear.ClearIndicesCacheRequest; +import org.elasticsearch.action.admin.indices.close.CloseIndexRequest; import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest; import org.elasticsearch.action.admin.indices.flush.FlushRequest; import org.elasticsearch.action.admin.indices.gateway.snapshot.GatewaySnapshotRequest; import org.elasticsearch.action.admin.indices.mapping.delete.DeleteMappingRequest; import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest; +import org.elasticsearch.action.admin.indices.open.OpenIndexRequest; import org.elasticsearch.action.admin.indices.optimize.OptimizeRequest; import org.elasticsearch.action.admin.indices.refresh.RefreshRequest; import org.elasticsearch.action.admin.indices.settings.UpdateSettingsRequest; @@ -207,6 +209,28 @@ public class Requests { return new DeleteIndexRequest(index); } + /** + * Creates a close index request. + * + * @param index The index to close + * @return The delete index request + * @see org.elasticsearch.client.IndicesAdminClient#close(org.elasticsearch.action.admin.indices.close.CloseIndexRequest) + */ + public static CloseIndexRequest closeIndexRequest(String index) { + return new CloseIndexRequest(index); + } + + /** + * Creates an open index request. + * + * @param index The index to open + * @return The delete index request + * @see org.elasticsearch.client.IndicesAdminClient#open(org.elasticsearch.action.admin.indices.open.OpenIndexRequest) + */ + public static OpenIndexRequest openIndexRequest(String index) { + return new OpenIndexRequest(index); + } + /** * Create a create mapping request against one or more indices. * @@ -223,7 +247,7 @@ public class Requests { * * @param indices The indices the mapping will be deleted from. Use null or _all to execute against all indices * @return The create mapping request - * @see org.elasticsearch.client.IndicesAdminClient#deleteMapping(org.elasticsearch.action.admin.indices.mapping.put.DeleteMappingRequest) + * @see org.elasticsearch.client.IndicesAdminClient#deleteMapping(org.elasticsearch.action.admin.indices.mapping.delete.DeleteMappingRequest) */ public static DeleteMappingRequest deleteMappingRequest(String... indices) { return new DeleteMappingRequest(indices); diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/client/action/admin/indices/close/CloseIndexRequestBuilder.java b/modules/elasticsearch/src/main/java/org/elasticsearch/client/action/admin/indices/close/CloseIndexRequestBuilder.java new file mode 100644 index 00000000000..d8517053380 --- /dev/null +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/client/action/admin/indices/close/CloseIndexRequestBuilder.java @@ -0,0 +1,75 @@ +/* + * Licensed to Elastic Search and Shay Banon under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. Elastic Search 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.client.action.admin.indices.close; + +import org.elasticsearch.action.ActionListener; +import org.elasticsearch.action.admin.indices.close.CloseIndexRequest; +import org.elasticsearch.action.admin.indices.close.CloseIndexResponse; +import org.elasticsearch.client.IndicesAdminClient; +import org.elasticsearch.client.action.admin.indices.support.BaseIndicesRequestBuilder; +import org.elasticsearch.common.unit.TimeValue; + +/** + * @author kimchy (shay.banon) + */ +public class CloseIndexRequestBuilder extends BaseIndicesRequestBuilder { + + public CloseIndexRequestBuilder(IndicesAdminClient indicesClient, String index) { + super(indicesClient, new CloseIndexRequest(index)); + } + + /** + * Timeout to wait for the operation to be acknowledged by current cluster nodes. Defaults + * to 10s. + */ + public CloseIndexRequestBuilder setTimeout(TimeValue timeout) { + request.timeout(timeout); + return this; + } + + /** + * Timeout to wait for the index deletion to be acknowledged by current cluster nodes. Defaults + * to 10s. + */ + public CloseIndexRequestBuilder setTimeout(String timeout) { + request.timeout(timeout); + return this; + } + + /** + * Sets the master node timeout in case the master has not yet been discovered. + */ + public CloseIndexRequestBuilder setMasterNodeTimeout(TimeValue timeout) { + request.masterNodeTimeout(timeout); + return this; + } + + /** + * Sets the master node timeout in case the master has not yet been discovered. + */ + public CloseIndexRequestBuilder setMasterNodeTimeout(String timeout) { + request.masterNodeTimeout(timeout); + return this; + } + + @Override protected void doExecute(ActionListener listener) { + client.close(request, listener); + } +} diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/client/action/admin/indices/open/OpenIndexRequestBuilder.java b/modules/elasticsearch/src/main/java/org/elasticsearch/client/action/admin/indices/open/OpenIndexRequestBuilder.java new file mode 100644 index 00000000000..aeea8fbfe87 --- /dev/null +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/client/action/admin/indices/open/OpenIndexRequestBuilder.java @@ -0,0 +1,75 @@ +/* + * Licensed to Elastic Search and Shay Banon under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. Elastic Search 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.client.action.admin.indices.open; + +import org.elasticsearch.action.ActionListener; +import org.elasticsearch.action.admin.indices.open.OpenIndexRequest; +import org.elasticsearch.action.admin.indices.open.OpenIndexResponse; +import org.elasticsearch.client.IndicesAdminClient; +import org.elasticsearch.client.action.admin.indices.support.BaseIndicesRequestBuilder; +import org.elasticsearch.common.unit.TimeValue; + +/** + * @author kimchy (shay.banon) + */ +public class OpenIndexRequestBuilder extends BaseIndicesRequestBuilder { + + public OpenIndexRequestBuilder(IndicesAdminClient indicesClient, String index) { + super(indicesClient, new OpenIndexRequest(index)); + } + + /** + * Timeout to wait for the operation to be acknowledged by current cluster nodes. Defaults + * to 10s. + */ + public OpenIndexRequestBuilder setTimeout(TimeValue timeout) { + request.timeout(timeout); + return this; + } + + /** + * Timeout to wait for the index deletion to be acknowledged by current cluster nodes. Defaults + * to 10s. + */ + public OpenIndexRequestBuilder setTimeout(String timeout) { + request.timeout(timeout); + return this; + } + + /** + * Sets the master node timeout in case the master has not yet been discovered. + */ + public OpenIndexRequestBuilder setMasterNodeTimeout(TimeValue timeout) { + request.masterNodeTimeout(timeout); + return this; + } + + /** + * Sets the master node timeout in case the master has not yet been discovered. + */ + public OpenIndexRequestBuilder setMasterNodeTimeout(String timeout) { + request.masterNodeTimeout(timeout); + return this; + } + + @Override protected void doExecute(ActionListener listener) { + client.open(request, listener); + } +} diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/client/node/NodeIndicesAdminClient.java b/modules/elasticsearch/src/main/java/org/elasticsearch/client/node/NodeIndicesAdminClient.java index 0ba16040586..7b8d5f47573 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/client/node/NodeIndicesAdminClient.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/client/node/NodeIndicesAdminClient.java @@ -27,6 +27,9 @@ import org.elasticsearch.action.admin.indices.alias.TransportIndicesAliasesActio import org.elasticsearch.action.admin.indices.cache.clear.ClearIndicesCacheRequest; import org.elasticsearch.action.admin.indices.cache.clear.ClearIndicesCacheResponse; import org.elasticsearch.action.admin.indices.cache.clear.TransportClearIndicesCacheAction; +import org.elasticsearch.action.admin.indices.close.CloseIndexRequest; +import org.elasticsearch.action.admin.indices.close.CloseIndexResponse; +import org.elasticsearch.action.admin.indices.close.TransportCloseIndexAction; import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; import org.elasticsearch.action.admin.indices.create.CreateIndexResponse; import org.elasticsearch.action.admin.indices.create.TransportCreateIndexAction; @@ -45,6 +48,9 @@ import org.elasticsearch.action.admin.indices.mapping.delete.TransportDeleteMapp import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest; import org.elasticsearch.action.admin.indices.mapping.put.PutMappingResponse; import org.elasticsearch.action.admin.indices.mapping.put.TransportPutMappingAction; +import org.elasticsearch.action.admin.indices.open.OpenIndexRequest; +import org.elasticsearch.action.admin.indices.open.OpenIndexResponse; +import org.elasticsearch.action.admin.indices.open.TransportOpenIndexAction; import org.elasticsearch.action.admin.indices.optimize.OptimizeRequest; import org.elasticsearch.action.admin.indices.optimize.OptimizeResponse; import org.elasticsearch.action.admin.indices.optimize.TransportOptimizeAction; @@ -76,6 +82,10 @@ public class NodeIndicesAdminClient extends AbstractIndicesAdminClient implement private final TransportDeleteIndexAction deleteIndexAction; + private final TransportCloseIndexAction closeIndexAction; + + private final TransportOpenIndexAction openIndexAction; + private final TransportRefreshAction refreshAction; private final TransportFlushAction flushAction; @@ -96,6 +106,7 @@ public class NodeIndicesAdminClient extends AbstractIndicesAdminClient implement @Inject public NodeIndicesAdminClient(Settings settings, ThreadPool threadPool, TransportIndicesStatusAction indicesStatusAction, TransportCreateIndexAction createIndexAction, TransportDeleteIndexAction deleteIndexAction, + TransportCloseIndexAction closeIndexAction, TransportOpenIndexAction openIndexAction, TransportRefreshAction refreshAction, TransportFlushAction flushAction, TransportOptimizeAction optimizeAction, TransportPutMappingAction putMappingAction, TransportDeleteMappingAction deleteMappingAction, TransportGatewaySnapshotAction gatewaySnapshotAction, TransportIndicesAliasesAction indicesAliasesAction, TransportClearIndicesCacheAction clearIndicesCacheAction, @@ -104,6 +115,8 @@ public class NodeIndicesAdminClient extends AbstractIndicesAdminClient implement this.indicesStatusAction = indicesStatusAction; this.createIndexAction = createIndexAction; this.deleteIndexAction = deleteIndexAction; + this.closeIndexAction = closeIndexAction; + this.openIndexAction = openIndexAction; this.refreshAction = refreshAction; this.flushAction = flushAction; this.optimizeAction = optimizeAction; @@ -143,6 +156,22 @@ public class NodeIndicesAdminClient extends AbstractIndicesAdminClient implement deleteIndexAction.execute(request, listener); } + @Override public ActionFuture close(CloseIndexRequest request) { + return closeIndexAction.execute(request); + } + + @Override public void close(CloseIndexRequest request, ActionListener listener) { + closeIndexAction.execute(request, listener); + } + + @Override public ActionFuture open(OpenIndexRequest request) { + return openIndexAction.execute(request); + } + + @Override public void open(OpenIndexRequest request, ActionListener listener) { + openIndexAction.execute(request, listener); + } + @Override public ActionFuture refresh(RefreshRequest request) { return refreshAction.execute(request); } diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/client/support/AbstractIndicesAdminClient.java b/modules/elasticsearch/src/main/java/org/elasticsearch/client/support/AbstractIndicesAdminClient.java index e028ae0c335..0f2a85e4f22 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/client/support/AbstractIndicesAdminClient.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/client/support/AbstractIndicesAdminClient.java @@ -21,12 +21,14 @@ package org.elasticsearch.client.support; import org.elasticsearch.client.action.admin.indices.alias.IndicesAliasesRequestBuilder; import org.elasticsearch.client.action.admin.indices.cache.clear.ClearIndicesCacheRequestBuilder; +import org.elasticsearch.client.action.admin.indices.close.CloseIndexRequestBuilder; import org.elasticsearch.client.action.admin.indices.create.CreateIndexRequestBuilder; import org.elasticsearch.client.action.admin.indices.delete.DeleteIndexRequestBuilder; import org.elasticsearch.client.action.admin.indices.flush.FlushRequestBuilder; import org.elasticsearch.client.action.admin.indices.gateway.snapshot.GatewaySnapshotRequestBuilder; import org.elasticsearch.client.action.admin.indices.mapping.delete.DeleteMappingRequestBuilder; import org.elasticsearch.client.action.admin.indices.mapping.put.PutMappingRequestBuilder; +import org.elasticsearch.client.action.admin.indices.open.OpenIndexRequestBuilder; import org.elasticsearch.client.action.admin.indices.optimize.OptimizeRequestBuilder; import org.elasticsearch.client.action.admin.indices.refresh.RefreshRequestBuilder; import org.elasticsearch.client.action.admin.indices.settings.UpdateSettingsRequestBuilder; @@ -54,6 +56,14 @@ public abstract class AbstractIndicesAdminClient implements InternalIndicesAdmin return new DeleteIndexRequestBuilder(this, index); } + @Override public CloseIndexRequestBuilder prepareClose(String index) { + return new CloseIndexRequestBuilder(this, index); + } + + @Override public OpenIndexRequestBuilder prepareOpen(String index) { + return new OpenIndexRequestBuilder(this, index); + } + @Override public FlushRequestBuilder prepareFlush(String... indices) { return new FlushRequestBuilder(this).setIndices(indices); } diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/client/transport/action/ClientTransportActionModule.java b/modules/elasticsearch/src/main/java/org/elasticsearch/client/transport/action/ClientTransportActionModule.java index bdc0f9704f3..d907e475b37 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/client/transport/action/ClientTransportActionModule.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/client/transport/action/ClientTransportActionModule.java @@ -30,12 +30,14 @@ import org.elasticsearch.client.transport.action.admin.cluster.ping.single.Clien import org.elasticsearch.client.transport.action.admin.cluster.state.ClientTransportClusterStateAction; import org.elasticsearch.client.transport.action.admin.indices.alias.ClientTransportIndicesAliasesAction; import org.elasticsearch.client.transport.action.admin.indices.cache.clear.ClientTransportClearIndicesCacheAction; +import org.elasticsearch.client.transport.action.admin.indices.close.ClientTransportCloseIndexAction; import org.elasticsearch.client.transport.action.admin.indices.create.ClientTransportCreateIndexAction; import org.elasticsearch.client.transport.action.admin.indices.delete.ClientTransportDeleteIndexAction; import org.elasticsearch.client.transport.action.admin.indices.flush.ClientTransportFlushAction; import org.elasticsearch.client.transport.action.admin.indices.gateway.snapshot.ClientTransportGatewaySnapshotAction; import org.elasticsearch.client.transport.action.admin.indices.mapping.delete.ClientTransportDeleteMappingAction; import org.elasticsearch.client.transport.action.admin.indices.mapping.put.ClientTransportPutMappingAction; +import org.elasticsearch.client.transport.action.admin.indices.open.ClientTransportOpenIndexAction; import org.elasticsearch.client.transport.action.admin.indices.optimize.ClientTransportOptimizeAction; import org.elasticsearch.client.transport.action.admin.indices.refresh.ClientTransportRefreshAction; import org.elasticsearch.client.transport.action.admin.indices.settings.ClientTransportUpdateSettingsAction; @@ -71,6 +73,8 @@ public class ClientTransportActionModule extends AbstractModule { bind(ClientTransportOptimizeAction.class).asEagerSingleton(); bind(ClientTransportCreateIndexAction.class).asEagerSingleton(); bind(ClientTransportDeleteIndexAction.class).asEagerSingleton(); + bind(ClientTransportCloseIndexAction.class).asEagerSingleton(); + bind(ClientTransportOpenIndexAction.class).asEagerSingleton(); bind(ClientTransportPutMappingAction.class).asEagerSingleton(); bind(ClientTransportDeleteMappingAction.class).asEagerSingleton(); bind(ClientTransportGatewaySnapshotAction.class).asEagerSingleton(); diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/client/transport/action/admin/indices/close/ClientTransportCloseIndexAction.java b/modules/elasticsearch/src/main/java/org/elasticsearch/client/transport/action/admin/indices/close/ClientTransportCloseIndexAction.java new file mode 100644 index 00000000000..467bc3d7d0f --- /dev/null +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/client/transport/action/admin/indices/close/ClientTransportCloseIndexAction.java @@ -0,0 +1,42 @@ +/* + * Licensed to Elastic Search and Shay Banon under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. Elastic Search 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.client.transport.action.admin.indices.close; + +import org.elasticsearch.action.TransportActions; +import org.elasticsearch.action.admin.indices.close.CloseIndexRequest; +import org.elasticsearch.action.admin.indices.close.CloseIndexResponse; +import org.elasticsearch.client.transport.action.support.BaseClientTransportAction; +import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.transport.TransportService; + +/** + * @author kimchy (Shay Banon) + */ +public class ClientTransportCloseIndexAction extends BaseClientTransportAction { + + @Inject public ClientTransportCloseIndexAction(Settings settings, TransportService transportService) { + super(settings, transportService, CloseIndexResponse.class); + } + + @Override protected String action() { + return TransportActions.Admin.Indices.CLOSE; + } +} \ No newline at end of file diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/client/transport/action/admin/indices/open/ClientTransportOpenIndexAction.java b/modules/elasticsearch/src/main/java/org/elasticsearch/client/transport/action/admin/indices/open/ClientTransportOpenIndexAction.java new file mode 100644 index 00000000000..4fd7eab1356 --- /dev/null +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/client/transport/action/admin/indices/open/ClientTransportOpenIndexAction.java @@ -0,0 +1,42 @@ +/* + * Licensed to Elastic Search and Shay Banon under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. Elastic Search 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.client.transport.action.admin.indices.open; + +import org.elasticsearch.action.TransportActions; +import org.elasticsearch.action.admin.indices.open.OpenIndexRequest; +import org.elasticsearch.action.admin.indices.open.OpenIndexResponse; +import org.elasticsearch.client.transport.action.support.BaseClientTransportAction; +import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.transport.TransportService; + +/** + * @author kimchy (Shay Banon) + */ +public class ClientTransportOpenIndexAction extends BaseClientTransportAction { + + @Inject public ClientTransportOpenIndexAction(Settings settings, TransportService transportService) { + super(settings, transportService, OpenIndexResponse.class); + } + + @Override protected String action() { + return TransportActions.Admin.Indices.OPEN; + } +} \ No newline at end of file diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/client/transport/support/InternalTransportIndicesAdminClient.java b/modules/elasticsearch/src/main/java/org/elasticsearch/client/transport/support/InternalTransportIndicesAdminClient.java index 31cdc314009..e3c175a419b 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/client/transport/support/InternalTransportIndicesAdminClient.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/client/transport/support/InternalTransportIndicesAdminClient.java @@ -26,6 +26,8 @@ import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest; import org.elasticsearch.action.admin.indices.alias.IndicesAliasesResponse; import org.elasticsearch.action.admin.indices.cache.clear.ClearIndicesCacheRequest; import org.elasticsearch.action.admin.indices.cache.clear.ClearIndicesCacheResponse; +import org.elasticsearch.action.admin.indices.close.CloseIndexRequest; +import org.elasticsearch.action.admin.indices.close.CloseIndexResponse; import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; import org.elasticsearch.action.admin.indices.create.CreateIndexResponse; import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest; @@ -38,6 +40,8 @@ import org.elasticsearch.action.admin.indices.mapping.delete.DeleteMappingReques import org.elasticsearch.action.admin.indices.mapping.delete.DeleteMappingResponse; import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest; import org.elasticsearch.action.admin.indices.mapping.put.PutMappingResponse; +import org.elasticsearch.action.admin.indices.open.OpenIndexRequest; +import org.elasticsearch.action.admin.indices.open.OpenIndexResponse; import org.elasticsearch.action.admin.indices.optimize.OptimizeRequest; import org.elasticsearch.action.admin.indices.optimize.OptimizeResponse; import org.elasticsearch.action.admin.indices.refresh.RefreshRequest; @@ -51,12 +55,14 @@ import org.elasticsearch.client.support.AbstractIndicesAdminClient; import org.elasticsearch.client.transport.TransportClientNodesService; import org.elasticsearch.client.transport.action.admin.indices.alias.ClientTransportIndicesAliasesAction; import org.elasticsearch.client.transport.action.admin.indices.cache.clear.ClientTransportClearIndicesCacheAction; +import org.elasticsearch.client.transport.action.admin.indices.close.ClientTransportCloseIndexAction; import org.elasticsearch.client.transport.action.admin.indices.create.ClientTransportCreateIndexAction; import org.elasticsearch.client.transport.action.admin.indices.delete.ClientTransportDeleteIndexAction; import org.elasticsearch.client.transport.action.admin.indices.flush.ClientTransportFlushAction; import org.elasticsearch.client.transport.action.admin.indices.gateway.snapshot.ClientTransportGatewaySnapshotAction; import org.elasticsearch.client.transport.action.admin.indices.mapping.delete.ClientTransportDeleteMappingAction; import org.elasticsearch.client.transport.action.admin.indices.mapping.put.ClientTransportPutMappingAction; +import org.elasticsearch.client.transport.action.admin.indices.open.ClientTransportOpenIndexAction; import org.elasticsearch.client.transport.action.admin.indices.optimize.ClientTransportOptimizeAction; import org.elasticsearch.client.transport.action.admin.indices.refresh.ClientTransportRefreshAction; import org.elasticsearch.client.transport.action.admin.indices.settings.ClientTransportUpdateSettingsAction; @@ -81,6 +87,10 @@ public class InternalTransportIndicesAdminClient extends AbstractIndicesAdminCli private final ClientTransportDeleteIndexAction deleteIndexAction; + private final ClientTransportCloseIndexAction closeIndexAction; + + private final ClientTransportOpenIndexAction openIndexAction; + private final ClientTransportRefreshAction refreshAction; private final ClientTransportFlushAction flushAction; @@ -102,6 +112,7 @@ public class InternalTransportIndicesAdminClient extends AbstractIndicesAdminCli @Inject public InternalTransportIndicesAdminClient(Settings settings, TransportClientNodesService nodesService, ThreadPool threadPool, ClientTransportIndicesStatusAction indicesStatusAction, ClientTransportCreateIndexAction createIndexAction, ClientTransportDeleteIndexAction deleteIndexAction, + ClientTransportCloseIndexAction closeIndexAction, ClientTransportOpenIndexAction openIndexAction, ClientTransportRefreshAction refreshAction, ClientTransportFlushAction flushAction, ClientTransportOptimizeAction optimizeAction, ClientTransportPutMappingAction putMappingAction, ClientTransportDeleteMappingAction deleteMappingAction, ClientTransportGatewaySnapshotAction gatewaySnapshotAction, ClientTransportIndicesAliasesAction indicesAliasesAction, ClientTransportClearIndicesCacheAction clearIndicesCacheAction, @@ -111,6 +122,8 @@ public class InternalTransportIndicesAdminClient extends AbstractIndicesAdminCli this.indicesStatusAction = indicesStatusAction; this.createIndexAction = createIndexAction; this.deleteIndexAction = deleteIndexAction; + this.closeIndexAction = closeIndexAction; + this.openIndexAction = openIndexAction; this.refreshAction = refreshAction; this.flushAction = flushAction; this.optimizeAction = optimizeAction; @@ -177,6 +190,40 @@ public class InternalTransportIndicesAdminClient extends AbstractIndicesAdminCli }); } + @Override public ActionFuture close(final CloseIndexRequest request) { + return nodesService.execute(new TransportClientNodesService.NodeCallback>() { + @Override public ActionFuture doWithNode(DiscoveryNode node) throws ElasticSearchException { + return closeIndexAction.execute(node, request); + } + }); + } + + @Override public void close(final CloseIndexRequest request, final ActionListener listener) { + nodesService.execute(new TransportClientNodesService.NodeCallback() { + @Override public Object doWithNode(DiscoveryNode node) throws ElasticSearchException { + closeIndexAction.execute(node, request, listener); + return null; + } + }); + } + + @Override public ActionFuture open(final OpenIndexRequest request) { + return nodesService.execute(new TransportClientNodesService.NodeCallback>() { + @Override public ActionFuture doWithNode(DiscoveryNode node) throws ElasticSearchException { + return openIndexAction.execute(node, request); + } + }); + } + + @Override public void open(final OpenIndexRequest request, final ActionListener listener) { + nodesService.execute(new TransportClientNodesService.NodeCallback() { + @Override public Object doWithNode(DiscoveryNode node) throws ElasticSearchException { + openIndexAction.execute(node, request, listener); + return null; + } + }); + } + @Override public ActionFuture refresh(final RefreshRequest request) { return nodesService.execute(new TransportClientNodesService.NodeCallback>() { @Override public ActionFuture doWithNode(DiscoveryNode node) throws ElasticSearchException { diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/cluster/ClusterModule.java b/modules/elasticsearch/src/main/java/org/elasticsearch/cluster/ClusterModule.java index 75ec6943d8b..8adc68e9b1e 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/cluster/ClusterModule.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/cluster/ClusterModule.java @@ -55,6 +55,7 @@ public class ClusterModule extends AbstractModule implements SpawnModules { bind(ClusterService.class).to(InternalClusterService.class).asEagerSingleton(); bind(MetaDataCreateIndexService.class).asEagerSingleton(); bind(MetaDataDeleteIndexService.class).asEagerSingleton(); + bind(MetaDataStateIndexService.class).asEagerSingleton(); bind(MetaDataMappingService.class).asEagerSingleton(); bind(MetaDataIndexAliasesService.class).asEagerSingleton(); bind(MetaDataUpdateSettingsService.class).asEagerSingleton(); diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/cluster/metadata/IndexMetaData.java b/modules/elasticsearch/src/main/java/org/elasticsearch/cluster/metadata/IndexMetaData.java index 9ea26d18f51..4cab42bac52 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/cluster/metadata/IndexMetaData.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/cluster/metadata/IndexMetaData.java @@ -19,6 +19,7 @@ package org.elasticsearch.cluster.metadata; +import org.elasticsearch.ElasticSearchIllegalStateException; import org.elasticsearch.common.Preconditions; import org.elasticsearch.common.collect.ImmutableMap; import org.elasticsearch.common.collect.ImmutableSet; @@ -46,12 +47,47 @@ import static org.elasticsearch.common.settings.ImmutableSettings.*; @Immutable public class IndexMetaData { + public static enum State { + OPEN((byte) 0), + CLOSE((byte) 1); + + private final byte id; + + State(byte id) { + this.id = id; + } + + public byte id() { + return this.id; + } + + public static State fromId(byte id) { + if (id == 0) { + return OPEN; + } else if (id == 1) { + return CLOSE; + } + throw new ElasticSearchIllegalStateException("No state match for id [" + id + "]"); + } + + public static State fromString(String state) { + if ("open".equals(state)) { + return OPEN; + } else if ("close".equals(state)) { + return CLOSE; + } + throw new ElasticSearchIllegalStateException("No state match for [" + state + "]"); + } + } + public static final String SETTING_NUMBER_OF_SHARDS = "index.number_of_shards"; public static final String SETTING_NUMBER_OF_REPLICAS = "index.number_of_replicas"; private final String index; + private final State state; + private final ImmutableSet aliases; private final Settings settings; @@ -60,10 +96,11 @@ public class IndexMetaData { private transient final int totalNumberOfShards; - private IndexMetaData(String index, Settings settings, ImmutableMap mappings) { + private IndexMetaData(String index, State state, Settings settings, ImmutableMap mappings) { Preconditions.checkArgument(settings.getAsInt(SETTING_NUMBER_OF_SHARDS, -1) != -1, "must specify numberOfShards for index [" + index + "]"); Preconditions.checkArgument(settings.getAsInt(SETTING_NUMBER_OF_REPLICAS, -1) != -1, "must specify numberOfReplicas for index [" + index + "]"); this.index = index; + this.state = state; this.settings = settings; this.mappings = mappings; this.totalNumberOfShards = numberOfShards() * (numberOfReplicas() + 1); @@ -79,6 +116,14 @@ public class IndexMetaData { return index(); } + public State state() { + return this.state; + } + + public State getState() { + return state(); + } + public int numberOfShards() { return settings.getAsInt(SETTING_NUMBER_OF_SHARDS, -1); } @@ -143,6 +188,8 @@ public class IndexMetaData { private String index; + private State state = State.OPEN; + private Settings settings = ImmutableSettings.Builder.EMPTY_SETTINGS; private MapBuilder mappings = MapBuilder.newMapBuilder(); @@ -155,6 +202,7 @@ public class IndexMetaData { this(indexMetaData.index()); settings(indexMetaData.settings()); mappings.putAll(indexMetaData.mappings); + this.state = indexMetaData.state; } public String index() { @@ -204,13 +252,20 @@ public class IndexMetaData { return this; } + public Builder state(State state) { + this.state = state; + return this; + } + public IndexMetaData build() { - return new IndexMetaData(index, settings, mappings.immutableMap()); + return new IndexMetaData(index, state, settings, mappings.immutableMap()); } public static void toXContent(IndexMetaData indexMetaData, XContentBuilder builder, ToXContent.Params params) throws IOException { builder.startObject(indexMetaData.index()); + builder.field("state", indexMetaData.state().toString().toLowerCase()); + builder.startObject("settings"); for (Map.Entry entry : indexMetaData.settings().getAsMap().entrySet()) { builder.field(entry.getKey(), entry.getValue()); @@ -262,6 +317,10 @@ public class IndexMetaData { } } } + } else if (token.isValue()) { + if ("state".equals(currentFieldName)) { + builder.state(State.fromString(parser.text())); + } } } return builder.build(); @@ -269,6 +328,7 @@ public class IndexMetaData { public static IndexMetaData readFrom(StreamInput in, Settings globalSettings) throws IOException { Builder builder = new Builder(in.readUTF()); + builder.state(State.fromId(in.readByte())); builder.settings(readSettingsFromStream(in, globalSettings)); int mappingsSize = in.readVInt(); for (int i = 0; i < mappingsSize; i++) { @@ -279,6 +339,7 @@ public class IndexMetaData { public static void writeTo(IndexMetaData indexMetaData, StreamOutput out) throws IOException { out.writeUTF(indexMetaData.index()); + out.writeByte(indexMetaData.state().id()); writeSettingsToStream(indexMetaData.settings(), out); out.writeVInt(indexMetaData.mappings().size()); for (Map.Entry entry : indexMetaData.mappings().entrySet()) { diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/cluster/metadata/MetaData.java b/modules/elasticsearch/src/main/java/org/elasticsearch/cluster/metadata/MetaData.java index b9f968734ba..54452232fb3 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/cluster/metadata/MetaData.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/cluster/metadata/MetaData.java @@ -215,6 +215,11 @@ public class MetaData implements Iterable { return indices.values().iterator(); } + public static Builder builder() { + return new Builder(); + } + + public static Builder newMetaDataBuilder() { return new Builder(); } diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/cluster/metadata/MetaDataCreateIndexService.java b/modules/elasticsearch/src/main/java/org/elasticsearch/cluster/metadata/MetaDataCreateIndexService.java index b1a87443b4d..c24541a696b 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/cluster/metadata/MetaDataCreateIndexService.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/cluster/metadata/MetaDataCreateIndexService.java @@ -195,6 +195,7 @@ public class MetaDataCreateIndexService extends AbstractComponent { for (Map.Entry entry : mappings.entrySet()) { indexMetaDataBuilder.putMapping(entry.getKey(), entry.getValue()); } + indexMetaDataBuilder.state(request.state); final IndexMetaData indexMetaData = indexMetaDataBuilder.build(); MetaData newMetaData = newMetaDataBuilder() @@ -210,6 +211,9 @@ public class MetaDataCreateIndexService extends AbstractComponent { blocks.addIndexBlock(request.index, block); } } + if (request.state == State.CLOSE) { + blocks.addIndexBlock(request.index, MetaDataStateIndexService.INDEX_CLOSED_BLOCK); + } return newClusterStateBuilder().state(currentState).blocks(blocks).metaData(newMetaData).build(); } catch (Exception e) { @@ -219,12 +223,12 @@ public class MetaDataCreateIndexService extends AbstractComponent { } @Override public void clusterStateProcessed(ClusterState clusterState) { + if (request.state == State.CLOSE) { // no need to do shard allocated when closed... + return; + } clusterService.submitStateUpdateTask("reroute after index [" + request.index + "] creation", new ProcessedClusterStateUpdateTask() { @Override public ClusterState execute(ClusterState currentState) { - RoutingTable.Builder routingTableBuilder = new RoutingTable.Builder(); - for (IndexRoutingTable indexRoutingTable : currentState.routingTable().indicesRouting().values()) { - routingTableBuilder.add(indexRoutingTable); - } + RoutingTable.Builder routingTableBuilder = RoutingTable.builder().routingTable(currentState.routingTable()); IndexRoutingTable.Builder indexRoutingBuilder = new IndexRoutingTable.Builder(request.index) .initializeEmpty(currentState.metaData().index(request.index)); routingTableBuilder.add(indexRoutingBuilder); @@ -270,6 +274,8 @@ public class MetaDataCreateIndexService extends AbstractComponent { final String index; + State state = State.OPEN; + Settings settings = ImmutableSettings.Builder.EMPTY_SETTINGS; Map mappings = Maps.newHashMap(); @@ -305,6 +311,11 @@ public class MetaDataCreateIndexService extends AbstractComponent { return this; } + public Request state(State state) { + this.state = state; + return this; + } + public Request timeout(TimeValue timeout) { this.timeout = timeout; return this; diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/cluster/metadata/MetaDataStateIndexService.java b/modules/elasticsearch/src/main/java/org/elasticsearch/cluster/metadata/MetaDataStateIndexService.java new file mode 100644 index 00000000000..c7ef547159d --- /dev/null +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/cluster/metadata/MetaDataStateIndexService.java @@ -0,0 +1,162 @@ +/* + * Licensed to Elastic Search and Shay Banon under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. Elastic Search 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.ClusterService; +import org.elasticsearch.cluster.ClusterState; +import org.elasticsearch.cluster.ProcessedClusterStateUpdateTask; +import org.elasticsearch.cluster.block.ClusterBlock; +import org.elasticsearch.cluster.block.ClusterBlockLevel; +import org.elasticsearch.cluster.block.ClusterBlocks; +import org.elasticsearch.cluster.routing.IndexRoutingTable; +import org.elasticsearch.cluster.routing.RoutingTable; +import org.elasticsearch.common.component.AbstractComponent; +import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.unit.TimeValue; +import org.elasticsearch.gateway.GatewayService; +import org.elasticsearch.index.Index; +import org.elasticsearch.indices.IndexMissingException; + +/** + * @author kimchy (shay.banon) + */ +public class MetaDataStateIndexService extends AbstractComponent { + + public static final ClusterBlock INDEX_CLOSED_BLOCK = new ClusterBlock(4, "index closed", ClusterBlockLevel.READ_WRITE); + + private final ClusterService clusterService; + + @Inject public MetaDataStateIndexService(Settings settings, ClusterService clusterService) { + super(settings); + this.clusterService = clusterService; + } + + public void closeIndex(final Request request, final Listener listener) { + clusterService.submitStateUpdateTask("close-index [" + request.index + "]", new ProcessedClusterStateUpdateTask() { + @Override public ClusterState execute(ClusterState currentState) { + + IndexMetaData indexMetaData = currentState.metaData().index(request.index); + if (indexMetaData == null) { + listener.onFailure(new IndexMissingException(new Index(request.index))); + return currentState; + } + + if (indexMetaData.state() == IndexMetaData.State.CLOSE) { + listener.onResponse(new Response(true)); + return currentState; + } + + logger.info("[{}] closing index", request.index); + + MetaData.Builder mdBuilder = MetaData.builder() + .metaData(currentState.metaData()) + .put(IndexMetaData.newIndexMetaDataBuilder(currentState.metaData().index(request.index)).state(IndexMetaData.State.CLOSE)); + + RoutingTable.Builder rtBuilder = RoutingTable.builder() + .routingTable(currentState.routingTable()) + .remove(request.index); + + ClusterBlocks.Builder blocks = ClusterBlocks.builder().blocks(currentState.blocks()) + .addIndexBlock(request.index, INDEX_CLOSED_BLOCK); + + return ClusterState.builder().state(currentState).metaData(mdBuilder).routingTable(rtBuilder).blocks(blocks).build(); + } + + @Override public void clusterStateProcessed(ClusterState clusterState) { + listener.onResponse(new Response(true)); + } + }); + } + + public void openIndex(final Request request, final Listener listener) { + clusterService.submitStateUpdateTask("open-index [" + request.index + "]", new ProcessedClusterStateUpdateTask() { + @Override public ClusterState execute(ClusterState currentState) { + + IndexMetaData indexMetaData = currentState.metaData().index(request.index); + if (indexMetaData == null) { + listener.onFailure(new IndexMissingException(new Index(request.index))); + return currentState; + } + + if (indexMetaData.state() == IndexMetaData.State.OPEN) { + listener.onResponse(new Response(true)); + return currentState; + } + + logger.info("[{}] opening index", request.index); + + MetaData.Builder mdBuilder = MetaData.builder() + .metaData(currentState.metaData()) + .put(IndexMetaData.newIndexMetaDataBuilder(currentState.metaData().index(request.index)).state(IndexMetaData.State.OPEN)); + + RoutingTable.Builder rtBuilder = RoutingTable.builder().routingTable(currentState.routingTable()); + IndexRoutingTable.Builder indexRoutingBuilder = new IndexRoutingTable.Builder(request.index) + .initializeEmpty(currentState.metaData().index(request.index)); + rtBuilder.add(indexRoutingBuilder); + + ClusterBlocks.Builder blocks = ClusterBlocks.builder().blocks(currentState.blocks()) + .removeIndexBlock(request.index, INDEX_CLOSED_BLOCK) + .addIndexBlock(request.index, GatewayService.INDEX_NOT_RECOVERED_BLOCK); + + return ClusterState.builder().state(currentState).metaData(mdBuilder).routingTable(rtBuilder).blocks(blocks).build(); + } + + @Override public void clusterStateProcessed(ClusterState clusterState) { + listener.onResponse(new Response(true)); + } + }); + } + + public static interface Listener { + + void onResponse(Response response); + + void onFailure(Throwable t); + } + + public static class Request { + + final String index; + + TimeValue timeout = TimeValue.timeValueSeconds(10); + + public Request(String index) { + this.index = index; + } + + public Request timeout(TimeValue timeout) { + this.timeout = timeout; + return this; + } + } + + public static class Response { + private final boolean acknowledged; + + public Response(boolean acknowledged) { + this.acknowledged = acknowledged; + } + + public boolean acknowledged() { + return acknowledged; + } + } +} diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/cluster/routing/RoutingTable.java b/modules/elasticsearch/src/main/java/org/elasticsearch/cluster/routing/RoutingTable.java index bc6d0b23d54..cd5d1457351 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/cluster/routing/RoutingTable.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/cluster/routing/RoutingTable.java @@ -150,7 +150,9 @@ public class RoutingTable implements Iterable { for (String index : indices) { IndexRoutingTable indexRoutingTable = index(index); if (indexRoutingTable == null) { - throw new IndexMissingException(new Index(index)); + continue; + // we simply ignore indices that don't exists (make sense for operations that use it currently) +// throw new IndexMissingException(new Index(index)); } for (IndexShardRoutingTable indexShardRoutingTable : indexRoutingTable) { for (ShardRouting shardRouting : indexShardRoutingTable) { @@ -188,6 +190,10 @@ public class RoutingTable implements Iterable { return its; } + public static Builder builder() { + return new Builder(); + } + public static Builder newRoutingTableBuilder() { return new Builder(); } @@ -249,6 +255,11 @@ public class RoutingTable implements Iterable { return this; } + public Builder remove(String index) { + indicesRouting.remove(index); + return this; + } + public Builder updateNodes(RoutingNodes routingNodes) { Map indexRoutingTableBuilders = newHashMap(); for (RoutingNode routingNode : routingNodes) { diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/gateway/local/LocalGateway.java b/modules/elasticsearch/src/main/java/org/elasticsearch/gateway/local/LocalGateway.java index ca8d0f56a3b..b5302614bf6 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/gateway/local/LocalGateway.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/gateway/local/LocalGateway.java @@ -180,6 +180,7 @@ public class LocalGateway extends AbstractLifecycleComponent implements createIndexService.createIndex(new MetaDataCreateIndexService.Request("gateway", indexMetaData.index()) .settings(indexMetaData.settings()) .mappingsCompressed(indexMetaData.mappings()) + .state(indexMetaData.state()) .blocks(ImmutableSet.of(GatewayService.INDEX_NOT_RECOVERED_BLOCK)) .timeout(timeValueSeconds(30)), diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/gateway/shared/SharedStorageGateway.java b/modules/elasticsearch/src/main/java/org/elasticsearch/gateway/shared/SharedStorageGateway.java index 0ee0b7bfe10..7400cd357d3 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/gateway/shared/SharedStorageGateway.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/gateway/shared/SharedStorageGateway.java @@ -150,6 +150,7 @@ public abstract class SharedStorageGateway extends AbstractLifecycleComponent entry : settings.getAsMap().entrySet()) { diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/rest/action/admin/indices/close/RestCloseIndexAction.java b/modules/elasticsearch/src/main/java/org/elasticsearch/rest/action/admin/indices/close/RestCloseIndexAction.java new file mode 100644 index 00000000000..0722e262460 --- /dev/null +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/rest/action/admin/indices/close/RestCloseIndexAction.java @@ -0,0 +1,87 @@ +/* + * Licensed to Elastic Search and Shay Banon under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. Elastic Search 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.close; + +import org.elasticsearch.action.ActionListener; +import org.elasticsearch.action.admin.indices.close.CloseIndexRequest; +import org.elasticsearch.action.admin.indices.close.CloseIndexResponse; +import org.elasticsearch.client.Client; +import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.XContentBuilderString; +import org.elasticsearch.indices.IndexMissingException; +import org.elasticsearch.rest.*; +import org.elasticsearch.rest.action.support.RestXContentBuilder; + +import java.io.IOException; + +import static org.elasticsearch.ExceptionsHelper.*; +import static org.elasticsearch.common.unit.TimeValue.*; +import static org.elasticsearch.rest.RestResponse.Status.*; + +/** + * @author kimchy (shay.banon) + */ +public class RestCloseIndexAction extends BaseRestHandler { + + @Inject public RestCloseIndexAction(Settings settings, Client client, RestController controller) { + super(settings, client); + controller.registerHandler(RestRequest.Method.POST, "/{index}/_close", this); + } + + @Override public void handleRequest(final RestRequest request, final RestChannel channel) { + CloseIndexRequest closeIndexRequest = new CloseIndexRequest(request.param("index")); + closeIndexRequest.timeout(request.paramAsTime("timeout", timeValueSeconds(10))); + client.admin().indices().close(closeIndexRequest, new ActionListener() { + @Override public void onResponse(CloseIndexResponse response) { + try { + XContentBuilder builder = RestXContentBuilder.restContentBuilder(request); + builder.startObject() + .field(Fields.OK, true) + .field(Fields.ACKNOWLEDGED, response.acknowledged()) + .endObject(); + channel.sendResponse(new XContentRestResponse(request, OK, builder)); + } catch (IOException e) { + onFailure(e); + } + } + + @Override public void onFailure(Throwable e) { + try { + Throwable t = unwrapCause(e); + if (t instanceof IndexMissingException) { + XContentBuilder builder = RestXContentBuilder.restContentBuilder(request); + channel.sendResponse(new XContentRestResponse(request, BAD_REQUEST, builder.startObject().field("error", t.getMessage()).endObject())); + } else { + channel.sendResponse(new XContentThrowableRestResponse(request, e)); + } + } catch (IOException e1) { + logger.error("Failed to send failure response", e1); + } + } + }); + } + + static final class Fields { + static final XContentBuilderString OK = new XContentBuilderString("ok"); + static final XContentBuilderString ACKNOWLEDGED = new XContentBuilderString("acknowledged"); + } +} \ No newline at end of file diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/rest/action/admin/indices/open/RestOpenIndexAction.java b/modules/elasticsearch/src/main/java/org/elasticsearch/rest/action/admin/indices/open/RestOpenIndexAction.java new file mode 100644 index 00000000000..5b0c2e3f76d --- /dev/null +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/rest/action/admin/indices/open/RestOpenIndexAction.java @@ -0,0 +1,87 @@ +/* + * Licensed to Elastic Search and Shay Banon under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. Elastic Search 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.open; + +import org.elasticsearch.action.ActionListener; +import org.elasticsearch.action.admin.indices.open.OpenIndexRequest; +import org.elasticsearch.action.admin.indices.open.OpenIndexResponse; +import org.elasticsearch.client.Client; +import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.XContentBuilderString; +import org.elasticsearch.indices.IndexMissingException; +import org.elasticsearch.rest.*; +import org.elasticsearch.rest.action.support.RestXContentBuilder; + +import java.io.IOException; + +import static org.elasticsearch.ExceptionsHelper.*; +import static org.elasticsearch.common.unit.TimeValue.*; +import static org.elasticsearch.rest.RestResponse.Status.*; + +/** + * @author kimchy (shay.banon) + */ +public class RestOpenIndexAction extends BaseRestHandler { + + @Inject public RestOpenIndexAction(Settings settings, Client client, RestController controller) { + super(settings, client); + controller.registerHandler(RestRequest.Method.POST, "/{index}/_open", this); + } + + @Override public void handleRequest(final RestRequest request, final RestChannel channel) { + OpenIndexRequest openIndexRequest = new OpenIndexRequest(request.param("index")); + openIndexRequest.timeout(request.paramAsTime("timeout", timeValueSeconds(10))); + client.admin().indices().open(openIndexRequest, new ActionListener() { + @Override public void onResponse(OpenIndexResponse response) { + try { + XContentBuilder builder = RestXContentBuilder.restContentBuilder(request); + builder.startObject() + .field(Fields.OK, true) + .field(Fields.ACKNOWLEDGED, response.acknowledged()) + .endObject(); + channel.sendResponse(new XContentRestResponse(request, OK, builder)); + } catch (IOException e) { + onFailure(e); + } + } + + @Override public void onFailure(Throwable e) { + try { + Throwable t = unwrapCause(e); + if (t instanceof IndexMissingException) { + XContentBuilder builder = RestXContentBuilder.restContentBuilder(request); + channel.sendResponse(new XContentRestResponse(request, BAD_REQUEST, builder.startObject().field("error", t.getMessage()).endObject())); + } else { + channel.sendResponse(new XContentThrowableRestResponse(request, e)); + } + } catch (IOException e1) { + logger.error("Failed to send failure response", e1); + } + } + }); + } + + static final class Fields { + static final XContentBuilderString OK = new XContentBuilderString("ok"); + static final XContentBuilderString ACKNOWLEDGED = new XContentBuilderString("acknowledged"); + } +} \ No newline at end of file diff --git a/modules/test/integration/src/test/java/org/elasticsearch/test/integration/gateway/local/LocalGatewayIndexStateTests.java b/modules/test/integration/src/test/java/org/elasticsearch/test/integration/gateway/local/LocalGatewayIndexStateTests.java new file mode 100644 index 00000000000..af92087fe25 --- /dev/null +++ b/modules/test/integration/src/test/java/org/elasticsearch/test/integration/gateway/local/LocalGatewayIndexStateTests.java @@ -0,0 +1,141 @@ +/* + * Licensed to Elastic Search and Shay Banon under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. Elastic Search 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.test.integration.gateway.local; + +import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse; +import org.elasticsearch.action.admin.cluster.state.ClusterStateResponse; +import org.elasticsearch.action.get.GetResponse; +import org.elasticsearch.cluster.block.ClusterBlockException; +import org.elasticsearch.cluster.metadata.IndexMetaData; +import org.elasticsearch.cluster.routing.ShardRoutingState; +import org.elasticsearch.common.logging.ESLogger; +import org.elasticsearch.common.logging.Loggers; +import org.elasticsearch.gateway.Gateway; +import org.elasticsearch.node.internal.InternalNode; +import org.elasticsearch.test.integration.AbstractNodesTests; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.Test; + +import static org.elasticsearch.common.settings.ImmutableSettings.*; +import static org.hamcrest.MatcherAssert.*; +import static org.hamcrest.Matchers.*; + +/** + * @author kimchy (shay.banon) + */ +public class LocalGatewayIndexStateTests extends AbstractNodesTests { + + private final ESLogger logger = Loggers.getLogger(LocalGatewayIndexStateTests.class); + + @AfterMethod public void cleanAndCloseNodes() throws Exception { + for (int i = 0; i < 10; i++) { + if (node("node" + i) != null) { + node("node" + i).stop(); + // since we store (by default) the index snapshot under the gateway, resetting it will reset the index data as well + ((InternalNode) node("node" + i)).injector().getInstance(Gateway.class).reset(); + } + } + closeAllNodes(); + } + + @Test public void testSimpleOpenClose() throws Exception { + logger.info("--> cleaning nodes"); + buildNode("node1", settingsBuilder().put("gateway.type", "local").build()); + buildNode("node2", settingsBuilder().put("gateway.type", "local").build()); + cleanAndCloseNodes(); + + logger.info("--> starting 2 nodes"); + startNode("node1", settingsBuilder().put("gateway.type", "local").put("index.number_of_shards", 2).put("index.number_of_replicas", 1).build()); + startNode("node2", settingsBuilder().put("gateway.type", "local").put("index.number_of_shards", 2).put("index.number_of_replicas", 1).build()); + + logger.info("--> creating test index"); + client("node1").admin().indices().prepareCreate("test").execute().actionGet(); + + logger.info("--> waiting for green status"); + ClusterHealthResponse health = client("node1").admin().cluster().prepareHealth().setWaitForGreenStatus().setWaitForNodes("2").execute().actionGet(); + assertThat(health.timedOut(), equalTo(false)); + + ClusterStateResponse stateResponse = client("node1").admin().cluster().prepareState().execute().actionGet(); + assertThat(stateResponse.state().metaData().index("test").state(), equalTo(IndexMetaData.State.OPEN)); + assertThat(stateResponse.state().routingTable().index("test").shards().size(), equalTo(2)); + assertThat(stateResponse.state().routingTable().index("test").shardsWithState(ShardRoutingState.STARTED).size(), equalTo(4)); + + logger.info("--> indexing a simple document"); + client("node1").prepareIndex("test", "type1", "1").setSource("field1", "value1").execute().actionGet(); + + logger.info("--> closing test index..."); + client("node1").admin().indices().prepareClose("test").execute().actionGet(); + + stateResponse = client("node1").admin().cluster().prepareState().execute().actionGet(); + assertThat(stateResponse.state().metaData().index("test").state(), equalTo(IndexMetaData.State.CLOSE)); + assertThat(stateResponse.state().routingTable().index("test"), nullValue()); + + logger.info("--> trying to index into a closed index ..."); + try { + client("node1").prepareIndex("test", "type1", "1").setSource("field1", "value1").execute().actionGet(); + assert false; + } catch (ClusterBlockException e) { + // all is well + } + + logger.info("--> closing nodes..."); + closeNode("node2"); + closeNode("node1"); + + logger.info("--> starting nodes again..."); + startNode("node1", settingsBuilder().put("gateway.type", "local").build()); + startNode("node2", settingsBuilder().put("gateway.type", "local").build()); + + logger.info("--> waiting for green status"); + health = client("node1").admin().cluster().prepareHealth().setWaitForGreenStatus().setWaitForNodes("2").execute().actionGet(); + assertThat(health.timedOut(), equalTo(false)); + + stateResponse = client("node1").admin().cluster().prepareState().execute().actionGet(); + assertThat(stateResponse.state().metaData().index("test").state(), equalTo(IndexMetaData.State.CLOSE)); + assertThat(stateResponse.state().routingTable().index("test"), nullValue()); + + logger.info("--> trying to index into a closed index ..."); + try { + client("node1").prepareIndex("test", "type1", "1").setSource("field1", "value1").execute().actionGet(); + assert false; + } catch (ClusterBlockException e) { + // all is well + } + + logger.info("--> opening index..."); + client("node1").admin().indices().prepareOpen("test").execute().actionGet(); + + logger.info("--> waiting for green status"); + health = client("node1").admin().cluster().prepareHealth().setWaitForGreenStatus().setWaitForNodes("2").execute().actionGet(); + assertThat(health.timedOut(), equalTo(false)); + + stateResponse = client("node1").admin().cluster().prepareState().execute().actionGet(); + assertThat(stateResponse.state().metaData().index("test").state(), equalTo(IndexMetaData.State.OPEN)); + assertThat(stateResponse.state().routingTable().index("test").shards().size(), equalTo(2)); + assertThat(stateResponse.state().routingTable().index("test").shardsWithState(ShardRoutingState.STARTED).size(), equalTo(4)); + + logger.info("--> trying to get the indexed document on the first round (before close and shutdown)"); + GetResponse getResponse = client("node1").prepareGet("test", "type1", "1").execute().actionGet(); + assertThat(getResponse.exists(), equalTo(true)); + + logger.info("--> indexing a simple document"); + client("node1").prepareIndex("test", "type1", "2").setSource("field1", "value1").execute().actionGet(); + } +} diff --git a/modules/test/integration/src/test/java/org/elasticsearch/test/integration/indices/state/SimpleIndexStateTests.java b/modules/test/integration/src/test/java/org/elasticsearch/test/integration/indices/state/SimpleIndexStateTests.java new file mode 100644 index 00000000000..350773f36ce --- /dev/null +++ b/modules/test/integration/src/test/java/org/elasticsearch/test/integration/indices/state/SimpleIndexStateTests.java @@ -0,0 +1,101 @@ +/* + * Licensed to Elastic Search and Shay Banon under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. Elastic Search 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.test.integration.indices.state; + +import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse; +import org.elasticsearch.action.admin.cluster.state.ClusterStateResponse; +import org.elasticsearch.action.admin.indices.status.IndicesStatusResponse; +import org.elasticsearch.cluster.block.ClusterBlockException; +import org.elasticsearch.cluster.metadata.IndexMetaData; +import org.elasticsearch.cluster.routing.ShardRoutingState; +import org.elasticsearch.common.logging.ESLogger; +import org.elasticsearch.common.logging.Loggers; +import org.elasticsearch.test.integration.AbstractNodesTests; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.Test; + +import static org.hamcrest.MatcherAssert.*; +import static org.hamcrest.Matchers.*; + +/** + * @author kimchy (shay.banon) + */ +public class SimpleIndexStateTests extends AbstractNodesTests { + + private final ESLogger logger = Loggers.getLogger(SimpleIndexStateTests.class); + + @AfterMethod public void closeNodes() { + closeAllNodes(); + } + + @Test public void testSimpleOpenClose() { + logger.info("--> starting two nodes...."); + startNode("node1"); + startNode("node2"); + + logger.info("--> creating test index"); + client("node1").admin().indices().prepareCreate("test").execute().actionGet(); + + logger.info("--> waiting for green status"); + ClusterHealthResponse health = client("node1").admin().cluster().prepareHealth().setWaitForGreenStatus().setWaitForNodes("2").execute().actionGet(); + assertThat(health.timedOut(), equalTo(false)); + + ClusterStateResponse stateResponse = client("node1").admin().cluster().prepareState().execute().actionGet(); + assertThat(stateResponse.state().metaData().index("test").state(), equalTo(IndexMetaData.State.OPEN)); + assertThat(stateResponse.state().routingTable().index("test").shards().size(), equalTo(5)); + assertThat(stateResponse.state().routingTable().index("test").shardsWithState(ShardRoutingState.STARTED).size(), equalTo(10)); + + logger.info("--> indexing a simple document"); + client("node1").prepareIndex("test", "type1", "1").setSource("field1", "value1").execute().actionGet(); + + logger.info("--> closing test index..."); + client("node1").admin().indices().prepareClose("test").execute().actionGet(); + + stateResponse = client("node1").admin().cluster().prepareState().execute().actionGet(); + assertThat(stateResponse.state().metaData().index("test").state(), equalTo(IndexMetaData.State.CLOSE)); + assertThat(stateResponse.state().routingTable().index("test"), nullValue()); + + logger.info("--> testing indices status api..."); + IndicesStatusResponse indicesStatusResponse = client("node1").admin().indices().prepareStatus().execute().actionGet(); + + logger.info("--> trying to index into a closed index ..."); + try { + client("node1").prepareIndex("test", "type1", "1").setSource("field1", "value1").execute().actionGet(); + assert false; + } catch (ClusterBlockException e) { + // all is well + } + + logger.info("--> opening index..."); + client("node1").admin().indices().prepareOpen("test").execute().actionGet(); + + logger.info("--> waiting for green status"); + health = client("node1").admin().cluster().prepareHealth().setWaitForGreenStatus().setWaitForNodes("2").execute().actionGet(); + assertThat(health.timedOut(), equalTo(false)); + + stateResponse = client("node1").admin().cluster().prepareState().execute().actionGet(); + assertThat(stateResponse.state().metaData().index("test").state(), equalTo(IndexMetaData.State.OPEN)); + assertThat(stateResponse.state().routingTable().index("test").shards().size(), equalTo(5)); + assertThat(stateResponse.state().routingTable().index("test").shardsWithState(ShardRoutingState.STARTED).size(), equalTo(10)); + + logger.info("--> indexing a simple document"); + client("node1").prepareIndex("test", "type1", "1").setSource("field1", "value1").execute().actionGet(); + } +}