Compare commits

..

8 Commits

Author SHA1 Message Date
2b12e7e0bf upd linter 2026-07-07 10:39:03 +02:00
b6f6eabba2 fix version 2026-07-07 10:35:39 +02:00
135792eea0 only exclude failing check 2026-07-07 10:28:57 +02:00
02fe22b18f satisfy linter 2026-07-07 10:24:59 +02:00
2f77c27715 wrap errors correctly 2026-07-07 09:34:36 +02:00
24038e36f7 go fix'd 2026-07-07 09:22:18 +02:00
T. von Dein
f10366dbde mv index allocate to shard allocate, add explanations, fixes #71 (#75) 2026-07-07 08:39:32 +02:00
T. von Dein
c35ffa5e4b internal/rework-table (#74) 2026-07-07 07:29:03 +02:00
32 changed files with 208 additions and 216 deletions

View File

@@ -2,7 +2,7 @@ matrix:
platform: platform:
- linux/amd64 - linux/amd64
goversion: goversion:
- 1.25.8 - 1.26.4
labels: labels:
platform: ${platform} platform: ${platform}
@@ -21,6 +21,6 @@ steps:
event: [push,manual] event: [push,manual]
image: golang:${goversion} image: golang:${goversion}
commands: commands:
- curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/HEAD/install.sh | sh -s -- -b $(go env GOPATH)/bin v2.5.0 - curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/HEAD/install.sh | sh -s -- -b $(go env GOPATH)/bin v2.12.2
- golangci-lint --version - golangci-lint --version
- golangci-lint run ./... - golangci-lint run ./...

View File

@@ -536,7 +536,6 @@ index - manage indicies
update - update an index update - update an index
delete - delete an index delete - delete an index
close - close an index close - close an index
allocation - explain index allocation
fields - show info about field capabilities fields - show info about field capabilities
ilm - show ilm status ilm - show ilm status
alias - manage index aliases alias - manage index aliases
@@ -564,6 +563,7 @@ search - search within an index
shard - manage shards shard - manage shards
list - list shards list - list shards
show - show details about a shard show - show details about a shard
allocation - explain shard allocation
snapshot - manage snapshots snapshot - manage snapshots
list - list snapshots list - list snapshots
show - show details about a snapshot show - show details about a snapshot

View File

@@ -3,13 +3,7 @@
- index show: add more details, see screenshots - index show: add more details, see screenshots
- add shard explain, aka:
get /_cluster/allocation/explain {"index":"yourindex", "primary": true, "shard":0}
- add datastream support: - add datastream support:
https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-indices-get-data-stream https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-indices-get-data-stream
also exclude data stream backing indices from index ls 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), IndexCreate(conf, true),
IndexDelete(conf), IndexDelete(conf),
IndexClose(conf), IndexClose(conf),
IndexAllocation(conf),
IndexFields(conf), IndexFields(conf),
IndexIlm(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 { func IndexShow(conf *cfg.Config) *cli.Command {
return &cli.Command{ return &cli.Command{
Name: "show", Name: "show",

View File

@@ -35,6 +35,7 @@ func Shard(conf *cfg.Config) *cli.Command {
Commands: []*cli.Command{ Commands: []*cli.Command{
ShardList(conf), ShardList(conf),
ShardShow(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

@@ -26,7 +26,7 @@ import (
func addReference(ref string) string { func addReference(ref string) string {
indentedRef := []string{} indentedRef := []string{}
for _, line := range strings.Split(ref, "\n") { for line := range strings.SplitSeq(ref, "\n") {
indentedRef = append(indentedRef, " "+line) indentedRef = append(indentedRef, " "+line)
} }
return fmt.Sprintf("%s\nREFERENCE:\n%s\n", return fmt.Sprintf("%s\nREFERENCE:\n%s\n",

2
go.mod
View File

@@ -14,7 +14,7 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>. // along with this program. If not, see <http://www.gnu.org/licenses/>.
module codeberg.org/scip/esctl module codeberg.org/scip/esctl
go 1.25.8 go 1.26.4
require ( require (
github.com/MichaelMure/go-term-markdown v0.1.4 github.com/MichaelMure/go-term-markdown v0.1.4

View File

@@ -45,7 +45,7 @@ func (t *DebugTransport) RoundTrip(req *http.Request) (*http.Response, error) {
var pretty bytes.Buffer var pretty bytes.Buffer
err = json.Indent(&pretty, buf.Bytes(), "", "\t") err = json.Indent(&pretty, buf.Bytes(), "", "\t")
if err != nil { if err != nil {
return nil, fmt.Errorf("json parse error: %s", err) return nil, fmt.Errorf("json parse error: %w", err)
} }
content = pretty.String() content = pretty.String()

View File

@@ -94,7 +94,7 @@ func ApiRepl(conf *cfg.Config) error {
}) })
if err != nil { if err != nil {
return fmt.Errorf("failed to initialize readline lib: %s", err) return fmt.Errorf("failed to initialize readline lib: %w", err)
} }
for { for {
@@ -237,7 +237,7 @@ func CallAPI(conf *cfg.Config, verb, path, data string) ([]byte, error) {
// Read and print response // Read and print response
body, err := io.ReadAll(resp.Body) body, err := io.ReadAll(resp.Body)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to read response body: %s", err) return nil, fmt.Errorf("failed to read response body: %w", err)
} }
return body, nil return body, nil
@@ -261,7 +261,7 @@ func prettyfiJson(conf *cfg.Config, raw []byte) (string, error) {
var pretty bytes.Buffer var pretty bytes.Buffer
err := json.Indent(&pretty, raw, "", "\t") err := json.Indent(&pretty, raw, "", "\t")
if err != nil { if err != nil {
return "", fmt.Errorf("json parse error: %s", err) return "", fmt.Errorf("json parse error: %w", err)
} }
return pretty.String(), nil return pretty.String(), nil
@@ -295,7 +295,7 @@ func readJSON(input string) (string, error) {
check := map[string]any{} check := map[string]any{}
err := json.Unmarshal([]byte(data), &check) err := json.Unmarshal([]byte(data), &check)
if err != nil { if err != nil {
return "", fmt.Errorf("error: input data is not proper JSON: %s", err) return "", fmt.Errorf("error: input data is not proper JSON: %w", err)
} }

View File

@@ -58,7 +58,7 @@ func CcrStatus(conf *cfg.Config, leader, follower string) error {
res, err := conf.Clusters[alias].ES().Cat.Indices(). res, err := conf.Clusters[alias].ES().Cat.Indices().
Do(context.Background()) Do(context.Background())
if err != nil { if err != nil {
return fmt.Errorf("failed to get indicies on %s: %s", alias, esErrorString(err)) return fmt.Errorf("failed to get indicies on %s: %w", alias, esErrorString(err))
} }
indices[alias] = make(map[string]*types.IndicesRecord, len(res)) indices[alias] = make(map[string]*types.IndicesRecord, len(res))
@@ -87,7 +87,7 @@ func CcrRemoteInfo(conf *cfg.Config, index string) error {
res, err := conf.DefaultCluster.ES().Cluster.RemoteInfo(). res, err := conf.DefaultCluster.ES().Cluster.RemoteInfo().
Do(context.Background()) Do(context.Background())
if err != nil { if err != nil {
return fmt.Errorf("failed to retrieve follower info: %s", esErrorString(err)) return fmt.Errorf("failed to retrieve follower info: %w", esErrorString(err))
} }
slog.Debug("ccr remote info", "info", res) slog.Debug("ccr remote info", "info", res)

View File

@@ -29,7 +29,7 @@ func getRemoteName(conf *cfg.Config) (string, error) {
res, err := conf.DefaultCluster.ES().Cluster.RemoteInfo(). res, err := conf.DefaultCluster.ES().Cluster.RemoteInfo().
Do(context.Background()) Do(context.Background())
if err != nil { if err != nil {
return "", fmt.Errorf("failed to retrieve follower info: %s", esErrorString(err)) return "", fmt.Errorf("failed to retrieve follower info: %w", esErrorString(err))
} }
remote := "" remote := ""
@@ -91,7 +91,7 @@ func CcrFollowerResume(conf *cfg.Config, index string) error {
Do(context.Background()) Do(context.Background())
if err != nil { if err != nil {
return fmt.Errorf("failed to resume ccr following: %s", esErrorString(err)) return fmt.Errorf("failed to resume ccr following: %w", esErrorString(err))
} }
return nil return nil
@@ -102,7 +102,7 @@ func CcrFollowerPause(conf *cfg.Config, index string) error {
Do(context.Background()) Do(context.Background())
if err != nil { if err != nil {
return fmt.Errorf("failed to pause ccr following: %s", esErrorString(err)) return fmt.Errorf("failed to pause ccr following: %w", esErrorString(err))
} }
return nil return nil
@@ -113,7 +113,7 @@ func CcrFollowerUnfollow(conf *cfg.Config, index string) error {
Do(context.Background()) Do(context.Background())
if err != nil { if err != nil {
return fmt.Errorf("failed to unfollow index: %s", esErrorString(err)) return fmt.Errorf("failed to unfollow index: %w", esErrorString(err))
} }
return nil return nil
@@ -136,7 +136,7 @@ func CcrFollowerAdd(conf *cfg.Config, index string) error {
_, err = create.Do(context.Background()) _, err = create.Do(context.Background())
if err != nil { if err != nil {
return fmt.Errorf("failed to create follower index: %s", esErrorString(err)) return fmt.Errorf("failed to create follower index: %w", esErrorString(err))
} }
return nil return nil
@@ -146,7 +146,7 @@ func CcrFollowerShow(conf *cfg.Config, index string) error {
res, err := conf.DefaultCluster.ES().Ccr.FollowStats(index). res, err := conf.DefaultCluster.ES().Ccr.FollowStats(index).
Do(context.Background()) Do(context.Background())
if err != nil { if err != nil {
return fmt.Errorf("failed to retrieve follower index info: %s", esErrorString(err)) return fmt.Errorf("failed to retrieve follower index info: %w", esErrorString(err))
} }
slog.Debug("ES result", "follower stats", res.Indices) slog.Debug("ES result", "follower stats", res.Indices)

View File

@@ -44,16 +44,14 @@ func ClusterList(conf *cfg.Config) error {
// check endpoints in parallel to speed things up // check endpoints in parallel to speed things up
for name, cluster := range conf.Clusters { for name, cluster := range conf.Clusters {
wg.Add(1)
go func() { wg.Go(func() {
defer wg.Done()
online, err := cluster.IsReachable() online, err := cluster.IsReachable()
mu.Lock() mu.Lock()
reachable[name] = clusterReachable{reachable: online, err: err} reachable[name] = clusterReachable{reachable: online, err: err}
mu.Unlock() mu.Unlock()
}() })
} }
wg.Wait() wg.Wait()

View File

@@ -35,7 +35,7 @@ func ClusterSettingsList(conf *cfg.Config) error {
FlatSettings(true). FlatSettings(true).
Do(context.Background()) Do(context.Background())
if err != nil { if err != nil {
return fmt.Errorf("failed to get cluster settings: %s", esErrorString(err)) return fmt.Errorf("failed to get cluster settings: %w", esErrorString(err))
} }
table := printer.NewTable(conf, 2, 0) table := printer.NewTable(conf, 2, 0)
@@ -75,7 +75,7 @@ func ClusterSettingsSet(conf *cfg.Config, args cli.Args) error {
case conf.Transient: case conf.Transient:
message, err := json.Marshal(value) message, err := json.Marshal(value)
if err != nil { if err != nil {
return fmt.Errorf("failed to marshall transient value <%v> to valid JSON: %s", value, err) return fmt.Errorf("failed to marshall transient value <%v> to valid JSON: %w", value, err)
} }
put.AddTransient(setting, message) put.AddTransient(setting, message)
case conf.Persistent: case conf.Persistent:
@@ -83,7 +83,7 @@ func ClusterSettingsSet(conf *cfg.Config, args cli.Args) error {
default: default:
message, err := json.Marshal(value) message, err := json.Marshal(value)
if err != nil { if err != nil {
return fmt.Errorf("failed to marshall persistent value <%v> to valid JSON: %s", value, err) return fmt.Errorf("failed to marshall persistent value <%v> to valid JSON: %w", value, err)
} }
put.AddPersistent(setting, message) put.AddPersistent(setting, message)
} }
@@ -91,7 +91,7 @@ func ClusterSettingsSet(conf *cfg.Config, args cli.Args) error {
_, err := put.Do(context.Background()) _, err := put.Do(context.Background())
if err != nil { if err != nil {
return fmt.Errorf("failed to set settings: %s", esErrorString(err)) return fmt.Errorf("failed to set settings: %w", esErrorString(err))
} }
return nil return nil
@@ -100,7 +100,7 @@ func ClusterSettingsSet(conf *cfg.Config, args cli.Args) error {
func ClusterSettingsSetSingle(conf *cfg.Config, setting, value string) error { func ClusterSettingsSetSingle(conf *cfg.Config, setting, value string) error {
message, err := json.Marshal(value) message, err := json.Marshal(value)
if err != nil { if err != nil {
return fmt.Errorf("failed to marshall persistent value <%v> to valid JSON: %s", value, err) return fmt.Errorf("failed to marshall persistent value <%v> to valid JSON: %w", value, err)
} }
_, err = conf.DefaultCluster.ES().Cluster.PutSettings(). _, err = conf.DefaultCluster.ES().Cluster.PutSettings().
@@ -108,7 +108,7 @@ func ClusterSettingsSetSingle(conf *cfg.Config, setting, value string) error {
Do(context.Background()) Do(context.Background())
if err != nil { if err != nil {
return fmt.Errorf("failed to set %s: %s", setting, esErrorString(err)) return fmt.Errorf("failed to set %s: %w", setting, esErrorString(err))
} }
return nil return nil

View File

@@ -32,7 +32,7 @@ func DatastreamNames(conf *cfg.Config) ([]string, error) {
res, err := conf.DefaultCluster.ES().Indices.GetDataStream(). res, err := conf.DefaultCluster.ES().Indices.GetDataStream().
Do(context.Background()) Do(context.Background())
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to get data streams: %s", esErrorString(err)) return nil, fmt.Errorf("failed to get data streams: %w", esErrorString(err))
} }
dss := make([]string, len(res.DataStreams)) dss := make([]string, len(res.DataStreams))
@@ -47,7 +47,7 @@ func DatastreamList(conf *cfg.Config) error {
res, err := conf.DefaultCluster.ES().Indices.GetDataStream(). res, err := conf.DefaultCluster.ES().Indices.GetDataStream().
Do(context.Background()) Do(context.Background())
if err != nil { if err != nil {
return fmt.Errorf("failed to get data streams: %s", esErrorString(err)) return fmt.Errorf("failed to get data streams: %w", esErrorString(err))
} }
slog.Debug("ES result", "data streams", res) slog.Debug("ES result", "data streams", res)
@@ -128,7 +128,7 @@ func DatastreamShow(conf *cfg.Config, dsname string) error {
Name(dsname). Name(dsname).
Do(context.Background()) Do(context.Background())
if err != nil { if err != nil {
return fmt.Errorf("failed to get data stream: %s", esErrorString(err)) return fmt.Errorf("failed to get data stream: %w", esErrorString(err))
} }
slog.Debug("ES result", "data stream", res) slog.Debug("ES result", "data stream", res)
@@ -141,7 +141,7 @@ func DatastreamShow(conf *cfg.Config, dsname string) error {
Name(dsname). Name(dsname).
Do(context.Background()) Do(context.Background())
if err != nil { if err != nil {
return fmt.Errorf("failed to get data stream stats: %s", esErrorString(err)) return fmt.Errorf("failed to get data stream stats: %w", esErrorString(err))
} }
table := printer.NewTable(conf, 11, 2) table := printer.NewTable(conf, 11, 2)
@@ -208,7 +208,7 @@ func DatastreamCreate(conf *cfg.Config, dsname string) error {
Do(context.Background()) Do(context.Background())
if err != nil { if err != nil {
return fmt.Errorf("failed to create datastream: %s", esErrorString(err)) return fmt.Errorf("failed to create datastream: %w", esErrorString(err))
} }
return nil return nil
@@ -219,7 +219,7 @@ func DatastreamDelete(conf *cfg.Config, dsname string) error {
Do(context.Background()) Do(context.Background())
if err != nil { if err != nil {
return fmt.Errorf("failed to delete datastream: %s", esErrorString(err)) return fmt.Errorf("failed to delete datastream: %w", esErrorString(err))
} }
return nil return nil
@@ -229,7 +229,7 @@ func DatastreamRollover(conf *cfg.Config, ds string) error {
res, err := RolloverAlias(conf, ds) res, err := RolloverAlias(conf, ds)
if err != nil { if err != nil {
return fmt.Errorf("failed to rollover data stream: %s", esErrorString(err)) return fmt.Errorf("failed to rollover data stream: %w", esErrorString(err))
} }
table := printer.NewTable(conf, 2, 5) table := printer.NewTable(conf, 2, 5)

View File

@@ -42,7 +42,7 @@ func DocAdd(conf *cfg.Config, jsondoc string) error {
err := json.Unmarshal([]byte(jsondoc), &data) err := json.Unmarshal([]byte(jsondoc), &data)
if err != nil { if err != nil {
return fmt.Errorf("supplied document was not valid JSON: %s", err) return fmt.Errorf("supplied document was not valid JSON: %w", err)
} }
now := fmt.Sprintf("%d", rand.Int64()) now := fmt.Sprintf("%d", rand.Int64())
@@ -51,7 +51,7 @@ func DocAdd(conf *cfg.Config, jsondoc string) error {
Document(data). Document(data).
Do(context.Background()) Do(context.Background())
if err != nil { if err != nil {
return fmt.Errorf("failed to create new doc in index %s: %s", conf.Index, esErrorString(err)) return fmt.Errorf("failed to create new doc in index %s: %w", conf.Index, esErrorString(err))
} }
fmt.Println(res.Id_) fmt.Println(res.Id_)
@@ -63,7 +63,7 @@ func DocShow(conf *cfg.Config, id string) error {
res, err := conf.DefaultCluster.ES().Get(conf.Index, id). res, err := conf.DefaultCluster.ES().Get(conf.Index, id).
Do(context.Background()) Do(context.Background())
if err != nil { if err != nil {
return fmt.Errorf("failed to retrieve doc in index %s: %s", conf.Index, esErrorString(err)) return fmt.Errorf("failed to retrieve doc in index %s: %w", conf.Index, esErrorString(err))
} }
if !res.Found { if !res.Found {
@@ -94,7 +94,7 @@ func DocDelete(conf *cfg.Config, queries []string) error {
_, err := conf.DefaultCluster.ES().Delete(conf.Index, id). _, err := conf.DefaultCluster.ES().Delete(conf.Index, id).
Do(context.Background()) Do(context.Background())
if err != nil { if err != nil {
return fmt.Errorf("failed to delete doc in index %s: %s", conf.Index, esErrorString(err)) return fmt.Errorf("failed to delete doc in index %s: %w", conf.Index, esErrorString(err))
} }
return nil return nil
@@ -117,7 +117,7 @@ func DocDelete(conf *cfg.Config, queries []string) error {
Request(req). Request(req).
Do(context.Background()) Do(context.Background())
if err != nil { if err != nil {
return fmt.Errorf("failed to delete docs in index %s: %s", conf.Index, esErrorString(err)) return fmt.Errorf("failed to delete docs in index %s: %w", conf.Index, esErrorString(err))
} }
return nil return nil

View File

@@ -17,29 +17,33 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
package es package es
import ( import (
"errors"
"fmt" "fmt"
"strings"
"github.com/elastic/go-elasticsearch/v9/typedapi/types" "github.com/elastic/go-elasticsearch/v9/typedapi/types"
) )
func esErrorString(err error) string { func esErrorString(err error) error {
msg := err.Error() msg := err.Error()
switch e := err.(type) { switch e := err.(type) {
case *types.ElasticsearchError: case *types.ElasticsearchError:
causes := "" var causes strings.Builder
for _, cause := range e.ErrorCause.RootCause { for _, cause := range e.ErrorCause.RootCause {
causes += fmt.Sprintf("%s\n", *cause.Reason) // FIXME: re-activate linter here, see https://github.com/golangci/golangci-lint/issues/6662
//nolint:staticcheck
causes.WriteString(fmt.Sprintf("%s\n", *cause.Reason))
} }
if e.ErrorCause.Reason != nil { if e.ErrorCause.Reason != nil {
msg = *e.ErrorCause.Reason + ": " + causes msg = *e.ErrorCause.Reason + ": " + causes.String()
} else { } else {
msg = fmt.Sprintf("http status %d: ", e.Status) msg = fmt.Sprintf("http status %d: ", e.Status)
} }
} }
return msg return errors.New(msg)
} }

View File

@@ -37,7 +37,7 @@ func IlmRetry(conf *cfg.Config, index string) error {
_, err := conf.DefaultCluster.ES().Ilm.Retry(index). _, err := conf.DefaultCluster.ES().Ilm.Retry(index).
Do(context.Background()) Do(context.Background())
if err != nil { if err != nil {
return fmt.Errorf("failed to retry ilm: %s", esErrorString(err)) return fmt.Errorf("failed to retry ilm: %w", esErrorString(err))
} }
return nil return nil
@@ -47,7 +47,7 @@ func IlmStatus(conf *cfg.Config) error {
res, err := conf.DefaultCluster.ES().Ilm.GetStatus(). res, err := conf.DefaultCluster.ES().Ilm.GetStatus().
Do(context.Background()) Do(context.Background())
if err != nil { if err != nil {
return fmt.Errorf("failed to get ilm status: %s", esErrorString(err)) return fmt.Errorf("failed to get ilm status: %w", esErrorString(err))
} }
fmt.Println(res.OperationMode.Name) fmt.Println(res.OperationMode.Name)
@@ -59,7 +59,7 @@ func IlmNames(conf *cfg.Config) ([]string, error) {
res, err := conf.DefaultCluster.ES().Ilm.GetLifecycle(). res, err := conf.DefaultCluster.ES().Ilm.GetLifecycle().
Do(context.Background()) Do(context.Background())
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to get ilm policies: %s", esErrorString(err)) return nil, fmt.Errorf("failed to get ilm policies: %w", esErrorString(err))
} }
names := make([]string, len(res)) names := make([]string, len(res))
@@ -82,7 +82,7 @@ func IlmList(conf *cfg.Config, pattern string) error {
res, err := ilm.Do(context.Background()) res, err := ilm.Do(context.Background())
if err != nil { if err != nil {
return fmt.Errorf("failed to get ilm policies: %s", esErrorString(err)) return fmt.Errorf("failed to get ilm policies: %w", esErrorString(err))
} }
if conf.Debug { if conf.Debug {
@@ -110,7 +110,7 @@ func IlmShow(conf *cfg.Config, policy string) error {
Policy(policy). Policy(policy).
Do(context.Background()) Do(context.Background())
if err != nil { if err != nil {
return fmt.Errorf("failed to get ilm status: %s", esErrorString(err)) return fmt.Errorf("failed to get ilm status: %w", esErrorString(err))
} }
if conf.Debug { if conf.Debug {
@@ -270,7 +270,7 @@ func IlmExplain(conf *cfg.Config, index string) error {
res, err := conf.DefaultCluster.ES().Ilm.ExplainLifecycle(index). res, err := conf.DefaultCluster.ES().Ilm.ExplainLifecycle(index).
Do(context.Background()) Do(context.Background())
if err != nil { if err != nil {
return fmt.Errorf("failed to get ilm state: %s", esErrorString(err)) return fmt.Errorf("failed to get ilm state: %w", esErrorString(err))
} }
slog.Debug("ilm status", "ilm", res) slog.Debug("ilm status", "ilm", res)
@@ -523,7 +523,7 @@ func IlmCreate(conf *cfg.Config, policyname string) error {
_, err = ilm.Do(context.Background()) _, err = ilm.Do(context.Background())
if err != nil { if err != nil {
return fmt.Errorf("failed create ilm policy: %s", esErrorString(err)) return fmt.Errorf("failed create ilm policy: %w", esErrorString(err))
} }
return nil return nil

View File

@@ -157,11 +157,7 @@ func IlmForecastShow(conf *cfg.Config) error {
var toBeFreed int64 = 0 var toBeFreed int64 = 0
for _, phase := range phaseData { for _, phase := range phaseData {
age := virtualAge(&phase) age := max(virtualAge(&phase), phase.age)
if age < phase.age {
age = phase.age
}
if age+within >= phase.minage { if age+within >= phase.minage {
toBeFreed += phase.size toBeFreed += phase.size
@@ -200,7 +196,7 @@ func getIlmPhaseData(conf *cfg.Config) ([]PhaseData, error) {
var indicesres *indices.Response var indicesres *indices.Response
var ilmpolicies getlifecycle.Response var ilmpolicies getlifecycle.Response
for i := 0; i < 3; i++ { for range 3 {
r := <-responses r := <-responses
if r.error != nil { if r.error != nil {

View File

@@ -39,7 +39,7 @@ func IndexNames(conf *cfg.Config) ([]string, error) {
Do(context.Background()) Do(context.Background())
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to get indicies: %s", esErrorString(err)) return nil, fmt.Errorf("failed to get indicies: %w", esErrorString(err))
} }
indices := make([]string, len(res)) indices := make([]string, len(res))
@@ -97,7 +97,7 @@ func IndexList(conf *cfg.Config) error {
res, err := cat.Do(context.Background()) res, err := cat.Do(context.Background())
if err != nil { if err != nil {
return fmt.Errorf("failed to get indicies: %s", esErrorString(err)) return fmt.Errorf("failed to get indicies: %w", esErrorString(err))
} }
slog.Debug("ES result", "indicies", res) slog.Debug("ES result", "indicies", res)
@@ -133,7 +133,7 @@ func IndexShow(conf *cfg.Config, indexpattern string) error {
res, err := conf.DefaultCluster.ES().Indices.Get(indexpattern). res, err := conf.DefaultCluster.ES().Indices.Get(indexpattern).
Do(context.Background()) Do(context.Background())
if err != nil { if err != nil {
return fmt.Errorf("failed to get index: %s", esErrorString(err)) return fmt.Errorf("failed to get index: %w", esErrorString(err))
} }
slog.Debug("index show", "index", res) slog.Debug("index show", "index", res)
@@ -234,7 +234,7 @@ func IndexCreate(conf *cfg.Config, index string, mappings []string) error {
Do(context.Background()) Do(context.Background())
if err != nil { if err != nil {
return fmt.Errorf("failed to create index: %s", esErrorString(err)) return fmt.Errorf("failed to create index: %w", esErrorString(err))
} }
return nil return nil
@@ -244,7 +244,7 @@ func IndexDelete(conf *cfg.Config, index string) error {
_, err := conf.DefaultCluster.ES().Indices.Delete(index). _, err := conf.DefaultCluster.ES().Indices.Delete(index).
Do(context.Background()) Do(context.Background())
if err != nil { if err != nil {
return fmt.Errorf("failed to delete index: %s", esErrorString(err)) return fmt.Errorf("failed to delete index: %w", esErrorString(err))
} }
return nil return nil
@@ -255,77 +255,19 @@ func IndexClose(conf *cfg.Config, index string) error {
Do(context.Background()) Do(context.Background())
if err != nil { if err != nil {
return fmt.Errorf("failed to close index: %s", esErrorString(err)) return fmt.Errorf("failed to close index: %w", esErrorString(err))
} }
return nil 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 { func IndexFields(conf *cfg.Config, index string) error {
res, err := conf.DefaultCluster.ES().FieldCaps(). res, err := conf.DefaultCluster.ES().FieldCaps().
Index(index). Index(index).
Fields("*"). Fields("*").
Do(context.Background()) Do(context.Background())
if err != nil { if err != nil {
return fmt.Errorf("failed to retrieve field capabilties: %s", esErrorString(err)) return fmt.Errorf("failed to retrieve field capabilties: %w", esErrorString(err))
} }
table := printer.NewTable(conf, 5, 0) table := printer.NewTable(conf, 5, 0)

View File

@@ -35,7 +35,7 @@ func IndexAliasCreate(conf *cfg.Config, index, alias string) error {
slog.Debug("create alias", "result", res) slog.Debug("create alias", "result", res)
if err != nil { if err != nil {
return fmt.Errorf("failed to create index alias: %s", esErrorString(err)) return fmt.Errorf("failed to create index alias: %w", esErrorString(err))
} }
return nil return nil
@@ -54,7 +54,7 @@ func IndexAliasList(conf *cfg.Config) error {
Do(context.Background()) Do(context.Background())
if err != nil { if err != nil {
return fmt.Errorf("failed to list index aliases: %s", esErrorString(err)) return fmt.Errorf("failed to list index aliases: %w", esErrorString(err))
} }
slog.Debug("aliases list", "result", res) slog.Debug("aliases list", "result", res)
@@ -102,7 +102,7 @@ func IndexAliasDelete(conf *cfg.Config, index, alias string) error {
slog.Debug("delete alias", "result", res) slog.Debug("delete alias", "result", res)
if err != nil { if err != nil {
return fmt.Errorf("failed to delete index alias: %s", esErrorString(err)) return fmt.Errorf("failed to delete index alias: %w", esErrorString(err))
} }
return nil return nil
@@ -112,7 +112,7 @@ func IndexAliasRollover(conf *cfg.Config, alias string) error {
res, err := RolloverAlias(conf, alias) res, err := RolloverAlias(conf, alias)
if err != nil { if err != nil {
return fmt.Errorf("failed to rollover index alias: %s", esErrorString(err)) return fmt.Errorf("failed to rollover index alias: %w", esErrorString(err))
} }
table := printer.NewTable(conf, 2, 5) table := printer.NewTable(conf, 2, 5)

View File

@@ -22,6 +22,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"log/slog" "log/slog"
"maps"
"strconv" "strconv"
"strings" "strings"
@@ -37,7 +38,7 @@ func IndexTemplateList(conf *cfg.Config) error {
Do(context.Background()) Do(context.Background())
if err != nil { if err != nil {
return fmt.Errorf("failed to get index templates: %s", esErrorString(err)) return fmt.Errorf("failed to get index templates: %w", esErrorString(err))
} }
slog.Debug("res", "index templates", res) slog.Debug("res", "index templates", res)
@@ -64,7 +65,7 @@ func IndexTemplateShow(conf *cfg.Config, tplname string) error {
Do(context.Background()) Do(context.Background())
if err != nil { if err != nil {
return fmt.Errorf("failed to get index template: %s", esErrorString(err)) return fmt.Errorf("failed to get index template: %w", esErrorString(err))
} }
slog.Debug("res", "index template", res) slog.Debug("res", "index template", res)
@@ -225,7 +226,7 @@ func IndexTemplateCreate(conf *cfg.Config, name string, mappings []string) error
_, err := create.Do(context.Background()) _, err := create.Do(context.Background())
if err != nil { if err != nil {
return fmt.Errorf("failed to create index template: %s", esErrorString(err)) return fmt.Errorf("failed to create index template: %w", esErrorString(err))
} }
return nil return nil
@@ -242,7 +243,7 @@ func IndexTemplateModify(conf *cfg.Config, name string, mappings []string) error
Do(context.Background()) Do(context.Background())
if err != nil { if err != nil {
return fmt.Errorf("failed to get index template: %s", esErrorString(err)) return fmt.Errorf("failed to get index template: %w", esErrorString(err))
} }
slog.Debug("res", "index template", res) slog.Debug("res", "index template", res)
@@ -336,7 +337,7 @@ func IndexTemplateModify(conf *cfg.Config, name string, mappings []string) error
_, err = modify.Do(context.Background()) _, err = modify.Do(context.Background())
if err != nil { if err != nil {
return fmt.Errorf("failed to modify index template: %s", esErrorString(err)) return fmt.Errorf("failed to modify index template: %w", esErrorString(err))
} }
if conf.Rollover { if conf.Rollover {
@@ -352,7 +353,7 @@ func IndexTemplateDelete(conf *cfg.Config, name string) error {
_, err := conf.DefaultCluster.ES().Indices.DeleteIndexTemplate(name). _, err := conf.DefaultCluster.ES().Indices.DeleteIndexTemplate(name).
Do(context.Background()) Do(context.Background())
if err != nil { if err != nil {
return fmt.Errorf("failed to delete index template: %s", esErrorString(err)) return fmt.Errorf("failed to delete index template: %w", esErrorString(err))
} }
return nil return nil
@@ -367,7 +368,7 @@ func rolloverAliasIndexTemplate(conf *cfg.Config, name string) error {
Do(context.Background()) Do(context.Background())
if err != nil { if err != nil {
return fmt.Errorf("failed to get index template: %s", esErrorString(err)) return fmt.Errorf("failed to get index template: %w", esErrorString(err))
} }
slog.Debug("res", "index template", res) slog.Debug("res", "index template", res)
@@ -384,7 +385,7 @@ func rolloverAliasIndexTemplate(conf *cfg.Config, name string) error {
res, err := conf.DefaultCluster.ES().Indices.ResolveIndex(pattern). res, err := conf.DefaultCluster.ES().Indices.ResolveIndex(pattern).
Do(context.Background()) Do(context.Background())
if err != nil { if err != nil {
return fmt.Errorf("failed to resolve index pattern: %s", esErrorString(err)) return fmt.Errorf("failed to resolve index pattern: %w", esErrorString(err))
} }
for _, index := range res.Indices { for _, index := range res.Indices {
@@ -448,9 +449,7 @@ func modMappings(mappings []string) (types.TypeMappingVariant, error) {
func modMeta(conf *cfg.Config, meta types.Metadata) (map[string]json.RawMessage, error) { func modMeta(conf *cfg.Config, meta types.Metadata) (map[string]json.RawMessage, error) {
metadata := map[string]json.RawMessage{} metadata := map[string]json.RawMessage{}
for key, value := range meta { maps.Copy(metadata, meta)
metadata[key] = value
}
for _, meta := range conf.Meta { for _, meta := range conf.Meta {
parts := strings.Split(meta, ":") parts := strings.Split(meta, ":")

View File

@@ -29,7 +29,7 @@ func LicenseShow(conf *cfg.Config) error {
res, err := conf.DefaultCluster.ES().License.Get(). res, err := conf.DefaultCluster.ES().License.Get().
Do(context.Background()) Do(context.Background())
if err != nil { if err != nil {
return fmt.Errorf("failed to get license: %s", esErrorString(err)) return fmt.Errorf("failed to get license: %w", esErrorString(err))
} }
slog.Debug("license show", "license", res) slog.Debug("license show", "license", res)

View File

@@ -32,7 +32,7 @@ func NodeList(conf *cfg.Config) error {
// get nodes // get nodes
nodes, err := conf.DefaultCluster.ES().Cat.Nodes().Do(context.Background()) nodes, err := conf.DefaultCluster.ES().Cat.Nodes().Do(context.Background())
if err != nil { if err != nil {
return fmt.Errorf("failed to get nodes: %s", esErrorString(err)) return fmt.Errorf("failed to get nodes: %w", esErrorString(err))
} }
slog.Debug("ES result", "nodes", nodes) slog.Debug("ES result", "nodes", nodes)
@@ -64,7 +64,7 @@ func NodeNames(conf *cfg.Config) ([]string, error) {
nodes, err := conf.DefaultCluster.ES().Cat.Nodes(). nodes, err := conf.DefaultCluster.ES().Cat.Nodes().
Do(context.Background()) Do(context.Background())
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to get nodes: %s", esErrorString(err)) return nil, fmt.Errorf("failed to get nodes: %w", esErrorString(err))
} }
slog.Debug("ES result", "nodes", nodes) slog.Debug("ES result", "nodes", nodes)
@@ -86,7 +86,7 @@ func NodeShow(conf *cfg.Config, nodename string) error {
Metric("os, jvm, thread_pool, remote_cluster_server"). Metric("os, jvm, thread_pool, remote_cluster_server").
Do(context.Background()) Do(context.Background())
if err != nil { if err != nil {
return fmt.Errorf("failed to get node info: %s", esErrorString(err)) return fmt.Errorf("failed to get node info: %w", esErrorString(err))
} }
slog.Debug("ES result", "node", res) slog.Debug("ES result", "node", res)
@@ -95,7 +95,7 @@ func NodeShow(conf *cfg.Config, nodename string) error {
NodeId(nodename). NodeId(nodename).
Do(context.Background()) Do(context.Background())
if err != nil { if err != nil {
return fmt.Errorf("failed to get node stats: %s", esErrorString(err)) return fmt.Errorf("failed to get node stats: %w", esErrorString(err))
} }
slog.Debug("ES result", "stat", stats) slog.Debug("ES result", "stat", stats)
@@ -159,7 +159,7 @@ func NodeClients(conf *cfg.Config, nodename string) error {
NodeId(nodename). NodeId(nodename).
Do(context.Background()) Do(context.Background())
if err != nil { if err != nil {
return fmt.Errorf("failed to get node stats: %s", esErrorString(err)) return fmt.Errorf("failed to get node stats: %w", esErrorString(err))
} }
slog.Debug("ES result", "stat", stats) slog.Debug("ES result", "stat", stats)

View File

@@ -158,7 +158,7 @@ func getApiData(
} }
if arerr != nil { if arerr != nil {
ar.error = fmt.Errorf("failed to get data from API: %s", arerr) ar.error = fmt.Errorf("failed to get data from API: %w", arerr)
} }
reschan <- ar reschan <- ar

View File

@@ -30,7 +30,7 @@ func RoleNames(conf *cfg.Config) ([]string, error) {
res, err := conf.DefaultCluster.ES().Security.GetRole(). res, err := conf.DefaultCluster.ES().Security.GetRole().
Do(context.Background()) Do(context.Background())
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to get roles: %s", esErrorString(err)) return nil, fmt.Errorf("failed to get roles: %w", esErrorString(err))
} }
roles := make([]string, len(res)) roles := make([]string, len(res))
@@ -47,7 +47,7 @@ func RoleList(conf *cfg.Config) error {
res, err := conf.DefaultCluster.ES().Security.GetRole(). res, err := conf.DefaultCluster.ES().Security.GetRole().
Do(context.Background()) Do(context.Background())
if err != nil { if err != nil {
return fmt.Errorf("failed to get roles: %s", esErrorString(err)) return fmt.Errorf("failed to get roles: %w", esErrorString(err))
} }
slog.Debug("ES result", "roles", res) slog.Debug("ES result", "roles", res)
@@ -74,7 +74,7 @@ func RoleShow(conf *cfg.Config, rolename string) error {
Name(rolename). Name(rolename).
Do(context.Background()) Do(context.Background())
if err != nil { if err != nil {
return fmt.Errorf("failed to get role: %s", esErrorString(err)) return fmt.Errorf("failed to get role: %w", esErrorString(err))
} }
slog.Debug("ES result", "role", res) slog.Debug("ES result", "role", res)

View File

@@ -75,7 +75,7 @@ type Register struct {
func getCsvRecords(conf *cfg.Config, csvfile string) (map[string]Record, error) { func getCsvRecords(conf *cfg.Config, csvfile string) (map[string]Record, error) {
data, err := os.ReadFile(csvfile) data, err := os.ReadFile(csvfile)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to read CSV file: %s", err) return nil, fmt.Errorf("failed to read CSV file: %w", err)
} }
csvreader := csv.NewReader(bytes.NewReader(data)) csvreader := csv.NewReader(bytes.NewReader(data))
@@ -85,7 +85,7 @@ func getCsvRecords(conf *cfg.Config, csvfile string) (map[string]Record, error)
rows, err := csvreader.ReadAll() rows, err := csvreader.ReadAll()
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to parse CSV: %s", err) return nil, fmt.Errorf("failed to parse CSV: %w", err)
} }
records := make(map[string]Record, len(rows)-1) records := make(map[string]Record, len(rows)-1)
@@ -118,7 +118,7 @@ func getCsvRecords(conf *cfg.Config, csvfile string) (map[string]Record, error)
func getCsvRecord(conf *cfg.Config, csvfile, rolename string) (*Record, error) { func getCsvRecord(conf *cfg.Config, csvfile, rolename string) (*Record, error) {
fd, err := os.Open(csvfile) fd, err := os.Open(csvfile)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to open CSV file: %s", err) return nil, fmt.Errorf("failed to open CSV file: %w", err)
} }
defer func() { defer func() {
if err := fd.Close(); err != nil { if err := fd.Close(); err != nil {
@@ -210,7 +210,7 @@ func RoleDiff(conf *cfg.Config, csvfile, role string) error {
res, err := conf.DefaultCluster.ES().Security.GetRole(). res, err := conf.DefaultCluster.ES().Security.GetRole().
Do(context.Background()) Do(context.Background())
if err != nil { if err != nil {
return fmt.Errorf("failed to get roles: %s", esErrorString(err)) return fmt.Errorf("failed to get roles: %w", esErrorString(err))
} }
rows := diffRoles(conf, records, res) rows := diffRoles(conf, records, res)
@@ -245,7 +245,7 @@ func getRoleMappingGroups(conf *cfg.Config, rolename string) ([]string, error) {
mappings, err := conf.DefaultCluster.ES().Security.GetRoleMapping(). mappings, err := conf.DefaultCluster.ES().Security.GetRoleMapping().
Do(context.Background()) Do(context.Background())
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to get role mappings: %s", esErrorString(err)) return nil, fmt.Errorf("failed to get role mappings: %w", esErrorString(err))
} }
groups := []string{} groups := []string{}
@@ -279,7 +279,7 @@ func RoleDiffSingle(conf *cfg.Config, csvfile, rolename string) error {
Name(rolename). Name(rolename).
Do(context.Background()) Do(context.Background())
if err != nil { if err != nil {
return fmt.Errorf("failed to get role: %s", esErrorString(err)) return fmt.Errorf("failed to get role: %w", esErrorString(err))
} }
record, err := getCsvRecord(conf, csvfile, rolename) record, err := getCsvRecord(conf, csvfile, rolename)

View File

@@ -82,13 +82,13 @@ func explainSearch(conf *cfg.Config, search *search.Search) error {
Size(1). // one's enough for explain Size(1). // one's enough for explain
Do(context.Background()) Do(context.Background())
if err != nil { if err != nil {
return fmt.Errorf("failed to call explain search (esdsl): %s", esErrorString(err)) return fmt.Errorf("failed to call explain search (esdsl): %w", esErrorString(err))
} }
if conf.Debug { if conf.Debug {
raw, err := json.Marshal(res) raw, err := json.Marshal(res)
if err != nil { if err != nil {
return fmt.Errorf("failed to marshal explain result: %s", err) return fmt.Errorf("failed to marshal explain result: %w", err)
} }
value := gjson.Get(string(raw), "hits.hits.0._explanation") value := gjson.Get(string(raw), "hits.hits.0._explanation")
@@ -134,7 +134,7 @@ func validateSearch(conf *cfg.Config, queries []string) error {
res, err := validate. res, err := validate.
Do(context.Background()) Do(context.Background())
if err != nil { if err != nil {
return fmt.Errorf("failed to validate search (esdsl): %s", esErrorString(err)) return fmt.Errorf("failed to validate search (esdsl): %w", esErrorString(err))
} }
slog.Debug("ES result", "search", res) slog.Debug("ES result", "search", res)
@@ -154,7 +154,7 @@ func searchOnce(conf *cfg.Config, search *search.Search) error {
Size(conf.To). Size(conf.To).
Do(context.Background()) Do(context.Background())
if err != nil { if err != nil {
return fmt.Errorf("failed to run search (esdsl): %s", esErrorString(err)) return fmt.Errorf("failed to run search (esdsl): %w", esErrorString(err))
} }
slog.Debug("ES result", "search", res) slog.Debug("ES result", "search", res)
@@ -169,7 +169,7 @@ func searchPit(conf *cfg.Config, req *search.Request) error {
ctx := context.Background() ctx := context.Background()
pit, err := conf.DefaultCluster.ES().OpenPointInTime(conf.Index).KeepAlive("1m").Do(ctx) pit, err := conf.DefaultCluster.ES().OpenPointInTime(conf.Index).KeepAlive("1m").Do(ctx)
if err != nil { if err != nil {
return fmt.Errorf("failed to open point-in-time request for search: %s", err) return fmt.Errorf("failed to open point-in-time request for search: %w", err)
} }
defer func() { defer func() {
_, err := conf.DefaultCluster.ES().ClosePointInTime().Id(pit.Id).Do(ctx) _, err := conf.DefaultCluster.ES().ClosePointInTime().Id(pit.Id).Do(ctx)
@@ -192,7 +192,7 @@ func searchPit(conf *cfg.Config, req *search.Request) error {
for { for {
res, err := search.Do(ctx) res, err := search.Do(ctx)
if err != nil { if err != nil {
return fmt.Errorf("failed to run search (esdsl pit): %s", esErrorString(err)) return fmt.Errorf("failed to run search (esdsl pit): %w", esErrorString(err))
} }
if len(res.Hits.Hits) == 0 { if len(res.Hits.Hits) == 0 {
@@ -222,7 +222,7 @@ func searchTail(conf *cfg.Config, search *search.Search) error {
for { for {
res, err := search.Do(context.Background()) res, err := search.Do(context.Background())
if err != nil { if err != nil {
return fmt.Errorf("failed to run search (esdsl): %s", esErrorString(err)) return fmt.Errorf("failed to run search (esdsl): %w", esErrorString(err))
} }
slog.Debug("ES result", "search", res) slog.Debug("ES result", "search", res)

View File

@@ -86,7 +86,7 @@ func ShardList(conf *cfg.Config) error {
res, err := conf.DefaultCluster.ES().Cat.Shards(). res, err := conf.DefaultCluster.ES().Cat.Shards().
Do(context.Background()) Do(context.Background())
if err != nil { if err != nil {
return fmt.Errorf("failed to get shards: %s", esErrorString(err)) return fmt.Errorf("failed to get shards: %w", esErrorString(err))
} }
shardlist := filterShards(conf, res) shardlist := filterShards(conf, res)
@@ -136,7 +136,7 @@ func ShardShow(conf *cfg.Config, index string) error {
res, err := conf.DefaultCluster.ES().Cat.Shards().Index(index). res, err := conf.DefaultCluster.ES().Cat.Shards().Index(index).
Do(context.Background()) Do(context.Background())
if err != nil { if err != nil {
return fmt.Errorf("failed to get shards: %s", esErrorString(err)) return fmt.Errorf("failed to get shards: %w", esErrorString(err))
} }
slog.Debug("ES result", "shards", res) slog.Debug("ES result", "shards", res)
@@ -145,3 +145,63 @@ func ShardShow(conf *cfg.Config, index string) error {
return printShards(conf, res) 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: %w", 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
}

View File

@@ -45,7 +45,7 @@ func SnapshotList(conf *cfg.Config) error {
// get partial indicies // get partial indicies
ires, err := conf.DefaultCluster.ES().Cat.Indices().Do(context.Background()) ires, err := conf.DefaultCluster.ES().Cat.Indices().Do(context.Background())
if err != nil { if err != nil {
return fmt.Errorf("failed to get indicies: %s", esErrorString(err)) return fmt.Errorf("failed to get indicies: %w", esErrorString(err))
} }
indicies := map[string]int{} indicies := map[string]int{}
@@ -58,7 +58,7 @@ func SnapshotList(conf *cfg.Config) error {
// get snapshots // get snapshots
sres, err := conf.DefaultCluster.ES().Cat.Snapshots().Do(context.Background()) sres, err := conf.DefaultCluster.ES().Cat.Snapshots().Do(context.Background())
if err != nil { if err != nil {
return fmt.Errorf("failed to get snapshots: %s", esErrorString(err)) return fmt.Errorf("failed to get snapshots: %w", esErrorString(err))
} }
slog.Debug("ES result", "indicies", sres) slog.Debug("ES result", "indicies", sres)
@@ -108,7 +108,7 @@ func SnapshotList(conf *cfg.Config) error {
func SnapshotShow(conf *cfg.Config, snapshot string) error { func SnapshotShow(conf *cfg.Config, snapshot string) error {
res, err := conf.DefaultCluster.ES().Snapshot.Get("*", snapshot).Do(context.Background()) res, err := conf.DefaultCluster.ES().Snapshot.Get("*", snapshot).Do(context.Background())
if err != nil { if err != nil {
return fmt.Errorf("failed to get snapshot: %s", esErrorString(err)) return fmt.Errorf("failed to get snapshot: %w", esErrorString(err))
} }
slog.Debug("ES result", "snapshot", res) slog.Debug("ES result", "snapshot", res)

View File

@@ -32,7 +32,7 @@ func TaskList(conf *cfg.Config) error {
Do(context.Background()) Do(context.Background())
if err != nil { if err != nil {
return fmt.Errorf("failed to get index templates: %s", esErrorString(err)) return fmt.Errorf("failed to get index templates: %w", esErrorString(err))
} }
slog.Debug("res", "tasks", res) slog.Debug("res", "tasks", res)
@@ -68,7 +68,7 @@ func TaskCancel(conf *cfg.Config, taskid string) error {
Do(context.Background()) Do(context.Background())
if err != nil { if err != nil {
return fmt.Errorf("failed to cancel task: %s", esErrorString(err)) return fmt.Errorf("failed to cancel task: %w", esErrorString(err))
} }
return nil return nil

View File

@@ -115,13 +115,6 @@ func (m model) footerView() string {
return lipgloss.JoinHorizontal(lipgloss.Center, line, info) return lipgloss.JoinHorizontal(lipgloss.Center, line, info)
} }
func max(a, b int) int {
if a > b {
return a
}
return b
}
func Pager(title, message string) { func Pager(title, message string) {
p := tea.NewProgram( p := tea.NewProgram(
model{content: message, title: title}, model{content: message, title: title},

View File

@@ -104,7 +104,7 @@ func (data *Table) PrintYAML() error {
body, err := yaml.Marshal(raw) body, err := yaml.Marshal(raw)
if err != nil { if err != nil {
return fmt.Errorf("failed to produce YAML output: %s", err) return fmt.Errorf("failed to produce YAML output: %w", err)
} }
fmt.Println(string(body)) fmt.Println(string(body))
@@ -117,7 +117,7 @@ func (data *Table) PrintJSON() error {
body, err := json.MarshalIndent(raw, "", " ") body, err := json.MarshalIndent(raw, "", " ")
if err != nil { if err != nil {
return fmt.Errorf("failed to produce JSON output: %s", err) return fmt.Errorf("failed to produce JSON output: %w", err)
} }
fmt.Println(string(body)) fmt.Println(string(body))