diff --git a/README.md b/README.md index 8ec40ed..1b34314 100644 --- a/README.md +++ b/README.md @@ -536,7 +536,6 @@ index - manage indicies update - update an index delete - delete an index close - close an index - allocation - explain index allocation fields - show info about field capabilities ilm - show ilm status alias - manage index aliases @@ -564,6 +563,7 @@ search - search within an index shard - manage shards list - list shards show - show details about a shard + allocation - explain shard allocation snapshot - manage snapshots list - list snapshots show - show details about a snapshot diff --git a/cmd/index.go b/cmd/index.go index 20be4d9..53d947c 100644 --- a/cmd/index.go +++ b/cmd/index.go @@ -40,7 +40,6 @@ func Index(conf *cfg.Config) *cli.Command { IndexCreate(conf, true), IndexDelete(conf), IndexClose(conf), - IndexAllocation(conf), IndexFields(conf), IndexIlm(conf), @@ -96,38 +95,6 @@ func IndexList(conf *cfg.Config) *cli.Command { } } -func IndexAllocation(conf *cfg.Config) *cli.Command { - return &cli.Command{ - Name: "allocation", - Aliases: []string{"a"}, - Usage: "explain index allocation", - - Flags: []cli.Flag{ - &cli.IntFlag{ - Name: "shard", - Usage: "shard number to explain for", - Destination: &conf.Shards, - Aliases: []string{"s"}, - }, - &cli.BoolFlag{ - Name: "primary", - Usage: "explain primary allocation (default true)", - Destination: &conf.Primary, - Aliases: []string{"p"}, - }, - }, - - Action: func(ctx context.Context, cmd *cli.Command) error { - index := cmd.Args().Get(0) - if index == "" { - return errors.New("no index specified") - } - - return es.IndexAllocation(conf, cmd.Args().Get(0)) - }, - } -} - func IndexShow(conf *cfg.Config) *cli.Command { return &cli.Command{ Name: "show", diff --git a/cmd/shards.go b/cmd/shards.go index e128cdd..d5e49c4 100644 --- a/cmd/shards.go +++ b/cmd/shards.go @@ -35,6 +35,7 @@ func Shard(conf *cfg.Config) *cli.Command { Commands: []*cli.Command{ ShardList(conf), ShardShow(conf), + ShardAllocation(conf), }, } } @@ -94,3 +95,41 @@ func ShardShow(conf *cfg.Config) *cli.Command { }, } } + +func ShardAllocation(conf *cfg.Config) *cli.Command { + return &cli.Command{ + Name: "allocation", + Aliases: []string{"a"}, + Usage: "explain shard allocation", + + Flags: []cli.Flag{ + &cli.IntFlag{ + Name: "shard", + Usage: "shard number to explain for", + Destination: &conf.Shards, + Aliases: []string{"s"}, + }, + &cli.BoolFlag{ + Name: "primary", + Usage: "explain primary allocation (default true)", + Destination: &conf.Primary, + Aliases: []string{"p"}, + }, + &cli.StringFlag{ + Name: "node", + Usage: "explain a shard only if it is currently located on the specified node name or node ID", + Destination: &conf.FromNode, + Aliases: []string{"n"}, + }, + }, + + Action: func(ctx context.Context, cmd *cli.Command) error { + index := cmd.Args().Get(0) + if index == "" { + return errors.New("no index specified") + } + + return es.ShardAllocation(conf, cmd.Args().Get(0)) + }, + } +} diff --git a/pkg/es/index.go b/pkg/es/index.go index 2d16ef6..3f2a170 100644 --- a/pkg/es/index.go +++ b/pkg/es/index.go @@ -261,64 +261,6 @@ func IndexClose(conf *cfg.Config, index string) error { return nil } -func IndexAllocation(conf *cfg.Config, index string) error { - res, err := conf.DefaultCluster.ES().Cluster.AllocationExplain(). - Index(index). - Primary(conf.Primary). - Shard(conf.Shards). - Do(context.Background()) - if err != nil { - return fmt.Errorf("failed to get index allocation explain: %s", esErrorString(err)) - } - - slog.Debug("ES result", "index", res) - - currentNode := res.CurrentNode - - table := printer.NewTable(conf, 2, 10) - table.Addheaders("index allocation setting", "value") - - roles := make([]string, len(currentNode.Roles)) - for idx, role := range currentNode.Roles { - roles[idx] = role.Name - } - - table.Entries = [][]any{ - {"Index", index}, - {"Current node", currentNode.Name}, - {"Current k8s node", currentNode.Attributes["k8s_node_name"]}, - {"Current node address", currentNode.TransportAddress}, - {"Current node id", currentNode.Id}, - {"Current node weight", currentNode.WeightRanking}, - {"Current node roles", roles}, - {"Can rebalance cluster", res.CanRebalanceCluster.Name}, - {"Can rebalance to another node", res.CanRebalanceToOtherNode.Name}, - {"Can remain on current node", res.CanRemainOnCurrentNode.Name}, - } - - if err := table.Print(); err != nil { - return err - } - - return nil -} - -/* -func IndexModify(conf *cfg.Config, index string) error { - settings := esdsl.NewIndexSettings().NumberOfReplicas(strconv.Itoa(conf.Replicas)) - - _, err := conf.DefaultCluster.ES().Indices.PutSettings(). - Indices(index). - Index(settings). - Do(context.Background()) - if err != nil { - return fmt.Errorf("failed to modify index settings: %s", esErrorString(err)) - } - - return nil -} -*/ - func IndexFields(conf *cfg.Config, index string) error { res, err := conf.DefaultCluster.ES().FieldCaps(). Index(index). diff --git a/pkg/es/shard.go b/pkg/es/shard.go index 2e6de38..9325c13 100644 --- a/pkg/es/shard.go +++ b/pkg/es/shard.go @@ -145,3 +145,63 @@ func ShardShow(conf *cfg.Config, index string) error { return printShards(conf, res) } + +func ShardAllocation(conf *cfg.Config, index string) error { + explain := conf.DefaultCluster.ES().Cluster.AllocationExplain(). + Index(index). + Primary(conf.Primary). + Shard(conf.Shards) + + if conf.FromNode != "" { + explain.CurrentNode(conf.FromNode) + } + + res, err := explain.Do(context.Background()) + if err != nil { + return fmt.Errorf("failed to get shard allocation explain: %s", esErrorString(err)) + } + + slog.Debug("ES result", "explain", res) + + currentNode := res.CurrentNode + + table := printer.NewTable(conf, 2, 10) + table.Addheaders("shard allocation setting", "value") + + roles := make([]string, len(currentNode.Roles)) + for idx, role := range currentNode.Roles { + roles[idx] = role.Name + } + + table.Entries = [][]any{ + {"Index", index}, + {"Current state", res.CurrentState}, + {"Current node", currentNode.Name}, + {"Current k8s node", currentNode.Attributes["k8s_node_name"]}, + {"Current node address", currentNode.TransportAddress}, + {"Current node id", currentNode.Id}, + {"Current node weight", currentNode.WeightRanking}, + {"Current node roles", roles}, + {"Can rebalance cluster", res.CanRebalanceCluster.Name}, + {"Can rebalance to another node", res.CanRebalanceToOtherNode.Name}, + {"Can remain on current node", res.CanRemainOnCurrentNode.Name}, + } + + if res.CurrentState == "unassigned" { + table.AddRow("Unassignment reason", res.UnassignedInfo.Reason.String()+" at "+res.UnassignedInfo.At.(string)) + } + + for _, nodeDecision := range res.NodeAllocationDecisions { + for _, decider := range nodeDecision.Deciders { + table.AddRow("Allocation decider", decider.Decider) + table.AddRow(" -> decision", decider.Decision.String()) + table.AddRow(" -> explanation", decider.Explanation) + } + } + + if err := table.Print(); err != nil { + return err + } + + return nil +}