Keep the builds every want names and each composition's provisioner plans; find the replaced controller in the build records (issue 1945)
With no plan left to name a build or a send to keep the plans, a want names what a collection must keep, and the composition is where the provisioner's plans are composed for the assignments mirror (ADR 0539 clauses 1 and 5); the assignments no longer name a node's build, so the controller replaced is the newest earlier build of it.
This commit is contained in:
@@ -2,6 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sort"
|
||||
@@ -79,6 +80,10 @@ func composeModules(ctx context.Context, open *stores, nodes []string) (map[stri
|
||||
errs = append(errs, fmt.Errorf("%s: %w", node, err))
|
||||
continue
|
||||
}
|
||||
// The provisioner's plans of the modules the node's composition hands to it, for the assignments mirror.
|
||||
if err := open.inventory.RecordComposedPlans(ctx, node, plansKept(declared)); err != nil {
|
||||
errs = append(errs, fmt.Errorf("%s: its provisioner's plans: %w", node, err))
|
||||
}
|
||||
comps, moved, err := compositionsOf(node, body, fps, manifests)
|
||||
if err != nil {
|
||||
errs = append(errs, fmt.Errorf("%s: %w", node, err))
|
||||
@@ -196,3 +201,68 @@ func haveOn(ctx context.Context, js jetstream.JetStream, node, module string) (s
|
||||
}
|
||||
return h, true, nil
|
||||
}
|
||||
|
||||
// wantedOnTheBus is every fingerprint a want names, as `<module> <fingerprint>`: what the keep set keeps the builds of
|
||||
// (ADR 0539 clause 1). Read from the assigner's bucket on each look; no bucket yet names none.
|
||||
func wantedOnTheBus(ctx context.Context) (map[string]bool, error) {
|
||||
bus, err := aBus()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer bus.Close()
|
||||
js, err := jetstream.New(bus.Conn())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
kv, err := js.KeyValue(ctx, sdkdelivery.AssignerWantsBucket)
|
||||
if errors.Is(err, jetstream.ErrBucketNotFound) {
|
||||
return map[string]bool{}, nil
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
lister, err := kv.ListKeys(ctx)
|
||||
if errors.Is(err, jetstream.ErrNoKeysFound) {
|
||||
return map[string]bool{}, nil
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out := map[string]bool{}
|
||||
for key := range lister.Keys() {
|
||||
_, module, err := sdkdelivery.ParseWantKey(key)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
e, err := kv.Get(ctx, key)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
w, err := sdkdelivery.DecodeWant(e.Value())
|
||||
if err != nil || w.FP == "" {
|
||||
continue
|
||||
}
|
||||
out[module+" "+w.FP] = true
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// plansKept is a composition's provisioner's plans as the store keeps them: by module, each plan and what requires a
|
||||
// module only pulled in by another (design 57 P6, issue 765); nil when it hands none.
|
||||
func plansKept(d sendable) []byte {
|
||||
if len(d.plans) == 0 {
|
||||
return nil
|
||||
}
|
||||
kept := map[string]composedPlan{}
|
||||
for module, p := range d.plans {
|
||||
kept[module] = composedPlan{Plan: p, RequiredBy: d.requiredBy[module]}
|
||||
}
|
||||
raw, _ := json.Marshal(kept) // plain strings and slices: it marshals
|
||||
return raw
|
||||
}
|
||||
|
||||
// composedPlan is one handed module's plan as the store keeps it, the shape inventory.SentProvisioningPlans reads.
|
||||
type composedPlan struct {
|
||||
catalogue.Plan
|
||||
RequiredBy string `json:"required-by,omitempty"`
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user