mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-03 19:58:17 +00:00 
			
		
		
		
	specify pod name and hostname in indexed job
This commit is contained in:
		@@ -449,6 +449,8 @@ type PodControlInterface interface {
 | 
			
		||||
	CreatePods(namespace string, template *v1.PodTemplateSpec, object runtime.Object) error
 | 
			
		||||
	// CreatePodsWithControllerRef creates new pods according to the spec, and sets object as the pod's controller.
 | 
			
		||||
	CreatePodsWithControllerRef(namespace string, template *v1.PodTemplateSpec, object runtime.Object, controllerRef *metav1.OwnerReference) error
 | 
			
		||||
	// CreatePodsWithControllerRefAndGenerateName creates new pods according to the spec, sets object as the pod's controller and sets pod's generateName.
 | 
			
		||||
	CreatePodsWithControllerRefAndGenerateName(namespace string, template *v1.PodTemplateSpec, object runtime.Object, controllerRef *metav1.OwnerReference, generateName string) error
 | 
			
		||||
	// DeletePod deletes the pod identified by podID.
 | 
			
		||||
	DeletePod(namespace string, podID string, object runtime.Object) error
 | 
			
		||||
	// PatchPod patches the pod.
 | 
			
		||||
@@ -514,14 +516,29 @@ func validateControllerRef(controllerRef *metav1.OwnerReference) error {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r RealPodControl) CreatePods(namespace string, template *v1.PodTemplateSpec, object runtime.Object) error {
 | 
			
		||||
	return r.createPods(namespace, template, object, nil)
 | 
			
		||||
	pod, err := GetPodFromTemplate(template, object, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	return r.createPods(namespace, pod, object)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r RealPodControl) CreatePodsWithControllerRef(namespace string, template *v1.PodTemplateSpec, controllerObject runtime.Object, controllerRef *metav1.OwnerReference) error {
 | 
			
		||||
	return r.CreatePodsWithControllerRefAndGenerateName(namespace, template, controllerObject, controllerRef, "")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r RealPodControl) CreatePodsWithControllerRefAndGenerateName(namespace string, template *v1.PodTemplateSpec, controllerObject runtime.Object, controllerRef *metav1.OwnerReference, generateName string) error {
 | 
			
		||||
	if err := validateControllerRef(controllerRef); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	return r.createPods(namespace, template, controllerObject, controllerRef)
 | 
			
		||||
	pod, err := GetPodFromTemplate(template, controllerObject, controllerRef)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if len(generateName) > 0 {
 | 
			
		||||
		pod.ObjectMeta.GenerateName = generateName
 | 
			
		||||
	}
 | 
			
		||||
	return r.createPods(namespace, pod, controllerObject)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r RealPodControl) PatchPod(namespace, name string, data []byte) error {
 | 
			
		||||
@@ -554,11 +571,7 @@ func GetPodFromTemplate(template *v1.PodTemplateSpec, parentObject runtime.Objec
 | 
			
		||||
	return pod, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r RealPodControl) createPods(namespace string, template *v1.PodTemplateSpec, object runtime.Object, controllerRef *metav1.OwnerReference) error {
 | 
			
		||||
	pod, err := GetPodFromTemplate(template, object, controllerRef)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
func (r RealPodControl) createPods(namespace string, pod *v1.Pod, object runtime.Object) error {
 | 
			
		||||
	if len(labels.Set(pod.Labels)) == 0 {
 | 
			
		||||
		return fmt.Errorf("unable to create pods, no labels")
 | 
			
		||||
	}
 | 
			
		||||
@@ -652,6 +665,21 @@ func (f *FakePodControl) CreatePodsWithControllerRef(namespace string, spec *v1.
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (f *FakePodControl) CreatePodsWithControllerRefAndGenerateName(namespace string, spec *v1.PodTemplateSpec, object runtime.Object, controllerRef *metav1.OwnerReference, generateNamePrefix string) error {
 | 
			
		||||
	f.Lock()
 | 
			
		||||
	defer f.Unlock()
 | 
			
		||||
	f.CreateCallCount++
 | 
			
		||||
	if f.CreateLimit != 0 && f.CreateCallCount > f.CreateLimit {
 | 
			
		||||
		return fmt.Errorf("not creating pod, limit %d already reached (create call %d)", f.CreateLimit, f.CreateCallCount)
 | 
			
		||||
	}
 | 
			
		||||
	f.Templates = append(f.Templates, *spec)
 | 
			
		||||
	f.ControllerRefs = append(f.ControllerRefs, *controllerRef)
 | 
			
		||||
	if f.Err != nil {
 | 
			
		||||
		return f.Err
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (f *FakePodControl) DeletePod(namespace string, podID string, object runtime.Object) error {
 | 
			
		||||
	f.Lock()
 | 
			
		||||
	defer f.Unlock()
 | 
			
		||||
 
 | 
			
		||||
@@ -29,6 +29,7 @@ import (
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	apps "k8s.io/api/apps/v1"
 | 
			
		||||
	batchv1 "k8s.io/api/batch/v1"
 | 
			
		||||
	v1 "k8s.io/api/core/v1"
 | 
			
		||||
	apiequality "k8s.io/apimachinery/pkg/api/equality"
 | 
			
		||||
	apierrors "k8s.io/apimachinery/pkg/api/errors"
 | 
			
		||||
@@ -320,6 +321,47 @@ func TestCreatePods(t *testing.T) {
 | 
			
		||||
		"Body: %s", fakeHandler.RequestBody)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestCreatePodsWithControllerRefAndGenerateName(t *testing.T) {
 | 
			
		||||
	ns := metav1.NamespaceDefault
 | 
			
		||||
	body := runtime.EncodeOrDie(clientscheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "empty_pod"}})
 | 
			
		||||
	fakeHandler := utiltesting.FakeHandler{
 | 
			
		||||
		StatusCode:   200,
 | 
			
		||||
		ResponseBody: string(body),
 | 
			
		||||
	}
 | 
			
		||||
	testServer := httptest.NewServer(&fakeHandler)
 | 
			
		||||
	defer testServer.Close()
 | 
			
		||||
	clientset := clientset.NewForConfigOrDie(&restclient.Config{Host: testServer.URL, ContentConfig: restclient.ContentConfig{GroupVersion: &schema.GroupVersion{Group: "", Version: "v1"}}})
 | 
			
		||||
 | 
			
		||||
	podControl := RealPodControl{
 | 
			
		||||
		KubeClient: clientset,
 | 
			
		||||
		Recorder:   &record.FakeRecorder{},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	controllerSpec := newReplicationController(1)
 | 
			
		||||
	controllerRef := metav1.NewControllerRef(controllerSpec, batchv1.SchemeGroupVersion.WithKind("Job"))
 | 
			
		||||
 | 
			
		||||
	// Make sure createReplica sends a POST to the apiserver with a pod from the controllers pod template
 | 
			
		||||
	generateName := "hello-"
 | 
			
		||||
	err := podControl.CreatePodsWithControllerRefAndGenerateName(ns, controllerSpec.Spec.Template, controllerSpec, controllerRef, generateName)
 | 
			
		||||
	assert.NoError(t, err, "unexpected error: %v", err)
 | 
			
		||||
 | 
			
		||||
	expectedPod := v1.Pod{
 | 
			
		||||
		ObjectMeta: metav1.ObjectMeta{
 | 
			
		||||
			Labels:          controllerSpec.Spec.Template.Labels,
 | 
			
		||||
			GenerateName:    generateName,
 | 
			
		||||
			OwnerReferences: []metav1.OwnerReference{*controllerRef},
 | 
			
		||||
		},
 | 
			
		||||
		Spec: controllerSpec.Spec.Template.Spec,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fakeHandler.ValidateRequest(t, "/api/v1/namespaces/default/pods", "POST", nil)
 | 
			
		||||
	var actualPod = &v1.Pod{}
 | 
			
		||||
	err = json.Unmarshal([]byte(fakeHandler.RequestBody), actualPod)
 | 
			
		||||
	assert.NoError(t, err, "unexpected error: %v", err)
 | 
			
		||||
	assert.True(t, apiequality.Semantic.DeepDerivative(&expectedPod, actualPod),
 | 
			
		||||
		"Body: %s", fakeHandler.RequestBody)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestDeletePodsAllowsMissing(t *testing.T) {
 | 
			
		||||
	fakeClient := fake.NewSimpleClientset()
 | 
			
		||||
	podControl := RealPodControl{
 | 
			
		||||
 
 | 
			
		||||
@@ -26,6 +26,7 @@ import (
 | 
			
		||||
	batch "k8s.io/api/batch/v1"
 | 
			
		||||
	v1 "k8s.io/api/core/v1"
 | 
			
		||||
	"k8s.io/apimachinery/pkg/util/sets"
 | 
			
		||||
	"k8s.io/apiserver/pkg/storage/names"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/controller"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@@ -216,6 +217,15 @@ func addCompletionIndexAnnotation(template *v1.PodTemplateSpec, index int) {
 | 
			
		||||
	template.Annotations[batch.JobCompletionIndexAnnotation] = strconv.Itoa(index)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func podGenerateNameWithIndex(jobName string, index int) string {
 | 
			
		||||
	appendIndex := "-" + strconv.Itoa(index) + "-"
 | 
			
		||||
	generateNamePrefix := jobName + appendIndex
 | 
			
		||||
	if len(generateNamePrefix) > names.MaxGeneratedNameLength {
 | 
			
		||||
		generateNamePrefix = generateNamePrefix[:names.MaxGeneratedNameLength-len(appendIndex)] + appendIndex
 | 
			
		||||
	}
 | 
			
		||||
	return generateNamePrefix
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type byCompletionIndex []*v1.Pod
 | 
			
		||||
 | 
			
		||||
func (bci byCompletionIndex) Less(i, j int) bool {
 | 
			
		||||
 
 | 
			
		||||
@@ -269,6 +269,38 @@ func TestAppendDuplicatedIndexPodsForRemoval(t *testing.T) {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestPodGenerateNameWithIndex(t *testing.T) {
 | 
			
		||||
	cases := map[string]struct {
 | 
			
		||||
		jobname             string
 | 
			
		||||
		index               int
 | 
			
		||||
		wantPodGenerateName string
 | 
			
		||||
	}{
 | 
			
		||||
		"short job name": {
 | 
			
		||||
			jobname:             "indexed-job",
 | 
			
		||||
			index:               1,
 | 
			
		||||
			wantPodGenerateName: "indexed-job-1-",
 | 
			
		||||
		},
 | 
			
		||||
		"job name exceeds MaxGeneneratedNameLength": {
 | 
			
		||||
			jobname:             "hhhhhooooohhhhhooooohhhhhooooohhhhhooooohhhhhooooohhhhhooooohhhhhooooo",
 | 
			
		||||
			index:               1,
 | 
			
		||||
			wantPodGenerateName: "hhhhhooooohhhhhooooohhhhhooooohhhhhooooohhhhhooooohhhhh-1-",
 | 
			
		||||
		},
 | 
			
		||||
		"job name with index suffix exceeds MaxGeneratedNameLength": {
 | 
			
		||||
			jobname:             "hhhhhooooohhhhhooooohhhhhooooohhhhhooooohhhhhooooohhhhhoo",
 | 
			
		||||
			index:               1,
 | 
			
		||||
			wantPodGenerateName: "hhhhhooooohhhhhooooohhhhhooooohhhhhooooohhhhhooooohhhhh-1-",
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	for name, tc := range cases {
 | 
			
		||||
		t.Run(name, func(t *testing.T) {
 | 
			
		||||
			podGenerateName := podGenerateNameWithIndex(tc.jobname, tc.index)
 | 
			
		||||
			if diff := cmp.Equal(tc.wantPodGenerateName, podGenerateName); !diff {
 | 
			
		||||
				t.Errorf("Got pod generateName %s, want %s", podGenerateName, tc.wantPodGenerateName)
 | 
			
		||||
			}
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func hollowPodsWithIndexPhase(descs []indexPhase) []*v1.Pod {
 | 
			
		||||
	pods := make([]*v1.Pod, 0, len(descs))
 | 
			
		||||
	for _, desc := range descs {
 | 
			
		||||
 
 | 
			
		||||
@@ -871,9 +871,11 @@ func (jm *Controller) manageJob(job *batch.Job, activePods []*v1.Pod, succeeded
 | 
			
		||||
					if completionIndex != unknownCompletionIndex {
 | 
			
		||||
						template = podTemplate.DeepCopy()
 | 
			
		||||
						addCompletionIndexAnnotation(template, completionIndex)
 | 
			
		||||
						template.Spec.Hostname = fmt.Sprintf("%s-%d", job.Name, completionIndex)
 | 
			
		||||
					}
 | 
			
		||||
					defer wait.Done()
 | 
			
		||||
					err := jm.podControl.CreatePodsWithControllerRef(job.Namespace, template, job, metav1.NewControllerRef(job, controllerKind))
 | 
			
		||||
					generateName := podGenerateNameWithIndex(job.Name, completionIndex)
 | 
			
		||||
					err := jm.podControl.CreatePodsWithControllerRefAndGenerateName(job.Namespace, template, job, metav1.NewControllerRef(job, controllerKind), generateName)
 | 
			
		||||
					if err != nil {
 | 
			
		||||
						if apierrors.HasStatusCause(err, v1.NamespaceTerminatingCause) {
 | 
			
		||||
							// If the namespace is being torn down, we can safely ignore
 | 
			
		||||
 
 | 
			
		||||
@@ -151,6 +151,7 @@ func setPodsStatusesWithIndexes(podIndexer cache.Indexer, job *batch.Job, status
 | 
			
		||||
			p.Annotations = map[string]string{
 | 
			
		||||
				batch.JobCompletionIndexAnnotation: s.Index,
 | 
			
		||||
			}
 | 
			
		||||
			p.Spec.Hostname = fmt.Sprintf("%s-%s", job.Name, s.Index)
 | 
			
		||||
		}
 | 
			
		||||
		podIndexer.Add(p)
 | 
			
		||||
	}
 | 
			
		||||
@@ -735,7 +736,7 @@ func TestControllerSyncJob(t *testing.T) {
 | 
			
		||||
				t.Errorf("Unexpected number of creates.  Expected %d, saw %d\n", tc.expectedCreations, len(fakePodControl.Templates))
 | 
			
		||||
			}
 | 
			
		||||
			if tc.completionMode == batch.IndexedCompletion {
 | 
			
		||||
				checkCompletionIndexesInPods(t, &fakePodControl, tc.expectedCreatedIndexes)
 | 
			
		||||
				checkIndexedJobPods(t, &fakePodControl, tc.expectedCreatedIndexes, job.Name)
 | 
			
		||||
			}
 | 
			
		||||
			if int32(len(fakePodControl.DeletePodName)) != tc.expectedDeletions {
 | 
			
		||||
				t.Errorf("Unexpected number of deletes.  Expected %d, saw %d\n", tc.expectedDeletions, len(fakePodControl.DeletePodName))
 | 
			
		||||
@@ -806,7 +807,7 @@ func TestControllerSyncJob(t *testing.T) {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func checkCompletionIndexesInPods(t *testing.T, control *controller.FakePodControl, wantIndexes sets.Int) {
 | 
			
		||||
func checkIndexedJobPods(t *testing.T, control *controller.FakePodControl, wantIndexes sets.Int, jobName string) {
 | 
			
		||||
	t.Helper()
 | 
			
		||||
	gotIndexes := sets.NewInt()
 | 
			
		||||
	for _, p := range control.Templates {
 | 
			
		||||
@@ -817,6 +818,10 @@ func checkCompletionIndexesInPods(t *testing.T, control *controller.FakePodContr
 | 
			
		||||
		} else {
 | 
			
		||||
			gotIndexes.Insert(ix)
 | 
			
		||||
		}
 | 
			
		||||
		expectedName := fmt.Sprintf("%s-%d", jobName, ix)
 | 
			
		||||
		if diff := cmp.Equal(expectedName, p.Spec.Hostname); !diff {
 | 
			
		||||
			t.Errorf("Got pod hostname %s, want %s", p.Spec.Hostname, expectedName)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if diff := cmp.Diff(wantIndexes.List(), gotIndexes.List()); diff != "" {
 | 
			
		||||
		t.Errorf("Unexpected created completion indexes (-want,+got):\n%s", diff)
 | 
			
		||||
 
 | 
			
		||||
@@ -43,12 +43,12 @@ const (
 | 
			
		||||
	// TODO: make this flexible for non-core resources with alternate naming rules.
 | 
			
		||||
	maxNameLength          = 63
 | 
			
		||||
	randomLength           = 5
 | 
			
		||||
	maxGeneratedNameLength = maxNameLength - randomLength
 | 
			
		||||
	MaxGeneratedNameLength = maxNameLength - randomLength
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (simpleNameGenerator) GenerateName(base string) string {
 | 
			
		||||
	if len(base) > maxGeneratedNameLength {
 | 
			
		||||
		base = base[:maxGeneratedNameLength]
 | 
			
		||||
	if len(base) > MaxGeneratedNameLength {
 | 
			
		||||
		base = base[:MaxGeneratedNameLength]
 | 
			
		||||
	}
 | 
			
		||||
	return fmt.Sprintf("%s%s", base, utilrand.String(randomLength))
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -153,7 +153,7 @@ var _ = SIGDescribe("Job", func() {
 | 
			
		||||
		Testcase: Ensure Pods of an Indexed Job get a unique index.
 | 
			
		||||
		Description: Create an Indexed Job, wait for completion, capture the output of the pods and verify that they contain the completion index.
 | 
			
		||||
	*/
 | 
			
		||||
	ginkgo.It("[Feature:IndexedJob] should create pods for an Indexed job with completion indexes", func() {
 | 
			
		||||
	ginkgo.It("[Feature:IndexedJob] should create pods for an Indexed job with completion indexes and specified hostname", func() {
 | 
			
		||||
		ginkgo.By("Creating Indexed job")
 | 
			
		||||
		job := e2ejob.NewTestJob("succeed", "indexed-job", v1.RestartPolicyNever, parallelism, completions, nil, backoffLimit)
 | 
			
		||||
		mode := batchv1.IndexedCompletion
 | 
			
		||||
@@ -174,11 +174,13 @@ var _ = SIGDescribe("Job", func() {
 | 
			
		||||
				ix, err := strconv.Atoi(pod.Annotations[batchv1.JobCompletionIndexAnnotation])
 | 
			
		||||
				framework.ExpectNoError(err, "failed obtaining completion index from pod in namespace: %s", f.Namespace.Name)
 | 
			
		||||
				succeededIndexes.Insert(ix)
 | 
			
		||||
				expectedName := fmt.Sprintf("%s-%d", job.Name, ix)
 | 
			
		||||
				framework.ExpectEqual(pod.Spec.Hostname, expectedName, "expected completed pod with hostname %s, but got %s", expectedName, pod.Spec.Hostname)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		gotIndexes := succeededIndexes.List()
 | 
			
		||||
		wantIndexes := []int{0, 1, 2, 3}
 | 
			
		||||
		framework.ExpectEqual(gotIndexes, wantIndexes, "expected completed indexes %s, but got %s", gotIndexes, wantIndexes)
 | 
			
		||||
		framework.ExpectEqual(gotIndexes, wantIndexes, "expected completed indexes %s, but got %s", wantIndexes, gotIndexes)
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
 
 | 
			
		||||
@@ -214,7 +214,7 @@ func TestIndexedJob(t *testing.T) {
 | 
			
		||||
	validateJobPodsStatus(ctx, t, clientSet, jobObj, podsByStatus{
 | 
			
		||||
		Active: 3,
 | 
			
		||||
	})
 | 
			
		||||
	validateJobPodsIndexes(ctx, t, clientSet, jobObj, sets.NewInt(0, 1, 2), "")
 | 
			
		||||
	validateIndexedJobPods(ctx, t, clientSet, jobObj, sets.NewInt(0, 1, 2), "")
 | 
			
		||||
 | 
			
		||||
	// One Pod succeeds.
 | 
			
		||||
	if err := setJobPhaseForIndex(ctx, clientSet, jobObj, v1.PodSucceeded, 1); err != nil {
 | 
			
		||||
@@ -224,7 +224,7 @@ func TestIndexedJob(t *testing.T) {
 | 
			
		||||
		Active:    3,
 | 
			
		||||
		Succeeded: 1,
 | 
			
		||||
	})
 | 
			
		||||
	validateJobPodsIndexes(ctx, t, clientSet, jobObj, sets.NewInt(0, 2, 3), "1")
 | 
			
		||||
	validateIndexedJobPods(ctx, t, clientSet, jobObj, sets.NewInt(0, 2, 3), "1")
 | 
			
		||||
 | 
			
		||||
	// Disable feature gate and restart controller.
 | 
			
		||||
	defer featuregatetesting.SetFeatureGateDuringTest(t, feature.DefaultFeatureGate, features.IndexedJob, false)()
 | 
			
		||||
@@ -243,7 +243,7 @@ func TestIndexedJob(t *testing.T) {
 | 
			
		||||
	if err := waitForEvent(events, jobObj.UID, "IndexedJobDisabled"); err != nil {
 | 
			
		||||
		t.Errorf("Waiting for an event for IndexedJobDisabled: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	validateJobPodsIndexes(ctx, t, clientSet, jobObj, sets.NewInt(0, 3), "1")
 | 
			
		||||
	validateIndexedJobPods(ctx, t, clientSet, jobObj, sets.NewInt(0, 3), "1")
 | 
			
		||||
 | 
			
		||||
	// Re-enable feature gate and restart controller. Failed Pod should be recreated now.
 | 
			
		||||
	defer featuregatetesting.SetFeatureGateDuringTest(t, feature.DefaultFeatureGate, features.IndexedJob, true)()
 | 
			
		||||
@@ -255,7 +255,7 @@ func TestIndexedJob(t *testing.T) {
 | 
			
		||||
		Failed:    1,
 | 
			
		||||
		Succeeded: 1,
 | 
			
		||||
	})
 | 
			
		||||
	validateJobPodsIndexes(ctx, t, clientSet, jobObj, sets.NewInt(0, 2, 3), "1")
 | 
			
		||||
	validateIndexedJobPods(ctx, t, clientSet, jobObj, sets.NewInt(0, 2, 3), "1")
 | 
			
		||||
 | 
			
		||||
	// Remaining Pods succeed.
 | 
			
		||||
	if err := setJobPodsPhase(ctx, clientSet, jobObj, v1.PodSucceeded, 3); err != nil {
 | 
			
		||||
@@ -266,7 +266,7 @@ func TestIndexedJob(t *testing.T) {
 | 
			
		||||
		Failed:    1,
 | 
			
		||||
		Succeeded: 4,
 | 
			
		||||
	})
 | 
			
		||||
	validateJobPodsIndexes(ctx, t, clientSet, jobObj, nil, "0-3")
 | 
			
		||||
	validateIndexedJobPods(ctx, t, clientSet, jobObj, nil, "0-3")
 | 
			
		||||
	validateJobSucceeded(ctx, t, clientSet, jobObj)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -439,9 +439,10 @@ func validateJobPodsStatus(ctx context.Context, t *testing.T, clientSet clientse
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// validateJobPodsIndexes validates indexes of active and completed Pods of an
 | 
			
		||||
// Indexed Job. Call after validateJobPodsStatus
 | 
			
		||||
func validateJobPodsIndexes(ctx context.Context, t *testing.T, clientSet clientset.Interface, jobObj *batchv1.Job, wantActive sets.Int, gotCompleted string) {
 | 
			
		||||
// validateIndexedJobPods validates indexes and hostname of
 | 
			
		||||
// active and completed Pods of an Indexed Job.
 | 
			
		||||
// Call after validateJobPodsStatus
 | 
			
		||||
func validateIndexedJobPods(ctx context.Context, t *testing.T, clientSet clientset.Interface, jobObj *batchv1.Job, wantActive sets.Int, gotCompleted string) {
 | 
			
		||||
	t.Helper()
 | 
			
		||||
	updatedJob, err := clientSet.BatchV1().Jobs(jobObj.Namespace).Get(ctx, jobObj.Name, metav1.GetOptions{})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
@@ -458,11 +459,16 @@ func validateJobPodsIndexes(ctx context.Context, t *testing.T, clientSet clients
 | 
			
		||||
	for _, pod := range pods.Items {
 | 
			
		||||
		if isPodOwnedByJob(&pod, jobObj) {
 | 
			
		||||
			if pod.Status.Phase == v1.PodPending || pod.Status.Phase == v1.PodRunning {
 | 
			
		||||
				if ix, err := getCompletionIndex(&pod); err != nil {
 | 
			
		||||
				ix, err := getCompletionIndex(&pod)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					t.Errorf("Failed getting completion index for pod %s: %v", pod.Name, err)
 | 
			
		||||
				} else {
 | 
			
		||||
					gotActive.Insert(ix)
 | 
			
		||||
				}
 | 
			
		||||
				expectedName := fmt.Sprintf("%s-%d", jobObj.Name, ix)
 | 
			
		||||
				if diff := cmp.Equal(expectedName, pod.Spec.Hostname); !diff {
 | 
			
		||||
					t.Errorf("Got pod hostname %s, want %s", pod.Spec.Hostname, expectedName)
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user