mesh/check failed: ace: novox/mesh-catalog#442: checks/particulars/go.mod cannot be read to check its mesh-sdk pin: Gitea API /repos/novox/mesh-catalo…
mesh/merge-gate head 98ca97fc5b3f merged into trunk dcf6e86d0236 — pass: builds nats, sent nowhere; merging this needs a person's bus upgrade; 1 wait(s) fo…
mesh/repo-check head 98ca97fc5b3f merged into trunk dcf6e86d0236 — pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-…
mesh/delivery delivered
The upgrade and restore steps told a person to docker exec the snapshot program; no mesh tool did it. nats_snapshot_verify reads the newest bus.tar of the snapshots directory only.
110 lines
3.2 KiB
Go
110 lines
3.2 KiB
Go
package busarchive
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"io/fs"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
// StreamReport is one stream of a verified snapshot.
|
|
type StreamReport struct {
|
|
Name string `json:"name"`
|
|
LastSeq uint64 `json:"last_seq"`
|
|
}
|
|
|
|
// Report is the answer of VerifyFile: which file was held to its manifest, and whether it passed.
|
|
type Report struct {
|
|
File string `json:"file"`
|
|
Modified time.Time `json:"modified"`
|
|
Size int64 `json:"size"`
|
|
Taken *time.Time `json:"taken,omitempty"`
|
|
Streams []StreamReport `json:"streams"`
|
|
Skipped []Skipped `json:"skipped,omitempty"`
|
|
Passed bool `json:"passed"`
|
|
// Fault is the first thing wrong, empty when the snapshot passed.
|
|
Fault string `json:"fault,omitempty"`
|
|
}
|
|
|
|
// VerifyFile verifies one snapshot inside dir: the file called name, or the newest *.tar when name is
|
|
// empty. Nothing outside dir is read and nothing is written there; a snapshot that fails is an answer
|
|
// (Passed false, the first Fault), and only a directory without a snapshot is an error.
|
|
func VerifyFile(dir, name string) (*Report, error) {
|
|
path, info, err := pick(dir, name)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
r := &Report{File: filepath.Base(path), Modified: info.ModTime().UTC(), Size: info.Size(), Streams: []StreamReport{}}
|
|
f, err := os.Open(path)
|
|
if err != nil {
|
|
r.Fault = err.Error()
|
|
return r, nil
|
|
}
|
|
defer f.Close()
|
|
a, err := ReadArchive(f, "")
|
|
if err != nil {
|
|
r.Fault = err.Error()
|
|
return r, nil
|
|
}
|
|
defer a.Close()
|
|
taken := a.Manifest.Finished
|
|
r.Taken = &taken
|
|
r.Skipped = a.Manifest.Skipped
|
|
for _, s := range a.Manifest.Streams {
|
|
r.Streams = append(r.Streams, StreamReport{Name: s.Name, LastSeq: s.LastSeq})
|
|
}
|
|
if err := a.Verify(); err != nil {
|
|
r.Fault = err.Error()
|
|
return r, nil
|
|
}
|
|
r.Passed = true
|
|
return r, nil
|
|
}
|
|
|
|
// pick names the regular file to verify, and nothing outside dir: a name is one path component, and a
|
|
// symbolic link is not followed out of the directory.
|
|
func pick(dir, name string) (string, fs.FileInfo, error) {
|
|
if dir == "" {
|
|
return "", nil, errors.New("the snapshots directory is not set")
|
|
}
|
|
if name != "" {
|
|
if name != filepath.Base(name) || name == "." || name == ".." || strings.ContainsRune(name, 0) {
|
|
return "", nil, fmt.Errorf("%q is not a file name inside the snapshots directory", name)
|
|
}
|
|
p := filepath.Join(dir, name)
|
|
info, err := os.Lstat(p)
|
|
if err != nil {
|
|
return "", nil, fmt.Errorf("no snapshot %s in the snapshots directory: %w", name, err)
|
|
}
|
|
if !info.Mode().IsRegular() {
|
|
return "", nil, fmt.Errorf("%s is not a regular file", name)
|
|
}
|
|
return p, info, nil
|
|
}
|
|
entries, err := os.ReadDir(dir)
|
|
if err != nil {
|
|
return "", nil, fmt.Errorf("the snapshots directory does not read: %w", err)
|
|
}
|
|
var best string
|
|
var bestInfo fs.FileInfo
|
|
for _, e := range entries {
|
|
if !strings.HasSuffix(e.Name(), ".tar") {
|
|
continue
|
|
}
|
|
info, err := e.Info()
|
|
if err != nil || !info.Mode().IsRegular() {
|
|
continue
|
|
}
|
|
if bestInfo == nil || info.ModTime().After(bestInfo.ModTime()) {
|
|
best, bestInfo = e.Name(), info
|
|
}
|
|
}
|
|
if bestInfo == nil {
|
|
return "", nil, errors.New("the snapshots directory holds no .tar snapshot")
|
|
}
|
|
return filepath.Join(dir, best), bestInfo, nil
|
|
}
|