Skip to content

Commit

Permalink
Error Prevention: Add transition action (opensearch-project#744)
Browse files Browse the repository at this point in the history
* Error Prevention: Add transition action

Signed-off-by: Angie Zhang <[email protected]>

* Fixed detekt

Signed-off-by: Angie Zhang <[email protected]>

* Added return false

Signed-off-by: Angie Zhang <[email protected]>

* Fixed detekt

Signed-off-by: Angie Zhang <[email protected]>

---------

Signed-off-by: Angie Zhang <[email protected]>
  • Loading branch information
Angie Zhang authored Apr 14, 2023
1 parent 363086f commit 3cf8668
Show file tree
Hide file tree
Showing 3 changed files with 142 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ class ActionValidation(
val jvmService: JvmService
) {

@Suppress("ComplexMethod")
fun validate(actionName: String, indexName: String): ValidationResult {
// map action to validation class
val validation = when (actionName) {
Expand All @@ -28,6 +29,7 @@ class ActionValidation(
"read_only" -> ValidateReadOnly(settings, clusterService, jvmService).execute(indexName)
"read_write" -> ValidateReadWrite(settings, clusterService, jvmService).execute(indexName)
"replica_count" -> ValidateReplicaCount(settings, clusterService, jvmService).execute(indexName)
"transition" -> ValidateTransition(settings, clusterService, jvmService).execute(indexName)
"close" -> ValidateClose(settings, clusterService, jvmService).execute(indexName)
"index_priority" -> ValidateIndexPriority(settings, clusterService, jvmService).execute(indexName)
// No validations for these actions at current stage.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

package org.opensearch.indexmanagement.indexstatemanagement.validation

import org.apache.logging.log4j.LogManager
import org.opensearch.cluster.metadata.MetadataCreateIndexService
import org.opensearch.cluster.service.ClusterService
import org.opensearch.common.settings.Settings
import org.opensearch.indexmanagement.spi.indexstatemanagement.Validate
import org.opensearch.indexmanagement.util.OpenForTesting
import org.opensearch.indices.InvalidIndexNameException
import org.opensearch.monitor.jvm.JvmService

@OpenForTesting
class ValidateTransition(
settings: Settings,
clusterService: ClusterService,
jvmService: JvmService
) : Validate(settings, clusterService, jvmService) {

private val logger = LogManager.getLogger(javaClass)

@Suppress("ReturnSuppressCount", "ReturnCount")
override fun execute(indexName: String): Validate {
// if these conditions are false, fail validation and do not execute transition action
if (!indexExists(indexName) || !validIndex(indexName)) {
return this
}
validationMessage = getValidationPassedMessage(indexName)
return this
}

private fun indexExists(indexName: String): Boolean {
val isIndexExists = clusterService.state().metadata.indices.containsKey(indexName)
if (!isIndexExists) {
val message = getNoIndexMessage(indexName)
logger.warn(message)
validationStatus = ValidationStatus.RE_VALIDATING
validationMessage = message
return false
}
return true
}

private fun validIndex(indexName: String): Boolean {
val exceptionGenerator: (String, String) -> RuntimeException = { index_name, reason -> InvalidIndexNameException(index_name, reason) }
// If the index name is invalid for any reason, this will throw an exception giving the reason why in the message.
// That will be displayed to the user as the cause.
try {
MetadataCreateIndexService.validateIndexOrAliasName(indexName, exceptionGenerator)
} catch (e: Exception) {
val message = getIndexNotValidMessage(indexName)
logger.warn(message)
validationStatus = ValidationStatus.RE_VALIDATING
validationMessage = message
return false
}
return true
}

@Suppress("TooManyFunctions")
companion object {
const val name = "validate_transition"
fun getNoIndexMessage(index: String) = "Index [index=$index] does not exist for transition"
fun getIndexNotValidMessage(index: String) = "Index [index=$index] is not valid for transition"
fun getValidationPassedMessage(index: String) = "Transition action validation passed for [index=$index]"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

package org.opensearch.indexmanagement.indexstatemanagement.validation

import org.opensearch.indexmanagement.indexstatemanagement.IndexStateManagementRestTestCase
import org.opensearch.indexmanagement.indexstatemanagement.model.Conditions
import org.opensearch.indexmanagement.indexstatemanagement.model.Policy
import org.opensearch.indexmanagement.indexstatemanagement.model.State
import org.opensearch.indexmanagement.indexstatemanagement.model.Transition
import org.opensearch.indexmanagement.indexstatemanagement.randomErrorNotification
import org.opensearch.indexmanagement.spi.indexstatemanagement.Validate
import org.opensearch.indexmanagement.waitFor
import java.time.Instant
import java.time.temporal.ChronoUnit
import java.util.Locale

class ValidateTransitionIT : IndexStateManagementRestTestCase() {

private val testIndexName = javaClass.simpleName.lowercase(Locale.ROOT)

fun `test transition validation with doc count condition`() {
enableValidationService()
val indexName = "${testIndexName}_index_1"
val policyID = "${testIndexName}_testPolicyName_1"
val secondStateName = "second"
val states = listOf(
State("first", listOf(), listOf(Transition(secondStateName, Conditions(docCount = 5L)))),
State(secondStateName, listOf(), listOf())
)

val policy = Policy(
id = policyID,
description = "$testIndexName description",
schemaVersion = 1L,
lastUpdatedTime = Instant.now().truncatedTo(ChronoUnit.MILLIS),
errorNotification = randomErrorNotification(),
defaultState = states[0].name,
states = states
)

createPolicy(policy, policyID)
createIndex(indexName, policyID)

val managedIndexConfig = getExistingManagedIndexConfig(indexName)

// Initializing the policy/metadata
updateManagedIndexConfigStartTime(managedIndexConfig)

waitFor { assertEquals(policyID, getExplainManagedIndexMetaData(indexName).policyID) }

// Add 6 documents (>5)
insertSampleData(indexName, 6)

// Evaluating transition conditions for second time
updateManagedIndexConfigStartTime(managedIndexConfig)

waitFor {
val data = getExplainValidationResult(indexName)
assertEquals(
"Index transition validation status is PASSED.",
Validate.ValidationStatus.PASSED,
data.validationStatus
)
}
}
}

0 comments on commit 3cf8668

Please sign in to comment.