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
}