Send each resource's module and each module's build to a node that reads them; pin mesh-host at 0b391f49a25f (issue 1145)
This commit is contained in:
+126
-16
@@ -103,6 +103,8 @@ type Resource interface {
|
||||
// and not a hash of the content: it is what lets the store say *this is the same resource
|
||||
// I applied last time*, which is what makes removal possible at all.
|
||||
Identity() string
|
||||
// DeclaredModule is the module the controller says the resource belongs to, or "" (issue 1132).
|
||||
DeclaredModule() string
|
||||
// Kind is the resource's type, for the store and for reporting.
|
||||
Kind() Type
|
||||
// Target is what the resource acts on, for a person reading a report.
|
||||
@@ -115,12 +117,30 @@ type Resource interface {
|
||||
// strict decoder would otherwise refuse. `Kind()` returns the constant and is what anything
|
||||
// else should read.
|
||||
|
||||
// DeclaredModule is on every kind: the module the controller says the resource belongs to, or "" when it does not say
|
||||
// (an older controller). Read through Declaration.ModuleOfID, which falls back to the guess.
|
||||
func (d *Directory) DeclaredModule() string { return d.Module }
|
||||
func (f *File) DeclaredModule() string { return f.Module }
|
||||
func (u *User) DeclaredModule() string { return u.Module }
|
||||
func (n *Network) DeclaredModule() string { return n.Module }
|
||||
func (a *Access) DeclaredModule() string { return a.Module }
|
||||
func (a *Archive) DeclaredModule() string { return a.Module }
|
||||
func (d *Process) DeclaredModule() string { return d.Module }
|
||||
func (s *Service) DeclaredModule() string { return s.Module }
|
||||
func (o *Opening) DeclaredModule() string { return o.Module }
|
||||
func (p *Package) DeclaredModule() string { return p.Module }
|
||||
func (c *Container) DeclaredModule() string { return c.Module }
|
||||
func (a *Action) DeclaredModule() string { return a.Module }
|
||||
|
||||
// Directory is a directory that should exist, with a mode.
|
||||
type Directory struct {
|
||||
ID string `json:"id"`
|
||||
Type Type `json:"type"`
|
||||
Path string `json:"path"`
|
||||
Mode string `json:"mode,omitempty"`
|
||||
// Module is the module this resource belongs to, as the controller says it (novox/hq ADR 0429 §4, issue 1132). Absent
|
||||
// is an older controller, and the module is then guessed from the id (ModuleGuess).
|
||||
Module string `json:"module,omitempty"`
|
||||
Path string `json:"path"`
|
||||
Mode string `json:"mode,omitempty"`
|
||||
// Owner is the user this belongs to, by name. Absent means root, which is what everything
|
||||
// managed was until users existed.
|
||||
Owner string `json:"owner,omitempty"`
|
||||
@@ -201,8 +221,11 @@ func (d *Directory) validate(where string, _ bool) []string {
|
||||
|
||||
// File is a file with literal content. The host renders nothing.
|
||||
type File struct {
|
||||
ID string `json:"id"`
|
||||
Type Type `json:"type"`
|
||||
ID string `json:"id"`
|
||||
Type Type `json:"type"`
|
||||
// Module is the module this resource belongs to, as the controller says it (novox/hq ADR 0429 §4, issue 1132). Absent
|
||||
// is an older controller, and the module is then guessed from the id (ModuleGuess).
|
||||
Module string `json:"module,omitempty"`
|
||||
Path string `json:"path"`
|
||||
Content string `json:"content"`
|
||||
Mode string `json:"mode,omitempty"`
|
||||
@@ -520,7 +543,10 @@ func (f *File) checkOwnership(where string) []string {
|
||||
type User struct {
|
||||
ID string `json:"id"`
|
||||
Type Type `json:"type"`
|
||||
Name string `json:"name"`
|
||||
// Module is the module this resource belongs to, as the controller says it (novox/hq ADR 0429 §4, issue 1132). Absent
|
||||
// is an older controller, and the module is then guessed from the id (ModuleGuess).
|
||||
Module string `json:"module,omitempty"`
|
||||
Name string `json:"name"`
|
||||
|
||||
// Shell this user logs in with. Absent means the host asserts nothing and leaves whatever is
|
||||
// there — the same rule Service.Boot follows, for the same reason: a field that always
|
||||
@@ -571,7 +597,10 @@ const RootNever = "never"
|
||||
type Network struct {
|
||||
ID string `json:"id"`
|
||||
Type Type `json:"type"`
|
||||
Name string `json:"name"`
|
||||
// Module is the module this resource belongs to, as the controller says it (novox/hq ADR 0429 §4, issue 1132). Absent
|
||||
// is an older controller, and the module is then guessed from the id (ModuleGuess).
|
||||
Module string `json:"module,omitempty"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
func (n *Network) Identity() string { return n.ID }
|
||||
@@ -616,7 +645,10 @@ const (
|
||||
type Access struct {
|
||||
ID string `json:"id"`
|
||||
Type Type `json:"type"`
|
||||
Path string `json:"path"`
|
||||
// Module is the module this resource belongs to, as the controller says it (novox/hq ADR 0429 §4, issue 1132). Absent
|
||||
// is an older controller, and the module is then guessed from the id (ModuleGuess).
|
||||
Module string `json:"module,omitempty"`
|
||||
Path string `json:"path"`
|
||||
// Mode is how this module reaches the path: read or read-write. Absent narrows to read.
|
||||
Mode string `json:"mode,omitempty"`
|
||||
|
||||
@@ -743,6 +775,9 @@ func (u *User) validate(where string, _ bool) []string {
|
||||
type Archive struct {
|
||||
ID string `json:"id"`
|
||||
Type Type `json:"type"`
|
||||
// Module is the module this resource belongs to, as the controller says it (novox/hq ADR 0429 §4, issue 1132). Absent
|
||||
// is an older controller, and the module is then guessed from the id (ModuleGuess).
|
||||
Module string `json:"module,omitempty"`
|
||||
// Source is where to fetch it from.
|
||||
Source string `json:"source"`
|
||||
// Digest is sha256 of the archive, as "sha256:<hex>".
|
||||
@@ -796,6 +831,9 @@ func (a *Archive) validate(where string, _ bool) []string {
|
||||
type Process struct {
|
||||
ID string `json:"id"`
|
||||
Type Type `json:"type"`
|
||||
// Module is the module this resource belongs to, as the controller says it (novox/hq ADR 0429 §4, issue 1132). Absent
|
||||
// is an older controller, and the module is then guessed from the id (ModuleGuess).
|
||||
Module string `json:"module,omitempty"`
|
||||
// Name is what the unit is called, and what an operator will see in the process table.
|
||||
Name string `json:"name"`
|
||||
// Source is where to fetch the bundle from, and Digest is what it must hash to. The same
|
||||
@@ -985,7 +1023,10 @@ func (d *Process) validate(where string, _ bool) []string {
|
||||
type Service struct {
|
||||
ID string `json:"id"`
|
||||
Type Type `json:"type"`
|
||||
Unit string `json:"unit"`
|
||||
// Module is the module this resource belongs to, as the controller says it (novox/hq ADR 0429 §4, issue 1132). Absent
|
||||
// is an older controller, and the module is then guessed from the id (ModuleGuess).
|
||||
Module string `json:"module,omitempty"`
|
||||
Unit string `json:"unit"`
|
||||
// State is "running" or "stopped" — or absent, and then **the unit's lifecycle is the
|
||||
// machine's; the mesh only reflects its triggers** (novox/hq ADR 0117). The uplink modules
|
||||
// declare the machine's own network manager this way: the mesh writes into its configuration
|
||||
@@ -1157,8 +1198,11 @@ func BlockMarkers(id string) (begin, end string) {
|
||||
// firewall sees a published port after the runtime has translated it, so a forwarded opening names
|
||||
// the container's own port in To as well as the machine's in Port.
|
||||
type Opening struct {
|
||||
ID string `json:"id"`
|
||||
Type Type `json:"type"`
|
||||
ID string `json:"id"`
|
||||
Type Type `json:"type"`
|
||||
// Module is the module this resource belongs to, as the controller says it (novox/hq ADR 0429 §4, issue 1132). Absent
|
||||
// is an older controller, and the module is then guessed from the id (ModuleGuess).
|
||||
Module string `json:"module,omitempty"`
|
||||
Port int `json:"port"`
|
||||
Protocol string `json:"protocol"`
|
||||
From string `json:"from"`
|
||||
@@ -1223,8 +1267,11 @@ func (o *Opening) validate(where string, _ bool) []string {
|
||||
// Present is the whole of what it asserts, never a version: version is the package manager's
|
||||
// business and the mesh does not hold a second opinion about it.
|
||||
type Package struct {
|
||||
ID string `json:"id"`
|
||||
Type Type `json:"type"`
|
||||
ID string `json:"id"`
|
||||
Type Type `json:"type"`
|
||||
// Module is the module this resource belongs to, as the controller says it (novox/hq ADR 0429 §4, issue 1132). Absent
|
||||
// is an older controller, and the module is then guessed from the id (ModuleGuess).
|
||||
Module string `json:"module,omitempty"`
|
||||
Package string `json:"package"`
|
||||
// Absent declares that the package is NOT installed (novox/hq ADR 0180): the host removes it
|
||||
// when it is, and leaves a machine that never had it alone. For the one case a module replaces
|
||||
@@ -1249,7 +1296,10 @@ func (p *Package) validate(where string, _ bool) []string {
|
||||
type Container struct {
|
||||
ID string `json:"id"`
|
||||
Type Type `json:"type"`
|
||||
Name string `json:"name"`
|
||||
// Module is the module this resource belongs to, as the controller says it (novox/hq ADR 0429 §4, issue 1132). Absent
|
||||
// is an older controller, and the module is then guessed from the id (ModuleGuess).
|
||||
Module string `json:"module,omitempty"`
|
||||
Name string `json:"name"`
|
||||
// Image is pinned by digest (novox/hq ADR 0006) — a tag moves and a digest does not.
|
||||
Image string `json:"image"`
|
||||
Env map[string]string `json:"env,omitempty"`
|
||||
@@ -1555,8 +1605,11 @@ func (c *Container) validate(where string, _ bool) []string {
|
||||
|
||||
// Action runs something the bundle declared, and the host never learns what it means.
|
||||
type Action struct {
|
||||
ID string `json:"id"`
|
||||
Type Type `json:"type"`
|
||||
ID string `json:"id"`
|
||||
Type Type `json:"type"`
|
||||
// Module is the module this resource belongs to, as the controller says it (novox/hq ADR 0429 §4, issue 1132). Absent
|
||||
// is an older controller, and the module is then guessed from the id (ModuleGuess).
|
||||
Module string `json:"module,omitempty"`
|
||||
Command []string `json:"command"`
|
||||
// Verify is not optional and is not a courtesy. It is the read-back AND the idempotency
|
||||
// check: the host does not know what a database is, so "is it already there" is a question
|
||||
@@ -1727,6 +1780,58 @@ type Declaration struct {
|
||||
// the only account whose write of a filled file the node-engine's local write socket accepts. Absent is a
|
||||
// controller that names none, and every such write is refused.
|
||||
Provisioner string
|
||||
|
||||
// Builds is the build id of every module this declaration names, by module (novox/hq ADR 0429 §4, issue 1132).
|
||||
Builds map[string]string
|
||||
|
||||
// declared is what each resource says of its module, by id; nil on a declaration built by hand.
|
||||
declared map[string]string
|
||||
}
|
||||
|
||||
// ModuleGuess is the module a resource id names when the declaration does not say: everything before its last dot.
|
||||
//
|
||||
// The mesh composes a module's resource ids as `<module>.<its own id>`, and **a module's name may contain a dot**
|
||||
// (`novox.be` is one on this mesh) while a resource's own id never does, so the owner is everything before the *last*
|
||||
// dot. False for what the mesh declares in its own right: the foundation's resources carry no dot, and the
|
||||
// adoption's are named for the mesh. This is the guess an older controller's declaration is read by; a declaration
|
||||
// that says `module` is read by ModuleOfID, which never guesses for a resource that says (issue 1132).
|
||||
func ModuleGuess(id string) (string, bool) {
|
||||
if strings.HasPrefix(id, AdoptionPrefix) {
|
||||
return "", false
|
||||
}
|
||||
at := strings.LastIndex(id, ".")
|
||||
if at <= 0 {
|
||||
return "", false
|
||||
}
|
||||
return id[:at], true
|
||||
}
|
||||
|
||||
// ModuleOfID is the module a resource of this declaration belongs to: the module it says (novox/hq ADR 0429 §4,
|
||||
// issue 1132), and otherwise the guess from its id (ModuleGuess), so a declaration from an older controller reads as
|
||||
// it always did. False for what belongs to no module.
|
||||
func (d *Declaration) ModuleOfID(id string) (string, bool) {
|
||||
if d != nil {
|
||||
if d.declared == nil {
|
||||
for _, r := range d.Resources {
|
||||
if r.Identity() == id && r.DeclaredModule() != "" {
|
||||
return r.DeclaredModule(), true
|
||||
}
|
||||
}
|
||||
} else if m, ok := d.declared[id]; ok {
|
||||
return m, true
|
||||
}
|
||||
}
|
||||
return ModuleGuess(id)
|
||||
}
|
||||
|
||||
// indexModules keeps what each resource says of its module, so ModuleOfID is a lookup.
|
||||
func (d *Declaration) indexModules() {
|
||||
d.declared = map[string]string{}
|
||||
for _, r := range d.Resources {
|
||||
if m := r.DeclaredModule(); m != "" {
|
||||
d.declared[r.Identity()] = m
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// checkProvisioner refuses a provisioner client's account that is no account name, or is root: the account whose
|
||||
@@ -2126,6 +2231,10 @@ type envelope struct {
|
||||
// Provisioner is optional too (novox/hq ADR 0349 §4). **An older host refuses this key**; a controller sends it
|
||||
// only to a host whose health says link.ProvisionerContract.
|
||||
Provisioner string `json:"provisioner_account,omitempty"`
|
||||
// Builds is optional too (novox/hq ADR 0429 §4, issue 1132): the build id of each module the declaration names, and
|
||||
// every resource's `module`. **An older host refuses these keys**; a controller sends them only to a host whose
|
||||
// reports say `reads_modules`.
|
||||
Builds map[string]string `json:"builds,omitempty"`
|
||||
}
|
||||
|
||||
func parse(raw []byte, allowActions bool) (*Declaration, error) {
|
||||
@@ -2145,7 +2254,7 @@ func parse(raw []byte, allowActions bool) (*Declaration, error) {
|
||||
d := &Declaration{Version: env.Version, For: env.For, Adoption: env.Adoption, Sequence: env.Sequence,
|
||||
Epoch: env.Epoch, LeftOut: env.LeftOut, Generation: env.Generation, PutBack: env.PutBack,
|
||||
Identities: env.Identities, Groups: env.Groups, Libraries: env.Libraries, Filled: env.Filled,
|
||||
Provisioner: env.Provisioner}
|
||||
Provisioner: env.Provisioner, Builds: env.Builds}
|
||||
problems := checkIdentities(env.Identities, env.Groups)
|
||||
problems = append(problems, checkProvisioner(env.Provisioner)...)
|
||||
problems = append(problems, checkLibraries(env.Groups, env.Libraries)...)
|
||||
@@ -2264,6 +2373,7 @@ func parse(raw []byte, allowActions bool) (*Declaration, error) {
|
||||
if len(problems) > 0 {
|
||||
return nil, &RefusalError{Problems: problems}
|
||||
}
|
||||
d.indexModules()
|
||||
return d, nil
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user