This is an automated email from the ASF dual-hosted git repository.
ricardozanini pushed a commit to branch main
in repository
https://gitbox.apache.org/repos/asf/incubator-kie-kogito-serverless-operator.git
The following commit(s) were added to refs/heads/main by this push:
new 132d1236 Break the current operator's configuration into custom and
managed properties (#367)
132d1236 is described below
commit 132d1236cc37e3f80ff10016f5303eb3af59f4d7
Author: Daniele Martinoli <[email protected]>
AuthorDate: Fri Feb 2 21:22:39 2024 +0100
Break the current operator's configuration into custom and managed
properties (#367)
* Initial commit
* integrating comments: introducing ObjectEnsurerWithPlatform and
ObjectCreatorWithPlatform
* Removing fewe more unneeded references to platform
* reviewed workflowProjectHandler. removed user props from managed props
* fixed unit tests
* workarond for failed discovery options
* fixed broken unit tests
* fixed mutator for user props
* reviewed hashing function
* Anticipating deactivation of broken e2e test
* integrating comments: removing unneeded comment
* adding discovered value to properties whose value mathes the service
discovery pattern
* removed unused package common_test
* Renamed managed props visitor and reviewed description of
NewAppPropertyHandler
---
controllers/profiles/common/ensurer.go | 39 +++++++++++++++
controllers/profiles/common/mutate_visitors.go | 32 ++++++------
controllers/profiles/common/object_creators.go | 17 +++++--
.../profiles/common/object_creators_test.go | 57 ++++++++++++----------
.../profiles/common/properties/application.go | 33 ++++++-------
.../profiles/common/properties/application_test.go | 45 ++++++++++-------
.../profiles/common/properties/discovery.go | 2 +
.../profiles/common/properties/discovery_test.go | 7 ++-
controllers/profiles/dev/object_creators_dev.go | 5 +-
.../profiles/dev/object_creators_dev_test.go | 1 -
controllers/profiles/dev/profile_dev.go | 33 +++++++------
controllers/profiles/dev/profile_dev_test.go | 24 ++++++---
controllers/profiles/dev/states_dev.go | 10 ++--
controllers/profiles/prod/deployment_handler.go | 26 ++++++----
.../profiles/prod/deployment_handler_test.go | 52 ++++++++++++--------
controllers/profiles/prod/object_creators_prod.go | 11 +++--
controllers/profiles/prod/profile_prod.go | 14 +++---
utils/kubernetes/deployment.go | 18 ++++---
workflowproj/operator.go | 50 +++++++++++++++----
workflowproj/workflowproj.go | 3 +-
workflowproj/workflowproj_test.go | 1 +
21 files changed, 312 insertions(+), 168 deletions(-)
diff --git a/controllers/profiles/common/ensurer.go
b/controllers/profiles/common/ensurer.go
index 0d9cb472..7d258dbb 100644
--- a/controllers/profiles/common/ensurer.go
+++ b/controllers/profiles/common/ensurer.go
@@ -36,6 +36,9 @@ var _ ObjectEnsurer = &noopObjectEnsurer{}
type ObjectEnsurer interface {
Ensure(ctx context.Context, workflow *operatorapi.SonataFlow, visitors
...MutateVisitor) (client.Object, controllerutil.OperationResult, error)
}
+type ObjectEnsurerWithPlatform interface {
+ Ensure(ctx context.Context, workflow *operatorapi.SonataFlow, platform
*operatorapi.SonataFlowPlatform, visitors ...MutateVisitor) (client.Object,
controllerutil.OperationResult, error)
+}
// MutateVisitor is a visitor function that mutates the given object before
performing any updates in the cluster.
// It gets called after the objectEnforcer reference.
@@ -56,6 +59,14 @@ func NewObjectEnsurer(client client.Client, creator
ObjectCreator) ObjectEnsurer
}
}
+// NewObjectEnsurerWithPlatform see defaultObjectEnsurerWithPLatform
+func NewObjectEnsurerWithPlatform(client client.Client, creator
ObjectCreatorWithPlatform) ObjectEnsurerWithPlatform {
+ return &defaultObjectEnsurerWithPlatform{
+ c: client,
+ creator: creator,
+ }
+}
+
// defaultObjectEnsurer provides the engine for a ReconciliationState that
needs to create or update a given Kubernetes object during the reconciliation
cycle.
type defaultObjectEnsurer struct {
c client.Client
@@ -84,6 +95,34 @@ func (d *defaultObjectEnsurer) Ensure(ctx context.Context,
workflow *operatorapi
return object, result, nil
}
+// defaultObjectEnsurerWithPlatform is the equivalent of defaultObjectEnsurer
for resources that require a reference to the SonataFlowPlatform
+type defaultObjectEnsurerWithPlatform struct {
+ c client.Client
+ creator ObjectCreatorWithPlatform
+}
+
+func (d *defaultObjectEnsurerWithPlatform) Ensure(ctx context.Context,
workflow *operatorapi.SonataFlow, pl *operatorapi.SonataFlowPlatform, visitors
...MutateVisitor) (client.Object, controllerutil.OperationResult, error) {
+ result := controllerutil.OperationResultNone
+
+ object, err := d.creator(workflow, pl)
+ if err != nil {
+ return nil, result, err
+ }
+ if result, err = controllerutil.CreateOrPatch(ctx, d.c, object,
+ func() error {
+ for _, v := range visitors {
+ if visitorErr := v(object)(); visitorErr != nil
{
+ return visitorErr
+ }
+ }
+ return controllerutil.SetControllerReference(workflow,
object, d.c.Scheme())
+ }); err != nil {
+ return nil, result, err
+ }
+ klog.V(log.I).InfoS("Object operation finalized", "result", result,
"kind", object.GetObjectKind().GroupVersionKind().String(), "name",
object.GetName(), "namespace", object.GetNamespace())
+ return object, result, nil
+}
+
// NewNoopObjectEnsurer see noopObjectEnsurer
func NewNoopObjectEnsurer() ObjectEnsurer {
return &noopObjectEnsurer{}
diff --git a/controllers/profiles/common/mutate_visitors.go
b/controllers/profiles/common/mutate_visitors.go
index ffe9784a..8ccbcab3 100644
--- a/controllers/profiles/common/mutate_visitors.go
+++ b/controllers/profiles/common/mutate_visitors.go
@@ -105,32 +105,28 @@ func ServiceMutateVisitor(workflow
*operatorapi.SonataFlow) MutateVisitor {
}
}
-func WorkflowPropertiesMutateVisitor(ctx context.Context, catalog
discovery.ServiceCatalog,
- workflow *operatorapi.SonataFlow, platform
*operatorapi.SonataFlowPlatform) MutateVisitor {
+func ManagedPropertiesMutateVisitor(ctx context.Context, catalog
discovery.ServiceCatalog,
+ workflow *operatorapi.SonataFlow, platform
*operatorapi.SonataFlowPlatform, userProps *corev1.ConfigMap) MutateVisitor {
return func(object client.Object) controllerutil.MutateFn {
return func() error {
- if kubeutil.IsObjectNew(object) {
- return nil
- }
- cm := object.(*corev1.ConfigMap)
- cm.Labels = workflow.GetLabels()
- _, hasKey :=
cm.Data[workflowproj.ApplicationPropertiesFileName]
+ managedProps := object.(*corev1.ConfigMap)
+ managedProps.Labels = workflow.GetLabels()
+ _, hasKey :=
managedProps.Data[workflowproj.GetManagedPropertiesFileName(workflow)]
if !hasKey {
- cm.Data = make(map[string]string, 1)
- props, err :=
properties.ImmutableApplicationProperties(workflow, platform)
- if err != nil {
- return err
- }
-
cm.Data[workflowproj.ApplicationPropertiesFileName] = props
- return nil
+ managedProps.Data = make(map[string]string, 1)
+
managedProps.Data[workflowproj.GetManagedPropertiesFileName(workflow)] = ""
}
+ userProperties, hasKey :=
userProps.Data[workflowproj.ApplicationPropertiesFileName]
+ if !hasKey {
+ userProperties = ""
+ }
// In the future, if this needs change, instead we can
receive an AppPropertyHandler in this mutator
props, err :=
properties.NewAppPropertyHandler(workflow, platform)
if err != nil {
return err
}
- cm.Data[workflowproj.ApplicationPropertiesFileName] =
props.WithUserProperties(cm.Data[workflowproj.ApplicationPropertiesFileName]).
+
managedProps.Data[workflowproj.GetManagedPropertiesFileName(workflow)] =
props.WithUserProperties(userProperties).
WithServiceDiscovery(ctx, catalog).
Build()
return nil
@@ -142,11 +138,11 @@ func WorkflowPropertiesMutateVisitor(ctx context.Context,
catalog discovery.Serv
// This method can be used as an alternative to the Kubernetes ConfigMap
refresher.
//
// See:
https://kubernetes.io/docs/concepts/configuration/configmap/#mounted-configmaps-are-updated-automatically
-func RolloutDeploymentIfCMChangedMutateVisitor(cm *v1.ConfigMap) MutateVisitor
{
+func RolloutDeploymentIfCMChangedMutateVisitor(workflow
*operatorapi.SonataFlow, userPropsCM *v1.ConfigMap, managedPropsCM
*v1.ConfigMap) MutateVisitor {
return func(object client.Object) controllerutil.MutateFn {
return func() error {
deployment := object.(*appsv1.Deployment)
- err :=
kubeutil.AnnotateDeploymentConfigChecksum(deployment, cm)
+ err :=
kubeutil.AnnotateDeploymentConfigChecksum(workflow, deployment, userPropsCM,
managedPropsCM)
return err
}
}
diff --git a/controllers/profiles/common/object_creators.go
b/controllers/profiles/common/object_creators.go
index 5739b6ad..0e2d6f20 100644
--- a/controllers/profiles/common/object_creators.go
+++ b/controllers/profiles/common/object_creators.go
@@ -41,6 +41,10 @@ import (
// Can be used as a reference to keep the object immutable
type ObjectCreator func(workflow *operatorapi.SonataFlow) (client.Object,
error)
+// ObjectCreatorWithPlatform is the func equivalent to ObjectCreator to use
when the resource being created needs a reference to the
+// SonataFlowPlatform
+type ObjectCreatorWithPlatform func(workflow *operatorapi.SonataFlow, platform
*operatorapi.SonataFlowPlatform) (client.Object, error)
+
const (
defaultHTTPServicePort = 80
@@ -209,13 +213,18 @@ func OpenShiftRouteCreator(workflow
*operatorapi.SonataFlow) (client.Object, err
return route, err
}
-// WorkflowPropsConfigMapCreator creates a ConfigMap to hold the external
application properties
-func WorkflowPropsConfigMapCreator(workflow *operatorapi.SonataFlow)
(client.Object, error) {
- props, err := properties.ImmutableApplicationProperties(workflow, nil)
+// UserPropsConfigMapCreator creates an empty ConfigMap to hold the user
application properties
+func UserPropsConfigMapCreator(workflow *operatorapi.SonataFlow)
(client.Object, error) {
+ return workflowproj.CreateNewUserPropsConfigMap(workflow), nil
+}
+
+// ManagedPropsConfigMapCreator creates an empty ConfigMap to hold the
external application properties
+func ManagedPropsConfigMapCreator(workflow *operatorapi.SonataFlow, platform
*operatorapi.SonataFlowPlatform) (client.Object, error) {
+ props, err := properties.ImmutableApplicationProperties(workflow,
platform)
if err != nil {
return nil, err
}
- return workflowproj.CreateNewAppPropsConfigMap(workflow, props), nil
+ return workflowproj.CreateNewManagedPropsConfigMap(workflow, props), nil
}
func ConfigurePersistence(serviceContainer *corev1.Container, options
*operatorapi.PersistenceOptions, defaultSchema, namespace string)
*corev1.Container {
diff --git a/controllers/profiles/common/object_creators_test.go
b/controllers/profiles/common/object_creators_test.go
index 64e8f43b..ae252248 100644
--- a/controllers/profiles/common/object_creators_test.go
+++ b/controllers/profiles/common/object_creators_test.go
@@ -27,7 +27,6 @@ import (
"github.com/stretchr/testify/assert"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/apache/incubator-kie-kogito-serverless-operator/utils"
kubeutil
"github.com/apache/incubator-kie-kogito-serverless-operator/utils/kubernetes"
@@ -39,50 +38,56 @@ import (
func Test_ensureWorkflowPropertiesConfigMapMutator(t *testing.T) {
workflow := test.GetBaseSonataFlowWithDevProfile(t.Name())
+ platform := test.GetBasePlatform()
// can't be new
- cm, _ := WorkflowPropsConfigMapCreator(workflow)
- cm.SetUID("1")
- cm.SetResourceVersion("1")
- reflectCm := cm.(*corev1.ConfigMap)
+ managedProps, _ := ManagedPropsConfigMapCreator(workflow, platform)
+ managedProps.SetUID("1")
+ managedProps.SetResourceVersion("1")
+ managedPropsCM := managedProps.(*corev1.ConfigMap)
- visitor := WorkflowPropertiesMutateVisitor(context.TODO(), nil,
workflow, nil)
- mutateFn := visitor(cm)
+ userProps, _ := UserPropsConfigMapCreator(workflow)
+ userPropsCM := userProps.(*corev1.ConfigMap)
+ visitor := ManagedPropertiesMutateVisitor(context.TODO(), nil,
workflow, nil, userPropsCM)
+ mutateFn := visitor(managedProps)
assert.NoError(t, mutateFn())
- assert.NotEmpty(t,
reflectCm.Data[workflowproj.ApplicationPropertiesFileName])
+ assert.Empty(t,
managedPropsCM.Data[workflowproj.ApplicationPropertiesFileName])
+ assert.NotEmpty(t,
managedPropsCM.Data[workflowproj.GetManagedPropertiesFileName(workflow)])
- props :=
properties.MustLoadString(reflectCm.Data[workflowproj.ApplicationPropertiesFileName])
+ props :=
properties.MustLoadString(managedPropsCM.Data[workflowproj.GetManagedPropertiesFileName(workflow)])
assert.Equal(t, "8080", props.GetString("quarkus.http.port", ""))
// we change the properties to something different, we add ours and
change the default
- reflectCm.Data[workflowproj.ApplicationPropertiesFileName] =
"quarkus.http.port=9090\nmy.new.prop=1"
- visitor(reflectCm)
+ userPropsCM.Data[workflowproj.ApplicationPropertiesFileName] =
"quarkus.http.port=9090\nmy.new.prop=1"
+ visitor(managedPropsCM)
assert.NoError(t, mutateFn())
// we should preserve the default, and still got ours
- props =
properties.MustLoadString(reflectCm.Data[workflowproj.ApplicationPropertiesFileName])
+ props =
properties.MustLoadString(managedPropsCM.Data[workflowproj.GetManagedPropertiesFileName(workflow)])
assert.Equal(t, "8080", props.GetString("quarkus.http.port", ""))
assert.Equal(t, "0.0.0.0", props.GetString("quarkus.http.host", ""))
- assert.Equal(t, "1", props.GetString("my.new.prop", ""))
+ assert.NotContains(t, "my.new.prop", props.Keys())
}
func Test_ensureWorkflowPropertiesConfigMapMutator_DollarReplacement(t
*testing.T) {
workflow := test.GetBaseSonataFlowWithDevProfile(t.Name())
- existingCM := &corev1.ConfigMap{
- ObjectMeta: metav1.ObjectMeta{
- Name: workflow.Name,
- Namespace: workflow.Namespace,
- UID: "0000-0001-0002-0003",
- },
- Data: map[string]string{
- workflowproj.ApplicationPropertiesFileName:
"mp.messaging.outgoing.kogito_outgoing_stream.url=${kubernetes:services.v1/event-listener}",
- },
- }
- mutateVisitorFn := WorkflowPropertiesMutateVisitor(context.TODO(), nil,
workflow, nil)
+ platform := test.GetBasePlatform()
+ managedProps, _ := ManagedPropsConfigMapCreator(workflow, platform)
+ managedProps.SetName(workflow.Name)
+ managedProps.SetNamespace(workflow.Namespace)
+ managedProps.SetUID("0000-0001-0002-0003")
+ managedPropsCM := managedProps.(*corev1.ConfigMap)
+
+ userProps, _ := UserPropsConfigMapCreator(workflow)
+ userPropsCM := userProps.(*corev1.ConfigMap)
+ userPropsCM.Data[workflowproj.ApplicationPropertiesFileName] =
"mp.messaging.outgoing.kogito_outgoing_stream.url=${kubernetes:services.v1/event-listener}"
+
+ mutateVisitorFn := ManagedPropertiesMutateVisitor(context.TODO(), nil,
workflow, nil, userPropsCM)
- err := mutateVisitorFn(existingCM)()
+ err := mutateVisitorFn(managedPropsCM)()
assert.NoError(t, err)
- assert.Contains(t,
existingCM.Data[workflowproj.ApplicationPropertiesFileName],
"${kubernetes:services.v1/event-listener}")
+ assert.NotContains(t,
managedPropsCM.Data[workflowproj.GetManagedPropertiesFileName(workflow)],
"mp.messaging.outgoing.kogito_outgoing_stream.url")
+ // assert.Contains(t,
managedPropsCM.Data[workflowproj.GetManagedPropertiesFileName(workflow)],
"${kubernetes:services.v1/event-listener}")
}
func TestMergePodSpec(t *testing.T) {
diff --git a/controllers/profiles/common/properties/application.go
b/controllers/profiles/common/properties/application.go
index fda4ec1e..41489140 100644
--- a/controllers/profiles/common/properties/application.go
+++ b/controllers/profiles/common/properties/application.go
@@ -75,36 +75,34 @@ func (a *appPropertyHandler) WithServiceDiscovery(ctx
context.Context, catalog d
}
func (a *appPropertyHandler) Build() string {
- var props *properties.Properties
+ var userProps *properties.Properties
var propErr error = nil
if len(a.userProperties) == 0 {
- props = properties.NewProperties()
+ userProps = properties.NewProperties()
} else {
- props, propErr = properties.LoadString(a.userProperties)
+ userProps, propErr = properties.LoadString(a.userProperties)
}
if propErr != nil {
klog.V(log.D).InfoS("Can't load user's property", "workflow",
a.workflow.Name, "namespace", a.workflow.Namespace, "properties",
a.userProperties)
- props = properties.NewProperties()
+ userProps = properties.NewProperties()
}
// Disable expansions since it's not our responsibility
// Property expansion means resolving ${} within the properties and
environment context. Quarkus will do that in runtime.
- props.DisableExpansion = true
+ userProps.DisableExpansion = true
- removeDiscoveryProperties(props)
+ removeDiscoveryProperties(userProps)
+ discoveryProps := properties.NewProperties()
if a.requireServiceDiscovery() {
// produce the MicroProfileConfigServiceCatalog properties for
the service discovery property values if any.
- discoveryProperties := generateDiscoveryProperties(a.ctx,
a.catalog, props, a.workflow)
- if discoveryProperties.Len() > 0 {
- props.Merge(discoveryProperties)
- }
+ discoveryProps.Merge(generateDiscoveryProperties(a.ctx,
a.catalog, userProps, a.workflow))
}
- props = utils.NewApplicationPropertiesBuilder().
- WithInitialProperties(props).
+ userProps = utils.NewApplicationPropertiesBuilder().
+ WithInitialProperties(discoveryProps).
WithImmutableProperties(properties.MustLoadString(immutableApplicationProperties)).
WithDefaultMutableProperties(a.defaultMutableProperties).
Build()
- return props.String()
+ return userProps.String()
}
// withKogitoServiceUrl adds the property kogitoServiceUrlProperty to the
application properties.
@@ -135,13 +133,14 @@ func (a *appPropertyHandler)
addDefaultMutableProperty(name string, value string
}
// NewAppPropertyHandler creates a property handler for a given workflow to
execute in the provided platform.
-// This handler is intended to build the application properties required by
the workflow to execute properly, note that
-// the produced properties might vary depending on the platfom, for example,
if the job service managed by the platform
+// This handler is intended to build the managed application properties
required by the workflow to execute properly together with
+// the user properties defined in the user-managed ConfigMap.
+// Note that the produced properties might vary depending on the platfom, for
example, if the job service managed by the platform
// a particular set of properties will be added, etc.
// By default, the following properties are incorporated:
// The set of immutable properties provided by the operator. (user can never
change)
-// The set of defaultMutableProperties that are provided by the operator, and
that the user might overwrite if it changes
-// the workflow ConfigMap. This set includes for example the required
properties to connect with the data index and the
+// The set of defaultMutableProperties that are provided by the operator, and
that the user cannot overwrite even if it changes
+// the user-managed ConfigMap. This set includes for example the required
properties to connect with the data index and the
// job service when any of these services are managed by the platform.
func NewAppPropertyHandler(workflow *operatorapi.SonataFlow, platform
*operatorapi.SonataFlowPlatform) (AppPropertyHandler, error) {
handler := &appPropertyHandler{
diff --git a/controllers/profiles/common/properties/application_test.go
b/controllers/profiles/common/properties/application_test.go
index 543247dd..d0f4d5df 100644
--- a/controllers/profiles/common/properties/application_test.go
+++ b/controllers/profiles/common/properties/application_test.go
@@ -124,9 +124,9 @@ func
Test_appPropertyHandler_WithUserPropertiesWithNoUserOverrides(t *testing.T)
assert.NoError(t, err)
generatedProps, propsErr :=
properties.LoadString(props.WithUserProperties(userProperties).Build())
assert.NoError(t, propsErr)
- assert.Equal(t, 9, len(generatedProps.Keys()))
- assert.Equal(t, "value1", generatedProps.GetString("property1", ""))
- assert.Equal(t, "value2", generatedProps.GetString("property2", ""))
+ assert.Equal(t, 7, len(generatedProps.Keys()))
+ assert.NotContains(t, "property1", generatedProps.Keys())
+ assert.NotContains(t, "property2", generatedProps.Keys())
assert.Equal(t, "http://greeting.default",
generatedProps.GetString("kogito.service.url", ""))
assert.Equal(t, "8080", generatedProps.GetString("quarkus.http.port",
""))
assert.Equal(t, "0.0.0.0",
generatedProps.GetString("quarkus.http.host", ""))
@@ -157,13 +157,16 @@ func
Test_appPropertyHandler_WithUserPropertiesWithServiceDiscovery(t *testing.T
Build())
generatedProps.DisableExpansion = true
assert.NoError(t, propsErr)
- assert.Equal(t, 23, len(generatedProps.Keys()))
- assertHasProperty(t, generatedProps, "property1", "value1")
- assertHasProperty(t, generatedProps, "property2", "value2")
-
- assertHasProperty(t, generatedProps, "service1",
"${kubernetes:services.v1/namespace1/my-service1}")
- assertHasProperty(t, generatedProps, "service2",
"${kubernetes:services.v1/my-service2}")
- assertHasProperty(t, generatedProps, "service3",
"${knative:namespace1/my-kn-service1}")
+ assert.Equal(t, 21, len(generatedProps.Keys()))
+ assert.NotContains(t, "property1", generatedProps.Keys())
+ assert.NotContains(t, "property2", generatedProps.Keys())
+ assertHasProperty(t, generatedProps, "service1", myService1Address)
+ assertHasProperty(t, generatedProps, "service2", myService2Address)
+ assertHasProperty(t, generatedProps, "service3", myKnService1Address)
+ assertHasProperty(t, generatedProps, "service4", myKnService2Address)
+ assertHasProperty(t, generatedProps, "service5", myKnService3Address)
+ assertHasProperty(t, generatedProps, "broker1", myKnBroker1Address)
+ assertHasProperty(t, generatedProps, "broker2", myKnBroker2Address)
//org.kie.kogito.addons.discovery.kubernetes\:services.v1\/usecase1ยบ/my-service1
below we use the unescaped vale because the properties.LoadString removes them.
assertHasProperty(t, generatedProps,
"org.kie.kogito.addons.discovery.kubernetes:services.v1/namespace1/my-service1",
myService1Address)
@@ -214,12 +217,12 @@ func
Test_appPropertyHandler_WithServicesWithUserOverrides(t *testing.T) {
assert.NoError(t, err)
generatedProps, propsErr :=
properties.LoadString(props.WithUserProperties(userProperties).Build())
assert.NoError(t, propsErr)
- assert.Equal(t, 13, len(generatedProps.Keys()))
- assert.Equal(t, "value1", generatedProps.GetString("property1", ""))
- assert.Equal(t, "value2", generatedProps.GetString("property2", ""))
+ assert.Equal(t, 11, len(generatedProps.Keys()))
+ assert.NotContains(t, "property1", generatedProps.Keys())
+ assert.NotContains(t, "property2", generatedProps.Keys())
- //kogito.service.url takes the user provided value since it's a default
mutable property.
- assert.Equal(t, "http://myUrl.override.com",
generatedProps.GetString("kogito.service.url", ""))
+ //kogito.service.url is a default immutable property.
+ assert.Equal(t, "http://greeting.default",
generatedProps.GetString("kogito.service.url", ""))
//quarkus.http.port remains with the default value since it's immutable.
assert.Equal(t, "8080", generatedProps.GetString("quarkus.http.port",
""))
assert.Equal(t, "0.0.0.0",
generatedProps.GetString("quarkus.http.host", ""))
@@ -239,7 +242,9 @@ func
Test_appPropertyHandler_WithServicesWithUserOverrides(t *testing.T) {
assert.NoError(t, err)
generatedProps, propsErr =
properties.LoadString(props.WithUserProperties(userProperties).Build())
assert.NoError(t, propsErr)
- assert.Equal(t, 18, len(generatedProps.Keys()))
+ assert.Equal(t, 16, len(generatedProps.Keys()))
+ assert.NotContains(t, "property1", generatedProps.Keys())
+ assert.NotContains(t, "property2", generatedProps.Keys())
assert.Equal(t,
"http://"+platform.Name+"-"+constants.DataIndexServiceName+"."+platform.Namespace+"/definitions",
generatedProps.GetString(constants.KogitoProcessDefinitionsEventsURL, ""))
assert.Equal(t, "true",
generatedProps.GetString(constants.KogitoProcessDefinitionsEventsEnabled, ""))
assert.Equal(t,
"http://"+platform.Name+"-"+constants.DataIndexServiceName+"."+platform.Namespace+"/processes",
generatedProps.GetString(constants.KogitoProcessInstancesEventsURL, ""))
@@ -259,7 +264,9 @@ func
Test_appPropertyHandler_WithServicesWithUserOverrides(t *testing.T) {
assert.NoError(t, err)
generatedProps, propsErr =
properties.LoadString(props.WithUserProperties(userProperties).Build())
assert.NoError(t, propsErr)
- assert.Equal(t, 14, len(generatedProps.Keys()))
+ assert.Equal(t, 12, len(generatedProps.Keys()))
+ assert.NotContains(t, "property1", generatedProps.Keys())
+ assert.NotContains(t, "property2", generatedProps.Keys())
assert.Equal(t, "",
generatedProps.GetString(constants.KogitoProcessDefinitionsEventsURL, ""))
assert.Equal(t, "false",
generatedProps.GetString(constants.KogitoProcessDefinitionsEventsEnabled, ""))
assert.Equal(t, "",
generatedProps.GetString(constants.KogitoProcessInstancesEventsURL, ""))
@@ -276,7 +283,9 @@ func
Test_appPropertyHandler_WithServicesWithUserOverrides(t *testing.T) {
assert.NoError(t, err)
generatedProps, propsErr =
properties.LoadString(props.WithUserProperties(userProperties).Build())
assert.NoError(t, propsErr)
- assert.Equal(t, 13, len(generatedProps.Keys()))
+ assert.Equal(t, 11, len(generatedProps.Keys()))
+ assert.NotContains(t, "property1", generatedProps.Keys())
+ assert.NotContains(t, "property2", generatedProps.Keys())
assert.Equal(t, "",
generatedProps.GetString(constants.KogitoProcessDefinitionsEventsURL, ""))
assert.Equal(t, "false",
generatedProps.GetString(constants.KogitoProcessDefinitionsEventsEnabled, ""))
assert.Equal(t, "",
generatedProps.GetString(constants.KogitoProcessInstancesEventsURL, ""))
diff --git a/controllers/profiles/common/properties/discovery.go
b/controllers/profiles/common/properties/discovery.go
index a7663d41..6d2ac71b 100644
--- a/controllers/profiles/common/properties/discovery.go
+++ b/controllers/profiles/common/properties/discovery.go
@@ -99,6 +99,8 @@ func generateDiscoveryProperties(ctx context.Context, catalog
discovery.ServiceC
mpProperty :=
generateMicroprofileServiceCatalogProperty(plainUri)
klog.V(log.I).Infof("Generating
microprofile service catalog property %s=%s.", mpProperty, address)
result.MustSet(mpProperty, address)
+ klog.V(log.I).Infof("Overriding the
discoverable value as the managed property %s=%s.", k, address)
+ result.MustSet(k, address)
}
}
}
diff --git a/controllers/profiles/common/properties/discovery_test.go
b/controllers/profiles/common/properties/discovery_test.go
index 4555c6c3..dd502d18 100644
--- a/controllers/profiles/common/properties/discovery_test.go
+++ b/controllers/profiles/common/properties/discovery_test.go
@@ -62,7 +62,12 @@ func Test_generateDiscoveryProperties(t *testing.T) {
Spec: v1alpha08.SonataFlowSpec{Flow: workflow},
})
- assert.Equal(t, result.Len(), 5)
+ assert.Equal(t, 8, result.Len())
+ assertHasProperty(t, result, "service1", myService1Address)
+ assertHasProperty(t, result, "service2", myService2Address)
+ assertHasProperty(t, result, "service3", myService3Address)
+ assertHasProperty(t, result,
"org.kie.kogito.addons.discovery.kubernetes\\:services.v1\\/namespace1\\/my-service1",
myService1Address)
+ assertHasProperty(t, result,
"org.kie.kogito.addons.discovery.kubernetes\\:services.v1\\/namespace1\\/my-service1",
myService1Address)
assertHasProperty(t, result,
"org.kie.kogito.addons.discovery.kubernetes\\:services.v1\\/namespace1\\/my-service1",
myService1Address)
assertHasProperty(t, result,
"org.kie.kogito.addons.discovery.kubernetes\\:services.v1\\/my-service2",
myService2Address)
assertHasProperty(t, result,
"org.kie.kogito.addons.discovery.kubernetes\\:services.v1\\/my-service3?port\\=http-port",
myService3Address)
diff --git a/controllers/profiles/dev/object_creators_dev.go
b/controllers/profiles/dev/object_creators_dev.go
index 1cbb42e4..03b85750 100644
--- a/controllers/profiles/dev/object_creators_dev.go
+++ b/controllers/profiles/dev/object_creators_dev.go
@@ -118,7 +118,7 @@ func ensureWorkflowDefConfigMapMutator(workflow
*operatorapi.SonataFlow) common.
}
// mountDevConfigMapsMutateVisitor mounts the required configMaps in the
Workflow Dev Deployment
-func mountDevConfigMapsMutateVisitor(flowDefCM, propsCM *corev1.ConfigMap,
workflowResCMs []operatorapi.ConfigMapWorkflowResource) common.MutateVisitor {
+func mountDevConfigMapsMutateVisitor(workflow *operatorapi.SonataFlow,
flowDefCM, userPropsCM, managedPropsCM *corev1.ConfigMap, workflowResCMs
[]operatorapi.ConfigMapWorkflowResource) common.MutateVisitor {
return func(object client.Object) controllerutil.MutateFn {
return func() error {
deployment := object.(*appsv1.Deployment)
@@ -129,7 +129,8 @@ func mountDevConfigMapsMutateVisitor(flowDefCM, propsCM
*corev1.ConfigMap, workf
// defaultResourcesVolume holds every ConfigMap mount
required on src/main/resources
defaultResourcesVolume := corev1.Volume{Name:
configMapResourcesVolumeName, VolumeSource: corev1.VolumeSource{Projected:
&corev1.ProjectedVolumeSource{}}}
-
kubeutil.VolumeProjectionAddConfigMap(defaultResourcesVolume.Projected,
propsCM.Name, corev1.KeyToPath{Key: workflowproj.ApplicationPropertiesFileName,
Path: workflowproj.ApplicationPropertiesFileName})
+
kubeutil.VolumeProjectionAddConfigMap(defaultResourcesVolume.Projected,
userPropsCM.Name, corev1.KeyToPath{Key:
workflowproj.ApplicationPropertiesFileName, Path:
workflowproj.ApplicationPropertiesFileName})
+
kubeutil.VolumeProjectionAddConfigMap(defaultResourcesVolume.Projected,
managedPropsCM.Name, corev1.KeyToPath{Key:
workflowproj.GetManagedPropertiesFileName(workflow), Path:
workflowproj.GetManagedPropertiesFileName(workflow)})
kubeutil.VolumeProjectionAddConfigMap(defaultResourcesVolume.Projected,
flowDefCM.Name)
// resourceVolumes holds every resource that needs to
be mounted on src/main/resources/<specific_dir>
diff --git a/controllers/profiles/dev/object_creators_dev_test.go
b/controllers/profiles/dev/object_creators_dev_test.go
index 37adaf8a..8209940a 100644
--- a/controllers/profiles/dev/object_creators_dev_test.go
+++ b/controllers/profiles/dev/object_creators_dev_test.go
@@ -30,7 +30,6 @@ import (
func Test_ensureWorkflowDevServiceIsExposed(t *testing.T) {
workflow := test.GetBaseSonataFlowWithDevProfile(t.Name())
-
//On Kubernetes we want the service exposed in Dev with NodePort
service, _ := serviceCreator(workflow)
service.SetUID("1")
diff --git a/controllers/profiles/dev/profile_dev.go
b/controllers/profiles/dev/profile_dev.go
index dd0ae728..42b9151a 100644
--- a/controllers/profiles/dev/profile_dev.go
+++ b/controllers/profiles/dev/profile_dev.go
@@ -75,21 +75,23 @@ func NewProfileReconciler(client client.Client, cfg
*rest.Config, recorder recor
func newObjectEnsurers(support *common.StateSupport) *objectEnsurers {
return &objectEnsurers{
- deployment: common.NewObjectEnsurer(support.C,
deploymentCreator),
- service: common.NewObjectEnsurer(support.C,
serviceCreator),
- network: common.NewNoopObjectEnsurer(),
- definitionConfigMap: common.NewObjectEnsurer(support.C,
workflowDefConfigMapCreator),
- propertiesConfigMap: common.NewObjectEnsurer(support.C,
common.WorkflowPropsConfigMapCreator),
+ deployment: common.NewObjectEnsurer(support.C,
deploymentCreator),
+ service: common.NewObjectEnsurer(support.C,
serviceCreator),
+ network: common.NewNoopObjectEnsurer(),
+ definitionConfigMap: common.NewObjectEnsurer(support.C,
workflowDefConfigMapCreator),
+ userPropsConfigMap: common.NewObjectEnsurer(support.C,
common.UserPropsConfigMapCreator),
+ managedPropsConfigMap:
common.NewObjectEnsurerWithPlatform(support.C,
common.ManagedPropsConfigMapCreator),
}
}
func newObjectEnsurersOpenShift(support *common.StateSupport) *objectEnsurers {
return &objectEnsurers{
- deployment: common.NewObjectEnsurer(support.C,
deploymentCreator),
- service: common.NewObjectEnsurer(support.C,
serviceCreator),
- network: common.NewObjectEnsurer(support.C,
common.OpenShiftRouteCreator),
- definitionConfigMap: common.NewObjectEnsurer(support.C,
workflowDefConfigMapCreator),
- propertiesConfigMap: common.NewObjectEnsurer(support.C,
common.WorkflowPropsConfigMapCreator),
+ deployment: common.NewObjectEnsurer(support.C,
deploymentCreator),
+ service: common.NewObjectEnsurer(support.C,
serviceCreator),
+ network: common.NewObjectEnsurer(support.C,
common.OpenShiftRouteCreator),
+ definitionConfigMap: common.NewObjectEnsurer(support.C,
workflowDefConfigMapCreator),
+ userPropsConfigMap: common.NewObjectEnsurer(support.C,
common.UserPropsConfigMapCreator),
+ managedPropsConfigMap:
common.NewObjectEnsurerWithPlatform(support.C,
common.ManagedPropsConfigMapCreator),
}
}
@@ -106,11 +108,12 @@ func newStatusEnrichersOpenShift(support
*common.StateSupport) *statusEnrichers
}
type objectEnsurers struct {
- deployment common.ObjectEnsurer
- service common.ObjectEnsurer
- network common.ObjectEnsurer
- definitionConfigMap common.ObjectEnsurer
- propertiesConfigMap common.ObjectEnsurer
+ deployment common.ObjectEnsurer
+ service common.ObjectEnsurer
+ network common.ObjectEnsurer
+ definitionConfigMap common.ObjectEnsurer
+ userPropsConfigMap common.ObjectEnsurer
+ managedPropsConfigMap common.ObjectEnsurerWithPlatform
}
type statusEnrichers struct {
diff --git a/controllers/profiles/dev/profile_dev_test.go
b/controllers/profiles/dev/profile_dev_test.go
index 5c2591d0..1c3478ea 100644
--- a/controllers/profiles/dev/profile_dev_test.go
+++ b/controllers/profiles/dev/profile_dev_test.go
@@ -145,12 +145,16 @@ func Test_newDevProfile(t *testing.T) {
assert.Equal(t, quarkusDevConfigMountPath,
deployment.Spec.Template.Spec.Containers[0].VolumeMounts[0].MountPath)
assert.Equal(t, "",
deployment.Spec.Template.Spec.Containers[0].VolumeMounts[0].SubPath)
//https://kubernetes.io/docs/concepts/configuration/configmap/#mounted-configmaps-are-updated-automatically
- propCM := &corev1.ConfigMap{}
- _ = client.Get(context.TODO(), types.NamespacedName{Namespace:
workflow.Namespace, Name:
workflowproj.GetWorkflowPropertiesConfigMapName(workflow)}, propCM)
- assert.NotEmpty(t,
propCM.Data[workflowproj.ApplicationPropertiesFileName])
+ userPropsCM := &corev1.ConfigMap{}
+ _ = client.Get(context.TODO(), types.NamespacedName{Namespace:
workflow.Namespace, Name:
workflowproj.GetWorkflowUserPropertiesConfigMapName(workflow)}, userPropsCM)
+ assert.Empty(t,
userPropsCM.Data[workflowproj.ApplicationPropertiesFileName])
+
+ managedPropsCM := &corev1.ConfigMap{}
+ _ = client.Get(context.TODO(), types.NamespacedName{Namespace:
workflow.Namespace, Name:
workflowproj.GetWorkflowManagedPropertiesConfigMapName(workflow)},
managedPropsCM)
+ assert.NotEmpty(t,
managedPropsCM.Data[workflowproj.GetManagedPropertiesFileName(workflow)])
assert.Equal(t, quarkusDevConfigMountPath,
deployment.Spec.Template.Spec.Containers[0].VolumeMounts[0].MountPath)
assert.Equal(t, "",
deployment.Spec.Template.Spec.Containers[0].VolumeMounts[0].SubPath)
//https://kubernetes.io/docs/concepts/configuration/configmap/#mounted-configmaps-are-updated-automatically
- assert.Contains(t,
propCM.Data[workflowproj.ApplicationPropertiesFileName], "quarkus.http.port")
+ assert.Contains(t,
managedPropsCM.Data[workflowproj.GetManagedPropertiesFileName(workflow)],
"quarkus.http.port")
service := test.MustGetService(t, client, workflow)
assert.Equal(t, int32(constants.DefaultHTTPWorkflowPortInt),
service.Spec.Ports[0].TargetPort.IntVal)
@@ -179,10 +183,14 @@ func Test_newDevProfile(t *testing.T) {
err = client.Update(context.TODO(), deployment)
assert.NoError(t, err)
- propCM = &corev1.ConfigMap{}
- _ = client.Get(context.TODO(), types.NamespacedName{Namespace:
workflow.Namespace, Name:
workflowproj.GetWorkflowPropertiesConfigMapName(workflow)}, propCM)
- assert.NotEmpty(t,
propCM.Data[workflowproj.ApplicationPropertiesFileName])
- assert.Contains(t,
propCM.Data[workflowproj.ApplicationPropertiesFileName], "quarkus.http.port")
+ userPropsCM = &corev1.ConfigMap{}
+ _ = client.Get(context.TODO(), types.NamespacedName{Namespace:
workflow.Namespace, Name:
workflowproj.GetWorkflowUserPropertiesConfigMapName(workflow)}, userPropsCM)
+ assert.Empty(t,
userPropsCM.Data[workflowproj.ApplicationPropertiesFileName])
+
+ managedPropsCM = &corev1.ConfigMap{}
+ _ = client.Get(context.TODO(), types.NamespacedName{Namespace:
workflow.Namespace, Name:
workflowproj.GetWorkflowManagedPropertiesConfigMapName(workflow)},
managedPropsCM)
+ assert.NotEmpty(t,
managedPropsCM.Data[workflowproj.GetManagedPropertiesFileName(workflow)])
+ assert.Contains(t,
managedPropsCM.Data[workflowproj.GetManagedPropertiesFileName(workflow)],
"quarkus.http.port")
// reconcile
workflow.Status.Manager().MarkTrue(api.RunningConditionType)
diff --git a/controllers/profiles/dev/states_dev.go
b/controllers/profiles/dev/states_dev.go
index e965547e..f98e03eb 100644
--- a/controllers/profiles/dev/states_dev.go
+++ b/controllers/profiles/dev/states_dev.go
@@ -74,11 +74,15 @@ func (e *ensureRunningWorkflowState) Do(ctx
context.Context, workflow *operatora
if err == nil && len(pl.Spec.DevMode.BaseImage) > 0 {
devBaseContainerImage = pl.Spec.DevMode.BaseImage
}
- propsCM, _, err := e.ensurers.propertiesConfigMap.Ensure(ctx, workflow,
common.WorkflowPropertiesMutateVisitor(ctx, e.StateSupport.Catalog, workflow,
pl))
+ userPropsCM, _, err := e.ensurers.userPropsConfigMap.Ensure(ctx,
workflow)
if err != nil {
return ctrl.Result{Requeue: false}, objs, err
}
- objs = append(objs, propsCM)
+ managedPropsCM, _, err := e.ensurers.managedPropsConfigMap.Ensure(ctx,
workflow, pl, common.ManagedPropertiesMutateVisitor(ctx,
e.StateSupport.Catalog, workflow, pl, userPropsCM.(*corev1.ConfigMap)))
+ if err != nil {
+ return ctrl.Result{Requeue: false}, objs, err
+ }
+ objs = append(objs, managedPropsCM)
externalCM, err := workflowdef.FetchExternalResourcesConfigMapsRef(e.C,
workflow)
if err != nil {
@@ -92,7 +96,7 @@ func (e *ensureRunningWorkflowState) Do(ctx context.Context,
workflow *operatora
deployment, _, err := e.ensurers.deployment.Ensure(ctx, workflow,
deploymentMutateVisitor(workflow),
common.ImageDeploymentMutateVisitor(workflow,
devBaseContainerImage),
- mountDevConfigMapsMutateVisitor(flowDefCM.(*corev1.ConfigMap),
propsCM.(*corev1.ConfigMap), externalCM))
+ mountDevConfigMapsMutateVisitor(workflow,
flowDefCM.(*corev1.ConfigMap), userPropsCM.(*corev1.ConfigMap),
managedPropsCM.(*corev1.ConfigMap), externalCM))
if err != nil {
return ctrl.Result{RequeueAfter:
constants.RequeueAfterFailure}, objs, err
}
diff --git a/controllers/profiles/prod/deployment_handler.go
b/controllers/profiles/prod/deployment_handler.go
index a5459a87..3b693429 100644
--- a/controllers/profiles/prod/deployment_handler.go
+++ b/controllers/profiles/prod/deployment_handler.go
@@ -49,9 +49,16 @@ func (d *deploymentReconciler) reconcile(ctx
context.Context, workflow *operator
func (d *deploymentReconciler) reconcileWithBuiltImage(ctx context.Context,
workflow *operatorapi.SonataFlow, image string) (reconcile.Result,
[]client.Object, error) {
pl, _ := platform.GetActivePlatform(ctx, d.C, workflow.Namespace)
- propsCM, _, err := d.ensurers.propertiesConfigMap.Ensure(ctx, workflow,
common.WorkflowPropertiesMutateVisitor(ctx, d.StateSupport.Catalog, workflow,
pl))
+ userPropsCM, _, err := d.ensurers.userPropsConfigMap.Ensure(ctx,
workflow)
if err != nil {
- workflow.Status.Manager().MarkFalse(api.RunningConditionType,
api.ExternalResourcesNotFoundReason, "Unable to retrieve the properties config
map")
+ workflow.Status.Manager().MarkFalse(api.RunningConditionType,
api.ExternalResourcesNotFoundReason, "Unable to retrieve the user properties
config map")
+ _, err = d.PerformStatusUpdate(ctx, workflow)
+ return ctrl.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")
_, err = d.PerformStatusUpdate(ctx, workflow)
return ctrl.Result{}, nil, err
}
@@ -60,7 +67,7 @@ func (d *deploymentReconciler) reconcileWithBuiltImage(ctx
context.Context, work
d.ensurers.deployment.Ensure(
ctx,
workflow,
- d.getDeploymentMutateVisitors(workflow, image,
propsCM.(*v1.ConfigMap))...,
+ d.getDeploymentMutateVisitors(workflow, 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)
@@ -75,7 +82,7 @@ func (d *deploymentReconciler) reconcileWithBuiltImage(ctx
context.Context, work
return reconcile.Result{}, nil, err
}
- objs := []client.Object{deployment, service, propsCM}
+ objs := []client.Object{deployment, service, managedPropsCM}
if deploymentOp == controllerutil.OperationResultCreated {
workflow.Status.Manager().MarkFalse(api.RunningConditionType,
api.WaitingForDeploymentReason, "")
@@ -100,17 +107,18 @@ func (d *deploymentReconciler)
reconcileWithBuiltImage(ctx context.Context, work
func (d *deploymentReconciler) getDeploymentMutateVisitors(
workflow *operatorapi.SonataFlow,
image string,
- configMap *v1.ConfigMap) []common.MutateVisitor {
+ userPropsCM *v1.ConfigMap,
+ managedPropsCM *v1.ConfigMap) []common.MutateVisitor {
if utils.IsOpenShift() {
return
[]common.MutateVisitor{common.DeploymentMutateVisitor(workflow),
- mountProdConfigMapsMutateVisitor(configMap),
+ mountProdConfigMapsMutateVisitor(workflow, userPropsCM,
managedPropsCM),
addOpenShiftImageTriggerDeploymentMutateVisitor(workflow, image),
common.ImageDeploymentMutateVisitor(workflow, image),
-
common.RolloutDeploymentIfCMChangedMutateVisitor(configMap),
+
common.RolloutDeploymentIfCMChangedMutateVisitor(workflow, userPropsCM,
managedPropsCM),
}
}
return []common.MutateVisitor{common.DeploymentMutateVisitor(workflow),
common.ImageDeploymentMutateVisitor(workflow, image),
- mountProdConfigMapsMutateVisitor(configMap),
- common.RolloutDeploymentIfCMChangedMutateVisitor(configMap)}
+ mountProdConfigMapsMutateVisitor(workflow, userPropsCM,
managedPropsCM),
+ common.RolloutDeploymentIfCMChangedMutateVisitor(workflow,
userPropsCM, managedPropsCM)}
}
diff --git a/controllers/profiles/prod/deployment_handler_test.go
b/controllers/profiles/prod/deployment_handler_test.go
index 5adfae68..a133b963 100644
--- a/controllers/profiles/prod/deployment_handler_test.go
+++ b/controllers/profiles/prod/deployment_handler_test.go
@@ -26,6 +26,7 @@ import (
"github.com/stretchr/testify/assert"
v1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
+ "k8s.io/apimachinery/pkg/types"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
)
@@ -77,8 +78,12 @@ func Test_CheckDeploymentRolloutAfterCMChange(t *testing.T) {
assert.NotEmpty(t, objects)
assert.True(t, result.Requeue)
+ userPropsCM := &corev1.ConfigMap{}
+ err = client.Get(context.TODO(), types.NamespacedName{Name:
workflowproj.GetWorkflowUserPropertiesConfigMapName(workflow), Namespace:
t.Name()}, userPropsCM)
+ assert.NoError(t, err)
+
// Second reconciliation, we do change the configmap and that must
rollout the deployment
- var cm *corev1.ConfigMap
+ var managedPropsCM *corev1.ConfigMap
var checksum string
for _, o := range objects {
if _, ok := o.(*v1.Deployment); ok {
@@ -89,16 +94,20 @@ func Test_CheckDeploymentRolloutAfterCMChange(t *testing.T)
{
assert.NotContains(t,
deployment.Spec.Template.ObjectMeta.Annotations, metadata.RestartedAt)
}
if _, ok := o.(*corev1.ConfigMap); ok {
- cm = o.(*corev1.ConfigMap)
- currentProps :=
cm.Data[workflowproj.ApplicationPropertiesFileName]
- props, err := properties.LoadString(currentProps)
- assert.Nil(t, err)
- props.MustSet("test.property", "test.value")
- cm.Data[workflowproj.ApplicationPropertiesFileName] =
props.String()
+ cm := o.(*corev1.ConfigMap)
+ if cm.Name ==
workflowproj.GetWorkflowManagedPropertiesConfigMapName(workflow) {
+ managedPropsCM = cm
+ }
}
}
- assert.NotNil(t, cm)
- utilruntime.Must(client.Update(context.TODO(), cm))
+ assert.NotNil(t, managedPropsCM)
+
+ currentProps :=
userPropsCM.Data[workflowproj.ApplicationPropertiesFileName]
+ props, err := properties.LoadString(currentProps)
+ assert.Nil(t, err)
+ props.MustSet("test.property", "test.value")
+ userPropsCM.Data[workflowproj.ApplicationPropertiesFileName] =
props.String()
+ utilruntime.Must(client.Update(context.TODO(), userPropsCM))
result, objects, err = handler.reconcile(context.TODO(), workflow)
assert.NoError(t, err)
assert.NotEmpty(t, objects)
@@ -131,9 +140,13 @@ func Test_CheckDeploymentUnchangedAfterCMChangeOtherKeys(t
*testing.T) {
assert.NotEmpty(t, objects)
assert.True(t, result.Requeue)
+ userPropsCM := &corev1.ConfigMap{}
+ err = client.Get(context.TODO(), types.NamespacedName{Name:
workflowproj.GetWorkflowUserPropertiesConfigMapName(workflow), Namespace:
t.Name()}, userPropsCM)
+ assert.NoError(t, err)
+
// Second reconciliation, we do change the configmap and that must not
rollout the deployment
// because we're not updating the application.properties key
- var cm *corev1.ConfigMap
+ var managedPropsCM *corev1.ConfigMap
var checksum string
for _, o := range objects {
if _, ok := o.(*v1.Deployment); ok {
@@ -144,12 +157,16 @@ func
Test_CheckDeploymentUnchangedAfterCMChangeOtherKeys(t *testing.T) {
assert.NotContains(t,
deployment.Spec.Template.ObjectMeta.Annotations, metadata.RestartedAt)
}
if _, ok := o.(*corev1.ConfigMap); ok {
- cm = o.(*corev1.ConfigMap)
- cm.Data["other.key"] = "useless.key = value"
+ cm := o.(*corev1.ConfigMap)
+ if cm.Name ==
workflowproj.GetWorkflowManagedPropertiesConfigMapName(workflow) {
+ managedPropsCM = cm
+ }
}
}
- assert.NotNil(t, cm)
- utilruntime.Must(client.Update(context.TODO(), cm))
+ assert.NotNil(t, managedPropsCM)
+
+ userPropsCM.Data["other.key"] = "useless.key = value"
+ utilruntime.Must(client.Update(context.TODO(), userPropsCM))
result, objects, err = handler.reconcile(context.TODO(), workflow)
assert.NoError(t, err)
assert.NotEmpty(t, objects)
@@ -157,13 +174,10 @@ func
Test_CheckDeploymentUnchangedAfterCMChangeOtherKeys(t *testing.T) {
for _, o := range objects {
if _, ok := o.(*v1.Deployment); ok {
deployment := o.(*v1.Deployment)
- // Commented while waiting for SRVLOGIC-195 to be
addressed
- // assert.NotContains(t,
deployment.Spec.Template.ObjectMeta.Annotations, metadata.RestartedAt)
- assert.Contains(t,
deployment.Spec.Template.ObjectMeta.Annotations, metadata.Checksum)
+ assert.NotContains(t,
deployment.Spec.Template.ObjectMeta.Annotations, metadata.RestartedAt)
newChecksum :=
deployment.Spec.Template.ObjectMeta.Annotations[metadata.Checksum]
assert.NotEmpty(t, newChecksum)
- // Change to asssert.Equal when SRVLOGIC-195 is
addressed
- assert.NotEqual(t, newChecksum, checksum)
+ assert.Equal(t, newChecksum, checksum)
break
}
}
diff --git a/controllers/profiles/prod/object_creators_prod.go
b/controllers/profiles/prod/object_creators_prod.go
index 34d1447e..02328e9b 100644
--- a/controllers/profiles/prod/object_creators_prod.go
+++ b/controllers/profiles/prod/object_creators_prod.go
@@ -28,6 +28,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
"github.com/apache/incubator-kie-kogito-serverless-operator/api/v1alpha08"
+ operatorapi
"github.com/apache/incubator-kie-kogito-serverless-operator/api/v1alpha08"
"github.com/apache/incubator-kie-kogito-serverless-operator/controllers/profiles/common"
"github.com/apache/incubator-kie-kogito-serverless-operator/controllers/profiles/common/constants"
@@ -64,7 +65,7 @@ func addOpenShiftImageTriggerDeploymentMutateVisitor(workflow
*v1alpha08.SonataF
}
// mountDevConfigMapsMutateVisitor mounts the required configMaps in the
Workflow Dev Deployment
-func mountProdConfigMapsMutateVisitor(propsCM *v1.ConfigMap)
common.MutateVisitor {
+func mountProdConfigMapsMutateVisitor(workflow *operatorapi.SonataFlow,
userPropsCM *v1.ConfigMap, managedPropsCM *v1.ConfigMap) common.MutateVisitor {
return func(object client.Object) controllerutil.MutateFn {
return func() error {
deployment := object.(*appsv1.Deployment)
@@ -77,12 +78,14 @@ func mountProdConfigMapsMutateVisitor(propsCM
*v1.ConfigMap) common.MutateVisito
deployment.Spec.Template.Spec.Containers[idx].VolumeMounts =
make([]v1.VolumeMount, 0, 1)
}
-
kubeutil.AddOrReplaceVolume(&deployment.Spec.Template.Spec,
-
kubeutil.VolumeConfigMap(constants.ConfigMapWorkflowPropsVolumeName,
propsCM.Name, v1.KeyToPath{Key: workflowproj.ApplicationPropertiesFileName,
Path: workflowproj.ApplicationPropertiesFileName}))
+ defaultResourcesVolume := v1.Volume{Name:
constants.ConfigMapWorkflowPropsVolumeName, VolumeSource:
v1.VolumeSource{Projected: &v1.ProjectedVolumeSource{}}}
+
kubeutil.VolumeProjectionAddConfigMap(defaultResourcesVolume.Projected,
userPropsCM.Name, v1.KeyToPath{Key: workflowproj.ApplicationPropertiesFileName,
Path: workflowproj.ApplicationPropertiesFileName})
+
kubeutil.VolumeProjectionAddConfigMap(defaultResourcesVolume.Projected,
managedPropsCM.Name, v1.KeyToPath{Key:
workflowproj.GetManagedPropertiesFileName(workflow), Path:
workflowproj.GetManagedPropertiesFileName(workflow)})
+
kubeutil.AddOrReplaceVolume(&deployment.Spec.Template.Spec,
defaultResourcesVolume)
kubeutil.AddOrReplaceVolumeMount(idx,
&deployment.Spec.Template.Spec,
kubeutil.VolumeMount(constants.ConfigMapWorkflowPropsVolumeName, true,
quarkusProdConfigMountPath))
- kubeutil.AnnotateDeploymentConfigChecksum(deployment,
propsCM)
+ kubeutil.AnnotateDeploymentConfigChecksum(workflow,
deployment, userPropsCM, managedPropsCM)
return nil
}
}
diff --git a/controllers/profiles/prod/profile_prod.go
b/controllers/profiles/prod/profile_prod.go
index 062359ee..f5046d05 100644
--- a/controllers/profiles/prod/profile_prod.go
+++ b/controllers/profiles/prod/profile_prod.go
@@ -52,16 +52,18 @@ const (
// ReconciliationState that needs access to it must include this struct as an
attribute and initialize it in the profile builder.
// Use newObjectEnsurers to facilitate building this struct
type objectEnsurers struct {
- deployment common.ObjectEnsurer
- service common.ObjectEnsurer
- propertiesConfigMap common.ObjectEnsurer
+ deployment common.ObjectEnsurer
+ service common.ObjectEnsurer
+ userPropsConfigMap common.ObjectEnsurer
+ managedPropsConfigMap common.ObjectEnsurerWithPlatform
}
func newObjectEnsurers(support *common.StateSupport) *objectEnsurers {
return &objectEnsurers{
- deployment: common.NewObjectEnsurer(support.C,
common.DeploymentCreator),
- service: common.NewObjectEnsurer(support.C,
common.ServiceCreator),
- propertiesConfigMap: common.NewObjectEnsurer(support.C,
common.WorkflowPropsConfigMapCreator),
+ deployment: common.NewObjectEnsurer(support.C,
common.DeploymentCreator),
+ service: common.NewObjectEnsurer(support.C,
common.ServiceCreator),
+ userPropsConfigMap: common.NewObjectEnsurer(support.C,
common.UserPropsConfigMapCreator),
+ managedPropsConfigMap:
common.NewObjectEnsurerWithPlatform(support.C,
common.ManagedPropsConfigMapCreator),
}
}
diff --git a/utils/kubernetes/deployment.go b/utils/kubernetes/deployment.go
index ab8dd940..676c4992 100644
--- a/utils/kubernetes/deployment.go
+++ b/utils/kubernetes/deployment.go
@@ -27,6 +27,7 @@ import (
"time"
"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/log"
"github.com/apache/incubator-kie-kogito-serverless-operator/workflowproj"
appsv1 "k8s.io/api/apps/v1"
@@ -112,7 +113,7 @@ func MarkDeploymentToRollout(deployment *appsv1.Deployment)
error {
// AnnotateDeploymentConfigChecksum adds the checksum/config annotation to the
template annotations of the Deployment to set the current configuration.
// If the checksum has changed from the previous value, the restartedAt
annotation is also added and a new rollout is started.
// Code adapted from here:
https://github.com/kubernetes/kubectl/blob/release-1.26/pkg/polymorphichelpers/objectrestarter.go#L44
-func AnnotateDeploymentConfigChecksum(deployment *appsv1.Deployment, cm
*v1.ConfigMap) error {
+func AnnotateDeploymentConfigChecksum(workflow *operatorapi.SonataFlow,
deployment *appsv1.Deployment, userPropsCM *v1.ConfigMap, managedPropsCM
*v1.ConfigMap) error {
if deployment.Spec.Paused {
return errors.New("can't restart paused deployment (run rollout
resume first)")
}
@@ -124,7 +125,7 @@ func AnnotateDeploymentConfigChecksum(deployment
*appsv1.Deployment, cm *v1.Conf
if !ok {
currentChecksum = ""
}
- newChecksum, err := configMapChecksum(cm)
+ newChecksum, err := calculateHash(userPropsCM, managedPropsCM, workflow)
if err != nil {
return err
}
@@ -141,14 +142,19 @@ func AnnotateDeploymentConfigChecksum(deployment
*appsv1.Deployment, cm *v1.Conf
return nil
}
-func configMapChecksum(cm *v1.ConfigMap) (string, error) {
- props, hasKey := cm.Data[workflowproj.ApplicationPropertiesFileName]
+func dataFromCM(cm *v1.ConfigMap, key string) string {
+ data, hasKey := cm.Data[key]
if !hasKey {
- props = ""
+ return ""
}
+ return data
+}
+func calculateHash(userPropsCM, managedPropsCM *v1.ConfigMap, workflow
*operatorapi.SonataFlow) (string, error) {
+ aggregatedProps := fmt.Sprintf("%s,%s", dataFromCM(userPropsCM,
workflowproj.ApplicationPropertiesFileName),
+ dataFromCM(managedPropsCM,
workflowproj.GetManagedPropertiesFileName(workflow)))
hash := sha256.New()
- _, err := hash.Write([]byte(props))
+ _, err := hash.Write([]byte(aggregatedProps))
if err != nil {
return "", err
}
diff --git a/workflowproj/operator.go b/workflowproj/operator.go
index 7821c36a..33b4ca67 100644
--- a/workflowproj/operator.go
+++ b/workflowproj/operator.go
@@ -20,18 +20,22 @@
package workflowproj
import (
+ "fmt"
+
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"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"
)
const (
- workflowConfigMapNameSuffix = "-props"
- // ApplicationPropertiesFileName is the default application properties
file name
- ApplicationPropertiesFileName = "application.properties"
+ workflowUserConfigMapNameSuffix = "-props"
+ // ApplicationPropertiesFileName is the default application properties
file name holding user properties
+ ApplicationPropertiesFileName = "application.properties"
+ workflowManagedConfigMapNameSuffix = "-managed-props"
// LabelApp key to use among object selectors, "app" is used among k8s
applications to group objects in some UI consoles
LabelApp = "app"
// LabelService key to use among object selectors
@@ -60,9 +64,23 @@ func SetTypeToObject(obj runtime.Object, s *runtime.Scheme)
error {
return nil
}
-// GetWorkflowPropertiesConfigMapName gets the default ConfigMap name that
holds the application property for the given workflow
-func GetWorkflowPropertiesConfigMapName(workflow *operatorapi.SonataFlow)
string {
- return workflow.Name + workflowConfigMapNameSuffix
+// GetWorkflowUserPropertiesConfigMapName gets the default ConfigMap name that
holds the user application property for the given workflow
+func GetWorkflowUserPropertiesConfigMapName(workflow *operatorapi.SonataFlow)
string {
+ return workflow.Name + workflowUserConfigMapNameSuffix
+}
+
+// GetWorkflowManagedPropertiesConfigMapName gets the default ConfigMap name
that holds the managed application property for the given workflow
+func GetWorkflowManagedPropertiesConfigMapName(workflow
*operatorapi.SonataFlow) string {
+ return workflow.Name + workflowManagedConfigMapNameSuffix
+}
+
+// GetWorkflowManagedPropertiesConfigMapName gets the default ConfigMap name
that holds the managed application property for the given workflow
+func GetManagedPropertiesFileName(workflow *operatorapi.SonataFlow) string {
+ profile := metadata.ProdProfile
+ if profiles.IsDevProfile(workflow) {
+ profile = metadata.DevProfile
+ }
+ return fmt.Sprintf("application-%s.properties", profile)
}
// SetDefaultLabels adds the default workflow application labels to the given
object.
@@ -80,15 +98,27 @@ func GetDefaultLabels(workflow *operatorapi.SonataFlow)
map[string]string {
}
}
-// CreateNewAppPropsConfigMap creates a new ConfigMap object to hold the
workflow application properties.
-func CreateNewAppPropsConfigMap(workflow *operatorapi.SonataFlow, properties
string) *corev1.ConfigMap {
+// CreateNewUserPropsConfigMap creates a new empty ConfigMap object to hold
the user application properties of the workflow.
+func CreateNewUserPropsConfigMap(workflow *operatorapi.SonataFlow)
*corev1.ConfigMap {
+ return &corev1.ConfigMap{
+ ObjectMeta: metav1.ObjectMeta{
+ Name:
GetWorkflowUserPropertiesConfigMapName(workflow),
+ Namespace: workflow.Namespace,
+ Labels: GetDefaultLabels(workflow),
+ },
+ Data: map[string]string{ApplicationPropertiesFileName: ""},
+ }
+}
+
+// CreateNewManagedPropsConfigMap creates a new ConfigMap object to hold the
managed application properties of the workflos.
+func CreateNewManagedPropsConfigMap(workflow *operatorapi.SonataFlow,
properties string) *corev1.ConfigMap {
return &corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
- Name: GetWorkflowPropertiesConfigMapName(workflow),
+ Name:
GetWorkflowManagedPropertiesConfigMapName(workflow),
Namespace: workflow.Namespace,
Labels: GetDefaultLabels(workflow),
},
- Data: map[string]string{ApplicationPropertiesFileName:
properties},
+ Data: map[string]string{GetManagedPropertiesFileName(workflow):
properties},
}
}
diff --git a/workflowproj/workflowproj.go b/workflowproj/workflowproj.go
index 3b46f8c9..afabd7e5 100644
--- a/workflowproj/workflowproj.go
+++ b/workflowproj/workflowproj.go
@@ -247,7 +247,8 @@ func (w *workflowProjectHandler) parseRawAppProperties()
error {
if err != nil {
return err
}
- w.project.Properties = CreateNewAppPropsConfigMap(w.project.Workflow,
string(appPropsContent))
+ w.project.Properties = CreateNewUserPropsConfigMap(w.project.Workflow)
+ w.project.Properties.Data[ApplicationPropertiesFileName] =
string(appPropsContent)
if err = SetTypeToObject(w.project.Properties, w.scheme); err != nil {
return err
}
diff --git a/workflowproj/workflowproj_test.go
b/workflowproj/workflowproj_test.go
index 0bc9679c..c1207527 100644
--- a/workflowproj/workflowproj_test.go
+++ b/workflowproj/workflowproj_test.go
@@ -61,6 +61,7 @@ func Test_Handler_WorkflowMinimalAndProps(t *testing.T) {
assert.NotNil(t, proj.Properties)
assert.Equal(t, "minimal", proj.Workflow.Name)
assert.Equal(t, "minimal-props", proj.Properties.Name)
+ assert.NotEmpty(t, proj.Properties.Data["application.properties"])
assert.Equal(t, string(metadata.ProdProfile),
proj.Workflow.Annotations[metadata.Profile])
assert.NotEmpty(t, proj.Properties.Data)
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]