/* * 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. */ /* * 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. */ /* * Modifications Copyright OpenSearch Contributors. See * GitHub history for details. */ package org.opensearch.cluster.metadata; import org.opensearch.action.admin.indices.alias.IndicesAliasesRequest; import org.opensearch.common.Nullable; import org.opensearch.core.common.Strings; /** * Individual operation to perform on the cluster state as part of an {@link IndicesAliasesRequest}. * * @opensearch.internal */ public abstract class AliasAction { private final String index; private AliasAction(String index) { if (false == Strings.hasText(index)) { throw new IllegalArgumentException("[index] is required"); } this.index = index; } /** * Get the index on which the operation should act. */ public String getIndex() { return index; } /** * Should this action remove the index? Actions that return true from this will never execute * {@link #apply(NewAliasValidator, Metadata.Builder, IndexMetadata)}. */ abstract boolean removeIndex(); /** * Apply the action. * * @param aliasValidator call to validate a new alias before adding it to the builder * @param metadata metadata builder for the changes made by all actions as part of this request * @param index metadata for the index being changed * @return did this action make any changes? */ abstract boolean apply(NewAliasValidator aliasValidator, Metadata.Builder metadata, IndexMetadata index); /** * Validate a new alias. * * @opensearch.internal */ @FunctionalInterface public interface NewAliasValidator { void validate(String alias, @Nullable String indexRouting, @Nullable String filter, @Nullable Boolean writeIndex); } /** * Operation to add an alias to an index. * * @opensearch.internal */ public static class Add extends AliasAction { private final String alias; @Nullable private final String filter; @Nullable private final String indexRouting; @Nullable private final String searchRouting; @Nullable private final Boolean writeIndex; @Nullable final Boolean isHidden; /** * Build the operation. */ public Add( String index, String alias, @Nullable String filter, @Nullable String indexRouting, @Nullable String searchRouting, @Nullable Boolean writeIndex, @Nullable Boolean isHidden ) { super(index); if (false == Strings.hasText(alias)) { throw new IllegalArgumentException("[alias] is required"); } this.alias = alias; this.filter = filter; this.indexRouting = indexRouting; this.searchRouting = searchRouting; this.writeIndex = writeIndex; this.isHidden = isHidden; } /** * Alias to add to the index. */ public String getAlias() { return alias; } public String getFilter() { return filter; } public String getSearchRouting() { return searchRouting; } public String getIndexRouting() { return indexRouting; } public Boolean writeIndex() { return writeIndex; } @Nullable public Boolean isHidden() { return isHidden; } @Override boolean removeIndex() { return false; } @Override boolean apply(NewAliasValidator aliasValidator, Metadata.Builder metadata, IndexMetadata index) { aliasValidator.validate(alias, indexRouting, filter, writeIndex); AliasMetadata newAliasMd = AliasMetadata.newAliasMetadataBuilder(alias) .filter(filter) .indexRouting(indexRouting) .searchRouting(searchRouting) .writeIndex(writeIndex) .isHidden(isHidden) .build(); // Check if this alias already exists AliasMetadata currentAliasMd = index.getAliases().get(alias); if (currentAliasMd != null && currentAliasMd.equals(newAliasMd)) { // It already exists, ignore it return false; } metadata.put(IndexMetadata.builder(index).putAlias(newAliasMd)); return true; } } /** * Operation to remove an alias from an index. * * @opensearch.internal */ public static class Remove extends AliasAction { private final String alias; @Nullable private final Boolean mustExist; /** * Build the operation. */ public Remove(String index, String alias, @Nullable Boolean mustExist) { super(index); if (false == Strings.hasText(alias)) { throw new IllegalArgumentException("[alias] is required"); } this.alias = alias; this.mustExist = mustExist; } /** * Alias to remove from the index. */ public String getAlias() { return alias; } @Override boolean removeIndex() { return false; } @Override boolean apply(NewAliasValidator aliasValidator, Metadata.Builder metadata, IndexMetadata index) { if (false == index.getAliases().containsKey(alias)) { if (mustExist != null && mustExist.booleanValue()) { throw new IllegalArgumentException("required alias [" + alias + "] does not exist"); } return false; } metadata.put(IndexMetadata.builder(index).removeAlias(alias)); return true; } } /** * Operation to remove an index. This is an "alias action" because it allows us to remove an index at the same time as we remove add an * alias to replace it. * * @opensearch.internal */ public static class RemoveIndex extends AliasAction { public RemoveIndex(String index) { super(index); } @Override boolean removeIndex() { return true; } @Override boolean apply(NewAliasValidator aliasValidator, Metadata.Builder metadata, IndexMetadata index) { throw new UnsupportedOperationException(); } } }