package activator import ( "encoding/json" "errors" "fmt" "os" "path/filepath" "github.com/carlosframework/platform/internal/provision" ) // InstallMarker is a box's own note that it finished a local install of // one generation of a host. Nothing reads it to trust a local database: // claim ruling R6 has every admitted writer purge and restore from the // certified remote (region HA spec 1 H13, §5.5 withdrawn). It is kept for // relocation's local install journal (§5.8), which plan 1b does not build. type InstallMarker struct { Incarnation string `json:"incarnation"` Generation string `json:"generation"` Stamp int64 `json:"stamp"` DBMarker string `json:"db_marker"` FilesSeq int64 `json:"files_seq"` } func InstallMarkerPath(dataDir, host string) string { return filepath.Join(dataDir, ".installed", provision.InstanceID(host)+".json") } // WriteInstallMarker replaces the marker atomically and syncs both the // file and its directory, so a marker that is read back was fully written. func WriteInstallMarker(dataDir, host string, m InstallMarker) error { path := InstallMarkerPath(dataDir, host) dir := filepath.Dir(path) if err := os.MkdirAll(dir, 0o700); err != nil { return err } body, err := json.Marshal(m) if err != nil { return err } tmp, err := os.CreateTemp(dir, ".marker-*") if err != nil { return err } defer os.Remove(tmp.Name()) if _, err := tmp.Write(body); err != nil { tmp.Close() return err } if err := tmp.Sync(); err != nil { tmp.Close() return err } if err := tmp.Close(); err != nil { return err } if err := os.Rename(tmp.Name(), path); err != nil { return err } d, err := os.Open(dir) if err != nil { return err } defer d.Close() return d.Sync() } // ReadInstallMarker returns the marker and whether there is one. A marker // that exists but cannot be parsed is an error, never "absent": the caller // restores either way, but it must not mistake damage for a clean slate. func ReadInstallMarker(dataDir, host string) (InstallMarker, bool, error) { body, err := os.ReadFile(InstallMarkerPath(dataDir, host)) if errors.Is(err, os.ErrNotExist) { return InstallMarker{}, false, nil } if err != nil { return InstallMarker{}, false, err } var m InstallMarker if err := json.Unmarshal(body, &m); err != nil { return InstallMarker{}, false, fmt.Errorf("activator: install marker for %s: %w", host, err) } return m, true, nil } func RemoveInstallMarker(dataDir, host string) error { err := os.Remove(InstallMarkerPath(dataDir, host)) if errors.Is(err, os.ErrNotExist) { return nil } return err }