Skip to content

Commit 5429476

Browse files
Tarun KishoreTarun-kishore
authored andcommitted
Added no_alias condition check for ISM
Signed-off-by: Tarun-kishore <[email protected]>
1 parent ca0416c commit 5429476

File tree

4 files changed

+100
-3
lines changed

4 files changed

+100
-3
lines changed

src/main/kotlin/org/opensearch/indexmanagement/indexstatemanagement/model/Transition.kt

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,10 +80,11 @@ data class Conditions(
8080
val size: ByteSizeValue? = null,
8181
val cron: CronSchedule? = null,
8282
val rolloverAge: TimeValue? = null,
83+
val noAlias: Boolean? = null,
8384
) : ToXContentObject,
8485
Writeable {
8586
init {
86-
val conditionsList = listOf(indexAge, docCount, size, cron, rolloverAge)
87+
val conditionsList = listOf(indexAge, docCount, size, cron, rolloverAge, noAlias)
8788
require(conditionsList.filterNotNull().size == 1) { "Cannot provide more than one Transition condition" }
8889

8990
// Validate doc count condition
@@ -100,6 +101,7 @@ data class Conditions(
100101
if (size != null) builder.field(MIN_SIZE_FIELD, size.stringRep)
101102
if (cron != null) builder.field(CRON_FIELD, cron)
102103
if (rolloverAge != null) builder.field(MIN_ROLLOVER_AGE_FIELD, rolloverAge.stringRep)
104+
if (noAlias != null) builder.field(NO_ALIAS_FIELD, noAlias)
103105
return builder.endObject()
104106
}
105107

@@ -110,6 +112,7 @@ data class Conditions(
110112
size = sin.readOptionalWriteable(::ByteSizeValue),
111113
cron = sin.readOptionalWriteable(::CronSchedule),
112114
rolloverAge = sin.readOptionalTimeValue(),
115+
noAlias = sin.readOptionalBoolean(),
113116
)
114117

115118
@Throws(IOException::class)
@@ -119,6 +122,7 @@ data class Conditions(
119122
out.writeOptionalWriteable(size)
120123
out.writeOptionalWriteable(cron)
121124
out.writeOptionalTimeValue(rolloverAge)
125+
out.writeOptionalBoolean(noAlias)
122126
}
123127

124128
companion object {
@@ -127,6 +131,7 @@ data class Conditions(
127131
const val MIN_SIZE_FIELD = "min_size"
128132
const val CRON_FIELD = "cron"
129133
const val MIN_ROLLOVER_AGE_FIELD = "min_rollover_age"
134+
const val NO_ALIAS_FIELD = "no_alias"
130135

131136
@JvmStatic
132137
@Throws(IOException::class)
@@ -136,6 +141,7 @@ data class Conditions(
136141
var size: ByteSizeValue? = null
137142
var cron: CronSchedule? = null
138143
var rolloverAge: TimeValue? = null
144+
var noAlias: Boolean? = null
139145

140146
ensureExpectedToken(Token.START_OBJECT, xcp.currentToken(), xcp)
141147
while (xcp.nextToken() != Token.END_OBJECT) {
@@ -148,11 +154,12 @@ data class Conditions(
148154
MIN_SIZE_FIELD -> size = ByteSizeValue.parseBytesSizeValue(xcp.text(), MIN_SIZE_FIELD)
149155
CRON_FIELD -> cron = ScheduleParser.parse(xcp) as? CronSchedule
150156
MIN_ROLLOVER_AGE_FIELD -> rolloverAge = TimeValue.parseTimeValue(xcp.text(), MIN_ROLLOVER_AGE_FIELD)
157+
NO_ALIAS_FIELD -> noAlias = xcp.booleanValue()
151158
else -> throw IllegalArgumentException("Invalid field: [$fieldName] found in Conditions.")
152159
}
153160
}
154161

155-
return Conditions(indexAge, docCount, size, cron, rolloverAge)
162+
return Conditions(indexAge, docCount, size, cron, rolloverAge, noAlias)
156163
}
157164
}
158165
}

src/main/kotlin/org/opensearch/indexmanagement/indexstatemanagement/step/transition/AttemptTransitionStep.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,9 +100,10 @@ class AttemptTransitionStep(private val action: TransitionsAction) : Step(name)
100100
}
101101

102102
// Find the first transition that evaluates to true and get the state to transition to, otherwise return null if none are true
103+
val indexAliasesCount = indexMetadata?.aliases?.size ?: 0
103104
stateName =
104105
transitions.find {
105-
it.evaluateConditions(indexCreationDateInstant, numDocs, indexSize, stepStartTime, rolloverDate)
106+
it.evaluateConditions(indexCreationDateInstant, numDocs, indexSize, stepStartTime, rolloverDate, indexAliasesCount)
106107
}?.stateName
107108
val message: String
108109
val stateName = stateName // shadowed on purpose to prevent var from changing

src/main/kotlin/org/opensearch/indexmanagement/indexstatemanagement/util/ManagedIndexUtils.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,7 @@ fun Transition.evaluateConditions(
189189
indexSize: ByteSizeValue?,
190190
transitionStartTime: Instant,
191191
rolloverDate: Instant?,
192+
indexAliasesCount: Int? = null,
192193
): Boolean {
193194
// If there are no conditions, treat as always true
194195
if (this.conditions == null) return true
@@ -219,6 +220,11 @@ fun Transition.evaluateConditions(
219220
return this.conditions.rolloverAge.millis <= elapsedTime
220221
}
221222

223+
if (this.conditions.noAlias != null && indexAliasesCount != null) {
224+
return (this.conditions.noAlias && indexAliasesCount == 0) ||
225+
(!this.conditions.noAlias && indexAliasesCount > 0)
226+
}
227+
222228
// We should never reach this
223229
return false
224230
}

src/test/kotlin/org/opensearch/indexmanagement/indexstatemanagement/action/TransitionActionIT.kt

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,4 +147,87 @@ class TransitionActionIT : IndexStateManagementRestTestCase() {
147147
// Should have evaluated to true
148148
waitFor { assertEquals(AttemptTransitionStep.getSuccessMessage(indexName, secondStateName), getExplainManagedIndexMetaData(indexName).info?.get("message")) }
149149
}
150+
151+
fun `test noAlias transition condition`() {
152+
val indexName = "${testIndexName}_no_alias"
153+
val policyID = "${testIndexName}_no_alias_policy"
154+
val secondStateName = "second"
155+
val states =
156+
listOf(
157+
State("first", listOf(), listOf(Transition(secondStateName, Conditions(noAlias = true)))),
158+
State(secondStateName, listOf(), listOf()),
159+
)
160+
161+
val policy =
162+
Policy(
163+
id = policyID,
164+
description = "$testIndexName description",
165+
schemaVersion = 1L,
166+
lastUpdatedTime = Instant.now().truncatedTo(ChronoUnit.MILLIS),
167+
errorNotification = randomErrorNotification(),
168+
defaultState = states[0].name,
169+
states = states,
170+
)
171+
172+
createPolicy(policy, policyID)
173+
createIndex(indexName, policyID)
174+
175+
val managedIndexConfig = getExistingManagedIndexConfig(indexName)
176+
177+
// Initializing the policy/metadata
178+
updateManagedIndexConfigStartTime(managedIndexConfig)
179+
180+
waitFor { assertEquals(policyID, getExplainManagedIndexMetaData(indexName).policyID) }
181+
182+
// Evaluating transition conditions for first time (should succeed, no alias)
183+
updateManagedIndexConfigStartTime(managedIndexConfig)
184+
waitFor { assertEquals(AttemptTransitionStep.getSuccessMessage(indexName, secondStateName), getExplainManagedIndexMetaData(indexName).info?.get("message")) }
185+
186+
// Create a new index and add an alias, then attach the policy with noAlias=true (should NOT transition)
187+
val indexWithAlias = "${testIndexName}_with_alias"
188+
createIndex(indexWithAlias, policyID, "foo-alias")
189+
addPolicyToIndex(indexWithAlias, policyID)
190+
val managedIndexConfigWithAlias = getExistingManagedIndexConfig(indexWithAlias)
191+
updateManagedIndexConfigStartTime(managedIndexConfigWithAlias)
192+
waitFor { assertEquals(policyID, getExplainManagedIndexMetaData(indexWithAlias).policyID) }
193+
updateManagedIndexConfigStartTime(managedIndexConfigWithAlias)
194+
// Should not transition because alias exists and noAlias=true
195+
waitFor { assertEquals(AttemptTransitionStep.getEvaluatingMessage(indexWithAlias), getExplainManagedIndexMetaData(indexWithAlias).info?.get("message")) }
196+
197+
// Now test noAlias=false: should transition if alias exists
198+
val indexWithAlias2 = "${indexWithAlias}_2"
199+
val policyIDWithNoAliasFalse = "${testIndexName}_no_alias_false_policy"
200+
val statesWithNoAliasFalse =
201+
listOf(
202+
State("first", listOf(), listOf(Transition(secondStateName, Conditions(noAlias = false)))),
203+
State(secondStateName, listOf(), listOf()),
204+
)
205+
val policyWithAlias =
206+
Policy(
207+
id = policyIDWithNoAliasFalse,
208+
description = "$testIndexName description",
209+
schemaVersion = 1L,
210+
lastUpdatedTime = Instant.now().truncatedTo(ChronoUnit.MILLIS),
211+
errorNotification = randomErrorNotification(),
212+
defaultState = statesWithNoAliasFalse[0].name,
213+
states = statesWithNoAliasFalse,
214+
)
215+
createPolicy(policyWithAlias, policyIDWithNoAliasFalse)
216+
waitFor { assertNotNull(getPolicy(policyIDWithNoAliasFalse)) }
217+
createIndex(indexWithAlias2, policyIDWithNoAliasFalse, "foo-alias-2")
218+
addPolicyToIndex(indexWithAlias2, policyIDWithNoAliasFalse)
219+
val managedIndexConfigWithAlias2 = getExistingManagedIndexConfig(indexWithAlias2)
220+
updateManagedIndexConfigStartTime(managedIndexConfigWithAlias2)
221+
waitFor { assertEquals(policyIDWithNoAliasFalse, getExplainManagedIndexMetaData(indexWithAlias2).policyID) }
222+
updateManagedIndexConfigStartTime(managedIndexConfigWithAlias2)
223+
// Should transition because alias exists and noAlias=false
224+
waitFor {
225+
assertEquals(
226+
AttemptTransitionStep.getSuccessMessage(indexWithAlias2, secondStateName),
227+
getExplainManagedIndexMetaData(
228+
indexWithAlias2,
229+
).info?.get("message"),
230+
)
231+
}
232+
}
150233
}

0 commit comments

Comments
 (0)