S2 sdk-config-forms: the forms config-lines and config-json are reader capabilities
referenceForms gains config-lines and config-json; textNeeds also finds the exact token ${config-json}, which holds no colon.
Builds: design 42 zfs-owns-zfs §4, §3, §9; answers A-13, A-15, A-24, A-25
This commit is contained in:
@@ -35,12 +35,16 @@ const (
|
||||
// referenceForms are the reference forms a manifest's values may hold, `${<name>:…}`, as this contract fills them. A new
|
||||
// reference form is added here in the change that teaches the contract to read it, so a node-engine built with it
|
||||
// states it (ADR 0612 §2's new reference form is one).
|
||||
var referenceForms = []string{"access", "backup", "bound", "collected", "config", "consumer", "consumers",
|
||||
"contribution", "dir", "machine", "port", "seat", "secret", "setting"}
|
||||
var referenceForms = []string{"access", "backup", "bound", "collected", "config", "config-json", "config-lines",
|
||||
"consumer", "consumers", "contribution", "dir", "machine", "port", "seat", "secret", "setting"}
|
||||
|
||||
// ifConfigWord is the reader capability for a resource's `if-config` (IfConfigField).
|
||||
const ifConfigWord = ReadWord + "resources." + IfConfigField
|
||||
|
||||
// configJSONToken is the reference form `${config-json}` whole: it holds no colon, so textNeeds's search for `${<form>:`
|
||||
// does not find it (design 42 zfs-owns-zfs, answer A-25).
|
||||
const configJSONToken = "${config-json}"
|
||||
|
||||
// ReferenceFormSeat names the reference form a registry seat answers for a build's artifact,
|
||||
// `<seat>/<module>/<artifact>@sha256:<digest>` (novox/hq ADR 0605 §9; the registry clients' reference forms), as the reader capability
|
||||
// `form:seat-reference` a node-engine built with this contract states (ADR 0618 §1, ADR 0624 §1): the builder writes it
|
||||
@@ -448,6 +452,9 @@ func textNeeds(text []byte, used map[string]bool) {
|
||||
used[ReadForm+f] = true
|
||||
}
|
||||
}
|
||||
if bytes.Contains(text, []byte(configJSONToken)) {
|
||||
used[ReadForm+"config-json"] = true
|
||||
}
|
||||
if ofSeatReach.Match(text) {
|
||||
used[ReadForm+ReferenceFormSeatReach] = true
|
||||
}
|
||||
|
||||
@@ -101,10 +101,20 @@ func TestOwnManifestUsesNoWordTheRunningControllerRefuses(t *testing.T) {
|
||||
`"if-config":["k"]}]}`, []string{"word:resources.if-config"}, []string{"word:resources.if-config"}},
|
||||
{"a resource without if-config", `{"module":"z","version":"1","resources":[{"id":"f","type":"file"}]}`,
|
||||
[]string{"word:resources"}, nil},
|
||||
// The template forms of the config file and the option lines (design 42 zfs-owns-zfs §3, §9; A-13, A-15, A-25).
|
||||
{"a template writing config lines", `{"module":"z","version":"1","resources":[{"id":"f","type":"file","template":"files/o.conf"}]}`,
|
||||
[]string{"form:config-lines"}, []string{"form:config-lines"}},
|
||||
{"a template writing the config as json", `{"module":"z","version":"1","resources":[{"id":"f","type":"file","template":"files/c.json"}]}`,
|
||||
[]string{"form:config-json"}, []string{"form:config-json"}},
|
||||
{"a template of the config form alone", `{"module":"z","version":"1","resources":[{"id":"f","type":"file","template":"files/k"}]}`,
|
||||
[]string{"form:config"}, nil},
|
||||
{"a word this contract does not know", `{"module":"u","version":"1","newer-word":{"inside":1}}`, []string{"word:module"}, nil},
|
||||
} {
|
||||
templates := map[string]map[string]string{ // the templates' text a row's module names
|
||||
"a template naming a seat's reach": {"files/daemon.json": `{"x":"${seat:container-image-registry:reach}"}`},
|
||||
"a template naming a seat's reach": {"files/daemon.json": `{"x":"${seat:container-image-registry:reach}"}`},
|
||||
"a template writing config lines": {"files/o.conf": "${config-lines:arc-max:options zfs zfs_arc_max=:mib-bytes}"},
|
||||
"a template writing the config as json": {"files/c.json": "${config-json}"},
|
||||
"a template of the config form alone": {"files/k": "${config:k}"},
|
||||
}[row.why]
|
||||
needs, err := ModuleNeeds([]byte(row.raw), templates)
|
||||
if err != nil {
|
||||
@@ -124,6 +134,12 @@ func TestOwnManifestUsesNoWordTheRunningControllerRefuses(t *testing.T) {
|
||||
if slices.ContainsFunc(needs, func(n string) bool { return n == "word:newer-word" || n == "form:count" }) {
|
||||
t.Errorf("%s: needs %v, naming what the contract does not read", row.why, needs)
|
||||
}
|
||||
for _, f := range []string{"form:config-lines", "form:config-json"} {
|
||||
if slices.Contains(needs, f) != (row.why == map[string]string{"form:config-lines": "a template writing config lines",
|
||||
"form:config-json": "a template writing the config as json"}[f]) {
|
||||
t.Errorf("%s: needs %v, %s read wrongly", row.why, needs, f)
|
||||
}
|
||||
}
|
||||
if slices.Contains(needs, "word:resources.if-config") != (row.why == "a resource under if-config") {
|
||||
t.Errorf("%s: needs %v, if-config read wrongly", row.why, needs)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user