diff --git a/daemon/internal/nri/nri.go b/daemon/internal/nri/nri.go index 48d26c28fb..25c2197cd7 100644 --- a/daemon/internal/nri/nri.go +++ b/daemon/internal/nri/nri.go @@ -135,6 +135,9 @@ func (n *NRI) CreateContainer(ctx context.Context, ctr *container.Container) err if resp.GetUpdate() != nil { return errors.New("container update is not supported") } + if resp.GetEvict() != nil { + return errors.New("container eviction is not supported") + } if err := applyAdjustments(ctx, ctr, resp.GetAdjust()); err != nil { return err } @@ -298,6 +301,9 @@ func applyAdjustments(ctx context.Context, ctr *container.Container, adj *adapta if adj == nil { return nil } + if err := checkForUnsupportedAdjustments(adj); err != nil { + return err + } if err := applyEnvVars(ctx, ctr, adj.Env); err != nil { return fmt.Errorf("applying environment variable adjustments: %w", err) } @@ -307,6 +313,67 @@ func applyAdjustments(ctx context.Context, ctr *container.Container, adj *adapta return nil } +func checkForUnsupportedAdjustments(adj *adaptation.ContainerAdjustment) error { + var unsupported []string + if len(adj.Annotations) > 0 { + unsupported = append(unsupported, "annotations") + } + if adj.Hooks != nil { + if len(adj.Hooks.Prestart) > 0 || + len(adj.Hooks.CreateRuntime) > 0 || + len(adj.Hooks.CreateContainer) > 0 || + len(adj.Hooks.StartContainer) > 0 || + len(adj.Hooks.Poststart) > 0 || + len(adj.Hooks.Poststop) > 0 { + unsupported = append(unsupported, "hooks") + } + } + if adj.Linux != nil { + if len(adj.Linux.Devices) > 0 || + adj.Linux.CgroupsPath != "" || + adj.Linux.OomScoreAdj != nil || + adj.Linux.IoPriority != nil || + adj.Linux.SeccompPolicy != nil || + len(adj.Linux.Namespaces) > 0 { + unsupported = append(unsupported, "linux") + } + if resMem := adj.Linux.GetResources().GetMemory(); resMem != nil && + (resMem.GetLimit() != nil || + resMem.GetReservation() != nil || + resMem.GetSwap() != nil || + resMem.GetKernel() != nil || + resMem.GetKernelTcp() != nil || + resMem.GetSwappiness() != nil || + resMem.GetDisableOomKiller() != nil || + resMem.GetUseHierarchy() != nil) { + unsupported = append(unsupported, "linux.resources.memory") + } + if resCPU := adj.Linux.GetResources().GetCpu(); resCPU != nil && + (resCPU.GetShares() != nil || + resCPU.GetQuota() != nil || + resCPU.GetPeriod() != nil || + resCPU.GetRealtimeRuntime() != nil || + resCPU.GetRealtimePeriod() != nil || + resCPU.GetCpus() != "" || + resCPU.GetMems() != "") { + unsupported = append(unsupported, "linux.resources.cpu") + } + } + if len(adj.Rlimits) > 0 { + unsupported = append(unsupported, "rlimits") + } + if len(adj.CDIDevices) > 0 { + unsupported = append(unsupported, "CDI") + } + if len(adj.Args) > 0 { + unsupported = append(unsupported, "args") + } + if len(unsupported) > 0 { + return fmt.Errorf("unsupported container adjustments: %s", strings.Join(unsupported, ",")) + } + return nil +} + func applyEnvVars(ctx context.Context, ctr *container.Container, envVars []*adaptation.KeyValue) error { if len(envVars) == 0 { return nil diff --git a/integration/daemon/nri/nri_test.go b/integration/daemon/nri/nri_test.go index 254c71805f..8e39089d5b 100644 --- a/integration/daemon/nri/nri_test.go +++ b/integration/daemon/nri/nri_test.go @@ -71,6 +71,66 @@ func TestNRIContainerCreateEnvVarMod(t *testing.T) { } } +func TestNRIContainerCreateUnsupportedAdj(t *testing.T) { + skip.If(t, testEnv.IsRemoteDaemon, "cannot run daemon when remote daemon") + skip.If(t, testEnv.DaemonInfo.OSType == "windows", "cannot start a separate daemon with NRI enabled on Windows") + skip.If(t, testEnv.IsRootless) + + ctx := testutil.StartSpan(baseContext, t) + + sockPath := filepath.Join(t.TempDir(), "nri.sock") + + d := daemon.New(t) + d.StartWithBusybox(ctx, t, + "--nri-opts=enable=true,socket-path="+sockPath, + "--iptables=false", "--ip6tables=false", + ) + defer d.Stop(t) + c := d.NewClientT(t) + + tests := []struct { + name string + ctrCreateAdj *api.ContainerAdjustment + expErr string + }{ + { + name: "hooks", + ctrCreateAdj: &api.ContainerAdjustment{Hooks: &api.Hooks{CreateRuntime: []*api.Hook{{Path: "/bin/true"}}}}, + expErr: "unsupported container adjustments: hooks", + }, + { + name: "cdi", + ctrCreateAdj: &api.ContainerAdjustment{CDIDevices: []*api.CDIDevice{{Name: "/dev/somedevice"}}}, + expErr: "unsupported container adjustments: CDI", + }, + { + name: "cpu", + ctrCreateAdj: &api.ContainerAdjustment{Linux: &api.LinuxContainerAdjustment{Resources: &api.LinuxResources{ + Cpu: &api.LinuxCPU{Shares: &api.OptionalUInt64{Value: 123}}, + }}}, + expErr: "unsupported container adjustments: linux.resources.cpu", + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + stopPlugin := startBuiltinPlugin(ctx, t, builtinPluginConfig{ + pluginName: "nri-test-plugin", + pluginIdx: "00", + sockPath: sockPath, + ctrCreateAdj: tc.ctrCreateAdj, + }) + defer stopPlugin() + + res, err := c.ContainerCreate(ctx, client.ContainerCreateOptions{Image: "busybox:latest"}) + if err != nil { + _, _ = c.ContainerRemove(ctx, res.ID, client.ContainerRemoveOptions{Force: true}) + } + assert.Check(t, is.ErrorContains(err, tc.expErr)) + }) + } +} + func TestNRIContainerCreateAddMount(t *testing.T) { skip.If(t, testEnv.IsRemoteDaemon, "cannot run daemon when remote daemon") skip.If(t, testEnv.DaemonInfo.OSType == "windows", "cannot start a separate daemon with NRI enabled on Windows")