Repository: kubernetes/kubernetes
File: pkg/controller/replicaset/replica_set.go (Go)

Code before:
		manageReplicasErr = rsc.manageReplicas(ctx, activePods, rs)
	}
	rs = rs.DeepCopy()
	// Use the same time for calculating status and nextSyncDuration.
	now := rsc.clock.Now()
	newStatus := calculateStatus(rs, activePods, terminatingPods, manageReplicasErr, rsc.controllerFeatures, now)

	// Always updates status as pods come up or die.
	updatedRS, err := updateReplicaSetStatus(logger, rsc.kubeClient.AppsV1().ReplicaSets(rs.Namespace), rs, newStatus, rsc.controllerFeatures)
	if err != nil {
		// Multiple things could lead to this update failing. Requeuing the replica set ensures
		// Returning an error causes a requeue without forcing a hotloop
		return err
	}
	rsc.consistencyStore.WroteAt(
		types.NamespacedName{Name: rs.Name, Namespace: rs.Namespace},
		rs.UID,
		replicaSetGroupResource,
		updatedRS.ResourceVersion,
	)
	if manageReplicasErr != nil {
		return manageReplicasErr
	}
	// Plan the next availability check as a last line of defense against queue preemption (we have one queue key for checking availability of all the pods)
	// or early sync (see https://github.com/kubernetes/kubernetes/issues/39785#issuecomment-279959133 for more info).
	if updatedRS.Spec.MinReadySeconds > 0 &&
		updatedRS.Status.ReadyReplicas != updatedRS.Status.AvailableReplicas {
		// Safeguard fallback to the .spec.minReadySeconds to ensure that we always end up with .status.availableReplicas updated.
		nextSyncDuration = ptr.To(time.Duration(updatedRS.Spec.MinReadySeconds) * time.Second)
		// Use the same point in time (now) for calculating status and nextSyncDuration to get matching availability for the pods.
		if nextCheck := controller.FindMinNextPodAvailabilityCheck(activePods, updatedRS.Spec.MinReadySeconds, now, rsc.clock); nextCheck != nil {
			nextSyncDuration = nextCheck
		}
	}
	if nextSyncDuration != nil {
		rsc.queue.AddAfter(key, *nextSyncDuration)
	}
	return nil
}

func (rsc *ReplicaSetController) claimPods(ctx context.Context, rs *apps.ReplicaSet, selector labels.Selector, filteredPods []*v1.Pod) ([]*v1.Pod, error) {
	// If any adoptions are attempted, we should first recheck for deletion with
	// an uncached quorum read sometime after listing Pods (see #42639).
	canAdoptFunc := controller.RecheckDeletionTimestamp(func(ctx context.Context) (metav1.Object, error) {
		fresh, err := rsc.kubeClient.AppsV1().ReplicaSets(rs.Namespace).Get(ctx, rs.Name, metav1.GetOptions{})
		if err != nil {
			return nil, err
		}
		if fresh.UID != rs.UID {
			return nil, fmt.Errorf("original %v %v/%v is gone: got uid %v, wanted %v", rsc.Kind, rs.Namespace, rs.Name, fresh.UID, rs.UID)
		}

Review comment (bug):
hard-coded `replicaSetGroupResource` will be incorrect for the replication controller variant of this controller ... would need to parameterize this and use `rsc.GroupResource` or something similar

Code after:
	if utilfeature.DefaultFeatureGate.Enabled(features.DeploymentReplicaSetTerminatingReplicas) && rsc.controllerFeatures.EnableStatusTerminatingReplicas {
		allTerminatingPods := controller.FilterTerminatingPods(allRSPods)
		terminatingPods = controller.FilterClaimedPods(rs, selector, allTerminatingPods)
	}

	var manageReplicasErr error
	var nextSyncDuration *time.Duration
	if rsNeedsSync && rs.DeletionTimestamp == nil {
		manageReplicasErr = rsc.manageReplicas(ctx, activePods, rs)
	}
	rs = rs.DeepCopy()
	// Use the same time for calculating status and nextSyncDuration.
	now := rsc.clock.Now()
	newStatus := calculateStatus(rs, activePods, terminatingPods, manageReplicasErr, rsc.controllerFeatures, now)

	// Always updates status as pods come up or die.
	updatedRS, err := updateReplicaSetStatus(logger, rsc.kubeClient.AppsV1().ReplicaSets(rs.Namespace), rs, newStatus, rsc.controllerFeatures)
	if err != nil {
		// Multiple things could lead to this update failing. Requeuing the replica set ensures
		// Returning an error causes a requeue without forcing a hotloop
		return err
	}
	rsc.consistencyStore.WroteAt(
		types.NamespacedName{Name: rs.Name, Namespace: rs.Namespace},
		rs.UID,
		replicaSetGroupResource,
		updatedRS.ResourceVersion,
	)
	if manageReplicasErr != nil {
		return manageReplicasErr
	}
	// Plan the next availability check as a last line of defense against queue preemption (we have one queue key for checking availability of all the pods)
	// or early sync (see https://github.com/kubernetes/kubernetes/issues/39785#issuecomment-279959133 for more info).
	if updatedRS.Spec.MinReadySeconds > 0 &&
		updatedRS.Status.ReadyReplicas != updatedRS.Status.AvailableReplicas {
		// Safeguard fallback to the .spec.minReadySeconds to ensure that we always end up with .status.availableReplicas updated.
		nextSyncDuration = ptr.To(time.Duration(updatedRS.Spec.MinReadySeconds) * time.Second)
		// Use the same point in time (now) for calculating status and nextSyncDuration to get matching availability for the pods.
		if nextCheck := controller.FindMinNextPodAvailabilityCheck(activePods, updatedRS.Spec.MinReadySeconds, now, rsc.clock); nextCheck != nil {
			nextSyncDuration = nextCheck
		}
	}
	if nextSyncDuration != nil {
		rsc.queue.AddAfter(key, *nextSyncDuration)
	}
	return nil
}

func (rsc *ReplicaSetController) claimPods(ctx context.Context, rs *apps.ReplicaSet, selector labels.Selector, filteredPods []*v1.Pod) ([]*v1.Pod, error) {
	// If any adoptions are attempted, we should first recheck for deletion with
	// an uncached quorum read sometime after listing Pods (see #42639).