mv index allocate to shard allocate, add explanations, fixes #71 (#75)

This commit is contained in:
T. von Dein
2026-07-07 08:39:32 +02:00
parent c35ffa5e4b
commit f10366dbde
6 changed files with 100 additions and 98 deletions

View File

@@ -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

View File

@@ -3,13 +3,7 @@
- index show: add more details, see screenshots
- add shard explain, aka:
get /_cluster/allocation/explain {"index":"yourindex", "primary": true, "shard":0}
- add datastream support:
https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-indices-get-data-stream
also exclude data stream backing indices from index ls
- table any2string

View File

@@ -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",

View File

@@ -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))
},
}
}

View File

@@ -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).

View File

@@ -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
}