A module whose container names groups needs the container-groups capability, so it is held, naming it, on an engine that does not read them (issue 1638, ADR 0480 clause 7)
mesh/merge-gate head e0e1a91496de merged into trunk 863a981e014e — fail: builds mesh-sdk (+41 dependent(s)) → ace, g14, novox, shanks; no bus step; 9 wait(…
mesh/repo-check head e0e1a91496de merged into trunk 863a981e014e — fail: head e0e1a91496de does not merge cleanly into trunk 863a981e014e: in conflict go/c…
mesh/delivery superseded: a newer head of the same pull request
mesh/merge-gate head e0e1a91496de merged into trunk 863a981e014e — fail: builds mesh-sdk (+41 dependent(s)) → ace, g14, novox, shanks; no bus step; 9 wait(…
mesh/repo-check head e0e1a91496de merged into trunk 863a981e014e — fail: head e0e1a91496de does not merge cleanly into trunk 863a981e014e: in conflict go/c…
mesh/delivery superseded: a newer head of the same pull request
This commit is contained in:
@@ -116,3 +116,34 @@ func TestAComposedMachineGetsTheGroupTheConfigValueNames(t *testing.T) {
|
|||||||
t.Fatalf("refused without the key: %v", err)
|
t.Fatalf("refused without the key: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The node-engine reads a container's groups only when it reports the capability (novox/hq ADR 0480 clause 7, issue 1638):
|
||||||
|
// a module with a container that names groups is hosted on a machine that reports container-groups, and left out of one
|
||||||
|
// that does not, the capability named, so the field is never sent to an engine that would refuse it.
|
||||||
|
func TestAModuleWhoseContainerNamesGroupsIsHeldOnAMachineThatDoesNotReadThem(t *testing.T) {
|
||||||
|
n8n := Manifest{Module: "n8n", Resources: []map[string]any{aContainerWithGroups("${config:media-gid}")}}
|
||||||
|
plain := Manifest{Module: "plain", Resources: []map[string]any{
|
||||||
|
{"id": "server", "type": "container", "name": "p", "image": "x@sha256:" + strings.Repeat("b", 64)}}}
|
||||||
|
for _, m := range []Manifest{n8n, plain} {
|
||||||
|
if got := impliedCapabilities(m); (m.Module == "n8n") != reflect.DeepEqual(got, []string{ContainerGroups}) {
|
||||||
|
t.Errorf("%s implies %v", m.Module, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
shelf := shelf(n8n, plain)
|
||||||
|
reads := Node{Name: "ace", Capabilities: map[string]bool{"container-runtime": true, ContainerGroups: true}}
|
||||||
|
got, err := Resolve(shelf, []string{"n8n", "plain"}, reads, World{})
|
||||||
|
if err != nil || len(got.Unhostable) != 0 || len(got.Modules) != 2 {
|
||||||
|
t.Fatalf("a machine that reads groups: %v, held %+v, hosted %v", err, got.Unhostable, names(got))
|
||||||
|
}
|
||||||
|
old := Node{Name: "g14", Capabilities: map[string]bool{"container-runtime": true}}
|
||||||
|
got, err = Resolve(shelf, []string{"n8n", "plain"}, old, World{})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(got.Unhostable) != 1 || got.Unhostable[0].Module != "n8n" || !reflect.DeepEqual(got.Unhostable[0].Missing, []string{ContainerGroups}) {
|
||||||
|
t.Fatalf("n8n was not held, naming the capability: %+v", got.Unhostable)
|
||||||
|
}
|
||||||
|
if h := names(got); len(h) != 1 || h[0] != "plain" {
|
||||||
|
t.Errorf("the module without groups is not the one hosted: %v", h)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+18
-1
@@ -904,7 +904,7 @@ func isModule(catalogue map[string]Manifest, want string) bool {
|
|||||||
// machine can host the module as far as its capabilities go.
|
// machine can host the module as far as its capabilities go.
|
||||||
func missingCapabilities(m Manifest, node Node) []string {
|
func missingCapabilities(m Manifest, node Node) []string {
|
||||||
var missing []string
|
var missing []string
|
||||||
for _, c := range m.Capabilities {
|
for _, c := range append(append([]string(nil), m.Capabilities...), impliedCapabilities(m)...) {
|
||||||
if !node.Capabilities[c] {
|
if !node.Capabilities[c] {
|
||||||
missing = append(missing, c)
|
missing = append(missing, c)
|
||||||
}
|
}
|
||||||
@@ -1457,3 +1457,20 @@ func packageNames(m map[string][]string) []string {
|
|||||||
sort.Strings(names)
|
sort.Strings(names)
|
||||||
return names
|
return names
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ContainerGroups is the capability a node-engine reports when it reads a container's `groups` and passes each as a
|
||||||
|
// supplementary group (novox/hq ADR 0480 clause 7, issue 1638). An older engine refuses the key (strict decoding).
|
||||||
|
const ContainerGroups = "container-groups"
|
||||||
|
|
||||||
|
// impliedCapabilities are the capabilities a module needs for what its resources say, beyond those it declares: a
|
||||||
|
// container that names groups needs an engine that reads them, so the module is left out of a machine whose report
|
||||||
|
// lacks the capability, naming it, and the field is sent to no engine that would refuse it. None for a module whose
|
||||||
|
// containers name no groups.
|
||||||
|
func impliedCapabilities(m Manifest) []string {
|
||||||
|
for _, r := range m.Resources {
|
||||||
|
if fmt.Sprint(r["type"]) == "container" && len(groupsOf(r)) > 0 {
|
||||||
|
return []string{ContainerGroups}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ var capabilityName = regexp.MustCompile(`^[a-z0-9][a-z0-9-]*$`)
|
|||||||
// names an `if-capability` may give (novox/hq ADR 0255). A name nothing detects would leave its
|
// names an `if-capability` may give (novox/hq ADR 0255). A name nothing detects would leave its
|
||||||
// contribution out on every machine, silently, so it is refused. A detector added there is added here.
|
// contribution out on every machine, silently, so it is refused. A detector added there is added here.
|
||||||
var KnownCapabilities = []string{
|
var KnownCapabilities = []string{
|
||||||
"battery", "container-runtime", "firewall", "graphical-session", "overlay", "package-manager",
|
"battery", "container-groups", "container-runtime", "firewall", "graphical-session", "overlay", "package-manager",
|
||||||
"power-meter", "privileged", "seat", "service-manager", "uplink-dhcpcd", "uplink-networkmanager",
|
"power-meter", "privileged", "seat", "service-manager", "uplink-dhcpcd", "uplink-networkmanager",
|
||||||
"uplink-systemd-networkd", "user-namespaces", "virtualisation",
|
"uplink-systemd-networkd", "user-namespaces", "virtualisation",
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user