// Command placement is the catalogue's check of its placement files (novox/hq ADR 0549 ยง1, ADR 0555; issue 1126): every // `placement/.json` reads as a placement of the node its name says, and the files together are refused, every // finding named at once, for two modules of one node on one host port, a pin, binding or holding naming a provider not // placed where it says, a seat held once for the mesh held twice, two nodes with one address on the private network, or // more than one hub (mesh-sdk delivery.CheckPlacements). // // A module the catalogue does not hold and a node not enrolled are the composition check's to refuse: placement names // modules of every repository the indexer reads and the nodes the mesh enrolled, neither of which this tree holds. // // go run . // // Exits 1 on a finding. package main import ( "fmt" "os" "path/filepath" "sort" "git.novox.be/novox/mesh-sdk/go/delivery" ) // Check reads every placement file under root and answers each finding; none is a catalogue whose placement holds. A // catalogue with no placement directory has none to check. func Check(root string) ([]string, error) { dir := filepath.Join(root, delivery.PlacementDir) entries, err := os.ReadDir(dir) if os.IsNotExist(err) { return nil, nil } if err != nil { return nil, err } var found []string placements := map[string]delivery.Placement{} for _, e := range entries { rel := delivery.PlacementDir + "/" + e.Name() node, ok := delivery.PlacementFileNode(rel) if e.IsDir() || !ok { found = append(found, fmt.Sprintf("%s is not a placement file: the directory holds only .json, one per node", rel)) continue } raw, err := os.ReadFile(filepath.Join(dir, e.Name())) if err != nil { return nil, err } p, err := delivery.DecodePlacement(raw) if err != nil { found = append(found, fmt.Sprintf("%s does not read as a placement: %v", rel, err)) continue } if p.Revision != "" { found = append(found, fmt.Sprintf("%s names a revision, which only the indexer writes into the key", rel)) } placements[node] = p } all := func(string) bool { return true } found = append(found, delivery.CheckPlacements(placements, all, all)...) sort.Strings(found) return found, nil } func main() { if len(os.Args) != 2 { fmt.Fprintln(os.Stderr, "usage: placement ") os.Exit(2) } found, err := Check(os.Args[1]) if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(2) } for _, f := range found { fmt.Println(f) } if len(found) > 0 { os.Exit(1) } }