in pkg/controller/build/build_controller.go [108:237]
func (r *reconcileBuild) Reconcile(ctx context.Context, request reconcile.Request) (reconcile.Result, error) {
rlog := Log.WithValues("request-namespace", request.Namespace, "request-name", request.Name)
rlog.Debug("Reconciling Build")
// Make sure the operator is allowed to act on namespace
if ok, err := platform.IsOperatorAllowedOnNamespace(ctx, r.client, request.Namespace); err != nil {
return reconcile.Result{}, err
} else if !ok {
rlog.Info("Ignoring request because namespace is locked")
return reconcile.Result{}, nil
}
// Fetch the Build instance
var instance v1.Build
if err := r.client.Get(ctx, request.NamespacedName, &instance); err != nil {
if k8serrors.IsNotFound(err) {
// Request object not found, could have been deleted after reconcile request.
// Owned objects are automatically garbage collected. For additional cleanup logic use finalizers.
// Return and don't requeue
return reconcile.Result{}, nil
}
// Error reading the object - requeue the request.
return reconcile.Result{}, err
}
// Only process resources assigned to the operator
if !platform.IsOperatorHandlerConsideringLock(ctx, r.client, request.Namespace, &instance) {
rlog.Info("Ignoring request because resource is not assigned to current operator")
return reconcile.Result{}, nil
}
target := instance.DeepCopy()
targetLog := rlog.ForBuild(target)
var actions []Action
ip, err := platform.GetOrFindForResource(ctx, r.client, &instance, true)
if err != nil {
rlog.Error(err, "Could not find a platform bound to this Build")
return reconcile.Result{}, err
}
buildMonitor := Monitor{
maxRunningBuilds: ip.Status.Build.MaxRunningBuilds,
buildOrderStrategy: ip.Status.Build.BuildConfiguration.OrderStrategy,
}
switch instance.BuilderConfiguration().Strategy {
case v1.BuildStrategyPod:
actions = []Action{
newInitializePodAction(r.reader),
newScheduleAction(r.reader, buildMonitor),
newMonitorPodAction(r.reader),
newErrorRecoveryAction(),
newErrorAction(),
}
case v1.BuildStrategyRoutine:
actions = []Action{
newInitializeRoutineAction(),
newScheduleAction(r.reader, buildMonitor),
newMonitorRoutineAction(),
newErrorRecoveryAction(),
newErrorAction(),
}
}
for _, a := range actions {
a.InjectClient(r.client)
a.InjectLogger(targetLog)
a.InjectRecorder(r.recorder)
if a.CanHandle(target) {
targetLog.Debugf("Invoking action %s", a.Name())
newTarget, err := a.Handle(ctx, target)
if err != nil {
camelevent.NotifyBuildError(ctx, r.client, r.recorder, &instance, newTarget, err)
return reconcile.Result{}, err
}
if newTarget != nil {
if err := r.update(ctx, &instance, newTarget); err != nil {
camelevent.NotifyBuildError(ctx, r.client, r.recorder, &instance, newTarget, err)
return reconcile.Result{}, err
}
if newTarget.Status.Phase != instance.Status.Phase {
targetLog.Info(
"State transition",
"phase-from", instance.Status.Phase,
"phase-to", newTarget.Status.Phase,
)
if newTarget.Status.Phase == v1.BuildPhaseError || newTarget.Status.Phase == v1.BuildPhaseFailed {
reason := string(newTarget.Status.Phase)
if newTarget.Status.Failure != nil {
reason = newTarget.Status.Failure.Reason
}
targetLog.Info(
"Build error",
"reason", reason,
"error-message", newTarget.Status.Error)
}
}
target = newTarget
}
// handle one action at time so the resource
// is always at its latest state
camelevent.NotifyBuildUpdated(ctx, r.client, r.recorder, &instance, newTarget)
break
}
}
if target.Status.Phase == v1.BuildPhaseScheduling || target.Status.Phase == v1.BuildPhaseFailed {
// Requeue scheduling (resp. failed) build so that it re-enters the build (resp. recovery) working queue
return reconcile.Result{RequeueAfter: 5 * time.Second}, nil
}
if target.BuilderConfiguration().Strategy == v1.BuildStrategyPod &&
(target.Status.Phase == v1.BuildPhasePending || target.Status.Phase == v1.BuildPhaseRunning) {
// Requeue running Build to poll Pod and signal timeout
return reconcile.Result{RequeueAfter: 1 * time.Second}, nil
}
return reconcile.Result{}, nil
}