add index create,delete, enhance index show, catch empty index arg

This commit is contained in:
T. von Dein
2026-04-29 13:44:21 +02:00
parent f89a09d1d2
commit a169d23b90
4 changed files with 178 additions and 1 deletions

View File

@@ -1,2 +1,5 @@
- [Go client docs](https://www.elastic.co/docs/reference/elasticsearch/clients/go/typed-api)
- [ES API docs](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-indices-get)
- Fix index names custom completion
- add cluster default <name> which would add a flag to the config, so that no -C is needed subsequently

View File

@@ -18,6 +18,7 @@ package cmd
import (
"context"
"fmt"
"codeberg.org/scip/esctl/pkg/cfg"
"codeberg.org/scip/esctl/pkg/es"
@@ -34,6 +35,8 @@ func Index(conf *cfg.Config) *cli.Command {
Commands: []*cli.Command{
IndexList(conf),
IndexShow(conf),
IndexCreate(conf),
IndexDelete(conf),
},
}
}
@@ -88,5 +91,76 @@ func IndexShow(conf *cfg.Config) *cli.Command {
return nil
},
// FIXME: doesn't work at all
// FIXME: also it would ONLY work if the user uses env vars, -C would not be
// there when the completion output is being generated
ShellComplete: func(ctx context.Context, cmd *cli.Command) {
if cmd.NArg() > 0 {
return
}
indices, err := es.IndexNames(conf)
if err != nil {
return
}
for _, index := range indices {
fmt.Println(index)
}
},
}
}
func IndexCreate(conf *cfg.Config) *cli.Command {
return &cli.Command{
Name: "create",
Aliases: []string{"+"},
Usage: "create a new index",
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "wait",
Usage: "wait for active shards",
Destination: &conf.Wait,
Aliases: []string{"w"},
},
&cli.IntFlag{
Name: "shards",
Usage: "number of shards to create",
Destination: &conf.Shards,
Aliases: []string{"s"},
},
&cli.IntFlag{
Name: "replicas",
Usage: "number of replicas to create",
Destination: &conf.Replicas,
Aliases: []string{"r"},
},
},
Action: func(ctx context.Context, cmd *cli.Command) error {
if err := es.IndexCreate(conf, cmd.Args().Get(0)); err != nil {
return err
}
return nil
},
}
}
func IndexDelete(conf *cfg.Config) *cli.Command {
return &cli.Command{
Name: "delete",
Aliases: []string{"rm"},
Usage: "delete an index",
Action: func(ctx context.Context, cmd *cli.Command) error {
if err := es.IndexDelete(conf, cmd.Args().Get(0)); err != nil {
return err
}
return nil
},
}
}

View File

@@ -46,6 +46,8 @@ type Config struct {
DefaultCluster *Cluster
Index string // index: -i
Failed, Partials bool // index: flags
Shards, Replicas int // index create: -s -r
Wait bool // index create: -w
From, To, MaxItems int // search: flags
Filter []string // search: -F
Exclude string // cluster compare: -e (regexp)

View File

@@ -20,11 +20,39 @@ import (
"context"
"fmt"
"log/slog"
"strconv"
"time"
"codeberg.org/scip/esctl/pkg/cfg"
"github.com/elastic/go-elasticsearch/v9/typedapi/esdsl"
"github.com/elastic/go-elasticsearch/v9/typedapi/types/enums/healthstatus"
)
type Settings struct {
wait_for_active_shards string
number_of_shards int
number_of_replicas int
}
// used for completion
func IndexNames(conf *cfg.Config) ([]string, error) {
res, err := conf.DefaultCluster.ES.Cat.Indices().
Header("content-type", "application/json").
Header("accept", "application/json").
Do(context.Background())
if err != nil {
return nil, fmt.Errorf("Error getting indicies: %s", err)
}
indices := make([]string, len(res))
for idx, index := range res {
indices[idx] = *index.Index
}
return indices, nil
}
func IndexList(conf *cfg.Config) error {
cat := conf.DefaultCluster.ES.Cat.Indices().
// we need to add custom request headers, required for older ES instances
@@ -70,6 +98,10 @@ func IndexList(conf *cfg.Config) error {
}
func IndexShow(conf *cfg.Config, index string) error {
if index == "" {
return fmt.Errorf("no index specified")
}
res, err := conf.DefaultCluster.ES.Indices.Get(index).
// we need to add custom request headers, required for older ES instances
Header("content-type", "application/json").
@@ -81,7 +113,73 @@ func IndexShow(conf *cfg.Config, index string) error {
slog.Debug("ES result", "index", res)
// FIXME: add table printer like SnapshotShow
table := NewTable(2, 5)
table.Addheaders("field", "value")
ts, err := strconv.ParseInt(res[index].Settings.Index.CreationDate.(string), 10, 64)
if err != nil {
ts = 0
}
created := time.Unix(ts/1000, 0)
table.entries = [][]string{
{"name", index},
{"replicas", *res[index].Settings.Index.NumberOfReplicas},
{"shards", *res[index].Settings.Index.NumberOfShards},
{"created", created.Format("2006-01-02 15:04:05")},
{"uuid", *res[index].Settings.Index.Uuid},
}
table.PrintMarkdown()
return nil
}
func IndexCreate(conf *cfg.Config, index string) error {
if index == "" {
return fmt.Errorf("no index specified")
}
settings := esdsl.NewIndexSettings()
create := conf.DefaultCluster.ES.Indices.Create(index).
Header("content-type", "application/json").
Header("accept", "application/json")
if conf.Wait {
create.WaitForActiveShards("all")
}
if conf.Shards > 0 {
settings = settings.NumberOfShards(strconv.Itoa(conf.Shards))
}
if conf.Replicas > 0 {
settings = settings.NumberOfReplicas(strconv.Itoa(conf.Replicas))
}
_, err := create.Settings(settings).
Do(context.Background())
if err != nil {
return fmt.Errorf("failed to create index: %s", err)
}
return nil
}
func IndexDelete(conf *cfg.Config, index string) error {
if index == "" {
return fmt.Errorf("no index specified")
}
_, err := conf.DefaultCluster.ES.Indices.Delete(index).
Header("content-type", "application/json").
Header("accept", "application/json").
Do(context.Background())
if err != nil {
return fmt.Errorf("failed to delete index: %s", err)
}
return nil
}