func EvictReplicasForPodIfNecessary()

in controllers/util/solr_update_util.go [551:616]


func EvictReplicasForPodIfNecessary(ctx context.Context, solrCloud *solr.SolrCloud, pod *corev1.Pod, podHasReplicas bool, evictionReason string, logger logr.Logger) (err error, canDeletePod bool, requestInProgress bool) {
	logger = logger.WithValues("evictionReason", evictionReason)
	// If the Cloud has 1 or zero pods, and this is the "-0" pod, then delete the data since we can't move it anywhere else
	// Otherwise, move the replicas to other pods
	if (solrCloud.Spec.Replicas == nil || *solrCloud.Spec.Replicas < 2) && strings.HasSuffix(pod.Name, "-0") {
		queryParams := url.Values{}
		queryParams.Add("action", "DELETENODE")
		queryParams.Add("node", SolrNodeName(solrCloud, pod.Name))
		// TODO: Figure out a way to do this, since DeleteNode will not delete the last replica of every type...
		canDeletePod = true
	} else {
		requestId := "move-replicas-" + pod.Name

		// First check to see if the Async Replace request has started
		if asyncState, message, asyncErr := solr_api.CheckAsyncRequest(ctx, solrCloud, requestId); asyncErr != nil {
			err = asyncErr
			logger.Error(err, "Error occurred while checking the status of the ReplaceNode task. Will try again.", "requestId", requestId)
		} else if asyncState == "notfound" {
			if podHasReplicas {
				// Submit new Replace Node request
				replaceResponse := &solr_api.SolrAsyncResponse{}
				queryParams := url.Values{}
				queryParams.Add("action", "REPLACENODE")
				queryParams.Add("parallel", "true")
				queryParams.Add("sourceNode", SolrNodeName(solrCloud, pod.Name))
				queryParams.Add("waitForFinalState", "true")
				queryParams.Add("async", requestId)
				err = solr_api.CallCollectionsApi(ctx, solrCloud, queryParams, replaceResponse)
				if _, apiErr := solr_api.CheckForCollectionsApiError("REPLACENODE", replaceResponse.ResponseHeader, replaceResponse.Error); apiErr != nil {
					err = apiErr
				}
				if err == nil {
					logger.Info("Migrating all replicas off of pod before deletion.", "requestId", requestId, "pod", pod.Name)
					requestInProgress = true
				} else {
					logger.Error(err, "Could not migrate all replicas off of pod before deletion. Will try again.")
				}
			} else {
				canDeletePod = true
			}

		} else {
			logger.Info("Found async status", "requestId", requestId, "state", asyncState)
			// Only continue to delete the pod if the ReplaceNode request is complete and successful
			if asyncState == "completed" {
				canDeletePod = true
				logger.Info("Migration of all replicas off of pod before deletion complete. Pod can now be deleted.", "pod", pod.Name)
			} else if asyncState == "failed" {
				logger.Info("Migration of all replicas off of pod before deletion failed. Will try again.", "pod", pod.Name, "message", message)
			} else {
				requestInProgress = true
			}

			// Delete the async request Id if the async request is successful or failed.
			// If the request failed, this will cause a retry since the next reconcile won't find the async requestId in Solr.
			if asyncState == "completed" || asyncState == "failed" {
				if _, err = solr_api.DeleteAsyncRequest(ctx, solrCloud, requestId); err != nil {
					logger.Error(err, "Could not delete Async request status.", "requestId", requestId)
					canDeletePod = false
					requestInProgress = true
				}
			}
		}
	}
	return err, canDeletePod, requestInProgress
}