2017-02-27 01:00:58 -05:00
/ *
Copyright 2017 The Kubernetes 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 pod
import (
2018-12-18 10:10:56 -05:00
"fmt"
2017-02-27 01:00:58 -05:00
"reflect"
"strings"
2018-08-17 05:03:30 -04:00
"testing"
2017-02-27 01:00:58 -05:00
2020-03-20 13:21:24 -04:00
"github.com/google/go-cmp/cmp"
2020-03-18 10:51:47 -04:00
2020-07-17 14:56:52 -04:00
v1 "k8s.io/api/core/v1"
2021-11-03 18:43:43 -04:00
"k8s.io/apimachinery/pkg/api/resource"
2019-01-07 15:10:11 -05:00
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2017-02-27 01:00:58 -05:00
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apimachinery/pkg/util/validation/field"
2017-08-09 13:51:46 -04:00
utilfeature "k8s.io/apiserver/pkg/util/feature"
2019-03-04 12:46:52 -05:00
featuregatetesting "k8s.io/component-base/featuregate/testing"
2017-11-08 17:34:54 -05:00
api "k8s.io/kubernetes/pkg/apis/core"
2017-08-09 13:51:46 -04:00
"k8s.io/kubernetes/pkg/features"
2022-02-23 07:11:59 -05:00
"k8s.io/utils/pointer"
2017-02-27 01:00:58 -05:00
)
2019-06-14 11:20:16 -04:00
func TestVisitContainers ( t * testing . T ) {
2021-10-04 05:44:19 -04:00
setAllFeatureEnabledContainersDuringTest := ContainerType ( 0 )
2019-06-14 11:20:16 -04:00
testCases := [ ] struct {
2022-07-24 10:36:42 -04:00
desc string
spec * api . PodSpec
wantContainers [ ] string
mask ContainerType
2019-06-14 11:20:16 -04:00
} {
{
2020-03-20 13:21:24 -04:00
desc : "empty podspec" ,
spec : & api . PodSpec { } ,
wantContainers : [ ] string { } ,
mask : AllContainers ,
2019-06-14 11:20:16 -04:00
} ,
{
2020-03-20 13:21:24 -04:00
desc : "regular containers" ,
spec : & api . PodSpec {
2019-06-14 11:20:16 -04:00
Containers : [ ] api . Container {
{ Name : "c1" } ,
{ Name : "c2" } ,
} ,
2020-03-20 13:21:24 -04:00
InitContainers : [ ] api . Container {
{ Name : "i1" } ,
{ Name : "i2" } ,
} ,
EphemeralContainers : [ ] api . EphemeralContainer {
{ EphemeralContainerCommon : api . EphemeralContainerCommon { Name : "e1" } } ,
{ EphemeralContainerCommon : api . EphemeralContainerCommon { Name : "e2" } } ,
} ,
2019-06-14 11:20:16 -04:00
} ,
2020-03-20 13:21:24 -04:00
wantContainers : [ ] string { "c1" , "c2" } ,
mask : Containers ,
2019-06-14 11:20:16 -04:00
} ,
{
2020-03-20 13:21:24 -04:00
desc : "init containers" ,
spec : & api . PodSpec {
Containers : [ ] api . Container {
{ Name : "c1" } ,
{ Name : "c2" } ,
} ,
2019-06-14 11:20:16 -04:00
InitContainers : [ ] api . Container {
{ Name : "i1" } ,
{ Name : "i2" } ,
} ,
2020-03-20 13:21:24 -04:00
EphemeralContainers : [ ] api . EphemeralContainer {
{ EphemeralContainerCommon : api . EphemeralContainerCommon { Name : "e1" } } ,
{ EphemeralContainerCommon : api . EphemeralContainerCommon { Name : "e2" } } ,
} ,
2019-06-14 11:20:16 -04:00
} ,
2020-03-20 13:21:24 -04:00
wantContainers : [ ] string { "i1" , "i2" } ,
mask : InitContainers ,
2019-06-14 11:20:16 -04:00
} ,
{
2020-03-20 13:21:24 -04:00
desc : "ephemeral containers" ,
spec : & api . PodSpec {
2019-06-14 11:20:16 -04:00
Containers : [ ] api . Container {
{ Name : "c1" } ,
{ Name : "c2" } ,
} ,
InitContainers : [ ] api . Container {
{ Name : "i1" } ,
{ Name : "i2" } ,
} ,
2020-03-20 13:21:24 -04:00
EphemeralContainers : [ ] api . EphemeralContainer {
{ EphemeralContainerCommon : api . EphemeralContainerCommon { Name : "e1" } } ,
{ EphemeralContainerCommon : api . EphemeralContainerCommon { Name : "e2" } } ,
} ,
2019-06-14 11:20:16 -04:00
} ,
2020-03-20 13:21:24 -04:00
wantContainers : [ ] string { "e1" , "e2" } ,
mask : EphemeralContainers ,
2019-06-14 11:20:16 -04:00
} ,
2018-08-09 09:24:23 -04:00
{
2020-03-20 13:21:24 -04:00
desc : "all container types" ,
spec : & api . PodSpec {
2018-08-09 09:24:23 -04:00
Containers : [ ] api . Container {
{ Name : "c1" } ,
{ Name : "c2" } ,
} ,
2020-03-20 13:21:24 -04:00
InitContainers : [ ] api . Container {
{ Name : "i1" } ,
{ Name : "i2" } ,
} ,
2018-08-09 09:24:23 -04:00
EphemeralContainers : [ ] api . EphemeralContainer {
{ EphemeralContainerCommon : api . EphemeralContainerCommon { Name : "e1" } } ,
2020-03-20 13:21:24 -04:00
{ EphemeralContainerCommon : api . EphemeralContainerCommon { Name : "e2" } } ,
2018-08-09 09:24:23 -04:00
} ,
} ,
2020-03-20 13:21:24 -04:00
wantContainers : [ ] string { "i1" , "i2" , "c1" , "c2" , "e1" , "e2" } ,
mask : AllContainers ,
2018-08-09 09:24:23 -04:00
} ,
2020-03-05 14:48:00 -05:00
{
2020-03-20 13:21:24 -04:00
desc : "all feature enabled container types with ephemeral containers enabled" ,
spec : & api . PodSpec {
2020-03-05 14:48:00 -05:00
Containers : [ ] api . Container {
{ Name : "c1" } ,
2020-03-20 13:21:24 -04:00
{ Name : "c2" , SecurityContext : & api . SecurityContext { } } ,
2020-03-05 14:48:00 -05:00
} ,
InitContainers : [ ] api . Container {
{ Name : "i1" } ,
2020-03-20 13:21:24 -04:00
{ Name : "i2" , SecurityContext : & api . SecurityContext { } } ,
2020-03-05 14:48:00 -05:00
} ,
EphemeralContainers : [ ] api . EphemeralContainer {
{ EphemeralContainerCommon : api . EphemeralContainerCommon { Name : "e1" } } ,
{ EphemeralContainerCommon : api . EphemeralContainerCommon { Name : "e2" } } ,
} ,
} ,
2022-07-24 10:36:42 -04:00
wantContainers : [ ] string { "i1" , "i2" , "c1" , "c2" , "e1" , "e2" } ,
mask : setAllFeatureEnabledContainersDuringTest ,
2018-08-09 09:24:23 -04:00
} ,
2019-06-14 11:20:16 -04:00
{
2020-03-20 13:21:24 -04:00
desc : "dropping fields" ,
spec : & api . PodSpec {
2019-06-14 11:20:16 -04:00
Containers : [ ] api . Container {
{ Name : "c1" } ,
{ Name : "c2" , SecurityContext : & api . SecurityContext { } } ,
} ,
InitContainers : [ ] api . Container {
{ Name : "i1" } ,
{ Name : "i2" , SecurityContext : & api . SecurityContext { } } ,
} ,
2018-08-09 09:24:23 -04:00
EphemeralContainers : [ ] api . EphemeralContainer {
{ EphemeralContainerCommon : api . EphemeralContainerCommon { Name : "e1" } } ,
{ EphemeralContainerCommon : api . EphemeralContainerCommon { Name : "e2" , SecurityContext : & api . SecurityContext { } } } ,
} ,
2019-06-14 11:20:16 -04:00
} ,
2020-03-20 13:21:24 -04:00
wantContainers : [ ] string { "i1" , "i2" , "c1" , "c2" , "e1" , "e2" } ,
mask : AllContainers ,
2019-06-14 11:20:16 -04:00
} ,
}
for _ , tc := range testCases {
2020-03-20 13:21:24 -04:00
t . Run ( tc . desc , func ( t * testing . T ) {
2021-10-04 05:44:19 -04:00
if tc . mask == setAllFeatureEnabledContainersDuringTest {
2020-03-20 13:21:24 -04:00
tc . mask = AllFeatureEnabledContainers ( )
2019-06-14 11:20:16 -04:00
}
2020-03-20 13:21:24 -04:00
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 )
2019-06-14 11:20:16 -04:00
}
2020-03-20 13:21:24 -04:00
for _ , c := range tc . spec . Containers {
if c . SecurityContext != nil {
t . Errorf ( "VisitContainers() did not drop SecurityContext for container %q" , c . Name )
}
2019-06-14 11:20:16 -04:00
}
2020-03-20 13:21:24 -04:00
for _ , c := range tc . spec . InitContainers {
if c . SecurityContext != nil {
t . Errorf ( "VisitContainers() did not drop SecurityContext for init container %q" , c . Name )
}
2018-08-09 09:24:23 -04:00
}
2020-03-20 13:21:24 -04:00
for _ , c := range tc . spec . EphemeralContainers {
if c . SecurityContext != nil {
t . Errorf ( "VisitContainers() did not drop SecurityContext for ephemeral container %q" , c . Name )
}
}
} )
2019-06-14 11:20:16 -04:00
}
}
2017-02-27 01:00:58 -05:00
func TestPodSecrets ( t * testing . T ) {
// Stub containing all possible secret references in a pod.
// The names of the referenced secrets match struct paths detected by reflection.
pod := & api . Pod {
Spec : api . PodSpec {
Containers : [ ] api . Container { {
EnvFrom : [ ] api . EnvFromSource { {
SecretRef : & api . SecretEnvSource {
LocalObjectReference : api . LocalObjectReference {
Name : "Spec.Containers[*].EnvFrom[*].SecretRef" } } } } ,
Env : [ ] api . EnvVar { {
ValueFrom : & api . EnvVarSource {
SecretKeyRef : & api . SecretKeySelector {
LocalObjectReference : api . LocalObjectReference {
Name : "Spec.Containers[*].Env[*].ValueFrom.SecretKeyRef" } } } } } } } ,
ImagePullSecrets : [ ] api . LocalObjectReference { {
Name : "Spec.ImagePullSecrets" } } ,
InitContainers : [ ] api . Container { {
EnvFrom : [ ] api . EnvFromSource { {
SecretRef : & api . SecretEnvSource {
LocalObjectReference : api . LocalObjectReference {
Name : "Spec.InitContainers[*].EnvFrom[*].SecretRef" } } } } ,
Env : [ ] api . EnvVar { {
ValueFrom : & api . EnvVarSource {
SecretKeyRef : & api . SecretKeySelector {
LocalObjectReference : api . LocalObjectReference {
Name : "Spec.InitContainers[*].Env[*].ValueFrom.SecretKeyRef" } } } } } } } ,
Volumes : [ ] api . Volume { {
VolumeSource : api . VolumeSource {
AzureFile : & api . AzureFileVolumeSource {
SecretName : "Spec.Volumes[*].VolumeSource.AzureFile.SecretName" } } } , {
VolumeSource : api . VolumeSource {
CephFS : & api . CephFSVolumeSource {
SecretRef : & api . LocalObjectReference {
Name : "Spec.Volumes[*].VolumeSource.CephFS.SecretRef" } } } } , {
2018-05-14 17:09:05 -04:00
VolumeSource : api . VolumeSource {
Cinder : & api . CinderVolumeSource {
SecretRef : & api . LocalObjectReference {
Name : "Spec.Volumes[*].VolumeSource.Cinder.SecretRef" } } } } , {
2017-02-27 01:00:58 -05:00
VolumeSource : api . VolumeSource {
FlexVolume : & api . FlexVolumeSource {
SecretRef : & api . LocalObjectReference {
Name : "Spec.Volumes[*].VolumeSource.FlexVolume.SecretRef" } } } } , {
VolumeSource : api . VolumeSource {
Projected : & api . ProjectedVolumeSource {
Sources : [ ] api . VolumeProjection { {
Secret : & api . SecretProjection {
LocalObjectReference : api . LocalObjectReference {
Name : "Spec.Volumes[*].VolumeSource.Projected.Sources[*].Secret" } } } } } } } , {
VolumeSource : api . VolumeSource {
RBD : & api . RBDVolumeSource {
SecretRef : & api . LocalObjectReference {
Name : "Spec.Volumes[*].VolumeSource.RBD.SecretRef" } } } } , {
VolumeSource : api . VolumeSource {
Secret : & api . SecretVolumeSource {
SecretName : "Spec.Volumes[*].VolumeSource.Secret.SecretName" } } } , {
VolumeSource : api . VolumeSource {
Secret : & api . SecretVolumeSource {
2016-11-19 15:46:23 -05:00
SecretName : "Spec.Volumes[*].VolumeSource.Secret" } } } , {
VolumeSource : api . VolumeSource {
ScaleIO : & api . ScaleIOVolumeSource {
SecretRef : & api . LocalObjectReference {
2017-03-17 16:42:15 -04:00
Name : "Spec.Volumes[*].VolumeSource.ScaleIO.SecretRef" } } } } , {
VolumeSource : api . VolumeSource {
ISCSI : & api . ISCSIVolumeSource {
SecretRef : & api . LocalObjectReference {
2017-02-24 10:47:40 -05:00
Name : "Spec.Volumes[*].VolumeSource.ISCSI.SecretRef" } } } } , {
VolumeSource : api . VolumeSource {
StorageOS : & api . StorageOSVolumeSource {
SecretRef : & api . LocalObjectReference {
2018-08-14 17:00:25 -04:00
Name : "Spec.Volumes[*].VolumeSource.StorageOS.SecretRef" } } } } , {
VolumeSource : api . VolumeSource {
CSI : & api . CSIVolumeSource {
NodePublishSecretRef : & api . LocalObjectReference {
Name : "Spec.Volumes[*].VolumeSource.CSI.NodePublishSecretRef" } } } } } ,
2018-08-09 09:24:23 -04:00
EphemeralContainers : [ ] api . EphemeralContainer { {
EphemeralContainerCommon : api . EphemeralContainerCommon {
EnvFrom : [ ] api . EnvFromSource { {
SecretRef : & api . SecretEnvSource {
LocalObjectReference : api . LocalObjectReference {
Name : "Spec.EphemeralContainers[*].EphemeralContainerCommon.EnvFrom[*].SecretRef" } } } } ,
Env : [ ] api . EnvVar { {
ValueFrom : & api . EnvVarSource {
SecretKeyRef : & api . SecretKeySelector {
LocalObjectReference : api . LocalObjectReference {
Name : "Spec.EphemeralContainers[*].EphemeralContainerCommon.Env[*].ValueFrom.SecretKeyRef" } } } } } } } } ,
2017-02-27 01:00:58 -05:00
} ,
}
extractedNames := sets . NewString ( )
VisitPodSecretNames ( pod , func ( name string ) bool {
extractedNames . Insert ( name )
return true
2020-03-20 10:59:44 -04:00
} , AllContainers )
2017-02-27 01:00:58 -05:00
// excludedSecretPaths holds struct paths to fields with "secret" in the name that are not actually references to secret API objects
excludedSecretPaths := sets . NewString (
"Spec.Volumes[*].VolumeSource.CephFS.SecretFile" ,
)
// expectedSecretPaths holds struct paths to fields with "secret" in the name that are references to secret API objects.
// every path here should be represented as an example in the Pod stub above, with the secret name set to the path.
expectedSecretPaths := sets . NewString (
"Spec.Containers[*].EnvFrom[*].SecretRef" ,
"Spec.Containers[*].Env[*].ValueFrom.SecretKeyRef" ,
2018-08-09 09:24:23 -04:00
"Spec.EphemeralContainers[*].EphemeralContainerCommon.EnvFrom[*].SecretRef" ,
"Spec.EphemeralContainers[*].EphemeralContainerCommon.Env[*].ValueFrom.SecretKeyRef" ,
2017-02-27 01:00:58 -05:00
"Spec.ImagePullSecrets" ,
"Spec.InitContainers[*].EnvFrom[*].SecretRef" ,
"Spec.InitContainers[*].Env[*].ValueFrom.SecretKeyRef" ,
"Spec.Volumes[*].VolumeSource.AzureFile.SecretName" ,
"Spec.Volumes[*].VolumeSource.CephFS.SecretRef" ,
2018-05-14 17:09:05 -04:00
"Spec.Volumes[*].VolumeSource.Cinder.SecretRef" ,
2017-02-27 01:00:58 -05:00
"Spec.Volumes[*].VolumeSource.FlexVolume.SecretRef" ,
"Spec.Volumes[*].VolumeSource.Projected.Sources[*].Secret" ,
"Spec.Volumes[*].VolumeSource.RBD.SecretRef" ,
"Spec.Volumes[*].VolumeSource.Secret" ,
"Spec.Volumes[*].VolumeSource.Secret.SecretName" ,
2016-11-19 15:46:23 -05:00
"Spec.Volumes[*].VolumeSource.ScaleIO.SecretRef" ,
2017-03-17 16:42:15 -04:00
"Spec.Volumes[*].VolumeSource.ISCSI.SecretRef" ,
2017-02-24 10:47:40 -05:00
"Spec.Volumes[*].VolumeSource.StorageOS.SecretRef" ,
2018-08-14 17:00:25 -04:00
"Spec.Volumes[*].VolumeSource.CSI.NodePublishSecretRef" ,
2017-02-27 01:00:58 -05:00
)
2017-11-10 02:44:51 -05:00
secretPaths := collectResourcePaths ( t , "secret" , nil , "" , reflect . TypeOf ( & api . Pod { } ) )
2017-02-27 01:00:58 -05:00
secretPaths = secretPaths . Difference ( excludedSecretPaths )
if missingPaths := expectedSecretPaths . Difference ( secretPaths ) ; len ( missingPaths ) > 0 {
t . Logf ( "Missing expected secret paths:\n%s" , strings . Join ( missingPaths . List ( ) , "\n" ) )
t . Error ( "Missing expected secret paths. Verify VisitPodSecretNames() is correctly finding the missing paths, then correct expectedSecretPaths" )
}
if extraPaths := secretPaths . Difference ( expectedSecretPaths ) ; len ( extraPaths ) > 0 {
t . Logf ( "Extra secret paths:\n%s" , strings . Join ( extraPaths . List ( ) , "\n" ) )
t . Error ( "Extra fields with 'secret' in the name found. Verify VisitPodSecretNames() is including these fields if appropriate, then correct expectedSecretPaths" )
}
if missingNames := expectedSecretPaths . Difference ( extractedNames ) ; len ( missingNames ) > 0 {
t . Logf ( "Missing expected secret names:\n%s" , strings . Join ( missingNames . List ( ) , "\n" ) )
t . Error ( "Missing expected secret names. Verify the pod stub above includes these references, then verify VisitPodSecretNames() is correctly finding the missing names" )
}
if extraNames := extractedNames . Difference ( expectedSecretPaths ) ; len ( extraNames ) > 0 {
t . Logf ( "Extra secret names:\n%s" , strings . Join ( extraNames . List ( ) , "\n" ) )
t . Error ( "Extra secret names extracted. Verify VisitPodSecretNames() is correctly extracting secret names" )
}
2021-02-27 14:09:57 -05:00
// emptyPod is a stub containing empty object names
emptyPod := & api . Pod {
Spec : api . PodSpec {
Containers : [ ] api . Container { {
EnvFrom : [ ] api . EnvFromSource { {
SecretRef : & api . SecretEnvSource {
LocalObjectReference : api . LocalObjectReference {
Name : "" } } } } } } ,
} ,
}
VisitPodSecretNames ( emptyPod , func ( name string ) bool {
t . Fatalf ( "expected no empty names collected, got %q" , name )
return false
} , AllContainers )
2017-02-27 01:00:58 -05:00
}
2017-11-10 02:44:51 -05:00
// collectResourcePaths traverses the object, computing all the struct paths that lead to fields with resourcename in the name.
func collectResourcePaths ( t * testing . T , resourcename string , path * field . Path , name string , tp reflect . Type ) sets . String {
resourcename = strings . ToLower ( resourcename )
resourcePaths := sets . NewString ( )
2017-02-27 01:00:58 -05:00
2022-06-25 12:23:43 -04:00
if tp . Kind ( ) == reflect . Pointer {
2017-11-10 02:44:51 -05:00
resourcePaths . Insert ( collectResourcePaths ( t , resourcename , path , name , tp . Elem ( ) ) . List ( ) ... )
return resourcePaths
2017-02-27 01:00:58 -05:00
}
2017-11-10 02:44:51 -05:00
if strings . Contains ( strings . ToLower ( name ) , resourcename ) {
resourcePaths . Insert ( path . String ( ) )
2017-02-27 01:00:58 -05:00
}
switch tp . Kind ( ) {
2022-06-25 12:23:43 -04:00
case reflect . Pointer :
2017-11-10 02:44:51 -05:00
resourcePaths . Insert ( collectResourcePaths ( t , resourcename , path , name , tp . Elem ( ) ) . List ( ) ... )
2017-02-27 01:00:58 -05:00
case reflect . Struct :
2019-02-01 14:55:18 -05:00
// ObjectMeta is generic and therefore should never have a field with a specific resource's name;
// it contains cycles so it's easiest to just skip it.
2019-01-17 00:14:42 -05:00
if name == "ObjectMeta" {
break
}
2017-02-27 01:00:58 -05:00
for i := 0 ; i < tp . NumField ( ) ; i ++ {
field := tp . Field ( i )
2017-11-10 02:44:51 -05:00
resourcePaths . Insert ( collectResourcePaths ( t , resourcename , path . Child ( field . Name ) , field . Name , field . Type ) . List ( ) ... )
2017-02-27 01:00:58 -05:00
}
case reflect . Interface :
2017-11-10 02:44:51 -05:00
t . Errorf ( "cannot find %s fields in interface{} field %s" , resourcename , path . String ( ) )
2017-02-27 01:00:58 -05:00
case reflect . Map :
2017-11-10 02:44:51 -05:00
resourcePaths . Insert ( collectResourcePaths ( t , resourcename , path . Key ( "*" ) , "" , tp . Elem ( ) ) . List ( ) ... )
2017-02-27 01:00:58 -05:00
case reflect . Slice :
2017-11-10 02:44:51 -05:00
resourcePaths . Insert ( collectResourcePaths ( t , resourcename , path . Key ( "*" ) , "" , tp . Elem ( ) ) . List ( ) ... )
2017-02-27 01:00:58 -05:00
default :
// all primitive types
}
2017-11-10 02:44:51 -05:00
return resourcePaths
}
func TestPodConfigmaps ( t * testing . T ) {
// Stub containing all possible ConfigMap references in a pod.
// The names of the referenced ConfigMaps match struct paths detected by reflection.
pod := & api . Pod {
Spec : api . PodSpec {
Containers : [ ] api . Container { {
EnvFrom : [ ] api . EnvFromSource { {
ConfigMapRef : & api . ConfigMapEnvSource {
LocalObjectReference : api . LocalObjectReference {
Name : "Spec.Containers[*].EnvFrom[*].ConfigMapRef" } } } } ,
Env : [ ] api . EnvVar { {
ValueFrom : & api . EnvVarSource {
ConfigMapKeyRef : & api . ConfigMapKeySelector {
LocalObjectReference : api . LocalObjectReference {
Name : "Spec.Containers[*].Env[*].ValueFrom.ConfigMapKeyRef" } } } } } } } ,
2018-08-09 09:24:23 -04:00
EphemeralContainers : [ ] api . EphemeralContainer { {
EphemeralContainerCommon : api . EphemeralContainerCommon {
EnvFrom : [ ] api . EnvFromSource { {
ConfigMapRef : & api . ConfigMapEnvSource {
LocalObjectReference : api . LocalObjectReference {
Name : "Spec.EphemeralContainers[*].EphemeralContainerCommon.EnvFrom[*].ConfigMapRef" } } } } ,
Env : [ ] api . EnvVar { {
ValueFrom : & api . EnvVarSource {
ConfigMapKeyRef : & api . ConfigMapKeySelector {
LocalObjectReference : api . LocalObjectReference {
Name : "Spec.EphemeralContainers[*].EphemeralContainerCommon.Env[*].ValueFrom.ConfigMapKeyRef" } } } } } } } } ,
2017-11-10 02:44:51 -05:00
InitContainers : [ ] api . Container { {
EnvFrom : [ ] api . EnvFromSource { {
ConfigMapRef : & api . ConfigMapEnvSource {
LocalObjectReference : api . LocalObjectReference {
Name : "Spec.InitContainers[*].EnvFrom[*].ConfigMapRef" } } } } ,
Env : [ ] api . EnvVar { {
ValueFrom : & api . EnvVarSource {
ConfigMapKeyRef : & api . ConfigMapKeySelector {
LocalObjectReference : api . LocalObjectReference {
Name : "Spec.InitContainers[*].Env[*].ValueFrom.ConfigMapKeyRef" } } } } } } } ,
Volumes : [ ] api . Volume { {
VolumeSource : api . VolumeSource {
Projected : & api . ProjectedVolumeSource {
Sources : [ ] api . VolumeProjection { {
ConfigMap : & api . ConfigMapProjection {
LocalObjectReference : api . LocalObjectReference {
Name : "Spec.Volumes[*].VolumeSource.Projected.Sources[*].ConfigMap" } } } } } } } , {
VolumeSource : api . VolumeSource {
ConfigMap : & api . ConfigMapVolumeSource {
LocalObjectReference : api . LocalObjectReference {
Name : "Spec.Volumes[*].VolumeSource.ConfigMap" } } } } } ,
} ,
}
extractedNames := sets . NewString ( )
VisitPodConfigmapNames ( pod , func ( name string ) bool {
extractedNames . Insert ( name )
return true
2020-03-20 10:59:44 -04:00
} , AllContainers )
2017-11-10 02:44:51 -05:00
// expectedPaths holds struct paths to fields with "ConfigMap" in the name that are references to ConfigMap API objects.
// every path here should be represented as an example in the Pod stub above, with the ConfigMap name set to the path.
expectedPaths := sets . NewString (
"Spec.Containers[*].EnvFrom[*].ConfigMapRef" ,
"Spec.Containers[*].Env[*].ValueFrom.ConfigMapKeyRef" ,
2018-08-09 09:24:23 -04:00
"Spec.EphemeralContainers[*].EphemeralContainerCommon.EnvFrom[*].ConfigMapRef" ,
"Spec.EphemeralContainers[*].EphemeralContainerCommon.Env[*].ValueFrom.ConfigMapKeyRef" ,
2017-11-10 02:44:51 -05:00
"Spec.InitContainers[*].EnvFrom[*].ConfigMapRef" ,
"Spec.InitContainers[*].Env[*].ValueFrom.ConfigMapKeyRef" ,
"Spec.Volumes[*].VolumeSource.Projected.Sources[*].ConfigMap" ,
"Spec.Volumes[*].VolumeSource.ConfigMap" ,
)
collectPaths := collectResourcePaths ( t , "ConfigMap" , nil , "" , reflect . TypeOf ( & api . Pod { } ) )
if missingPaths := expectedPaths . Difference ( collectPaths ) ; len ( missingPaths ) > 0 {
t . Logf ( "Missing expected paths:\n%s" , strings . Join ( missingPaths . List ( ) , "\n" ) )
t . Error ( "Missing expected paths. Verify VisitPodConfigmapNames() is correctly finding the missing paths, then correct expectedPaths" )
}
if extraPaths := collectPaths . Difference ( expectedPaths ) ; len ( extraPaths ) > 0 {
t . Logf ( "Extra paths:\n%s" , strings . Join ( extraPaths . List ( ) , "\n" ) )
t . Error ( "Extra fields with resource in the name found. Verify VisitPodConfigmapNames() is including these fields if appropriate, then correct expectedPaths" )
}
if missingNames := expectedPaths . Difference ( extractedNames ) ; len ( missingNames ) > 0 {
t . Logf ( "Missing expected names:\n%s" , strings . Join ( missingNames . List ( ) , "\n" ) )
t . Error ( "Missing expected names. Verify the pod stub above includes these references, then verify VisitPodConfigmapNames() is correctly finding the missing names" )
}
if extraNames := extractedNames . Difference ( expectedPaths ) ; len ( extraNames ) > 0 {
t . Logf ( "Extra names:\n%s" , strings . Join ( extraNames . List ( ) , "\n" ) )
t . Error ( "Extra names extracted. Verify VisitPodConfigmapNames() is correctly extracting resource names" )
}
2021-02-27 14:09:57 -05:00
// emptyPod is a stub containing empty object names
emptyPod := & api . Pod {
Spec : api . PodSpec {
Containers : [ ] api . Container { {
EnvFrom : [ ] api . EnvFromSource { {
ConfigMapRef : & api . ConfigMapEnvSource {
LocalObjectReference : api . LocalObjectReference {
Name : "" } } } } } } ,
} ,
}
VisitPodConfigmapNames ( emptyPod , func ( name string ) bool {
t . Fatalf ( "expected no empty names collected, got %q" , name )
return false
} , AllContainers )
2017-02-27 01:00:58 -05:00
}
2017-08-09 13:51:46 -04:00
2020-02-21 16:35:52 -05:00
func TestDropFSGroupFields ( t * testing . T ) {
nofsGroupPod := func ( ) * api . Pod {
return & api . Pod {
Spec : api . PodSpec {
Containers : [ ] api . Container {
{
Name : "container1" ,
Image : "testimage" ,
} ,
} ,
} ,
}
}
var podFSGroup int64 = 100
changePolicy := api . FSGroupChangeAlways
fsGroupPod := func ( ) * api . Pod {
return & api . Pod {
Spec : api . PodSpec {
Containers : [ ] api . Container {
{
Name : "container1" ,
Image : "testimage" ,
} ,
} ,
SecurityContext : & api . PodSecurityContext {
FSGroup : & podFSGroup ,
FSGroupChangePolicy : & changePolicy ,
} ,
} ,
}
}
podInfos := [ ] struct {
description string
newPodHasFSGroupChangePolicy bool
pod func ( ) * api . Pod
expectPolicyInPod bool
} {
{
description : "oldPod.FSGroupChangePolicy=nil, feature=true, newPod.FSGroupChangePolicy=true" ,
pod : nofsGroupPod ,
newPodHasFSGroupChangePolicy : true ,
expectPolicyInPod : true ,
} ,
{
description : "oldPod=nil, feature=true, newPod.FSGroupChangePolicy=true" ,
pod : func ( ) * api . Pod { return nil } ,
newPodHasFSGroupChangePolicy : true ,
expectPolicyInPod : true ,
} ,
{
description : "oldPod.FSGroupChangePolicy=true, feature=true, newPod.FSGroupChangePolicy=false" ,
pod : fsGroupPod ,
newPodHasFSGroupChangePolicy : false ,
expectPolicyInPod : false ,
} ,
}
for _ , podInfo := range podInfos {
t . Run ( podInfo . description , func ( t * testing . T ) {
oldPod := podInfo . pod ( )
newPod := oldPod . DeepCopy ( )
if oldPod == nil && podInfo . newPodHasFSGroupChangePolicy {
newPod = fsGroupPod ( )
}
if oldPod != nil {
if podInfo . newPodHasFSGroupChangePolicy {
newPod . Spec . SecurityContext = & api . PodSecurityContext {
FSGroup : & podFSGroup ,
FSGroupChangePolicy : & changePolicy ,
}
} else {
newPod . Spec . SecurityContext = & api . PodSecurityContext { }
}
}
DropDisabledPodFields ( newPod , oldPod )
if podInfo . expectPolicyInPod {
secContext := newPod . Spec . SecurityContext
if secContext == nil || secContext . FSGroupChangePolicy == nil {
t . Errorf ( "for %s, expected fsGroupChangepolicy found none" , podInfo . description )
}
} else {
2023-09-17 05:18:43 -04:00
secContext := newPod . Spec . SecurityContext
if secContext != nil && secContext . FSGroupChangePolicy != nil {
2020-02-21 16:35:52 -05:00
t . Errorf ( "for %s, unexpected fsGroupChangepolicy set" , podInfo . description )
}
}
} )
}
}
2018-12-20 12:28:08 -05:00
func TestDropProcMount ( t * testing . T ) {
procMount := api . UnmaskedProcMount
defaultProcMount := api . DefaultProcMount
podWithProcMount := func ( ) * api . Pod {
return & api . Pod {
Spec : api . PodSpec {
RestartPolicy : api . RestartPolicyNever ,
Containers : [ ] api . Container { { Name : "container1" , Image : "testimage" , SecurityContext : & api . SecurityContext { ProcMount : & procMount } } } ,
InitContainers : [ ] api . Container { { Name : "container1" , Image : "testimage" , SecurityContext : & api . SecurityContext { ProcMount : & procMount } } } ,
} ,
}
}
2019-06-10 21:47:00 -04:00
podWithDefaultProcMount := func ( ) * api . Pod {
2018-12-20 12:28:08 -05:00
return & api . Pod {
Spec : api . PodSpec {
RestartPolicy : api . RestartPolicyNever ,
Containers : [ ] api . Container { { Name : "container1" , Image : "testimage" , SecurityContext : & api . SecurityContext { ProcMount : & defaultProcMount } } } ,
InitContainers : [ ] api . Container { { Name : "container1" , Image : "testimage" , SecurityContext : & api . SecurityContext { ProcMount : & defaultProcMount } } } ,
} ,
}
}
2019-06-10 21:47:00 -04:00
podWithoutProcMount := func ( ) * api . Pod {
return & api . Pod {
Spec : api . PodSpec {
RestartPolicy : api . RestartPolicyNever ,
Containers : [ ] api . Container { { Name : "container1" , Image : "testimage" , SecurityContext : & api . SecurityContext { ProcMount : nil } } } ,
InitContainers : [ ] api . Container { { Name : "container1" , Image : "testimage" , SecurityContext : & api . SecurityContext { ProcMount : nil } } } ,
} ,
}
}
2018-12-20 12:28:08 -05:00
podInfo := [ ] struct {
description string
hasProcMount bool
pod func ( ) * api . Pod
} {
{
description : "has ProcMount" ,
hasProcMount : true ,
pod : podWithProcMount ,
} ,
2019-06-10 21:47:00 -04:00
{
description : "has default ProcMount" ,
hasProcMount : false ,
pod : podWithDefaultProcMount ,
} ,
2018-12-20 12:28:08 -05:00
{
description : "does not have ProcMount" ,
hasProcMount : false ,
pod : podWithoutProcMount ,
} ,
{
description : "is nil" ,
hasProcMount : false ,
pod : func ( ) * api . Pod { return nil } ,
} ,
}
for _ , enabled := range [ ] bool { true , false } {
for _ , oldPodInfo := range podInfo {
for _ , newPodInfo := range podInfo {
oldPodHasProcMount , oldPod := oldPodInfo . hasProcMount , oldPodInfo . pod ( )
newPodHasProcMount , newPod := newPodInfo . hasProcMount , newPodInfo . pod ( )
if newPod == nil {
continue
}
t . Run ( fmt . Sprintf ( "feature enabled=%v, old pod %v, new pod %v" , enabled , oldPodInfo . description , newPodInfo . description ) , func ( t * testing . T ) {
2019-03-04 12:46:52 -05:00
defer featuregatetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . ProcMountType , enabled ) ( )
2018-12-20 12:28:08 -05:00
var oldPodSpec * api . PodSpec
if oldPod != nil {
oldPodSpec = & oldPod . Spec
}
2019-01-07 14:17:29 -05:00
dropDisabledFields ( & newPod . Spec , nil , oldPodSpec , nil )
2018-12-20 12:28:08 -05:00
// old pod should never be changed
if ! reflect . DeepEqual ( oldPod , oldPodInfo . pod ( ) ) {
2021-03-17 05:35:21 -04:00
t . Errorf ( "old pod changed: %v" , cmp . Diff ( oldPod , oldPodInfo . pod ( ) ) )
2018-12-20 12:28:08 -05:00
}
switch {
case enabled || oldPodHasProcMount :
// new pod should not be changed if the feature is enabled, or if the old pod had ProcMount
if ! reflect . DeepEqual ( newPod , newPodInfo . pod ( ) ) {
2021-03-17 05:35:21 -04:00
t . Errorf ( "new pod changed: %v" , cmp . Diff ( newPod , newPodInfo . pod ( ) ) )
2018-12-20 12:28:08 -05:00
}
case newPodHasProcMount :
// new pod should be changed
if reflect . DeepEqual ( newPod , newPodInfo . pod ( ) ) {
t . Errorf ( "new pod was not changed" )
}
// new pod should not have ProcMount
2019-06-10 21:47:00 -04:00
if procMountInUse ( & newPod . Spec ) {
t . Errorf ( "new pod had ProcMount: %#v" , & newPod . Spec )
2018-12-20 12:28:08 -05:00
}
default :
// new pod should not need to be changed
if ! reflect . DeepEqual ( newPod , newPodInfo . pod ( ) ) {
2021-03-17 05:35:21 -04:00
t . Errorf ( "new pod changed: %v" , cmp . Diff ( newPod , newPodInfo . pod ( ) ) )
2019-01-08 17:26:21 -05:00
}
}
} )
}
}
}
}
2019-01-07 15:10:11 -05:00
func TestDropAppArmor ( t * testing . T ) {
podWithAppArmor := func ( ) * api . Pod {
return & api . Pod {
2020-03-18 10:51:47 -04:00
ObjectMeta : metav1 . ObjectMeta { Annotations : map [ string ] string { "a" : "1" , v1 . AppArmorBetaContainerAnnotationKeyPrefix + "foo" : "default" } } ,
2019-01-07 15:10:11 -05:00
Spec : api . PodSpec { } ,
}
}
podWithoutAppArmor := func ( ) * api . Pod {
return & api . Pod {
ObjectMeta : metav1 . ObjectMeta { Annotations : map [ string ] string { "a" : "1" } } ,
Spec : api . PodSpec { } ,
}
}
podInfo := [ ] struct {
description string
hasAppArmor bool
pod func ( ) * api . Pod
} {
{
description : "has AppArmor" ,
hasAppArmor : true ,
pod : podWithAppArmor ,
} ,
{
description : "does not have AppArmor" ,
hasAppArmor : false ,
pod : podWithoutAppArmor ,
} ,
{
description : "is nil" ,
hasAppArmor : false ,
pod : func ( ) * api . Pod { return nil } ,
} ,
}
for _ , enabled := range [ ] bool { true , false } {
for _ , oldPodInfo := range podInfo {
for _ , newPodInfo := range podInfo {
oldPodHasAppArmor , oldPod := oldPodInfo . hasAppArmor , oldPodInfo . pod ( )
newPodHasAppArmor , newPod := newPodInfo . hasAppArmor , newPodInfo . pod ( )
if newPod == nil {
continue
}
t . Run ( fmt . Sprintf ( "feature enabled=%v, old pod %v, new pod %v" , enabled , oldPodInfo . description , newPodInfo . description ) , func ( t * testing . T ) {
2019-03-04 12:46:52 -05:00
defer featuregatetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . AppArmor , enabled ) ( )
2019-01-07 15:10:11 -05:00
DropDisabledPodFields ( newPod , oldPod )
// old pod should never be changed
if ! reflect . DeepEqual ( oldPod , oldPodInfo . pod ( ) ) {
2021-03-17 05:35:21 -04:00
t . Errorf ( "old pod changed: %v" , cmp . Diff ( oldPod , oldPodInfo . pod ( ) ) )
2019-01-07 15:10:11 -05:00
}
switch {
case enabled || oldPodHasAppArmor :
// new pod should not be changed if the feature is enabled, or if the old pod had AppArmor
if ! reflect . DeepEqual ( newPod , newPodInfo . pod ( ) ) {
2021-03-17 05:35:21 -04:00
t . Errorf ( "new pod changed: %v" , cmp . Diff ( newPod , newPodInfo . pod ( ) ) )
2019-01-07 15:10:11 -05:00
}
case newPodHasAppArmor :
// new pod should be changed
if reflect . DeepEqual ( newPod , newPodInfo . pod ( ) ) {
t . Errorf ( "new pod was not changed" )
}
// new pod should not have AppArmor
if ! reflect . DeepEqual ( newPod , podWithoutAppArmor ( ) ) {
2021-03-17 05:35:21 -04:00
t . Errorf ( "new pod had EmptyDir SizeLimit: %v" , cmp . Diff ( newPod , podWithoutAppArmor ( ) ) )
2019-01-07 15:10:11 -05:00
}
default :
// new pod should not need to be changed
2019-01-08 15:21:49 -05:00
if ! reflect . DeepEqual ( newPod , newPodInfo . pod ( ) ) {
2021-03-17 05:35:21 -04:00
t . Errorf ( "new pod changed: %v" , cmp . Diff ( newPod , newPodInfo . pod ( ) ) )
2019-01-08 15:21:49 -05:00
}
}
2021-06-23 18:24:35 -04:00
} )
}
2018-11-20 08:05:19 -05:00
}
}
}
2019-06-21 13:42:53 -04:00
2022-11-04 08:46:49 -04:00
func TestDropDynamicResourceAllocation ( t * testing . T ) {
resourceClaimName := "external-claim"
podWithClaims := & api . Pod {
Spec : api . PodSpec {
Containers : [ ] api . Container {
{
Resources : api . ResourceRequirements {
Claims : [ ] api . ResourceClaim { { Name : "my-claim" } } ,
} ,
} ,
} ,
InitContainers : [ ] api . Container {
{
Resources : api . ResourceRequirements {
Claims : [ ] api . ResourceClaim { { Name : "my-claim" } } ,
} ,
} ,
} ,
EphemeralContainers : [ ] api . EphemeralContainer {
{
EphemeralContainerCommon : api . EphemeralContainerCommon {
Resources : api . ResourceRequirements {
Claims : [ ] api . ResourceClaim { { Name : "my-claim" } } ,
} ,
} ,
} ,
} ,
ResourceClaims : [ ] api . PodResourceClaim {
{
Name : "my-claim" ,
Source : api . ClaimSource {
ResourceClaimName : & resourceClaimName ,
} ,
} ,
} ,
} ,
2023-04-14 03:50:52 -04:00
Status : api . PodStatus {
ResourceClaimStatuses : [ ] api . PodResourceClaimStatus {
{ Name : "my-claim" , ResourceClaimName : pointer . String ( "pod-my-claim" ) } ,
} ,
} ,
2022-11-04 08:46:49 -04:00
}
podWithoutClaims := & api . Pod {
Spec : api . PodSpec {
Containers : [ ] api . Container { { } } ,
InitContainers : [ ] api . Container { { } } ,
EphemeralContainers : [ ] api . EphemeralContainer { { } } ,
} ,
}
var noPod * api . Pod
testcases := [ ] struct {
description string
enabled bool
oldPod * api . Pod
newPod * api . Pod
wantPod * api . Pod
} {
{
description : "old with claims / new with claims / disabled" ,
oldPod : podWithClaims ,
newPod : podWithClaims ,
wantPod : podWithClaims ,
} ,
{
description : "old without claims / new with claims / disabled" ,
oldPod : podWithoutClaims ,
newPod : podWithClaims ,
wantPod : podWithoutClaims ,
} ,
{
description : "no old pod/ new with claims / disabled" ,
oldPod : noPod ,
newPod : podWithClaims ,
wantPod : podWithoutClaims ,
} ,
{
description : "old with claims / new without claims / disabled" ,
oldPod : podWithClaims ,
newPod : podWithoutClaims ,
wantPod : podWithoutClaims ,
} ,
{
description : "old without claims / new without claims / disabled" ,
oldPod : podWithoutClaims ,
newPod : podWithoutClaims ,
wantPod : podWithoutClaims ,
} ,
{
description : "no old pod/ new without claims / disabled" ,
oldPod : noPod ,
newPod : podWithoutClaims ,
wantPod : podWithoutClaims ,
} ,
{
description : "old with claims / new with claims / enabled" ,
enabled : true ,
oldPod : podWithClaims ,
newPod : podWithClaims ,
wantPod : podWithClaims ,
} ,
{
description : "old without claims / new with claims / enabled" ,
enabled : true ,
oldPod : podWithoutClaims ,
newPod : podWithClaims ,
wantPod : podWithClaims ,
} ,
{
description : "no old pod/ new with claims / enabled" ,
enabled : true ,
oldPod : noPod ,
newPod : podWithClaims ,
wantPod : podWithClaims ,
} ,
{
description : "old with claims / new without claims / enabled" ,
enabled : true ,
oldPod : podWithClaims ,
newPod : podWithoutClaims ,
wantPod : podWithoutClaims ,
} ,
{
description : "old without claims / new without claims / enabled" ,
enabled : true ,
oldPod : podWithoutClaims ,
newPod : podWithoutClaims ,
wantPod : podWithoutClaims ,
} ,
{
description : "no old pod/ new without claims / enabled" ,
enabled : true ,
oldPod : noPod ,
newPod : podWithoutClaims ,
wantPod : podWithoutClaims ,
} ,
}
for _ , tc := range testcases {
t . Run ( tc . description , func ( t * testing . T ) {
defer featuregatetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . DynamicResourceAllocation , tc . enabled ) ( )
oldPod := tc . oldPod . DeepCopy ( )
newPod := tc . newPod . DeepCopy ( )
wantPod := tc . wantPod
DropDisabledPodFields ( newPod , oldPod )
// old pod should never be changed
if diff := cmp . Diff ( oldPod , tc . oldPod ) ; diff != "" {
t . Errorf ( "old pod changed: %s" , diff )
}
if diff := cmp . Diff ( wantPod , newPod ) ; diff != "" {
t . Errorf ( "new pod changed (- want, + got): %s" , diff )
}
} )
}
}
2021-02-17 15:39:42 -05:00
func TestValidatePodDeletionCostOption ( t * testing . T ) {
testCases := [ ] struct {
name string
oldPodMeta * metav1 . ObjectMeta
featureEnabled bool
wantAllowInvalidPodDeletionCost bool
} {
{
name : "CreateFeatureEnabled" ,
featureEnabled : true ,
wantAllowInvalidPodDeletionCost : false ,
} ,
{
name : "CreateFeatureDisabled" ,
featureEnabled : false ,
wantAllowInvalidPodDeletionCost : true ,
} ,
{
name : "UpdateFeatureDisabled" ,
2021-04-08 20:44:54 -04:00
oldPodMeta : & metav1 . ObjectMeta { Annotations : map [ string ] string { api . PodDeletionCost : "100" } } ,
2021-02-17 15:39:42 -05:00
featureEnabled : false ,
wantAllowInvalidPodDeletionCost : true ,
} ,
{
name : "UpdateFeatureEnabledValidOldValue" ,
2021-04-08 20:44:54 -04:00
oldPodMeta : & metav1 . ObjectMeta { Annotations : map [ string ] string { api . PodDeletionCost : "100" } } ,
2021-02-17 15:39:42 -05:00
featureEnabled : true ,
wantAllowInvalidPodDeletionCost : false ,
} ,
{
name : "UpdateFeatureEnabledValidOldValue" ,
2021-04-08 20:44:54 -04:00
oldPodMeta : & metav1 . ObjectMeta { Annotations : map [ string ] string { api . PodDeletionCost : "invalid-value" } } ,
2021-02-17 15:39:42 -05:00
featureEnabled : true ,
wantAllowInvalidPodDeletionCost : true ,
} ,
}
for _ , tc := range testCases {
t . Run ( tc . name , func ( t * testing . T ) {
defer featuregatetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . PodDeletionCost , tc . featureEnabled ) ( )
// The new pod doesn't impact the outcome.
gotOptions := GetValidationOptionsFromPodSpecAndMeta ( nil , nil , nil , tc . oldPodMeta )
if tc . wantAllowInvalidPodDeletionCost != gotOptions . AllowInvalidPodDeletionCost {
t . Errorf ( "unexpected diff, want: %v, got: %v" , tc . wantAllowInvalidPodDeletionCost , gotOptions . AllowInvalidPodDeletionCost )
}
2021-01-26 14:28:35 -05:00
} )
}
}
2022-02-23 07:11:59 -05:00
func TestDropDisabledTopologySpreadConstraintsFields ( t * testing . T ) {
testCases := [ ] struct {
name string
enabled bool
podSpec * api . PodSpec
oldPodSpec * api . PodSpec
wantPodSpec * api . PodSpec
} {
{
name : "TopologySpreadConstraints is nil" ,
podSpec : & api . PodSpec { } ,
oldPodSpec : & api . PodSpec { } ,
wantPodSpec : & api . PodSpec { } ,
} ,
{
name : "TopologySpreadConstraints is empty" ,
podSpec : & api . PodSpec { TopologySpreadConstraints : [ ] api . TopologySpreadConstraint { } } ,
oldPodSpec : & api . PodSpec { TopologySpreadConstraints : [ ] api . TopologySpreadConstraint { } } ,
wantPodSpec : & api . PodSpec { TopologySpreadConstraints : [ ] api . TopologySpreadConstraint { } } ,
} ,
{
name : "TopologySpreadConstraints is not empty, but all constraints don't have minDomains" ,
podSpec : & api . PodSpec { TopologySpreadConstraints : [ ] api . TopologySpreadConstraint {
{
MinDomains : nil ,
} ,
{
MinDomains : nil ,
} ,
} } ,
oldPodSpec : & api . PodSpec { TopologySpreadConstraints : [ ] api . TopologySpreadConstraint {
{
MinDomains : nil ,
} ,
{
MinDomains : nil ,
} ,
} } ,
wantPodSpec : & api . PodSpec { TopologySpreadConstraints : [ ] api . TopologySpreadConstraint {
{
MinDomains : nil ,
} ,
{
MinDomains : nil ,
} ,
} } ,
} ,
{
name : "one constraint in podSpec has non-empty minDomains, feature gate is disabled " +
"and all constraint in oldPodSpec doesn't have minDomains" ,
enabled : false ,
podSpec : & api . PodSpec {
TopologySpreadConstraints : [ ] api . TopologySpreadConstraint {
{
MinDomains : pointer . Int32 ( 2 ) ,
} ,
{
MinDomains : nil ,
} ,
} ,
} ,
oldPodSpec : & api . PodSpec {
TopologySpreadConstraints : [ ] api . TopologySpreadConstraint {
{
MinDomains : nil ,
} ,
{
MinDomains : nil ,
} ,
} ,
} ,
wantPodSpec : & api . PodSpec {
TopologySpreadConstraints : [ ] api . TopologySpreadConstraint {
{
// cleared.
MinDomains : nil ,
} ,
{
MinDomains : nil ,
} ,
} ,
} ,
} ,
{
name : "one constraint in podSpec has non-empty minDomains, feature gate is disabled " +
"and one constraint in oldPodSpec has minDomains" ,
enabled : false ,
podSpec : & api . PodSpec {
TopologySpreadConstraints : [ ] api . TopologySpreadConstraint {
{
MinDomains : pointer . Int32 ( 2 ) ,
} ,
{
MinDomains : nil ,
} ,
} ,
} ,
oldPodSpec : & api . PodSpec {
TopologySpreadConstraints : [ ] api . TopologySpreadConstraint {
{
MinDomains : pointer . Int32 ( 2 ) ,
} ,
{
MinDomains : nil ,
} ,
} ,
} ,
wantPodSpec : & api . PodSpec {
TopologySpreadConstraints : [ ] api . TopologySpreadConstraint {
{
// not cleared.
MinDomains : pointer . Int32 ( 2 ) ,
} ,
{
MinDomains : nil ,
} ,
} ,
} ,
} ,
{
name : "one constraint in podSpec has non-empty minDomains, feature gate is enabled" +
"and all constraint in oldPodSpec doesn't have minDomains" ,
enabled : true ,
podSpec : & api . PodSpec {
TopologySpreadConstraints : [ ] api . TopologySpreadConstraint {
{
MinDomains : pointer . Int32 ( 2 ) ,
} ,
{
MinDomains : nil ,
} ,
} ,
} ,
oldPodSpec : & api . PodSpec {
TopologySpreadConstraints : [ ] api . TopologySpreadConstraint {
{
MinDomains : nil ,
} ,
{
MinDomains : nil ,
} ,
} ,
} ,
wantPodSpec : & api . PodSpec {
TopologySpreadConstraints : [ ] api . TopologySpreadConstraint {
{
// not cleared.
MinDomains : pointer . Int32 ( 2 ) ,
} ,
{
MinDomains : nil ,
} ,
} ,
} ,
} ,
}
for _ , tc := range testCases {
t . Run ( tc . name , func ( t * testing . T ) {
defer featuregatetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . MinDomainsInPodTopologySpread , tc . enabled ) ( )
dropDisabledFields ( tc . podSpec , nil , tc . oldPodSpec , nil )
if diff := cmp . Diff ( tc . wantPodSpec , tc . podSpec ) ; diff != "" {
t . Errorf ( "unexpected pod spec (-want, +got):\n%s" , diff )
}
} )
}
}
2023-03-03 03:51:07 -05:00
func TestDropDisabledPodStatusFields ( t * testing . T ) {
podWithHostIPs := func ( ) * api . PodStatus {
return & api . PodStatus {
HostIPs : makeHostIPs ( "10.0.0.1" , "fd00:10::1" ) ,
}
}
podWithoutHostIPs := func ( ) * api . PodStatus {
return & api . PodStatus {
HostIPs : nil ,
}
}
tests := [ ] struct {
name string
podStatus * api . PodStatus
oldPodStatus * api . PodStatus
wantPodStatus * api . PodStatus
featureEnabled bool
} {
{
name : "gate off, old=without, new=without" ,
oldPodStatus : podWithoutHostIPs ( ) ,
podStatus : podWithoutHostIPs ( ) ,
featureEnabled : false ,
wantPodStatus : podWithoutHostIPs ( ) ,
} ,
{
name : "gate off, old=without, new=with" ,
oldPodStatus : podWithoutHostIPs ( ) ,
podStatus : podWithHostIPs ( ) ,
featureEnabled : false ,
wantPodStatus : podWithoutHostIPs ( ) ,
} ,
{
name : "gate off, old=with, new=without" ,
oldPodStatus : podWithHostIPs ( ) ,
podStatus : podWithoutHostIPs ( ) ,
featureEnabled : false ,
wantPodStatus : podWithoutHostIPs ( ) ,
} ,
{
name : "gate off, old=with, new=with" ,
oldPodStatus : podWithHostIPs ( ) ,
podStatus : podWithHostIPs ( ) ,
featureEnabled : false ,
wantPodStatus : podWithHostIPs ( ) ,
} ,
{
name : "gate on, old=without, new=without" ,
oldPodStatus : podWithoutHostIPs ( ) ,
podStatus : podWithoutHostIPs ( ) ,
featureEnabled : true ,
wantPodStatus : podWithoutHostIPs ( ) ,
} ,
{
name : "gate on, old=without, new=with" ,
oldPodStatus : podWithoutHostIPs ( ) ,
podStatus : podWithHostIPs ( ) ,
featureEnabled : true ,
wantPodStatus : podWithHostIPs ( ) ,
} ,
{
name : "gate on, old=with, new=without" ,
oldPodStatus : podWithHostIPs ( ) ,
podStatus : podWithoutHostIPs ( ) ,
featureEnabled : true ,
wantPodStatus : podWithoutHostIPs ( ) ,
} ,
{
name : "gate on, old=with, new=with" ,
oldPodStatus : podWithHostIPs ( ) ,
podStatus : podWithHostIPs ( ) ,
featureEnabled : true ,
wantPodStatus : podWithHostIPs ( ) ,
} ,
}
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
defer featuregatetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . PodHostIPs , tt . featureEnabled ) ( )
dropDisabledPodStatusFields ( tt . podStatus , tt . oldPodStatus , & api . PodSpec { } , & api . PodSpec { } )
if ! reflect . DeepEqual ( tt . podStatus , tt . wantPodStatus ) {
t . Errorf ( "dropDisabledStatusFields() = %v, want %v" , tt . podStatus , tt . wantPodStatus )
}
} )
}
}
func makeHostIPs ( ips ... string ) [ ] api . HostIP {
ret := [ ] api . HostIP { }
for _ , ip := range ips {
ret = append ( ret , api . HostIP { IP : ip } )
}
return ret
}
2022-05-10 00:54:49 -04:00
func TestDropNodeInclusionPolicyFields ( t * testing . T ) {
ignore := api . NodeInclusionPolicyIgnore
honor := api . NodeInclusionPolicyHonor
tests := [ ] struct {
name string
enabled bool
podSpec * api . PodSpec
oldPodSpec * api . PodSpec
wantPodSpec * api . PodSpec
} {
{
name : "feature disabled, both pods don't use the fields" ,
enabled : false ,
oldPodSpec : & api . PodSpec {
TopologySpreadConstraints : [ ] api . TopologySpreadConstraint { } ,
} ,
podSpec : & api . PodSpec {
TopologySpreadConstraints : [ ] api . TopologySpreadConstraint { } ,
} ,
wantPodSpec : & api . PodSpec {
TopologySpreadConstraints : [ ] api . TopologySpreadConstraint { } ,
} ,
} ,
{
name : "feature disabled, only old pod use NodeAffinityPolicy field" ,
enabled : false ,
oldPodSpec : & api . PodSpec {
TopologySpreadConstraints : [ ] api . TopologySpreadConstraint {
{ NodeAffinityPolicy : & honor } ,
} ,
} ,
podSpec : & api . PodSpec {
TopologySpreadConstraints : [ ] api . TopologySpreadConstraint { } ,
} ,
wantPodSpec : & api . PodSpec {
TopologySpreadConstraints : [ ] api . TopologySpreadConstraint { } ,
} ,
} ,
{
name : "feature disabled, only old pod use NodeTaintsPolicy field" ,
enabled : false ,
oldPodSpec : & api . PodSpec {
TopologySpreadConstraints : [ ] api . TopologySpreadConstraint {
{ NodeTaintsPolicy : & ignore } ,
} ,
} ,
podSpec : & api . PodSpec {
TopologySpreadConstraints : [ ] api . TopologySpreadConstraint { } ,
} ,
wantPodSpec : & api . PodSpec {
TopologySpreadConstraints : [ ] api . TopologySpreadConstraint { } ,
} ,
} ,
{
name : "feature disabled, only current pod use NodeAffinityPolicy field" ,
enabled : false ,
oldPodSpec : & api . PodSpec {
TopologySpreadConstraints : [ ] api . TopologySpreadConstraint { } ,
} ,
podSpec : & api . PodSpec {
TopologySpreadConstraints : [ ] api . TopologySpreadConstraint {
{ NodeAffinityPolicy : & honor } ,
} ,
} ,
wantPodSpec : & api . PodSpec {
TopologySpreadConstraints : [ ] api . TopologySpreadConstraint { {
NodeAffinityPolicy : nil ,
} } ,
} ,
} ,
{
name : "feature disabled, only current pod use NodeTaintsPolicy field" ,
enabled : false ,
oldPodSpec : & api . PodSpec {
TopologySpreadConstraints : [ ] api . TopologySpreadConstraint { } ,
} ,
podSpec : & api . PodSpec {
TopologySpreadConstraints : [ ] api . TopologySpreadConstraint {
{ NodeTaintsPolicy : & ignore } ,
} ,
} ,
wantPodSpec : & api . PodSpec {
TopologySpreadConstraints : [ ] api . TopologySpreadConstraint {
{ NodeTaintsPolicy : nil } ,
} ,
} ,
} ,
{
name : "feature disabled, both pods use NodeAffinityPolicy fields" ,
enabled : false ,
oldPodSpec : & api . PodSpec {
TopologySpreadConstraints : [ ] api . TopologySpreadConstraint {
{ NodeAffinityPolicy : & honor } ,
} ,
} ,
podSpec : & api . PodSpec {
TopologySpreadConstraints : [ ] api . TopologySpreadConstraint {
{ NodeAffinityPolicy : & ignore } ,
} ,
} ,
wantPodSpec : & api . PodSpec {
TopologySpreadConstraints : [ ] api . TopologySpreadConstraint {
{ NodeAffinityPolicy : & ignore } ,
} ,
} ,
} ,
{
name : "feature disabled, both pods use NodeTaintsPolicy fields" ,
enabled : false ,
oldPodSpec : & api . PodSpec {
TopologySpreadConstraints : [ ] api . TopologySpreadConstraint {
{ NodeTaintsPolicy : & ignore } ,
} ,
} ,
podSpec : & api . PodSpec {
TopologySpreadConstraints : [ ] api . TopologySpreadConstraint {
{ NodeTaintsPolicy : & honor } ,
} ,
} ,
wantPodSpec : & api . PodSpec {
TopologySpreadConstraints : [ ] api . TopologySpreadConstraint {
{ NodeTaintsPolicy : & honor } ,
} ,
} ,
} ,
{
name : "feature enabled, both pods use the fields" ,
enabled : true ,
oldPodSpec : & api . PodSpec {
TopologySpreadConstraints : [ ] api . TopologySpreadConstraint {
{
NodeAffinityPolicy : & ignore ,
NodeTaintsPolicy : & honor ,
} ,
} ,
} ,
podSpec : & api . PodSpec {
TopologySpreadConstraints : [ ] api . TopologySpreadConstraint {
{
NodeAffinityPolicy : & honor ,
NodeTaintsPolicy : & ignore ,
} ,
} ,
} ,
wantPodSpec : & api . PodSpec {
TopologySpreadConstraints : [ ] api . TopologySpreadConstraint {
{
NodeAffinityPolicy : & honor ,
NodeTaintsPolicy : & ignore ,
} ,
} ,
} ,
} ,
{
name : "feature enabled, only old pod use NodeAffinityPolicy field" ,
enabled : true ,
oldPodSpec : & api . PodSpec {
TopologySpreadConstraints : [ ] api . TopologySpreadConstraint {
{
NodeAffinityPolicy : & honor ,
} ,
} ,
} ,
podSpec : & api . PodSpec {
TopologySpreadConstraints : [ ] api . TopologySpreadConstraint { } ,
} ,
wantPodSpec : & api . PodSpec {
TopologySpreadConstraints : [ ] api . TopologySpreadConstraint { } ,
} ,
} ,
{
name : "feature enabled, only old pod use NodeTaintsPolicy field" ,
enabled : true ,
oldPodSpec : & api . PodSpec {
TopologySpreadConstraints : [ ] api . TopologySpreadConstraint {
{
NodeTaintsPolicy : & ignore ,
} ,
} ,
} ,
podSpec : & api . PodSpec {
TopologySpreadConstraints : [ ] api . TopologySpreadConstraint { } ,
} ,
wantPodSpec : & api . PodSpec {
TopologySpreadConstraints : [ ] api . TopologySpreadConstraint { } ,
} ,
} ,
{
name : "feature enabled, only current pod use NodeAffinityPolicy field" ,
enabled : true ,
oldPodSpec : & api . PodSpec {
TopologySpreadConstraints : [ ] api . TopologySpreadConstraint { } ,
} ,
podSpec : & api . PodSpec {
TopologySpreadConstraints : [ ] api . TopologySpreadConstraint {
{
NodeAffinityPolicy : & ignore ,
} ,
} ,
} ,
wantPodSpec : & api . PodSpec {
TopologySpreadConstraints : [ ] api . TopologySpreadConstraint {
{
NodeAffinityPolicy : & ignore ,
} ,
} ,
} ,
} ,
{
name : "feature enabled, only current pod use NodeTaintsPolicy field" ,
enabled : true ,
oldPodSpec : & api . PodSpec {
TopologySpreadConstraints : [ ] api . TopologySpreadConstraint { } ,
} ,
podSpec : & api . PodSpec {
TopologySpreadConstraints : [ ] api . TopologySpreadConstraint {
{
NodeTaintsPolicy : & honor ,
} ,
} ,
} ,
wantPodSpec : & api . PodSpec {
TopologySpreadConstraints : [ ] api . TopologySpreadConstraint {
{
NodeTaintsPolicy : & honor ,
} ,
} ,
} ,
} ,
}
for _ , test := range tests {
t . Run ( test . name , func ( t * testing . T ) {
defer featuregatetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . NodeInclusionPolicyInPodTopologySpread , test . enabled ) ( )
dropDisabledFields ( test . podSpec , nil , test . oldPodSpec , nil )
if diff := cmp . Diff ( test . wantPodSpec , test . podSpec ) ; diff != "" {
t . Errorf ( "unexpected pod spec (-want, +got):\n%s" , diff )
}
} )
}
}
2022-07-30 01:21:16 -04:00
2023-02-25 23:25:59 -05:00
func Test_dropDisabledMatchLabelKeysFieldInPodAffinity ( t * testing . T ) {
tests := [ ] struct {
name string
enabled bool
podSpec * api . PodSpec
oldPodSpec * api . PodSpec
wantPodSpec * api . PodSpec
} {
{
name : "[PodAffinity/required] feature disabled, both pods don't use MatchLabelKeys/MismatchLabelKeys fields" ,
enabled : false ,
oldPodSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAffinity : & api . PodAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] api . PodAffinityTerm { } ,
} ,
} ,
} ,
podSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAffinity : & api . PodAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] api . PodAffinityTerm { } ,
} ,
} ,
} ,
wantPodSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAffinity : & api . PodAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] api . PodAffinityTerm { } ,
} ,
} ,
} ,
} ,
{
name : "[PodAffinity/required] feature disabled, only old pod uses MatchLabelKeys/MismatchLabelKeys field" ,
enabled : false ,
oldPodSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAffinity : & api . PodAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] api . PodAffinityTerm {
{ MatchLabelKeys : [ ] string { "foo" } , MismatchLabelKeys : [ ] string { "foo" } } ,
} ,
} ,
} ,
} ,
podSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAffinity : & api . PodAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] api . PodAffinityTerm { } ,
} ,
} ,
} ,
wantPodSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAffinity : & api . PodAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] api . PodAffinityTerm { } ,
} ,
} ,
} ,
} ,
{
name : "[PodAffinity/required] feature disabled, only current pod uses MatchLabelKeys/MismatchLabelKeys field" ,
enabled : false ,
oldPodSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAffinity : & api . PodAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] api . PodAffinityTerm { } ,
} ,
} ,
} ,
podSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAffinity : & api . PodAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] api . PodAffinityTerm {
{ MatchLabelKeys : [ ] string { "foo" } , MismatchLabelKeys : [ ] string { "foo" } } ,
} ,
} ,
} ,
} ,
wantPodSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAffinity : & api . PodAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] api . PodAffinityTerm { { } } ,
} ,
} ,
} ,
} ,
{
name : "[PodAffinity/required] feature disabled, both pods use MatchLabelKeys/MismatchLabelKeys fields" ,
enabled : false ,
oldPodSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAffinity : & api . PodAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] api . PodAffinityTerm {
{ MatchLabelKeys : [ ] string { "foo" } , MismatchLabelKeys : [ ] string { "foo" } } ,
} ,
} ,
} ,
} ,
podSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAffinity : & api . PodAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] api . PodAffinityTerm {
{ MatchLabelKeys : [ ] string { "foo" } , MismatchLabelKeys : [ ] string { "foo" } } ,
} ,
} ,
} ,
} ,
wantPodSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAffinity : & api . PodAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] api . PodAffinityTerm {
{ MatchLabelKeys : [ ] string { "foo" } , MismatchLabelKeys : [ ] string { "foo" } } ,
} ,
} ,
} ,
} ,
} ,
{
name : "[PodAffinity/required] feature enabled, only old pod uses MatchLabelKeys/MismatchLabelKeys field" ,
enabled : true ,
oldPodSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAffinity : & api . PodAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] api . PodAffinityTerm {
{ MatchLabelKeys : [ ] string { "foo" } , MismatchLabelKeys : [ ] string { "foo" } } ,
} ,
} ,
} ,
} ,
podSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAffinity : & api . PodAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] api . PodAffinityTerm { } ,
} ,
} ,
} ,
wantPodSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAffinity : & api . PodAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] api . PodAffinityTerm { } ,
} ,
} ,
} ,
} ,
{
name : "[PodAffinity/required] feature enabled, only current pod uses MatchLabelKeys/MismatchLabelKeys field" ,
enabled : true ,
oldPodSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAffinity : & api . PodAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] api . PodAffinityTerm { } ,
} ,
} ,
} ,
podSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAffinity : & api . PodAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] api . PodAffinityTerm {
{ MatchLabelKeys : [ ] string { "foo" } , MismatchLabelKeys : [ ] string { "foo" } } ,
} ,
} ,
} ,
} ,
wantPodSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAffinity : & api . PodAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] api . PodAffinityTerm {
{ MatchLabelKeys : [ ] string { "foo" } , MismatchLabelKeys : [ ] string { "foo" } } ,
} ,
} ,
} ,
} ,
} ,
{
name : "[PodAffinity/required] feature enabled, both pods use MatchLabelKeys/MismatchLabelKeys fields" ,
enabled : false ,
oldPodSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAffinity : & api . PodAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] api . PodAffinityTerm {
{ MatchLabelKeys : [ ] string { "foo" } , MismatchLabelKeys : [ ] string { "foo" } } ,
} ,
} ,
} ,
} ,
podSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAffinity : & api . PodAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] api . PodAffinityTerm {
{ MatchLabelKeys : [ ] string { "foo" } , MismatchLabelKeys : [ ] string { "foo" } } ,
} ,
} ,
} ,
} ,
wantPodSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAffinity : & api . PodAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] api . PodAffinityTerm {
{ MatchLabelKeys : [ ] string { "foo" } , MismatchLabelKeys : [ ] string { "foo" } } ,
} ,
} ,
} ,
} ,
} ,
{
name : "[PodAffinity/preferred] feature disabled, both pods don't use MatchLabelKeys/MismatchLabelKeys fields" ,
enabled : false ,
oldPodSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAffinity : & api . PodAffinity {
PreferredDuringSchedulingIgnoredDuringExecution : [ ] api . WeightedPodAffinityTerm { } ,
} ,
} ,
} ,
podSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAffinity : & api . PodAffinity {
PreferredDuringSchedulingIgnoredDuringExecution : [ ] api . WeightedPodAffinityTerm { } ,
} ,
} ,
} ,
wantPodSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAffinity : & api . PodAffinity {
PreferredDuringSchedulingIgnoredDuringExecution : [ ] api . WeightedPodAffinityTerm { } ,
} ,
} ,
} ,
} ,
{
name : "[PodAffinity/preferred] feature disabled, only old pod uses MatchLabelKeys/MismatchLabelKeys field" ,
enabled : false ,
oldPodSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAffinity : & api . PodAffinity {
PreferredDuringSchedulingIgnoredDuringExecution : [ ] api . WeightedPodAffinityTerm {
{
PodAffinityTerm : api . PodAffinityTerm { MatchLabelKeys : [ ] string { "foo" } , MismatchLabelKeys : [ ] string { "foo" } } ,
} ,
} ,
} ,
} ,
} ,
podSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAffinity : & api . PodAffinity {
PreferredDuringSchedulingIgnoredDuringExecution : [ ] api . WeightedPodAffinityTerm { } ,
} ,
} ,
} ,
wantPodSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAffinity : & api . PodAffinity {
PreferredDuringSchedulingIgnoredDuringExecution : [ ] api . WeightedPodAffinityTerm { } ,
} ,
} ,
} ,
} ,
{
name : "[PodAffinity/preferred] feature disabled, only current pod uses MatchLabelKeys/MismatchLabelKeys field" ,
enabled : false ,
oldPodSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAffinity : & api . PodAffinity {
PreferredDuringSchedulingIgnoredDuringExecution : [ ] api . WeightedPodAffinityTerm { } ,
} ,
} ,
} ,
podSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAffinity : & api . PodAffinity {
PreferredDuringSchedulingIgnoredDuringExecution : [ ] api . WeightedPodAffinityTerm {
{
PodAffinityTerm : api . PodAffinityTerm { MatchLabelKeys : [ ] string { "foo" } , MismatchLabelKeys : [ ] string { "foo" } } ,
} ,
} ,
} ,
} ,
} ,
wantPodSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAffinity : & api . PodAffinity {
PreferredDuringSchedulingIgnoredDuringExecution : [ ] api . WeightedPodAffinityTerm { { } } ,
} ,
} ,
} ,
} ,
{
name : "[PodAffinity/preferred] feature disabled, both pods use MatchLabelKeys/MismatchLabelKeys fields" ,
enabled : false ,
oldPodSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAffinity : & api . PodAffinity {
PreferredDuringSchedulingIgnoredDuringExecution : [ ] api . WeightedPodAffinityTerm {
{
PodAffinityTerm : api . PodAffinityTerm { MatchLabelKeys : [ ] string { "foo" } , MismatchLabelKeys : [ ] string { "foo" } } ,
} ,
} ,
} ,
} ,
} ,
podSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAffinity : & api . PodAffinity {
PreferredDuringSchedulingIgnoredDuringExecution : [ ] api . WeightedPodAffinityTerm {
{
PodAffinityTerm : api . PodAffinityTerm { MatchLabelKeys : [ ] string { "foo" } , MismatchLabelKeys : [ ] string { "foo" } } ,
} ,
} ,
} ,
} ,
} ,
wantPodSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAffinity : & api . PodAffinity {
PreferredDuringSchedulingIgnoredDuringExecution : [ ] api . WeightedPodAffinityTerm {
{
PodAffinityTerm : api . PodAffinityTerm { MatchLabelKeys : [ ] string { "foo" } , MismatchLabelKeys : [ ] string { "foo" } } ,
} ,
} ,
} ,
} ,
} ,
} ,
{
name : "[PodAffinity/preferred] feature enabled, only old pod uses MatchLabelKeys/MismatchLabelKeys field" ,
enabled : true ,
oldPodSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAffinity : & api . PodAffinity {
PreferredDuringSchedulingIgnoredDuringExecution : [ ] api . WeightedPodAffinityTerm {
{
PodAffinityTerm : api . PodAffinityTerm { MatchLabelKeys : [ ] string { "foo" } , MismatchLabelKeys : [ ] string { "foo" } } ,
} ,
} ,
} ,
} ,
} ,
podSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAffinity : & api . PodAffinity {
PreferredDuringSchedulingIgnoredDuringExecution : [ ] api . WeightedPodAffinityTerm { } ,
} ,
} ,
} ,
wantPodSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAffinity : & api . PodAffinity {
PreferredDuringSchedulingIgnoredDuringExecution : [ ] api . WeightedPodAffinityTerm { } ,
} ,
} ,
} ,
} ,
{
name : "[PodAffinity/preferred] feature enabled, only current pod uses MatchLabelKeys/MismatchLabelKeys field" ,
enabled : true ,
oldPodSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAffinity : & api . PodAffinity {
PreferredDuringSchedulingIgnoredDuringExecution : [ ] api . WeightedPodAffinityTerm { } ,
} ,
} ,
} ,
podSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAffinity : & api . PodAffinity {
PreferredDuringSchedulingIgnoredDuringExecution : [ ] api . WeightedPodAffinityTerm {
{
PodAffinityTerm : api . PodAffinityTerm { MatchLabelKeys : [ ] string { "foo" } , MismatchLabelKeys : [ ] string { "foo" } } ,
} ,
} ,
} ,
} ,
} ,
wantPodSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAffinity : & api . PodAffinity {
PreferredDuringSchedulingIgnoredDuringExecution : [ ] api . WeightedPodAffinityTerm {
{
PodAffinityTerm : api . PodAffinityTerm { MatchLabelKeys : [ ] string { "foo" } , MismatchLabelKeys : [ ] string { "foo" } } ,
} ,
} ,
} ,
} ,
} ,
} ,
{
name : "[PodAffinity/preferred] feature enabled, both pods use MatchLabelKeys/MismatchLabelKeys fields" ,
enabled : false ,
oldPodSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAffinity : & api . PodAffinity {
PreferredDuringSchedulingIgnoredDuringExecution : [ ] api . WeightedPodAffinityTerm {
{
PodAffinityTerm : api . PodAffinityTerm { MatchLabelKeys : [ ] string { "foo" } , MismatchLabelKeys : [ ] string { "foo" } } ,
} ,
} ,
} ,
} ,
} ,
podSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAffinity : & api . PodAffinity {
PreferredDuringSchedulingIgnoredDuringExecution : [ ] api . WeightedPodAffinityTerm {
{
PodAffinityTerm : api . PodAffinityTerm { MatchLabelKeys : [ ] string { "foo" } , MismatchLabelKeys : [ ] string { "foo" } } ,
} ,
} ,
} ,
} ,
} ,
wantPodSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAffinity : & api . PodAffinity {
PreferredDuringSchedulingIgnoredDuringExecution : [ ] api . WeightedPodAffinityTerm {
{
PodAffinityTerm : api . PodAffinityTerm { MatchLabelKeys : [ ] string { "foo" } , MismatchLabelKeys : [ ] string { "foo" } } ,
} ,
} ,
} ,
} ,
} ,
} ,
{
name : "[PodAntiAffinity/required] feature disabled, both pods don't use MatchLabelKeys/MismatchLabelKeys fields" ,
enabled : false ,
oldPodSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAntiAffinity : & api . PodAntiAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] api . PodAffinityTerm { } ,
} ,
} ,
} ,
podSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAntiAffinity : & api . PodAntiAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] api . PodAffinityTerm { } ,
} ,
} ,
} ,
wantPodSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAntiAffinity : & api . PodAntiAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] api . PodAffinityTerm { } ,
} ,
} ,
} ,
} ,
{
name : "[PodAntiAffinity/required] feature disabled, only old pod uses MatchLabelKeys/MismatchLabelKeys field" ,
enabled : false ,
oldPodSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAntiAffinity : & api . PodAntiAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] api . PodAffinityTerm {
{ MatchLabelKeys : [ ] string { "foo" } , MismatchLabelKeys : [ ] string { "foo" } } ,
} ,
} ,
} ,
} ,
podSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAntiAffinity : & api . PodAntiAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] api . PodAffinityTerm { } ,
} ,
} ,
} ,
wantPodSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAntiAffinity : & api . PodAntiAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] api . PodAffinityTerm { } ,
} ,
} ,
} ,
} ,
{
name : "[PodAntiAffinity/required] feature disabled, only current pod uses MatchLabelKeys/MismatchLabelKeys field" ,
enabled : false ,
oldPodSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAntiAffinity : & api . PodAntiAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] api . PodAffinityTerm { } ,
} ,
} ,
} ,
podSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAntiAffinity : & api . PodAntiAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] api . PodAffinityTerm {
{ MatchLabelKeys : [ ] string { "foo" } , MismatchLabelKeys : [ ] string { "foo" } } ,
} ,
} ,
} ,
} ,
wantPodSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAntiAffinity : & api . PodAntiAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] api . PodAffinityTerm { { } } ,
} ,
} ,
} ,
} ,
{
name : "[PodAntiAffinity/required] feature disabled, both pods use MatchLabelKeys/MismatchLabelKeys fields" ,
enabled : false ,
oldPodSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAntiAffinity : & api . PodAntiAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] api . PodAffinityTerm {
{ MatchLabelKeys : [ ] string { "foo" } , MismatchLabelKeys : [ ] string { "foo" } } ,
} ,
} ,
} ,
} ,
podSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAntiAffinity : & api . PodAntiAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] api . PodAffinityTerm {
{ MatchLabelKeys : [ ] string { "foo" } , MismatchLabelKeys : [ ] string { "foo" } } ,
} ,
} ,
} ,
} ,
wantPodSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAntiAffinity : & api . PodAntiAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] api . PodAffinityTerm {
{ MatchLabelKeys : [ ] string { "foo" } , MismatchLabelKeys : [ ] string { "foo" } } ,
} ,
} ,
} ,
} ,
} ,
{
name : "[PodAntiAffinity/required] feature enabled, only old pod uses MatchLabelKeys/MismatchLabelKeys field" ,
enabled : true ,
oldPodSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAntiAffinity : & api . PodAntiAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] api . PodAffinityTerm {
{ MatchLabelKeys : [ ] string { "foo" } , MismatchLabelKeys : [ ] string { "foo" } } ,
} ,
} ,
} ,
} ,
podSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAntiAffinity : & api . PodAntiAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] api . PodAffinityTerm { } ,
} ,
} ,
} ,
wantPodSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAntiAffinity : & api . PodAntiAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] api . PodAffinityTerm { } ,
} ,
} ,
} ,
} ,
{
name : "[PodAntiAffinity/required] feature enabled, only current pod uses MatchLabelKeys/MismatchLabelKeys field" ,
enabled : true ,
oldPodSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAntiAffinity : & api . PodAntiAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] api . PodAffinityTerm { } ,
} ,
} ,
} ,
podSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAntiAffinity : & api . PodAntiAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] api . PodAffinityTerm {
{ MatchLabelKeys : [ ] string { "foo" } , MismatchLabelKeys : [ ] string { "foo" } } ,
} ,
} ,
} ,
} ,
wantPodSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAntiAffinity : & api . PodAntiAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] api . PodAffinityTerm {
{ MatchLabelKeys : [ ] string { "foo" } , MismatchLabelKeys : [ ] string { "foo" } } ,
} ,
} ,
} ,
} ,
} ,
{
name : "[PodAntiAffinity/required] feature enabled, both pods use MatchLabelKeys/MismatchLabelKeys fields" ,
enabled : false ,
oldPodSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAntiAffinity : & api . PodAntiAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] api . PodAffinityTerm {
{ MatchLabelKeys : [ ] string { "foo" } , MismatchLabelKeys : [ ] string { "foo" } } ,
} ,
} ,
} ,
} ,
podSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAntiAffinity : & api . PodAntiAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] api . PodAffinityTerm {
{ MatchLabelKeys : [ ] string { "foo" } , MismatchLabelKeys : [ ] string { "foo" } } ,
} ,
} ,
} ,
} ,
wantPodSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAntiAffinity : & api . PodAntiAffinity {
RequiredDuringSchedulingIgnoredDuringExecution : [ ] api . PodAffinityTerm {
{ MatchLabelKeys : [ ] string { "foo" } , MismatchLabelKeys : [ ] string { "foo" } } ,
} ,
} ,
} ,
} ,
} ,
{
name : "[PodAntiAffinity/preferred] feature disabled, both pods don't use MatchLabelKeys/MismatchLabelKeys fields" ,
enabled : false ,
oldPodSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAntiAffinity : & api . PodAntiAffinity {
PreferredDuringSchedulingIgnoredDuringExecution : [ ] api . WeightedPodAffinityTerm { } ,
} ,
} ,
} ,
podSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAntiAffinity : & api . PodAntiAffinity {
PreferredDuringSchedulingIgnoredDuringExecution : [ ] api . WeightedPodAffinityTerm { } ,
} ,
} ,
} ,
wantPodSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAntiAffinity : & api . PodAntiAffinity {
PreferredDuringSchedulingIgnoredDuringExecution : [ ] api . WeightedPodAffinityTerm { } ,
} ,
} ,
} ,
} ,
{
name : "[PodAntiAffinity/preferred] feature disabled, only old pod uses MatchLabelKeys/MismatchLabelKeys field" ,
enabled : false ,
oldPodSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAntiAffinity : & api . PodAntiAffinity {
PreferredDuringSchedulingIgnoredDuringExecution : [ ] api . WeightedPodAffinityTerm {
{
PodAffinityTerm : api . PodAffinityTerm { MatchLabelKeys : [ ] string { "foo" } , MismatchLabelKeys : [ ] string { "foo" } } ,
} ,
} ,
} ,
} ,
} ,
podSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAntiAffinity : & api . PodAntiAffinity {
PreferredDuringSchedulingIgnoredDuringExecution : [ ] api . WeightedPodAffinityTerm { } ,
} ,
} ,
} ,
wantPodSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAntiAffinity : & api . PodAntiAffinity {
PreferredDuringSchedulingIgnoredDuringExecution : [ ] api . WeightedPodAffinityTerm { } ,
} ,
} ,
} ,
} ,
{
name : "[PodAntiAffinity/preferred] feature disabled, only current pod uses MatchLabelKeys/MismatchLabelKeys field" ,
enabled : false ,
oldPodSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAntiAffinity : & api . PodAntiAffinity {
PreferredDuringSchedulingIgnoredDuringExecution : [ ] api . WeightedPodAffinityTerm { } ,
} ,
} ,
} ,
podSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAntiAffinity : & api . PodAntiAffinity {
PreferredDuringSchedulingIgnoredDuringExecution : [ ] api . WeightedPodAffinityTerm {
{
PodAffinityTerm : api . PodAffinityTerm { MatchLabelKeys : [ ] string { "foo" } , MismatchLabelKeys : [ ] string { "foo" } } ,
} ,
} ,
} ,
} ,
} ,
wantPodSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAntiAffinity : & api . PodAntiAffinity {
PreferredDuringSchedulingIgnoredDuringExecution : [ ] api . WeightedPodAffinityTerm { { } } ,
} ,
} ,
} ,
} ,
{
name : "[PodAntiAffinity/preferred] feature disabled, both pods use MatchLabelKeys/MismatchLabelKeys fields" ,
enabled : false ,
oldPodSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAntiAffinity : & api . PodAntiAffinity {
PreferredDuringSchedulingIgnoredDuringExecution : [ ] api . WeightedPodAffinityTerm {
{
PodAffinityTerm : api . PodAffinityTerm { MatchLabelKeys : [ ] string { "foo" } , MismatchLabelKeys : [ ] string { "foo" } } ,
} ,
} ,
} ,
} ,
} ,
podSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAntiAffinity : & api . PodAntiAffinity {
PreferredDuringSchedulingIgnoredDuringExecution : [ ] api . WeightedPodAffinityTerm {
{
PodAffinityTerm : api . PodAffinityTerm { MatchLabelKeys : [ ] string { "foo" } , MismatchLabelKeys : [ ] string { "foo" } } ,
} ,
} ,
} ,
} ,
} ,
wantPodSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAntiAffinity : & api . PodAntiAffinity {
PreferredDuringSchedulingIgnoredDuringExecution : [ ] api . WeightedPodAffinityTerm {
{
PodAffinityTerm : api . PodAffinityTerm { MatchLabelKeys : [ ] string { "foo" } , MismatchLabelKeys : [ ] string { "foo" } } ,
} ,
} ,
} ,
} ,
} ,
} ,
{
name : "[PodAntiAffinity/preferred] feature enabled, only old pod uses MatchLabelKeys/MismatchLabelKeys field" ,
enabled : true ,
oldPodSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAntiAffinity : & api . PodAntiAffinity {
PreferredDuringSchedulingIgnoredDuringExecution : [ ] api . WeightedPodAffinityTerm {
{
PodAffinityTerm : api . PodAffinityTerm { MatchLabelKeys : [ ] string { "foo" } , MismatchLabelKeys : [ ] string { "foo" } } ,
} ,
} ,
} ,
} ,
} ,
podSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAntiAffinity : & api . PodAntiAffinity {
PreferredDuringSchedulingIgnoredDuringExecution : [ ] api . WeightedPodAffinityTerm { } ,
} ,
} ,
} ,
wantPodSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAntiAffinity : & api . PodAntiAffinity {
PreferredDuringSchedulingIgnoredDuringExecution : [ ] api . WeightedPodAffinityTerm { } ,
} ,
} ,
} ,
} ,
{
name : "[PodAntiAffinity/preferred] feature enabled, only current pod uses MatchLabelKeys/MismatchLabelKeys field" ,
enabled : true ,
oldPodSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAntiAffinity : & api . PodAntiAffinity {
PreferredDuringSchedulingIgnoredDuringExecution : [ ] api . WeightedPodAffinityTerm { } ,
} ,
} ,
} ,
podSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAntiAffinity : & api . PodAntiAffinity {
PreferredDuringSchedulingIgnoredDuringExecution : [ ] api . WeightedPodAffinityTerm {
{
PodAffinityTerm : api . PodAffinityTerm { MatchLabelKeys : [ ] string { "foo" } , MismatchLabelKeys : [ ] string { "foo" } } ,
} ,
} ,
} ,
} ,
} ,
wantPodSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAntiAffinity : & api . PodAntiAffinity {
PreferredDuringSchedulingIgnoredDuringExecution : [ ] api . WeightedPodAffinityTerm {
{
PodAffinityTerm : api . PodAffinityTerm { MatchLabelKeys : [ ] string { "foo" } , MismatchLabelKeys : [ ] string { "foo" } } ,
} ,
} ,
} ,
} ,
} ,
} ,
{
name : "[PodAntiAffinity/preferred] feature enabled, both pods use MatchLabelKeys/MismatchLabelKeys fields" ,
enabled : false ,
oldPodSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAntiAffinity : & api . PodAntiAffinity {
PreferredDuringSchedulingIgnoredDuringExecution : [ ] api . WeightedPodAffinityTerm {
{
PodAffinityTerm : api . PodAffinityTerm { MatchLabelKeys : [ ] string { "foo" } , MismatchLabelKeys : [ ] string { "foo" } } ,
} ,
} ,
} ,
} ,
} ,
podSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAntiAffinity : & api . PodAntiAffinity {
PreferredDuringSchedulingIgnoredDuringExecution : [ ] api . WeightedPodAffinityTerm {
{
PodAffinityTerm : api . PodAffinityTerm { MatchLabelKeys : [ ] string { "foo" } , MismatchLabelKeys : [ ] string { "foo" } } ,
} ,
} ,
} ,
} ,
} ,
wantPodSpec : & api . PodSpec {
Affinity : & api . Affinity {
PodAntiAffinity : & api . PodAntiAffinity {
PreferredDuringSchedulingIgnoredDuringExecution : [ ] api . WeightedPodAffinityTerm {
{
PodAffinityTerm : api . PodAffinityTerm { MatchLabelKeys : [ ] string { "foo" } , MismatchLabelKeys : [ ] string { "foo" } } ,
} ,
} ,
} ,
} ,
} ,
} ,
}
for _ , test := range tests {
t . Run ( test . name , func ( t * testing . T ) {
defer featuregatetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . MatchLabelKeysInPodAffinity , test . enabled ) ( )
dropDisabledFields ( test . podSpec , nil , test . oldPodSpec , nil )
if diff := cmp . Diff ( test . wantPodSpec , test . podSpec ) ; diff != "" {
t . Errorf ( "unexpected pod spec (-want, +got):\n%s" , diff )
}
} )
}
}
func Test_dropDisabledMatchLabelKeysFieldInTopologySpread ( t * testing . T ) {
2022-07-30 01:21:16 -04:00
tests := [ ] struct {
name string
enabled bool
podSpec * api . PodSpec
oldPodSpec * api . PodSpec
wantPodSpec * api . PodSpec
} {
{
name : "feature disabled, both pods don't use MatchLabelKeys fields" ,
enabled : false ,
oldPodSpec : & api . PodSpec {
TopologySpreadConstraints : [ ] api . TopologySpreadConstraint { } ,
} ,
podSpec : & api . PodSpec {
TopologySpreadConstraints : [ ] api . TopologySpreadConstraint { } ,
} ,
wantPodSpec : & api . PodSpec {
TopologySpreadConstraints : [ ] api . TopologySpreadConstraint { } ,
} ,
} ,
{
name : "feature disabled, only old pod uses MatchLabelKeys field" ,
enabled : false ,
oldPodSpec : & api . PodSpec {
TopologySpreadConstraints : [ ] api . TopologySpreadConstraint {
{ MatchLabelKeys : [ ] string { "foo" } } ,
} ,
} ,
podSpec : & api . PodSpec {
TopologySpreadConstraints : [ ] api . TopologySpreadConstraint { } ,
} ,
wantPodSpec : & api . PodSpec {
TopologySpreadConstraints : [ ] api . TopologySpreadConstraint { } ,
} ,
} ,
{
name : "feature disabled, only current pod uses MatchLabelKeys field" ,
enabled : false ,
oldPodSpec : & api . PodSpec {
TopologySpreadConstraints : [ ] api . TopologySpreadConstraint { } ,
} ,
podSpec : & api . PodSpec {
TopologySpreadConstraints : [ ] api . TopologySpreadConstraint {
{ MatchLabelKeys : [ ] string { "foo" } } ,
} ,
} ,
wantPodSpec : & api . PodSpec {
TopologySpreadConstraints : [ ] api . TopologySpreadConstraint { { } } ,
} ,
} ,
{
name : "feature disabled, both pods use MatchLabelKeys fields" ,
enabled : false ,
oldPodSpec : & api . PodSpec {
TopologySpreadConstraints : [ ] api . TopologySpreadConstraint {
{ MatchLabelKeys : [ ] string { "foo" } } ,
} ,
} ,
podSpec : & api . PodSpec {
TopologySpreadConstraints : [ ] api . TopologySpreadConstraint {
{ MatchLabelKeys : [ ] string { "foo" } } ,
} ,
} ,
wantPodSpec : & api . PodSpec {
TopologySpreadConstraints : [ ] api . TopologySpreadConstraint {
{ MatchLabelKeys : [ ] string { "foo" } } ,
} ,
} ,
} ,
{
name : "feature enabled, only old pod uses MatchLabelKeys field" ,
enabled : true ,
oldPodSpec : & api . PodSpec {
TopologySpreadConstraints : [ ] api . TopologySpreadConstraint {
{ MatchLabelKeys : [ ] string { "foo" } } ,
} ,
} ,
podSpec : & api . PodSpec {
TopologySpreadConstraints : [ ] api . TopologySpreadConstraint { } ,
} ,
wantPodSpec : & api . PodSpec {
TopologySpreadConstraints : [ ] api . TopologySpreadConstraint { } ,
} ,
} ,
{
name : "feature enabled, only current pod uses MatchLabelKeys field" ,
enabled : true ,
oldPodSpec : & api . PodSpec {
TopologySpreadConstraints : [ ] api . TopologySpreadConstraint { } ,
} ,
podSpec : & api . PodSpec {
TopologySpreadConstraints : [ ] api . TopologySpreadConstraint {
{ MatchLabelKeys : [ ] string { "foo" } } ,
} ,
} ,
wantPodSpec : & api . PodSpec {
TopologySpreadConstraints : [ ] api . TopologySpreadConstraint {
{ MatchLabelKeys : [ ] string { "foo" } } ,
} ,
} ,
} ,
{
name : "feature enabled, both pods use MatchLabelKeys fields" ,
enabled : false ,
oldPodSpec : & api . PodSpec {
TopologySpreadConstraints : [ ] api . TopologySpreadConstraint {
{ MatchLabelKeys : [ ] string { "foo" } } ,
} ,
} ,
podSpec : & api . PodSpec {
TopologySpreadConstraints : [ ] api . TopologySpreadConstraint {
{ MatchLabelKeys : [ ] string { "foo" } } ,
} ,
} ,
wantPodSpec : & api . PodSpec {
TopologySpreadConstraints : [ ] api . TopologySpreadConstraint {
{ MatchLabelKeys : [ ] string { "foo" } } ,
} ,
} ,
} ,
}
for _ , test := range tests {
t . Run ( test . name , func ( t * testing . T ) {
defer featuregatetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . MatchLabelKeysInPodTopologySpread , test . enabled ) ( )
dropDisabledFields ( test . podSpec , nil , test . oldPodSpec , nil )
if diff := cmp . Diff ( test . wantPodSpec , test . podSpec ) ; diff != "" {
t . Errorf ( "unexpected pod spec (-want, +got):\n%s" , diff )
}
} )
}
}
2022-07-07 10:49:39 -04:00
func TestDropHostUsers ( t * testing . T ) {
falseVar := false
trueVar := true
podWithoutHostUsers := func ( ) * api . Pod {
return & api . Pod {
Spec : api . PodSpec {
SecurityContext : & api . PodSecurityContext { } } ,
}
}
podWithHostUsersFalse := func ( ) * api . Pod {
return & api . Pod {
Spec : api . PodSpec {
SecurityContext : & api . PodSecurityContext {
HostUsers : & falseVar ,
} ,
} ,
}
}
podWithHostUsersTrue := func ( ) * api . Pod {
return & api . Pod {
Spec : api . PodSpec {
SecurityContext : & api . PodSecurityContext {
HostUsers : & trueVar ,
} ,
} ,
}
}
podInfo := [ ] struct {
description string
hasHostUsers bool
pod func ( ) * api . Pod
} {
{
description : "with hostUsers=true" ,
hasHostUsers : true ,
pod : podWithHostUsersTrue ,
} ,
{
description : "with hostUsers=false" ,
hasHostUsers : true ,
pod : podWithHostUsersFalse ,
} ,
{
description : "with hostUsers=nil" ,
pod : func ( ) * api . Pod { return nil } ,
} ,
}
for _ , enabled := range [ ] bool { true , false } {
for _ , oldPodInfo := range podInfo {
for _ , newPodInfo := range podInfo {
oldPodHasHostUsers , oldPod := oldPodInfo . hasHostUsers , oldPodInfo . pod ( )
newPodHasHostUsers , newPod := newPodInfo . hasHostUsers , newPodInfo . pod ( )
if newPod == nil {
continue
}
t . Run ( fmt . Sprintf ( "feature enabled=%v, old pod %v, new pod %v" , enabled , oldPodInfo . description , newPodInfo . description ) , func ( t * testing . T ) {
2023-06-22 09:18:22 -04:00
defer featuregatetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . UserNamespacesSupport , enabled ) ( )
2022-07-07 10:49:39 -04:00
DropDisabledPodFields ( newPod , oldPod )
// old pod should never be changed
if ! reflect . DeepEqual ( oldPod , oldPodInfo . pod ( ) ) {
t . Errorf ( "old pod changed: %v" , cmp . Diff ( oldPod , oldPodInfo . pod ( ) ) )
}
switch {
case enabled || oldPodHasHostUsers :
// new pod should not be changed if the feature is enabled, or if the old pod had hostUsers
if ! reflect . DeepEqual ( newPod , newPodInfo . pod ( ) ) {
t . Errorf ( "new pod changed: %v" , cmp . Diff ( newPod , newPodInfo . pod ( ) ) )
}
case newPodHasHostUsers :
// new pod should be changed
if reflect . DeepEqual ( newPod , newPodInfo . pod ( ) ) {
t . Errorf ( "new pod was not changed" )
}
// new pod should not have hostUsers
if exp := podWithoutHostUsers ( ) ; ! reflect . DeepEqual ( newPod , exp ) {
t . Errorf ( "new pod had hostUsers: %v" , cmp . Diff ( newPod , exp ) )
}
default :
// new pod should not need to be changed
if ! reflect . DeepEqual ( newPod , newPodInfo . pod ( ) ) {
t . Errorf ( "new pod changed: %v" , cmp . Diff ( newPod , newPodInfo . pod ( ) ) )
}
}
} )
}
}
}
}
2022-10-28 15:05:46 -04:00
func TestDropSchedulingGates ( t * testing . T ) {
podWithSchedulingGates := func ( ) * api . Pod {
return & api . Pod {
Spec : api . PodSpec {
SchedulingGates : [ ] api . PodSchedulingGate {
{ Name : "foo" } ,
{ Name : "bar" } ,
} ,
} ,
}
}
podWithoutSchedulingGates := func ( ) * api . Pod { return & api . Pod { } }
podInfo := [ ] struct {
description string
hasSchedulingGatesField bool
pod func ( ) * api . Pod
} {
{
description : "has SchedulingGates field" ,
hasSchedulingGatesField : true ,
pod : podWithSchedulingGates ,
} ,
{
description : "does not have SchedulingGates field" ,
hasSchedulingGatesField : false ,
pod : podWithoutSchedulingGates ,
} ,
{
description : "is nil" ,
hasSchedulingGatesField : false ,
pod : func ( ) * api . Pod { return nil } ,
} ,
}
for _ , enabled := range [ ] bool { true , false } {
for _ , oldPodInfo := range podInfo {
for _ , newPodInfo := range podInfo {
oldPodHasSchedulingGates , oldPod := oldPodInfo . hasSchedulingGatesField , oldPodInfo . pod ( )
newPodHasSchedulingGates , newPod := newPodInfo . hasSchedulingGatesField , newPodInfo . pod ( )
if newPod == nil {
continue
}
t . Run ( fmt . Sprintf ( "feature enabled=%v, old pod %v, new pod %v" , enabled , oldPodInfo . description , newPodInfo . description ) , func ( t * testing . T ) {
defer featuregatetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . PodSchedulingReadiness , enabled ) ( )
var oldPodSpec * api . PodSpec
if oldPod != nil {
oldPodSpec = & oldPod . Spec
}
dropDisabledFields ( & newPod . Spec , nil , oldPodSpec , nil )
// Old Pod should never be changed.
if diff := cmp . Diff ( oldPod , oldPodInfo . pod ( ) ) ; diff != "" {
t . Errorf ( "old pod changed: %v" , diff )
}
switch {
case enabled || oldPodHasSchedulingGates :
// New Pod should not be changed if the feature is enabled, or if the old Pod had schedulingGates.
if diff := cmp . Diff ( newPod , newPodInfo . pod ( ) ) ; diff != "" {
t . Errorf ( "new pod changed: %v" , diff )
}
case newPodHasSchedulingGates :
// New Pod should be changed.
if reflect . DeepEqual ( newPod , newPodInfo . pod ( ) ) {
t . Errorf ( "new pod was not changed" )
}
// New Pod should not have SchedulingGates field.
if diff := cmp . Diff ( newPod , podWithoutSchedulingGates ( ) ) ; diff != "" {
t . Errorf ( "new pod has SchedulingGates field: %v" , diff )
}
default :
// New pod should not need to be changed.
if diff := cmp . Diff ( newPod , newPodInfo . pod ( ) ) ; diff != "" {
t . Errorf ( "new pod changed: %v" , diff )
}
}
} )
}
}
}
}
2022-08-11 09:21:06 -04:00
func TestValidateTopologySpreadConstraintLabelSelectorOption ( t * testing . T ) {
testCases := [ ] struct {
name string
oldPodSpec * api . PodSpec
wantOption bool
} {
{
name : "Create" ,
wantOption : false ,
} ,
{
name : "UpdateInvalidLabelSelector" ,
oldPodSpec : & api . PodSpec {
TopologySpreadConstraints : [ ] api . TopologySpreadConstraint {
{
LabelSelector : & metav1 . LabelSelector {
MatchLabels : map [ string ] string { "NoUppercaseOrSpecialCharsLike=Equals" : "foo" } ,
} ,
} ,
} ,
} ,
wantOption : true ,
} ,
{
name : "UpdateValidLabelSelector" ,
oldPodSpec : & api . PodSpec {
TopologySpreadConstraints : [ ] api . TopologySpreadConstraint {
{
LabelSelector : & metav1 . LabelSelector {
MatchLabels : map [ string ] string { "foo" : "foo" } ,
} ,
} ,
} ,
} ,
wantOption : false ,
} ,
{
name : "UpdateEmptyLabelSelector" ,
oldPodSpec : & api . PodSpec {
TopologySpreadConstraints : [ ] api . TopologySpreadConstraint {
{
LabelSelector : nil ,
} ,
} ,
} ,
wantOption : false ,
} ,
}
for _ , tc := range testCases {
t . Run ( tc . name , func ( t * testing . T ) {
// Pod meta doesn't impact the outcome.
gotOptions := GetValidationOptionsFromPodSpecAndMeta ( & api . PodSpec { } , tc . oldPodSpec , nil , nil )
if tc . wantOption != gotOptions . AllowInvalidTopologySpreadConstraintLabelSelector {
t . Errorf ( "Got AllowInvalidLabelValueInSelector=%t, want %t" , gotOptions . AllowInvalidTopologySpreadConstraintLabelSelector , tc . wantOption )
}
} )
}
}
2023-02-21 09:36:55 -05:00
2021-11-03 18:43:43 -04:00
func TestDropInPlacePodVerticalScaling ( t * testing . T ) {
podWithInPlaceVerticalScaling := func ( ) * api . Pod {
return & api . Pod {
Spec : api . PodSpec {
Containers : [ ] api . Container {
{
Name : "c1" ,
Image : "image" ,
Resources : api . ResourceRequirements {
Requests : api . ResourceList { api . ResourceCPU : resource . MustParse ( "100m" ) } ,
Limits : api . ResourceList { api . ResourceCPU : resource . MustParse ( "200m" ) } ,
} ,
ResizePolicy : [ ] api . ContainerResizePolicy {
2023-03-09 20:57:14 -05:00
{ ResourceName : api . ResourceCPU , RestartPolicy : api . NotRequired } ,
2023-02-28 02:30:31 -05:00
{ ResourceName : api . ResourceMemory , RestartPolicy : api . RestartContainer } ,
2021-11-03 18:43:43 -04:00
} ,
} ,
} ,
} ,
Status : api . PodStatus {
Resize : api . PodResizeStatusInProgress ,
ContainerStatuses : [ ] api . ContainerStatus {
{
Name : "c1" ,
Image : "image" ,
2023-03-09 22:35:35 -05:00
AllocatedResources : api . ResourceList { api . ResourceCPU : resource . MustParse ( "100m" ) } ,
2021-11-03 18:43:43 -04:00
Resources : & api . ResourceRequirements {
Requests : api . ResourceList { api . ResourceCPU : resource . MustParse ( "200m" ) } ,
Limits : api . ResourceList { api . ResourceCPU : resource . MustParse ( "300m" ) } ,
} ,
} ,
} ,
} ,
}
}
podWithoutInPlaceVerticalScaling := func ( ) * api . Pod {
return & api . Pod {
Spec : api . PodSpec {
Containers : [ ] api . Container {
{
Name : "c1" ,
Image : "image" ,
Resources : api . ResourceRequirements {
Requests : api . ResourceList { api . ResourceCPU : resource . MustParse ( "100m" ) } ,
Limits : api . ResourceList { api . ResourceCPU : resource . MustParse ( "200m" ) } ,
} ,
} ,
} ,
} ,
Status : api . PodStatus {
ContainerStatuses : [ ] api . ContainerStatus {
{
Name : "c1" ,
Image : "image" ,
} ,
} ,
} ,
}
}
podInfo := [ ] struct {
description string
hasInPlaceVerticalScaling bool
pod func ( ) * api . Pod
} {
{
description : "has in-place vertical scaling enabled with resources" ,
hasInPlaceVerticalScaling : true ,
pod : podWithInPlaceVerticalScaling ,
} ,
{
description : "has in-place vertical scaling disabled" ,
hasInPlaceVerticalScaling : false ,
pod : podWithoutInPlaceVerticalScaling ,
} ,
{
description : "is nil" ,
hasInPlaceVerticalScaling : false ,
pod : func ( ) * api . Pod { return nil } ,
} ,
}
for _ , enabled := range [ ] bool { true , false } {
for _ , oldPodInfo := range podInfo {
for _ , newPodInfo := range podInfo {
oldPodHasInPlaceVerticalScaling , oldPod := oldPodInfo . hasInPlaceVerticalScaling , oldPodInfo . pod ( )
newPodHasInPlaceVerticalScaling , newPod := newPodInfo . hasInPlaceVerticalScaling , newPodInfo . pod ( )
if newPod == nil {
continue
}
t . Run ( fmt . Sprintf ( "feature enabled=%v, old pod %v, new pod %v" , enabled , oldPodInfo . description , newPodInfo . description ) , func ( t * testing . T ) {
defer featuregatetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . InPlacePodVerticalScaling , enabled ) ( )
var oldPodSpec * api . PodSpec
var oldPodStatus * api . PodStatus
if oldPod != nil {
oldPodSpec = & oldPod . Spec
oldPodStatus = & oldPod . Status
}
dropDisabledFields ( & newPod . Spec , nil , oldPodSpec , nil )
dropDisabledPodStatusFields ( & newPod . Status , oldPodStatus , & newPod . Spec , oldPodSpec )
// old pod should never be changed
if ! reflect . DeepEqual ( oldPod , oldPodInfo . pod ( ) ) {
2023-03-23 14:34:03 -04:00
t . Errorf ( "old pod changed: %v" , cmp . Diff ( oldPod , oldPodInfo . pod ( ) ) )
2021-11-03 18:43:43 -04:00
}
switch {
case enabled || oldPodHasInPlaceVerticalScaling :
// new pod shouldn't change if feature enabled or if old pod has ResizePolicy set
if ! reflect . DeepEqual ( newPod , newPodInfo . pod ( ) ) {
2023-03-23 14:34:03 -04:00
t . Errorf ( "new pod changed: %v" , cmp . Diff ( newPod , newPodInfo . pod ( ) ) )
2021-11-03 18:43:43 -04:00
}
case newPodHasInPlaceVerticalScaling :
// new pod should be changed
if reflect . DeepEqual ( newPod , newPodInfo . pod ( ) ) {
t . Errorf ( "new pod was not changed" )
}
// new pod should not have ResizePolicy
if ! reflect . DeepEqual ( newPod , podWithoutInPlaceVerticalScaling ( ) ) {
2023-03-23 14:34:03 -04:00
t . Errorf ( "new pod has ResizePolicy: %v" , cmp . Diff ( newPod , podWithoutInPlaceVerticalScaling ( ) ) )
2021-11-03 18:43:43 -04:00
}
default :
// new pod should not need to be changed
if ! reflect . DeepEqual ( newPod , newPodInfo . pod ( ) ) {
2023-03-23 14:34:03 -04:00
t . Errorf ( "new pod changed: %v" , cmp . Diff ( newPod , newPodInfo . pod ( ) ) )
2021-11-03 18:43:43 -04:00
}
}
} )
}
}
}
}
2023-05-09 12:34:46 -04:00
func TestDropSidecarContainers ( t * testing . T ) {
containerRestartPolicyAlways := api . ContainerRestartPolicyAlways
podWithSidecarContainers := func ( ) * api . Pod {
return & api . Pod {
Spec : api . PodSpec {
InitContainers : [ ] api . Container {
{
Name : "c1" ,
Image : "image" ,
RestartPolicy : & containerRestartPolicyAlways ,
} ,
} ,
} ,
}
}
podWithoutSidecarContainers := func ( ) * api . Pod {
return & api . Pod {
Spec : api . PodSpec {
InitContainers : [ ] api . Container {
{
Name : "c1" ,
Image : "image" ,
} ,
} ,
} ,
}
}
podInfo := [ ] struct {
description string
hasSidecarContainer bool
pod func ( ) * api . Pod
} {
{
description : "has a sidecar container" ,
hasSidecarContainer : true ,
pod : podWithSidecarContainers ,
} ,
{
description : "does not have a sidecar container" ,
hasSidecarContainer : false ,
pod : podWithoutSidecarContainers ,
} ,
{
description : "is nil" ,
hasSidecarContainer : false ,
pod : func ( ) * api . Pod { return nil } ,
} ,
}
for _ , enabled := range [ ] bool { true , false } {
for _ , oldPodInfo := range podInfo {
for _ , newPodInfo := range podInfo {
oldPodHasSidecarContainer , oldPod := oldPodInfo . hasSidecarContainer , oldPodInfo . pod ( )
newPodHasSidecarContainer , newPod := newPodInfo . hasSidecarContainer , newPodInfo . pod ( )
if newPod == nil {
continue
}
t . Run ( fmt . Sprintf ( "feature enabled=%v, old pod %v, new pod %v" , enabled , oldPodInfo . description , newPodInfo . description ) , func ( t * testing . T ) {
defer featuregatetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . SidecarContainers , enabled ) ( )
var oldPodSpec * api . PodSpec
if oldPod != nil {
oldPodSpec = & oldPod . Spec
}
dropDisabledFields ( & newPod . Spec , nil , oldPodSpec , nil )
// old pod should never be changed
if ! reflect . DeepEqual ( oldPod , oldPodInfo . pod ( ) ) {
t . Errorf ( "old pod changed: %v" , cmp . Diff ( oldPod , oldPodInfo . pod ( ) ) )
}
switch {
case enabled || oldPodHasSidecarContainer :
// new pod shouldn't change if feature enabled or if old pod has
// any sidecar container
if ! reflect . DeepEqual ( newPod , newPodInfo . pod ( ) ) {
t . Errorf ( "new pod changed: %v" , cmp . Diff ( newPod , newPodInfo . pod ( ) ) )
}
case newPodHasSidecarContainer :
// new pod should be changed
if reflect . DeepEqual ( newPod , newPodInfo . pod ( ) ) {
t . Errorf ( "new pod was not changed" )
}
// new pod should not have any sidecar container
if ! reflect . DeepEqual ( newPod , podWithoutSidecarContainers ( ) ) {
t . Errorf ( "new pod has a sidecar container: %v" , cmp . Diff ( newPod , podWithoutSidecarContainers ( ) ) )
}
default :
// new pod should not need to be changed
if ! reflect . DeepEqual ( newPod , newPodInfo . pod ( ) ) {
t . Errorf ( "new pod changed: %v" , cmp . Diff ( newPod , newPodInfo . pod ( ) ) )
}
}
} )
}
}
}
}
2021-11-03 18:43:43 -04:00
func TestMarkPodProposedForResize ( t * testing . T ) {
testCases := [ ] struct {
desc string
newPod * api . Pod
oldPod * api . Pod
expectedPod * api . Pod
} {
{
desc : "nil requests" ,
newPod : & api . Pod {
Spec : api . PodSpec {
Containers : [ ] api . Container {
{
Name : "c1" ,
Image : "image" ,
} ,
} ,
} ,
Status : api . PodStatus {
ContainerStatuses : [ ] api . ContainerStatus {
{
Name : "c1" ,
Image : "image" ,
} ,
} ,
} ,
} ,
oldPod : & api . Pod {
Spec : api . PodSpec {
Containers : [ ] api . Container {
{
Name : "c1" ,
Image : "image" ,
} ,
} ,
} ,
Status : api . PodStatus {
ContainerStatuses : [ ] api . ContainerStatus {
{
Name : "c1" ,
Image : "image" ,
} ,
} ,
} ,
} ,
expectedPod : & api . Pod {
Spec : api . PodSpec {
Containers : [ ] api . Container {
{
Name : "c1" ,
Image : "image" ,
} ,
} ,
} ,
Status : api . PodStatus {
ContainerStatuses : [ ] api . ContainerStatus {
{
Name : "c1" ,
Image : "image" ,
} ,
} ,
} ,
} ,
} ,
{
desc : "resources unchanged" ,
newPod : & api . Pod {
Spec : api . PodSpec {
Containers : [ ] api . Container {
{
Name : "c1" ,
Image : "image" ,
Resources : api . ResourceRequirements {
Requests : api . ResourceList { api . ResourceCPU : resource . MustParse ( "100m" ) } ,
Limits : api . ResourceList { api . ResourceCPU : resource . MustParse ( "200m" ) } ,
} ,
} ,
} ,
} ,
Status : api . PodStatus {
ContainerStatuses : [ ] api . ContainerStatus {
{
Name : "c1" ,
Image : "image" ,
} ,
} ,
} ,
} ,
oldPod : & api . Pod {
Spec : api . PodSpec {
Containers : [ ] api . Container {
{
Name : "c1" ,
Image : "image" ,
Resources : api . ResourceRequirements {
Requests : api . ResourceList { api . ResourceCPU : resource . MustParse ( "100m" ) } ,
Limits : api . ResourceList { api . ResourceCPU : resource . MustParse ( "200m" ) } ,
} ,
} ,
} ,
} ,
Status : api . PodStatus {
ContainerStatuses : [ ] api . ContainerStatus {
{
Name : "c1" ,
Image : "image" ,
} ,
} ,
} ,
} ,
expectedPod : & api . Pod {
Spec : api . PodSpec {
Containers : [ ] api . Container {
{
Name : "c1" ,
Image : "image" ,
Resources : api . ResourceRequirements {
Requests : api . ResourceList { api . ResourceCPU : resource . MustParse ( "100m" ) } ,
Limits : api . ResourceList { api . ResourceCPU : resource . MustParse ( "200m" ) } ,
} ,
} ,
} ,
} ,
Status : api . PodStatus {
ContainerStatuses : [ ] api . ContainerStatus {
{
Name : "c1" ,
Image : "image" ,
} ,
} ,
} ,
} ,
} ,
{
desc : "resize desired" ,
newPod : & api . Pod {
Spec : api . PodSpec {
Containers : [ ] api . Container {
{
Name : "c1" ,
Image : "image" ,
Resources : api . ResourceRequirements {
Requests : api . ResourceList { api . ResourceCPU : resource . MustParse ( "100m" ) } ,
Limits : api . ResourceList { api . ResourceCPU : resource . MustParse ( "200m" ) } ,
} ,
} ,
{
Name : "c2" ,
Image : "image" ,
Resources : api . ResourceRequirements {
Requests : api . ResourceList { api . ResourceCPU : resource . MustParse ( "300m" ) } ,
Limits : api . ResourceList { api . ResourceCPU : resource . MustParse ( "400m" ) } ,
} ,
} ,
} ,
} ,
Status : api . PodStatus {
ContainerStatuses : [ ] api . ContainerStatus {
{
Name : "c1" ,
Image : "image" ,
2023-03-09 22:35:35 -05:00
AllocatedResources : api . ResourceList { api . ResourceCPU : resource . MustParse ( "100m" ) } ,
2021-11-03 18:43:43 -04:00
} ,
{
Name : "c2" ,
Image : "image" ,
2023-03-09 22:35:35 -05:00
AllocatedResources : api . ResourceList { api . ResourceCPU : resource . MustParse ( "200m" ) } ,
2021-11-03 18:43:43 -04:00
} ,
} ,
} ,
} ,
oldPod : & api . Pod {
Spec : api . PodSpec {
Containers : [ ] api . Container {
{
Name : "c1" ,
Image : "image" ,
Resources : api . ResourceRequirements {
Requests : api . ResourceList { api . ResourceCPU : resource . MustParse ( "100m" ) } ,
Limits : api . ResourceList { api . ResourceCPU : resource . MustParse ( "200m" ) } ,
} ,
} ,
{
Name : "c2" ,
Image : "image" ,
Resources : api . ResourceRequirements {
Requests : api . ResourceList { api . ResourceCPU : resource . MustParse ( "200m" ) } ,
Limits : api . ResourceList { api . ResourceCPU : resource . MustParse ( "300m" ) } ,
} ,
} ,
} ,
} ,
Status : api . PodStatus {
ContainerStatuses : [ ] api . ContainerStatus {
{
Name : "c1" ,
Image : "image" ,
2023-03-09 22:35:35 -05:00
AllocatedResources : api . ResourceList { api . ResourceCPU : resource . MustParse ( "100m" ) } ,
2021-11-03 18:43:43 -04:00
} ,
{
Name : "c2" ,
Image : "image" ,
2023-03-09 22:35:35 -05:00
AllocatedResources : api . ResourceList { api . ResourceCPU : resource . MustParse ( "200m" ) } ,
2021-11-03 18:43:43 -04:00
} ,
} ,
} ,
} ,
expectedPod : & api . Pod {
Spec : api . PodSpec {
Containers : [ ] api . Container {
{
Name : "c1" ,
Image : "image" ,
Resources : api . ResourceRequirements {
Requests : api . ResourceList { api . ResourceCPU : resource . MustParse ( "100m" ) } ,
Limits : api . ResourceList { api . ResourceCPU : resource . MustParse ( "200m" ) } ,
} ,
} ,
{
Name : "c2" ,
Image : "image" ,
Resources : api . ResourceRequirements {
Requests : api . ResourceList { api . ResourceCPU : resource . MustParse ( "300m" ) } ,
Limits : api . ResourceList { api . ResourceCPU : resource . MustParse ( "400m" ) } ,
} ,
} ,
} ,
} ,
Status : api . PodStatus {
Resize : api . PodResizeStatusProposed ,
ContainerStatuses : [ ] api . ContainerStatus {
{
Name : "c1" ,
Image : "image" ,
2023-03-09 22:35:35 -05:00
AllocatedResources : api . ResourceList { api . ResourceCPU : resource . MustParse ( "100m" ) } ,
2021-11-03 18:43:43 -04:00
} ,
{
Name : "c2" ,
Image : "image" ,
2023-03-09 22:35:35 -05:00
AllocatedResources : api . ResourceList { api . ResourceCPU : resource . MustParse ( "200m" ) } ,
2021-11-03 18:43:43 -04:00
} ,
} ,
} ,
} ,
} ,
}
for _ , tc := range testCases {
t . Run ( tc . desc , func ( t * testing . T ) {
MarkPodProposedForResize ( tc . oldPod , tc . newPod )
if diff := cmp . Diff ( tc . expectedPod , tc . newPod ) ; diff != "" {
t . Errorf ( "unexpected pod spec (-want, +got):\n%s" , diff )
}
} )
}
}
2022-10-22 02:13:42 -04:00
func TestDropClusterTrustBundleProjectedVolumes ( t * testing . T ) {
testCases := [ ] struct {
description string
clusterTrustBundleProjectionEnabled bool
oldPod * api . PodSpec
newPod * api . PodSpec
wantPod * api . PodSpec
} {
{
description : "feature gate disabled, cannot add CTB volume to pod" ,
oldPod : & api . PodSpec {
Volumes : [ ] api . Volume { } ,
} ,
newPod : & api . PodSpec {
Volumes : [ ] api . Volume {
{
Name : "foo" ,
VolumeSource : api . VolumeSource {
Projected : & api . ProjectedVolumeSource {
Sources : [ ] api . VolumeProjection {
{
ClusterTrustBundle : & api . ClusterTrustBundleProjection {
Name : pointer . String ( "foo" ) ,
} ,
} ,
} ,
} } ,
} ,
} ,
} ,
wantPod : & api . PodSpec {
Volumes : [ ] api . Volume {
{
Name : "foo" ,
VolumeSource : api . VolumeSource {
Projected : & api . ProjectedVolumeSource {
Sources : [ ] api . VolumeProjection {
{ } ,
} ,
} } ,
} ,
} ,
} ,
} ,
{
description : "feature gate disabled, can keep CTB volume on pod" ,
oldPod : & api . PodSpec {
Volumes : [ ] api . Volume {
{
Name : "foo" ,
VolumeSource : api . VolumeSource {
Projected : & api . ProjectedVolumeSource {
Sources : [ ] api . VolumeProjection {
{
ClusterTrustBundle : & api . ClusterTrustBundleProjection {
Name : pointer . String ( "foo" ) ,
} ,
} ,
} ,
} } ,
} ,
} ,
} ,
newPod : & api . PodSpec {
Volumes : [ ] api . Volume {
{
Name : "foo" ,
VolumeSource : api . VolumeSource {
Projected : & api . ProjectedVolumeSource {
Sources : [ ] api . VolumeProjection {
{
ClusterTrustBundle : & api . ClusterTrustBundleProjection {
Name : pointer . String ( "foo" ) ,
} ,
} ,
} ,
} } ,
} ,
} ,
} ,
wantPod : & api . PodSpec {
Volumes : [ ] api . Volume {
{
Name : "foo" ,
VolumeSource : api . VolumeSource {
Projected : & api . ProjectedVolumeSource {
Sources : [ ] api . VolumeProjection {
{
ClusterTrustBundle : & api . ClusterTrustBundleProjection {
Name : pointer . String ( "foo" ) ,
} ,
} ,
} ,
} } ,
} ,
} ,
} ,
} ,
{
description : "feature gate enabled, can add CTB volume to pod" ,
clusterTrustBundleProjectionEnabled : true ,
oldPod : & api . PodSpec {
Volumes : [ ] api . Volume { } ,
} ,
newPod : & api . PodSpec {
Volumes : [ ] api . Volume {
{
Name : "foo" ,
VolumeSource : api . VolumeSource {
Projected : & api . ProjectedVolumeSource {
Sources : [ ] api . VolumeProjection {
{
ClusterTrustBundle : & api . ClusterTrustBundleProjection {
Name : pointer . String ( "foo" ) ,
} ,
} ,
} ,
} } ,
} ,
} ,
} ,
wantPod : & api . PodSpec {
Volumes : [ ] api . Volume {
{
Name : "foo" ,
VolumeSource : api . VolumeSource {
Projected : & api . ProjectedVolumeSource {
Sources : [ ] api . VolumeProjection {
{
ClusterTrustBundle : & api . ClusterTrustBundleProjection {
Name : pointer . String ( "foo" ) ,
} ,
} ,
} ,
} } ,
} ,
} ,
} ,
} ,
}
for _ , tc := range testCases {
t . Run ( tc . description , func ( t * testing . T ) {
defer featuregatetesting . SetFeatureGateDuringTest ( t , utilfeature . DefaultFeatureGate , features . ClusterTrustBundleProjection , tc . clusterTrustBundleProjectionEnabled ) ( )
dropDisabledClusterTrustBundleProjection ( tc . newPod , tc . oldPod )
if diff := cmp . Diff ( tc . newPod , tc . wantPod ) ; diff != "" {
t . Fatalf ( "Unexpected modification to new pod; diff (-got +want)\n%s" , diff )
}
} )
}
}