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 "context"
5 "errors"
6 "fmt"
7
8 "github.com/carlosframework/platform/internal/instancectl"
9 "github.com/carlosframework/platform/internal/registry"
10 "github.com/carlosframework/platform/internal/release"
11)
12
13// identityBackend is the exec backend's identity-pinned spawn and seed
14// (settings spec §4.2, Astra I1 #5). A cold wake captures ONE staged
15// identity (LiveIdentity), records it, and then seeds and spawns exactly
16// that file by path, verified against its digest. Neither call execs
17// live/<host>, so root repointing the link between the record and the exec
18// cannot make a different build touch the instance's data.
19type identityBackend interface {
20 // LiveIdentity materializes host's live link if it is missing (the
21 // Materialize hook and its root-stage relay), then resolves it ONCE
22 // into the file it names and that file's digest. Version is "" for a
23 // link outside the version store; the caller decides what that means.
24 LiveIdentity(ctx context.Context, rt registry.Route) (release.StagedIdentity, error)
25 // StartGenExe is StartGen (generation n, perGen choosing the socket)
26 // with the executable named: id.StagedPath, verified against id.Digest
27 // first. A copy that changed is a failed start, never a fallback to the
28 // link. The Gen it returns carries id's build, path, digest and demand,
29 // so a later sidecar binds the same file.
30 StartGenExe(ctx context.Context, rt registry.Route, n uint64, perGen bool, id release.StagedIdentity) (Proc, Gen, error)
31 // SeedExe is Seed with the executable named, verified the same way.
32 SeedExe(ctx context.Context, rt registry.Route, id release.StagedIdentity) error
33}
34
35var _ identityBackend = (*ExecBackend)(nil)
36
37// identityPicker is a composed backend that answers per route.
38type identityPicker interface {
39 identityFor(rt registry.Route) identityBackend
40}
41
42// identityFor is the backend that can pin an executable for rt, or nil
43// (rt then keeps today's Start and Seed, and nothing is recorded for it).
44// Production's SplitBackend serves unit rows too, so a composed backend
45// answers per route, never by a type assertion on itself alone.
46func identityFor(b Backend, rt registry.Route) identityBackend {
47 if p, ok := b.(identityPicker); ok {
48 return p.identityFor(rt)
49 }
50 ib, _ := b.(identityBackend)
51 return ib
52}
53
54// identityFor is the exec half for an exec row and nil for a unit row:
55// systemd execs a unit row's live link itself, so nothing here can pin its
56// file. SplitBackend does not implement identityBackend itself. The exec
57// half answers by the same rule (identityFor), so a half that is itself
58// composed answers per route too.
59func (b *SplitBackend) identityFor(rt registry.Route) identityBackend {
60 if rt.Backing == registry.BackingUnit {
61 return nil
62 }
63 return identityFor(b.pick(rt), rt)
64}
65
66// buildIdentifier names build's staged executable of rt's app on this box,
67// hashed now: VersionPath(OptDir, RouteAccount(rt), build, rt.App) and its
68// sha256, refused for an invalid version or an unreadable file. A legacy
69// sidecar whose live link names a build the declined gate refuses runs its
70// instance's own build through it instead (Service.startSidecar).
71type buildIdentifier interface {
72 BuildIdentity(rt registry.Route, build string) (release.StagedIdentity, error)
73}
74
75var (
76 _ buildIdentifier = (*ExecBackend)(nil)
77 _ buildIdentifier = (*SplitBackend)(nil)
78)
79
80// errUnitNoBuildIdentity refuses BuildIdentity for a unit row: systemd
81// execs its live link itself, so no staged file can be named for it.
82var errUnitNoBuildIdentity = errors.New("activator: a unit-backed row runs its live link, so no staged build can be named for it")
83
84// BuildIdentity forwards to the exec half for exec rows. A unit row, or an
85// exec half that cannot name a build, refuses.
86func (b *SplitBackend) BuildIdentity(rt registry.Route, build string) (release.StagedIdentity, error) {
87 if rt.Backing == registry.BackingUnit {
88 return release.StagedIdentity{}, errUnitNoBuildIdentity
89 }
90 bi, ok := b.Exec.(buildIdentifier)
91 if !ok {
92 return release.StagedIdentity{}, fmt.Errorf("%s: the exec backend cannot name a staged build", rt.Host)
93 }
94 return bi.BuildIdentity(rt, build)
95}
96
97// stagedExeOf is id as root's control channel names an executable.
98func stagedExeOf(id release.StagedIdentity) *instancectl.StagedExe {
99 return &instancectl.StagedExe{Path: id.StagedPath, Version: id.Version, Digest: id.Digest}
100}
101