kubernetes: Job created with no selector and extra template labels fails validation

When creating a job like this:

job := &extensions.Job{}
job.Name = "testjob"
job.Spec.Template.Labels = map[string]string{"foo": "bar"}
job.Spec.Template.Spec = ...
job.Spec.Template.Spec.RestartPolicy = kapi.RestartPolicyNever
_, err = client.Extensions().Jobs(testutil.Namespace()).Create(job)

the API returns the following error:

Job.extensions “testjob” is invalid: spec.selector: Invalid value: {“matchLabels”:{“controller-uid”:“db5d1cc3-e8f0-11e5-914d-acbc32c1ca87”,“foo”:“bar”}}: selector not auto-generated

This is the object passed to ValidateGeneratedSelector, which seems like it should validate:

(api.ObjectMeta) {
 Name: (string) (len=7) "testjob",
 GenerateName: (string) "",
 Namespace: (string) (len=11) "integration",
 SelfLink: (string) "",
 UID: (types.UID) (len=36) "db5d1cc3-e8f0-11e5-914d-acbc32c1ca87",
 ResourceVersion: (string) "",
 Generation: (int64) 0,
 CreationTimestamp: (unversioned.Time) 2016-03-13 03:54:47.477573961 -0400 EDT,
 DeletionTimestamp: (*unversioned.Time)(<nil>),
 DeletionGracePeriodSeconds: (*int64)(<nil>),
 Labels: (map[string]string) (len=1) {
  (string) (len=3) "foo": (string) (len=3) "bar"
 },
 Annotations: (map[string]string) <nil>
}
(extensions.JobSpec) {
 Parallelism: (*int)(0xc20b1caaa0)(1),
 Completions: (*int)(0xc20b1caaa8)(1),
 ActiveDeadlineSeconds: (*int64)(<nil>),
 Selector: (*unversioned.LabelSelector)(0xc209403220)({
  MatchLabels: (map[string]string) (len=2) {
   (string) (len=3) "foo": (string) (len=3) "bar",
   (string) (len=14) "controller-uid": (string) (len=36) "db5d1cc3-e8f0-11e5-914d-acbc32c1ca87"
  },
  MatchExpressions: ([]unversioned.LabelSelectorRequirement) <nil>
 }),
 ManualSelector: (*bool)(<nil>),
 Template: (api.PodTemplateSpec) {
  ObjectMeta: (api.ObjectMeta) {
   Name: (string) "",
   GenerateName: (string) "",
   Namespace: (string) "",
   SelfLink: (string) "",
   UID: (types.UID) "",
   ResourceVersion: (string) "",
   Generation: (int64) 0,
   CreationTimestamp: (unversioned.Time) 0001-01-01 00:00:00 +0000 UTC,
   DeletionTimestamp: (*unversioned.Time)(<nil>),
   DeletionGracePeriodSeconds: (*int64)(<nil>),
   Labels: (map[string]string) (len=3) {
    (string) (len=3) "foo": (string) (len=3) "bar",
    (string) (len=8) "job-name": (string) (len=7) "testjob",
    (string) (len=14) "controller-uid": (string) (len=36) "db5d1cc3-e8f0-11e5-914d-acbc32c1ca87"
   },
   Annotations: (map[string]string) <nil>
  },
  Spec: (api.PodSpec) {
   Volumes: ([]api.Volume) <nil>,
   Containers: ([]api.Container) (len=1 cap=1) {
    (api.Container) {
     Name: (string) (len=9) "container",
     Image: (string) (len=10) "test/image",
     Command: ([]string) <nil>,
     Args: ([]string) <nil>,
     WorkingDir: (string) "",
     Ports: ([]api.ContainerPort) <nil>,
     Env: ([]api.EnvVar) <nil>,
     Resources: (api.ResourceRequirements) {
      Limits: (api.ResourceList) <nil>,
      Requests: (api.ResourceList) <nil>
     },
     VolumeMounts: ([]api.VolumeMount) <nil>,
     LivenessProbe: (*api.Probe)(<nil>),
     ReadinessProbe: (*api.Probe)(<nil>),
     Lifecycle: (*api.Lifecycle)(<nil>),
     TerminationMessagePath: (string) (len=20) "/dev/termination-log",
     ImagePullPolicy: (api.PullPolicy) (len=6) "Always",
     SecurityContext: (*api.SecurityContext)(<nil>),
     Stdin: (bool) false,
     StdinOnce: (bool) false,
     TTY: (bool) false
    }
   },
   RestartPolicy: (api.RestartPolicy) (len=5) "Never",
   TerminationGracePeriodSeconds: (*int64)(0xc20b1caab8)(30),
   ActiveDeadlineSeconds: (*int64)(<nil>),
   DNSPolicy: (api.DNSPolicy) (len=12) "ClusterFirst",
   NodeSelector: (map[string]string) <nil>,
   ServiceAccountName: (string) "",
   NodeName: (string) (len=20) "nodename.example.com",
   SecurityContext: (*api.PodSecurityContext)(0xc20943c5c0)({
    HostNetwork: (bool) false,
    HostPID: (bool) false,
    HostIPC: (bool) false,
    SELinuxOptions: (*api.SELinuxOptions)(<nil>),
    RunAsUser: (*int64)(<nil>),
    RunAsNonRoot: (*bool)(<nil>),
    SupplementalGroups: ([]int64) <nil>,
    FSGroup: (*int64)(<nil>)
   }),
   ImagePullSecrets: ([]api.LocalObjectReference) <nil>
  }
 }
}

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Comments: 17 (17 by maintainers)

Commits related to this issue

Most upvoted comments

it looks like the issue is that the expected labels only include the generated labels:

    expectedLabels := make(map[string]string)
    expectedLabels["controller-uid"] = string(obj.UID)
    expectedLabels["job-name"] = string(obj.Name)

whereas the selector includes some of the actual template’s labels

including the actual labels from the template in addition to the generated ones correctly indicates if the selector will match