func()

in pkg/controller/build/monitor_pod.go [65:196]


func (action *monitorPodAction) Handle(ctx context.Context, build *v1.Build) (*v1.Build, error) {
	pod, err := getBuilderPod(ctx, action.reader, build)
	if err != nil {
		return nil, err
	}

	if pod == nil {
		switch build.Status.Phase {

		case v1.BuildPhasePending:
			if pod, err = newBuildPod(ctx, action.reader, action.client, build); err != nil {
				return nil, err
			}

			// If the Builder Pod is in the Build namespace, we can set the ownership to it. If not (global operator mode)
			// we set the ownership to the Operator Pod instead
			var owner metav1.Object
			owner = build
			if build.Namespace != pod.Namespace {
				operatorPod := platform.GetOperatorPod(ctx, action.reader, pod.Namespace)
				if operatorPod != nil {
					owner = operatorPod
				}
			}
			if err = controllerutil.SetControllerReference(owner, pod, action.client.GetScheme()); err != nil {
				return nil, err
			}

			if err = action.client.Create(ctx, pod); err != nil {
				return nil, fmt.Errorf("cannot create build pod: %w", err)
			}

		case v1.BuildPhaseRunning:
			// Emulate context cancellation
			build.Status.Phase = v1.BuildPhaseInterrupted
			build.Status.Error = "Pod deleted"
			monitorFinishedBuild(build)
			return build, nil
		}
	}

	switch pod.Status.Phase {

	case corev1.PodPending, corev1.PodRunning:
		// Pod remains in pending phase when init containers execute
		if action.isPodScheduled(pod) {
			build.Status.Phase = v1.BuildPhaseRunning
		}
		if time.Since(build.Status.StartedAt.Time) > build.Spec.Timeout.Duration {
			// Patch the Pod with an annotation, to identify termination signal
			// has been sent because the Build has timed out
			if err = action.addTimeoutAnnotation(ctx, pod, metav1.Now()); err != nil {
				return nil, err
			}
			// Send SIGTERM signal to running containers
			if err = action.sigterm(pod); err != nil {
				// Requeue
				return nil, err
			}

			monitorFinishedBuild(build)
		} else {
			// Monitor running state of the build - this may have been done already by the schedule action but the build monitor is idempotent
			// We do this here to potentially restore the running build state in the monitor in case of an operator restart
			monitorRunningBuild(build)
		}

	case corev1.PodSucceeded:
		build.Status.Phase = v1.BuildPhaseSucceeded
		// Remove the annotation in case the Build succeeded, between
		// the timeout deadline and the termination signal.
		if err = action.removeTimeoutAnnotation(ctx, pod); err != nil {
			return nil, err
		}
		finishedAt := action.getTerminatedTime(pod)
		duration := finishedAt.Sub(build.Status.StartedAt.Time)
		build.Status.Duration = duration.String()
		action.setConditionsFromTerminationMessages(ctx, pod, &build.Status)
		monitorFinishedBuild(build)

		buildCreator := kubernetes.GetCamelCreator(build)
		// Account for the Build metrics
		observeBuildResult(build, build.Status.Phase, buildCreator, duration)

		for _, task := range build.Spec.Tasks {
			if t := task.Buildah; t != nil {
				build.Status.Image = t.Image

				break
			} else if t := task.Kaniko; t != nil {
				build.Status.Image = t.Image

				break
			}
		}
		// Reconcile image digest from build container status if available
		for _, container := range pod.Status.ContainerStatuses {
			if container.Name == "buildah" {
				build.Status.Digest = container.State.Terminated.Message

				break
			}
		}

	case corev1.PodFailed:
		phase := v1.BuildPhaseFailed
		message := fmt.Sprintf("Builder Pod %s failed (see conditions for more details)", pod.Name)
		if pod.DeletionTimestamp != nil {
			phase = v1.BuildPhaseInterrupted
			message = fmt.Sprintf("Builder Pod %s deleted", pod.Name)
		} else if _, ok := pod.GetAnnotations()[timeoutAnnotation]; ok {
			message = fmt.Sprintf("Builder Pod %s timeout", pod.Name)
		}
		// Do not override errored build
		if build.Status.Phase == v1.BuildPhaseError {
			phase = v1.BuildPhaseError
		}
		build.Status.Phase = phase
		build.Status.Error = message
		finishedAt := action.getTerminatedTime(pod)
		duration := finishedAt.Sub(build.Status.StartedAt.Time)
		build.Status.Duration = duration.String()
		action.setConditionsFromTerminationMessages(ctx, pod, &build.Status)
		monitorFinishedBuild(build)

		buildCreator := kubernetes.GetCamelCreator(build)
		// Account for the Build metrics
		observeBuildResult(build, build.Status.Phase, buildCreator, duration)
	}

	return build, nil
}