diff --git a/pkg/controller/statefulset/stateful_set_control_test.go b/pkg/controller/statefulset/stateful_set_control_test.go index c7fe131996c..a7db67285a9 100644 --- a/pkg/controller/statefulset/stateful_set_control_test.go +++ b/pkg/controller/statefulset/stateful_set_control_test.go @@ -227,6 +227,31 @@ func CreatesPods(t *testing.T, set *apps.StatefulSet, invariants invariantFunc) if set.Status.UpdatedReplicas != 3 { t.Error("Failed to set UpdatedReplicas correctly") } + // Check all pods have correct pod index label. + if utilfeature.DefaultFeatureGate.Enabled(features.PodIndexLabel) { + selector, err := metav1.LabelSelectorAsSelector(set.Spec.Selector) + if err != nil { + t.Error(err) + } + pods, err := om.podsLister.Pods(set.Namespace).List(selector) + if err != nil { + t.Error(err) + } + if len(pods) != 3 { + t.Errorf("Expected 3 pods, got %d", len(pods)) + } + for _, pod := range pods { + podIndexFromLabel, exists := pod.Labels[apps.PodIndexLabel] + if !exists { + t.Errorf("Missing pod index label: %s", apps.PodIndexLabel) + continue + } + podIndexFromName := strconv.Itoa(getOrdinal(pod)) + if podIndexFromLabel != podIndexFromName { + t.Errorf("Pod index label value (%s) does not match pod index in pod name (%s)", podIndexFromLabel, podIndexFromName) + } + } + } } func ScalesUp(t *testing.T, set *apps.StatefulSet, invariants invariantFunc) { diff --git a/pkg/controller/statefulset/stateful_set_utils.go b/pkg/controller/statefulset/stateful_set_utils.go index 5ab1f9af114..6898aabe56e 100644 --- a/pkg/controller/statefulset/stateful_set_utils.go +++ b/pkg/controller/statefulset/stateful_set_utils.go @@ -390,12 +390,16 @@ func initIdentity(set *apps.StatefulSet, pod *v1.Pod) { // updateIdentity updates pod's name, hostname, and subdomain, and StatefulSetPodNameLabel to conform to set's name // and headless service. func updateIdentity(set *apps.StatefulSet, pod *v1.Pod) { - pod.Name = getPodName(set, getOrdinal(pod)) + ordinal := getOrdinal(pod) + pod.Name = getPodName(set, ordinal) pod.Namespace = set.Namespace if pod.Labels == nil { pod.Labels = make(map[string]string) } pod.Labels[apps.StatefulSetPodNameLabel] = pod.Name + if utilfeature.DefaultFeatureGate.Enabled(features.PodIndexLabel) { + pod.Labels[apps.PodIndexLabel] = strconv.Itoa(ordinal) + } } // isRunningAndReady returns true if pod is in the PodRunning Phase, if it has a condition of PodReady. diff --git a/staging/src/k8s.io/api/apps/v1/types.go b/staging/src/k8s.io/api/apps/v1/types.go index 15dc3150a63..644d368fe4d 100644 --- a/staging/src/k8s.io/api/apps/v1/types.go +++ b/staging/src/k8s.io/api/apps/v1/types.go @@ -17,7 +17,7 @@ limitations under the License. package v1 import ( - "k8s.io/api/core/v1" + v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/intstr" @@ -29,6 +29,7 @@ const ( DeprecatedRollbackTo = "deprecated.deployment.rollback.to" DeprecatedTemplateGeneration = "deprecated.daemonset.template.generation" StatefulSetPodNameLabel = "statefulset.kubernetes.io/pod-name" + PodIndexLabel = "apps.kubernetes.io/pod-index" ) // +genclient