From b7a87051c031624a9eadfc8b012165ffd7a54f80 Mon Sep 17 00:00:00 2001 From: "T. von Dein" Date: Mon, 29 Jun 2026 10:11:50 +0200 Subject: [PATCH] add 'ilm show -t' to show a better visualization of a ilm policy (#57) --- cmd/ilm.go | 9 +++++++ pkg/cfg/ilm.go | 1 + pkg/es/ilm.go | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+) diff --git a/cmd/ilm.go b/cmd/ilm.go index 128caa9..ca72b56 100644 --- a/cmd/ilm.go +++ b/cmd/ilm.go @@ -103,6 +103,15 @@ func IlmShow(conf *cfg.Config) *cli.Command { Usage: "show details about an index lifecycle policy", UsageText: "show ", + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "tree", + Usage: "display policy as a tree", + Destination: &conf.Ilm.Tree, + Aliases: []string{"t"}, + }, + }, + Action: func(ctx context.Context, cmd *cli.Command) error { policy := cmd.Args().Get(0) if policy == "" { diff --git a/pkg/cfg/ilm.go b/pkg/cfg/ilm.go index 67c742a..433b463 100644 --- a/pkg/cfg/ilm.go +++ b/pkg/cfg/ilm.go @@ -42,6 +42,7 @@ type Ilm struct { DeleteSearchableSnapshots bool MinAge, FromPhase, Within string // forecast + Tree bool } func (cfg *Ilm) HaveHot() bool { diff --git a/pkg/es/ilm.go b/pkg/es/ilm.go index 9fa14f7..6514f80 100644 --- a/pkg/es/ilm.go +++ b/pkg/es/ilm.go @@ -121,6 +121,10 @@ func IlmShow(conf *cfg.Config, policy string) error { return errors.New("no ilm policy retrieved") } + if conf.Ilm.Tree { + return IlmShowTree(conf, ilm.Policy) + } + table := printer.NewTable(conf, 2, 5) table.Addheaders("ilm policy setting", "value") @@ -135,6 +139,69 @@ func IlmShow(conf *cfg.Config, policy string) error { return table.Print() } +// Visualize phases or a ILM policy, taking into account that the +// minAge for the current phases is set in the next phase +func IlmShowTree(conf *cfg.Config, ilm types.IlmPolicy) error { + indent := "" + + table := printer.NewTable(conf, 4, 0) + table.Addheaders("phase", "min age", "min size", "snapshot repo") + + for _, phase := range IlmPhaseOrder { + if phase == "hot" { + fmt.Printf("%s%s phase:\n%s rollover after %s\n%s or rollover when storage > %s\n", + indent, phase, + indent, formatDuration(parseDuration(ilm.Phases.Hot.Actions.Rollover.MaxAge.(string))), + indent, ilm.Phases.Hot.Actions.Rollover.MaxPrimaryShardSize, + ) + + indent += " " + continue + } + + current := getIlmCurrentPhase(ilm, phase) + + if current == nil { + continue + } + + next := findNextPhase(ilm, phase) + + fmt.Printf("%s%s phase:\n", indent, phase) + + if next != nil { + fmt.Printf("%s rollover after %s\n", + indent, formatDuration(next.minage), + ) + + if current.Actions.SearchableSnapshot != nil { + fmt.Printf("%s snapshot repo: %s\n", + indent, current.Actions.SearchableSnapshot.SnapshotRepository, + ) + } + } + + indent += " " + } + + return nil +} + +func getIlmCurrentPhase(policy types.IlmPolicy, currentPhase string) *types.Phase { + switch currentPhase { + case "hot": + return policy.Phases.Hot + case "warm": + return policy.Phases.Warm + case "cold": + return policy.Phases.Cold + case "frozen": + return policy.Phases.Frozen + default: + return policy.Phases.Delete + } +} + func ilmPhaseString(phase *types.Phase, short bool) string { if phase == nil { return ""