mirror of
https://codeberg.org/scip/esctl.git
synced 2026-08-25 21:54:19 +02:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a169d23b90 | ||
|
|
f89a09d1d2 |
@@ -49,6 +49,10 @@ clusters:
|
|||||||
pass: asdasdasd
|
pass: asdasdasd
|
||||||
```
|
```
|
||||||
|
|
||||||
|
and specify it with `-c configfile`. You may also put clusters into a
|
||||||
|
default config file in `~/.config/esctl/config.yaml`. In this case you
|
||||||
|
can omit `-c ...`.
|
||||||
|
|
||||||
If you want to work on a specific cluster, specify its name with the
|
If you want to work on a specific cluster, specify its name with the
|
||||||
global `-C` option.
|
global `-C` option.
|
||||||
|
|
||||||
|
|||||||
3
TODO.md
3
TODO.md
@@ -1,2 +1,5 @@
|
|||||||
- [Go client docs](https://www.elastic.co/docs/reference/elasticsearch/clients/go/typed-api)
|
- [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)
|
- [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
|
||||||
|
|||||||
74
cmd/index.go
74
cmd/index.go
@@ -18,6 +18,7 @@ package cmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"codeberg.org/scip/esctl/pkg/cfg"
|
"codeberg.org/scip/esctl/pkg/cfg"
|
||||||
"codeberg.org/scip/esctl/pkg/es"
|
"codeberg.org/scip/esctl/pkg/es"
|
||||||
@@ -34,6 +35,8 @@ func Index(conf *cfg.Config) *cli.Command {
|
|||||||
Commands: []*cli.Command{
|
Commands: []*cli.Command{
|
||||||
IndexList(conf),
|
IndexList(conf),
|
||||||
IndexShow(conf),
|
IndexShow(conf),
|
||||||
|
IndexCreate(conf),
|
||||||
|
IndexDelete(conf),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -88,5 +91,76 @@ func IndexShow(conf *cfg.Config) *cli.Command {
|
|||||||
|
|
||||||
return nil
|
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
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
Version string = `v0.0.3`
|
Version string = `v0.0.4`
|
||||||
)
|
)
|
||||||
|
|
||||||
type Cluster struct {
|
type Cluster struct {
|
||||||
@@ -46,6 +46,8 @@ type Config struct {
|
|||||||
DefaultCluster *Cluster
|
DefaultCluster *Cluster
|
||||||
Index string // index: -i
|
Index string // index: -i
|
||||||
Failed, Partials bool // index: flags
|
Failed, Partials bool // index: flags
|
||||||
|
Shards, Replicas int // index create: -s -r
|
||||||
|
Wait bool // index create: -w
|
||||||
From, To, MaxItems int // search: flags
|
From, To, MaxItems int // search: flags
|
||||||
Filter []string // search: -F
|
Filter []string // search: -F
|
||||||
Exclude string // cluster compare: -e (regexp)
|
Exclude string // cluster compare: -e (regexp)
|
||||||
@@ -57,11 +59,17 @@ func NewConfig() *Config {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (conf *Config) Init() error {
|
func (conf *Config) Init() error {
|
||||||
if conf.ConfigFile != "" {
|
DefaultConfig := os.Getenv("HOME") + "/.config/esctl/config.yaml"
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case fileExists(DefaultConfig):
|
||||||
|
conf.ConfigFile = DefaultConfig
|
||||||
|
fallthrough
|
||||||
|
case conf.ConfigFile != "":
|
||||||
if err := conf.LoadConfig(); err != nil {
|
if err := conf.LoadConfig(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
default:
|
||||||
if err := conf.LoadEnv(); err != nil {
|
if err := conf.LoadEnv(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -165,3 +173,14 @@ func (conf *Config) SetupES() error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func fileExists(filename string) bool {
|
||||||
|
info, err := os.Stat(filename)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
// return false on any error
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return !info.IsDir()
|
||||||
|
}
|
||||||
|
|||||||
@@ -85,6 +85,7 @@ func List(conf *cfg.Config) error {
|
|||||||
idx++
|
idx++
|
||||||
}
|
}
|
||||||
|
|
||||||
|
table.Sort()
|
||||||
table.PrintMarkdown()
|
table.PrintMarkdown()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
100
pkg/es/index.go
100
pkg/es/index.go
@@ -20,11 +20,39 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
"codeberg.org/scip/esctl/pkg/cfg"
|
"codeberg.org/scip/esctl/pkg/cfg"
|
||||||
|
"github.com/elastic/go-elasticsearch/v9/typedapi/esdsl"
|
||||||
"github.com/elastic/go-elasticsearch/v9/typedapi/types/enums/healthstatus"
|
"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 {
|
func IndexList(conf *cfg.Config) error {
|
||||||
cat := conf.DefaultCluster.ES.Cat.Indices().
|
cat := conf.DefaultCluster.ES.Cat.Indices().
|
||||||
// we need to add custom request headers, required for older ES instances
|
// 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 {
|
func IndexShow(conf *cfg.Config, index string) error {
|
||||||
|
if index == "" {
|
||||||
|
return fmt.Errorf("no index specified")
|
||||||
|
}
|
||||||
|
|
||||||
res, err := conf.DefaultCluster.ES.Indices.Get(index).
|
res, err := conf.DefaultCluster.ES.Indices.Get(index).
|
||||||
// we need to add custom request headers, required for older ES instances
|
// we need to add custom request headers, required for older ES instances
|
||||||
Header("content-type", "application/json").
|
Header("content-type", "application/json").
|
||||||
@@ -81,7 +113,73 @@ func IndexShow(conf *cfg.Config, index string) error {
|
|||||||
|
|
||||||
slog.Debug("ES result", "index", res)
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user