Skip to content

Commit

Permalink
Fix Issue apache#319 - Rename prod profile to preview (apache#414)
Browse files Browse the repository at this point in the history
* Fix Issue apache#319 - Rename prod profile to preview

Signed-off-by: Ricardo Zanini <[email protected]>

* Renaming profile after rebase

Signed-off-by: Ricardo Zanini <[email protected]>

---------

Signed-off-by: Ricardo Zanini <[email protected]>
  • Loading branch information
ricardozanini authored and rgdoliveira committed Mar 27, 2024
1 parent 0699a93 commit ca5744d
Show file tree
Hide file tree
Showing 44 changed files with 275 additions and 179 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,5 @@
/.idea/
/.vscode/
/target/

e2e-test-report.xml
24 changes: 23 additions & 1 deletion api/metadata/annotations.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,35 @@ const (
SpecVersion = "0.8"
)

type QuarkusProfileType string

func (p QuarkusProfileType) String() string {
return string(p)
}

const (
// QuarkusDevProfile the profile used by quarkus in devmode
QuarkusDevProfile QuarkusProfileType = "dev"
// QuarkusProdProfile the profile used by quarkus in an immutable image
QuarkusProdProfile QuarkusProfileType = "prod"
)

type ProfileType string

func (p ProfileType) String() string {
return string(p)
}

const (
DevProfile ProfileType = "dev"
// DevProfile deploys a mutable workflow that can be changed based on .spec.flow definitions CR change.
DevProfile ProfileType = "dev"
// Deprecated: use PreviewProfile.
ProdProfile ProfileType = "prod"
// PreviewProfile is the default profile if none is set.
// The operator will use the platform to do a minimal image build for users to preview an immutable app deployed in the cluster.
// Not suitable for production use cases since the managed build has configuration and resources limitations.
PreviewProfile ProfileType = "preview"
// GitOpsProfile signs the operator that the application image is built externally, skipping any internal managed build.
// Ideally used in production use cases
GitOpsProfile ProfileType = "gitops"
)
22 changes: 11 additions & 11 deletions controllers/profiles/common/properties/application_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ func Test_appPropertyHandler_WithServicesWithUserOverrides(t *testing.T) {
assert.Equal(t, "false", generatedProps.GetString(constants.KogitoUserTasksEventsEnabled, ""))

// prod profile enables config of outgoing events url
workflow.SetAnnotations(map[string]string{metadata.Profile: string(metadata.ProdProfile)})
workflow.SetAnnotations(map[string]string{metadata.Profile: string(metadata.PreviewProfile)})
services.SetServiceUrlsInWorkflowStatus(platform, workflow)
assert.NotNil(t, workflow.Status.Services)
assert.NotNil(t, workflow.Status.Services.JobServiceRef)
Expand Down Expand Up @@ -329,23 +329,23 @@ var _ = Describe("Platform properties", func() {
generatePlatform(setJobServiceEnabledValue(&disabled), setPlatformNamespace("default"), setPlatformName("foo")),
generateJobServiceWorkflowDevProperties()),
Entry("has enabled field set to false and workflow with production profile",
generateFlow(setProfileInFlow(metadata.ProdProfile), setWorkflowName("foo"), setWorkflowNamespace("default")),
generateFlow(setProfileInFlow(metadata.PreviewProfile), setWorkflowName("foo"), setWorkflowNamespace("default")),
generatePlatform(setJobServiceEnabledValue(&disabled), setPlatformNamespace("default"), setPlatformName("foo")),
generateJobServiceWorkflowDevProperties()),
Entry("has enabled field undefined and workflow with dev profile",
generateFlow(setProfileInFlow(metadata.DevProfile), setWorkflowName("foo"), setWorkflowNamespace("default")),
generatePlatform(setJobServiceEnabledValue(nil), setPlatformNamespace("default"), setPlatformName("foo")),
generateJobServiceWorkflowDevProperties()),
Entry("has enabled field undefined and workflow with production profile",
generateFlow(setProfileInFlow(metadata.ProdProfile), setWorkflowName("foo"), setWorkflowNamespace("default")),
generateFlow(setProfileInFlow(metadata.PreviewProfile), setWorkflowName("foo"), setWorkflowNamespace("default")),
generatePlatform(setJobServiceEnabledValue(nil), setPlatformNamespace("default"), setPlatformName("foo")),
generateJobServiceWorkflowDevProperties()),
Entry("has enabled field set to true and workflow with dev profile",
generateFlow(setProfileInFlow(metadata.DevProfile), setWorkflowName("foo"), setWorkflowNamespace("default")),
generatePlatform(setJobServiceEnabledValue(&enabled), setPlatformName("foo"), setPlatformNamespace("default")),
generateJobServiceWorkflowDevProperties()),
Entry("has enabled field set to true and workflow with production profile",
generateFlow(setProfileInFlow(metadata.ProdProfile), setWorkflowName("foo"), setWorkflowNamespace("default")),
generateFlow(setProfileInFlow(metadata.PreviewProfile), setWorkflowName("foo"), setWorkflowNamespace("default")),
generatePlatform(setJobServiceEnabledValue(&enabled), setPlatformName("foo"), setPlatformNamespace("default")),
generateJobServiceWorkflowProductionProperties()),
Entry("has enabled field set to true and workflow with no profile",
Expand Down Expand Up @@ -377,23 +377,23 @@ var _ = Describe("Platform properties", func() {
generatePlatform(setDataIndexEnabledValue(&disabled), setPlatformNamespace("default"), setPlatformName("foo")),
generateDataIndexWorkflowDevProperties()),
Entry("has enabled field set to false and workflow with production profile",
generateFlow(setProfileInFlow(metadata.ProdProfile), setWorkflowName("foo"), setWorkflowNamespace("default")),
generateFlow(setProfileInFlow(metadata.PreviewProfile), setWorkflowName("foo"), setWorkflowNamespace("default")),
generatePlatform(setDataIndexEnabledValue(&disabled), setPlatformNamespace("default"), setPlatformName("foo")),
generateDataIndexWorkflowDevProperties()),
Entry("has enabled field undefined and workflow with dev profile",
generateFlow(setProfileInFlow(metadata.DevProfile), setWorkflowName("foo"), setWorkflowNamespace("default")),
generatePlatform(setDataIndexEnabledValue(nil), setPlatformNamespace("default"), setPlatformName("foo")),
generateDataIndexWorkflowDevProperties()),
Entry("has enabled field undefined and workflow with production profile",
generateFlow(setProfileInFlow(metadata.ProdProfile), setWorkflowName("foo"), setWorkflowNamespace("default")),
generateFlow(setProfileInFlow(metadata.PreviewProfile), setWorkflowName("foo"), setWorkflowNamespace("default")),
generatePlatform(setDataIndexEnabledValue(nil), setPlatformNamespace("default"), setPlatformName("foo")),
generateDataIndexWorkflowDevProperties()),
Entry("has enabled field set to true and workflow with dev profile",
generateFlow(setProfileInFlow(metadata.DevProfile), setWorkflowName("foo"), setWorkflowNamespace("default")),
generatePlatform(setDataIndexEnabledValue(&enabled), setPlatformNamespace("default"), setPlatformName("foo")),
generateDataIndexWorkflowDevProperties()),
Entry("has enabled field set to true and workflow with production profile",
generateFlow(setProfileInFlow(metadata.ProdProfile), setWorkflowName("foo"), setWorkflowNamespace("default")),
generateFlow(setProfileInFlow(metadata.PreviewProfile), setWorkflowName("foo"), setWorkflowNamespace("default")),
generatePlatform(setDataIndexEnabledValue(&enabled), setPlatformNamespace("default"), setPlatformName("foo")),
generateDataIndexWorkflowProductionProperties()),
Entry("has enabled field set to false and workflow with no profile",
Expand Down Expand Up @@ -424,31 +424,31 @@ var _ = Describe("Platform properties", func() {
generatePlatform(setPlatformNamespace("default"), setPlatformName("foo")),
generateDataIndexAndJobServiceWorkflowDevProperties()),
Entry("both are undefined and workflow in prod profile",
generateFlow(setProfileInFlow(metadata.ProdProfile), setWorkflowName("foo"), setWorkflowNamespace("default")),
generateFlow(setProfileInFlow(metadata.PreviewProfile), setWorkflowName("foo"), setWorkflowNamespace("default")),
generatePlatform(setPlatformNamespace("default"), setPlatformName("foo")),
generateDataIndexAndJobServiceWorkflowDevProperties()),
Entry("both have enabled field set to true and workflow with dev profile",
generateFlow(setProfileInFlow(metadata.DevProfile), setWorkflowName("foo"), setWorkflowNamespace("default")),
generatePlatform(setJobServiceEnabledValue(&enabled), setDataIndexEnabledValue(&enabled), setPlatformName("foo"), setPlatformNamespace("default")),
generateDataIndexAndJobServiceWorkflowDevProperties()),
Entry("both have enabled field set to true and workflow with production profile",
generateFlow(setProfileInFlow(metadata.ProdProfile), setWorkflowName("foo"), setWorkflowNamespace("default")),
generateFlow(setProfileInFlow(metadata.PreviewProfile), setWorkflowName("foo"), setWorkflowNamespace("default")),
generatePlatform(setJobServiceEnabledValue(&enabled), setDataIndexEnabledValue(&enabled), setPlatformName("foo"), setPlatformNamespace("default")),
generateDataIndexAndJobServiceWorkflowProductionProperties()),
Entry("both have enabled field undefined and workflow with dev profile",
generateFlow(setProfileInFlow(metadata.DevProfile), setWorkflowName("foo"), setWorkflowNamespace("default")),
generatePlatform(setJobServiceEnabledValue(nil), setDataIndexEnabledValue(nil), setPlatformName("foo"), setPlatformNamespace("default")),
generateDataIndexAndJobServiceWorkflowDevProperties()),
Entry("both have enabled field undefined and workflow with production profile",
generateFlow(setProfileInFlow(metadata.ProdProfile), setWorkflowName("foo"), setWorkflowNamespace("default")),
generateFlow(setProfileInFlow(metadata.PreviewProfile), setWorkflowName("foo"), setWorkflowNamespace("default")),
generatePlatform(setJobServiceEnabledValue(nil), setDataIndexEnabledValue(nil), setPlatformName("foo"), setPlatformNamespace("default"), setJobServiceJDBC("jdbc:postgresql://postgres:5432/sonataflow?currentSchema=myschema")),
generateDataIndexAndJobServiceWorkflowDevProperties()),
Entry("both have enabled field set to false and workflow with dev profile",
generateFlow(setProfileInFlow(metadata.DevProfile), setWorkflowName("foo"), setWorkflowNamespace("default")),
generatePlatform(setJobServiceEnabledValue(&disabled), setDataIndexEnabledValue(&disabled), setPlatformName("foo"), setPlatformNamespace("default"), setJobServiceJDBC("jdbc:postgresql://postgres:5432/sonataflow?currentSchema=myschema")),
generateDataIndexAndJobServiceWorkflowDevProperties()),
Entry("both have enabled field set to false and workflow with production profile",
generateFlow(setProfileInFlow(metadata.ProdProfile), setWorkflowName("foo"), setWorkflowNamespace("default")),
generateFlow(setProfileInFlow(metadata.PreviewProfile), setWorkflowName("foo"), setWorkflowNamespace("default")),
generatePlatform(setJobServiceEnabledValue(&disabled), setDataIndexEnabledValue(&disabled), setPlatformName("foo"), setPlatformNamespace("default"), setJobServiceJDBC("jdbc:postgresql://postgres:5432/sonataflow?currentSchema=myschema")),
generateDataIndexAndJobServiceWorkflowDevProperties()),
Entry("both have enabled field set to false and workflow with no profile",
Expand Down
27 changes: 18 additions & 9 deletions controllers/profiles/factory/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,40 +20,49 @@
package factory

import (
"github.com/apache/incubator-kie-kogito-serverless-operator/controllers/profiles/gitops"
"github.com/apache/incubator-kie-kogito-serverless-operator/controllers/profiles/preview"
"github.com/apache/incubator-kie-kogito-serverless-operator/log"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/record"
"k8s.io/klog/v2"
"sigs.k8s.io/controller-runtime/pkg/client"

"github.com/apache/incubator-kie-kogito-serverless-operator/api/metadata"
operatorapi "github.com/apache/incubator-kie-kogito-serverless-operator/api/v1alpha08"
"github.com/apache/incubator-kie-kogito-serverless-operator/controllers/profiles"
"github.com/apache/incubator-kie-kogito-serverless-operator/controllers/profiles/dev"
"github.com/apache/incubator-kie-kogito-serverless-operator/controllers/profiles/prod"
)

const (
defaultProfile = metadata.ProdProfile
// internal profile
opsProfile metadata.ProfileType = "prod_for_ops"
defaultProfile = metadata.PreviewProfile
)

type reconcilerBuilder func(client client.Client, cfg *rest.Config, recorder record.EventRecorder) profiles.ProfileReconciler

var profileBuilders = map[metadata.ProfileType]reconcilerBuilder{
metadata.ProdProfile: prod.NewProfileReconciler,
metadata.DevProfile: dev.NewProfileReconciler,
opsProfile: prod.NewProfileForOpsReconciler,
metadata.PreviewProfile: preview.NewProfileReconciler,
metadata.DevProfile: dev.NewProfileReconciler,
metadata.GitOpsProfile: gitops.NewProfileForOpsReconciler,
}

func profileBuilder(workflow *operatorapi.SonataFlow) reconcilerBuilder {
profile := workflow.Annotations[metadata.Profile]
if len(profile) == 0 {
profile = defaultProfile.String()
}
if profile == metadata.ProdProfile.String() && workflow.HasContainerSpecImage() {
return profileBuilders[opsProfile]
// keep backward compatibility
if profile == metadata.ProdProfile.String() {
klog.V(log.W).Infof("Profile %s is deprecated, please use '%s' instead.", metadata.ProdProfile, metadata.PreviewProfile)
profile = metadata.PreviewProfile.String()
}
// Enforce GitOps profile if the .spec.podTemplate.container.image is set in the Preview profile.
if (profile == metadata.PreviewProfile.String() || profile == metadata.ProdProfile.String()) && workflow.HasContainerSpecImage() {
workflow.Annotations[metadata.Profile] = metadata.GitOpsProfile.String()
return profileBuilders[metadata.GitOpsProfile]
}
if _, ok := profileBuilders[metadata.ProfileType(profile)]; !ok {
klog.V(log.W).Infof("Profile %s not supported, please use '%s' or '%s'. Falling back to %s", profile, metadata.PreviewProfile, metadata.DevProfile, defaultProfile)
return profileBuilders[defaultProfile]
}
return profileBuilders[metadata.ProfileType(profile)]
Expand Down
25 changes: 25 additions & 0 deletions controllers/profiles/gitops/alias.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright 2024 Apache Software Foundation (ASF)
//
// 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 gitops

import "github.com/apache/incubator-kie-kogito-serverless-operator/controllers/profiles/preview"

// Aliases to preview profile package to avoid cluttering this package with references to preview profile.
// It makes easier to maintain and understand where it comes the references.

var newDeploymentReconciler = preview.NewDeploymentReconciler
var newObjectEnsurers = preview.NewObjectEnsurers

type objectEnsurers = preview.ObjectEnsurers
56 changes: 56 additions & 0 deletions controllers/profiles/gitops/profile_gitops.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Copyright 2024 Apache Software Foundation (ASF)
//
// 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 gitops

import (
"github.com/apache/incubator-kie-kogito-serverless-operator/api/metadata"
"github.com/apache/incubator-kie-kogito-serverless-operator/controllers/discovery"
"github.com/apache/incubator-kie-kogito-serverless-operator/controllers/profiles"
"github.com/apache/incubator-kie-kogito-serverless-operator/controllers/profiles/common"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/record"
"sigs.k8s.io/controller-runtime/pkg/client"
)

var _ profiles.ProfileReconciler = &gitOpsProfile{}

type gitOpsProfile struct {
common.Reconciler
}

// NewProfileForOpsReconciler creates an alternative prod profile that won't require to build the workflow image in order to deploy
// the workflow application. It assumes that the image has been built somewhere else.
func NewProfileForOpsReconciler(client client.Client, cfg *rest.Config, recorder record.EventRecorder) profiles.ProfileReconciler {
support := &common.StateSupport{
C: client,
Cfg: cfg,
Catalog: discovery.NewServiceCatalogForConfig(client, cfg),
Recorder: recorder,
}
// the reconciliation state machine
stateMachine := common.NewReconciliationStateMachine(
&ensureBuildSkipped{StateSupport: support},
&followDeployWorkflowState{StateSupport: support, ensurers: newObjectEnsurers(support)},
)
reconciler := &gitOpsProfile{
Reconciler: common.NewReconciler(support, stateMachine),
}

return reconciler
}

func (p gitOpsProfile) GetProfile() metadata.ProfileType {
return metadata.GitOpsProfile
}
68 changes: 68 additions & 0 deletions controllers/profiles/gitops/profile_gitops_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// Copyright 2024 Apache Software Foundation (ASF)
//
// 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 gitops

import (
"context"
"testing"

"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/test"
"github.com/stretchr/testify/assert"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
"k8s.io/client-go/rest"
clientruntime "sigs.k8s.io/controller-runtime/pkg/client"
)

func Test_Reconciler_ProdOps(t *testing.T) {
workflow := test.GetBaseSonataFlowWithProdOpsProfile(t.Name())
workflow.Spec.PodTemplate.PodSpec.InitContainers = append(workflow.Spec.PodTemplate.PodSpec.InitContainers, corev1.Container{
Name: "check-postgres",
Image: "registry.access.redhat.com/ubi9/ubi-micro:latest",
Command: []string{"sh", "-c", "until (echo 1 > /dev/tcp/postgres.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local/5432) >/dev/null 2>&1; do echo \"Waiting for postgres server\"; sleep 3; done;"},
})
client := test.NewSonataFlowClientBuilder().
WithRuntimeObjects(workflow).
WithStatusSubresource(workflow, &operatorapi.SonataFlowBuild{}).Build()
result, err := NewProfileForOpsReconciler(client, &rest.Config{}, test.NewFakeRecorder()).Reconcile(context.TODO(), workflow)
assert.NoError(t, err)

assert.NotNil(t, result.RequeueAfter)
assert.True(t, workflow.Status.GetCondition(api.BuiltConditionType).IsFalse())
assert.Equal(t, api.BuildSkippedReason, workflow.Status.GetCondition(api.BuiltConditionType).Reason)
// We need the deployment controller to tell us that the workflow is ready
// Since we don't have it in a mocked env, the result must be ready == false
assert.False(t, workflow.Status.IsReady())

// Reconcile again to run the deployment handler
result, err = NewProfileForOpsReconciler(client, &rest.Config{}, test.NewFakeRecorder()).Reconcile(context.TODO(), workflow)
assert.NoError(t, err)

// Let's check for the right creation of the workflow (one CM volume, one container with a custom image)
deployment := &appsv1.Deployment{}
err = client.Get(context.TODO(), clientruntime.ObjectKeyFromObject(workflow), deployment)
assert.NoError(t, err)

assert.Len(t, deployment.Spec.Template.Spec.Volumes, 1)
assert.Len(t, deployment.Spec.Template.Spec.Containers, 1)
assert.Len(t, deployment.Spec.Template.Spec.InitContainers, 1)
assert.Len(t, deployment.Spec.Template.Spec.Containers[0].VolumeMounts, 1)

assert.NotNil(t, deployment.ObjectMeta)
assert.NotNil(t, deployment.ObjectMeta.Labels)
assert.Equal(t, deployment.ObjectMeta.Labels, map[string]string{"test": "test", "app": "simple", "sonataflow.org/workflow-app": "simple"})
}
Loading

0 comments on commit ca5744d

Please sign in to comment.