func DeterminePodsSafeToUpdate(cloud *solr.SolrCloud, outOfDatePods []corev1.Pod, totalPods int, readyPods int, availableUpdatedPodCount int, outOfDatePodsNotStartedCount int, logger logr.Logger, httpHeaders map[string]string) (podsToUpdate []corev1.Pod, retryLater bool) {
	// Before fetching the cluster state, be sure that there is room to update at least 1 pod
	maxPodsUnavailable, unavailableUpdatedPodCount, maxPodsToUpdate := calculateMaxPodsToUpdate(cloud, totalPods, len(outOfDatePods), outOfDatePodsNotStartedCount, availableUpdatedPodCount)
	if maxPodsToUpdate <= 0 {
		logger.Info("Pod update selection canceled. The number of updated pods unavailable equals or exceeds the calculated maxPodsUnavailable.",
			"unavailableUpdatedPods", unavailableUpdatedPodCount, "outOfDatePodsNotStarted", outOfDatePodsNotStartedCount, "maxPodsUnavailable", maxPodsUnavailable)
	} else {
		clusterResp := &solr_api.SolrClusterStatusResponse{}
		overseerResp := &solr_api.SolrOverseerStatusResponse{}

		if readyPods > 0 {
			queryParams := url.Values{}
			queryParams.Add("action", "CLUSTERSTATUS")
			err := solr_api.CallCollectionsApi(cloud, queryParams, httpHeaders, clusterResp)
			if err == nil {
				if hasError, apiErr := solr_api.CheckForCollectionsApiError("CLUSTERSTATUS", clusterResp.ResponseHeader); hasError {
					err = apiErr
				} else {
					queryParams.Set("action", "OVERSEERSTATUS")
					err = solr_api.CallCollectionsApi(cloud, queryParams, httpHeaders, overseerResp)
					if hasError, apiErr := solr_api.CheckForCollectionsApiError("OVERSEERSTATUS", clusterResp.ResponseHeader); hasError {
						err = apiErr
					}
				}
			} else {
				logger.Error(err, "Error retrieving cluster status, delaying pod update selection")
				// If there is an error fetching the clusterState, retry later.
				retryLater = true
			}
		}
		// If the update logic already wants to retry later, then do not pick any pods
		if !retryLater {
			logger.Info("Pod update selection started.", "outOfDatePods", len(outOfDatePods), "maxPodsUnavailable", maxPodsUnavailable, "unavailableUpdatedPods", unavailableUpdatedPodCount, "outOfDatePodsNotStarted", outOfDatePodsNotStartedCount, "maxPodsToUpdate", maxPodsToUpdate)
			podsToUpdate = pickPodsToUpdate(cloud, outOfDatePods, clusterResp.ClusterStatus, overseerResp.Leader, totalPods, maxPodsToUpdate, logger)

			// If there are no pods to upgrade, even though the maxPodsToUpdate is >0, then retry later because the issue stems from cluster state
			// and clusterState changes will not call the reconciler.
			if len(podsToUpdate) == 0 && len(outOfDatePods) > 0 {
				retryLater = true
			}
		}
	}
	return podsToUpdate, retryLater
}
// DeterminePodsSafeToUpdate takes a list of solr Pods and returns a list of pods that are safe to upgrade now.
// This function MUST be idempotent and return the same list of pods given the same kubernetes/solr state.
//
// NOTE: It is assumed that the list of pods provided are all started.
// If an out of date pod has a solr container that is not started, it should be accounted for in outOfDatePodsNotStartedCount not outOfDatePods.
//
// TODO:
//  - Think about caching this for ~250 ms? Not a huge need to send these requests milliseconds apart.
//    - Might be too much complexity for very little gain.
DeterminePodsSafeToUpdate takes a list of solr Pods and returns a list of pods that are safe to upgrade now.
This function MUST be idempotent and return the same list of pods given the same kubernetes/solr state.

It is assumed that the list of pods provided are all started.
If an out of date pod has a solr container that is not started, it should be accounted for in outOfDatePodsNotStartedCount not outOfDatePods.

- Think about caching this for ~250 ms. Not a huge need to send these requests milliseconds apart.
- Might be too much complexity for very little gain.
// DeterminePodsSafeToUpdate takes a list of solr Pods and returns a list of pods that are safe to upgrade now . // This function MUST be idempotent and return the same list of pods given the same kubernetes / solr state . // // NOTE : It is assumed that the list of pods provided are all started . // If an out of date pod has a solr container that is not started it should be accounted for in outOfDatePodsNotStartedCount not outOfDatePods . // // TODO : // - Think about caching this for ~250 ms? Not a huge need to send these requests milliseconds apart . // - Might be too much complexity for very little gain .
func DeterminePodsSafeToUpdate(cloud *solr.SolrCloud, outOfDatePods []corev1.Pod, totalPods int, readyPods int, availableUpdatedPodCount int, outOfDatePodsNotStartedCount int, logger logr.Logger, httpHeaders map[string]string) (podsToUpdate []corev1.Pod, retryLater bool) {
	maxPodsUnavailable, unavailableUpdatedPodCount, maxPodsToUpdate := calculateMaxPodsToUpdate(cloud, totalPods, len(outOfDatePods), outOfDatePodsNotStartedCount, availableUpdatedPodCount)
	if maxPodsToUpdate <= 0 {
		logger.Info("Pod update selection canceled. The number of updated pods unavailable equals or exceeds the calculated maxPodsUnavailable.",
			"unavailableUpdatedPods", unavailableUpdatedPodCount, "outOfDatePodsNotStarted", outOfDatePodsNotStartedCount, "maxPodsUnavailable", maxPodsUnavailable)
	} else {
		clusterResp := &solr_api.SolrClusterStatusResponse{}
		overseerResp := &solr_api.SolrOverseerStatusResponse{}
		if readyPods > 0 {
			queryParams := url.Values{}
			queryParams.Add("action", "CLUSTERSTATUS")
			err := solr_api.CallCollectionsApi(cloud, queryParams, httpHeaders, clusterResp)
			if err == nil {
				if hasError, apiErr := solr_api.CheckForCollectionsApiError("CLUSTERSTATUS", clusterResp.ResponseHeader); hasError {
					err = apiErr
				} else {
					queryParams.Set("action", "OVERSEERSTATUS")
					err = solr_api.CallCollectionsApi(cloud, queryParams, httpHeaders, overseerResp)
					if hasError, apiErr := solr_api.CheckForCollectionsApiError("OVERSEERSTATUS", clusterResp.ResponseHeader); hasError {
						err = apiErr
					}
				}
			} else {
				logger.Error(err, "Error retrieving cluster status, delaying pod update selection")
				retryLater = true
			}
		}
		if !retryLater {
			logger.Info("Pod update selection started.", "outOfDatePods", len(outOfDatePods), "maxPodsUnavailable", maxPodsUnavailable, "unavailableUpdatedPods", unavailableUpdatedPodCount, "outOfDatePodsNotStarted", outOfDatePodsNotStartedCount, "maxPodsToUpdate", maxPodsToUpdate)
			podsToUpdate = pickPodsToUpdate(cloud, outOfDatePods, clusterResp.ClusterStatus, overseerResp.Leader, totalPods, maxPodsToUpdate, logger)
			if len(podsToUpdate) == 0 && len(outOfDatePods) > 0 {
				retryLater = true
			}
		}
	}
	return podsToUpdate, retryLater
}
func DeterminePodsSafeToUpdate ( cloud * solr . SolrCloud , outOfDatePods [ ] corev1 . Pod , totalPods int , readyPods int , availableUpdatedPodCount int , outOfDatePodsNotStartedCount int , logger logr . Logger , httpHeaders map [ string ] string ) ( podsToUpdate [ ] corev1 . Pod , retryLater bool ) { maxPodsUnavailable , unavailableUpdatedPodCount , maxPodsToUpdate := calculateMaxPodsToUpdate ( cloud , totalPods , len ( outOfDatePods ) , outOfDatePodsNotStartedCount , availableUpdatedPodCount ) if maxPodsToUpdate <= 0 { logger . Info ( " " , " " , unavailableUpdatedPodCount , " " , outOfDatePodsNotStartedCount , " " , maxPodsUnavailable ) } else { clusterResp := & solr_api . SolrClusterStatusResponse { } overseerResp := & solr_api . SolrOverseerStatusResponse { } if readyPods > 0 { queryParams := url . Values { } queryParams . Add ( " " , " " ) err := solr_api . CallCollectionsApi ( cloud , queryParams , httpHeaders , clusterResp ) if err == nil { if hasError , apiErr := solr_api . CheckForCollectionsApiError ( " " , clusterResp . ResponseHeader ) ; hasError { err = apiErr } else { queryParams . Set ( " " , " " ) err = solr_api . CallCollectionsApi ( cloud , queryParams , httpHeaders , overseerResp ) if hasError , apiErr := solr_api . CheckForCollectionsApiError ( " " , clusterResp . ResponseHeader ) ; hasError { err = apiErr } } } else { logger . Error ( err , " " ) retryLater = true } } if ! retryLater { logger . Info ( " " , " " , len ( outOfDatePods ) , " " , maxPodsUnavailable , " " , unavailableUpdatedPodCount , " " , outOfDatePodsNotStartedCount , " " , maxPodsToUpdate ) podsToUpdate = pickPodsToUpdate ( cloud , outOfDatePods , clusterResp . ClusterStatus , overseerResp . Leader , totalPods , maxPodsToUpdate , logger ) if len ( podsToUpdate ) == 0 && len ( outOfDatePods ) > 0 { retryLater = true } } } return podsToUpdate , retryLater }
DeterminePodsSafeToUpdate takes a list of solr Pods and returns a list of pods that are safe to upgrade now.
DeterminePodsSafeToUpdate takes a list of solr Pods and returns a list of pods that are safe to upgrade now .
// Before fetching the cluster state, be sure that there is room to update at least 1 pod // If there is an error fetching the clusterState, retry later. // If the update logic already wants to retry later, then do not pick any pods // If there are no pods to upgrade, even though the maxPodsToUpdate is >0, then retry later because the issue stems from cluster state // and clusterState changes will not call the reconciler.