Files
nmon/internal/backup/vmverify.go

63 lines
2.0 KiB
Go

package backup
import (
"context"
"errors"
"fmt"
"net/http"
"os"
"path/filepath"
"time"
"github.com/v10networks/nmon/internal/vmsup"
)
// openStaged opens a file still in the restore staging area.
func openStaged(dataDir, name string) (*os.File, error) {
return os.Open(filepath.Join(dataDir, stagingDir, name))
}
// VMVerifier verifies series by starting the restored stores for a moment under a vmsup.Supervisor and
// comparing each fingerprint with a live /api/v1/export. This is the strongest check available (the real
// store reads the real restored files) and needs the embedded store binary, so it runs wherever
// nmon itself runs.
type VMVerifier struct{ opts vmsup.Options }
// NewVMVerifier returns a VMVerifier; opts.DataDir is set per call. Retention defaults are the supervisor's.
func NewVMVerifier(opts vmsup.Options) *VMVerifier { return &VMVerifier{opts: opts} }
// VerifySeries implements SeriesVerifier.
func (v *VMVerifier) VerifySeries(ctx context.Context, dataDir string, boundary time.Time, stores []StoreManifest) (err error) {
opts := v.opts
opts.DataDir = dataDir
sup, err := vmsup.New(opts)
if err != nil {
return err
}
sctx, cancel := context.WithTimeout(ctx, 2*time.Minute)
defer cancel()
if err := sup.Start(sctx); err != nil {
return fmt.Errorf("start restored stores: %w", err)
}
defer func() {
stopCtx, stop := context.WithTimeout(context.WithoutCancel(ctx), time.Minute)
defer stop()
err = errors.Join(err, sup.Stop(stopCtx))
}()
hc := &http.Client{Timeout: time.Minute}
for _, s := range stores {
api := vmAPI{hc: hc, base: sup.URL(s.Name)}
for _, want := range s.Series {
got, err := api.fingerprint(ctx, want.Selector, boundary)
if err != nil {
return fmt.Errorf("%s store: %w", s.Name, err)
}
if got != want {
return fmt.Errorf("%s store: series %s has %d samples (sha %.12s), backup had %d (sha %.12s)",
s.Name, want.Selector, got.Samples, got.SHA256, want.Samples, want.SHA256)
}
}
}
return nil
}