Compose a module that has no resource of its own as an empty composition (issue 1945)
Its want names a composition (ADR 0539 clauses 1 and 6), so a module whose needs others meet must still have one at its fingerprint, or no want could ever be written for it. Found by the served test.
This commit is contained in:
@@ -99,7 +99,7 @@ func TestAChangedUserListIsANewRevisionOfTheBusModulesCompositionAlone(t *testin
|
||||
d["resources"] = append(d["resources"].([]any), map[string]any{"id": "nats.bus-users", "type": "file",
|
||||
"module": "nats", "path": "/var/lib/mesh/nats/users.conf", "content": users, "mode": "0600"})
|
||||
raw, _ := json.Marshal(d)
|
||||
comps, _, err := compositionsOf("g14", raw, fps, nil)
|
||||
comps, _, err := compositionsOf("g14", raw, fps, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ func composeModules(ctx context.Context, open *stores, nodes []string) (map[stri
|
||||
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)
|
||||
comps, moved, err := compositionsOf(node, body, fps, manifests, declared.modules)
|
||||
if err != nil {
|
||||
errs = append(errs, fmt.Errorf("%s: %w", node, err))
|
||||
continue
|
||||
|
||||
@@ -64,7 +64,7 @@ type composedPlace struct {
|
||||
// fingerprint fps gives it, the node's own with its adoption and provisioner, and every resource of a module fps names
|
||||
// no fingerprint for in the node's own, its module taken off it and named in moved. Data says the module's manifest
|
||||
// declares data.
|
||||
func compositionsOf(node string, body []byte, fps map[string]string, manifests map[string]catalogue.Manifest) (
|
||||
func compositionsOf(node string, body []byte, fps map[string]string, manifests map[string]catalogue.Manifest, runs []string) (
|
||||
out map[string]sdkdelivery.Composed, moved []string, err error) {
|
||||
|
||||
var envelope struct {
|
||||
@@ -110,6 +110,22 @@ func compositionsOf(node string, body []byte, fps map[string]string, manifests m
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
// A module the node runs that composes no resource of its own (all its needs met by others) still has its
|
||||
// composition, empty, at its fingerprint: its want names that composition (the assigner's seventh rule), and without
|
||||
// one no want could ever be written.
|
||||
for _, module := range runs {
|
||||
fp := fps[module]
|
||||
if !strings.HasPrefix(fp, sdkdelivery.SourcePrefix2) {
|
||||
continue
|
||||
}
|
||||
key, err := sdkdelivery.ComposedKey(node, module, fp)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if _, ok := out[key]; !ok {
|
||||
out[key] = sdkdelivery.Composed{Node: node, Module: module, FP: fp, Resources: []json.RawMessage{}}
|
||||
}
|
||||
}
|
||||
for key, c := range out {
|
||||
if m, ok := manifests[c.Module]; ok && c.Module != "" {
|
||||
c.Data = len(m.DataItems()) > 0
|
||||
|
||||
@@ -218,7 +218,7 @@ func TestTheCompositionsOfANodeAreItsDeclaration(t *testing.T) {
|
||||
Resources []json.RawMessage `json:"resources"`
|
||||
}
|
||||
_ = json.Unmarshal(body, &d)
|
||||
comps, moved, err := compositionsOf(node, body, fps, nil)
|
||||
comps, moved, err := compositionsOf(node, body, fps, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("%s: %v", node, err)
|
||||
}
|
||||
@@ -253,7 +253,7 @@ func TestTheCompositionsOfANodeAreItsDeclaration(t *testing.T) {
|
||||
// unchanged it writes nothing; a changed input writes a new revision of that key alone, by compare-and-set.
|
||||
func TestACompositionIsWrittenOnceAndAgainOnlyWhenItChanges(t *testing.T) {
|
||||
body, fps := capturedBody(t, "g14")
|
||||
comps, _, err := compositionsOf("g14", body, fps, nil)
|
||||
comps, _, err := compositionsOf("g14", body, fps, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -335,3 +335,28 @@ func TestCompositionsOutsideTheFiveNewestAreDeleted(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 1945 (found by the served test): a module the node runs that composes no resource of its own still has its
|
||||
// composition, empty, at its fingerprint, so a want can name it; a module the node runs with no fingerprint of the new
|
||||
// form gets none.
|
||||
func TestAModuleWithNoResourceOfItsOwnStillHasItsComposition(t *testing.T) {
|
||||
body := []byte(`{"declaration":1,"resources":[]}`)
|
||||
fp := sdkdelivery.SourcePrefix2 + strings.Repeat("b", 64)
|
||||
comps, _, err := compositionsOf("laptop", body, map[string]string{"board": fp}, nil, []string{"board", "legacy"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
key, _ := sdkdelivery.ComposedKey("laptop", "board", fp)
|
||||
c, ok := comps[key]
|
||||
if !ok || len(c.Resources) != 0 {
|
||||
t.Fatalf("the board's composition: %+v (%v)", c, ok)
|
||||
}
|
||||
if _, err := sdkdelivery.EncodeComposed(c); err != nil {
|
||||
t.Errorf("an empty composition does not encode: %v", err)
|
||||
}
|
||||
for k := range comps {
|
||||
if strings.Contains(k, "legacy") {
|
||||
t.Errorf("a module with no fingerprint of the new form was composed: %s", k)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user