mirror of
https://github.com/k3s-io/kubernetes.git
synced 2026-01-04 15:05:20 +00:00
sync api/v1/pod/util with api/pod/util and remove DefaultContainers
This commit is contained in:
@@ -47,5 +47,6 @@ go_test(
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
|
||||
"//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library",
|
||||
"//staging/src/k8s.io/component-base/featuregate/testing:go_default_library",
|
||||
"//vendor/github.com/google/go-cmp/cmp:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -29,9 +29,6 @@ import (
|
||||
// ContainerType signifies container type
|
||||
type ContainerType int
|
||||
|
||||
// DefaultContainers defines default behavior: Iterate containers based on feature gates
|
||||
const DefaultContainers ContainerType = 0
|
||||
|
||||
const (
|
||||
// Containers is for normal containers
|
||||
Containers ContainerType = 1 << iota
|
||||
@@ -44,35 +41,40 @@ const (
|
||||
// AllContainers specifies that all containers be visited
|
||||
const AllContainers ContainerType = (InitContainers | Containers | EphemeralContainers)
|
||||
|
||||
// AllFeatureEnabledContainers returns a ContainerType mask which includes all container
|
||||
// types except for the ones guarded by feature gate.
|
||||
func AllFeatureEnabledContainers() ContainerType {
|
||||
containerType := AllContainers
|
||||
if !utilfeature.DefaultFeatureGate.Enabled(features.EphemeralContainers) {
|
||||
containerType &= ^EphemeralContainers
|
||||
}
|
||||
return containerType
|
||||
}
|
||||
|
||||
// ContainerVisitor is called with each container spec, and returns true
|
||||
// if visiting should continue.
|
||||
type ContainerVisitor func(container *api.Container, containerType ContainerType) (shouldContinue bool)
|
||||
|
||||
// VisitContainers invokes the visitor function with a pointer to the container
|
||||
// spec of every container in the given pod spec. If visitor returns false,
|
||||
// VisitContainers invokes the visitor function with a pointer to every container
|
||||
// spec in the given pod spec with type set in mask. If visitor returns false,
|
||||
// visiting is short-circuited. VisitContainers returns true if visiting completes,
|
||||
// false if visiting was short-circuited.
|
||||
//
|
||||
// With the default mask (zero value or DefaultContainers) VisitContainers will visit all containers
|
||||
// enabled by current feature gates. If mask is non-zero, VisitContainers will unconditionally visit
|
||||
// container types specified by mask, and no feature gate checks will be performed.
|
||||
func VisitContainers(podSpec *api.PodSpec, mask ContainerType, visitor ContainerVisitor) bool {
|
||||
if mask == DefaultContainers || (mask&InitContainers) > 0 {
|
||||
if mask&InitContainers != 0 {
|
||||
for i := range podSpec.InitContainers {
|
||||
if !visitor(&podSpec.InitContainers[i], InitContainers) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
if mask == DefaultContainers || (mask&Containers) > 0 {
|
||||
if mask&Containers != 0 {
|
||||
for i := range podSpec.Containers {
|
||||
if !visitor(&podSpec.Containers[i], Containers) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mask == DefaultContainers && utilfeature.DefaultFeatureGate.Enabled(features.EphemeralContainers)) ||
|
||||
(mask&EphemeralContainers) > 0 {
|
||||
if mask&EphemeralContainers != 0 {
|
||||
for i := range podSpec.EphemeralContainers {
|
||||
if !visitor((*api.Container)(&podSpec.EphemeralContainers[i].EphemeralContainerCommon), EphemeralContainers) {
|
||||
return false
|
||||
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/diff"
|
||||
@@ -35,74 +36,22 @@ import (
|
||||
)
|
||||
|
||||
func TestVisitContainers(t *testing.T) {
|
||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.EphemeralContainers, true)()
|
||||
|
||||
testCases := []struct {
|
||||
description string
|
||||
haveSpec *api.PodSpec
|
||||
wantNames []string
|
||||
mask ContainerType
|
||||
desc string
|
||||
spec *api.PodSpec
|
||||
wantContainers []string
|
||||
mask ContainerType
|
||||
ephemeralContainersEnabled bool
|
||||
}{
|
||||
{
|
||||
"empty podspec",
|
||||
&api.PodSpec{},
|
||||
[]string{},
|
||||
DefaultContainers,
|
||||
desc: "empty podspec",
|
||||
spec: &api.PodSpec{},
|
||||
wantContainers: []string{},
|
||||
mask: AllContainers,
|
||||
},
|
||||
{
|
||||
"regular containers",
|
||||
&api.PodSpec{
|
||||
Containers: []api.Container{
|
||||
{Name: "c1"},
|
||||
{Name: "c2"},
|
||||
},
|
||||
},
|
||||
[]string{"c1", "c2"},
|
||||
DefaultContainers,
|
||||
},
|
||||
{
|
||||
"init containers",
|
||||
&api.PodSpec{
|
||||
InitContainers: []api.Container{
|
||||
{Name: "i1"},
|
||||
{Name: "i2"},
|
||||
},
|
||||
},
|
||||
[]string{"i1", "i2"},
|
||||
DefaultContainers,
|
||||
},
|
||||
{
|
||||
"regular and init containers",
|
||||
&api.PodSpec{
|
||||
Containers: []api.Container{
|
||||
{Name: "c1"},
|
||||
{Name: "c2"},
|
||||
},
|
||||
InitContainers: []api.Container{
|
||||
{Name: "i1"},
|
||||
{Name: "i2"},
|
||||
},
|
||||
},
|
||||
[]string{"i1", "i2", "c1", "c2"},
|
||||
DefaultContainers,
|
||||
},
|
||||
{
|
||||
"ephemeral containers",
|
||||
&api.PodSpec{
|
||||
Containers: []api.Container{
|
||||
{Name: "c1"},
|
||||
{Name: "c2"},
|
||||
},
|
||||
EphemeralContainers: []api.EphemeralContainer{
|
||||
{EphemeralContainerCommon: api.EphemeralContainerCommon{Name: "e1"}},
|
||||
},
|
||||
},
|
||||
[]string{"c1", "c2", "e1"},
|
||||
DefaultContainers,
|
||||
},
|
||||
{
|
||||
"all container types",
|
||||
&api.PodSpec{
|
||||
desc: "regular containers",
|
||||
spec: &api.PodSpec{
|
||||
Containers: []api.Container{
|
||||
{Name: "c1"},
|
||||
{Name: "c2"},
|
||||
@@ -116,12 +65,12 @@ func TestVisitContainers(t *testing.T) {
|
||||
{EphemeralContainerCommon: api.EphemeralContainerCommon{Name: "e2"}},
|
||||
},
|
||||
},
|
||||
[]string{"i1", "i2", "c1", "c2", "e1", "e2"},
|
||||
DefaultContainers,
|
||||
wantContainers: []string{"c1", "c2"},
|
||||
mask: Containers,
|
||||
},
|
||||
{
|
||||
"all container types with init and regular container types chosen",
|
||||
&api.PodSpec{
|
||||
desc: "init containers",
|
||||
spec: &api.PodSpec{
|
||||
Containers: []api.Container{
|
||||
{Name: "c1"},
|
||||
{Name: "c2"},
|
||||
@@ -135,12 +84,89 @@ func TestVisitContainers(t *testing.T) {
|
||||
{EphemeralContainerCommon: api.EphemeralContainerCommon{Name: "e2"}},
|
||||
},
|
||||
},
|
||||
[]string{"i1", "i2", "c1", "c2"},
|
||||
Containers | InitContainers,
|
||||
wantContainers: []string{"i1", "i2"},
|
||||
mask: InitContainers,
|
||||
},
|
||||
{
|
||||
"dropping fields",
|
||||
&api.PodSpec{
|
||||
desc: "ephemeral containers",
|
||||
spec: &api.PodSpec{
|
||||
Containers: []api.Container{
|
||||
{Name: "c1"},
|
||||
{Name: "c2"},
|
||||
},
|
||||
InitContainers: []api.Container{
|
||||
{Name: "i1"},
|
||||
{Name: "i2"},
|
||||
},
|
||||
EphemeralContainers: []api.EphemeralContainer{
|
||||
{EphemeralContainerCommon: api.EphemeralContainerCommon{Name: "e1"}},
|
||||
{EphemeralContainerCommon: api.EphemeralContainerCommon{Name: "e2"}},
|
||||
},
|
||||
},
|
||||
wantContainers: []string{"e1", "e2"},
|
||||
mask: EphemeralContainers,
|
||||
},
|
||||
{
|
||||
desc: "all container types",
|
||||
spec: &api.PodSpec{
|
||||
Containers: []api.Container{
|
||||
{Name: "c1"},
|
||||
{Name: "c2"},
|
||||
},
|
||||
InitContainers: []api.Container{
|
||||
{Name: "i1"},
|
||||
{Name: "i2"},
|
||||
},
|
||||
EphemeralContainers: []api.EphemeralContainer{
|
||||
{EphemeralContainerCommon: api.EphemeralContainerCommon{Name: "e1"}},
|
||||
{EphemeralContainerCommon: api.EphemeralContainerCommon{Name: "e2"}},
|
||||
},
|
||||
},
|
||||
wantContainers: []string{"i1", "i2", "c1", "c2", "e1", "e2"},
|
||||
mask: AllContainers,
|
||||
},
|
||||
{
|
||||
desc: "all feature enabled container types with ephemeral containers disabled",
|
||||
spec: &api.PodSpec{
|
||||
Containers: []api.Container{
|
||||
{Name: "c1"},
|
||||
{Name: "c2"},
|
||||
},
|
||||
InitContainers: []api.Container{
|
||||
{Name: "i1"},
|
||||
{Name: "i2"},
|
||||
},
|
||||
EphemeralContainers: []api.EphemeralContainer{
|
||||
{EphemeralContainerCommon: api.EphemeralContainerCommon{Name: "e1"}},
|
||||
{EphemeralContainerCommon: api.EphemeralContainerCommon{Name: "e2"}},
|
||||
},
|
||||
},
|
||||
wantContainers: []string{"i1", "i2", "c1", "c2"},
|
||||
mask: AllFeatureEnabledContainers(),
|
||||
},
|
||||
{
|
||||
desc: "all feature enabled container types with ephemeral containers enabled",
|
||||
spec: &api.PodSpec{
|
||||
Containers: []api.Container{
|
||||
{Name: "c1"},
|
||||
{Name: "c2", SecurityContext: &api.SecurityContext{}},
|
||||
},
|
||||
InitContainers: []api.Container{
|
||||
{Name: "i1"},
|
||||
{Name: "i2", SecurityContext: &api.SecurityContext{}},
|
||||
},
|
||||
EphemeralContainers: []api.EphemeralContainer{
|
||||
{EphemeralContainerCommon: api.EphemeralContainerCommon{Name: "e1"}},
|
||||
{EphemeralContainerCommon: api.EphemeralContainerCommon{Name: "e2"}},
|
||||
},
|
||||
},
|
||||
wantContainers: []string{"i1", "i2", "c1", "c2", "e1", "e2"},
|
||||
mask: AllFeatureEnabledContainers(),
|
||||
ephemeralContainersEnabled: true,
|
||||
},
|
||||
{
|
||||
desc: "dropping fields",
|
||||
spec: &api.PodSpec{
|
||||
Containers: []api.Container{
|
||||
{Name: "c1"},
|
||||
{Name: "c2", SecurityContext: &api.SecurityContext{}},
|
||||
@@ -154,38 +180,45 @@ func TestVisitContainers(t *testing.T) {
|
||||
{EphemeralContainerCommon: api.EphemeralContainerCommon{Name: "e2", SecurityContext: &api.SecurityContext{}}},
|
||||
},
|
||||
},
|
||||
[]string{"i1", "i2", "c1", "c2", "e1", "e2"},
|
||||
DefaultContainers,
|
||||
wantContainers: []string{"i1", "i2", "c1", "c2", "e1", "e2"},
|
||||
mask: AllContainers,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
gotNames := []string{}
|
||||
VisitContainers(tc.haveSpec, tc.mask, func(c *api.Container, containerType ContainerType) bool {
|
||||
gotNames = append(gotNames, c.Name)
|
||||
if c.SecurityContext != nil {
|
||||
c.SecurityContext = nil
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
if tc.ephemeralContainersEnabled {
|
||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.EphemeralContainers, tc.ephemeralContainersEnabled)()
|
||||
tc.mask = AllFeatureEnabledContainers()
|
||||
}
|
||||
|
||||
gotContainers := []string{}
|
||||
VisitContainers(tc.spec, tc.mask, func(c *api.Container, containerType ContainerType) bool {
|
||||
gotContainers = append(gotContainers, c.Name)
|
||||
if c.SecurityContext != nil {
|
||||
c.SecurityContext = nil
|
||||
}
|
||||
return true
|
||||
})
|
||||
if !cmp.Equal(gotContainers, tc.wantContainers) {
|
||||
t.Errorf("VisitContainers() = %+v, want %+v", gotContainers, tc.wantContainers)
|
||||
}
|
||||
for _, c := range tc.spec.Containers {
|
||||
if c.SecurityContext != nil {
|
||||
t.Errorf("VisitContainers() did not drop SecurityContext for container %q", c.Name)
|
||||
}
|
||||
}
|
||||
for _, c := range tc.spec.InitContainers {
|
||||
if c.SecurityContext != nil {
|
||||
t.Errorf("VisitContainers() did not drop SecurityContext for init container %q", c.Name)
|
||||
}
|
||||
}
|
||||
for _, c := range tc.spec.EphemeralContainers {
|
||||
if c.SecurityContext != nil {
|
||||
t.Errorf("VisitContainers() did not drop SecurityContext for ephemeral container %q", c.Name)
|
||||
}
|
||||
}
|
||||
return true
|
||||
})
|
||||
if !reflect.DeepEqual(gotNames, tc.wantNames) {
|
||||
t.Errorf("VisitContainers() for test case %q visited containers %q, wanted to visit %q", tc.description, gotNames, tc.wantNames)
|
||||
}
|
||||
for _, c := range tc.haveSpec.Containers {
|
||||
if c.SecurityContext != nil {
|
||||
t.Errorf("VisitContainers() for test case %q: got SecurityContext %#v for container %v, wanted nil", tc.description, c.SecurityContext, c.Name)
|
||||
}
|
||||
}
|
||||
for _, c := range tc.haveSpec.InitContainers {
|
||||
if c.SecurityContext != nil {
|
||||
t.Errorf("VisitContainers() for test case %q: got SecurityContext %#v for init container %v, wanted nil", tc.description, c.SecurityContext, c.Name)
|
||||
}
|
||||
}
|
||||
for _, c := range tc.haveSpec.EphemeralContainers {
|
||||
if c.SecurityContext != nil {
|
||||
t.Errorf("VisitContainers() for test case %q: got SecurityContext %#v for ephemeral container %v, wanted nil", tc.description, c.SecurityContext, c.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user