Provision and provider users take the provisioner's client; mesh-vault writes its findings through the conditions client (K-4..K-20, K-21 part; ADR 0634 §4; issue 1966)
This commit is contained in:
@@ -39,17 +39,17 @@ import (
|
||||
|
||||
occ "git.novox.be/novox/mesh-contracts/operator-and-conversation/go/clients/operatorchannelclient"
|
||||
oc "git.novox.be/novox/mesh-contracts/operator-and-conversation/go/seats/operatorchannel"
|
||||
"git.novox.be/novox/mesh-contracts/provisioning/go/clients/meshprovisionerclient"
|
||||
stdio "git.novox.be/novox/mesh-sdk/go"
|
||||
"git.novox.be/novox/mesh-sdk/go/catalogue"
|
||||
"git.novox.be/novox/mesh-sdk/go/delivery"
|
||||
"git.novox.be/novox/mesh-sdk/go/provisions"
|
||||
)
|
||||
|
||||
// The states it keeps, beside Registry, Needs, Applied and Collect. RefusedState holds, by `<node>.<module>`, why a
|
||||
// placed module has no plan composed (issue 774): written while it is held, deleted once it composes again.
|
||||
const (
|
||||
ProvisionsState = provisions.ProvisionsState
|
||||
PlansState = provisions.PlansState
|
||||
ProvisionsState = meshprovisionerclient.ProvisionsState
|
||||
PlansState = meshprovisionerclient.PlansState
|
||||
RefusedState = "refused"
|
||||
)
|
||||
|
||||
@@ -169,7 +169,7 @@ func TookSaid(took []Took) string {
|
||||
return strings.Join(said, ", ")
|
||||
}
|
||||
|
||||
// ComposeNode composes one node: its plans and its provisions.
|
||||
// ComposeNode composes one node: its plans and its meshprovisionerclient.
|
||||
func (h *Holder) ComposeNode(ctx context.Context, node string) (Composed, error) {
|
||||
return h.ComposeNodeWith(ctx, node, false)
|
||||
}
|
||||
@@ -250,8 +250,8 @@ func (h *Holder) ComposeNodeWith(ctx context.Context, node string, retireMany bo
|
||||
out.Problems = append(out.Problems, err.Error())
|
||||
}
|
||||
lap("plans written")
|
||||
needed := map[string]provisions.Provision{}
|
||||
elsewhere := map[string]provisions.Provision{}
|
||||
needed := map[string]meshprovisionerclient.Provision{}
|
||||
elsewhere := map[string]meshprovisionerclient.Provision{}
|
||||
// ahead are the keys only the newest build of their consumer requires: the plan written, its wanted build's, names
|
||||
// them not yet, and the provider binds them from the entry they carry (issue 1126).
|
||||
ahead := map[string]string{}
|
||||
@@ -259,10 +259,10 @@ func (h *Holder) ComposeNodeWith(ctx context.Context, node string, retireMany bo
|
||||
for i, plans := range []map[string]catalogue.Plan{atWants, newest} {
|
||||
for module, plan := range plans {
|
||||
for _, p := range plan.Provisions {
|
||||
consumer := provisions.End{Module: module, Node: node}
|
||||
provider := provisions.End{Module: p.ProviderModule, Node: p.Provider}
|
||||
pv := provisions.Provision{Provision: p.Provision, Local: p.Local, Consumer: consumer, Provider: provider,
|
||||
DependsOn: provisions.DependsOn(consumer, p, h.providerPlan(p, node, atWants))}
|
||||
consumer := meshprovisionerclient.End{Module: module, Node: node}
|
||||
provider := meshprovisionerclient.End{Module: p.ProviderModule, Node: p.Provider}
|
||||
pv := meshprovisionerclient.Provision{Provision: p.Provision, Local: p.Local, Consumer: consumer, Provider: provider,
|
||||
DependsOn: meshprovisionerclient.DependsOn(consumer, p, h.providerPlan(p, node, atWants))}
|
||||
key, err := pv.Key()
|
||||
if err != nil {
|
||||
out.Problems = append(out.Problems, err.Error())
|
||||
@@ -281,11 +281,11 @@ func (h *Holder) ComposeNodeWith(ctx context.Context, node string, retireMany bo
|
||||
}
|
||||
// Its credential is a provision of its own, the vault's (clause 6): on the consumer's node for a value of the
|
||||
// consumer's own, on the provider's for the provider's one shared value.
|
||||
ck, ok := provisions.CredentialKey(p.CredentialForm, consumer, provider, p.Provision, p.Local)
|
||||
ck, ok := meshprovisionerclient.CredentialKey(p.CredentialForm, consumer, provider, p.Provision, p.Local)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
cn, cm, cp, cl, err := provisions.ParseKey(ck)
|
||||
cn, cm, cp, cl, err := meshprovisionerclient.ParseKey(ck)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
@@ -293,8 +293,8 @@ func (h *Holder) ComposeNodeWith(ctx context.Context, node string, retireMany bo
|
||||
out.Problems = append(out.Problems, "no node runs mesh-vault, so the credential "+ck+" has no provider")
|
||||
continue
|
||||
}
|
||||
cred := provisions.Provision{Provision: cp, Local: cl, Consumer: provisions.End{Module: cm, Node: cn},
|
||||
Provider: provisions.End{Module: provisions.VaultModule, Node: vaultNode}}
|
||||
cred := meshprovisionerclient.Provision{Provision: cp, Local: cl, Consumer: meshprovisionerclient.End{Module: cm, Node: cn},
|
||||
Provider: meshprovisionerclient.End{Module: meshprovisionerclient.VaultModule, Node: vaultNode}}
|
||||
if cn == node {
|
||||
if _, seen := needed[ck]; !seen {
|
||||
needed[ck] = cred
|
||||
@@ -329,7 +329,7 @@ func (h *Holder) ComposeNodeWith(ctx context.Context, node string, retireMany bo
|
||||
func (h *Holder) writeRefused(node string, held map[string]string) error {
|
||||
var problems []error
|
||||
for _, module := range sortedKeys(held) {
|
||||
key, err := provisions.PlanKey(node, module)
|
||||
key, err := meshprovisionerclient.PlanKey(node, module)
|
||||
if err != nil {
|
||||
problems = append(problems, err)
|
||||
continue
|
||||
@@ -382,7 +382,7 @@ func (h *Holder) providerPlan(p catalogue.PlanProvision, node string, here map[s
|
||||
}
|
||||
return nil
|
||||
}
|
||||
key, err := provisions.PlanKey(p.Provider, p.ProviderModule)
|
||||
key, err := meshprovisionerclient.PlanKey(p.Provider, p.ProviderModule)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
@@ -390,7 +390,7 @@ func (h *Holder) providerPlan(p catalogue.PlanProvision, node string, here map[s
|
||||
if err != nil || e == nil {
|
||||
return nil
|
||||
}
|
||||
plan, err := provisions.DecodePlan(e.Value)
|
||||
plan, err := meshprovisionerclient.DecodePlan(e.Value)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
@@ -399,7 +399,7 @@ func (h *Holder) providerPlan(p catalogue.PlanProvision, node string, here map[s
|
||||
|
||||
// vaultNode is the node mesh-vault is placed on: the provider of every credential.
|
||||
func (h *Holder) vaultNode() string {
|
||||
nodes := h.placedOn(provisions.VaultModule)
|
||||
nodes := h.placedOn(meshprovisionerclient.VaultModule)
|
||||
if len(nodes) == 0 {
|
||||
return ""
|
||||
}
|
||||
@@ -421,7 +421,7 @@ func (h *Holder) dependedOn(node string) []string {
|
||||
if err != nil || e == nil {
|
||||
continue
|
||||
}
|
||||
if p, err := provisions.Decode(e.Value); err == nil {
|
||||
if p, err := meshprovisionerclient.Decode(e.Value); err == nil {
|
||||
for _, d := range p.DependsOn {
|
||||
if strings.HasPrefix(d, node+".") {
|
||||
out = append(out, d)
|
||||
@@ -434,13 +434,13 @@ func (h *Holder) dependedOn(node string) []string {
|
||||
|
||||
// judgeElsewhere writes each needed key of another node (a provider's shared credential), its state from its outcome;
|
||||
// that node's own composition keeps it while a provision depends on it.
|
||||
func (h *Holder) judgeElsewhere(keys map[string]provisions.Provision, out *Composed) {
|
||||
func (h *Holder) judgeElsewhere(keys map[string]meshprovisionerclient.Provision, out *Composed) {
|
||||
for _, key := range sortedKeys(keys) {
|
||||
next := keys[key]
|
||||
var have provisions.Provision
|
||||
var have meshprovisionerclient.Provision
|
||||
e, err := h.Store.Get(ProvisionsState, key)
|
||||
if err == nil && e != nil {
|
||||
if have, err = provisions.Decode(e.Value); err == nil {
|
||||
if have, err = meshprovisionerclient.Decode(e.Value); err == nil {
|
||||
next.Reference = have.Reference
|
||||
}
|
||||
}
|
||||
@@ -505,12 +505,12 @@ func (h *Holder) runningOn(node string) (map[string]string, error) {
|
||||
func (h *Holder) writePlans(node string, plans map[string]catalogue.Plan, held map[string]string, out *Composed) error {
|
||||
var problems []error
|
||||
for _, module := range sortedKeys(plans) {
|
||||
key, err := provisions.PlanKey(node, module)
|
||||
key, err := meshprovisionerclient.PlanKey(node, module)
|
||||
if err != nil {
|
||||
problems = append(problems, err)
|
||||
continue
|
||||
}
|
||||
raw, err := provisions.EncodePlan(provisions.Plan{Node: node, Module: module, Plan: plans[module]})
|
||||
raw, err := meshprovisionerclient.EncodePlan(meshprovisionerclient.Plan{Node: node, Module: module, Plan: plans[module]})
|
||||
if err != nil {
|
||||
problems = append(problems, err)
|
||||
continue
|
||||
@@ -552,7 +552,7 @@ func (h *Holder) writePlans(node string, plans map[string]catalogue.Plan, held m
|
||||
// untouched (held on the node, or with a want or a have and no plan read in this pass) that its composition no longer
|
||||
// names is left as it is: not composed is not unneeded. A pass that would retire most of the node's consumers at once retires none, said as a fault of
|
||||
// the mesh (issue 940), unless retireMany.
|
||||
func (h *Holder) judgeNode(node string, needed map[string]provisions.Provision, ahead map[string]string,
|
||||
func (h *Holder) judgeNode(node string, needed map[string]meshprovisionerclient.Provision, ahead map[string]string,
|
||||
untouched map[string]string, retireMany bool, out *Composed) {
|
||||
held := h.held(node)
|
||||
consumers := map[string]bool{}
|
||||
@@ -577,7 +577,7 @@ func (h *Holder) judgeNode(node string, needed map[string]provisions.Provision,
|
||||
var newly []string
|
||||
leaving := map[string]bool{}
|
||||
for key, have := range held {
|
||||
if _, isNeeded := needed[key]; !isNeeded && have.State != provisions.Retiring {
|
||||
if _, isNeeded := needed[key]; !isNeeded && have.State != meshprovisionerclient.Retiring {
|
||||
newly = append(newly, key)
|
||||
leaving[have.Consumer.Module] = true
|
||||
}
|
||||
@@ -607,7 +607,7 @@ func (h *Holder) judgeNode(node string, needed map[string]provisions.Provision,
|
||||
for _, key := range unionKeys(needed, held) {
|
||||
want, isNeeded := needed[key]
|
||||
have, isHeld := held[key]
|
||||
var next provisions.Provision
|
||||
var next meshprovisionerclient.Provision
|
||||
switch {
|
||||
case isNeeded:
|
||||
next = want
|
||||
@@ -615,7 +615,7 @@ func (h *Holder) judgeNode(node string, needed map[string]provisions.Provision,
|
||||
next.Reference = have.Reference
|
||||
}
|
||||
h.outcome(key, &next)
|
||||
if module, isAhead := ahead[key]; isAhead && next.State == provisions.Asked {
|
||||
if module, isAhead := ahead[key]; isAhead && next.State == meshprovisionerclient.Asked {
|
||||
// The reason the provider's helper says too: no plan names it yet, and it binds it from this key's entry.
|
||||
why := "no plan names it yet: the newest build of " + module + " requires it and its wanted build does " +
|
||||
"not, so its provider binds it from this key's plan entry"
|
||||
@@ -624,7 +624,7 @@ func (h *Holder) judgeNode(node string, needed map[string]provisions.Provision,
|
||||
}
|
||||
next.Why = why
|
||||
}
|
||||
case have.State == provisions.Retiring:
|
||||
case have.State == meshprovisionerclient.Retiring:
|
||||
next = have
|
||||
if next.Ask != "" && next.Warrant == nil && !h.askHeld(next) {
|
||||
out.Problems = append(out.Problems, "the router holds no ask "+next.Ask+" of "+key+": it is raised again")
|
||||
@@ -643,7 +643,7 @@ func (h *Holder) judgeNode(node string, needed map[string]provisions.Provision,
|
||||
}
|
||||
default:
|
||||
next = have
|
||||
next.State, next.Why = provisions.Retiring, fmt.Sprintf("no build wanted or placed on %s requires %s of %s on %s "+
|
||||
next.State, next.Why = meshprovisionerclient.Retiring, fmt.Sprintf("no build wanted or placed on %s requires %s of %s on %s "+
|
||||
"any more", node, have.Provision, have.Provider.Module, have.Provider.Node)
|
||||
next.Warrant = nil
|
||||
h.raise(&next, key, out)
|
||||
@@ -652,7 +652,7 @@ func (h *Holder) judgeNode(node string, needed map[string]provisions.Provision,
|
||||
continue
|
||||
}
|
||||
next.At = h.Now().UTC()
|
||||
raw, err := provisions.Encode(next)
|
||||
raw, err := meshprovisionerclient.Encode(next)
|
||||
if err != nil {
|
||||
out.Problems = append(out.Problems, err.Error())
|
||||
continue
|
||||
@@ -666,8 +666,8 @@ func (h *Holder) judgeNode(node string, needed map[string]provisions.Provision,
|
||||
}
|
||||
|
||||
// held is the node's provision keys as kept.
|
||||
func (h *Holder) held(node string) map[string]provisions.Provision {
|
||||
out := map[string]provisions.Provision{}
|
||||
func (h *Holder) held(node string) map[string]meshprovisionerclient.Provision {
|
||||
out := map[string]meshprovisionerclient.Provision{}
|
||||
keys, err := h.Store.Keys(ProvisionsState)
|
||||
if err != nil {
|
||||
return out
|
||||
@@ -680,7 +680,7 @@ func (h *Holder) held(node string) map[string]provisions.Provision {
|
||||
if err != nil || e == nil {
|
||||
continue
|
||||
}
|
||||
if p, err := provisions.Decode(e.Value); err == nil {
|
||||
if p, err := meshprovisionerclient.Decode(e.Value); err == nil {
|
||||
out[k] = p
|
||||
}
|
||||
}
|
||||
@@ -688,7 +688,7 @@ func (h *Holder) held(node string) map[string]provisions.Provision {
|
||||
}
|
||||
|
||||
// same says two provisions say the same, their time aside.
|
||||
func same(a, b provisions.Provision) bool {
|
||||
func same(a, b meshprovisionerclient.Provision) bool {
|
||||
a.At, b.At, a.V, b.V = time.Time{}, time.Time{}, 0, 0
|
||||
ra, _ := json.Marshal(a)
|
||||
rb, _ := json.Marshal(b)
|
||||
@@ -710,11 +710,11 @@ type entry struct {
|
||||
// outcome sets a needed provision's state from its provider's entry: provided, failed or waits; asked while it has
|
||||
// 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) {
|
||||
func (h *Holder) outcome(key string, p *meshprovisionerclient.Provision) {
|
||||
p.Ask, p.Warrant = "", nil
|
||||
keeps, err := h.keepsEntries(p.Provider.Module, p.Provision)
|
||||
if err != nil {
|
||||
p.State, p.Why = provisions.Asked, "the manifest of "+p.Provider.Module+" cannot be read: "+err.Error()
|
||||
p.State, p.Why = meshprovisionerclient.Asked, "the manifest of "+p.Provider.Module+" cannot be read: "+err.Error()
|
||||
return
|
||||
}
|
||||
if !keeps {
|
||||
@@ -722,40 +722,40 @@ func (h *Holder) outcome(key string, p *provisions.Provision) {
|
||||
return
|
||||
}
|
||||
if !slices.Contains(BoundReads, p.Provider.Module) {
|
||||
p.State, p.Why = provisions.Asked, p.Provider.Module+" keeps its outcome in its entries, which mesh-provisioner's "+
|
||||
p.State, p.Why = meshprovisionerclient.Asked, p.Provider.Module+" keeps its outcome in its entries, which mesh-provisioner's "+
|
||||
"manifest does not read yet"
|
||||
return
|
||||
}
|
||||
e, err := h.Store.Get(boundRead(p.Provider.Module), key)
|
||||
if err != nil {
|
||||
p.State, p.Why = provisions.Asked, "the provider's entries cannot be read: "+err.Error()
|
||||
p.State, p.Why = meshprovisionerclient.Asked, "the provider's entries cannot be read: "+err.Error()
|
||||
return
|
||||
}
|
||||
if e == nil {
|
||||
p.State, p.Why = provisions.Asked, h.unread(p.Provider.Module)
|
||||
p.State, p.Why = meshprovisionerclient.Asked, h.unread(p.Provider.Module)
|
||||
return
|
||||
}
|
||||
var en entry
|
||||
if err := json.Unmarshal(e.Value, &en); err != nil {
|
||||
p.State, p.Why = provisions.Asked, "the provider's entry is not readable"
|
||||
p.State, p.Why = meshprovisionerclient.Asked, "the provider's entry is not readable"
|
||||
return
|
||||
}
|
||||
switch {
|
||||
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 == meshprovisionerclient.Failed:
|
||||
p.State, p.Why = meshprovisionerclient.Failed, orSaid(en.Why, en.Refused, "the provider said it failed")
|
||||
case en.State == meshprovisionerclient.Waits:
|
||||
p.State, p.Why = meshprovisionerclient.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
|
||||
p.State, p.Why = meshprovisionerclient.Failed, en.Refused
|
||||
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"
|
||||
p.State, p.Why = meshprovisionerclient.Waits, en.Waits
|
||||
case en.State != "" && en.State != meshprovisionerclient.Provided:
|
||||
p.State, p.Why = meshprovisionerclient.Asked, "the provider's entry says "+en.State+", which no state of a provision is"
|
||||
return
|
||||
default:
|
||||
p.State, p.Why = provisions.Provided, ""
|
||||
p.State, p.Why = meshprovisionerclient.Provided, ""
|
||||
if en.VaultName != "" || en.Generation > 0 {
|
||||
p.Reference = &provisions.Reference{ID: en.VaultName, Generation: en.Generation}
|
||||
p.Reference = &meshprovisionerclient.Reference{ID: en.VaultName, Generation: en.Generation}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -773,44 +773,44 @@ func (h *Holder) unread(module string) string {
|
||||
var decl struct {
|
||||
Reads []string `json:"reads"`
|
||||
}
|
||||
if json.Unmarshal([]byte(manifest), &decl) != nil || slices.Contains(decl.Reads, provisions.PlansRead) {
|
||||
if json.Unmarshal([]byte(manifest), &decl) != nil || slices.Contains(decl.Reads, meshprovisionerclient.PlansRead) {
|
||||
return ""
|
||||
}
|
||||
return module + " reads no plans of the seat (its manifest's reads do not name " + provisions.PlansRead +
|
||||
return module + " reads no plans of the seat (its manifest's reads do not name " + meshprovisionerclient.PlansRead +
|
||||
"), so its helper never answers this key"
|
||||
}
|
||||
|
||||
// haveOutcome is the outcome of a provider that makes no credential per consumer: its own have on its node (the lead's
|
||||
// reading of ADR 0570 clause 3, recorded as an insight). Running with health ok at the build its want names is
|
||||
// provided; failed is failed with the have's words; anything else is asked, waiting for the provider to run.
|
||||
func (h *Holder) haveOutcome(p *provisions.Provision) {
|
||||
func (h *Holder) haveOutcome(p *meshprovisionerclient.Provision) {
|
||||
where := p.Provider.Module + " on " + p.Provider.Node
|
||||
// It makes what the consumer needs only once all it depends on is provided (its credential first).
|
||||
for _, dep := range p.DependsOn {
|
||||
state := "not composed yet"
|
||||
if e, err := h.Store.Get(ProvisionsState, dep); err == nil && e != nil {
|
||||
if d, err := provisions.Decode(e.Value); err == nil {
|
||||
if d, err := meshprovisionerclient.Decode(e.Value); err == nil {
|
||||
state = d.State
|
||||
}
|
||||
}
|
||||
if state != provisions.Provided {
|
||||
p.State, p.Why = provisions.Asked, "waits for "+dep+" ("+state+") before "+where+" can provide it"
|
||||
if state != meshprovisionerclient.Provided {
|
||||
p.State, p.Why = meshprovisionerclient.Asked, "waits for "+dep+" ("+state+") before "+where+" can provide it"
|
||||
return
|
||||
}
|
||||
}
|
||||
key := p.Provider.Node + "." + p.Provider.Module
|
||||
e, err := h.Store.Get(HaveRead, key)
|
||||
if err != nil {
|
||||
p.State, p.Why = provisions.Asked, "the have of "+where+" cannot be read: "+err.Error()
|
||||
p.State, p.Why = meshprovisionerclient.Asked, "the have of "+where+" cannot be read: "+err.Error()
|
||||
return
|
||||
}
|
||||
if e == nil {
|
||||
p.State, p.Why = provisions.Asked, "waits for "+where+" to run: it says nothing yet"
|
||||
p.State, p.Why = meshprovisionerclient.Asked, "waits for "+where+" to run: it says nothing yet"
|
||||
return
|
||||
}
|
||||
have, err := delivery.DecodeHave(e.Value)
|
||||
if err != nil {
|
||||
p.State, p.Why = provisions.Asked, "the have of "+where+" is not readable"
|
||||
p.State, p.Why = meshprovisionerclient.Asked, "the have of "+where+" is not readable"
|
||||
return
|
||||
}
|
||||
wantFP := ""
|
||||
@@ -821,19 +821,19 @@ func (h *Holder) haveOutcome(p *provisions.Provision) {
|
||||
}
|
||||
switch {
|
||||
case have.Phase == delivery.PhaseFailed || have.Health == delivery.HealthFailed:
|
||||
p.State, p.Why = provisions.Failed, orSaid(have.Detail, where+" failed")
|
||||
p.State, p.Why = meshprovisionerclient.Failed, orSaid(have.Detail, where+" failed")
|
||||
case have.Phase == delivery.PhaseRunning && have.Health == delivery.HealthOK && (wantFP == "" || have.FP == wantFP):
|
||||
// A provider's have counts as its outcome only from a build whose manifest offers the provision (ADR 0603 clause 5).
|
||||
// Refused only when that manifest is known and does not offer it: a have with no builder key (an old-form build, an
|
||||
// adopted module) or an unreadable manifest keeps the outcome it had.
|
||||
if offers, known := h.buildOffers(p.Provider.Module, have.FP, p.Provision); known && !offers {
|
||||
p.State, p.Why = provisions.Asked, "waits for "+where+" to run a build that offers "+p.Provision+": the build it runs ("+
|
||||
p.State, p.Why = meshprovisionerclient.Asked, "waits for "+where+" to run a build that offers "+p.Provision+": the build it runs ("+
|
||||
have.FP+") does not"
|
||||
return
|
||||
}
|
||||
p.State, p.Why = provisions.Provided, ""
|
||||
p.State, p.Why = meshprovisionerclient.Provided, ""
|
||||
default:
|
||||
p.State, p.Why = provisions.Asked, fmt.Sprintf("waits for %s to run healthy at the build its want names (it is %s, "+
|
||||
p.State, p.Why = meshprovisionerclient.Asked, fmt.Sprintf("waits for %s to run healthy at the build its want names (it is %s, "+
|
||||
"health %s)", where, have.Phase, have.Health)
|
||||
}
|
||||
}
|
||||
@@ -975,7 +975,7 @@ func (h *Holder) providerManifest(module string) (string, error) {
|
||||
}
|
||||
|
||||
// retired says a retiring key the operator approved is retired: its provider's entry is gone.
|
||||
func (h *Holder) retired(key string, p provisions.Provision) (bool, string) {
|
||||
func (h *Holder) retired(key string, p meshprovisionerclient.Provision) (bool, string) {
|
||||
if p.Warrant == nil || p.Warrant.Option != OptionApprove {
|
||||
return false, ""
|
||||
}
|
||||
@@ -1003,7 +1003,7 @@ const (
|
||||
const askLasts = occ.ApproveLasts - 10*time.Minute
|
||||
|
||||
// retiringAsk is the ask of one retiring provision, composed from the key alone.
|
||||
func retiringAsk(key string, p provisions.Provision, at time.Time, id string) oc.Ask {
|
||||
func retiringAsk(key string, p meshprovisionerclient.Provision, at time.Time, id string) oc.Ask {
|
||||
what := fmt.Sprintf("%s's access to %s on %s, for %s on %s", p.Consumer.Module, p.Provision, p.Provider.Node,
|
||||
p.Consumer.Module, p.Consumer.Node)
|
||||
a := oc.Ask{ID: id, Headline: "Remove " + p.Consumer.Module + "'s " + p.Provision + " access?",
|
||||
@@ -1011,7 +1011,7 @@ func retiringAsk(key string, p provisions.Provision, at time.Time, id string) oc
|
||||
"is handed to the resource's owner and its credential goes; the resource and its data stay.", p.Consumer.Node,
|
||||
p.Provision, p.Provider.Module, what),
|
||||
Who: occ.Operator, Expires: occ.FormatTime(at.Add(askLasts)), OnExpiry: "nothing is removed; it is asked again when it changes",
|
||||
About: "provision." + key, Details: "The provision " + key + " of mesh-provisioner's state provisions."}
|
||||
About: "provision." + key, Details: "The provision " + key + " of mesh-provisioner's state meshprovisionerclient."}
|
||||
for _, o := range []struct{ id, label, does string }{
|
||||
{OptionApprove, "Remove", "the provider removes the credential; the resource and its data stay"},
|
||||
{OptionDecline, "Keep", "nothing is removed, and it is not asked again while nothing changes"},
|
||||
@@ -1041,7 +1041,7 @@ const askWaits = "its ask waits until fewer than 3 of mesh-provisioner's asks st
|
||||
var errAskWaits = errors.New(askWaits)
|
||||
|
||||
// raise asks a retiring key and says so in out: asked, waiting for an open ask to end, or a problem.
|
||||
func (h *Holder) raise(p *provisions.Provision, key string, out *Composed) {
|
||||
func (h *Holder) raise(p *meshprovisionerclient.Provision, key string, out *Composed) {
|
||||
switch err := h.ask(p, key); {
|
||||
case err == nil:
|
||||
out.Asked = append(out.Asked, key)
|
||||
@@ -1053,7 +1053,7 @@ func (h *Holder) raise(p *provisions.Provision, key string, out *Composed) {
|
||||
|
||||
// ask raises the retiring ask of a key, under mesh-provisioner's own name; one already raised stands. While
|
||||
// askOpenAtMost asks stand open it raises none and the key's why says so.
|
||||
func (h *Holder) ask(p *provisions.Provision, key string) error {
|
||||
func (h *Holder) ask(p *meshprovisionerclient.Provision, key string) error {
|
||||
if p.Ask != "" {
|
||||
return nil
|
||||
}
|
||||
@@ -1086,7 +1086,7 @@ func (h *Holder) openAsks() int {
|
||||
keys, _ := h.Store.Keys(ProvisionsState)
|
||||
for _, k := range keys {
|
||||
if e, err := h.Store.Get(ProvisionsState, k); err == nil && e != nil {
|
||||
if p, err := provisions.Decode(e.Value); err == nil && p.State == provisions.Retiring && p.Ask != "" &&
|
||||
if p, err := meshprovisionerclient.Decode(e.Value); err == nil && p.State == meshprovisionerclient.Retiring && p.Ask != "" &&
|
||||
p.Warrant == nil {
|
||||
n++
|
||||
}
|
||||
@@ -1097,7 +1097,7 @@ func (h *Holder) openAsks() int {
|
||||
|
||||
// askHeld says the router holds a key's ask, or may not have taken it yet: false only when it has no record of it
|
||||
// askHeldWithin after it was raised (issue 940: an ask the router refused was counted asked for good).
|
||||
func (h *Holder) askHeld(p provisions.Provision) bool {
|
||||
func (h *Holder) askHeld(p meshprovisionerclient.Provision) bool {
|
||||
if h.Asks == nil || p.Ask == "" {
|
||||
return true
|
||||
}
|
||||
@@ -1125,8 +1125,8 @@ func (h *Holder) Decide() []string {
|
||||
if err != nil || e == nil {
|
||||
continue
|
||||
}
|
||||
p, err := provisions.Decode(e.Value)
|
||||
if err != nil || p.State != provisions.Retiring || p.Ask == "" || p.Warrant != nil {
|
||||
p, err := meshprovisionerclient.Decode(e.Value)
|
||||
if err != nil || p.State != meshprovisionerclient.Retiring || p.Ask == "" || p.Warrant != nil {
|
||||
continue
|
||||
}
|
||||
raw, found, err := h.Asks.Record(p.Ask)
|
||||
@@ -1180,7 +1180,7 @@ func (h *Holder) Decide() []string {
|
||||
said = append(said, k+": the answer is refused: its time is not RFC 3339 ("+err.Error()+")")
|
||||
continue
|
||||
}
|
||||
p.Warrant = &provisions.Warrant{Ask: p.Ask, Option: option, By: by, At: answeredAt.UTC()}
|
||||
p.Warrant = &meshprovisionerclient.Warrant{Ask: p.Ask, Option: option, By: by, At: answeredAt.UTC()}
|
||||
h.put(k, p)
|
||||
said = append(said, k+": "+option+" by "+by)
|
||||
}
|
||||
@@ -1200,8 +1200,8 @@ func (h *Holder) raiseWaiting() []string {
|
||||
if err != nil || e == nil {
|
||||
continue
|
||||
}
|
||||
p, err := provisions.Decode(e.Value)
|
||||
if err != nil || p.State != provisions.Retiring || p.Ask != "" || p.Warrant != nil || !strings.Contains(p.Why, askWaits) {
|
||||
p, err := meshprovisionerclient.Decode(e.Value)
|
||||
if err != nil || p.State != meshprovisionerclient.Retiring || p.Ask != "" || p.Warrant != nil || !strings.Contains(p.Why, askWaits) {
|
||||
continue
|
||||
}
|
||||
switch err := h.ask(&p, k); {
|
||||
@@ -1297,9 +1297,9 @@ func (h *Holder) LastingHolds() map[string]string {
|
||||
return out
|
||||
}
|
||||
|
||||
func (h *Holder) put(key string, p provisions.Provision) {
|
||||
func (h *Holder) put(key string, p meshprovisionerclient.Provision) {
|
||||
p.At = h.Now().UTC()
|
||||
if raw, err := provisions.Encode(p); err == nil {
|
||||
if raw, err := meshprovisionerclient.Encode(p); err == nil {
|
||||
if err := h.Store.Put(ProvisionsState, key, json.RawMessage(raw)); err != nil {
|
||||
h.Logf("[%s] %s is not written: %v", Module, key, err)
|
||||
}
|
||||
@@ -1334,7 +1334,7 @@ func (h *Holder) NodesOfModule(module string) []string {
|
||||
if keys, err := h.Store.Keys(ProvisionsState); err == nil {
|
||||
for _, k := range keys {
|
||||
if e, err := h.Store.Get(ProvisionsState, k); err == nil && e != nil {
|
||||
if p, err := provisions.Decode(e.Value); err == nil && p.Provider.Module == module {
|
||||
if p, err := meshprovisionerclient.Decode(e.Value); err == nil && p.Provider.Module == module {
|
||||
nodes[p.Consumer.Node] = true
|
||||
}
|
||||
}
|
||||
@@ -1368,7 +1368,7 @@ func (h *Holder) placedOn(module string) []string {
|
||||
|
||||
// NodeOfEntry is the consumer's node a provider's entry key names.
|
||||
func NodeOfEntry(key string) []string {
|
||||
if n, _, _, _, err := provisions.ParseKey(key); err == nil {
|
||||
if n, _, _, _, err := meshprovisionerclient.ParseKey(key); err == nil {
|
||||
return []string{n}
|
||||
}
|
||||
return nil
|
||||
@@ -1403,11 +1403,11 @@ func (h *Holder) Rejudge(key string) (string, error) {
|
||||
if err != nil || e == nil {
|
||||
return "", err
|
||||
}
|
||||
have, err := provisions.Decode(e.Value)
|
||||
have, err := meshprovisionerclient.Decode(e.Value)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if have.State == provisions.Retiring {
|
||||
if have.State == meshprovisionerclient.Retiring {
|
||||
if gone, why := h.retired(key, have); gone {
|
||||
return key + " retired: " + why, h.Store.Delete(ProvisionsState, key)
|
||||
}
|
||||
|
||||
@@ -22,9 +22,9 @@ import (
|
||||
"github.com/nats-io/nats.go/jetstream"
|
||||
|
||||
oc "git.novox.be/novox/mesh-contracts/operator-and-conversation/go/seats/operatorchannel"
|
||||
"git.novox.be/novox/mesh-contracts/provisioning/go/clients/meshprovisionerclient"
|
||||
stdio "git.novox.be/novox/mesh-sdk/go"
|
||||
"git.novox.be/novox/mesh-sdk/go/delivery"
|
||||
"git.novox.be/novox/mesh-sdk/go/provisions"
|
||||
"git.novox.be/novox/mesh-sdk/go/testbus"
|
||||
)
|
||||
|
||||
@@ -132,9 +132,9 @@ func TestTheHolderPlansProvidesAndAsksOnTheBus(t *testing.T) {
|
||||
published(t, mem, c)
|
||||
vaultManifest := `{"module":"mesh-vault","version":"1","state":["bound"]}` // the vault keeps its outcomes as entries
|
||||
vaultDigest := delivery.ManifestDigest([]byte(vaultManifest))
|
||||
vaultValue, _ := delivery.EncodeManifest(delivery.Manifest{Module: provisions.VaultModule, JSON: vaultManifest})
|
||||
vaultValue, _ := delivery.EncodeManifest(delivery.Manifest{Module: meshprovisionerclient.VaultModule, JSON: vaultManifest})
|
||||
mem.write(t, ManifestsRead, mustKey(delivery.ManifestsKey(vaultDigest)), string(vaultValue))
|
||||
mem.write(t, ModulesRead, provisions.VaultModule, `{"v":1,"none2":"the test's","manifest":"`+vaultDigest+`"}`)
|
||||
mem.write(t, ModulesRead, meshprovisionerclient.VaultModule, `{"v":1,"none2":"the test's","manifest":"`+vaultDigest+`"}`)
|
||||
for state, keys := range mem.states {
|
||||
for key, raw := range keys {
|
||||
if err := s.Put(state, key, json.RawMessage(raw)); err != nil {
|
||||
@@ -195,19 +195,19 @@ func TestTheHolderPlansProvidesAndAsksOnTheBus(t *testing.T) {
|
||||
a := &asked{}
|
||||
h := &Holder{Store: Watching(s, ws), Asks: a, Now: time.Now, Logf: t.Logf}
|
||||
h.Compose = FromCompositions(h.Store)
|
||||
state := func(key string) provisions.Provision {
|
||||
state := func(key string) meshprovisionerclient.Provision {
|
||||
e, _ := s.Get(ProvisionsState, key)
|
||||
if e == nil {
|
||||
return provisions.Provision{}
|
||||
return meshprovisionerclient.Provision{}
|
||||
}
|
||||
p, _ := provisions.Decode(e.Value)
|
||||
p, _ := meshprovisionerclient.Decode(e.Value)
|
||||
return p
|
||||
}
|
||||
key := node + ".restic.postgres-database"
|
||||
if _, err := h.ComposeNode(ctx, node); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if p := state(key); p.State != provisions.Asked || p.Provider.Module != "postgres" {
|
||||
if p := state(key); p.State != meshprovisionerclient.Asked || p.Provider.Module != "postgres" {
|
||||
t.Fatalf("the placement and the want composed %+v", p)
|
||||
}
|
||||
if e, _ := s.Get(PlansState, node+".restic"); e == nil {
|
||||
@@ -215,7 +215,7 @@ func TestTheHolderPlansProvidesAndAsksOnTheBus(t *testing.T) {
|
||||
}
|
||||
// The providers' outcomes: the vault provides the credential where restic has one, postgres runs healthy.
|
||||
for _, dep := range state(key).DependsOn {
|
||||
if err := s.Put(boundRead(provisions.VaultModule), dep, map[string]any{"state": "provided"}); err != nil {
|
||||
if err := s.Put(boundRead(meshprovisionerclient.VaultModule), dep, map[string]any{"state": "provided"}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
@@ -248,7 +248,7 @@ func TestTheHolderPlansProvidesAndAsksOnTheBus(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
if p := state(key); p.State != provisions.Asked {
|
||||
if p := state(key); p.State != meshprovisionerclient.Asked {
|
||||
t.Fatalf("a build not offering the provision turned it %s", p.State)
|
||||
}
|
||||
offered(`["postgres-database"]`)
|
||||
@@ -257,7 +257,7 @@ func TestTheHolderPlansProvidesAndAsksOnTheBus(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
if p := state(key); p.State != provisions.Provided {
|
||||
if p := state(key); p.State != meshprovisionerclient.Provided {
|
||||
t.Fatalf("the outcomes did not turn it provided: %+v", p)
|
||||
}
|
||||
// restic leaves the node and its want goes: retiring, one ask. Its compositions stay until its engine deletes them.
|
||||
@@ -273,7 +273,7 @@ func TestTheHolderPlansProvidesAndAsksOnTheBus(t *testing.T) {
|
||||
if _, err := h.ComposeNode(ctx, node); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if r := state(key); r.State != provisions.Retiring || r.Ask == "" || len(a.ids) == 0 {
|
||||
if r := state(key); r.State != meshprovisionerclient.Retiring || r.Ask == "" || len(a.ids) == 0 {
|
||||
t.Fatalf("removing the want did not ask: %+v, asked %v", r, a.ids)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,10 +15,10 @@ import (
|
||||
|
||||
occ "git.novox.be/novox/mesh-contracts/operator-and-conversation/go/clients/operatorchannelclient"
|
||||
oc "git.novox.be/novox/mesh-contracts/operator-and-conversation/go/seats/operatorchannel"
|
||||
"git.novox.be/novox/mesh-contracts/provisioning/go/clients/meshprovisionerclient"
|
||||
stdio "git.novox.be/novox/mesh-sdk/go"
|
||||
"git.novox.be/novox/mesh-sdk/go/catalogue"
|
||||
"git.novox.be/novox/mesh-sdk/go/delivery"
|
||||
"git.novox.be/novox/mesh-sdk/go/provisions"
|
||||
)
|
||||
|
||||
// router is the operator's channel as the holder asks on it: it holds an ask open, or, like the router past its open
|
||||
@@ -114,13 +114,13 @@ var (
|
||||
split = catalogue.PlanProvision{Provision: "split-dns", Provider: "g14", ProviderModule: "systemd-resolved"}
|
||||
)
|
||||
|
||||
func (m *mesh) state(t *testing.T, key string) provisions.Provision {
|
||||
func (m *mesh) state(t *testing.T, key string) meshprovisionerclient.Provision {
|
||||
t.Helper()
|
||||
e, _ := m.s.Get(ProvisionsState, key)
|
||||
if e == nil {
|
||||
return provisions.Provision{}
|
||||
return meshprovisionerclient.Provision{}
|
||||
}
|
||||
p, err := provisions.Decode(e.Value)
|
||||
p, err := meshprovisionerclient.Decode(e.Value)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -150,11 +150,11 @@ func TestAKeysStateFollowsItsProvidersOutcome(t *testing.T) {
|
||||
state string
|
||||
why string
|
||||
}{
|
||||
{"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 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, ""},
|
||||
{"composed: asked", "", meshprovisionerclient.Asked, ""},
|
||||
{"the provider waits for a person", `{"waits":"the database's owner to accept"}`, meshprovisionerclient.Waits, "owner"},
|
||||
{"the provider refused", `{"refused":"no room on ace"}`, meshprovisionerclient.Failed, "no room"},
|
||||
{"the provider says failed in its state", `{"state":"failed","why":"the disk is full"}`, meshprovisionerclient.Failed, "disk"},
|
||||
{"the provider made it", `{"state":"provided","vault-name":"pair/gitea-postgres","generation":3}`, meshprovisionerclient.Provided, ""},
|
||||
}
|
||||
for _, s := range steps {
|
||||
if s.entry != "" {
|
||||
@@ -173,11 +173,11 @@ func TestAKeysStateFollowsItsProvidersOutcome(t *testing.T) {
|
||||
// holder alone.
|
||||
split := "g14.gitea.split-dns"
|
||||
for _, row := range []struct{ have, want, state, why string }{
|
||||
{"", "", provisions.Asked, "says nothing yet"},
|
||||
{`{"v":1,"fp":"src2:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","phase":"applying","health":"unknown"}`, "", provisions.Asked, "applying"},
|
||||
{`{"v":1,"fp":"src2:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","phase":"running","health":"ok"}`, `{"v":1,"fp":"src2:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb","self":true}`, provisions.Asked, "build its want"},
|
||||
{`{"v":1,"fp":"src2:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb","phase":"failed","health":"failed","detail":"the unit did not start"}`, "", provisions.Failed, "did not start"},
|
||||
{`{"v":1,"fp":"src2:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb","phase":"running","health":"ok"}`, `{"v":1,"fp":"src2:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb","self":true}`, provisions.Provided, ""},
|
||||
{"", "", meshprovisionerclient.Asked, "says nothing yet"},
|
||||
{`{"v":1,"fp":"src2:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","phase":"applying","health":"unknown"}`, "", meshprovisionerclient.Asked, "applying"},
|
||||
{`{"v":1,"fp":"src2:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","phase":"running","health":"ok"}`, `{"v":1,"fp":"src2:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb","self":true}`, meshprovisionerclient.Asked, "build its want"},
|
||||
{`{"v":1,"fp":"src2:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb","phase":"failed","health":"failed","detail":"the unit did not start"}`, "", meshprovisionerclient.Failed, "did not start"},
|
||||
{`{"v":1,"fp":"src2:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb","phase":"running","health":"ok"}`, `{"v":1,"fp":"src2:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb","self":true}`, meshprovisionerclient.Provided, ""},
|
||||
} {
|
||||
if row.have != "" {
|
||||
m.s.write(t, HaveRead, "g14.systemd-resolved", row.have)
|
||||
@@ -195,8 +195,8 @@ func TestAKeysStateFollowsItsProvidersOutcome(t *testing.T) {
|
||||
bfp := "src2:" + strings.Repeat("bb", 32)
|
||||
buildKey := mustKey(delivery.BuilderBuildKey("systemd-resolved", bfp))
|
||||
for _, row := range []struct{ name, provides, state, why string }{
|
||||
{"a build whose manifest does not offer it", `["other"]`, provisions.Asked, "offers split-dns"},
|
||||
{"a build whose manifest offers it", `[{"name":"split-dns"}]`, provisions.Provided, ""},
|
||||
{"a build whose manifest does not offer it", `["other"]`, meshprovisionerclient.Asked, "offers split-dns"},
|
||||
{"a build whose manifest offers it", `[{"name":"split-dns"}]`, meshprovisionerclient.Provided, ""},
|
||||
} {
|
||||
raw := `{"module":"systemd-resolved","version":"1","provides":` + row.provides + `}`
|
||||
digest := delivery.ManifestDigest([]byte(raw))
|
||||
@@ -238,7 +238,7 @@ func TestAKeysStateFollowsItsProvidersOutcome(t *testing.T) {
|
||||
c.atNewest["g14"] = c.atWant["g14"]
|
||||
c.compose(t, "g14")
|
||||
cred := c.state(t, "g14.gitea.secret-postgres-database")
|
||||
if cred.Provider.Module != "mesh-vault" || cred.Provider.Node != "novox" || cred.State != provisions.Asked {
|
||||
if cred.Provider.Module != "mesh-vault" || cred.Provider.Node != "novox" || cred.State != meshprovisionerclient.Asked {
|
||||
t.Errorf("the credential's provision is %+v", cred)
|
||||
}
|
||||
if d := c.state(t, key).DependsOn; !slices.Equal(d, []string{"g14.gitea.secret-postgres-database"}) {
|
||||
@@ -254,9 +254,9 @@ func TestAKeysStateFollowsItsProvidersOutcome(t *testing.T) {
|
||||
for _, row := range []struct {
|
||||
name, entry, cred, state string
|
||||
}{
|
||||
{"its credential still asked", "", provisions.Asked, provisions.Asked},
|
||||
{"its credential still asked", "", meshprovisionerclient.Asked, meshprovisionerclient.Asked},
|
||||
{"its credential provided by the vault", `{"state":"provided","vault-name":"pair/g14/s3-bucket/g14/gitea","generation":1}`,
|
||||
provisions.Provided, provisions.Provided},
|
||||
meshprovisionerclient.Provided, meshprovisionerclient.Provided},
|
||||
} {
|
||||
if row.entry != "" {
|
||||
c.s.write(t, "mesh-vault.bound", s3cred, row.entry)
|
||||
@@ -270,7 +270,7 @@ func TestAKeysStateFollowsItsProvidersOutcome(t *testing.T) {
|
||||
// An entry's change judges its key alone, no composition.
|
||||
before := len(m.composed)
|
||||
m.s.write(t, "postgres.bound", key, `{"refused":"the login is locked"}`)
|
||||
if said, err := m.h.Rejudge(key); err != nil || !strings.Contains(said, provisions.Failed) || len(m.composed) != before {
|
||||
if said, err := m.h.Rejudge(key); err != nil || !strings.Contains(said, meshprovisionerclient.Failed) || len(m.composed) != before {
|
||||
t.Errorf("rejudged %q, %v, composed %d more", said, err, len(m.composed)-before)
|
||||
}
|
||||
}
|
||||
@@ -293,17 +293,17 @@ func TestRetiringIsAskedAndActsOnlyOnTheWarrant(t *testing.T) {
|
||||
removed bool
|
||||
}{
|
||||
{"a key composed ahead of its want is asked, not retiring", func() {}, nil,
|
||||
map[string]string{pg: provisions.Provided, kc: provisions.Asked}, false},
|
||||
map[string]string{pg: meshprovisionerclient.Provided, kc: meshprovisionerclient.Asked}, false},
|
||||
{"one requirement removed and another added: only the removed retires", func() {
|
||||
m.atWant["g14"] = map[string]catalogue.Plan{"gitea": planOf(oidc)}
|
||||
m.atNewest["g14"] = map[string]catalogue.Plan{"gitea": planOf(oidc)}
|
||||
}, []string{pg}, map[string]string{pg: provisions.Retiring, kc: provisions.Asked}, false},
|
||||
{"composed again: no second ask", func() {}, nil, map[string]string{pg: provisions.Retiring}, false},
|
||||
}, []string{pg}, map[string]string{pg: meshprovisionerclient.Retiring, kc: meshprovisionerclient.Asked}, false},
|
||||
{"composed again: no second ask", func() {}, nil, map[string]string{pg: meshprovisionerclient.Retiring}, false},
|
||||
{"needed again before the warrant: back to its outcome", func() {
|
||||
m.atWant["g14"] = map[string]catalogue.Plan{"gitea": planOf(oidc, pgDB)}
|
||||
}, nil, map[string]string{pg: provisions.Provided}, false},
|
||||
}, nil, map[string]string{pg: meshprovisionerclient.Provided}, false},
|
||||
{"gone again: asked again", func() { m.atWant["g14"] = map[string]catalogue.Plan{"gitea": planOf(oidc)} },
|
||||
[]string{pg}, map[string]string{pg: provisions.Retiring}, false},
|
||||
[]string{pg}, map[string]string{pg: meshprovisionerclient.Retiring}, false},
|
||||
}
|
||||
for _, s := range steps {
|
||||
s.change()
|
||||
@@ -336,7 +336,7 @@ func TestRetiringIsAskedAndActsOnlyOnTheWarrant(t *testing.T) {
|
||||
if w := m.state(t, pg).Warrant; w.Option != "yes" {
|
||||
t.Fatalf("the warrant says %q, and a provider lets go only on \"yes\"", w.Option)
|
||||
}
|
||||
if said, _ := m.h.Rejudge(pg); said != "" || m.state(t, pg).State != provisions.Retiring {
|
||||
if said, _ := m.h.Rejudge(pg); said != "" || m.state(t, pg).State != meshprovisionerclient.Retiring {
|
||||
t.Errorf("retired while the provider's entry stands: %q", said)
|
||||
}
|
||||
_ = m.s.Delete("postgres.bound", pg)
|
||||
@@ -397,7 +397,7 @@ func TestOneBadModuleDoesNotDropItsNode(t *testing.T) {
|
||||
if e, _ := m.s.Get(PlansState, "g14.nats"); e == nil {
|
||||
t.Error("the held module's last plan was removed")
|
||||
}
|
||||
if p := m.state(t, "g14.nats.oidc-client"); p.State != provisions.Asked {
|
||||
if p := m.state(t, "g14.nats.oidc-client"); p.State != meshprovisionerclient.Asked {
|
||||
t.Errorf("the held module's provision is %s (%s), not kept", p.State, p.Why)
|
||||
}
|
||||
got, err := m.h.read(RefusedState, "", "g14", "")
|
||||
@@ -539,21 +539,21 @@ func TestAProvidersOutcomeIsReadPerOffer(t *testing.T) {
|
||||
}{
|
||||
{"gitea-read: the helper's refusal is not its outcome; gitea runs, so provided", "ace",
|
||||
map[string]catalogue.Plan{"claude-code": planOf(catalogue.PlanProvision{Provision: "gitea-read", Provider: "novox", ProviderModule: "gitea"})},
|
||||
"ace.claude-code.gitea-read", "gitea.bound", refused, "novox.gitea", provisions.Provided, ""},
|
||||
"ace.claude-code.gitea-read", "gitea.bound", refused, "novox.gitea", meshprovisionerclient.Provided, ""},
|
||||
{"forge-account: still the helper's entry", "ace",
|
||||
map[string]catalogue.Plan{"mesh-build-go": planOf(catalogue.PlanProvision{Provision: "forge-account", Provider: "novox", ProviderModule: "gitea"})},
|
||||
"ace.mesh-build-go.forge-account", "gitea.bound", `{"state":"provided"}`, "", provisions.Provided, ""},
|
||||
"ace.mesh-build-go.forge-account", "gitea.bound", `{"state":"provided"}`, "", meshprovisionerclient.Provided, ""},
|
||||
{"route: route-proxy's entry is read", "novox",
|
||||
map[string]catalogue.Plan{"gitea": planOf(catalogue.PlanProvision{Provision: "route", Provider: "novox", ProviderModule: "route-proxy"})},
|
||||
"novox.gitea.route", "route-proxy.bound", `{"state":"provided"}`, "", provisions.Provided, ""},
|
||||
"novox.gitea.route", "route-proxy.bound", `{"state":"provided"}`, "", meshprovisionerclient.Provided, ""},
|
||||
{"mcp-endpoint: node-tools' entry is read", "ace",
|
||||
map[string]catalogue.Plan{"claude-code": planOf(catalogue.PlanProvision{Provision: "mcp-endpoint", Provider: "ace", ProviderModule: "node-tools"})},
|
||||
"ace.claude-code.mcp-endpoint", "node-tools.bound", `{"state":"provided"}`, "", provisions.Provided, ""},
|
||||
"ace.claude-code.mcp-endpoint", "node-tools.bound", `{"state":"provided"}`, "", meshprovisionerclient.Provided, ""},
|
||||
// Issue 774, 2026-10-31: route-proxy's helper read the controller's assignments, never the seat's plans, so 38
|
||||
// routes the seat keys stood asked with no why while the assigner withheld their consumers' builds.
|
||||
{"route: no entry from a provider that reads no plans of the seat is said so", "ace",
|
||||
map[string]catalogue.Plan{"grafana": planOf(catalogue.PlanProvision{Provision: "route", Provider: "ace", ProviderModule: "route-proxy"})},
|
||||
"ace.grafana.route", "", "", "", provisions.Asked, "reads no plans of the seat"},
|
||||
"ace.grafana.route", "", "", "", meshprovisionerclient.Asked, "reads no plans of the seat"},
|
||||
} {
|
||||
m := newMesh()
|
||||
m.manifestOf("gitea", gitea)
|
||||
@@ -588,7 +588,7 @@ func TestAKeyAheadOfItsWantCarriesItsPlanEntryAndSaysWhy(t *testing.T) {
|
||||
if kc.Plan == nil || kc.Plan.Provision != "oidc-client" || kc.Plan.ProviderModule != "keycloak" || kc.Plan.As != "gitea-g14" {
|
||||
t.Errorf("the key ahead of its want carries %+v", kc.Plan)
|
||||
}
|
||||
if kc.State != provisions.Asked || !strings.Contains(kc.Why, "no plan names it") {
|
||||
if kc.State != meshprovisionerclient.Asked || !strings.Contains(kc.Why, "no plan names it") {
|
||||
t.Errorf("the key ahead of its want: %s %q", kc.State, kc.Why)
|
||||
}
|
||||
// A key a plan names carries no entry: a reader on an older mesh-sdk, which refused a field it did not know, reads it
|
||||
@@ -712,7 +712,7 @@ func TestARetirementIsJudgedOnlyFromAWholePicture(t *testing.T) {
|
||||
}
|
||||
retiring := 0
|
||||
for i := range row.consumer {
|
||||
if m.state(t, "novox."+apps[i]+".route.1").State == provisions.Retiring {
|
||||
if m.state(t, "novox."+apps[i]+".route.1").State == meshprovisionerclient.Retiring {
|
||||
retiring++
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,9 +10,9 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"git.novox.be/novox/mesh-contracts/provisioning/go/clients/meshprovisionerclient"
|
||||
stdio "git.novox.be/novox/mesh-sdk/go"
|
||||
"git.novox.be/novox/mesh-sdk/go/health"
|
||||
"git.novox.be/novox/mesh-sdk/go/provisions"
|
||||
)
|
||||
|
||||
// The holder's tools.
|
||||
@@ -133,7 +133,7 @@ func (h *Holder) read(state, key, node, want string) (any, error) {
|
||||
}
|
||||
row := map[string]any{"key": k}
|
||||
if state == ProvisionsState {
|
||||
p, err := provisions.Decode(e.Value)
|
||||
p, err := meshprovisionerclient.Decode(e.Value)
|
||||
if err != nil {
|
||||
row["unreadable"] = err.Error()
|
||||
} else {
|
||||
|
||||
@@ -3,6 +3,7 @@ module mesh-provisioner
|
||||
go 1.26.0
|
||||
|
||||
require (
|
||||
git.novox.be/novox/mesh-contracts/provisioning/go/clients/meshprovisionerclient v0.0.0-00010101000000-000000000000
|
||||
git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshconditionsclient v0.0.0-00010101000000-000000000000
|
||||
git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshhandactsclient v0.0.0-00010101000000-000000000000
|
||||
git.novox.be/novox/mesh-contracts/operator-and-conversation/go/clients/operatorchannelclient v0.0.0-00010101000000-000000000000
|
||||
|
||||
Reference in New Issue
Block a user