Skip to content

Commit 0d969d2

Browse files
ikiboikibo
authored andcommitted
Support switch aliases in shrink action.
Signed-off-by: Oleg Kravchuk <oleg.ikibo@gmail.com>
1 parent 6aad0be commit 0d969d2

File tree

8 files changed

+235
-13
lines changed

8 files changed

+235
-13
lines changed

src/main/kotlin/org/opensearch/indexmanagement/indexstatemanagement/action/ShrinkAction.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ class ShrinkAction(
2828
val percentageOfSourceShards: Double?,
2929
val targetIndexTemplate: Script?,
3030
val aliases: List<Alias>?,
31+
val switchAliases: Boolean = false,
3132
val forceUnsafe: Boolean?,
3233
index: Int
3334
) : Action(name, index) {
@@ -104,6 +105,7 @@ class ShrinkAction(
104105
if (percentageOfSourceShards != null) builder.field(PERCENTAGE_OF_SOURCE_SHARDS_FIELD, percentageOfSourceShards)
105106
if (targetIndexTemplate != null) builder.field(TARGET_INDEX_TEMPLATE_FIELD, targetIndexTemplate)
106107
if (aliases != null) { builder.aliasesField(aliases) }
108+
builder.field(SWITCH_ALIASES, switchAliases)
107109
if (forceUnsafe != null) builder.field(FORCE_UNSAFE_FIELD, forceUnsafe)
108110
builder.endObject()
109111
}
@@ -120,6 +122,7 @@ class ShrinkAction(
120122
} else {
121123
out.writeBoolean(false)
122124
}
125+
out.writeBoolean(switchAliases)
123126
out.writeOptionalBoolean(forceUnsafe)
124127
out.writeInt(actionIndex)
125128
}
@@ -131,6 +134,7 @@ class ShrinkAction(
131134
const val MAX_SHARD_SIZE_FIELD = "max_shard_size"
132135
const val TARGET_INDEX_TEMPLATE_FIELD = "target_index_name_template"
133136
const val ALIASES_FIELD = "aliases"
137+
const val SWITCH_ALIASES = "switch_aliases"
134138
const val FORCE_UNSAFE_FIELD = "force_unsafe"
135139
const val LOCK_SOURCE_JOB_ID = "shrink-node_name"
136140
fun getSecurityFailureMessage(failure: String) = "Shrink action failed because of missing permissions: $failure"

src/main/kotlin/org/opensearch/indexmanagement/indexstatemanagement/action/ShrinkActionParser.kt

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import org.opensearch.indexmanagement.indexstatemanagement.action.ShrinkAction.C
1515
import org.opensearch.indexmanagement.indexstatemanagement.action.ShrinkAction.Companion.MAX_SHARD_SIZE_FIELD
1616
import org.opensearch.indexmanagement.indexstatemanagement.action.ShrinkAction.Companion.NUM_NEW_SHARDS_FIELD
1717
import org.opensearch.indexmanagement.indexstatemanagement.action.ShrinkAction.Companion.PERCENTAGE_OF_SOURCE_SHARDS_FIELD
18+
import org.opensearch.indexmanagement.indexstatemanagement.action.ShrinkAction.Companion.SWITCH_ALIASES
1819
import org.opensearch.indexmanagement.indexstatemanagement.action.ShrinkAction.Companion.TARGET_INDEX_TEMPLATE_FIELD
1920
import org.opensearch.indexmanagement.spi.indexstatemanagement.Action
2021
import org.opensearch.indexmanagement.spi.indexstatemanagement.ActionParser
@@ -27,10 +28,11 @@ class ShrinkActionParser : ActionParser() {
2728
val percentageOfSourceShards = sin.readOptionalDouble()
2829
val targetIndexTemplate = if (sin.readBoolean()) Script(sin) else null
2930
val aliases = if (sin.readBoolean()) sin.readList(::Alias) else null
31+
val switchAliases = sin.readBoolean()
3032
val forceUnsafe = sin.readOptionalBoolean()
3133
val index = sin.readInt()
3234

33-
return ShrinkAction(numNewShards, maxShardSize, percentageOfSourceShards, targetIndexTemplate, aliases, forceUnsafe, index)
35+
return ShrinkAction(numNewShards, maxShardSize, percentageOfSourceShards, targetIndexTemplate, aliases, switchAliases, forceUnsafe, index)
3436
}
3537

3638
@Suppress("NestedBlockDepth")
@@ -40,6 +42,7 @@ class ShrinkActionParser : ActionParser() {
4042
var percentageOfSourceShards: Double? = null
4143
var targetIndexTemplate: Script? = null
4244
var aliases: List<Alias>? = null
45+
var switchAliases = false
4346
var forceUnsafe: Boolean? = null
4447

4548
ensureExpectedToken(XContentParser.Token.START_OBJECT, xcp.currentToken(), xcp)
@@ -63,12 +66,13 @@ class ShrinkActionParser : ActionParser() {
6366
}
6467
}
6568
}
69+
SWITCH_ALIASES -> switchAliases = xcp.booleanValue()
6670
FORCE_UNSAFE_FIELD -> forceUnsafe = xcp.booleanValue()
6771
else -> throw IllegalArgumentException("Invalid field: [$fieldName] found in ShrinkAction.")
6872
}
6973
}
7074

71-
return ShrinkAction(numNewShards, maxShardSize, percentageOfSourceShards, targetIndexTemplate, aliases, forceUnsafe, index)
75+
return ShrinkAction(numNewShards, maxShardSize, percentageOfSourceShards, targetIndexTemplate, aliases, switchAliases, forceUnsafe, index)
7276
}
7377

7478
override fun getActionType(): String {

src/main/kotlin/org/opensearch/indexmanagement/indexstatemanagement/step/shrink/WaitForShrinkStep.kt

Lines changed: 71 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,23 @@
55

66
package org.opensearch.indexmanagement.indexstatemanagement.step.shrink
77

8+
import org.opensearch.action.admin.indices.alias.IndicesAliasesRequest
9+
import org.opensearch.action.admin.indices.alias.IndicesAliasesRequest.AliasActions
810
import org.opensearch.action.admin.indices.stats.IndicesStatsRequest
911
import org.opensearch.action.admin.indices.stats.IndicesStatsResponse
1012
import org.opensearch.action.support.master.AcknowledgedResponse
1113
import org.opensearch.client.Client
1214
import org.opensearch.cluster.service.ClusterService
1315
import org.opensearch.common.settings.Settings
1416
import org.opensearch.indexmanagement.indexstatemanagement.action.ShrinkAction
15-
import org.opensearch.indexmanagement.indexstatemanagement.util.resetReadOnlyAndRouting
1617
import org.opensearch.indexmanagement.indexstatemanagement.util.deleteShrinkLock
1718
import org.opensearch.indexmanagement.indexstatemanagement.util.getActionStartTime
1819
import org.opensearch.indexmanagement.indexstatemanagement.util.issueUpdateSettingsRequest
20+
import org.opensearch.indexmanagement.indexstatemanagement.util.resetReadOnlyAndRouting
1921
import org.opensearch.indexmanagement.opensearchapi.suspendUntil
2022
import org.opensearch.indexmanagement.spi.indexstatemanagement.model.ActionProperties
2123
import org.opensearch.indexmanagement.spi.indexstatemanagement.model.ManagedIndexMetaData
24+
import org.opensearch.indexmanagement.spi.indexstatemanagement.model.ShrinkActionProperties
2225
import org.opensearch.indexmanagement.spi.indexstatemanagement.model.StepContext
2326
import org.opensearch.indexmanagement.spi.indexstatemanagement.model.StepMetaData
2427
import java.time.Duration
@@ -45,8 +48,15 @@ class WaitForShrinkStep(private val action: ShrinkAction) : ShrinkStep(name, tru
4548
if (!deleteShrinkLock(localShrinkActionProperties, context.lockService, logger)) {
4649
logger.error("Failed to delete Shrink action lock on node [${localShrinkActionProperties.nodeName}]")
4750
}
48-
stepStatus = StepStatus.COMPLETED
49-
info = mapOf("message" to SUCCESS_MESSAGE)
51+
52+
if (switchAliases(context, localShrinkActionProperties)) {
53+
stepStatus = StepStatus.COMPLETED
54+
info = mapOf("message" to SUCCESS_MESSAGE)
55+
} else {
56+
stepStatus = StepStatus.FAILED
57+
info = mapOf("message" to "Shrink failed due to aliases switch failure.")
58+
}
59+
5060
return this
5161
}
5262

@@ -91,6 +101,64 @@ class WaitForShrinkStep(private val action: ShrinkAction) : ShrinkStep(name, tru
91101
}
92102
}
93103

104+
private suspend fun switchAliases(context: StepContext, shrinkActionProperties: ShrinkActionProperties): Boolean {
105+
106+
val sourceIndexName = context.metadata.index
107+
val targetIndexName = shrinkActionProperties.targetIndexName
108+
109+
if (!action.switchAliases) {
110+
logger.info("Switch aliases disabled from [$sourceIndexName] to [$targetIndexName].")
111+
return true
112+
}
113+
114+
logger.info("Switching aliases from [$sourceIndexName] to [$targetIndexName].")
115+
116+
val targetIndexAliasesNames = context
117+
.clusterService
118+
.state()
119+
.metadata()
120+
.index(targetIndexName)
121+
.aliases
122+
.keys
123+
val sourceIndexAliases = context
124+
.clusterService
125+
.state()
126+
.metadata()
127+
.index(sourceIndexName)
128+
.aliases
129+
.values
130+
131+
val req = IndicesAliasesRequest()
132+
sourceIndexAliases.map { it.alias }.forEach { req.addAliasAction(AliasActions(AliasActions.Type.REMOVE).index(sourceIndexName).alias(it)) }
133+
134+
sourceIndexAliases
135+
.filterNot { targetIndexAliasesNames.contains(it.alias) }
136+
.map {
137+
AliasActions(AliasActions.Type.ADD)
138+
.index(targetIndexName)
139+
.alias(it.alias)
140+
.filter(it.filter?.string())
141+
.indexRouting(it.indexRouting)
142+
.searchRouting(it.searchRouting)
143+
.isHidden(it.isHidden)
144+
.writeIndex(it.writeIndex())
145+
}
146+
.forEach { req.addAliasAction(it) }
147+
148+
return try {
149+
val response: AcknowledgedResponse = context.client.admin().indices().suspendUntil { aliases(req, it) }
150+
if (response.isAcknowledged) {
151+
logger.info("Aliases switched successfully from [$sourceIndexName] to [$targetIndexName].")
152+
return true
153+
}
154+
logger.error("Switching aliases from [$sourceIndexName] to [$targetIndexName] failed.")
155+
return false
156+
} catch (e: Exception) {
157+
logger.error("Switching aliases from [$sourceIndexName] to [$targetIndexName] failed due to exception.", e)
158+
false
159+
}
160+
}
161+
94162
override fun getUpdatedManagedIndexMetadata(currentMetadata: ManagedIndexMetaData): ManagedIndexMetaData {
95163
return currentMetadata.copy(
96164
actionMetaData = currentMetadata.actionMetaData?.copy(

src/main/resources/mappings/opendistro-ism-config.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"_meta" : {
3-
"schema_version": 20
3+
"schema_version": 21
44
},
55
"dynamic": "strict",
66
"properties": {
@@ -551,6 +551,9 @@
551551
"type": "object",
552552
"enabled": false
553553
},
554+
"switch_aliases": {
555+
"type": "boolean"
556+
},
554557
"force_unsafe": {
555558
"type": "boolean"
556559
}

src/test/kotlin/org/opensearch/indexmanagement/IndexManagementRestTestCase.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ import javax.management.remote.JMXServiceURL
4242

4343
abstract class IndexManagementRestTestCase : ODFERestTestCase() {
4444

45-
val configSchemaVersion = 20
45+
val configSchemaVersion = 21
4646
val historySchemaVersion = 7
4747

4848
// Having issues with tests leaking into other tests and mappings being incorrect and they are not caught by any pending task wait check as

src/test/kotlin/org/opensearch/indexmanagement/indexstatemanagement/TestHelpers.kt

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -152,16 +152,17 @@ fun randomShrinkAction(
152152
percentageOfSourceShards: Double? = null,
153153
targetIndexTemplate: Script? = if (randomBoolean()) randomTemplateScript(randomAlphaOfLength(10)) else null,
154154
aliases: List<Alias>? = if (randomBoolean()) randomList(10) { randomAlias() } else null,
155+
switchAliases: Boolean = randomBoolean(),
155156
forceUnsafe: Boolean? = if (randomBoolean()) randomBoolean() else null
156157
): ShrinkAction {
157158
if (numNewShards == null && maxShardSize == null && percentageOfSourceShards == null) {
158159
when (randomInt(2)) {
159-
0 -> return ShrinkAction(abs(randomInt()) + 1, null, null, targetIndexTemplate, aliases, forceUnsafe, 0)
160-
1 -> return ShrinkAction(null, randomByteSizeValue(), null, targetIndexTemplate, aliases, forceUnsafe, 0)
161-
2 -> return ShrinkAction(null, null, randomDoubleBetween(0.0, 1.0, true), targetIndexTemplate, aliases, forceUnsafe, 0)
160+
0 -> return ShrinkAction(abs(randomInt()) + 1, null, null, targetIndexTemplate, aliases, switchAliases, forceUnsafe, 0)
161+
1 -> return ShrinkAction(null, randomByteSizeValue(), null, targetIndexTemplate, aliases, switchAliases, forceUnsafe, 0)
162+
2 -> return ShrinkAction(null, null, randomDoubleBetween(0.0, 1.0, true), targetIndexTemplate, aliases, switchAliases, forceUnsafe, 0)
162163
}
163164
}
164-
return ShrinkAction(numNewShards, maxShardSize, percentageOfSourceShards, targetIndexTemplate, aliases, forceUnsafe, 0)
165+
return ShrinkAction(numNewShards, maxShardSize, percentageOfSourceShards, targetIndexTemplate, aliases, switchAliases, forceUnsafe, 0)
165166
}
166167

167168
fun randomReadOnlyActionConfig(): ReadOnlyAction {

0 commit comments

Comments
 (0)