diff --git a/internal/cri/server/container_create.go b/internal/cri/server/container_create.go index 254d2079b..1a187b99c 100644 --- a/internal/cri/server/container_create.go +++ b/internal/cri/server/container_create.go @@ -795,12 +795,12 @@ func (c *criService) buildLinuxSpec( specOpts = append(specOpts, oci.WithRdt(rdtClass, "", "")) } - for pKey, pValue := range getPassthroughAnnotations(sandboxConfig.Annotations, + for pKey, pValue := range util.GetPassthroughAnnotations(sandboxConfig.Annotations, ociRuntime.PodAnnotations) { specOpts = append(specOpts, customopts.WithAnnotation(pKey, pValue)) } - for pKey, pValue := range getPassthroughAnnotations(config.Annotations, + for pKey, pValue := range util.GetPassthroughAnnotations(config.Annotations, ociRuntime.ContainerAnnotations) { specOpts = append(specOpts, customopts.WithAnnotation(pKey, pValue)) } @@ -930,12 +930,12 @@ func (c *criService) buildWindowsSpec( // when trying to run the init process. specOpts = append(specOpts, oci.WithUser(username)) - for pKey, pValue := range getPassthroughAnnotations(sandboxConfig.Annotations, + for pKey, pValue := range util.GetPassthroughAnnotations(sandboxConfig.Annotations, ociRuntime.PodAnnotations) { specOpts = append(specOpts, customopts.WithAnnotation(pKey, pValue)) } - for pKey, pValue := range getPassthroughAnnotations(config.Annotations, + for pKey, pValue := range util.GetPassthroughAnnotations(config.Annotations, ociRuntime.ContainerAnnotations) { specOpts = append(specOpts, customopts.WithAnnotation(pKey, pValue)) } @@ -982,12 +982,12 @@ func (c *criService) buildDarwinSpec( specOpts = append(specOpts, customopts.WithDarwinMounts(c.os, config, extraMounts)) - for pKey, pValue := range getPassthroughAnnotations(sandboxConfig.Annotations, + for pKey, pValue := range util.GetPassthroughAnnotations(sandboxConfig.Annotations, ociRuntime.PodAnnotations) { specOpts = append(specOpts, customopts.WithAnnotation(pKey, pValue)) } - for pKey, pValue := range getPassthroughAnnotations(config.Annotations, + for pKey, pValue := range util.GetPassthroughAnnotations(config.Annotations, ociRuntime.ContainerAnnotations) { specOpts = append(specOpts, customopts.WithAnnotation(pKey, pValue)) } diff --git a/internal/cri/server/helpers.go b/internal/cri/server/helpers.go index d94360b7c..c53d6c9c8 100644 --- a/internal/cri/server/helpers.go +++ b/internal/cri/server/helpers.go @@ -273,25 +273,6 @@ func unknownContainerStatus() containerstore.Status { } } -// getPassthroughAnnotations filters requested pod annotations by comparing -// against permitted annotations for the given runtime. -func getPassthroughAnnotations(podAnnotations map[string]string, - runtimePodAnnotations []string) (passthroughAnnotations map[string]string) { - passthroughAnnotations = make(map[string]string) - - for podAnnotationKey, podAnnotationValue := range podAnnotations { - for _, pattern := range runtimePodAnnotations { - // Use path.Match instead of filepath.Match here. - // filepath.Match treated `\\` as path separator - // on windows, which is not what we want. - if ok, _ := path.Match(pattern, podAnnotationKey); ok { - passthroughAnnotations[podAnnotationKey] = podAnnotationValue - } - } - } - return passthroughAnnotations -} - // copyResourcesToStatus copys container resource contraints from spec to // container status. // This will need updates when new fields are added to ContainerResources. diff --git a/internal/cri/server/helpers_test.go b/internal/cri/server/helpers_test.go index 6d70d6794..53865decd 100644 --- a/internal/cri/server/helpers_test.go +++ b/internal/cri/server/helpers_test.go @@ -262,121 +262,6 @@ func TestEnvDeduplication(t *testing.T) { } } -func TestPassThroughAnnotationsFilter(t *testing.T) { - for _, test := range []struct { - desc string - podAnnotations map[string]string - runtimePodAnnotations []string - passthroughAnnotations map[string]string - }{ - { - desc: "should support direct match", - podAnnotations: map[string]string{"c": "d", "d": "e"}, - runtimePodAnnotations: []string{"c"}, - passthroughAnnotations: map[string]string{"c": "d"}, - }, - { - desc: "should support wildcard match", - podAnnotations: map[string]string{ - "t.f": "j", - "z.g": "o", - "z": "o", - "y.ca": "b", - "y": "b", - }, - runtimePodAnnotations: []string{"*.f", "z*g", "y.c*"}, - passthroughAnnotations: map[string]string{ - "t.f": "j", - "z.g": "o", - "y.ca": "b", - }, - }, - { - desc: "should support wildcard match all", - podAnnotations: map[string]string{ - "t.f": "j", - "z.g": "o", - "z": "o", - "y.ca": "b", - "y": "b", - }, - runtimePodAnnotations: []string{"*"}, - passthroughAnnotations: map[string]string{ - "t.f": "j", - "z.g": "o", - "z": "o", - "y.ca": "b", - "y": "b", - }, - }, - { - desc: "should support match including path separator", - podAnnotations: map[string]string{ - "matchend.com/end": "1", - "matchend.com/end1": "2", - "matchend.com/1end": "3", - "matchmid.com/mid": "4", - "matchmid.com/mi1d": "5", - "matchmid.com/mid1": "6", - "matchhead.com/head": "7", - "matchhead.com/1head": "8", - "matchhead.com/head1": "9", - "matchall.com/abc": "10", - "matchall.com/def": "11", - "end/matchend": "12", - "end1/matchend": "13", - "1end/matchend": "14", - "mid/matchmid": "15", - "mi1d/matchmid": "16", - "mid1/matchmid": "17", - "head/matchhead": "18", - "1head/matchhead": "19", - "head1/matchhead": "20", - "abc/matchall": "21", - "def/matchall": "22", - "match1/match2": "23", - "nomatch/nomatch": "24", - }, - runtimePodAnnotations: []string{ - "matchend.com/end*", - "matchmid.com/mi*d", - "matchhead.com/*head", - "matchall.com/*", - "end*/matchend", - "mi*d/matchmid", - "*head/matchhead", - "*/matchall", - "match*/match*", - }, - passthroughAnnotations: map[string]string{ - "matchend.com/end": "1", - "matchend.com/end1": "2", - "matchmid.com/mid": "4", - "matchmid.com/mi1d": "5", - "matchhead.com/head": "7", - "matchhead.com/1head": "8", - "matchall.com/abc": "10", - "matchall.com/def": "11", - "end/matchend": "12", - "end1/matchend": "13", - "mid/matchmid": "15", - "mi1d/matchmid": "16", - "head/matchhead": "18", - "1head/matchhead": "19", - "abc/matchall": "21", - "def/matchall": "22", - "match1/match2": "23", - }, - }, - } { - test := test - t.Run(test.desc, func(t *testing.T) { - passthroughAnnotations := getPassthroughAnnotations(test.podAnnotations, test.runtimePodAnnotations) - assert.Equal(t, test.passthroughAnnotations, passthroughAnnotations) - }) - } -} - func TestEnsureRemoveAllNotExist(t *testing.T) { // should never return an error for a non-existent path if err := ensureRemoveAll(context.Background(), "/non/existent/path"); err != nil { diff --git a/internal/cri/server/podsandbox/helpers.go b/internal/cri/server/podsandbox/helpers.go index 071be4782..0a17b1aff 100644 --- a/internal/cri/server/podsandbox/helpers.go +++ b/internal/cri/server/podsandbox/helpers.go @@ -19,7 +19,6 @@ package podsandbox import ( "context" "fmt" - "path" "path/filepath" "github.com/containerd/log" @@ -93,25 +92,6 @@ func buildLabels(configLabels, imageConfigLabels map[string]string, containerTyp return labels } -// getPassthroughAnnotations filters requested pod annotations by comparing -// against permitted annotations for the given runtime. -func getPassthroughAnnotations(podAnnotations map[string]string, - runtimePodAnnotations []string) (passthroughAnnotations map[string]string) { - passthroughAnnotations = make(map[string]string) - - for podAnnotationKey, podAnnotationValue := range podAnnotations { - for _, pattern := range runtimePodAnnotations { - // Use path.Match instead of filepath.Match here. - // filepath.Match treated `\\` as path separator - // on windows, which is not what we want. - if ok, _ := path.Match(pattern, podAnnotationKey); ok { - passthroughAnnotations[podAnnotationKey] = podAnnotationValue - } - } - } - return passthroughAnnotations -} - // runtimeSpec returns a default runtime spec used in cri-containerd. func (c *Controller) runtimeSpec(id string, baseSpecFile string, opts ...oci.SpecOpts) (*runtimespec.Spec, error) { // GenerateSpec needs namespace. diff --git a/internal/cri/server/podsandbox/helpers_test.go b/internal/cri/server/podsandbox/helpers_test.go index f2cab5962..524153f02 100644 --- a/internal/cri/server/podsandbox/helpers_test.go +++ b/internal/cri/server/podsandbox/helpers_test.go @@ -131,121 +131,6 @@ func TestEnvDeduplication(t *testing.T) { } } -func TestPassThroughAnnotationsFilter(t *testing.T) { - for _, test := range []struct { - desc string - podAnnotations map[string]string - runtimePodAnnotations []string - passthroughAnnotations map[string]string - }{ - { - desc: "should support direct match", - podAnnotations: map[string]string{"c": "d", "d": "e"}, - runtimePodAnnotations: []string{"c"}, - passthroughAnnotations: map[string]string{"c": "d"}, - }, - { - desc: "should support wildcard match", - podAnnotations: map[string]string{ - "t.f": "j", - "z.g": "o", - "z": "o", - "y.ca": "b", - "y": "b", - }, - runtimePodAnnotations: []string{"*.f", "z*g", "y.c*"}, - passthroughAnnotations: map[string]string{ - "t.f": "j", - "z.g": "o", - "y.ca": "b", - }, - }, - { - desc: "should support wildcard match all", - podAnnotations: map[string]string{ - "t.f": "j", - "z.g": "o", - "z": "o", - "y.ca": "b", - "y": "b", - }, - runtimePodAnnotations: []string{"*"}, - passthroughAnnotations: map[string]string{ - "t.f": "j", - "z.g": "o", - "z": "o", - "y.ca": "b", - "y": "b", - }, - }, - { - desc: "should support match including path separator", - podAnnotations: map[string]string{ - "matchend.com/end": "1", - "matchend.com/end1": "2", - "matchend.com/1end": "3", - "matchmid.com/mid": "4", - "matchmid.com/mi1d": "5", - "matchmid.com/mid1": "6", - "matchhead.com/head": "7", - "matchhead.com/1head": "8", - "matchhead.com/head1": "9", - "matchall.com/abc": "10", - "matchall.com/def": "11", - "end/matchend": "12", - "end1/matchend": "13", - "1end/matchend": "14", - "mid/matchmid": "15", - "mi1d/matchmid": "16", - "mid1/matchmid": "17", - "head/matchhead": "18", - "1head/matchhead": "19", - "head1/matchhead": "20", - "abc/matchall": "21", - "def/matchall": "22", - "match1/match2": "23", - "nomatch/nomatch": "24", - }, - runtimePodAnnotations: []string{ - "matchend.com/end*", - "matchmid.com/mi*d", - "matchhead.com/*head", - "matchall.com/*", - "end*/matchend", - "mi*d/matchmid", - "*head/matchhead", - "*/matchall", - "match*/match*", - }, - passthroughAnnotations: map[string]string{ - "matchend.com/end": "1", - "matchend.com/end1": "2", - "matchmid.com/mid": "4", - "matchmid.com/mi1d": "5", - "matchhead.com/head": "7", - "matchhead.com/1head": "8", - "matchall.com/abc": "10", - "matchall.com/def": "11", - "end/matchend": "12", - "end1/matchend": "13", - "mid/matchmid": "15", - "mi1d/matchmid": "16", - "head/matchhead": "18", - "1head/matchhead": "19", - "abc/matchall": "21", - "def/matchall": "22", - "match1/match2": "23", - }, - }, - } { - test := test - t.Run(test.desc, func(t *testing.T) { - passthroughAnnotations := getPassthroughAnnotations(test.podAnnotations, test.runtimePodAnnotations) - assert.Equal(t, test.passthroughAnnotations, passthroughAnnotations) - }) - } -} - func TestEnsureRemoveAllNotExist(t *testing.T) { // should never return an error for a non-existent path if err := ensureRemoveAll(context.Background(), "/non/existent/path"); err != nil { diff --git a/internal/cri/server/podsandbox/sandbox_run_linux.go b/internal/cri/server/podsandbox/sandbox_run_linux.go index b9ad3047d..030cd542a 100644 --- a/internal/cri/server/podsandbox/sandbox_run_linux.go +++ b/internal/cri/server/podsandbox/sandbox_run_linux.go @@ -33,6 +33,7 @@ import ( "github.com/containerd/containerd/v2/core/snapshots" "github.com/containerd/containerd/v2/internal/cri/annotations" customopts "github.com/containerd/containerd/v2/internal/cri/opts" + "github.com/containerd/containerd/v2/internal/cri/util" ) func (c *Controller) sandboxContainerSpec(id string, config *runtime.PodSandboxConfig, @@ -187,7 +188,7 @@ func (c *Controller) sandboxContainerSpec(id string, config *runtime.PodSandboxC specOpts = append(specOpts, customopts.WithPodOOMScoreAdj(int(defaultSandboxOOMAdj), c.config.RestrictOOMScoreAdj)) - for pKey, pValue := range getPassthroughAnnotations(config.Annotations, + for pKey, pValue := range util.GetPassthroughAnnotations(config.Annotations, runtimePodAnnotations) { specOpts = append(specOpts, customopts.WithAnnotation(pKey, pValue)) } diff --git a/internal/cri/server/podsandbox/sandbox_run_windows.go b/internal/cri/server/podsandbox/sandbox_run_windows.go index a7ad590df..067f4a850 100644 --- a/internal/cri/server/podsandbox/sandbox_run_windows.go +++ b/internal/cri/server/podsandbox/sandbox_run_windows.go @@ -28,6 +28,7 @@ import ( "github.com/containerd/containerd/v2/core/snapshots" "github.com/containerd/containerd/v2/internal/cri/annotations" customopts "github.com/containerd/containerd/v2/internal/cri/opts" + "github.com/containerd/containerd/v2/internal/cri/util" ) func (c *Controller) sandboxContainerSpec(id string, config *runtime.PodSandboxConfig, @@ -75,7 +76,7 @@ func (c *Controller) sandboxContainerSpec(id string, config *runtime.PodSandboxC // when trying to run the init process. specOpts = append(specOpts, oci.WithUser(username)) - for pKey, pValue := range getPassthroughAnnotations(config.Annotations, + for pKey, pValue := range util.GetPassthroughAnnotations(config.Annotations, runtimePodAnnotations) { specOpts = append(specOpts, customopts.WithAnnotation(pKey, pValue)) } diff --git a/internal/cri/util/util.go b/internal/cri/util/util.go index 3eb1d644d..ecc2823a6 100644 --- a/internal/cri/util/util.go +++ b/internal/cri/util/util.go @@ -18,6 +18,7 @@ package util import ( "context" + "path" "time" "github.com/containerd/containerd/v2/pkg/namespaces" @@ -44,3 +45,22 @@ func NamespacedContext() context.Context { func WithNamespace(ctx context.Context) context.Context { return namespaces.WithNamespace(ctx, constants.K8sContainerdNamespace) } + +// GetPassthroughAnnotations filters requested pod annotations by comparing +// against permitted annotations for the given runtime. +func GetPassthroughAnnotations(podAnnotations map[string]string, + runtimePodAnnotations []string) (passthroughAnnotations map[string]string) { + passthroughAnnotations = make(map[string]string) + + for podAnnotationKey, podAnnotationValue := range podAnnotations { + for _, pattern := range runtimePodAnnotations { + // Use path.Match instead of filepath.Match here. + // filepath.Match treated `\\` as path separator + // on windows, which is not what we want. + if ok, _ := path.Match(pattern, podAnnotationKey); ok { + passthroughAnnotations[podAnnotationKey] = podAnnotationValue + } + } + } + return passthroughAnnotations +} diff --git a/internal/cri/util/util_test.go b/internal/cri/util/util_test.go new file mode 100644 index 000000000..2a1263b8f --- /dev/null +++ b/internal/cri/util/util_test.go @@ -0,0 +1,138 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package util + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestPassThroughAnnotationsFilter(t *testing.T) { + for _, test := range []struct { + desc string + podAnnotations map[string]string + runtimePodAnnotations []string + passthroughAnnotations map[string]string + }{ + { + desc: "should support direct match", + podAnnotations: map[string]string{"c": "d", "d": "e"}, + runtimePodAnnotations: []string{"c"}, + passthroughAnnotations: map[string]string{"c": "d"}, + }, + { + desc: "should support wildcard match", + podAnnotations: map[string]string{ + "t.f": "j", + "z.g": "o", + "z": "o", + "y.ca": "b", + "y": "b", + }, + runtimePodAnnotations: []string{"*.f", "z*g", "y.c*"}, + passthroughAnnotations: map[string]string{ + "t.f": "j", + "z.g": "o", + "y.ca": "b", + }, + }, + { + desc: "should support wildcard match all", + podAnnotations: map[string]string{ + "t.f": "j", + "z.g": "o", + "z": "o", + "y.ca": "b", + "y": "b", + }, + runtimePodAnnotations: []string{"*"}, + passthroughAnnotations: map[string]string{ + "t.f": "j", + "z.g": "o", + "z": "o", + "y.ca": "b", + "y": "b", + }, + }, + { + desc: "should support match including path separator", + podAnnotations: map[string]string{ + "matchend.com/end": "1", + "matchend.com/end1": "2", + "matchend.com/1end": "3", + "matchmid.com/mid": "4", + "matchmid.com/mi1d": "5", + "matchmid.com/mid1": "6", + "matchhead.com/head": "7", + "matchhead.com/1head": "8", + "matchhead.com/head1": "9", + "matchall.com/abc": "10", + "matchall.com/def": "11", + "end/matchend": "12", + "end1/matchend": "13", + "1end/matchend": "14", + "mid/matchmid": "15", + "mi1d/matchmid": "16", + "mid1/matchmid": "17", + "head/matchhead": "18", + "1head/matchhead": "19", + "head1/matchhead": "20", + "abc/matchall": "21", + "def/matchall": "22", + "match1/match2": "23", + "nomatch/nomatch": "24", + }, + runtimePodAnnotations: []string{ + "matchend.com/end*", + "matchmid.com/mi*d", + "matchhead.com/*head", + "matchall.com/*", + "end*/matchend", + "mi*d/matchmid", + "*head/matchhead", + "*/matchall", + "match*/match*", + }, + passthroughAnnotations: map[string]string{ + "matchend.com/end": "1", + "matchend.com/end1": "2", + "matchmid.com/mid": "4", + "matchmid.com/mi1d": "5", + "matchhead.com/head": "7", + "matchhead.com/1head": "8", + "matchall.com/abc": "10", + "matchall.com/def": "11", + "end/matchend": "12", + "end1/matchend": "13", + "mid/matchmid": "15", + "mi1d/matchmid": "16", + "head/matchhead": "18", + "1head/matchhead": "19", + "abc/matchall": "21", + "def/matchall": "22", + "match1/match2": "23", + }, + }, + } { + test := test + t.Run(test.desc, func(t *testing.T) { + passthroughAnnotations := GetPassthroughAnnotations(test.podAnnotations, test.runtimePodAnnotations) + assert.Equal(t, test.passthroughAnnotations, passthroughAnnotations) + }) + } +}