Files
esctl/pkg/es/snapshot.go
2026-07-07 10:41:34 +02:00

157 lines
3.6 KiB
Go

/*
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 <http://www.gnu.org/licenses/>.
*/
package es
import (
"context"
"errors"
"fmt"
"log/slog"
"regexp"
"strings"
"codeberg.org/scip/esctl/pkg/cfg"
"codeberg.org/scip/esctl/pkg/printer"
)
var (
findIndex = regexp.MustCompile(`^\d{4}\.\d{2}\.\d{2}\-(.*)\-timeseries`)
)
type Snapshot struct {
Name string
Forindex string
Orphaned string
Status string
Start string
IndexCount int
}
func SnapshotList(conf *cfg.Config) error {
// get partial indicies
ires, err := conf.DefaultCluster.ES().Cat.Indices().Do(context.Background())
if err != nil {
return fmt.Errorf("failed to get indicies: %w", esErrorString(err))
}
indicies := map[string]int{}
for _, index := range ires {
name := strings.ReplaceAll(*index.Index, "partial-", "")
indicies[name] = 1
}
// get snapshots
sres, err := conf.DefaultCluster.ES().Cat.Snapshots().Do(context.Background())
if err != nil {
return fmt.Errorf("failed to get snapshots: %w", esErrorString(err))
}
slog.Debug("ES result", "indicies", sres)
snapshots := []*Snapshot{} // original snapshot names
for _, snapshot := range sres {
snap := &Snapshot{
Name: *snapshot.Id,
Status: *snapshot.Status,
Start: fmt.Sprintf("%s", snapshot.StartTime),
Forindex: indexFromSnapshot(*snapshot.Id),
Orphaned: "no",
}
_, exists := indicies[snap.Forindex]
if !exists {
snap.Orphaned = "orphaned"
}
if (conf.Failed && snap.Orphaned == "orphaned") || !conf.Failed {
snapshots = append(snapshots, snap)
}
}
table := printer.NewTable(conf, 5, len(snapshots))
table.Addheaders("name", "index", "start", "orphaned", "status")
for idx, snap := range snapshots {
table.Entries[idx] = []any{
snap.Name,
snap.Forindex,
snap.Start,
snap.Orphaned,
snap.Status,
}
}
table.Sort()
if err := table.Print(); err != nil {
return err
}
return nil
}
func SnapshotShow(conf *cfg.Config, snapshot string) error {
res, err := conf.DefaultCluster.ES().Snapshot.Get("*", snapshot).Do(context.Background())
if err != nil {
return fmt.Errorf("failed to get snapshot: %w", esErrorString(err))
}
slog.Debug("ES result", "snapshot", res)
if res.Total == 0 {
return errors.New("no snapshot retrieved")
}
table := printer.NewTable(conf, 2, 17)
table.Addheaders("snapshot property", "value")
snap := res.Snapshots[0]
table.Entries = [][]any{
{"snapshot", snapshot},
{"uuid", snap.Uuid},
{"repository", *snap.Repository},
{"version_id", snap.VersionId},
{"version", *snap.Version},
{"include_global_state", *snap.IncludeGlobalState},
{"state", *snap.State},
{"start_time", snap.StartTime},
{"end_time", snap.EndTime},
{"duration_in_millis", *snap.DurationInMillis},
{"shards-total", snap.Shards.Total},
{"shards-failed", snap.Shards.Failed},
{"shards-successful", snap.Shards.Successful},
}
if err := table.Print(); err != nil {
return err
}
return nil
}
func indexFromSnapshot(snapshot string) string {
matches := findIndex.FindStringSubmatch(snapshot)
if len(matches) != 2 {
return ""
}
return matches[1]
}