/* * Copyright OpenSearch Contributors * SPDX-License-Identifier: Apache-2.0 */ @file:Suppress("TopLevelPropertyNaming", "MatchingDeclarationName") package org.opensearch.indexmanagement.indexstatemanagement.util import org.apache.logging.log4j.Logger import org.opensearch.OpenSearchParseException import org.opensearch.action.support.clustermanager.ClusterManagerNodeRequest import org.opensearch.action.support.master.AcknowledgedResponse import org.opensearch.client.Client import org.opensearch.core.common.io.stream.StreamInput import org.opensearch.core.common.io.stream.StreamOutput import org.opensearch.core.common.io.stream.Writeable import org.opensearch.common.logging.DeprecationLogger import org.opensearch.common.unit.TimeValue import org.opensearch.core.xcontent.ToXContent import org.opensearch.core.xcontent.ToXContentFragment import org.opensearch.core.xcontent.XContentBuilder import org.opensearch.common.xcontent.XContentFactory import org.opensearch.core.index.Index import org.opensearch.indexmanagement.indexstatemanagement.model.ChangePolicy import org.opensearch.indexmanagement.indexstatemanagement.model.ManagedIndexConfig import org.opensearch.indexmanagement.indexstatemanagement.transport.action.updateindexmetadata.UpdateManagedIndexMetaDataAction import org.opensearch.indexmanagement.indexstatemanagement.transport.action.updateindexmetadata.UpdateManagedIndexMetaDataRequest import org.opensearch.indexmanagement.opensearchapi.optionalTimeField import org.opensearch.indexmanagement.opensearchapi.suspendUntil import org.opensearch.rest.RestRequest import java.lang.Exception import java.time.Instant const val WITH_TYPE = "with_type" const val WITH_USER = "with_user" val XCONTENT_WITHOUT_TYPE = ToXContent.MapParams(mapOf(WITH_TYPE to "false")) val XCONTENT_WITHOUT_USER = ToXContent.MapParams(mapOf(WITH_USER to "false")) val XCONTENT_WITHOUT_TYPE_AND_USER = ToXContent.MapParams(mapOf(WITH_TYPE to "false", WITH_USER to "false")) const val FAILURES = "failures" const val FAILED_INDICES = "failed_indices" const val UPDATED_INDICES = "updated_indices" const val TOTAL_MANAGED_INDICES = "total_managed_indices" const val ISM_TEMPLATE_FIELD = "policy.ism_template" const val MANAGED_INDEX_FIELD = "managed_index" const val MANAGED_INDEX_NAME_KEYWORD_FIELD = "$MANAGED_INDEX_FIELD.name.keyword" const val MANAGED_INDEX_INDEX_FIELD = "$MANAGED_INDEX_FIELD.index" const val MANAGED_INDEX_INDEX_UUID_FIELD = "$MANAGED_INDEX_FIELD.index_uuid" const val DEFAULT_JOB_SORT_FIELD = MANAGED_INDEX_INDEX_FIELD const val DEFAULT_POLICY_SORT_FIELD = "policy.policy_id.keyword" const val SHOW_POLICY_QUERY_PARAM = "show_policy" const val DEFAULT_EXPLAIN_SHOW_POLICY = false const val SHOW_VALIDATE_ACTION = "validate_action" const val DEFAULT_EXPLAIN_VALIDATE_ACTION = false const val INDEX_HIDDEN = "index.hidden" const val INDEX_NUMBER_OF_SHARDS = "index.number_of_shards" const val INDEX_NUMBER_OF_REPLICAS = "index.number_of_replicas" const val TYPE_PARAM_KEY = "type" const val DEFAULT_INDEX_TYPE = "_default" fun buildInvalidIndexResponse(builder: XContentBuilder, failedIndices: List<FailedIndex>) { if (failedIndices.isNotEmpty()) { builder.field(FAILURES, true) builder.startArray(FAILED_INDICES) for (failedIndex in failedIndices) { failedIndex.toXContent(builder, ToXContent.EMPTY_PARAMS) } builder.endArray() } else { builder.field(FAILURES, false) builder.startArray(FAILED_INDICES).endArray() } } data class FailedIndex(val name: String, val uuid: String, val reason: String) : Writeable, ToXContentFragment { override fun toXContent(builder: XContentBuilder, params: ToXContent.Params): XContentBuilder { builder.startObject() .field(INDEX_NAME_FIELD, name) .field(INDEX_UUID_FIELD, uuid) .field(REASON_FIELD, reason) return builder.endObject() } companion object { const val INDEX_NAME_FIELD = "index_name" const val INDEX_UUID_FIELD = "index_uuid" const val REASON_FIELD = "reason" } constructor(sin: StreamInput) : this( name = sin.readString(), uuid = sin.readString(), reason = sin.readString() ) override fun writeTo(out: StreamOutput) { out.writeString(name) out.writeString(uuid) out.writeString(reason) } } /** * Gets the XContentBuilder for partially updating a [ManagedIndexConfig]'s ChangePolicy */ fun getPartialChangePolicyBuilder( changePolicy: ChangePolicy? ): XContentBuilder { val builder = XContentFactory.jsonBuilder() .startObject() .startObject(ManagedIndexConfig.MANAGED_INDEX_TYPE) .optionalTimeField(ManagedIndexConfig.LAST_UPDATED_TIME_FIELD, Instant.now()) .field(ManagedIndexConfig.CHANGE_POLICY_FIELD, changePolicy) return builder.endObject().endObject() } /** * Removes the managed index metadata from the cluster state for the the provided indices. */ suspend fun removeClusterStateMetadatas(client: Client, logger: Logger, indices: List<Index>) { val request = UpdateManagedIndexMetaDataRequest(indicesToRemoveManagedIndexMetaDataFrom = indices) try { val response: AcknowledgedResponse = client.suspendUntil { execute(UpdateManagedIndexMetaDataAction.INSTANCE, request, it) } logger.debug("Cleaned cluster state metadata for $indices, ${response.isAcknowledged}") } catch (e: Exception) { logger.error("Failed to clean cluster state metadata for $indices") } } const val MASTER_TIMEOUT_DEPRECATED_MESSAGE = "Parameter [master_timeout] is deprecated and will be removed in 3.0. " + "To support inclusive language, please use [cluster_manager_timeout] instead." const val DUPLICATE_PARAMETER_ERROR_MESSAGE = "Please only use one of the request parameters [master_timeout, cluster_manager_timeout]." fun parseClusterManagerTimeout(request: RestRequest, deprecationLogger: DeprecationLogger, restActionName: String): TimeValue { var timeout = request.paramAsTime("cluster_manager_timeout", ClusterManagerNodeRequest.DEFAULT_CLUSTER_MANAGER_NODE_TIMEOUT) if (request.hasParam("master_timeout")) { deprecationLogger.deprecate(restActionName + "_master_timeout_parameter", MASTER_TIMEOUT_DEPRECATED_MESSAGE) if (request.hasParam("cluster_manager_timeout")) { throw OpenSearchParseException(DUPLICATE_PARAMETER_ERROR_MESSAGE) } timeout = request.paramAsTime("master_timeout", timeout) } return timeout }