Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
package com.sksamuel.elastic4s.api

import com.sksamuel.elastic4s.requests.indexlifecyclemanagement.{StartIlmRequest, GetIlmStatusRequest, StopIlmRequest}
import com.sksamuel.elastic4s.requests.indexlifecyclemanagement.policy.IndexLifecyclePolicy
import com.sksamuel.elastic4s.requests.indexlifecyclemanagement._

trait IndexLifecycleManagementApi {
def getIlmStatus: GetIlmStatusRequest = GetIlmStatusRequest()

def startIlm(): StartIlmRequest = StartIlmRequest()

def stopIlm(): StopIlmRequest = StopIlmRequest()

def createIndexLifecyclePolicy(policy: IndexLifecyclePolicy): CreateLifecyclePolicyRequest =
CreateLifecyclePolicyRequest(policy)

def getIndexLifecyclePolicy(policyName: String): GetIndexLifecyclePolicyRequest =
GetIndexLifecyclePolicyRequest(policyName)

def deleteIndexLifecyclePolicy(policyName: String): DeleteIndexLifecyclePolicyRequest =
DeleteIndexLifecyclePolicyRequest(policyName)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.sksamuel.elastic4s.requests.indexlifecyclemanagement

import com.sksamuel.elastic4s.ext.OptionImplicits.RichOptionImplicits
import com.sksamuel.elastic4s.requests.indexlifecyclemanagement.policy.IndexLifecyclePolicy

import scala.concurrent.duration.Duration

case class CreateLifecyclePolicyRequest(
policy: IndexLifecyclePolicy,
masterTimeout: Option[String] = None,
timeout: Option[String] = None
) {
def masterTimeout(timeout: Duration): CreateLifecyclePolicyRequest =
copy(masterTimeout = s"${timeout.toNanos}nanos".some)
def masterTimeout(timeout: String): CreateLifecyclePolicyRequest = copy(masterTimeout = timeout.some)

def timeout(timeout: Duration): CreateLifecyclePolicyRequest = copy(timeout = s"${timeout.toNanos}nanos".some)
def timeout(timeout: String): CreateLifecyclePolicyRequest = copy(timeout = timeout.some)

def policy(policy: IndexLifecyclePolicy): CreateLifecyclePolicyRequest = copy(policy = policy)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package com.sksamuel.elastic4s.requests.indexlifecyclemanagement

case class CreateLifecyclePolicyResponse(acknowledged: Boolean)
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.sksamuel.elastic4s.requests.indexlifecyclemanagement

import scala.concurrent.duration.Duration

case class DeleteIndexLifecyclePolicyRequest(
policyName: String,
masterTimeout: Option[String] = None,
timeout: Option[String] = None
) {
def masterTimeout(timeout: Duration): DeleteIndexLifecyclePolicyRequest =
copy(masterTimeout = Some(s"${timeout.toNanos}nanos"))
def masterTimeout(timeout: String): DeleteIndexLifecyclePolicyRequest =
copy(masterTimeout = Some(timeout))

def timeout(timeout: Duration): DeleteIndexLifecyclePolicyRequest = copy(timeout = Some(s"${timeout.toNanos}nanos"))
def timeout(timeout: String): DeleteIndexLifecyclePolicyRequest = copy(timeout = Some(timeout))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package com.sksamuel.elastic4s.requests.indexlifecyclemanagement

case class DeleteIndexLifecyclePolicyResponse(acknowledged: Boolean)
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.sksamuel.elastic4s.requests.indexlifecyclemanagement

import scala.concurrent.duration.Duration

case class GetIndexLifecyclePolicyRequest(
policyName: String,
masterTimeout: Option[String] = None,
timeout: Option[String] = None
) {
def masterTimeout(timeout: Duration): GetIndexLifecyclePolicyRequest =
copy(masterTimeout = Some(s"${timeout.toNanos}nanos"))
def masterTimeout(timeout: String): GetIndexLifecyclePolicyRequest = copy(masterTimeout = Some(timeout))

def timeout(timeout: Duration): GetIndexLifecyclePolicyRequest = copy(timeout = Some(s"${timeout.toNanos}nanos"))
def timeout(timeout: String): GetIndexLifecyclePolicyRequest = copy(timeout = Some(timeout))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com.sksamuel.elastic4s.requests.indexlifecyclemanagement

import com.fasterxml.jackson.annotation.JsonProperty
import com.fasterxml.jackson.databind.JsonNode
import com.sksamuel.elastic4s.JacksonSupport
import com.sksamuel.elastic4s.requests.indexlifecyclemanagement.policy.IndexLifecyclePolicy

import scala.collection.JavaConverters._

case class GetIndexLifecyclePolicyResponse(
version: Int,
modifiedDate: Long,
policy: IndexLifecyclePolicy,
inUseBy: Option[InUseBy]
)

object GetIndexLifecyclePolicyResponse {
def deserialize(node: JsonNode): GetIndexLifecyclePolicyResponse = {
val policyProperty = node.properties().iterator().next()
val policyNode = policyProperty.getValue
val policyName = policyProperty.getKey
val version = Option(policyNode.get("version")).map(_.asInt(1)).getOrElse(1)
val modifiedDate = Option(policyNode.get("modified_date")).map(_.asLong(0L)).getOrElse(0L)
val policy = IndexLifecyclePolicy.deserialize(policyNode.get("policy"))
val inUseBy = Option(policyNode.get("in_use_by")).map(InUseBy.deserialize)
GetIndexLifecyclePolicyResponse(version, modifiedDate, policy.copy(name = policyName), inUseBy)
}

}

case class InUseBy(indices: List[String], data_streams: List[String], composable_templates: List[String])

object InUseBy {
def deserialize(node: JsonNode): InUseBy = {
val indices =
Option(node.get("indices")).getOrElse(JacksonSupport.mapper.createObjectNode())
.values().asScala.map(_.asText()).toList
val dataStreams =
Option(node.get("data_streams")).getOrElse(JacksonSupport.mapper.createObjectNode())
.values().asScala.map(_.asText()).toList
val composableTemplates =
Option(node.get("composable_templates")).getOrElse(JacksonSupport.mapper.createObjectNode())
.values().asScala.map(_.asText()).toList
InUseBy(indices, dataStreams, composableTemplates)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package com.sksamuel.elastic4s.requests.indexlifecyclemanagement.policy

import com.fasterxml.jackson.databind.JsonNode
import com.sksamuel.elastic4s.JacksonSupport
import com.sksamuel.elastic4s.json.{JsonValue, StringValue}

import scala.collection.JavaConverters._

case class IndexLifecyclePolicy(
name: String,
phases: List[IndexLifecyclePolicyPhase],
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think maybe a Map is more appropriate here? Then you don't need to override the equals method.

Copy link
Author

@UralRoman UralRoman Oct 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea of this solution is that the user can use only the phases that exist in the API. The user should use the phase enumeration rather than create the phases themselves. Therefore, Map will not help here.

meta: Map[String, JsonValue]
) {
def withPhases(addPhases: IndexLifecyclePolicyPhase*): IndexLifecyclePolicy =
copy(phases = addPhases.toList ::: phases)
def withMeta(meta: (String, JsonValue)*): IndexLifecyclePolicy =
copy(meta = this.meta ++ meta.toMap)

override def equals(obj: Any): Boolean = obj match {
case that: IndexLifecyclePolicy =>
this.name == that.name &&
this.phases.sortBy(_.phaseName) == that.phases.sortBy(_.phaseName) &&
this.meta == that.meta
case _ => false
}
}

object IndexLifecyclePolicy {
def apply(name: String): IndexLifecyclePolicy = IndexLifecyclePolicy(name, Nil, Map.empty)

def deserialize(node: JsonNode): IndexLifecyclePolicy = {

val phases = Option(node.get("phases"))
.getOrElse(JacksonSupport.mapper.createObjectNode())
.properties()
.asScala
.map(entry => IndexLifecyclePolicyPhase.deserialize(entry.getKey, entry.getValue))
.toList

val meta = Option(node.get("_meta"))
.getOrElse(JacksonSupport.mapper.createObjectNode())
.properties()
.asScala
.map(entry => entry.getKey -> StringValue(entry.getValue.asText()))
.toMap

IndexLifecyclePolicy("", phases, meta)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.sksamuel.elastic4s.requests.indexlifecyclemanagement.policy

import com.fasterxml.jackson.databind.JsonNode
import com.sksamuel.elastic4s.json.{JsonValue, StringValue}

import scala.collection.JavaConverters._

case class IndexLifecyclePolicyAction(
actionName: String,
settings: Map[String, JsonValue]
) {

def withSettings(settings: (String, JsonValue)*): IndexLifecyclePolicyAction =
copy(settings = this.settings ++ settings.toMap)
}

object IndexLifecyclePolicyAction {
def apply(actionName: String): IndexLifecyclePolicyAction = IndexLifecyclePolicyAction(actionName, Map.empty)

def deserialize(actionName: String, node: JsonNode): IndexLifecyclePolicyAction = {
val settings = node.properties().asScala.map { entry =>
entry.getKey -> StringValue(entry.getValue.asText())
}.toMap

IndexLifecyclePolicyAction(actionName, settings)
}

val ForceMergeAction: IndexLifecyclePolicyAction = IndexLifecyclePolicyAction("forcemerge")
val DeleteAction: IndexLifecyclePolicyAction = IndexLifecyclePolicyAction("delete")
val AllocateAction: IndexLifecyclePolicyAction = IndexLifecyclePolicyAction("allocate")
val DownsampleAction: IndexLifecyclePolicyAction = IndexLifecyclePolicyAction("downsample")
val FreezeAction: IndexLifecyclePolicyAction = IndexLifecyclePolicyAction("freeze")
val MigrateAction: IndexLifecyclePolicyAction = IndexLifecyclePolicyAction("migrate")
val ReadonlyAction: IndexLifecyclePolicyAction = IndexLifecyclePolicyAction("readonly")
val RolloverAction: IndexLifecyclePolicyAction = IndexLifecyclePolicyAction("rollover")
val SetPriorityAction: IndexLifecyclePolicyAction = IndexLifecyclePolicyAction("set_priority")
val SearchableSnapshotAction: IndexLifecyclePolicyAction = IndexLifecyclePolicyAction("searchable_snapshot")
val ShrinkAction: IndexLifecyclePolicyAction = IndexLifecyclePolicyAction("shrink")
val UnfollowAction: IndexLifecyclePolicyAction = IndexLifecyclePolicyAction("unfollow")
val WaitForSnapshotAction: IndexLifecyclePolicyAction = IndexLifecyclePolicyAction("wait_for_snapshot")

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package com.sksamuel.elastic4s.requests.indexlifecyclemanagement.policy

import com.fasterxml.jackson.databind.JsonNode
import com.sksamuel.elastic4s.JacksonSupport
import com.sksamuel.elastic4s.json.{JsonValue, StringValue}

import scala.collection.JavaConverters._

case class IndexLifecyclePolicyPhase(
phaseName: String,
settings: Map[String, JsonValue],
actions: List[IndexLifecyclePolicyAction]
) {
def withSettings(settings: (String, JsonValue)*): IndexLifecyclePolicyPhase =
copy(settings = this.settings ++ settings.toMap)

def withActions(actions: IndexLifecyclePolicyAction*): IndexLifecyclePolicyPhase =
copy(actions = actions.toList ::: this.actions)

override def equals(obj: Any): Boolean = obj match {
case that: IndexLifecyclePolicyPhase =>
this.phaseName == that.phaseName &&
this.settings == that.settings &&
this.actions.sortBy(_.actionName) == that.actions.sortBy(_.actionName)
case _ => false
}
}

object IndexLifecyclePolicyPhase {
def apply(phaseName: String): IndexLifecyclePolicyPhase = IndexLifecyclePolicyPhase(phaseName, Map.empty, Nil)

def deserialize(name: String, node: JsonNode): IndexLifecyclePolicyPhase = {
val actions = Option(node.get("actions"))
.getOrElse(JacksonSupport.mapper.createObjectNode())
.properties()
.asScala
.map(entry => IndexLifecyclePolicyAction.deserialize(entry.getKey, entry.getValue))
.toList

val settings = node.properties().asScala.filterNot(_.getKey == "actions").map { entry =>
entry.getKey -> StringValue(entry.getValue.asText())
}.toMap

IndexLifecyclePolicyPhase(name, settings, actions)
}

val DeletePhase: IndexLifecyclePolicyPhase = IndexLifecyclePolicyPhase("delete")
val WarmPhase: IndexLifecyclePolicyPhase = IndexLifecyclePolicyPhase("warm")
val ColdPhase: IndexLifecyclePolicyPhase = IndexLifecyclePolicyPhase("cold")
val FrozenPhase: IndexLifecyclePolicyPhase = IndexLifecyclePolicyPhase("frozen")
val HotPhase: IndexLifecyclePolicyPhase = IndexLifecyclePolicyPhase("hot")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.sksamuel.elastic4s.handlers.indexlifecyclemanagement

import com.sksamuel.elastic4s.json.{XContentBuilder, XContentFactory}
import com.sksamuel.elastic4s.requests.indexlifecyclemanagement.policy.IndexLifecyclePolicyAction

object ElasticPolicyActionContentBuilder {
def apply(action: IndexLifecyclePolicyAction): XContentBuilder = {
val builder = XContentFactory.jsonBuilder()
action.settings.foreach { case (name, value) => builder.field(name, value) }
builder
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.sksamuel.elastic4s.handlers.indexlifecyclemanagement

import com.sksamuel.elastic4s.json.{XContentBuilder, XContentFactory}
import com.sksamuel.elastic4s.requests.indexlifecyclemanagement.policy.IndexLifecyclePolicyPhase

object ElasticPolicyPhaseContentBuilder {
def apply(phase: IndexLifecyclePolicyPhase): XContentBuilder = {
val builder = XContentFactory.jsonBuilder()
phase.settings.foreach { case (name, value) => builder.field(name, value) }
builder.startObject("actions")
phase.actions.map(action => builder.rawField(action.actionName, ElasticPolicyActionContentBuilder(action)))
builder.endObject()
builder.endObject()
}
}
Loading