99 lines
3.9 KiB
Go
99 lines
3.9 KiB
Go
package catalogue
|
|
|
|
import (
|
|
"fmt"
|
|
"regexp"
|
|
"strings"
|
|
)
|
|
|
|
// **The data items of a node's modules, placed, read from the composition** (novox/hq ADR 0571 clause 3, ADR 0233 §22 to
|
|
// §25): disk-load measures each item every module on its node declares, and the node-backup holder, mounts and nfs-server
|
|
// read the readings. Each item is its module's declaration with its path resolved to this node's place, its protection
|
|
// and how it is measured: the same lines the node-backup holder is handed as `${backup:data}`, composed by the same
|
|
// function, so a reader that composes from the bus and a holder handed the file read one list.
|
|
|
|
// PlacedDataItem is one data item a module on a node declares, as placed on that node.
|
|
type PlacedDataItem struct {
|
|
Module string `json:"module"`
|
|
ID string `json:"item"`
|
|
Class string `json:"class"`
|
|
// Path is the item's place on the node; CoveredBy the path whose snapshot keeps it (the item, or the item its dump
|
|
// writes into), empty when it is not backed up.
|
|
Path string `json:"path"`
|
|
CoveredBy string `json:"covered_by,omitempty"`
|
|
// Protection is backup, redundancy, both or none; Measure walk, dataset or shallow.
|
|
Protection string `json:"protection,omitempty"`
|
|
Measure string `json:"measure,omitempty"`
|
|
}
|
|
|
|
var (
|
|
dataModuleHeader = regexp.MustCompile(`^#\s*([a-z0-9][a-z0-9-]*)$`)
|
|
dataSafePath = regexp.MustCompile(`^/[^\s'"\\$` + "`" + `]*$`)
|
|
)
|
|
|
|
// ParseDataItems reads the node-backup holder's data text (`${backup:data}`: a `# <module>` line, then one line per item,
|
|
// `item <id> <class> <path> <covered-by or -> <protection> <measure>`) into each module's items, in order. A line it does
|
|
// not read is refused, naming the module: a path with a space or a quote is never handed to a measuring shell.
|
|
func ParseDataItems(text string) (map[string][]PlacedDataItem, error) {
|
|
out := map[string][]PlacedDataItem{}
|
|
module := ""
|
|
for _, raw := range strings.Split(text, "\n") {
|
|
line := strings.TrimSpace(raw)
|
|
if line == "" {
|
|
continue
|
|
}
|
|
if m := dataModuleHeader.FindStringSubmatch(line); m != nil {
|
|
module = m[1]
|
|
continue
|
|
}
|
|
if strings.HasPrefix(line, "#") || module == "" {
|
|
continue
|
|
}
|
|
f := strings.Fields(line)
|
|
if len(f) < 5 || len(f) > 7 || f[0] != "item" || !dataSafePath.MatchString(f[3]) || (f[4] != "-" && !dataSafePath.MatchString(f[4])) {
|
|
return nil, fmt.Errorf("%s declares a data line that is not read: %s", module, line)
|
|
}
|
|
it := PlacedDataItem{Module: module, ID: f[1], Class: f[2], Path: f[3], Measure: MeasureWalk}
|
|
if len(f) >= 6 {
|
|
it.Protection = f[5]
|
|
}
|
|
if len(f) == 7 {
|
|
it.Measure = f[6]
|
|
}
|
|
if it.Measure != MeasureWalk && it.Measure != MeasureDataset && it.Measure != MeasureShallow {
|
|
return nil, fmt.Errorf("%s declares a data line that is not read: %s", module, line)
|
|
}
|
|
if f[4] != "-" {
|
|
it.CoveredBy = f[4]
|
|
}
|
|
out[module] = append(out[module], it)
|
|
}
|
|
return out, nil
|
|
}
|
|
|
|
// DataItems is every data item the resolution's modules declare, placed on its node with the rendering given: the text
|
|
// the node-backup holder is handed, read. A module left out of the node's declaration keeps its items, as its data is
|
|
// still on the node (ADR 0262); an item that cannot be placed is said in unplaced and left out.
|
|
func (r Resolution) DataItems(with Rendering) (items map[string][]PlacedDataItem, unplaced []string, err error) {
|
|
left := r.LeftOut(with.Settings, with.Adopted)
|
|
for module, why := range with.NotPlaced {
|
|
if _, already := left[module]; !already {
|
|
left[module] = why
|
|
}
|
|
}
|
|
modules := make([]Manifest, 0, len(r.Modules))
|
|
for _, m := range r.Modules {
|
|
if _, isLeft := left[m.Module]; isLeft {
|
|
m = backupView(m)
|
|
}
|
|
modules = append(modules, m)
|
|
}
|
|
text, unplaced, err := seatContributions(modules, Manifest{}, BackupSeat+":"+BackupKindData, with,
|
|
machineFacts(r, with.Names, with.MeshRange), r.Capabilities)
|
|
if err != nil {
|
|
return nil, unplaced, err
|
|
}
|
|
items, err = ParseDataItems(text)
|
|
return items, unplaced, err
|
|
}
|