carlos / platform Public

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

Plain git — no account needed to clone.

Download

Download this file

1package activator
2
3import (
4 "encoding/json"
5 "errors"
6 "fmt"
7 "os"
8 "path/filepath"
9
10 "github.com/carlosframework/platform/internal/provision"
11)
12
13// InstallMarker is a box's own note that it finished a local install of
14// one generation of a host. Nothing reads it to trust a local database:
15// claim ruling R6 has every admitted writer purge and restore from the
16// certified remote (region HA spec 1 H13, §5.5 withdrawn). It is kept for
17// relocation's local install journal (§5.8), which plan 1b does not build.
18type InstallMarker struct {
19 Incarnation string `json:"incarnation"`
20 Generation string `json:"generation"`
21 Stamp int64 `json:"stamp"`
22 DBMarker string `json:"db_marker"`
23 FilesSeq int64 `json:"files_seq"`
24}
25
26func InstallMarkerPath(dataDir, host string) string {
27 return filepath.Join(dataDir, ".installed", provision.InstanceID(host)+".json")
28}
29
30// WriteInstallMarker replaces the marker atomically and syncs both the
31// file and its directory, so a marker that is read back was fully written.
32func WriteInstallMarker(dataDir, host string, m InstallMarker) error {
33 path := InstallMarkerPath(dataDir, host)
34 dir := filepath.Dir(path)
35 if err := os.MkdirAll(dir, 0o700); err != nil {
36 return err
37 }
38 body, err := json.Marshal(m)
39 if err != nil {
40 return err
41 }
42 tmp, err := os.CreateTemp(dir, ".marker-*")
43 if err != nil {
44 return err
45 }
46 defer os.Remove(tmp.Name())
47 if _, err := tmp.Write(body); err != nil {
48 tmp.Close()
49 return err
50 }
51 if err := tmp.Sync(); err != nil {
52 tmp.Close()
53 return err
54 }
55 if err := tmp.Close(); err != nil {
56 return err
57 }
58 if err := os.Rename(tmp.Name(), path); err != nil {
59 return err
60 }
61 d, err := os.Open(dir)
62 if err != nil {
63 return err
64 }
65 defer d.Close()
66 return d.Sync()
67}
68
69// ReadInstallMarker returns the marker and whether there is one. A marker
70// that exists but cannot be parsed is an error, never "absent": the caller
71// restores either way, but it must not mistake damage for a clean slate.
72func ReadInstallMarker(dataDir, host string) (InstallMarker, bool, error) {
73 body, err := os.ReadFile(InstallMarkerPath(dataDir, host))
74 if errors.Is(err, os.ErrNotExist) {
75 return InstallMarker{}, false, nil
76 }
77 if err != nil {
78 return InstallMarker{}, false, err
79 }
80 var m InstallMarker
81 if err := json.Unmarshal(body, &m); err != nil {
82 return InstallMarker{}, false, fmt.Errorf("activator: install marker for %s: %w", host, err)
83 }
84 return m, true, nil
85}
86
87func RemoveInstallMarker(dataDir, host string) error {
88 err := os.Remove(InstallMarkerPath(dataDir, host))
89 if errors.Is(err, os.ErrNotExist) {
90 return nil
91 }
92 return err
93}
94