/* * Licensed to Elasticsearch under one or more contributor * license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright * ownership. Elasticsearch licenses this file to you under * the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.elasticsearch.action.admin.cluster.state; import com.carrotsearch.hppc.cursors.ObjectObjectCursor; import org.elasticsearch.Version; import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.support.ActionFilters; import org.elasticsearch.action.support.master.TransportMasterNodeReadAction; import org.elasticsearch.cluster.ClusterState; import org.elasticsearch.cluster.block.ClusterBlockException; import org.elasticsearch.cluster.metadata.IndexMetaData; import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver; import org.elasticsearch.cluster.metadata.MetaData; import org.elasticsearch.cluster.metadata.MetaData.Custom; import org.elasticsearch.cluster.routing.RoutingTable; import org.elasticsearch.cluster.service.ClusterService; import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.transport.TransportService; import java.io.IOException; import static org.elasticsearch.discovery.zen.PublishClusterStateAction.serializeFullClusterState; public class TransportClusterStateAction extends TransportMasterNodeReadAction<ClusterStateRequest, ClusterStateResponse> { @Inject public TransportClusterStateAction(Settings settings, TransportService transportService, ClusterService clusterService, ThreadPool threadPool, ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver) { super(settings, ClusterStateAction.NAME, false, transportService, clusterService, threadPool, actionFilters, indexNameExpressionResolver, ClusterStateRequest::new); } @Override protected String executor() { // very lightweight operation in memory, no need to fork to a thread return ThreadPool.Names.SAME; } @Override protected ClusterBlockException checkBlock(ClusterStateRequest request, ClusterState state) { // cluster state calls are done also on a fully blocked cluster to figure out what is going // on in the cluster. For example, which nodes have joined yet the recovery has not yet kicked // in, we need to make sure we allow those calls // return state.blocks().globalBlockedException(ClusterBlockLevel.METADATA); return null; } @Override protected ClusterStateResponse newResponse() { return new ClusterStateResponse(); } @Override protected void masterOperation(final ClusterStateRequest request, final ClusterState state, final ActionListener<ClusterStateResponse> listener) throws IOException { ClusterState currentState = clusterService.state(); logger.trace("Serving cluster state request using version {}", currentState.version()); ClusterState.Builder builder = ClusterState.builder(currentState.getClusterName()); builder.version(currentState.version()); builder.stateUUID(currentState.stateUUID()); if (request.nodes()) { builder.nodes(currentState.nodes()); } if (request.routingTable()) { if (request.indices().length > 0) { RoutingTable.Builder routingTableBuilder = RoutingTable.builder(); String[] indices = indexNameExpressionResolver.concreteIndexNames(currentState, request); for (String filteredIndex : indices) { if (currentState.routingTable().getIndicesRouting().containsKey(filteredIndex)) { routingTableBuilder.add(currentState.routingTable().getIndicesRouting().get(filteredIndex)); } } builder.routingTable(routingTableBuilder.build()); } else { builder.routingTable(currentState.routingTable()); } } if (request.blocks()) { builder.blocks(currentState.blocks()); } if (request.metaData()) { MetaData.Builder mdBuilder; if (request.indices().length == 0) { mdBuilder = MetaData.builder(currentState.metaData()); } else { mdBuilder = MetaData.builder(); } if (request.indices().length > 0) { String[] indices = indexNameExpressionResolver.concreteIndexNames(currentState, request); for (String filteredIndex : indices) { IndexMetaData indexMetaData = currentState.metaData().index(filteredIndex); if (indexMetaData != null) { mdBuilder.put(indexMetaData, false); } } } // Filter our metadata that shouldn't be returned by API for(ObjectObjectCursor<String, Custom> custom : currentState.metaData().customs()) { if(!custom.value.context().contains(MetaData.XContentContext.API)) { mdBuilder.removeCustom(custom.key); } } builder.metaData(mdBuilder); } if (request.customs()) { builder.customs(currentState.customs()); } listener.onResponse(new ClusterStateResponse(currentState.getClusterName(), builder.build(), serializeFullClusterState(currentState, Version.CURRENT).length())); } }