/*
Copyright © 2026 Thomas von Dein
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
package cmd
import (
"context"
"errors"
"codeberg.org/scip/esctl/pkg/cfg"
"codeberg.org/scip/esctl/pkg/es"
"github.com/urfave/cli/v3"
)
func ClusterReroute(conf *cfg.Config) *cli.Command {
return &cli.Command{
Name: "reroute",
Usage: "manually change the allocation of individual shards in the cluster.",
UsageText: "reroute ",
Aliases: []string{"ctx"},
Commands: []*cli.Command{
ClusterRerouteMove(conf),
ClusterRerouteAllocateReplica(conf),
ClusterRerouteCancel(conf),
ClusterRerouteAllocatePrimary(conf, false),
ClusterRerouteAllocatePrimary(conf, true),
},
}
}
func ClusterRerouteMove(conf *cfg.Config) *cli.Command {
return &cli.Command{
Name: "move",
Usage: "move shard to another node",
UsageText: "move [options] ",
ShellComplete: func(ctx context.Context, cmd *cli.Command) {
complete(cmd, Cindex)
},
Flags: []cli.Flag{
&cli.IntFlag{
Name: "shard",
Usage: "shard to move",
Destination: &conf.Shards,
Aliases: []string{"s"},
Required: true,
},
&cli.StringFlag{
Name: "from-node",
Usage: "current node",
Destination: &conf.FromNode,
Aliases: []string{"f"},
Required: true,
},
&cli.StringFlag{
Name: "to-node",
Usage: "node to move to",
Destination: &conf.ToNode,
Aliases: []string{"t"},
Required: true,
},
},
Action: func(ctx context.Context, cmd *cli.Command) error {
index := cmd.Args().Get(0)
if index == "" {
return errors.New("no index specified")
}
return es.ClusterRerouteMove(conf, index)
},
}
}
func ClusterRerouteAllocateReplica(conf *cfg.Config) *cli.Command {
return &cli.Command{
Name: "allocate-replica",
Usage: "allocate-replica replica to another node",
UsageText: "allocate-replica [options] ",
ShellComplete: func(ctx context.Context, cmd *cli.Command) {
complete(cmd, Cindex)
},
Flags: []cli.Flag{
&cli.IntFlag{
Name: "shard",
Usage: "shard to move",
Destination: &conf.Shards,
Aliases: []string{"s"},
Required: true,
},
&cli.StringFlag{
Name: "to-node",
Usage: "node to move to",
Destination: &conf.ToNode,
Aliases: []string{"t"},
Required: true,
},
},
Action: func(ctx context.Context, cmd *cli.Command) error {
index := cmd.Args().Get(0)
if index == "" {
return errors.New("no index specified")
}
return es.ClusterRerouteAllocateReplica(conf, index)
},
}
}
func ClusterRerouteCancel(conf *cfg.Config) *cli.Command {
return &cli.Command{
Name: "cancel",
Usage: "cancel a reroute operation",
UsageText: "cancel [options] ",
ShellComplete: func(ctx context.Context, cmd *cli.Command) {
complete(cmd, Cindex)
},
Flags: []cli.Flag{
&cli.IntFlag{
Name: "shard",
Usage: "shard to move",
Destination: &conf.Shards,
Aliases: []string{"s"},
Required: true,
},
&cli.StringFlag{
Name: "to-node",
Usage: "node to move to",
Destination: &conf.ToNode,
Aliases: []string{"t"},
Required: true,
},
&cli.BoolFlag{
Name: "allow-primary",
Usage: "allow primary shard to cancel",
Destination: &conf.AllowPrimary,
Aliases: []string{"a"},
},
},
Action: func(ctx context.Context, cmd *cli.Command) error {
index := cmd.Args().Get(0)
if index == "" {
return errors.New("no index specified")
}
return es.ClusterRerouteCancel(conf, index)
},
}
}
func ClusterRerouteAllocatePrimary(conf *cfg.Config, stale bool) *cli.Command {
name := "allocate-empty-primary"
usage := "allocate an empty primary shard to a node"
if stale {
name = "allocate-stale-primary"
usage = "allocate a stale primary shard to a node"
}
return &cli.Command{
Name: name,
Usage: usage,
UsageText: name + " [options] ",
ShellComplete: func(ctx context.Context, cmd *cli.Command) {
complete(cmd, Cindex)
},
Flags: []cli.Flag{
&cli.IntFlag{
Name: "shard",
Usage: "shard to move",
Destination: &conf.Shards,
Aliases: []string{"s"},
Required: true,
},
&cli.StringFlag{
Name: "to-node",
Usage: "node to move to",
Destination: &conf.ToNode,
Aliases: []string{"t"},
Required: true,
},
&cli.BoolFlag{
Name: "accept-data-loss",
Usage: "",
Destination: &conf.AcceptDataLoss,
Aliases: []string{"a"},
Required: true,
},
},
Action: func(ctx context.Context, cmd *cli.Command) error {
index := cmd.Args().Get(0)
if index == "" {
return errors.New("no index specified")
}
return es.ClusterRerouteAllocatePrimary(conf, index, stale)
},
}
}