Never set a provision provided without its provider's outcome, read from the entry's state and why, and pin mesh-sdk 692dbf9 (issue 1954)
A provider that writes no outcome leaves its keys asked (ADR 0570 clause 3), so a provider that fails is never hidden.
This commit is contained in:
@@ -2,7 +2,7 @@ module mesh-config
|
||||
|
||||
go 1.26.0
|
||||
|
||||
require git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029213929-66ff33dbd35d
|
||||
require git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029214150-692dbf9a1791
|
||||
|
||||
require (
|
||||
github.com/klauspost/compress v1.20.0 // indirect
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029213929-66ff33dbd35d h1:J1QAvzlaIvCCyZGBQX0XGJjYWdNPjLXBF4zaAeIkUOg=
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029213929-66ff33dbd35d/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029214150-692dbf9a1791 h1:HVKR7kENzltQVkfBN+2zhU9JOPZme7MjDkTvr/oiJ24=
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029214150-692dbf9a1791/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
|
||||
github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op h1:Z/MZK75wC/NSrkgqeNIa7jexam9uWzhLmFTSCPI/kn0=
|
||||
github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op/go.mod h1:FQyySiasQQM8735Ddel3MRojmy4dA1IqCeyJ5jmPMbI=
|
||||
github.com/google/go-tpm v0.9.8 h1:slArAR9Ft+1ybZu0lBwpSmpwhRXaa85hWtMinMyRAWo=
|
||||
|
||||
@@ -3,7 +3,7 @@ module mesh-hand-acts
|
||||
go 1.26.0
|
||||
|
||||
require (
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029213929-66ff33dbd35d
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029214150-692dbf9a1791
|
||||
github.com/nats-io/nats.go v1.54.0
|
||||
)
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029213929-66ff33dbd35d h1:J1QAvzlaIvCCyZGBQX0XGJjYWdNPjLXBF4zaAeIkUOg=
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029213929-66ff33dbd35d/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029214150-692dbf9a1791 h1:HVKR7kENzltQVkfBN+2zhU9JOPZme7MjDkTvr/oiJ24=
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029214150-692dbf9a1791/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
|
||||
github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op h1:Z/MZK75wC/NSrkgqeNIa7jexam9uWzhLmFTSCPI/kn0=
|
||||
github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op/go.mod h1:FQyySiasQQM8735Ddel3MRojmy4dA1IqCeyJ5jmPMbI=
|
||||
github.com/google/go-tpm v0.9.8 h1:slArAR9Ft+1ybZu0lBwpSmpwhRXaa85hWtMinMyRAWo=
|
||||
|
||||
@@ -3,7 +3,7 @@ module mesh-healers
|
||||
go 1.26.0
|
||||
|
||||
require (
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029213929-66ff33dbd35d
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029214150-692dbf9a1791
|
||||
github.com/nats-io/nats.go v1.54.0
|
||||
)
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029213929-66ff33dbd35d h1:J1QAvzlaIvCCyZGBQX0XGJjYWdNPjLXBF4zaAeIkUOg=
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029213929-66ff33dbd35d/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029214150-692dbf9a1791 h1:HVKR7kENzltQVkfBN+2zhU9JOPZme7MjDkTvr/oiJ24=
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029214150-692dbf9a1791/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
|
||||
github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op h1:Z/MZK75wC/NSrkgqeNIa7jexam9uWzhLmFTSCPI/kn0=
|
||||
github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op/go.mod h1:FQyySiasQQM8735Ddel3MRojmy4dA1IqCeyJ5jmPMbI=
|
||||
github.com/google/go-tpm v0.9.8 h1:slArAR9Ft+1ybZu0lBwpSmpwhRXaa85hWtMinMyRAWo=
|
||||
|
||||
@@ -12,8 +12,7 @@ package main
|
||||
// - **A key's state comes from its provider's outcome alone** (clause 3, 7): the provider's own entry for that
|
||||
// consumer, `<provider>_bound` under the same key: present is provided (the vault's generation carried into the
|
||||
// reference, clause 6), refused is failed with why, waits is waits with what. The holder never sets provided by
|
||||
// itself, but for a provider that keeps no entries at all (its manifest declares no `bound`), which makes nothing per
|
||||
// consumer.
|
||||
// itself: a key of a provider that writes no outcome stays asked.
|
||||
// - **Retiring is asked** (clause 5): a key no longer needed is `retiring`, one approve ask under mesh-provisioner's
|
||||
// name says what goes from which provider on which node; the warrant goes into the key and the provider acts on it;
|
||||
// a decline is kept and not asked again while nothing changes; a key needed again returns to its outcome's state.
|
||||
@@ -292,6 +291,9 @@ func same(a, b provisions.Provision) bool {
|
||||
// entry is a provider's outcome for one consumer, as its entry says it: the provider helper's Entry, read for what
|
||||
// the holder needs and nothing more.
|
||||
type entry struct {
|
||||
// State and Why are the provider's outcome (provider.Entry, ADR 0570 clause 3): provided, failed or waits.
|
||||
State string `json:"state,omitempty"`
|
||||
Why string `json:"why,omitempty"`
|
||||
Refused string `json:"refused,omitempty"`
|
||||
Waits string `json:"waits,omitempty"`
|
||||
VaultName string `json:"vault-name,omitempty"`
|
||||
@@ -299,12 +301,12 @@ type entry struct {
|
||||
}
|
||||
|
||||
// outcome sets a needed provision's state from its provider's entry: provided, failed or waits; asked while it has
|
||||
// none. A provider that keeps no entries makes nothing per consumer: provided, said so.
|
||||
// none. The holder never sets provided by itself (clause 3): a provider whose entries it does not read keeps the key
|
||||
// asked, said so.
|
||||
func (h *Holder) outcome(key string, p *provisions.Provision) {
|
||||
p.Ask, p.Warrant = "", nil
|
||||
if !keepsEntries(p.Provider.Module) {
|
||||
p.State, p.Why = provisions.Provided, p.Provider.Module+" makes nothing per consumer: what it provides is its "+
|
||||
"placement and served values"
|
||||
p.State, p.Why = provisions.Asked, p.Provider.Module+" writes no outcome yet: provided once it says it in its own entry"
|
||||
return
|
||||
}
|
||||
e, err := h.Store.Get(boundRead(p.Provider.Module), key)
|
||||
@@ -322,10 +324,17 @@ func (h *Holder) outcome(key string, p *provisions.Provision) {
|
||||
return
|
||||
}
|
||||
switch {
|
||||
case en.Refused != "":
|
||||
case en.State == provisions.Failed:
|
||||
p.State, p.Why = provisions.Failed, orSaid(en.Why, en.Refused, "the provider said it failed")
|
||||
case en.State == provisions.Waits:
|
||||
p.State, p.Why = provisions.Waits, orSaid(en.Why, en.Waits, "the provider waits for a person")
|
||||
case en.State == "" && en.Refused != "":
|
||||
p.State, p.Why = provisions.Failed, en.Refused
|
||||
case en.Waits != "":
|
||||
case en.State == "" && en.Waits != "":
|
||||
p.State, p.Why = provisions.Waits, en.Waits
|
||||
case en.State != "" && en.State != provisions.Provided:
|
||||
p.State, p.Why = provisions.Asked, "the provider's entry says "+en.State+", which no state of a provision is"
|
||||
return
|
||||
default:
|
||||
p.State, p.Why = provisions.Provided, ""
|
||||
if en.VaultName != "" || en.Generation > 0 {
|
||||
@@ -349,7 +358,7 @@ func (h *Holder) retired(key string, p provisions.Provision) (bool, string) {
|
||||
return false, ""
|
||||
}
|
||||
if !keepsEntries(p.Provider.Module) {
|
||||
return true, "its provider keeps nothing for it"
|
||||
return false, ""
|
||||
}
|
||||
e, err := h.Store.Get(boundRead(p.Provider.Module), key)
|
||||
if err != nil || e != nil {
|
||||
@@ -615,3 +624,13 @@ func (h *Holder) RetireNeeds() (int, error) {
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// orSaid is the first of the words that says something.
|
||||
func orSaid(words ...string) string {
|
||||
for _, w := range words {
|
||||
if strings.TrimSpace(w) != "" {
|
||||
return w
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ func (m *mesh) compose(t *testing.T, node string) Composed {
|
||||
}
|
||||
|
||||
// A node composes its plans and provisions from what is wanted and placed; a key's state follows its provider's entry
|
||||
// alone; a provider that keeps no entries makes nothing per consumer; the vault's generation reaches the reference; a
|
||||
// alone; the vault's generation reaches the reference; a
|
||||
// quiet pass writes nothing (ADR 0570 clauses 1-3, 6, 7; issue 1954 H1, H2).
|
||||
func TestAKeysStateFollowsItsProvidersOutcome(t *testing.T) {
|
||||
m := newMesh()
|
||||
@@ -124,7 +124,8 @@ func TestAKeysStateFollowsItsProvidersOutcome(t *testing.T) {
|
||||
{"composed: asked", "", provisions.Asked, ""},
|
||||
{"the provider waits for a person", `{"waits":"the database's owner to accept"}`, provisions.Waits, "owner"},
|
||||
{"the provider refused", `{"refused":"no room on ace"}`, provisions.Failed, "no room"},
|
||||
{"the provider made it", `{"vault-name":"pair/gitea-postgres","generation":3}`, provisions.Provided, ""},
|
||||
{"the provider says failed in its state", `{"state":"failed","why":"the disk is full"}`, provisions.Failed, "disk"},
|
||||
{"the provider made it", `{"state":"provided","vault-name":"pair/gitea-postgres","generation":3}`, provisions.Provided, ""},
|
||||
}
|
||||
for _, s := range steps {
|
||||
if s.entry != "" {
|
||||
@@ -139,8 +140,9 @@ func TestAKeysStateFollowsItsProvidersOutcome(t *testing.T) {
|
||||
if p := m.state(t, key); p.Reference == nil || p.Reference.ID != "pair/gitea-postgres" || p.Reference.Generation != 3 {
|
||||
t.Errorf("the vault's generation does not reach the reference: %+v", p.Reference)
|
||||
}
|
||||
if p := m.state(t, "g14.gitea.split-dns"); p.State != provisions.Provided || !strings.Contains(p.Why, "makes nothing") {
|
||||
t.Errorf("a provider keeping no entries: %+v", p)
|
||||
// The holder never sets provided by itself: a provider writing no outcome leaves its key asked (clause 3).
|
||||
if p := m.state(t, "g14.gitea.split-dns"); p.State != provisions.Asked || !strings.Contains(p.Why, "writes no outcome") {
|
||||
t.Errorf("a provider writing no outcome: %+v", p)
|
||||
}
|
||||
if e, _ := m.s.Get(PlansState, "g14.gitea"); e == nil {
|
||||
t.Error("the plan is not written")
|
||||
|
||||
@@ -2,4 +2,4 @@ module mesh-provisioner
|
||||
|
||||
go 1.26.0
|
||||
|
||||
require git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029213929-66ff33dbd35d
|
||||
require git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029214150-692dbf9a1791
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029213929-66ff33dbd35d h1:J1QAvzlaIvCCyZGBQX0XGJjYWdNPjLXBF4zaAeIkUOg=
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029213929-66ff33dbd35d/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029214150-692dbf9a1791 h1:HVKR7kENzltQVkfBN+2zhU9JOPZme7MjDkTvr/oiJ24=
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029214150-692dbf9a1791/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
|
||||
github.com/klauspost/compress v1.20.0 h1:a3C1ke2ohxFymNlb2HWAHjDeKCI90scRskErZkR0ezA=
|
||||
github.com/klauspost/compress v1.20.0/go.mod h1:LUdAzn7YLVvxLpc7y3V1m40wESHTgc1422pwwBSKYuI=
|
||||
github.com/nats-io/nats.go v1.54.0 h1:vsXoOxjHp/GmPUN+EcI7uOf/uB+iAP+kEsAFNQN0yzA=
|
||||
|
||||
@@ -3,7 +3,7 @@ module mesh-self-check
|
||||
go 1.26.0
|
||||
|
||||
require (
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029213929-66ff33dbd35d
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029214150-692dbf9a1791
|
||||
github.com/nats-io/nats.go v1.54.0
|
||||
)
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029213929-66ff33dbd35d h1:J1QAvzlaIvCCyZGBQX0XGJjYWdNPjLXBF4zaAeIkUOg=
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029213929-66ff33dbd35d/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029214150-692dbf9a1791 h1:HVKR7kENzltQVkfBN+2zhU9JOPZme7MjDkTvr/oiJ24=
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029214150-692dbf9a1791/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
|
||||
github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op h1:Z/MZK75wC/NSrkgqeNIa7jexam9uWzhLmFTSCPI/kn0=
|
||||
github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op/go.mod h1:FQyySiasQQM8735Ddel3MRojmy4dA1IqCeyJ5jmPMbI=
|
||||
github.com/google/go-tpm v0.9.8 h1:slArAR9Ft+1ybZu0lBwpSmpwhRXaa85hWtMinMyRAWo=
|
||||
|
||||
Reference in New Issue
Block a user