...

Source file src/k8s.io/kubernetes/pkg/apis/core/fuzzer/fuzzer.go

Documentation: k8s.io/kubernetes/pkg/apis/core/fuzzer

     1  /*
     2  Copyright 2017 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package fuzzer
    18  
    19  import (
    20  	"reflect"
    21  	"strconv"
    22  	"time"
    23  
    24  	fuzz "github.com/google/gofuzz"
    25  
    26  	v1 "k8s.io/api/core/v1"
    27  	"k8s.io/apimachinery/pkg/api/resource"
    28  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    29  	"k8s.io/apimachinery/pkg/runtime"
    30  	"k8s.io/apimachinery/pkg/runtime/schema"
    31  	runtimeserializer "k8s.io/apimachinery/pkg/runtime/serializer"
    32  	"k8s.io/apimachinery/pkg/util/intstr"
    33  	"k8s.io/kubernetes/pkg/apis/core"
    34  	utilpointer "k8s.io/utils/pointer"
    35  )
    36  
    37  // Funcs returns the fuzzer functions for the core group.
    38  var Funcs = func(codecs runtimeserializer.CodecFactory) []interface{} {
    39  	return []interface{}{
    40  		func(q *resource.Quantity, c fuzz.Continue) {
    41  			*q = *resource.NewQuantity(c.Int63n(1000), resource.DecimalExponent)
    42  		},
    43  		func(j *core.ObjectReference, c fuzz.Continue) {
    44  			// We have to customize the randomization of TypeMetas because their
    45  			// APIVersion and Kind must remain blank in memory.
    46  			j.APIVersion = c.RandString()
    47  			j.Kind = c.RandString()
    48  			j.Namespace = c.RandString()
    49  			j.Name = c.RandString()
    50  			j.ResourceVersion = strconv.FormatUint(c.RandUint64(), 10)
    51  			j.FieldPath = c.RandString()
    52  		},
    53  		func(j *core.PodExecOptions, c fuzz.Continue) {
    54  			j.Stdout = true
    55  			j.Stderr = true
    56  		},
    57  		func(j *core.PodAttachOptions, c fuzz.Continue) {
    58  			j.Stdout = true
    59  			j.Stderr = true
    60  		},
    61  		func(j *core.PodPortForwardOptions, c fuzz.Continue) {
    62  			if c.RandBool() {
    63  				j.Ports = make([]int32, c.Intn(10))
    64  				for i := range j.Ports {
    65  					j.Ports[i] = c.Int31n(65535)
    66  				}
    67  			}
    68  		},
    69  		func(s *core.PodSpec, c fuzz.Continue) {
    70  			c.FuzzNoCustom(s)
    71  			// has a default value
    72  			ttl := int64(30)
    73  			if c.RandBool() {
    74  				ttl = int64(c.Uint32())
    75  			}
    76  			s.TerminationGracePeriodSeconds = &ttl
    77  
    78  			c.Fuzz(s.SecurityContext)
    79  
    80  			if s.SecurityContext == nil {
    81  				s.SecurityContext = new(core.PodSecurityContext)
    82  			}
    83  			if s.Affinity == nil {
    84  				s.Affinity = new(core.Affinity)
    85  			}
    86  			if s.SchedulerName == "" {
    87  				s.SchedulerName = v1.DefaultSchedulerName
    88  			}
    89  			if s.EnableServiceLinks == nil {
    90  				enableServiceLinks := v1.DefaultEnableServiceLinks
    91  				s.EnableServiceLinks = &enableServiceLinks
    92  			}
    93  		},
    94  		func(s *core.PodStatus, c fuzz.Continue) {
    95  			c.Fuzz(&s)
    96  			s.HostIPs = []core.HostIP{{IP: s.HostIP}}
    97  		},
    98  		func(j *core.PodPhase, c fuzz.Continue) {
    99  			statuses := []core.PodPhase{core.PodPending, core.PodRunning, core.PodFailed, core.PodUnknown}
   100  			*j = statuses[c.Rand.Intn(len(statuses))]
   101  		},
   102  		func(j *core.Binding, c fuzz.Continue) {
   103  			c.Fuzz(&j.ObjectMeta)
   104  			j.Target.Name = c.RandString()
   105  		},
   106  		func(j *core.ReplicationController, c fuzz.Continue) {
   107  			c.FuzzNoCustom(j)
   108  
   109  			// match defaulting
   110  			if j.Spec.Template != nil {
   111  				if len(j.Labels) == 0 {
   112  					j.Labels = j.Spec.Template.Labels
   113  				}
   114  				if len(j.Spec.Selector) == 0 {
   115  					j.Spec.Selector = j.Spec.Template.Labels
   116  				}
   117  			}
   118  		},
   119  		func(j *core.ReplicationControllerSpec, c fuzz.Continue) {
   120  			c.FuzzNoCustom(j) // fuzz self without calling this function again
   121  			//j.TemplateRef = nil // this is required for round trip
   122  		},
   123  		func(j *core.List, c fuzz.Continue) {
   124  			c.FuzzNoCustom(j) // fuzz self without calling this function again
   125  			// TODO: uncomment when round trip starts from a versioned object
   126  			if false { //j.Items == nil {
   127  				j.Items = []runtime.Object{}
   128  			}
   129  		},
   130  		func(q *core.ResourceRequirements, c fuzz.Continue) {
   131  			randomQuantity := func() resource.Quantity {
   132  				var q resource.Quantity
   133  				c.Fuzz(&q)
   134  				// precalc the string for benchmarking purposes
   135  				_ = q.String()
   136  				return q
   137  			}
   138  			q.Limits = make(core.ResourceList)
   139  			q.Requests = make(core.ResourceList)
   140  			cpuLimit := randomQuantity()
   141  			q.Limits[core.ResourceCPU] = cpuLimit.DeepCopy()
   142  			q.Requests[core.ResourceCPU] = cpuLimit.DeepCopy()
   143  			memoryLimit := randomQuantity()
   144  			q.Limits[core.ResourceMemory] = memoryLimit.DeepCopy()
   145  			q.Requests[core.ResourceMemory] = memoryLimit.DeepCopy()
   146  			storageLimit := randomQuantity()
   147  			q.Limits[core.ResourceStorage] = storageLimit.DeepCopy()
   148  			q.Requests[core.ResourceStorage] = storageLimit.DeepCopy()
   149  		},
   150  		func(q *core.LimitRangeItem, c fuzz.Continue) {
   151  			var cpuLimit resource.Quantity
   152  			c.Fuzz(&cpuLimit)
   153  
   154  			q.Type = core.LimitTypeContainer
   155  			q.Default = make(core.ResourceList)
   156  			q.Default[core.ResourceCPU] = cpuLimit.DeepCopy()
   157  
   158  			q.DefaultRequest = make(core.ResourceList)
   159  			q.DefaultRequest[core.ResourceCPU] = cpuLimit.DeepCopy()
   160  
   161  			q.Max = make(core.ResourceList)
   162  			q.Max[core.ResourceCPU] = cpuLimit.DeepCopy()
   163  
   164  			q.Min = make(core.ResourceList)
   165  			q.Min[core.ResourceCPU] = cpuLimit.DeepCopy()
   166  
   167  			q.MaxLimitRequestRatio = make(core.ResourceList)
   168  			q.MaxLimitRequestRatio[core.ResourceCPU] = resource.MustParse("10")
   169  		},
   170  		func(p *core.PullPolicy, c fuzz.Continue) {
   171  			policies := []core.PullPolicy{core.PullAlways, core.PullNever, core.PullIfNotPresent}
   172  			*p = policies[c.Rand.Intn(len(policies))]
   173  		},
   174  		func(rp *core.RestartPolicy, c fuzz.Continue) {
   175  			policies := []core.RestartPolicy{core.RestartPolicyAlways, core.RestartPolicyNever, core.RestartPolicyOnFailure}
   176  			*rp = policies[c.Rand.Intn(len(policies))]
   177  		},
   178  		// core.DownwardAPIVolumeFile needs to have a specific func since FieldRef has to be
   179  		// defaulted to a version otherwise roundtrip will fail
   180  		func(m *core.DownwardAPIVolumeFile, c fuzz.Continue) {
   181  			m.Path = c.RandString()
   182  			versions := []string{"v1"}
   183  			m.FieldRef = &core.ObjectFieldSelector{}
   184  			m.FieldRef.APIVersion = versions[c.Rand.Intn(len(versions))]
   185  			m.FieldRef.FieldPath = c.RandString()
   186  			c.Fuzz(m.Mode)
   187  			if m.Mode != nil {
   188  				*m.Mode &= 0777
   189  			}
   190  		},
   191  		func(s *core.SecretVolumeSource, c fuzz.Continue) {
   192  			c.FuzzNoCustom(s) // fuzz self without calling this function again
   193  
   194  			if c.RandBool() {
   195  				opt := c.RandBool()
   196  				s.Optional = &opt
   197  			}
   198  			// DefaultMode should always be set, it has a default
   199  			// value and it is expected to be between 0 and 0777
   200  			var mode int32
   201  			c.Fuzz(&mode)
   202  			mode &= 0777
   203  			s.DefaultMode = &mode
   204  		},
   205  		func(cm *core.ConfigMapVolumeSource, c fuzz.Continue) {
   206  			c.FuzzNoCustom(cm) // fuzz self without calling this function again
   207  
   208  			if c.RandBool() {
   209  				opt := c.RandBool()
   210  				cm.Optional = &opt
   211  			}
   212  			// DefaultMode should always be set, it has a default
   213  			// value and it is expected to be between 0 and 0777
   214  			var mode int32
   215  			c.Fuzz(&mode)
   216  			mode &= 0777
   217  			cm.DefaultMode = &mode
   218  		},
   219  		func(d *core.DownwardAPIVolumeSource, c fuzz.Continue) {
   220  			c.FuzzNoCustom(d) // fuzz self without calling this function again
   221  
   222  			// DefaultMode should always be set, it has a default
   223  			// value and it is expected to be between 0 and 0777
   224  			var mode int32
   225  			c.Fuzz(&mode)
   226  			mode &= 0777
   227  			d.DefaultMode = &mode
   228  		},
   229  		func(s *core.ProjectedVolumeSource, c fuzz.Continue) {
   230  			c.FuzzNoCustom(s) // fuzz self without calling this function again
   231  
   232  			// DefaultMode should always be set, it has a default
   233  			// value and it is expected to be between 0 and 0777
   234  			var mode int32
   235  			c.Fuzz(&mode)
   236  			mode &= 0777
   237  			s.DefaultMode = &mode
   238  		},
   239  		func(k *core.KeyToPath, c fuzz.Continue) {
   240  			c.FuzzNoCustom(k) // fuzz self without calling this function again
   241  			k.Key = c.RandString()
   242  			k.Path = c.RandString()
   243  
   244  			// Mode is not mandatory, but if it is set, it should be
   245  			// a value between 0 and 0777
   246  			if k.Mode != nil {
   247  				*k.Mode &= 0777
   248  			}
   249  		},
   250  		func(vs *core.VolumeSource, c fuzz.Continue) {
   251  			// Exactly one of the fields must be set.
   252  			v := reflect.ValueOf(vs).Elem()
   253  			i := int(c.RandUint64() % uint64(v.NumField()))
   254  			t := v.Field(i).Addr()
   255  			for v.Field(i).IsNil() {
   256  				c.Fuzz(t.Interface())
   257  			}
   258  		},
   259  		func(i *core.ISCSIVolumeSource, c fuzz.Continue) {
   260  			i.ISCSIInterface = c.RandString()
   261  			if i.ISCSIInterface == "" {
   262  				i.ISCSIInterface = "default"
   263  			}
   264  		},
   265  		func(i *core.ISCSIPersistentVolumeSource, c fuzz.Continue) {
   266  			i.ISCSIInterface = c.RandString()
   267  			if i.ISCSIInterface == "" {
   268  				i.ISCSIInterface = "default"
   269  			}
   270  		},
   271  		func(i *core.PersistentVolumeClaimSpec, c fuzz.Continue) {
   272  			// Match defaulting in pkg/apis/core/v1/defaults.go.
   273  			volumeMode := core.PersistentVolumeMode(c.RandString())
   274  			if volumeMode == "" {
   275  				volumeMode = core.PersistentVolumeFilesystem
   276  			}
   277  			i.VolumeMode = &volumeMode
   278  		},
   279  		func(d *core.DNSPolicy, c fuzz.Continue) {
   280  			policies := []core.DNSPolicy{core.DNSClusterFirst, core.DNSDefault}
   281  			*d = policies[c.Rand.Intn(len(policies))]
   282  		},
   283  		func(p *core.Protocol, c fuzz.Continue) {
   284  			protocols := []core.Protocol{core.ProtocolTCP, core.ProtocolUDP, core.ProtocolSCTP}
   285  			*p = protocols[c.Rand.Intn(len(protocols))]
   286  		},
   287  		func(p *core.ServiceAffinity, c fuzz.Continue) {
   288  			types := []core.ServiceAffinity{core.ServiceAffinityClientIP, core.ServiceAffinityNone}
   289  			*p = types[c.Rand.Intn(len(types))]
   290  		},
   291  		func(p *core.ServiceType, c fuzz.Continue) {
   292  			types := []core.ServiceType{core.ServiceTypeClusterIP, core.ServiceTypeNodePort, core.ServiceTypeLoadBalancer}
   293  			*p = types[c.Rand.Intn(len(types))]
   294  		},
   295  		func(p *core.IPFamily, c fuzz.Continue) {
   296  			types := []core.IPFamily{core.IPv4Protocol, core.IPv6Protocol}
   297  			selected := types[c.Rand.Intn(len(types))]
   298  			*p = selected
   299  		},
   300  		func(p *core.ServiceExternalTrafficPolicy, c fuzz.Continue) {
   301  			types := []core.ServiceExternalTrafficPolicy{core.ServiceExternalTrafficPolicyCluster, core.ServiceExternalTrafficPolicyLocal}
   302  			*p = types[c.Rand.Intn(len(types))]
   303  		},
   304  		func(p *core.ServiceInternalTrafficPolicy, c fuzz.Continue) {
   305  			types := []core.ServiceInternalTrafficPolicy{core.ServiceInternalTrafficPolicyCluster, core.ServiceInternalTrafficPolicyLocal}
   306  			*p = types[c.Rand.Intn(len(types))]
   307  		},
   308  		func(ct *core.Container, c fuzz.Continue) {
   309  			c.FuzzNoCustom(ct)                                          // fuzz self without calling this function again
   310  			ct.TerminationMessagePath = "/" + ct.TerminationMessagePath // Must be non-empty
   311  			ct.TerminationMessagePolicy = "File"
   312  		},
   313  		func(ep *core.EphemeralContainer, c fuzz.Continue) {
   314  			c.FuzzNoCustom(ep)                                                                   // fuzz self without calling this function again
   315  			ep.EphemeralContainerCommon.TerminationMessagePath = "/" + ep.TerminationMessagePath // Must be non-empty
   316  			ep.EphemeralContainerCommon.TerminationMessagePolicy = "File"
   317  		},
   318  		func(p *core.Probe, c fuzz.Continue) {
   319  			c.FuzzNoCustom(p)
   320  			// These fields have default values.
   321  			intFieldsWithDefaults := [...]string{"TimeoutSeconds", "PeriodSeconds", "SuccessThreshold", "FailureThreshold"}
   322  			v := reflect.ValueOf(p).Elem()
   323  			for _, field := range intFieldsWithDefaults {
   324  				f := v.FieldByName(field)
   325  				if f.Int() == 0 {
   326  					f.SetInt(1)
   327  				}
   328  			}
   329  		},
   330  		func(ev *core.EnvVar, c fuzz.Continue) {
   331  			ev.Name = c.RandString()
   332  			if c.RandBool() {
   333  				ev.Value = c.RandString()
   334  			} else {
   335  				ev.ValueFrom = &core.EnvVarSource{}
   336  				ev.ValueFrom.FieldRef = &core.ObjectFieldSelector{}
   337  
   338  				versions := []schema.GroupVersion{
   339  					{Group: "admission.k8s.io", Version: "v1alpha1"},
   340  					{Group: "apps", Version: "v1beta1"},
   341  					{Group: "apps", Version: "v1beta2"},
   342  					{Group: "foo", Version: "v42"},
   343  				}
   344  
   345  				ev.ValueFrom.FieldRef.APIVersion = versions[c.Rand.Intn(len(versions))].String()
   346  				ev.ValueFrom.FieldRef.FieldPath = c.RandString()
   347  			}
   348  		},
   349  		func(ev *core.EnvFromSource, c fuzz.Continue) {
   350  			if c.RandBool() {
   351  				ev.Prefix = "p_"
   352  			}
   353  			if c.RandBool() {
   354  				c.Fuzz(&ev.ConfigMapRef)
   355  			} else {
   356  				c.Fuzz(&ev.SecretRef)
   357  			}
   358  		},
   359  		func(cm *core.ConfigMapEnvSource, c fuzz.Continue) {
   360  			c.FuzzNoCustom(cm) // fuzz self without calling this function again
   361  			if c.RandBool() {
   362  				opt := c.RandBool()
   363  				cm.Optional = &opt
   364  			}
   365  		},
   366  		func(s *core.SecretEnvSource, c fuzz.Continue) {
   367  			c.FuzzNoCustom(s) // fuzz self without calling this function again
   368  		},
   369  		func(sc *core.SecurityContext, c fuzz.Continue) {
   370  			c.FuzzNoCustom(sc) // fuzz self without calling this function again
   371  			if c.RandBool() {
   372  				priv := c.RandBool()
   373  				sc.Privileged = &priv
   374  			}
   375  
   376  			if c.RandBool() {
   377  				sc.Capabilities = &core.Capabilities{
   378  					Add:  make([]core.Capability, 0),
   379  					Drop: make([]core.Capability, 0),
   380  				}
   381  				c.Fuzz(&sc.Capabilities.Add)
   382  				c.Fuzz(&sc.Capabilities.Drop)
   383  			}
   384  		},
   385  		func(s *core.Secret, c fuzz.Continue) {
   386  			c.FuzzNoCustom(s) // fuzz self without calling this function again
   387  			s.Type = core.SecretTypeOpaque
   388  		},
   389  		func(r *core.RBDVolumeSource, c fuzz.Continue) {
   390  			r.RBDPool = c.RandString()
   391  			if r.RBDPool == "" {
   392  				r.RBDPool = "rbd"
   393  			}
   394  			r.RadosUser = c.RandString()
   395  			if r.RadosUser == "" {
   396  				r.RadosUser = "admin"
   397  			}
   398  			r.Keyring = c.RandString()
   399  			if r.Keyring == "" {
   400  				r.Keyring = "/etc/ceph/keyring"
   401  			}
   402  		},
   403  		func(r *core.RBDPersistentVolumeSource, c fuzz.Continue) {
   404  			r.RBDPool = c.RandString()
   405  			if r.RBDPool == "" {
   406  				r.RBDPool = "rbd"
   407  			}
   408  			r.RadosUser = c.RandString()
   409  			if r.RadosUser == "" {
   410  				r.RadosUser = "admin"
   411  			}
   412  			r.Keyring = c.RandString()
   413  			if r.Keyring == "" {
   414  				r.Keyring = "/etc/ceph/keyring"
   415  			}
   416  		},
   417  		func(obj *core.HostPathVolumeSource, c fuzz.Continue) {
   418  			c.FuzzNoCustom(obj)
   419  			types := []core.HostPathType{core.HostPathUnset, core.HostPathDirectoryOrCreate, core.HostPathDirectory,
   420  				core.HostPathFileOrCreate, core.HostPathFile, core.HostPathSocket, core.HostPathCharDev, core.HostPathBlockDev}
   421  			typeVol := types[c.Rand.Intn(len(types))]
   422  			if obj.Type == nil {
   423  				obj.Type = &typeVol
   424  			}
   425  		},
   426  		func(pv *core.PersistentVolume, c fuzz.Continue) {
   427  			c.FuzzNoCustom(pv) // fuzz self without calling this function again
   428  			types := []core.PersistentVolumePhase{core.VolumeAvailable, core.VolumePending, core.VolumeBound, core.VolumeReleased, core.VolumeFailed}
   429  			pv.Status.Phase = types[c.Rand.Intn(len(types))]
   430  			pv.Status.Message = c.RandString()
   431  			reclamationPolicies := []core.PersistentVolumeReclaimPolicy{core.PersistentVolumeReclaimRecycle, core.PersistentVolumeReclaimRetain}
   432  			pv.Spec.PersistentVolumeReclaimPolicy = reclamationPolicies[c.Rand.Intn(len(reclamationPolicies))]
   433  			volumeModes := []core.PersistentVolumeMode{core.PersistentVolumeFilesystem, core.PersistentVolumeBlock}
   434  			pv.Spec.VolumeMode = &volumeModes[c.Rand.Intn(len(volumeModes))]
   435  		},
   436  		func(pvc *core.PersistentVolumeClaim, c fuzz.Continue) {
   437  			c.FuzzNoCustom(pvc) // fuzz self without calling this function again
   438  			types := []core.PersistentVolumeClaimPhase{core.ClaimBound, core.ClaimPending, core.ClaimLost}
   439  			pvc.Status.Phase = types[c.Rand.Intn(len(types))]
   440  			volumeModes := []core.PersistentVolumeMode{core.PersistentVolumeFilesystem, core.PersistentVolumeBlock}
   441  			pvc.Spec.VolumeMode = &volumeModes[c.Rand.Intn(len(volumeModes))]
   442  		},
   443  		func(obj *core.AzureDiskVolumeSource, c fuzz.Continue) {
   444  			if obj.CachingMode == nil {
   445  				obj.CachingMode = new(core.AzureDataDiskCachingMode)
   446  				*obj.CachingMode = core.AzureDataDiskCachingReadWrite
   447  			}
   448  			if obj.Kind == nil {
   449  				obj.Kind = new(core.AzureDataDiskKind)
   450  				*obj.Kind = core.AzureSharedBlobDisk
   451  			}
   452  			if obj.FSType == nil {
   453  				obj.FSType = new(string)
   454  				*obj.FSType = "ext4"
   455  			}
   456  			if obj.ReadOnly == nil {
   457  				obj.ReadOnly = new(bool)
   458  				*obj.ReadOnly = false
   459  			}
   460  		},
   461  		func(sio *core.ScaleIOVolumeSource, c fuzz.Continue) {
   462  			sio.StorageMode = c.RandString()
   463  			if sio.StorageMode == "" {
   464  				sio.StorageMode = "ThinProvisioned"
   465  			}
   466  			sio.FSType = c.RandString()
   467  			if sio.FSType == "" {
   468  				sio.FSType = "xfs"
   469  			}
   470  		},
   471  		func(sio *core.ScaleIOPersistentVolumeSource, c fuzz.Continue) {
   472  			sio.StorageMode = c.RandString()
   473  			if sio.StorageMode == "" {
   474  				sio.StorageMode = "ThinProvisioned"
   475  			}
   476  			sio.FSType = c.RandString()
   477  			if sio.FSType == "" {
   478  				sio.FSType = "xfs"
   479  			}
   480  		},
   481  		func(s *core.NamespaceSpec, c fuzz.Continue) {
   482  			s.Finalizers = []core.FinalizerName{core.FinalizerKubernetes}
   483  		},
   484  		func(s *core.Namespace, c fuzz.Continue) {
   485  			c.FuzzNoCustom(s) // fuzz self without calling this function again
   486  			// Match name --> label defaulting
   487  			if len(s.Name) > 0 {
   488  				if s.Labels == nil {
   489  					s.Labels = map[string]string{}
   490  				}
   491  				s.Labels["kubernetes.io/metadata.name"] = s.Name
   492  			}
   493  		},
   494  		func(s *core.NamespaceStatus, c fuzz.Continue) {
   495  			s.Phase = core.NamespaceActive
   496  		},
   497  		func(http *core.HTTPGetAction, c fuzz.Continue) {
   498  			c.FuzzNoCustom(http)            // fuzz self without calling this function again
   499  			http.Path = "/" + http.Path     // can't be blank
   500  			http.Scheme = "x" + http.Scheme // can't be blank
   501  		},
   502  		func(ss *core.ServiceSpec, c fuzz.Continue) {
   503  			c.FuzzNoCustom(ss) // fuzz self without calling this function again
   504  			if len(ss.Ports) == 0 {
   505  				// There must be at least 1 port.
   506  				ss.Ports = append(ss.Ports, core.ServicePort{})
   507  				c.Fuzz(&ss.Ports[0])
   508  			}
   509  			for i := range ss.Ports {
   510  				switch ss.Ports[i].TargetPort.Type {
   511  				case intstr.Int:
   512  					ss.Ports[i].TargetPort.IntVal = 1 + ss.Ports[i].TargetPort.IntVal%65535 // non-zero
   513  				case intstr.String:
   514  					ss.Ports[i].TargetPort.StrVal = "x" + ss.Ports[i].TargetPort.StrVal // non-empty
   515  				}
   516  			}
   517  			types := []core.ServiceAffinity{core.ServiceAffinityNone, core.ServiceAffinityClientIP}
   518  			ss.SessionAffinity = types[c.Rand.Intn(len(types))]
   519  			switch ss.SessionAffinity {
   520  			case core.ServiceAffinityClientIP:
   521  				timeoutSeconds := int32(c.Rand.Intn(int(core.MaxClientIPServiceAffinitySeconds)))
   522  				ss.SessionAffinityConfig = &core.SessionAffinityConfig{
   523  					ClientIP: &core.ClientIPConfig{
   524  						TimeoutSeconds: &timeoutSeconds,
   525  					},
   526  				}
   527  			case core.ServiceAffinityNone:
   528  				ss.SessionAffinityConfig = nil
   529  			}
   530  			if ss.AllocateLoadBalancerNodePorts == nil {
   531  				ss.AllocateLoadBalancerNodePorts = utilpointer.Bool(true)
   532  			}
   533  		},
   534  		func(s *core.NodeStatus, c fuzz.Continue) {
   535  			c.FuzzNoCustom(s)
   536  			s.Allocatable = s.Capacity
   537  		},
   538  		func(e *core.Event, c fuzz.Continue) {
   539  			c.FuzzNoCustom(e)
   540  			e.EventTime = metav1.MicroTime{Time: time.Unix(1, 1000)}
   541  			if e.Series != nil {
   542  				e.Series.LastObservedTime = metav1.MicroTime{Time: time.Unix(3, 3000)}
   543  			}
   544  		},
   545  		func(j *core.GRPCAction, c fuzz.Continue) {
   546  			empty := ""
   547  			if j.Service == nil {
   548  				j.Service = &empty
   549  			}
   550  		},
   551  		func(j *core.LoadBalancerStatus, c fuzz.Continue) {
   552  			ipMode := core.LoadBalancerIPModeVIP
   553  			for i := range j.Ingress {
   554  				if j.Ingress[i].IPMode == nil {
   555  					j.Ingress[i].IPMode = &ipMode
   556  				}
   557  			}
   558  		},
   559  	}
   560  }
   561  

View as plain text