func ValidateLabels(a, b string) bool { sA, eA := labels.Parse(a) if eA != nil { return false } sB, eB := labels.Parse(b) if eB != nil { return false } return sA.String() == sB.String() }
// rsAndPodsWithHashKeySynced returns the RSes and pods the given deployment targets, with pod-template-hash information synced. func (dc *DeploymentController) rsAndPodsWithHashKeySynced(deployment *extensions.Deployment) ([]*extensions.ReplicaSet, *v1.PodList, error) { rsList, err := deploymentutil.ListReplicaSets(deployment, func(namespace string, options v1.ListOptions) ([]*extensions.ReplicaSet, error) { parsed, err := labels.Parse(options.LabelSelector) if err != nil { return nil, err } return dc.rsLister.ReplicaSets(namespace).List(parsed) }) if err != nil { return nil, nil, fmt.Errorf("error listing ReplicaSets: %v", err) } syncedRSList := []*extensions.ReplicaSet{} for _, rs := range rsList { // Add pod-template-hash information if it's not in the RS. // Otherwise, new RS produced by Deployment will overlap with pre-existing ones // that aren't constrained by the pod-template-hash. syncedRS, err := dc.addHashKeyToRSAndPods(rs) if err != nil { return nil, nil, err } syncedRSList = append(syncedRSList, syncedRS) } syncedPodList, err := dc.listPods(deployment) if err != nil { return nil, nil, err } return syncedRSList, syncedPodList, nil }
func (o TopPodOptions) RunTopPod() error { var err error selector := labels.Everything() if len(o.Selector) > 0 { selector, err = labels.Parse(o.Selector) if err != nil { return err } } metrics, err := o.Client.GetPodMetrics(o.Namespace, o.ResourceName, o.AllNamespaces, selector) // TODO: Refactor this once Heapster becomes the API server. // First we check why no metrics have been received. if len(metrics) == 0 { // If the API server query is successful but all the pods are newly created, // the metrics are probably not ready yet, so we return the error here in the first place. e := verifyEmptyMetrics(o, selector) if e != nil { return e } } if err != nil { return err } return o.Printer.PrintPodMetrics(metrics, o.PrintContainers, o.AllNamespaces) }
func ExtractFromListOptions(opts interface{}) (labelSelector labels.Selector, fieldSelector fields.Selector, resourceVersion string) { var err error switch t := opts.(type) { case api.ListOptions: labelSelector = t.LabelSelector fieldSelector = t.FieldSelector resourceVersion = t.ResourceVersion case v1.ListOptions: labelSelector, err = labels.Parse(t.LabelSelector) if err != nil { panic(err) } fieldSelector, err = fields.ParseSelector(t.FieldSelector) if err != nil { panic(err) } resourceVersion = t.ResourceVersion default: panic(fmt.Errorf("expect a ListOptions")) } if labelSelector == nil { labelSelector = labels.Everything() } if fieldSelector == nil { fieldSelector = fields.Everything() } return labelSelector, fieldSelector, resourceVersion }
func Convert_string_To_labels_Selector(in *string, out *labels.Selector, s conversion.Scope) error { selector, err := labels.Parse(*in) if err != nil { return err } *out = selector return nil }
func TestLabelSelectorAsSelector(t *testing.T) { matchLabels := map[string]string{"foo": "bar"} matchExpressions := []LabelSelectorRequirement{{ Key: "baz", Operator: LabelSelectorOpIn, Values: []string{"qux", "norf"}, }} mustParse := func(s string) labels.Selector { out, e := labels.Parse(s) if e != nil { panic(e) } return out } tc := []struct { in *LabelSelector out labels.Selector expectErr bool }{ {in: nil, out: labels.Nothing()}, {in: &LabelSelector{}, out: labels.Everything()}, { in: &LabelSelector{MatchLabels: matchLabels}, out: mustParse("foo=bar"), }, { in: &LabelSelector{MatchExpressions: matchExpressions}, out: mustParse("baz in (norf,qux)"), }, { in: &LabelSelector{MatchLabels: matchLabels, MatchExpressions: matchExpressions}, out: mustParse("baz in (norf,qux),foo=bar"), }, { in: &LabelSelector{ MatchExpressions: []LabelSelectorRequirement{{ Key: "baz", Operator: LabelSelectorOpExists, Values: []string{"qux", "norf"}, }}, }, expectErr: true, }, } for i, tc := range tc { out, err := LabelSelectorAsSelector(tc.in) if err == nil && tc.expectErr { t.Errorf("[%v]expected error but got none.", i) } if err != nil && !tc.expectErr { t.Errorf("[%v]did not expect error but got: %v", i, err) } if !reflect.DeepEqual(out, tc.out) { t.Errorf("[%v]expected:\n\t%+v\nbut got:\n\t%+v", i, tc.out, out) } } }
func (o *TopNodeOptions) Validate() error { if len(o.ResourceName) > 0 && len(o.Selector) > 0 { return errors.New("only one of NAME or --selector can be provided") } if len(o.Selector) > 0 { _, err := labels.Parse(o.Selector) if err != nil { return err } } return nil }
// ListResourceUsingInformerFunc returns a listing function based on the shared informer factory for the specified resource. func ListResourceUsingInformerFunc(f informers.SharedInformerFactory, groupResource schema.GroupResource) ListFuncByNamespace { return func(namespace string, options v1.ListOptions) ([]runtime.Object, error) { labelSelector, err := labels.Parse(options.LabelSelector) if err != nil { return nil, err } informer, err := f.ForResource(groupResource) if err != nil { return nil, err } return informer.Lister().ByNamespace(namespace).List(labelSelector) } }
func (dc *DeploymentController) listPods(deployment *extensions.Deployment) (*v1.PodList, error) { return deploymentutil.ListPods(deployment, func(namespace string, options v1.ListOptions) (*v1.PodList, error) { parsed, err := labels.Parse(options.LabelSelector) if err != nil { return nil, err } pods, err := dc.podLister.Pods(namespace).List(parsed) result := v1.PodList{Items: make([]v1.Pod, 0, len(pods))} for i := range pods { result.Items = append(result.Items, *pods[i]) } return &result, err }) }
// SelectorParam defines a selector that should be applied to the object types to load. // This will not affect files loaded from disk or URL. If the parameter is empty it is // a no-op - to select all resources invoke `b.Selector(labels.Everything)`. func (b *Builder) SelectorParam(s string) *Builder { selector, err := labels.Parse(s) if err != nil { b.errs = append(b.errs, fmt.Errorf("the provided selector %q is not valid: %v", s, err)) return b } if selector.Empty() { return b } if b.selectAll { b.errs = append(b.errs, fmt.Errorf("found non empty selector %q with previously set 'all' parameter. ", s)) return b } return b.Selector(selector) }
func (o TopNodeOptions) RunTopNode() error { var err error selector := labels.Everything() if len(o.Selector) > 0 { selector, err = labels.Parse(o.Selector) if err != nil { return err } } metrics, err := o.Client.GetNodeMetrics(o.ResourceName, selector) if err != nil { return err } if len(metrics) == 0 { return errors.New("metrics not available yet") } var nodes []api.Node if len(o.ResourceName) > 0 { node, err := o.NodeClient.Nodes().Get(o.ResourceName, metav1.GetOptions{}) if err != nil { return err } nodes = append(nodes, *node) } else { nodeList, err := o.NodeClient.Nodes().List(api.ListOptions{ LabelSelector: selector, }) if err != nil { return err } nodes = append(nodes, nodeList.Items...) } allocatable := make(map[string]api.ResourceList) for _, n := range nodes { allocatable[n.Name] = n.Status.Allocatable } return o.Printer.PrintNodeMetrics(metrics, allocatable) }
// addHashKeyToRSAndPods adds pod-template-hash information to the given rs, if it's not already there, with the following steps: // 1. Add hash label to the rs's pod template, and make sure the controller sees this update so that no orphaned pods will be created // 2. Add hash label to all pods this rs owns, wait until replicaset controller reports rs.Status.FullyLabeledReplicas equal to the desired number of replicas // 3. Add hash label to the rs's label and selector func (dc *DeploymentController) addHashKeyToRSAndPods(rs *extensions.ReplicaSet) (*extensions.ReplicaSet, error) { // If the rs already has the new hash label in its selector, it's done syncing if labelsutil.SelectorHasLabel(rs.Spec.Selector, extensions.DefaultDeploymentUniqueLabelKey) { return rs, nil } hash := deploymentutil.GetReplicaSetHash(rs) // 1. Add hash template label to the rs. This ensures that any newly created pods will have the new label. updatedRS, err := deploymentutil.UpdateRSWithRetries(dc.client.Extensions().ReplicaSets(rs.Namespace), dc.rsLister, rs.Namespace, rs.Name, func(updated *extensions.ReplicaSet) error { // Precondition: the RS doesn't contain the new hash in its pod template label. if updated.Spec.Template.Labels[extensions.DefaultDeploymentUniqueLabelKey] == hash { return utilerrors.ErrPreconditionViolated } updated.Spec.Template.Labels = labelsutil.AddLabel(updated.Spec.Template.Labels, extensions.DefaultDeploymentUniqueLabelKey, hash) return nil }) if err != nil { return nil, fmt.Errorf("error updating replica set %s/%s pod template label with template hash: %v", rs.Namespace, rs.Name, err) } // Make sure rs pod template is updated so that it won't create pods without the new label (orphaned pods). if updatedRS.Generation > updatedRS.Status.ObservedGeneration { if err = deploymentutil.WaitForReplicaSetUpdated(dc.client, updatedRS.Generation, updatedRS.Namespace, updatedRS.Name); err != nil { return nil, fmt.Errorf("error waiting for replica set %s/%s to be observed by controller: %v", updatedRS.Namespace, updatedRS.Name, err) } glog.V(4).Infof("Observed the update of replica set %s/%s's pod template with hash %s.", rs.Namespace, rs.Name, hash) } // 2. Update all pods managed by the rs to have the new hash label, so they will be correctly adopted. selector, err := metav1.LabelSelectorAsSelector(updatedRS.Spec.Selector) if err != nil { return nil, fmt.Errorf("error in converting selector to label selector for replica set %s: %s", updatedRS.Name, err) } options := v1.ListOptions{LabelSelector: selector.String()} parsed, err := labels.Parse(options.LabelSelector) if err != nil { return nil, err } pods, err := dc.podLister.Pods(updatedRS.Namespace).List(parsed) if err != nil { return nil, fmt.Errorf("error in getting pod list for namespace %s and list options %+v: %s", rs.Namespace, options, err) } podList := v1.PodList{Items: make([]v1.Pod, 0, len(pods))} for i := range pods { podList.Items = append(podList.Items, *pods[i]) } if err := deploymentutil.LabelPodsWithHash(&podList, dc.client, dc.podLister, rs.Namespace, rs.Name, hash); err != nil { return nil, fmt.Errorf("error in adding template hash label %s to pods %+v: %s", hash, podList, err) } // We need to wait for the replicaset controller to observe the pods being // labeled with pod template hash. Because previously we've called // WaitForReplicaSetUpdated, the replicaset controller should have dropped // FullyLabeledReplicas to 0 already, we only need to wait it to increase // back to the number of replicas in the spec. if err := deploymentutil.WaitForPodsHashPopulated(dc.client, updatedRS.Generation, updatedRS.Namespace, updatedRS.Name); err != nil { return nil, fmt.Errorf("Replica set %s/%s: error waiting for replicaset controller to observe pods being labeled with template hash: %v", updatedRS.Namespace, updatedRS.Name, err) } // 3. Update rs label and selector to include the new hash label // Copy the old selector, so that we can scrub out any orphaned pods updatedRS, err = deploymentutil.UpdateRSWithRetries(dc.client.Extensions().ReplicaSets(rs.Namespace), dc.rsLister, rs.Namespace, rs.Name, func(updated *extensions.ReplicaSet) error { // Precondition: the RS doesn't contain the new hash in its label and selector. if updated.Labels[extensions.DefaultDeploymentUniqueLabelKey] == hash && updated.Spec.Selector.MatchLabels[extensions.DefaultDeploymentUniqueLabelKey] == hash { return utilerrors.ErrPreconditionViolated } updated.Labels = labelsutil.AddLabel(updated.Labels, extensions.DefaultDeploymentUniqueLabelKey, hash) updated.Spec.Selector = labelsutil.AddLabelToSelector(updated.Spec.Selector, extensions.DefaultDeploymentUniqueLabelKey, hash) return nil }) // If the RS isn't actually updated, that's okay, we'll retry in the // next sync loop since its selector isn't updated yet. if err != nil { return nil, fmt.Errorf("error updating ReplicaSet %s/%s label and selector with template hash: %v", updatedRS.Namespace, updatedRS.Name, err) } // TODO: look for orphaned pods and label them in the background somewhere else periodically return updatedRS, nil }
func TestNodeSelectorRequirementsAsSelector(t *testing.T) { matchExpressions := []NodeSelectorRequirement{{ Key: "foo", Operator: NodeSelectorOpIn, Values: []string{"bar", "baz"}, }} mustParse := func(s string) labels.Selector { out, e := labels.Parse(s) if e != nil { panic(e) } return out } tc := []struct { in []NodeSelectorRequirement out labels.Selector expectErr bool }{ {in: nil, out: labels.Nothing()}, {in: []NodeSelectorRequirement{}, out: labels.Nothing()}, { in: matchExpressions, out: mustParse("foo in (baz,bar)"), }, { in: []NodeSelectorRequirement{{ Key: "foo", Operator: NodeSelectorOpExists, Values: []string{"bar", "baz"}, }}, expectErr: true, }, { in: []NodeSelectorRequirement{{ Key: "foo", Operator: NodeSelectorOpGt, Values: []string{"1"}, }}, out: mustParse("foo>1"), }, { in: []NodeSelectorRequirement{{ Key: "bar", Operator: NodeSelectorOpLt, Values: []string{"7"}, }}, out: mustParse("bar<7"), }, } for i, tc := range tc { out, err := NodeSelectorRequirementsAsSelector(tc.in) if err == nil && tc.expectErr { t.Errorf("[%v]expected error but got none.", i) } if err != nil && !tc.expectErr { t.Errorf("[%v]did not expect error but got: %v", i, err) } if !reflect.DeepEqual(out, tc.out) { t.Errorf("[%v]expected:\n\t%+v\nbut got:\n\t%+v", i, tc.out, out) } } }
func RunApply(f cmdutil.Factory, cmd *cobra.Command, out, errOut io.Writer, options *ApplyOptions) error { schema, err := f.Validator(cmdutil.GetFlagBool(cmd, "validate"), cmdutil.GetFlagString(cmd, "schema-cache-dir")) if err != nil { return err } cmdNamespace, enforceNamespace, err := f.DefaultNamespace() if err != nil { return err } if options.Prune { options.PruneResources, err = parsePruneResources(cmdutil.GetFlagStringArray(cmd, "prune-whitelist")) if err != nil { return err } } mapper, typer := f.Object() r := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)). Schema(schema). ContinueOnError(). NamespaceParam(cmdNamespace).DefaultNamespace(). FilenameParam(enforceNamespace, &options.FilenameOptions). SelectorParam(options.Selector). Flatten(). Do() err = r.Err() if err != nil { return err } dryRun := cmdutil.GetFlagBool(cmd, "dry-run") output := cmdutil.GetFlagString(cmd, "output") shortOutput := output == "name" encoder := f.JSONEncoder() decoder := f.Decoder(false) visitedUids := sets.NewString() visitedNamespaces := sets.NewString() count := 0 err = r.Visit(func(info *resource.Info, err error) error { // In this method, info.Object contains the object retrieved from the server // and info.VersionedObject contains the object decoded from the input source. if err != nil { return err } if info.Namespaced() { visitedNamespaces.Insert(info.Namespace) } // Get the modified configuration of the object. Embed the result // as an annotation in the modified configuration, so that it will appear // in the patch sent to the server. modified, err := kubectl.GetModifiedConfiguration(info, true, encoder) if err != nil { return cmdutil.AddSourceToErr(fmt.Sprintf("retrieving modified configuration from:\n%v\nfor:", info), info.Source, err) } if err := info.Get(); err != nil { if !errors.IsNotFound(err) { return cmdutil.AddSourceToErr(fmt.Sprintf("retrieving current configuration of:\n%v\nfrom server for:", info), info.Source, err) } // Create the resource if it doesn't exist // First, update the annotation used by kubectl apply if err := kubectl.CreateApplyAnnotation(info, encoder); err != nil { return cmdutil.AddSourceToErr("creating", info.Source, err) } if cmdutil.ShouldRecord(cmd, info) { if err := cmdutil.RecordChangeCause(info.Object, f.Command()); err != nil { return cmdutil.AddSourceToErr("creating", info.Source, err) } } if !dryRun { // Then create the resource and skip the three-way merge if err := createAndRefresh(info); err != nil { return cmdutil.AddSourceToErr("creating", info.Source, err) } if uid, err := info.Mapping.UID(info.Object); err != nil { return err } else { visitedUids.Insert(string(uid)) } } count++ if len(output) > 0 && !shortOutput { return cmdutil.PrintResourceInfoForCommand(cmd, info, f, out) } cmdutil.PrintSuccess(mapper, shortOutput, out, info.Mapping.Resource, info.Name, dryRun, "created") return nil } if !dryRun { annotationMap, err := info.Mapping.MetadataAccessor.Annotations(info.Object) if err != nil { return err } if _, ok := annotationMap[annotations.LastAppliedConfigAnnotation]; !ok { fmt.Fprintf(errOut, warningNoLastAppliedConfigAnnotation) } overwrite := cmdutil.GetFlagBool(cmd, "overwrite") helper := resource.NewHelper(info.Client, info.Mapping) patcher := &patcher{ encoder: encoder, decoder: decoder, mapping: info.Mapping, helper: helper, clientsetFunc: f.ClientSet, overwrite: overwrite, backOff: clockwork.NewRealClock(), force: options.Force, cascade: options.Cascade, timeout: options.Timeout, gracePeriod: options.GracePeriod, } patchBytes, err := patcher.patch(info.Object, modified, info.Source, info.Namespace, info.Name) if err != nil { return cmdutil.AddSourceToErr(fmt.Sprintf("applying patch:\n%s\nto:\n%v\nfor:", patchBytes, info), info.Source, err) } if cmdutil.ShouldRecord(cmd, info) { patch, err := cmdutil.ChangeResourcePatch(info, f.Command()) if err != nil { return err } _, err = helper.Patch(info.Namespace, info.Name, types.StrategicMergePatchType, patch) if err != nil { return cmdutil.AddSourceToErr(fmt.Sprintf("applying patch:\n%s\nto:\n%v\nfor:", patch, info), info.Source, err) } } if uid, err := info.Mapping.UID(info.Object); err != nil { return err } else { visitedUids.Insert(string(uid)) } } count++ if len(output) > 0 && !shortOutput { return cmdutil.PrintResourceInfoForCommand(cmd, info, f, out) } cmdutil.PrintSuccess(mapper, shortOutput, out, info.Mapping.Resource, info.Name, dryRun, "configured") return nil }) if err != nil { return err } if count == 0 { return fmt.Errorf("no objects passed to apply") } if !options.Prune { return nil } selector, err := labels.Parse(options.Selector) if err != nil { return err } p := pruner{ mapper: mapper, clientFunc: f.ClientForMapping, clientsetFunc: f.ClientSet, selector: selector, visitedUids: visitedUids, cascade: options.Cascade, dryRun: dryRun, gracePeriod: options.GracePeriod, out: out, } namespacedRESTMappings, nonNamespacedRESTMappings, err := getRESTMappings(&(options.PruneResources)) if err != nil { return fmt.Errorf("error retrieving RESTMappings to prune: %v", err) } for n := range visitedNamespaces { for _, m := range namespacedRESTMappings { if err := p.prune(n, m, shortOutput); err != nil { return fmt.Errorf("error pruning namespaced object %v: %v", m.GroupVersionKind, err) } } } for _, m := range nonNamespacedRESTMappings { if err := p.prune(api.NamespaceNone, m, shortOutput); err != nil { return fmt.Errorf("error pruning nonNamespaced object %v: %v", m.GroupVersionKind, err) } } return nil }
func TestSelectionPredicate(t *testing.T) { table := map[string]struct { labelSelector, fieldSelector string labels labels.Set fields fields.Set err error shouldMatch bool matchSingleKey string }{ "A": { labelSelector: "name=foo", fieldSelector: "uid=12345", labels: labels.Set{"name": "foo"}, fields: fields.Set{"uid": "12345"}, shouldMatch: true, }, "B": { labelSelector: "name=foo", fieldSelector: "uid=12345", labels: labels.Set{"name": "foo"}, fields: fields.Set{}, shouldMatch: false, }, "C": { labelSelector: "name=foo", fieldSelector: "uid=12345", labels: labels.Set{}, fields: fields.Set{"uid": "12345"}, shouldMatch: false, }, "D": { fieldSelector: "metadata.name=12345", labels: labels.Set{}, fields: fields.Set{"metadata.name": "12345"}, shouldMatch: true, matchSingleKey: "12345", }, "error": { labelSelector: "name=foo", fieldSelector: "uid=12345", err: errors.New("maybe this is a 'wrong object type' error"), shouldMatch: false, }, } for name, item := range table { parsedLabel, err := labels.Parse(item.labelSelector) if err != nil { panic(err) } parsedField, err := fields.ParseSelector(item.fieldSelector) if err != nil { panic(err) } sp := &SelectionPredicate{ Label: parsedLabel, Field: parsedField, GetAttrs: func(runtime.Object) (label labels.Set, field fields.Set, err error) { return item.labels, item.fields, item.err }, } got, err := sp.Matches(&Ignored{}) if e, a := item.err, err; e != a { t.Errorf("%v: expected %v, got %v", name, e, a) continue } if e, a := item.shouldMatch, got; e != a { t.Errorf("%v: expected %v, got %v", name, e, a) } if key := item.matchSingleKey; key != "" { got, ok := sp.MatchesSingle() if !ok { t.Errorf("%v: expected single match", name) } if e, a := key, got; e != a { t.Errorf("%v: expected %v, got %v", name, e, a) } } } }
// FuzzerFor can randomly populate api objects that are destined for version. func FuzzerFor(t *testing.T, version schema.GroupVersion, src rand.Source) *fuzz.Fuzzer { f := fuzz.New().NilChance(.5).NumElements(0, 1) if src != nil { f.RandSource(src) } f.Funcs( func(j *int, c fuzz.Continue) { *j = int(c.Int31()) }, func(j **int, c fuzz.Continue) { if c.RandBool() { i := int(c.Int31()) *j = &i } else { *j = nil } }, func(q *resource.Quantity, c fuzz.Continue) { *q = *resource.NewQuantity(c.Int63n(1000), resource.DecimalExponent) }, func(j *runtime.TypeMeta, c fuzz.Continue) { // We have to customize the randomization of TypeMetas because their // APIVersion and Kind must remain blank in memory. j.APIVersion = "" j.Kind = "" }, func(j *metav1.TypeMeta, c fuzz.Continue) { // We have to customize the randomization of TypeMetas because their // APIVersion and Kind must remain blank in memory. j.APIVersion = "" j.Kind = "" }, func(j *metav1.ObjectMeta, c fuzz.Continue) { j.Name = c.RandString() j.ResourceVersion = strconv.FormatUint(c.RandUint64(), 10) j.SelfLink = c.RandString() j.UID = types.UID(c.RandString()) j.GenerateName = c.RandString() var sec, nsec int64 c.Fuzz(&sec) c.Fuzz(&nsec) j.CreationTimestamp = metav1.Unix(sec, nsec).Rfc3339Copy() }, func(j *api.ObjectReference, c fuzz.Continue) { // We have to customize the randomization of TypeMetas because their // APIVersion and Kind must remain blank in memory. j.APIVersion = c.RandString() j.Kind = c.RandString() j.Namespace = c.RandString() j.Name = c.RandString() j.ResourceVersion = strconv.FormatUint(c.RandUint64(), 10) j.FieldPath = c.RandString() }, func(j *metav1.ListMeta, c fuzz.Continue) { j.ResourceVersion = strconv.FormatUint(c.RandUint64(), 10) j.SelfLink = c.RandString() }, func(j *api.ListOptions, c fuzz.Continue) { label, _ := labels.Parse("a=b") j.LabelSelector = label field, _ := fields.ParseSelector("a=b") j.FieldSelector = field }, func(j *api.PodExecOptions, c fuzz.Continue) { j.Stdout = true j.Stderr = true }, func(j *api.PodAttachOptions, c fuzz.Continue) { j.Stdout = true j.Stderr = true }, func(s *api.PodSpec, c fuzz.Continue) { c.FuzzNoCustom(s) // has a default value ttl := int64(30) if c.RandBool() { ttl = int64(c.Uint32()) } s.TerminationGracePeriodSeconds = &ttl c.Fuzz(s.SecurityContext) if s.SecurityContext == nil { s.SecurityContext = new(api.PodSecurityContext) } if s.Affinity == nil { s.Affinity = new(api.Affinity) } if s.SchedulerName == "" { s.SchedulerName = api.DefaultSchedulerName } }, func(j *api.PodPhase, c fuzz.Continue) { statuses := []api.PodPhase{api.PodPending, api.PodRunning, api.PodFailed, api.PodUnknown} *j = statuses[c.Rand.Intn(len(statuses))] }, func(j *api.Binding, c fuzz.Continue) { c.Fuzz(&j.ObjectMeta) j.Target.Name = c.RandString() }, func(j *api.ReplicationControllerSpec, c fuzz.Continue) { c.FuzzNoCustom(j) // fuzz self without calling this function again //j.TemplateRef = nil // this is required for round trip }, func(j *extensions.DeploymentStrategy, c fuzz.Continue) { c.FuzzNoCustom(j) // fuzz self without calling this function again // Ensure that strategyType is one of valid values. strategyTypes := []extensions.DeploymentStrategyType{extensions.RecreateDeploymentStrategyType, extensions.RollingUpdateDeploymentStrategyType} j.Type = strategyTypes[c.Rand.Intn(len(strategyTypes))] if j.Type != extensions.RollingUpdateDeploymentStrategyType { j.RollingUpdate = nil } else { rollingUpdate := extensions.RollingUpdateDeployment{} if c.RandBool() { rollingUpdate.MaxUnavailable = intstr.FromInt(int(c.Rand.Int31())) rollingUpdate.MaxSurge = intstr.FromInt(int(c.Rand.Int31())) } else { rollingUpdate.MaxSurge = intstr.FromString(fmt.Sprintf("%d%%", c.Rand.Int31())) } j.RollingUpdate = &rollingUpdate } }, func(j *batch.JobSpec, c fuzz.Continue) { c.FuzzNoCustom(j) // fuzz self without calling this function again completions := int32(c.Rand.Int31()) parallelism := int32(c.Rand.Int31()) j.Completions = &completions j.Parallelism = ¶llelism if c.Rand.Int31()%2 == 0 { j.ManualSelector = newBool(true) } else { j.ManualSelector = nil } }, func(sj *batch.CronJobSpec, c fuzz.Continue) { c.FuzzNoCustom(sj) suspend := c.RandBool() sj.Suspend = &suspend sds := int64(c.RandUint64()) sj.StartingDeadlineSeconds = &sds sj.Schedule = c.RandString() }, func(cp *batch.ConcurrencyPolicy, c fuzz.Continue) { policies := []batch.ConcurrencyPolicy{batch.AllowConcurrent, batch.ForbidConcurrent, batch.ReplaceConcurrent} *cp = policies[c.Rand.Intn(len(policies))] }, func(j *api.List, c fuzz.Continue) { c.FuzzNoCustom(j) // fuzz self without calling this function again // TODO: uncomment when round trip starts from a versioned object if false { //j.Items == nil { j.Items = []runtime.Object{} } }, func(j *runtime.Object, c fuzz.Continue) { // TODO: uncomment when round trip starts from a versioned object if true { //c.RandBool() { *j = &runtime.Unknown{ // We do not set TypeMeta here because it is not carried through a round trip Raw: []byte(`{"apiVersion":"unknown.group/unknown","kind":"Something","someKey":"someValue"}`), ContentType: runtime.ContentTypeJSON, } } else { types := []runtime.Object{&api.Pod{}, &api.ReplicationController{}} t := types[c.Rand.Intn(len(types))] c.Fuzz(t) *j = t } }, func(q *api.ResourceRequirements, c fuzz.Continue) { randomQuantity := func() resource.Quantity { var q resource.Quantity c.Fuzz(&q) // precalc the string for benchmarking purposes _ = q.String() return q } q.Limits = make(api.ResourceList) q.Requests = make(api.ResourceList) cpuLimit := randomQuantity() q.Limits[api.ResourceCPU] = *cpuLimit.Copy() q.Requests[api.ResourceCPU] = *cpuLimit.Copy() memoryLimit := randomQuantity() q.Limits[api.ResourceMemory] = *memoryLimit.Copy() q.Requests[api.ResourceMemory] = *memoryLimit.Copy() storageLimit := randomQuantity() q.Limits[api.ResourceStorage] = *storageLimit.Copy() q.Requests[api.ResourceStorage] = *storageLimit.Copy() }, func(q *api.LimitRangeItem, c fuzz.Continue) { var cpuLimit resource.Quantity c.Fuzz(&cpuLimit) q.Type = api.LimitTypeContainer q.Default = make(api.ResourceList) q.Default[api.ResourceCPU] = *(cpuLimit.Copy()) q.DefaultRequest = make(api.ResourceList) q.DefaultRequest[api.ResourceCPU] = *(cpuLimit.Copy()) q.Max = make(api.ResourceList) q.Max[api.ResourceCPU] = *(cpuLimit.Copy()) q.Min = make(api.ResourceList) q.Min[api.ResourceCPU] = *(cpuLimit.Copy()) q.MaxLimitRequestRatio = make(api.ResourceList) q.MaxLimitRequestRatio[api.ResourceCPU] = resource.MustParse("10") }, func(p *api.PullPolicy, c fuzz.Continue) { policies := []api.PullPolicy{api.PullAlways, api.PullNever, api.PullIfNotPresent} *p = policies[c.Rand.Intn(len(policies))] }, func(rp *api.RestartPolicy, c fuzz.Continue) { policies := []api.RestartPolicy{api.RestartPolicyAlways, api.RestartPolicyNever, api.RestartPolicyOnFailure} *rp = policies[c.Rand.Intn(len(policies))] }, // api.DownwardAPIVolumeFile needs to have a specific func since FieldRef has to be // defaulted to a version otherwise roundtrip will fail func(m *api.DownwardAPIVolumeFile, c fuzz.Continue) { m.Path = c.RandString() versions := []string{"v1"} m.FieldRef = &api.ObjectFieldSelector{} m.FieldRef.APIVersion = versions[c.Rand.Intn(len(versions))] m.FieldRef.FieldPath = c.RandString() c.Fuzz(m.Mode) if m.Mode != nil { *m.Mode &= 0777 } }, func(s *api.SecretVolumeSource, c fuzz.Continue) { c.FuzzNoCustom(s) // fuzz self without calling this function again // DefaultMode should always be set, it has a default // value and it is expected to be between 0 and 0777 var mode int32 c.Fuzz(&mode) mode &= 0777 s.DefaultMode = &mode }, func(cm *api.ConfigMapVolumeSource, c fuzz.Continue) { c.FuzzNoCustom(cm) // fuzz self without calling this function again // DefaultMode should always be set, it has a default // value and it is expected to be between 0 and 0777 var mode int32 c.Fuzz(&mode) mode &= 0777 cm.DefaultMode = &mode }, func(d *api.DownwardAPIVolumeSource, c fuzz.Continue) { c.FuzzNoCustom(d) // fuzz self without calling this function again // DefaultMode should always be set, it has a default // value and it is expected to be between 0 and 0777 var mode int32 c.Fuzz(&mode) mode &= 0777 d.DefaultMode = &mode }, func(k *api.KeyToPath, c fuzz.Continue) { c.FuzzNoCustom(k) // fuzz self without calling this function again k.Key = c.RandString() k.Path = c.RandString() // Mode is not mandatory, but if it is set, it should be // a value between 0 and 0777 if k.Mode != nil { *k.Mode &= 0777 } }, func(vs *api.VolumeSource, c fuzz.Continue) { // Exactly one of the fields must be set. v := reflect.ValueOf(vs).Elem() i := int(c.RandUint64() % uint64(v.NumField())) t := v.Field(i).Addr() for v.Field(i).IsNil() { c.Fuzz(t.Interface()) } }, func(i *api.ISCSIVolumeSource, c fuzz.Continue) { i.ISCSIInterface = c.RandString() if i.ISCSIInterface == "" { i.ISCSIInterface = "default" } }, func(d *api.DNSPolicy, c fuzz.Continue) { policies := []api.DNSPolicy{api.DNSClusterFirst, api.DNSDefault} *d = policies[c.Rand.Intn(len(policies))] }, func(p *api.Protocol, c fuzz.Continue) { protocols := []api.Protocol{api.ProtocolTCP, api.ProtocolUDP} *p = protocols[c.Rand.Intn(len(protocols))] }, func(p *api.ServiceAffinity, c fuzz.Continue) { types := []api.ServiceAffinity{api.ServiceAffinityClientIP, api.ServiceAffinityNone} *p = types[c.Rand.Intn(len(types))] }, func(p *api.ServiceType, c fuzz.Continue) { types := []api.ServiceType{api.ServiceTypeClusterIP, api.ServiceTypeNodePort, api.ServiceTypeLoadBalancer} *p = types[c.Rand.Intn(len(types))] }, func(ct *api.Container, c fuzz.Continue) { c.FuzzNoCustom(ct) // fuzz self without calling this function again ct.TerminationMessagePath = "/" + ct.TerminationMessagePath // Must be non-empty }, func(p *api.Probe, c fuzz.Continue) { c.FuzzNoCustom(p) // These fields have default values. intFieldsWithDefaults := [...]string{"TimeoutSeconds", "PeriodSeconds", "SuccessThreshold", "FailureThreshold"} v := reflect.ValueOf(p).Elem() for _, field := range intFieldsWithDefaults { f := v.FieldByName(field) if f.Int() == 0 { f.SetInt(1) } } }, func(ev *api.EnvVar, c fuzz.Continue) { ev.Name = c.RandString() if c.RandBool() { ev.Value = c.RandString() } else { ev.ValueFrom = &api.EnvVarSource{} ev.ValueFrom.FieldRef = &api.ObjectFieldSelector{} var versions []schema.GroupVersion for _, testGroup := range testapi.Groups { versions = append(versions, *testGroup.GroupVersion()) } ev.ValueFrom.FieldRef.APIVersion = versions[c.Rand.Intn(len(versions))].String() ev.ValueFrom.FieldRef.FieldPath = c.RandString() } }, func(ev *api.EnvFromSource, c fuzz.Continue) { if c.RandBool() { ev.Prefix = "p_" } if c.RandBool() { c.Fuzz(&ev.ConfigMapRef) } else { c.Fuzz(&ev.SecretRef) } }, func(cm *api.ConfigMapEnvSource, c fuzz.Continue) { c.FuzzNoCustom(cm) // fuzz self without calling this function again }, func(s *api.SecretEnvSource, c fuzz.Continue) { c.FuzzNoCustom(s) // fuzz self without calling this function again }, func(sc *api.SecurityContext, c fuzz.Continue) { c.FuzzNoCustom(sc) // fuzz self without calling this function again if c.RandBool() { priv := c.RandBool() sc.Privileged = &priv } if c.RandBool() { sc.Capabilities = &api.Capabilities{ Add: make([]api.Capability, 0), Drop: make([]api.Capability, 0), } c.Fuzz(&sc.Capabilities.Add) c.Fuzz(&sc.Capabilities.Drop) } }, func(s *api.Secret, c fuzz.Continue) { c.FuzzNoCustom(s) // fuzz self without calling this function again s.Type = api.SecretTypeOpaque }, func(r *api.RBDVolumeSource, c fuzz.Continue) { r.RBDPool = c.RandString() if r.RBDPool == "" { r.RBDPool = "rbd" } r.RadosUser = c.RandString() if r.RadosUser == "" { r.RadosUser = "******" } r.Keyring = c.RandString() if r.Keyring == "" { r.Keyring = "/etc/ceph/keyring" } }, func(pv *api.PersistentVolume, c fuzz.Continue) { c.FuzzNoCustom(pv) // fuzz self without calling this function again types := []api.PersistentVolumePhase{api.VolumeAvailable, api.VolumePending, api.VolumeBound, api.VolumeReleased, api.VolumeFailed} pv.Status.Phase = types[c.Rand.Intn(len(types))] pv.Status.Message = c.RandString() reclamationPolicies := []api.PersistentVolumeReclaimPolicy{api.PersistentVolumeReclaimRecycle, api.PersistentVolumeReclaimRetain} pv.Spec.PersistentVolumeReclaimPolicy = reclamationPolicies[c.Rand.Intn(len(reclamationPolicies))] }, func(pvc *api.PersistentVolumeClaim, c fuzz.Continue) { c.FuzzNoCustom(pvc) // fuzz self without calling this function again types := []api.PersistentVolumeClaimPhase{api.ClaimBound, api.ClaimPending, api.ClaimLost} pvc.Status.Phase = types[c.Rand.Intn(len(types))] }, func(obj *api.AzureDiskVolumeSource, c fuzz.Continue) { if obj.CachingMode == nil { obj.CachingMode = new(api.AzureDataDiskCachingMode) *obj.CachingMode = api.AzureDataDiskCachingNone } if obj.FSType == nil { obj.FSType = new(string) *obj.FSType = "ext4" } if obj.ReadOnly == nil { obj.ReadOnly = new(bool) *obj.ReadOnly = false } }, func(s *api.NamespaceSpec, c fuzz.Continue) { s.Finalizers = []api.FinalizerName{api.FinalizerKubernetes} }, func(s *api.NamespaceStatus, c fuzz.Continue) { s.Phase = api.NamespaceActive }, func(http *api.HTTPGetAction, c fuzz.Continue) { c.FuzzNoCustom(http) // fuzz self without calling this function again http.Path = "/" + http.Path // can't be blank http.Scheme = "x" + http.Scheme // can't be blank }, func(ss *api.ServiceSpec, c fuzz.Continue) { c.FuzzNoCustom(ss) // fuzz self without calling this function again if len(ss.Ports) == 0 { // There must be at least 1 port. ss.Ports = append(ss.Ports, api.ServicePort{}) c.Fuzz(&ss.Ports[0]) } for i := range ss.Ports { switch ss.Ports[i].TargetPort.Type { case intstr.Int: ss.Ports[i].TargetPort.IntVal = 1 + ss.Ports[i].TargetPort.IntVal%65535 // non-zero case intstr.String: ss.Ports[i].TargetPort.StrVal = "x" + ss.Ports[i].TargetPort.StrVal // non-empty } } }, func(n *api.Node, c fuzz.Continue) { c.FuzzNoCustom(n) n.Spec.ExternalID = "external" }, func(s *api.NodeStatus, c fuzz.Continue) { c.FuzzNoCustom(s) s.Allocatable = s.Capacity }, func(s *autoscaling.HorizontalPodAutoscalerSpec, c fuzz.Continue) { c.FuzzNoCustom(s) // fuzz self without calling this function again minReplicas := int32(c.Rand.Int31()) s.MinReplicas = &minReplicas targetCpu := int32(c.RandUint64()) s.TargetCPUUtilizationPercentage = &targetCpu }, func(psp *extensions.PodSecurityPolicySpec, c fuzz.Continue) { c.FuzzNoCustom(psp) // fuzz self without calling this function again runAsUserRules := []extensions.RunAsUserStrategy{extensions.RunAsUserStrategyMustRunAsNonRoot, extensions.RunAsUserStrategyMustRunAs, extensions.RunAsUserStrategyRunAsAny} psp.RunAsUser.Rule = runAsUserRules[c.Rand.Intn(len(runAsUserRules))] seLinuxRules := []extensions.SELinuxStrategy{extensions.SELinuxStrategyRunAsAny, extensions.SELinuxStrategyMustRunAs} psp.SELinux.Rule = seLinuxRules[c.Rand.Intn(len(seLinuxRules))] }, func(s *extensions.Scale, c fuzz.Continue) { c.FuzzNoCustom(s) // fuzz self without calling this function again // TODO: Implement a fuzzer to generate valid keys, values and operators for // selector requirements. if s.Status.Selector != nil { s.Status.Selector = &metav1.LabelSelector{ MatchLabels: map[string]string{ "testlabelkey": "testlabelval", }, MatchExpressions: []metav1.LabelSelectorRequirement{ { Key: "testkey", Operator: metav1.LabelSelectorOpIn, Values: []string{"val1", "val2", "val3"}, }, }, } } }, func(r *rbac.RoleRef, c fuzz.Continue) { c.FuzzNoCustom(r) // fuzz self without calling this function again // match defaulter if len(r.APIGroup) == 0 { r.APIGroup = rbac.GroupName } }, func(r *runtime.RawExtension, c fuzz.Continue) { // Pick an arbitrary type and fuzz it types := []runtime.Object{&api.Pod{}, &extensions.Deployment{}, &api.Service{}} obj := types[c.Rand.Intn(len(types))] c.Fuzz(obj) // Find a codec for converting the object to raw bytes. This is necessary for the // api version and kind to be correctly set be serialization. var codec runtime.Codec switch obj.(type) { case *api.Pod: codec = testapi.Default.Codec() case *extensions.Deployment: codec = testapi.Extensions.Codec() case *api.Service: codec = testapi.Default.Codec() default: t.Errorf("Failed to find codec for object type: %T", obj) return } // Convert the object to raw bytes bytes, err := runtime.Encode(codec, obj) if err != nil { t.Errorf("Failed to encode object: %v", err) return } // Set the bytes field on the RawExtension r.Raw = bytes }, func(obj *kubeadm.MasterConfiguration, c fuzz.Continue) { c.FuzzNoCustom(obj) obj.KubernetesVersion = "v10" obj.API.Port = 20 obj.Networking.ServiceSubnet = "foo" obj.Networking.DNSDomain = "foo" obj.AuthorizationMode = "foo" obj.Discovery.Token = &kubeadm.TokenDiscovery{} }, func(s *policy.PodDisruptionBudgetStatus, c fuzz.Continue) { c.FuzzNoCustom(s) // fuzz self without calling this function again s.PodDisruptionsAllowed = int32(c.Rand.Intn(2)) }, func(obj *certificates.CertificateSigningRequestSpec, c fuzz.Continue) { c.FuzzNoCustom(obj) // fuzz self without calling this function again obj.Usages = []certificates.KeyUsage{certificates.UsageKeyEncipherment} }, ) return f }