add support for config file and multiple clusters config (#1)

This commit is contained in:
T. von Dein
2026-04-27 09:11:10 +02:00
parent 496f4aeda3
commit 17f92874e5
7 changed files with 154 additions and 37 deletions

View File

@@ -37,10 +37,7 @@ func Finish(err error) int {
}
func Main() int {
conf, err := cfg.Init()
if err != nil {
return Finish(err)
}
conf := cfg.NewConfig()
cmd := &cli.Command{
Name: "esctl",
@@ -57,6 +54,21 @@ func Main() int {
Sources: cli.EnvVars("ES_DEBUG"),
Destination: &conf.Debug,
},
&cli.StringFlag{
Name: "config",
Aliases: []string{"c"},
Value: "",
Usage: "config file",
Sources: cli.EnvVars("ES_CONFIG"),
Destination: &conf.ConfigFile,
},
&cli.StringFlag{
Name: "cluster",
Aliases: []string{"C"},
Value: "",
Usage: "cluster alias to work with",
Destination: &conf.CurrentCluster,
},
},
Commands: []*cli.Command{
@@ -67,7 +79,12 @@ func Main() int {
},
Before: func(ctx context.Context, cmd *cli.Command) (context.Context, error) {
if err := conf.Init(); err != nil {
Finish(err)
}
log.Init(conf)
return nil, nil
},
}

View File

@@ -19,56 +19,147 @@ package cfg
import (
"crypto/tls"
"errors"
"fmt"
"net/http"
"os"
"github.com/alecthomas/repr"
"github.com/elastic/elastic-transport-go/v8/elastictransport"
"github.com/elastic/go-elasticsearch/v9"
"gopkg.in/yaml.v3"
)
const (
Version string = `v0.0.1`
Version string = `v0.0.2`
)
type Cluster struct {
Uri, User, Pass string
ES *elasticsearch.TypedClient
}
type Config struct {
Uri, User, Pass string
ES *elasticsearch.TypedClient
Debug bool
ConfigFile string // -c
CurrentCluster string // -C
Debug bool // -d
Clusters map[string]*Cluster
DefaultCluster *Cluster
From, To, MaxItems int
Index string
Filter []string
Failed, Partials bool
}
func Init() (*Config, error) {
cfg := Config{
func NewConfig() *Config {
return &Config{Clusters: map[string]*Cluster{}}
}
func (conf *Config) Init() error {
if conf.ConfigFile != "" {
if err := conf.LoadConfig(); err != nil {
return err
}
} else {
if err := conf.LoadEnv(); err != nil {
return err
}
}
if conf.CurrentCluster != "" {
current, exists := conf.Clusters[conf.CurrentCluster]
if !exists {
return fmt.Errorf("no cluster with alias %s configured", conf.CurrentCluster)
} else {
conf.DefaultCluster = current
}
}
if conf.Debug {
repr.Println(conf)
}
conf.SetupES()
return nil
}
func (conf *Config) LoadEnv() error {
cluster := Cluster{
Uri: os.Getenv("ES_URI"),
User: os.Getenv("ES_USER"),
Pass: os.Getenv("ES_PASS"),
}
switch {
case cfg.Uri == "":
return nil, errors.New("ES_URI unset")
case cfg.User == "":
return nil, errors.New("ES_USER unset")
case cfg.Pass == "":
return nil, errors.New("ES_PASS unset")
case cluster.Uri == "":
return errors.New("ES_URI unset")
case cluster.User == "":
return errors.New("ES_USER unset")
case cluster.Pass == "":
return errors.New("ES_PASS unset")
}
es, _ := elasticsearch.NewTyped(
elasticsearch.WithAddresses(cfg.Uri),
elasticsearch.WithBasicAuth(cfg.User, cfg.Pass),
elasticsearch.WithTransportOptions(
elastictransport.WithTransport(
&http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
},
),
),
)
conf.Clusters["default"] = &cluster
conf.DefaultCluster = &cluster
cfg.ES = es
return &cfg, nil
return nil
}
func (conf *Config) LoadConfig() error {
if conf.ConfigFile == "" {
return nil
}
data, err := os.ReadFile(conf.ConfigFile)
if err != nil {
return fmt.Errorf("failed to read config file: %w", err)
}
newconf := &Config{}
err = yaml.Unmarshal(data, newconf)
if err != nil {
return fmt.Errorf("failed to unmarshal config file: %w", err)
}
if len(newconf.Clusters) > 0 {
conf.Clusters = newconf.Clusters
_, exists := conf.Clusters["default"]
if !exists {
// no "default", just use the first we stumble upon
for _, cluster := range conf.Clusters {
conf.DefaultCluster = cluster
break
}
} else {
conf.DefaultCluster = newconf.Clusters["default"]
}
}
return nil
}
func (conf *Config) SetupES() error {
for _, cluster := range conf.Clusters {
es, err := elasticsearch.NewTyped(
elasticsearch.WithAddresses(cluster.Uri),
elasticsearch.WithBasicAuth(cluster.User, cluster.Pass),
elasticsearch.WithTransportOptions(
elastictransport.WithTransport(
&http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
},
),
),
)
if err != nil {
return fmt.Errorf("failed to setup elasticsearch connection: %w", err)
}
cluster.ES = es
}
return nil
}

View File

@@ -26,7 +26,7 @@ import (
)
func Health(conf *cfg.Config) error {
res, err := conf.ES.Cluster.Health().Do(context.Background())
res, err := conf.DefaultCluster.ES.Cluster.Health().Do(context.Background())
if err != nil {
log.Fatalf("Error getting health: %s", err)
}

View File

@@ -26,7 +26,7 @@ import (
)
func IndexList(conf *cfg.Config) error {
cat := conf.ES.Cat.Indices()
cat := conf.DefaultCluster.ES.Cat.Indices()
if conf.Failed {
cat = cat.Health(healthstatus.Red)
@@ -67,7 +67,7 @@ func IndexList(conf *cfg.Config) error {
}
func IndexShow(conf *cfg.Config, index string) error {
res, err := conf.ES.Indices.Get(index).Do(context.Background())
res, err := conf.DefaultCluster.ES.Indices.Get(index).Do(context.Background())
if err != nil {
return fmt.Errorf("failed to get index: %s", err)
}

View File

@@ -53,7 +53,7 @@ func Search(conf *cfg.Config, q string) error {
query.Filter(filters...)
}
res, err := conf.ES.Search().
res, err := conf.DefaultCluster.ES.Search().
Index(conf.Index).
Request(&search.Request{
Query: query.QueryCaster(),

View File

@@ -42,7 +42,7 @@ type Snapshot struct {
func SnapshotList(conf *cfg.Config) error {
// get partial indicies
ires, err := conf.ES.Cat.Indices().Do(context.Background())
ires, err := conf.DefaultCluster.ES.Cat.Indices().Do(context.Background())
if err != nil {
return fmt.Errorf("Error getting indicies: %s", err)
}
@@ -55,7 +55,7 @@ func SnapshotList(conf *cfg.Config) error {
}
// get snapshots
sres, err := conf.ES.Cat.Snapshots().Do(context.Background())
sres, err := conf.DefaultCluster.ES.Cat.Snapshots().Do(context.Background())
if err != nil {
return fmt.Errorf("Error getting snapshots: %s", err)
}
@@ -103,7 +103,7 @@ func SnapshotList(conf *cfg.Config) error {
}
func SnapshotShow(conf *cfg.Config, snapshot string) error {
res, err := conf.ES.Snapshot.Get("*", snapshot).Do(context.Background())
res, err := conf.DefaultCluster.ES.Snapshot.Get("*", snapshot).Do(context.Background())
if err != nil {
return fmt.Errorf("failed to get snapshot: %s", err)
}

9
sample-2-clusters.yaml Normal file
View File

@@ -0,0 +1,9 @@
clusters:
default:
uri: https://es.foo.bar:9200/
user: elastic
pass: 123456
other:
uri: https://myes.foo:9200/
user: elastic
pass: asdasdasd