blob: dfbac25388c5ea10a0f07719e4373cc669fd6f85 [file] [log] [blame]
// Copyright 2023 Red Hat, Inc. and/or its affiliates
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package preview
import (
"context"
"github.com/apache/incubator-kie-kogito-serverless-operator/controllers/knative"
v1 "k8s.io/api/core/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
"github.com/apache/incubator-kie-kogito-serverless-operator/api"
operatorapi "github.com/apache/incubator-kie-kogito-serverless-operator/api/v1alpha08"
"github.com/apache/incubator-kie-kogito-serverless-operator/controllers/platform"
"github.com/apache/incubator-kie-kogito-serverless-operator/controllers/profiles/common"
"github.com/apache/incubator-kie-kogito-serverless-operator/controllers/profiles/common/constants"
"github.com/apache/incubator-kie-kogito-serverless-operator/utils"
)
type DeploymentReconciler struct {
*common.StateSupport
ensurers *ObjectEnsurers
}
func NewDeploymentReconciler(stateSupport *common.StateSupport, ensurer *ObjectEnsurers) *DeploymentReconciler {
return &DeploymentReconciler{
StateSupport: stateSupport,
ensurers: ensurer,
}
}
func (d *DeploymentReconciler) Reconcile(ctx context.Context, workflow *operatorapi.SonataFlow) (reconcile.Result, []client.Object, error) {
return d.reconcileWithImage(ctx, workflow, "")
}
func (d *DeploymentReconciler) reconcileWithImage(ctx context.Context, workflow *operatorapi.SonataFlow, image string) (reconcile.Result, []client.Object, error) {
// Checks if we need Knative installed and is not present.
if requires, err := d.ensureKnativeServingRequired(workflow); requires || err != nil {
return reconcile.Result{Requeue: false}, nil, err
}
// Ensure objects
result, objs, err := d.ensureObjects(ctx, workflow, image)
if err != nil || result.Requeue {
return result, objs, err
}
// Follow deployment status
result, err = common.DeploymentManager(d.C).SyncDeploymentStatus(ctx, workflow)
if err != nil {
return reconcile.Result{Requeue: false}, nil, err
}
if _, err := d.PerformStatusUpdate(ctx, workflow); err != nil {
return reconcile.Result{Requeue: false}, nil, err
}
return result, objs, nil
}
// ensureKnativeServingRequired returns true if the SonataFlow instance requires Knative deployment and Knative Serving is not available.
func (d *DeploymentReconciler) ensureKnativeServingRequired(workflow *operatorapi.SonataFlow) (bool, error) {
if workflow.IsKnativeDeployment() {
avail, err := knative.GetKnativeAvailability(d.Cfg)
if err != nil {
return true, err
}
if !avail.Serving {
d.Recorder.Eventf(workflow, v1.EventTypeWarning,
"KnativeServingNotAvailable",
"Knative Serving is not available in this cluster, can't deploy workflow. Please update the deployment model to %s",
operatorapi.KubernetesDeploymentModel)
return true, nil
}
}
return false, nil
}
func (d *DeploymentReconciler) ensureObjects(ctx context.Context, workflow *operatorapi.SonataFlow, image string) (reconcile.Result, []client.Object, error) {
pl, _ := platform.GetActivePlatform(ctx, d.C, workflow.Namespace)
userPropsCM, _, err := d.ensurers.userPropsConfigMap.Ensure(ctx, workflow)
if err != nil {
workflow.Status.Manager().MarkFalse(api.RunningConditionType, api.ExternalResourcesNotFoundReason, "Unable to retrieve the user properties config map")
_, _ = d.PerformStatusUpdate(ctx, workflow)
return reconcile.Result{}, nil, err
}
managedPropsCM, _, err := d.ensurers.managedPropsConfigMap.Ensure(ctx, workflow, pl,
common.ManagedPropertiesMutateVisitor(ctx, d.StateSupport.Catalog, workflow, pl, userPropsCM.(*v1.ConfigMap)))
if err != nil {
workflow.Status.Manager().MarkFalse(api.RunningConditionType, api.ExternalResourcesNotFoundReason, "Unable to retrieve the managed properties config map")
_, _ = d.PerformStatusUpdate(ctx, workflow)
return reconcile.Result{}, nil, err
}
deployment, deploymentOp, err :=
d.ensurers.DeploymentByDeploymentModel(workflow).Ensure(ctx, workflow, pl,
d.deploymentModelMutateVisitors(workflow, pl, image, userPropsCM.(*v1.ConfigMap), managedPropsCM.(*v1.ConfigMap))...)
if err != nil {
workflow.Status.Manager().MarkFalse(api.RunningConditionType, api.DeploymentUnavailableReason, "Unable to perform the deploy due to ", err)
_, _ = d.PerformStatusUpdate(ctx, workflow)
return reconcile.Result{}, nil, err
}
service, _, err := d.ensurers.ServiceByDeploymentModel(workflow).Ensure(ctx, workflow, common.ServiceMutateVisitor(workflow))
if err != nil {
workflow.Status.Manager().MarkFalse(api.RunningConditionType, api.DeploymentUnavailableReason, "Unable to make the service available due to ", err)
_, _ = d.PerformStatusUpdate(ctx, workflow)
return reconcile.Result{}, nil, err
}
eventingObjs, err := common.NewKnativeEventingHandler(d.StateSupport).Ensure(ctx, workflow)
if err != nil {
return reconcile.Result{}, nil, err
}
objs := []client.Object{deployment, managedPropsCM, service}
if deploymentOp == controllerutil.OperationResultCreated {
workflow.Status.Manager().MarkFalse(api.RunningConditionType, api.WaitingForDeploymentReason, "")
if _, err := d.PerformStatusUpdate(ctx, workflow); err != nil {
return reconcile.Result{}, nil, err
}
return reconcile.Result{RequeueAfter: constants.RequeueAfterFollowDeployment, Requeue: true}, objs, nil
}
objs = append(objs, eventingObjs...)
return reconcile.Result{}, objs, nil
}
func (d *DeploymentReconciler) deploymentModelMutateVisitors(
workflow *operatorapi.SonataFlow,
plf *operatorapi.SonataFlowPlatform,
image string,
userPropsCM *v1.ConfigMap,
managedPropsCM *v1.ConfigMap) []common.MutateVisitor {
if workflow.IsKnativeDeployment() {
return []common.MutateVisitor{common.KServiceMutateVisitor(workflow, plf),
common.ImageKServiceMutateVisitor(workflow, image),
mountConfigMapsMutateVisitor(workflow, userPropsCM, managedPropsCM)}
}
if utils.IsOpenShift() {
return []common.MutateVisitor{common.DeploymentMutateVisitor(workflow, plf),
mountConfigMapsMutateVisitor(workflow, userPropsCM, managedPropsCM),
addOpenShiftImageTriggerDeploymentMutateVisitor(workflow, image),
common.ImageDeploymentMutateVisitor(workflow, image),
common.RolloutDeploymentIfCMChangedMutateVisitor(workflow, userPropsCM, managedPropsCM),
}
}
return []common.MutateVisitor{common.DeploymentMutateVisitor(workflow, plf),
common.ImageDeploymentMutateVisitor(workflow, image),
mountConfigMapsMutateVisitor(workflow, userPropsCM, managedPropsCM),
common.RolloutDeploymentIfCMChangedMutateVisitor(workflow, userPropsCM, managedPropsCM)}
}