func()

in pkg/handler/warm.go [59:131]


func (w *warmResourceHandler) HandleCreate(_ int, pod *v1.Pod) (ctrl.Result, error) {
	resourcePool, err := w.getResourcePool(pod.Spec.NodeName)
	if err != nil {
		return ctrl.Result{}, err
	}
	if _, present := pod.Annotations[w.resourceName]; present {
		// Pod has already been allocated the resource, skip the event
		return ctrl.Result{}, nil
	}

	log := w.log.WithValues("UID", string(pod.UID), "namespace",
		pod.Namespace, "name", pod.Name)

	resID, shouldReconcile, err := resourcePool.AssignResource(string(pod.UID))
	if err != nil {
		// Reconcile the pool before retrying or returning an error
		w.reconcilePool(shouldReconcile, resourcePool)
		switch err {
		case pool.ErrResourceAreBeingCooledDown:
			log.V(1).Info("resources are currently being cooled down, will retry")
			w.APIWrapper.K8sAPI.BroadcastEvent(pod, ReasonResourceAllocationFailed,
				fmt.Sprintf("Resource %s are being cooled down, will retry in %s",
					w.resourceName, RequeueAfterWhenResourceCooling), v1.EventTypeWarning)
			return ctrl.Result{Requeue: true, RequeueAfter: RequeueAfterWhenResourceCooling}, nil
		case pool.ErrResourcesAreBeingCreated, pool.ErrWarmPoolEmpty:
			log.V(1).Info("resources are currently being created or warm pool is empty, will retry")
			w.APIWrapper.K8sAPI.BroadcastEvent(pod, ReasonResourceAllocationFailed,
				fmt.Sprintf("Warm pool for resource %s is currently empty, will retry in %s",
					w.resourceName, RequeueAfterWhenWPEmpty), v1.EventTypeWarning)
			return ctrl.Result{Requeue: true, RequeueAfter: RequeueAfterWhenWPEmpty}, nil
		case pool.ErrResourceAlreadyAssigned:
			// The Pod may already have the request annotated, however the cache may not have
			// may not reflect the change immediately.
			pod, err := w.APIWrapper.PodAPI.GetPodFromAPIServer(w.ctx, pod.Namespace, pod.Name)
			if err != nil {
				return ctrl.Result{}, err
			}
			resourceID, present := pod.Annotations[w.resourceName]
			if present {
				log.Info("cache had stale entry, pod already has resource",
					"resource from annotation", resourceID,
					"resource from data store", resID)
				return ctrl.Result{}, nil
			}
			return ctrl.Result{}, err
		case pool.ErrInsufficientCidrBlocks:
			log.V(1).Info("prefix is not available in subnet, will retry")
			w.APIWrapper.K8sAPI.BroadcastEvent(pod, ReasonResourceAllocationFailed,
				fmt.Sprintf("Warm pool for resource %s is currently empty because the specified subnet does not have enough "+
					"free cidr blocks, will retry in %s", w.resourceName, RequeueAfterWhenPrefixNotAvailable), v1.EventTypeWarning)
			return ctrl.Result{Requeue: true, RequeueAfter: RequeueAfterWhenPrefixNotAvailable}, nil
		default:
			return ctrl.Result{}, err
		}
	}

	err = w.APIWrapper.PodAPI.AnnotatePod(pod.Namespace, pod.Name, pod.UID, w.resourceName, resID)
	if err != nil {
		_, errFree := resourcePool.FreeResource(string(pod.UID), resID)
		if errFree != nil {
			err = fmt.Errorf("failed to annotate %v, failed to free %v", err, errFree)
		}
	}

	w.APIWrapper.K8sAPI.BroadcastEvent(pod, ReasonResourceAllocated,
		fmt.Sprintf("Allocated Resource %s: %s to the pod", w.resourceName, resID), v1.EventTypeNormal)

	log.Info("successfully allocated and annotated resource", "resource id", resID)

	w.reconcilePool(shouldReconcile, resourcePool)

	return ctrl.Result{}, err
}