carlos / platform Public

Clone
git clone https://amadan.net/carlos/platform

Plain git — no account needed to clone.

Download

Download this file

1package hostbox
2
3import (
4 "bytes"
5 "context"
6 "encoding/json"
7 "io"
8 "path/filepath"
9)
10
11type GenerationPayload struct {
12 Inventory StopInventory
13 Revision uint64
14}
15
16// GenerationPayloads reads both sides of the inventory/revision relation.
17// An inner join would silently discard an obligation with a missing revision.
18// The caller still has to bind these records to root installations and inspect
19// kernel references; Complete in a stored payload cannot establish that alone.
20func (j *LaunchJournal) GenerationPayloads(ctx context.Context) ([]GenerationPayload, error) {
21 if j == nil || j.db == nil || j.remote != nil {
22 return nil, ErrUnsupported
23 }
24 if err := journalIdentity(j.path, j.identity); err != nil {
25 return nil, err
26 }
27 rows, err := journalExecutorFor(ctx, j.db).QueryContext(ctx, `
28SELECT k.host,k.incarnation,k.stamp,i.body,v.revision
29FROM (SELECT host,incarnation,stamp FROM stop_inventory
30 UNION SELECT host,incarnation,stamp FROM journal_inventory_versions) k
31LEFT JOIN stop_inventory i USING(host,incarnation,stamp)
32LEFT JOIN journal_inventory_versions v USING(host,incarnation,stamp)
33ORDER BY k.host,k.incarnation,k.stamp`)
34 if err != nil {
35 return nil, err
36 }
37 defer rows.Close()
38 var out []GenerationPayload
39 for rows.Next() {
40 var host, incarnation string
41 var stamp uint64
42 var raw []byte
43 var p GenerationPayload
44 if err := rows.Scan(&host, &incarnation, &stamp, &raw, &p.Revision); err != nil {
45 return nil, err
46 }
47 if len(raw) > 1<<20 || len(out) >= 8192 {
48 return nil, ErrTypedInventory
49 }
50 dec := json.NewDecoder(bytes.NewReader(raw))
51 dec.DisallowUnknownFields()
52 if dec.Decode(&p.Inventory) != nil || dec.Decode(new(any)) != io.EOF {
53 return nil, ErrTypedInventory
54 }
55 in := p.Inventory
56 if !component(host) || incarnation == "" || stamp == 0 || p.Revision == 0 || in.Host != host || in.Incarnation != incarnation || in.InstallationStamp != stamp || !in.Complete || in.Box == "" || in.Enrollment == "" || in.DirectoryRevision == "" {
57 return nil, ErrTypedInventory
58 }
59 ids := map[string]bool{}
60 for _, e := range in.Entries {
61 if !component(e.ArtifactID) || ids[e.ArtifactID] || !filepath.IsLocal(e.RelativePath) || e.Ownership == "" || (e.Materialization != "intended" && e.Materialization != "materialized") {
62 return nil, ErrTypedInventory
63 }
64 ids[e.ArtifactID] = true
65 switch e.Kind {
66 case "route", "timer":
67 if e.ManagedRoot != "registry" || e.RowIdentity == "" || e.Device != 0 || e.Inode != 0 || e.Type != 0 {
68 return nil, ErrTypedInventory
69 }
70 case "path":
71 if e.ManagedRoot != "data" || e.RowIdentity != "" || (e.Materialization == "materialized" && (e.Device == 0 || e.Inode == 0 || e.Type == 0)) {
72 return nil, ErrTypedInventory
73 }
74 default:
75 return nil, ErrTypedInventory
76 }
77 }
78 out = append(out, p)
79 }
80 if err := rows.Err(); err != nil {
81 return nil, err
82 }
83 if err := journalIdentity(j.path, j.identity); err != nil {
84 return nil, err
85 }
86 return out, nil
87}
88