/* * SPDX-License-Identifier: Apache-2.0 * * The OpenSearch Contributors require contributions made to * this file be licensed under the Apache-2.0 license or a * compatible open source license. * * Modifications Copyright OpenSearch Contributors. See * GitHub history for details. */ package org.opensearch.ad.util; import java.util.List; import java.util.Locale; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.opensearch.action.support.IndicesOptions; import org.opensearch.client.Client; import org.opensearch.cluster.ClusterState; import org.opensearch.cluster.block.ClusterBlockLevel; import org.opensearch.cluster.health.ClusterIndexHealth; import org.opensearch.cluster.metadata.IndexMetadata; import org.opensearch.cluster.metadata.IndexNameExpressionResolver; import org.opensearch.cluster.service.ClusterService; import org.opensearch.common.inject.Inject; import org.opensearch.timeseries.util.ClientUtil; public class IndexUtils { /** * Status string of index that does not exist */ public static final String NONEXISTENT_INDEX_STATUS = "non-existent"; /** * Status string when an alias exists, but does not point to an index */ public static final String ALIAS_EXISTS_NO_INDICES_STATUS = "alias exists, but does not point to any indices"; public static final String ALIAS_POINTS_TO_MULTIPLE_INDICES_STATUS = "alias exists, but does not point to any " + "indices"; private static final Logger logger = LogManager.getLogger(IndexUtils.class); private Client client; private ClientUtil clientUtil; private ClusterService clusterService; private final IndexNameExpressionResolver indexNameExpressionResolver; /** * Inject annotation required by Guice to instantiate EntityResultTransportAction (transitive dependency) * * @param client Client to make calls to OpenSearch * @param clientUtil AD Client utility * @param clusterService ES ClusterService * @param indexNameExpressionResolver index name resolver */ @Inject public IndexUtils( Client client, ClientUtil clientUtil, ClusterService clusterService, IndexNameExpressionResolver indexNameExpressionResolver ) { this.client = client; this.clientUtil = clientUtil; this.clusterService = clusterService; this.indexNameExpressionResolver = indexNameExpressionResolver; } /** * Gets the cluster index health for a particular index or the index an alias points to * * If an alias is passed in, it will only return the health status of an index it points to if it only points to a * single index. If it points to multiple indices, it will throw an exception. * * @param indexOrAliasName String of the index or alias name to get health of. * @return String represents the status of the index: "red", "yellow" or "green" * @throws IllegalArgumentException Thrown when an alias is passed in that points to more than one index */ public String getIndexHealthStatus(String indexOrAliasName) throws IllegalArgumentException { if (!clusterService.state().getRoutingTable().hasIndex(indexOrAliasName)) { // Check if the index is actually an alias if (clusterService.state().metadata().hasAlias(indexOrAliasName)) { // List of all indices the alias refers to List indexMetaDataList = clusterService .state() .metadata() .getIndicesLookup() .get(indexOrAliasName) .getIndices(); if (indexMetaDataList.size() == 0) { return ALIAS_EXISTS_NO_INDICES_STATUS; } else if (indexMetaDataList.size() > 1) { throw new IllegalArgumentException("Cannot get health for alias that points to multiple indices"); } else { indexOrAliasName = indexMetaDataList.get(0).getIndex().getName(); } } else { return NONEXISTENT_INDEX_STATUS; } } ClusterIndexHealth indexHealth = new ClusterIndexHealth( clusterService.state().metadata().index(indexOrAliasName), clusterService.state().getRoutingTable().index(indexOrAliasName) ); return indexHealth.getStatus().name().toLowerCase(Locale.ROOT); } /** * Similar to checkGlobalBlock, we check block on the indices level. * * @param state Cluster state * @param level block level * @param indices the indices on which to check block * @return whether any of the index has block on the level. */ public boolean checkIndicesBlocked(ClusterState state, ClusterBlockLevel level, String... indices) { // the original index might be an index expression with wildcards like "log*", // so we need to expand the expression to concrete index name String[] concreteIndices = indexNameExpressionResolver.concreteIndexNames(state, IndicesOptions.lenientExpandOpen(), indices); return state.blocks().indicesBlockedException(level, concreteIndices) != null; } }