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 7c848392 Closes #436 - Introduce SonataFlowPlatform flow properties
propagation (#443)
7c848392 is described below
commit 7c848392e21f0822a1bafabfe1b3104f843df8e1
Author: Ricardo Zanini <[email protected]>
AuthorDate: Tue Apr 16 12:22:40 2024 -0300
Closes #436 - Introduce SonataFlowPlatform flow properties propagation
(#443)
---
Makefile | 2 +-
api/v1alpha08/sonataflowplatform_property_types.go | 53 +++++++++
api/v1alpha08/sonataflowplatform_types.go | 9 +-
api/v1alpha08/zz_generated.deepcopy.go | 72 +++++++++++++
.../sonataflow.org_sonataflowplatforms.yaml | 74 ++++++++++++-
.../bases/sonataflow.org_sonataflowplatforms.yaml | 74 ++++++++++++-
controllers/cfg/controllers_cfg.go | 3 +
controllers/platform/services/properties.go | 8 +-
controllers/profiles/common/ensurer.go | 2 +-
controllers/profiles/common/mutate_visitors.go | 5 +-
controllers/profiles/common/object_creators.go | 3 +-
.../profiles/common/object_creators_test.go | 1 -
.../properties/{properties.go => knative.go} | 2 +-
.../properties/{application.go => managed.go} | 73 +++++++------
.../{application_test.go => managed_test.go} | 30 +++---
controllers/profiles/common/properties/platform.go | 87 +++++++++++++++
.../profiles/common/properties/platform_test.go | 119 +++++++++++++++++++++
.../profiles/common/properties/properties_test.go | 28 +++++
hack/local/run-operator.sh | 2 +
main.go | 6 +-
operator.yaml | 74 ++++++++++++-
...onataflow.org_v1alpha08_sonataflowplatform.yaml | 4 +
.../by_service/02-sonataflow_platform.yaml | 2 +-
.../02-sonataflow_platform.yaml | 2 +-
.../02-sonataflow_platform.yaml | 2 +-
.../02-sonataflow_platform.yaml | 2 +-
.../02-sonataflow_platform.yaml | 2 +-
utils/client.go | 32 ++++++
utils/properties.go | 18 ++--
29 files changed, 708 insertions(+), 83 deletions(-)
diff --git a/Makefile b/Makefile
index e704728c..ce87602d 100644
--- a/Makefile
+++ b/Makefile
@@ -158,7 +158,7 @@ run: manifests generate ## Run a controller from your host.
.PHONY: debug
debug: build-4-debug ## Run a controller from your host from binary
- ./bin/manager -v=2
+ ./bin/manager -v=2
-controller-cfg-path=$(CURDIR)/config/manager/controllers_cfg.yaml
# This is currently done directly into the CI
# PLATFORMS defines the target platforms for the manager image be build to
provide support to multiple
diff --git a/api/v1alpha08/sonataflowplatform_property_types.go
b/api/v1alpha08/sonataflowplatform_property_types.go
new file mode 100644
index 00000000..d138ac40
--- /dev/null
+++ b/api/v1alpha08/sonataflowplatform_property_types.go
@@ -0,0 +1,53 @@
+// 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 v1alpha08
+
+import v1 "k8s.io/api/core/v1"
+
+// PropertyPlatformSpec defines the struct for global managed properties in
the SonataFlowPlatform.
+// These properties are ignored in the SonataFlowClusterPlatform since a
source of a property (PropertyVarSource) can only be local.
+type PropertyPlatformSpec struct {
+ // Properties that will be added to the SonataFlow managed configMaps
in the current context.
+ // +optional
+ // +patchMergeKey=name
+ // +patchStrategy=merge
+ Flow []PropertyVar `json:"flow,omitempty" patchStrategy:"merge"
patchMergeKey:"name"`
+}
+
+// PropertyVar is the entry for a property set derived from the Kubernetes API
EnvVar.
+// Note that the name doesn't have to match C_IDENTIFIER.
+type PropertyVar struct {
+ // The property name
+ Name string `json:"name"`
+
+ // Optional: no more than one of the following may be specified.
+
+ // Defaults to "".
+ // +optional
+ Value string `json:"value,omitempty"`
+ // Source for the property's value. Cannot be used if value is not
empty.
+ // +optional
+ ValueFrom *PropertyVarSource `json:"valueFrom,omitempty"`
+}
+
+// PropertyVarSource is the definition of a property source derived from the
Kubernetes API EnvVarSource.
+type PropertyVarSource struct {
+ // Selects a key of a ConfigMap.
+ // +optional
+ ConfigMapKeyRef *v1.ConfigMapKeySelector
`json:"configMapKeyRef,omitempty"`
+ // Selects a key of a secret in the flow's namespace
+ // +optional
+ SecretKeyRef *v1.SecretKeySelector `json:"secretKeyRef,omitempty"`
+}
diff --git a/api/v1alpha08/sonataflowplatform_types.go
b/api/v1alpha08/sonataflowplatform_types.go
index 9dfff7ce..26276fb8 100644
--- a/api/v1alpha08/sonataflowplatform_types.go
+++ b/api/v1alpha08/sonataflowplatform_types.go
@@ -48,10 +48,17 @@ type SonataFlowPlatformSpec struct {
//
+operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Services"
Services *ServicesPlatformSpec `json:"services,omitempty"`
// Persistence defines the platform persistence configuration. When
this field is set,
- // the configuration is used as the persistence for platform services
and sonataflow instances
+ // the configuration is used as the persistence for platform services
and SonataFlow instances
// that don't provide one of their own.
// +optional
Persistence *PlatformPersistenceOptionsSpec
`json:"persistence,omitempty"`
+ // Properties defines the property set for a given actor in the current
context.
+ // For example, the workflow managed properties. One can define here a
set of properties for SonataFlow deployments
+ // that will be reused across every workflow deployment.
+ //
+ // These properties MAY NOT be propagated to a
SonataFlowClusterPlatform since PropertyVarSource can only refer local context
sources.
+ // +optional
+ Properties *PropertyPlatformSpec `json:"properties,omitempty"`
}
// PlatformCluster is the kind of orchestration cluster the platform is
installed into
diff --git a/api/v1alpha08/zz_generated.deepcopy.go
b/api/v1alpha08/zz_generated.deepcopy.go
index b311b3a8..c970b108 100644
--- a/api/v1alpha08/zz_generated.deepcopy.go
+++ b/api/v1alpha08/zz_generated.deepcopy.go
@@ -662,6 +662,73 @@ func (in *PostgreSQLServiceOptions) DeepCopy()
*PostgreSQLServiceOptions {
return out
}
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver,
writing into out. in must be non-nil.
+func (in *PropertyPlatformSpec) DeepCopyInto(out *PropertyPlatformSpec) {
+ *out = *in
+ if in.Flow != nil {
+ in, out := &in.Flow, &out.Flow
+ *out = make([]PropertyVar, len(*in))
+ for i := range *in {
+ (*in)[i].DeepCopyInto(&(*out)[i])
+ }
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver,
creating a new PropertyPlatformSpec.
+func (in *PropertyPlatformSpec) DeepCopy() *PropertyPlatformSpec {
+ if in == nil {
+ return nil
+ }
+ out := new(PropertyPlatformSpec)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver,
writing into out. in must be non-nil.
+func (in *PropertyVar) DeepCopyInto(out *PropertyVar) {
+ *out = *in
+ if in.ValueFrom != nil {
+ in, out := &in.ValueFrom, &out.ValueFrom
+ *out = new(PropertyVarSource)
+ (*in).DeepCopyInto(*out)
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver,
creating a new PropertyVar.
+func (in *PropertyVar) DeepCopy() *PropertyVar {
+ if in == nil {
+ return nil
+ }
+ out := new(PropertyVar)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver,
writing into out. in must be non-nil.
+func (in *PropertyVarSource) DeepCopyInto(out *PropertyVarSource) {
+ *out = *in
+ if in.ConfigMapKeyRef != nil {
+ in, out := &in.ConfigMapKeyRef, &out.ConfigMapKeyRef
+ *out = new(v1.ConfigMapKeySelector)
+ (*in).DeepCopyInto(*out)
+ }
+ if in.SecretKeyRef != nil {
+ in, out := &in.SecretKeyRef, &out.SecretKeyRef
+ *out = new(v1.SecretKeySelector)
+ (*in).DeepCopyInto(*out)
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver,
creating a new PropertyVarSource.
+func (in *PropertyVarSource) DeepCopy() *PropertyVarSource {
+ if in == nil {
+ return nil
+ }
+ out := new(PropertyVarSource)
+ in.DeepCopyInto(out)
+ return out
+}
+
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver,
writing into out. in must be non-nil.
func (in *RegistrySpec) DeepCopyInto(out *RegistrySpec) {
*out = *in
@@ -1124,6 +1191,11 @@ func (in *SonataFlowPlatformSpec) DeepCopyInto(out
*SonataFlowPlatformSpec) {
*out = new(PlatformPersistenceOptionsSpec)
(*in).DeepCopyInto(*out)
}
+ if in.Properties != nil {
+ in, out := &in.Properties, &out.Properties
+ *out = new(PropertyPlatformSpec)
+ (*in).DeepCopyInto(*out)
+ }
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver,
creating a new SonataFlowPlatformSpec.
diff --git a/bundle/manifests/sonataflow.org_sonataflowplatforms.yaml
b/bundle/manifests/sonataflow.org_sonataflowplatforms.yaml
index 29791ec8..09a2f254 100644
--- a/bundle/manifests/sonataflow.org_sonataflowplatforms.yaml
+++ b/bundle/manifests/sonataflow.org_sonataflowplatforms.yaml
@@ -423,7 +423,7 @@ spec:
persistence:
description: Persistence defines the platform persistence
configuration.
When this field is set, the configuration is used as the
persistence
- for platform services and sonataflow instances that don't
provide
+ for platform services and SonataFlow instances that don't
provide
one of their own.
maxProperties: 1
properties:
@@ -477,6 +477,78 @@ spec:
- secretRef
type: object
type: object
+ properties:
+ description: "Properties defines the property set for a given
actor
+ in the current context. For example, the workflow managed
properties.
+ One can define here a set of properties for SonataFlow
deployments
+ that will be reused across every workflow deployment. \n
These properties
+ MAY NOT be propagated to a SonataFlowClusterPlatform since
PropertyVarSource
+ can only refer local context sources."
+ properties:
+ flow:
+ description: Properties that will be added to the
SonataFlow managed
+ configMaps in the current context.
+ items:
+ description: PropertyVar is the entry for a property set
derived
+ from the Kubernetes API EnvVar. Note that the name
doesn't
+ have to match C_IDENTIFIER.
+ properties:
+ name:
+ description: The property name
+ type: string
+ value:
+ description: Defaults to "".
+ type: string
+ valueFrom:
+ description: Source for the property's value. Cannot
be
+ used if value is not empty.
+ properties:
+ configMapKeyRef:
+ description: Selects a key of a ConfigMap.
+ properties:
+ key:
+ description: The key to select.
+ type: string
+ name:
+ description: 'Name of the referent. More
info:
https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap
or its
+ key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ secretKeyRef:
+ description: Selects a key of a secret in the
flow's
+ namespace
+ properties:
+ key:
+ description: The key of the secret to select
from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More
info:
https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or
its key
+ must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ required:
+ - name
+ type: object
+ type: array
+ type: object
services:
description: 'Services attributes for deploying supporting
applications
like Data Index & Job Service. Only workflows without the
`sonataflow.org/profile:
diff --git a/config/crd/bases/sonataflow.org_sonataflowplatforms.yaml
b/config/crd/bases/sonataflow.org_sonataflowplatforms.yaml
index 8d433833..648b1bcd 100644
--- a/config/crd/bases/sonataflow.org_sonataflowplatforms.yaml
+++ b/config/crd/bases/sonataflow.org_sonataflowplatforms.yaml
@@ -424,7 +424,7 @@ spec:
persistence:
description: Persistence defines the platform persistence
configuration.
When this field is set, the configuration is used as the
persistence
- for platform services and sonataflow instances that don't
provide
+ for platform services and SonataFlow instances that don't
provide
one of their own.
maxProperties: 1
properties:
@@ -478,6 +478,78 @@ spec:
- secretRef
type: object
type: object
+ properties:
+ description: "Properties defines the property set for a given
actor
+ in the current context. For example, the workflow managed
properties.
+ One can define here a set of properties for SonataFlow
deployments
+ that will be reused across every workflow deployment. \n
These properties
+ MAY NOT be propagated to a SonataFlowClusterPlatform since
PropertyVarSource
+ can only refer local context sources."
+ properties:
+ flow:
+ description: Properties that will be added to the
SonataFlow managed
+ configMaps in the current context.
+ items:
+ description: PropertyVar is the entry for a property set
derived
+ from the Kubernetes API EnvVar. Note that the name
doesn't
+ have to match C_IDENTIFIER.
+ properties:
+ name:
+ description: The property name
+ type: string
+ value:
+ description: Defaults to "".
+ type: string
+ valueFrom:
+ description: Source for the property's value. Cannot
be
+ used if value is not empty.
+ properties:
+ configMapKeyRef:
+ description: Selects a key of a ConfigMap.
+ properties:
+ key:
+ description: The key to select.
+ type: string
+ name:
+ description: 'Name of the referent. More
info:
https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap
or its
+ key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ secretKeyRef:
+ description: Selects a key of a secret in the
flow's
+ namespace
+ properties:
+ key:
+ description: The key of the secret to select
from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More
info:
https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or
its key
+ must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ required:
+ - name
+ type: object
+ type: array
+ type: object
services:
description: 'Services attributes for deploying supporting
applications
like Data Index & Job Service. Only workflows without the
`sonataflow.org/profile:
diff --git a/controllers/cfg/controllers_cfg.go
b/controllers/cfg/controllers_cfg.go
index 05e409cf..4f299092 100644
--- a/controllers/cfg/controllers_cfg.go
+++ b/controllers/cfg/controllers_cfg.go
@@ -65,6 +65,9 @@ func InitializeControllersCfg() (*ControllersCfg, error) {
// InitializeControllersCfgAt same as InitializeControllersCfg receiving a
path as input.
func InitializeControllersCfgAt(configFilePath string) (*ControllersCfg,
error) {
+ if len(configFilePath) == 0 {
+ configFilePath = defaultConfigMountPath
+ }
controllersCfg = nil
yamlFile, err := os.ReadFile(configFilePath)
if err != nil {
diff --git a/controllers/platform/services/properties.go
b/controllers/platform/services/properties.go
index 1d9e784e..c1deedcb 100644
--- a/controllers/platform/services/properties.go
+++ b/controllers/platform/services/properties.go
@@ -49,7 +49,7 @@ var (
type serviceAppPropertyHandler struct {
userProperties string
serviceHandler PlatformServiceHandler
- defaultMutableProperties *properties.Properties
+ defaultManagedProperties *properties.Properties
}
type ServiceAppPropertyHandler interface {
@@ -59,14 +59,14 @@ type ServiceAppPropertyHandler interface {
// NewServiceAppPropertyHandler creates the default service configurations
property handler
// The set of properties is initialized with the operator provided immutable
properties.
-// The set of defaultMutableProperties is initialized with the operator
provided properties that the user might override.
+// The set of defaultManagedProperties is initialized with the operator
provided properties that the user might override.
func NewServiceAppPropertyHandler(serviceHandler PlatformServiceHandler)
(ServiceAppPropertyHandler, error) {
handler := &serviceAppPropertyHandler{}
props, err := serviceHandler.GenerateServiceProperties()
if err != nil {
return nil, err
}
- handler.defaultMutableProperties = props
+ handler.defaultManagedProperties = props
return handler, nil
}
@@ -90,7 +90,7 @@ func (a *serviceAppPropertyHandler) Build() string {
props = utils.NewApplicationPropertiesBuilder().
WithInitialProperties(props).
WithImmutableProperties(properties.MustLoadString(immutableApplicationProperties)).
- WithDefaultMutableProperties(a.defaultMutableProperties).
+ WithDefaultManagedProperties(a.defaultManagedProperties).
Build()
props.Sort()
return props.String()
diff --git a/controllers/profiles/common/ensurer.go
b/controllers/profiles/common/ensurer.go
index a1b8c92c..ad4558d2 100644
--- a/controllers/profiles/common/ensurer.go
+++ b/controllers/profiles/common/ensurer.go
@@ -60,7 +60,7 @@ func NewObjectEnsurer(client client.Client, creator
ObjectCreator) ObjectEnsurer
}
}
-// NewObjectEnsurerWithPlatform see defaultObjectEnsurerWithPLatform
+// NewObjectEnsurerWithPlatform see defaultObjectEnsurerWithPlatform
func NewObjectEnsurerWithPlatform(client client.Client, creator
ObjectCreatorWithPlatform) ObjectEnsurerWithPlatform {
return &defaultObjectEnsurerWithPlatform{
c: client,
diff --git a/controllers/profiles/common/mutate_visitors.go
b/controllers/profiles/common/mutate_visitors.go
index 6b70bc0f..eab1944b 100644
--- a/controllers/profiles/common/mutate_visitors.go
+++ b/controllers/profiles/common/mutate_visitors.go
@@ -120,12 +120,11 @@ func ManagedPropertiesMutateVisitor(ctx context.Context,
catalog discovery.Servi
if !hasKey {
userProperties = ""
}
- // In the future, if this needs change, instead we can
receive an AppPropertyHandler in this mutator
- props, err :=
properties.NewAppPropertyHandler(workflow, plf)
+ propertyHandler, err :=
properties.NewManagedPropertyHandler(workflow, plf)
if err != nil {
return err
}
-
managedProps.Data[workflowproj.GetManagedPropertiesFileName(workflow)] =
props.WithUserProperties(userProperties).
+
managedProps.Data[workflowproj.GetManagedPropertiesFileName(workflow)] =
propertyHandler.WithUserProperties(userProperties).
WithServiceDiscovery(ctx, catalog).
Build()
return nil
diff --git a/controllers/profiles/common/object_creators.go
b/controllers/profiles/common/object_creators.go
index 61ea65db..8da5956d 100644
--- a/controllers/profiles/common/object_creators.go
+++ b/controllers/profiles/common/object_creators.go
@@ -69,7 +69,6 @@ const (
healthStartedFailureThreshold = 5
healthStartedPeriodSeconds = 15
healthStartedInitialDelaySeconds = 10
- defaultSchemaName = "default"
)
// DeploymentCreator is an objectCreator for a base Kubernetes Deployments for
profiles that need to deploy the workflow on a vanilla deployment.
@@ -307,7 +306,7 @@ func UserPropsConfigMapCreator(workflow
*operatorapi.SonataFlow) (client.Object,
// 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)
+ props, err := properties.ApplicationManagedProperties(workflow,
platform)
if err != nil {
return nil, err
}
diff --git a/controllers/profiles/common/object_creators_test.go
b/controllers/profiles/common/object_creators_test.go
index 7a35bd48..26b54999 100644
--- a/controllers/profiles/common/object_creators_test.go
+++ b/controllers/profiles/common/object_creators_test.go
@@ -90,7 +90,6 @@ func
Test_ensureWorkflowPropertiesConfigMapMutator_DollarReplacement(t *testing.
err := mutateVisitorFn(managedPropsCM)()
assert.NoError(t, err)
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/properties.go
b/controllers/profiles/common/properties/knative.go
similarity index 96%
rename from controllers/profiles/common/properties/properties.go
rename to controllers/profiles/common/properties/knative.go
index ec4c3b09..195dd21f 100644
--- a/controllers/profiles/common/properties/properties.go
+++ b/controllers/profiles/common/properties/knative.go
@@ -22,7 +22,7 @@ import (
cncfmodel "github.com/serverlessworkflow/sdk-go/v2/model"
)
-// GenerateKnativeEventingWorkflowProperties returns the set of application
properties required for the workflow to produce or consume
+// generateKnativeEventingWorkflowProperties returns the set of application
properties required for the workflow to produce or consume
// Knative Events.
// Never nil.
func generateKnativeEventingWorkflowProperties(workflow
*operatorapi.SonataFlow) (*properties.Properties, error) {
diff --git a/controllers/profiles/common/properties/application.go
b/controllers/profiles/common/properties/managed.go
similarity index 70%
rename from controllers/profiles/common/properties/application.go
rename to controllers/profiles/common/properties/managed.go
index 9b592608..a9da9edf 100644
--- a/controllers/profiles/common/properties/application.go
+++ b/controllers/profiles/common/properties/managed.go
@@ -42,36 +42,36 @@ var (
"quarkus.http.host=0.0.0.0\n"+
"quarkus.devservices.enabled=false\n"+
"quarkus.kogito.devservices.enabled=false\n",
constants.DefaultHTTPWorkflowPortInt)
- _ AppPropertyHandler = &appPropertyHandler{}
+ _ ManagedPropertyHandler = &managedPropertyHandler{}
)
-type AppPropertyHandler interface {
- WithUserProperties(userProperties string) AppPropertyHandler
- WithServiceDiscovery(ctx context.Context, catalog
discovery.ServiceCatalog) AppPropertyHandler
+type ManagedPropertyHandler interface {
+ WithUserProperties(userProperties string) ManagedPropertyHandler
+ WithServiceDiscovery(ctx context.Context, catalog
discovery.ServiceCatalog) ManagedPropertyHandler
Build() string
}
-type appPropertyHandler struct {
+type managedPropertyHandler struct {
workflow *operatorapi.SonataFlow
platform *operatorapi.SonataFlowPlatform
catalog discovery.ServiceCatalog
ctx context.Context
userProperties string
- defaultMutableProperties *properties.Properties
+ defaultManagedProperties *properties.Properties
}
-func (a *appPropertyHandler) WithUserProperties(properties string)
AppPropertyHandler {
+func (a *managedPropertyHandler) WithUserProperties(properties string)
ManagedPropertyHandler {
a.userProperties = properties
return a
}
-func (a *appPropertyHandler) WithServiceDiscovery(ctx context.Context, catalog
discovery.ServiceCatalog) AppPropertyHandler {
+func (a *managedPropertyHandler) WithServiceDiscovery(ctx context.Context,
catalog discovery.ServiceCatalog) ManagedPropertyHandler {
a.ctx = ctx
a.catalog = catalog
return a
}
-func (a *appPropertyHandler) Build() string {
+func (a *managedPropertyHandler) Build() string {
var userProps *properties.Properties
var propErr error = nil
if len(a.userProperties) == 0 {
@@ -87,6 +87,7 @@ func (a *appPropertyHandler) Build() string {
// Property expansion means resolving ${} within the properties and
environment context. Quarkus will do that in runtime.
userProps.DisableExpansion = true
+ // Update discovery properties
removeDiscoveryProperties(userProps)
discoveryProps := properties.NewProperties()
if a.requireServiceDiscovery() {
@@ -96,7 +97,7 @@ func (a *appPropertyHandler) Build() string {
userProps = utils.NewApplicationPropertiesBuilder().
WithInitialProperties(discoveryProps).
WithImmutableProperties(properties.MustLoadString(immutableApplicationProperties)).
- WithDefaultMutableProperties(a.defaultMutableProperties).
+ WithDefaultManagedProperties(a.defaultManagedProperties).
Build()
return userProps.String()
@@ -104,81 +105,87 @@ func (a *appPropertyHandler) Build() string {
// withKogitoServiceUrl adds the property kogitoServiceUrlProperty to the
application properties.
// See Service Discovery
https://kubernetes.io/docs/concepts/services-networking/service/#dns
-func (a *appPropertyHandler) withKogitoServiceUrl() AppPropertyHandler {
+func (a *managedPropertyHandler) withKogitoServiceUrl() ManagedPropertyHandler
{
var kogitoServiceUrl string
if len(a.workflow.Namespace) > 0 {
kogitoServiceUrl = fmt.Sprintf("%s://%s.%s",
constants.KogitoServiceURLProtocol, a.workflow.Name, a.workflow.Namespace)
} else {
kogitoServiceUrl = fmt.Sprintf("%s://%s",
constants.KogitoServiceURLProtocol, a.workflow.Name)
}
- return a.addDefaultMutableProperty(constants.KogitoServiceURLProperty,
kogitoServiceUrl)
+ return a.addDefaultManagedProperty(constants.KogitoServiceURLProperty,
kogitoServiceUrl)
}
// withKafkaHealthCheckDisabled adds the property kafkaSmallRyeHealthProperty
to the application properties.
// See Service Discovery
https://kubernetes.io/docs/concepts/services-networking/service/#dns
-func (a *appPropertyHandler) withKafkaHealthCheckDisabled() AppPropertyHandler
{
- a.addDefaultMutableProperty(
+func (a *managedPropertyHandler) withKafkaHealthCheckDisabled()
ManagedPropertyHandler {
+ a.addDefaultManagedProperty(
constants.DataIndexKafkaSmallRyeHealthProperty,
"false",
)
return a
}
-func (a *appPropertyHandler) addDefaultMutableProperty(name string, value
string) AppPropertyHandler {
- a.defaultMutableProperties.Set(name, value)
+func (a *managedPropertyHandler) addDefaultManagedProperty(name string, value
string) ManagedPropertyHandler {
+ a.defaultManagedProperties.Set(name, value)
return a
}
-// NewAppPropertyHandler creates a property handler for a given workflow to
execute in the provided platform.
+// NewManagedPropertyHandler creates a property handler for a given workflow
to execute in the provided 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.
+// Note that the produced properties might vary depending on the platform, for
example, if the job service managed by the platform
+// have 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 cannot overwrite even if it changes
+// The set of defaultManagedProperties 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{
+func NewManagedPropertyHandler(workflow *operatorapi.SonataFlow, platform
*operatorapi.SonataFlowPlatform) (ManagedPropertyHandler, error) {
+ handler := &managedPropertyHandler{
workflow: workflow,
platform: platform,
}
props := properties.NewProperties()
props.Set(constants.KogitoUserTasksEventsEnabled, "false")
if platform != nil {
- p, err :=
services.GenerateDataIndexWorkflowProperties(workflow, platform)
+ p, err := resolvePlatformWorkflowProperties(platform)
if err != nil {
return nil, err
}
props.Merge(p)
- p, err =
services.GenerateJobServiceWorkflowProperties(workflow, platform)
+ p, err = services.GenerateDataIndexWorkflowProperties(workflow,
platform)
if err != nil {
return nil, err
}
props.Merge(p)
- p, err = generateKnativeEventingWorkflowProperties(workflow)
+ p, err =
services.GenerateJobServiceWorkflowProperties(workflow, platform)
if err != nil {
return nil, err
}
props.Merge(p)
- props.Sort()
}
- handler.defaultMutableProperties = props
+
+ p, err := generateKnativeEventingWorkflowProperties(workflow)
+ if err != nil {
+ return nil, err
+ }
+ props.Merge(p)
+ props.Sort()
+
+ handler.defaultManagedProperties = props
return handler.withKogitoServiceUrl(), nil
}
-// ImmutableApplicationProperties immutable default application properties
that can be used with any workflow based on Quarkus.
-// Alias for NewAppPropertyHandler(workflow).Build()
-func ImmutableApplicationProperties(workflow *operatorapi.SonataFlow, platform
*operatorapi.SonataFlowPlatform) (string, error) {
- p, err := NewAppPropertyHandler(workflow, platform)
+// ApplicationManagedProperties immutable default application properties that
can be used with any workflow based on Quarkus.
+// Alias for NewManagedPropertyHandler(workflow).Build()
+func ApplicationManagedProperties(workflow *operatorapi.SonataFlow, platform
*operatorapi.SonataFlowPlatform) (string, error) {
+ p, err := NewManagedPropertyHandler(workflow, platform)
if err != nil {
return "", err
}
return p.Build(), nil
-
}
-func (a *appPropertyHandler) requireServiceDiscovery() bool {
+func (a *managedPropertyHandler) requireServiceDiscovery() bool {
return a.ctx != nil && a.catalog != nil
}
diff --git a/controllers/profiles/common/properties/application_test.go
b/controllers/profiles/common/properties/managed_test.go
similarity index 97%
rename from controllers/profiles/common/properties/application_test.go
rename to controllers/profiles/common/properties/managed_test.go
index 93700baf..d27d69e1 100644
--- a/controllers/profiles/common/properties/application_test.go
+++ b/controllers/profiles/common/properties/managed_test.go
@@ -111,7 +111,7 @@ func (c *mockCatalogService) Query(ctx context.Context, uri
discovery.ResourceUr
func Test_appPropertyHandler_WithKogitoServiceUrl(t *testing.T) {
workflow := test.GetBaseSonataFlow("default")
- props, err := ImmutableApplicationProperties(workflow, nil)
+ props, err := ApplicationManagedProperties(workflow, nil)
assert.NoError(t, err)
assert.Contains(t, props, constants.KogitoServiceURLProperty)
assert.Contains(t, props,
"http://"+workflow.Name+"."+workflow.Namespace)
@@ -121,11 +121,11 @@ func
Test_appPropertyHandler_WithUserPropertiesWithNoUserOverrides(t *testing.T)
//just add some user provided properties, no overrides.
userProperties := "property1=value1\nproperty2=value2"
workflow := test.GetBaseSonataFlow("default")
- props, err := NewAppPropertyHandler(workflow, nil)
+ props, err := NewManagedPropertyHandler(workflow, nil)
assert.NoError(t, err)
generatedProps, propsErr :=
properties.LoadString(props.WithUserProperties(userProperties).Build())
assert.NoError(t, propsErr)
- assert.Equal(t, 6, len(generatedProps.Keys()))
+ 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", ""))
@@ -149,7 +149,7 @@ func
Test_appPropertyHandler_WithUserPropertiesWithServiceDiscovery(t *testing.T
userProperties = userProperties +
"broker2=${knative:brokers.v1.eventing.knative.dev/my-kn-broker2}\n"
workflow := test.GetBaseSonataFlow(defaultNamespace)
- props, err := NewAppPropertyHandler(workflow, nil)
+ props, err := NewManagedPropertyHandler(workflow, nil)
assert.NoError(t, err)
generatedProps, propsErr := properties.LoadString(props.
WithUserProperties(userProperties).
@@ -157,7 +157,7 @@ func
Test_appPropertyHandler_WithUserPropertiesWithServiceDiscovery(t *testing.T
Build())
generatedProps.DisableExpansion = true
assert.NoError(t, propsErr)
- assert.Equal(t, 20, len(generatedProps.Keys()))
+ assert.Equal(t, 21, len(generatedProps.Keys()))
assert.NotContains(t, "property1", generatedProps.Keys())
assert.NotContains(t, "property2", generatedProps.Keys())
assertHasProperty(t, generatedProps, "service1", myService1Address)
@@ -186,12 +186,6 @@ func
Test_appPropertyHandler_WithUserPropertiesWithServiceDiscovery(t *testing.T
assertHasProperty(t, generatedProps,
constants.KogitoUserTasksEventsEnabled, "false")
}
-func assertHasProperty(t *testing.T, props *properties.Properties,
expectedProperty string, expectedValue string) {
- value, ok := props.Get(expectedProperty)
- assert.True(t, ok, "Property %s, is not present as expected.",
expectedProperty)
- assert.Equal(t, expectedValue, value, "Expected value for property: %s,
is: %s but current value is: %s", expectedProperty, expectedValue, value)
-}
-
func Test_appPropertyHandler_WithServicesWithUserOverrides(t *testing.T) {
//try to override kogito.service.url and quarkus.http.port
userProperties :=
"property1=value1\nproperty2=value2\nquarkus.http.port=9090\nkogito.service.url=http://myUrl.override.com\nquarkus.http.port=9090"
@@ -214,7 +208,7 @@ func
Test_appPropertyHandler_WithServicesWithUserOverrides(t *testing.T) {
services.SetServiceUrlsInWorkflowStatus(platform, workflow)
assert.Nil(t, workflow.Status.Services)
- props, err := NewAppPropertyHandler(workflow, platform)
+ props, err := NewManagedPropertyHandler(workflow, platform)
assert.NoError(t, err)
generatedProps, propsErr :=
properties.LoadString(props.WithUserProperties(userProperties).Build())
assert.NoError(t, propsErr)
@@ -243,7 +237,7 @@ func
Test_appPropertyHandler_WithServicesWithUserOverrides(t *testing.T) {
assert.NotNil(t, workflow.Status.Services)
assert.NotNil(t, workflow.Status.Services.JobServiceRef)
assert.NotNil(t, workflow.Status.Services.DataIndexRef)
- props, err = NewAppPropertyHandler(workflow, platform)
+ props, err = NewManagedPropertyHandler(workflow, platform)
assert.NoError(t, err)
generatedProps, propsErr =
properties.LoadString(props.WithUserProperties(userProperties).Build())
assert.NoError(t, propsErr)
@@ -270,7 +264,7 @@ func
Test_appPropertyHandler_WithServicesWithUserOverrides(t *testing.T) {
assert.NotNil(t, workflow.Status.Services)
assert.NotNil(t, workflow.Status.Services.JobServiceRef)
assert.Nil(t, workflow.Status.Services.DataIndexRef)
- props, err = NewAppPropertyHandler(workflow, platform)
+ props, err = NewManagedPropertyHandler(workflow, platform)
assert.NoError(t, err)
generatedProps, propsErr =
properties.LoadString(props.WithUserProperties(userProperties).Build())
assert.NoError(t, propsErr)
@@ -290,7 +284,7 @@ func
Test_appPropertyHandler_WithServicesWithUserOverrides(t *testing.T) {
platform.Spec.Services.JobService.Enabled = nil
services.SetServiceUrlsInWorkflowStatus(platform, workflow)
assert.Nil(t, workflow.Status.Services)
- props, err = NewAppPropertyHandler(workflow, platform)
+ props, err = NewManagedPropertyHandler(workflow, platform)
assert.NoError(t, err)
generatedProps, propsErr =
properties.LoadString(props.WithUserProperties(userProperties).Build())
assert.NoError(t, propsErr)
@@ -317,7 +311,7 @@ var _ = Describe("Platform properties", func() {
DescribeTable("only job services when the spec",
func(wf *operatorapi.SonataFlow, plfm
*operatorapi.SonataFlowPlatform, expectedProperties *properties.Properties) {
services.SetServiceUrlsInWorkflowStatus(plfm, wf)
- handler, err :=
NewAppPropertyHandler(wf, plfm)
+ handler, err :=
NewManagedPropertyHandler(wf, plfm)
Expect(err).NotTo(HaveOccurred())
p, err :=
properties.LoadString(handler.Build())
Expect(err).NotTo(HaveOccurred())
@@ -365,7 +359,7 @@ var _ = Describe("Platform properties", func() {
DescribeTable("only data index service when the spec",
func(wf *operatorapi.SonataFlow, plfm
*operatorapi.SonataFlowPlatform, expectedProperties *properties.Properties) {
services.SetServiceUrlsInWorkflowStatus(plfm, wf)
- handler, err :=
NewAppPropertyHandler(wf, plfm)
+ handler, err :=
NewManagedPropertyHandler(wf, plfm)
Expect(err).NotTo(HaveOccurred())
p, err :=
properties.LoadString(handler.Build())
Expect(err).NotTo(HaveOccurred())
@@ -412,7 +406,7 @@ var _ = Describe("Platform properties", func() {
DescribeTable("both Data Index and Job Services are
available and", func(wf *operatorapi.SonataFlow, plfm
*operatorapi.SonataFlowPlatform, expectedProperties *properties.Properties) {
services.SetServiceUrlsInWorkflowStatus(plfm,
wf)
- handler, err := NewAppPropertyHandler(wf, plfm)
+ handler, err := NewManagedPropertyHandler(wf,
plfm)
Expect(err).NotTo(HaveOccurred())
p, err := properties.LoadString(handler.Build())
Expect(err).NotTo(HaveOccurred())
diff --git a/controllers/profiles/common/properties/platform.go
b/controllers/profiles/common/properties/platform.go
new file mode 100644
index 00000000..2b5704f4
--- /dev/null
+++ b/controllers/profiles/common/properties/platform.go
@@ -0,0 +1,87 @@
+// 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 properties
+
+import (
+ "context"
+
+ 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/utils"
+ "github.com/magiconair/properties"
+ v1 "k8s.io/api/core/v1"
+ "k8s.io/apimachinery/pkg/api/errors"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/types"
+ "k8s.io/klog/v2"
+)
+
+func resolvePlatformWorkflowProperties(platform
*operatorapi.SonataFlowPlatform) (*properties.Properties, error) {
+ props := properties.NewProperties()
+
+ if platform.Spec.Properties == nil {
+ return props, nil
+ }
+
+ for _, propVar := range platform.Spec.Properties.Flow {
+ if len(propVar.Value) > 0 {
+ props.Set(propVar.Name, propVar.Value)
+ } else if propVar.ValueFrom != nil {
+ val, err := getPropVarRefValue(propVar.ValueFrom,
platform.Namespace)
+ if err != nil {
+ return nil, err
+ }
+ props.Set(propVar.Name, val)
+ }
+ }
+
+ return props, nil
+}
+
+func getPropVarRefValue(from *operatorapi.PropertyVarSource, namespace string)
(string, error) {
+ // same order as k8s api (we try to fetch first a secret)
+ if from.SecretKeyRef != nil {
+ secret := &v1.Secret{
+ ObjectMeta: metav1.ObjectMeta{Namespace: namespace,
Name: from.SecretKeyRef.Name},
+ }
+ err := utils.GetClient().Get(context.TODO(),
types.NamespacedName{Namespace: secret.Namespace, Name: secret.Name}, secret)
+ if err != nil && !errors.IsNotFound(err) {
+ return "", err
+ }
+ if data, ok := secret.Data[from.SecretKeyRef.Key]; ok {
+ return string(data), nil
+ }
+ if from.SecretKeyRef.Optional == utils.Pbool(false) {
+ klog.V(log.D).InfoS("Key not found in secret", "Key",
from.SecretKeyRef.Key)
+ }
+ }
+ if from.ConfigMapKeyRef != nil {
+ cm := &v1.ConfigMap{
+ ObjectMeta: metav1.ObjectMeta{Namespace: namespace,
Name: from.ConfigMapKeyRef.Name},
+ }
+ err := utils.GetClient().Get(context.TODO(),
types.NamespacedName{Namespace: cm.Namespace, Name: cm.Name}, cm)
+ if err != nil && !errors.IsNotFound(err) {
+ return "", err
+ }
+ if data, ok := cm.Data[from.ConfigMapKeyRef.Key]; ok {
+ return data, nil
+ }
+ if from.ConfigMapKeyRef.Optional == utils.Pbool(false) {
+ klog.V(log.D).InfoS("Key not found in configMap",
"Key", from.ConfigMapKeyRef.Key)
+ }
+ }
+
+ return "", nil
+}
diff --git a/controllers/profiles/common/properties/platform_test.go
b/controllers/profiles/common/properties/platform_test.go
new file mode 100644
index 00000000..52363661
--- /dev/null
+++ b/controllers/profiles/common/properties/platform_test.go
@@ -0,0 +1,119 @@
+// 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 properties
+
+import (
+ "testing"
+
+
"github.com/apache/incubator-kie-kogito-serverless-operator/api/v1alpha08"
+ "github.com/apache/incubator-kie-kogito-serverless-operator/test"
+ "github.com/apache/incubator-kie-kogito-serverless-operator/utils"
+ "github.com/stretchr/testify/assert"
+ v1 "k8s.io/api/core/v1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+func Test_resolvePlatformWorkflowProperties(t *testing.T) {
+ secret := &v1.Secret{
+ ObjectMeta: metav1.ObjectMeta{Name: "secretPlatformTest",
Namespace: t.Name()},
+ Data: map[string][]byte{"my-key": []byte("secret")},
+ }
+ cm := &v1.ConfigMap{
+ ObjectMeta: metav1.ObjectMeta{Name: "configMapPlatformTest",
Namespace: t.Name()},
+ Data: map[string]string{"my-key": "value"},
+ }
+
+ platform := test.GetBasePlatform()
+ platform.Namespace = t.Name()
+ platform.Spec.Properties = &v1alpha08.PropertyPlatformSpec{
+ Flow: []v1alpha08.PropertyVar{
+ {
+ Name: "quarkus.log.category",
+ Value: "DEBUG",
+ },
+ {
+ Name: "quarkus.custom.property",
+ ValueFrom: &v1alpha08.PropertyVarSource{
+ ConfigMapKeyRef:
&v1.ConfigMapKeySelector{
+ Key: "my-key",
+ LocalObjectReference:
v1.LocalObjectReference{Name: "configMapPlatformTest"},
+ },
+ },
+ },
+ {
+ Name: "quarkus.custom.secret",
+ ValueFrom: &v1alpha08.PropertyVarSource{
+ SecretKeyRef: &v1.SecretKeySelector{
+ Key: "my-key",
+ LocalObjectReference:
v1.LocalObjectReference{Name: "secretPlatformTest"},
+ },
+ },
+ },
+ },
+ }
+
+ client :=
test.NewSonataFlowClientBuilder().WithRuntimeObjects(platform, secret,
cm).WithStatusSubresource(platform).Build()
+ utils.SetClient(client)
+
+ props, err := resolvePlatformWorkflowProperties(platform)
+ assert.NoError(t, err)
+ assert.NotNil(t, props)
+
+ assertHasProperty(t, props, "quarkus.log.category", "DEBUG")
+ assertHasProperty(t, props, "quarkus.custom.property", "value")
+ assertHasProperty(t, props, "quarkus.custom.secret", "secret")
+}
+
+func Test_resolvePlatformWorkflowProperties_RefNotFound(t *testing.T) {
+ platform := test.GetBasePlatform()
+ platform.Namespace = t.Name()
+ platform.Spec.Properties = &v1alpha08.PropertyPlatformSpec{
+ Flow: []v1alpha08.PropertyVar{
+ {
+ Name: "quarkus.log.category",
+ Value: "DEBUG",
+ },
+ {
+ Name: "quarkus.custom.property",
+ ValueFrom: &v1alpha08.PropertyVarSource{
+ ConfigMapKeyRef:
&v1.ConfigMapKeySelector{
+ Key: "my-key",
+ LocalObjectReference:
v1.LocalObjectReference{Name: "configMapPlatformTest"},
+ },
+ },
+ },
+ {
+ Name: "quarkus.custom.secret",
+ ValueFrom: &v1alpha08.PropertyVarSource{
+ SecretKeyRef: &v1.SecretKeySelector{
+ Key: "my-key",
+ LocalObjectReference:
v1.LocalObjectReference{Name: "secretPlatformTest"},
+ },
+ },
+ },
+ },
+ }
+
+ client :=
test.NewSonataFlowClientBuilder().WithRuntimeObjects(platform).WithStatusSubresource(platform).Build()
+ utils.SetClient(client)
+
+ props, err := resolvePlatformWorkflowProperties(platform)
+ assert.NoError(t, err)
+ assert.NotNil(t, props)
+
+ assertHasProperty(t, props, "quarkus.log.category", "DEBUG")
+ assertHasProperty(t, props, "quarkus.custom.property", "")
+ assertHasProperty(t, props, "quarkus.custom.secret", "")
+}
diff --git a/controllers/profiles/common/properties/properties_test.go
b/controllers/profiles/common/properties/properties_test.go
new file mode 100644
index 00000000..81c91ef8
--- /dev/null
+++ b/controllers/profiles/common/properties/properties_test.go
@@ -0,0 +1,28 @@
+// 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 properties
+
+import (
+ "testing"
+
+ "github.com/magiconair/properties"
+ "github.com/stretchr/testify/assert"
+)
+
+func assertHasProperty(t *testing.T, props *properties.Properties,
expectedProperty string, expectedValue string) {
+ value, ok := props.Get(expectedProperty)
+ assert.True(t, ok, "Property %s, is not present as expected.",
expectedProperty)
+ assert.Equal(t, expectedValue, value, "Expected value for property: %s,
is: %s but current value is: %s", expectedProperty, expectedValue, value)
+}
diff --git a/hack/local/run-operator.sh b/hack/local/run-operator.sh
index 628bee27..5cb8a73c 100755
--- a/hack/local/run-operator.sh
+++ b/hack/local/run-operator.sh
@@ -18,11 +18,13 @@
# Runs the operator locally via go main
+kubectl delete --ignore-not-found=true -f
./bundle/manifests/sonataflow.org_sonataflowclusterplatforms.yaml
kubectl delete --ignore-not-found=true -f
./bundle/manifests/sonataflow.org_sonataflowplatforms.yaml
kubectl delete --ignore-not-found=true -f
./bundle/manifests/sonataflow.org_sonataflowbuilds.yaml
kubectl delete --ignore-not-found=true -f
./bundle/manifests/sonataflow.org_sonataflows.yaml
kubectl create -f ./bundle/manifests/sonataflow.org_sonataflowplatforms.yaml
+kubectl create -f
./bundle/manifests/sonataflow.org_sonataflowclusterplatforms.yaml
kubectl create -f ./bundle/manifests/sonataflow.org_sonataflowbuilds.yaml
kubectl create -f ./bundle/manifests/sonataflow.org_sonataflows.yaml
kubectl apply -f
./bundle/manifests/sonataflow-operator-builder-config_v1_configmap.yaml
diff --git a/main.go b/main.go
index 2e39652c..535a3ed0 100644
--- a/main.go
+++ b/main.go
@@ -67,12 +67,14 @@ func main() {
var metricsAddr string
var enableLeaderElection bool
var probeAddr string
+ var controllerCfgPath string
klog.InitFlags(nil)
flag.StringVar(&metricsAddr, "metrics-bind-address", ":8080", "The
address the metric endpoint binds to.")
flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The
address the probe endpoint binds to.")
flag.BoolVar(&enableLeaderElection, "leader-elect", false,
"Enable leader election for controller manager. "+
"Enabling this will ensure there is only one active
controller manager.")
+ flag.StringVar(&controllerCfgPath, "controller-cfg-path", "", "The
controller config file path.")
flag.Parse()
ctrl.SetLogger(klogr.New().WithName(controllers.ComponentName))
@@ -90,10 +92,12 @@ func main() {
os.Exit(1)
}
+ // Set global assessors
utils.SetIsOpenShift(mgr.GetConfig())
+ utils.SetClient(mgr.GetClient())
// Fail fast, we can change this behavior in the future to read from
defaults instead.
- if _, err = cfg.InitializeControllersCfg(); err != nil {
+ if _, err = cfg.InitializeControllersCfgAt(controllerCfgPath); err !=
nil {
klog.V(log.E).ErrorS(err, "unable to read controllers
configuration file")
os.Exit(1)
}
diff --git a/operator.yaml b/operator.yaml
index ef09c6cb..14dfec14 100644
--- a/operator.yaml
+++ b/operator.yaml
@@ -915,7 +915,7 @@ spec:
persistence:
description: Persistence defines the platform persistence
configuration.
When this field is set, the configuration is used as the
persistence
- for platform services and sonataflow instances that don't
provide
+ for platform services and SonataFlow instances that don't
provide
one of their own.
maxProperties: 1
properties:
@@ -969,6 +969,78 @@ spec:
- secretRef
type: object
type: object
+ properties:
+ description: "Properties defines the property set for a given
actor
+ in the current context. For example, the workflow managed
properties.
+ One can define here a set of properties for SonataFlow
deployments
+ that will be reused across every workflow deployment. \n
These properties
+ MAY NOT be propagated to a SonataFlowClusterPlatform since
PropertyVarSource
+ can only refer local context sources."
+ properties:
+ flow:
+ description: Properties that will be added to the
SonataFlow managed
+ configMaps in the current context.
+ items:
+ description: PropertyVar is the entry for a property set
derived
+ from the Kubernetes API EnvVar. Note that the name
doesn't
+ have to match C_IDENTIFIER.
+ properties:
+ name:
+ description: The property name
+ type: string
+ value:
+ description: Defaults to "".
+ type: string
+ valueFrom:
+ description: Source for the property's value. Cannot
be
+ used if value is not empty.
+ properties:
+ configMapKeyRef:
+ description: Selects a key of a ConfigMap.
+ properties:
+ key:
+ description: The key to select.
+ type: string
+ name:
+ description: 'Name of the referent. More
info:
https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the ConfigMap
or its
+ key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ secretKeyRef:
+ description: Selects a key of a secret in the
flow's
+ namespace
+ properties:
+ key:
+ description: The key of the secret to select
from. Must
+ be a valid secret key.
+ type: string
+ name:
+ description: 'Name of the referent. More
info:
https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ TODO: Add other useful fields. apiVersion,
kind,
+ uid?'
+ type: string
+ optional:
+ description: Specify whether the Secret or
its key
+ must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ required:
+ - name
+ type: object
+ type: array
+ type: object
services:
description: 'Services attributes for deploying supporting
applications
like Data Index & Job Service. Only workflows without the
`sonataflow.org/profile:
diff --git a/test/testdata/sonataflow.org_v1alpha08_sonataflowplatform.yaml
b/test/testdata/sonataflow.org_v1alpha08_sonataflowplatform.yaml
index 23af744d..39c5f1c1 100644
--- a/test/testdata/sonataflow.org_v1alpha08_sonataflowplatform.yaml
+++ b/test/testdata/sonataflow.org_v1alpha08_sonataflowplatform.yaml
@@ -20,6 +20,10 @@ kind: SonataFlowPlatform
metadata:
name: sonataflow-platform
spec:
+ properties:
+ flow:
+ - name: quarkus.log.level
+ value: INFO
build:
config:
registry:
diff --git
a/test/testdata/workflow/persistence/by_service/02-sonataflow_platform.yaml
b/test/testdata/workflow/persistence/by_service/02-sonataflow_platform.yaml
index 2de0372b..f61974cb 100644
--- a/test/testdata/workflow/persistence/by_service/02-sonataflow_platform.yaml
+++ b/test/testdata/workflow/persistence/by_service/02-sonataflow_platform.yaml
@@ -21,7 +21,7 @@ spec:
template:
buildArgs:
- name: QUARKUS_EXTENSIONS
- value:
org.kie.kogito:kogito-addons-quarkus-persistence-jdbc:999-SNAPSHOT,io.quarkus:quarkus-jdbc-postgresql:3.2.9.Final,io.quarkus:quarkus-agroal:3.2.9.Final
+ value:
org.kie:kie-addons-quarkus-persistence-jdbc:999-SNAPSHOT,io.quarkus:quarkus-jdbc-postgresql:3.2.9.Final,io.quarkus:quarkus-agroal:3.2.9.Final
config:
strategyOptions:
KanikoBuildCacheEnabled: "true"
diff --git
a/test/testdata/workflow/persistence/from_platform_overwritten_by_service/02-sonataflow_platform.yaml
b/test/testdata/workflow/persistence/from_platform_overwritten_by_service/02-sonataflow_platform.yaml
index e342b1c1..ddae61a8 100644
---
a/test/testdata/workflow/persistence/from_platform_overwritten_by_service/02-sonataflow_platform.yaml
+++
b/test/testdata/workflow/persistence/from_platform_overwritten_by_service/02-sonataflow_platform.yaml
@@ -31,7 +31,7 @@ spec:
template:
buildArgs:
- name: QUARKUS_EXTENSIONS
- value:
org.kie.kogito:kogito-addons-quarkus-persistence-jdbc:999-SNAPSHOT,io.quarkus:quarkus-jdbc-postgresql:3.2.9.Final,io.quarkus:quarkus-agroal:3.2.9.Final
+ value:
org.kie:kie-addons-quarkus-persistence-jdbc:999-SNAPSHOT,io.quarkus:quarkus-jdbc-postgresql:3.2.9.Final,io.quarkus:quarkus-agroal:3.2.9.Final
config:
strategyOptions:
KanikoBuildCacheEnabled: "true"
diff --git
a/test/testdata/workflow/persistence/from_platform_with_di_and_js_services/02-sonataflow_platform.yaml
b/test/testdata/workflow/persistence/from_platform_with_di_and_js_services/02-sonataflow_platform.yaml
index 66eec55a..0d1088fd 100644
---
a/test/testdata/workflow/persistence/from_platform_with_di_and_js_services/02-sonataflow_platform.yaml
+++
b/test/testdata/workflow/persistence/from_platform_with_di_and_js_services/02-sonataflow_platform.yaml
@@ -31,7 +31,7 @@ spec:
template:
buildArgs:
- name: QUARKUS_EXTENSIONS
- value:
org.kie.kogito:kogito-addons-quarkus-persistence-jdbc:999-SNAPSHOT,io.quarkus:quarkus-jdbc-postgresql:3.2.9.Final,io.quarkus:quarkus-agroal:3.2.9.Final
+ value:
org.kie:kie-addons-quarkus-persistence-jdbc:999-SNAPSHOT,io.quarkus:quarkus-jdbc-postgresql:3.2.9.Final,io.quarkus:quarkus-agroal:3.2.9.Final
config:
strategyOptions:
KanikoBuildCacheEnabled: "true"
diff --git
a/test/testdata/workflow/persistence/from_platform_with_no_persistence_required/02-sonataflow_platform.yaml
b/test/testdata/workflow/persistence/from_platform_with_no_persistence_required/02-sonataflow_platform.yaml
index f61f4a84..0b076a86 100644
---
a/test/testdata/workflow/persistence/from_platform_with_no_persistence_required/02-sonataflow_platform.yaml
+++
b/test/testdata/workflow/persistence/from_platform_with_no_persistence_required/02-sonataflow_platform.yaml
@@ -31,7 +31,7 @@ spec:
template:
buildArgs:
- name: QUARKUS_EXTENSIONS
- value:
org.kie.kogito:kogito-addons-quarkus-persistence-jdbc:999-SNAPSHOT,io.quarkus:quarkus-jdbc-postgresql:3.2.9.Final,io.quarkus:quarkus-agroal:3.2.9.Final
+ value:
org.kie:kie-addons-quarkus-persistence-jdbc:999-SNAPSHOT,io.quarkus:quarkus-jdbc-postgresql:3.2.9.Final,io.quarkus:quarkus-agroal:3.2.9.Final
config:
strategyOptions:
KanikoBuildCacheEnabled: "true"
diff --git
a/test/testdata/workflow/persistence/from_platform_without_di_and_js_services/02-sonataflow_platform.yaml
b/test/testdata/workflow/persistence/from_platform_without_di_and_js_services/02-sonataflow_platform.yaml
index 6dc311d6..3e24fe66 100644
---
a/test/testdata/workflow/persistence/from_platform_without_di_and_js_services/02-sonataflow_platform.yaml
+++
b/test/testdata/workflow/persistence/from_platform_without_di_and_js_services/02-sonataflow_platform.yaml
@@ -31,7 +31,7 @@ spec:
template:
buildArgs:
- name: QUARKUS_EXTENSIONS
- value:
org.kie.kogito:kogito-addons-quarkus-persistence-jdbc:999-SNAPSHOT,io.quarkus:quarkus-jdbc-postgresql:3.2.9.Final,io.quarkus:quarkus-agroal:3.2.9.Final
+ value:
org.kie:kie-addons-quarkus-persistence-jdbc:999-SNAPSHOT,io.quarkus:quarkus-jdbc-postgresql:3.2.9.Final,io.quarkus:quarkus-agroal:3.2.9.Final
config:
strategyOptions:
KanikoBuildCacheEnabled: "true"
diff --git a/utils/client.go b/utils/client.go
new file mode 100644
index 00000000..9b1cd085
--- /dev/null
+++ b/utils/client.go
@@ -0,0 +1,32 @@
+// 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 utils
+
+import "sigs.k8s.io/controller-runtime/pkg/client"
+
+var k8sClient client.Client
+
+// TODO: consider refactor the internals as we progress adding features to
rely on this client instead of passing it through all the functions
+
+// GetClient default client created by the main operator's thread.
+// It's safe to use since it's set when the operator main function runs.
+func GetClient() client.Client {
+ return k8sClient
+}
+
+// SetClient is meant for internal use only. Don't call it!
+func SetClient(client client.Client) {
+ k8sClient = client
+}
diff --git a/utils/properties.go b/utils/properties.go
index 382dc1b5..97c3c54c 100644
--- a/utils/properties.go
+++ b/utils/properties.go
@@ -26,7 +26,7 @@ import (
type ApplicationPropertiesBuilder interface {
WithInitialProperties(initialProperties *properties.Properties)
ApplicationPropertiesBuilder
WithImmutableProperties(immutableProperties *properties.Properties)
ApplicationPropertiesBuilder
- WithDefaultMutableProperties(defaultMutableProperties
*properties.Properties) ApplicationPropertiesBuilder
+ WithDefaultManagedProperties(defaultManagedProperties
*properties.Properties) ApplicationPropertiesBuilder
BuildAsString() string
Build() *properties.Properties
}
@@ -34,7 +34,7 @@ type ApplicationPropertiesBuilder interface {
type applicationPropertiesBuilder struct {
initialProperties *properties.Properties
immutableProperties *properties.Properties
- defaultMutableProperties *properties.Properties
+ defaultManagedProperties *properties.Properties
}
func (a *applicationPropertiesBuilder) WithInitialProperties(initialProperties
*properties.Properties) ApplicationPropertiesBuilder {
@@ -47,8 +47,8 @@ func (a *applicationPropertiesBuilder)
WithImmutableProperties(immutableProperti
return a
}
-func (a *applicationPropertiesBuilder)
WithDefaultMutableProperties(defaultMutableProperties *properties.Properties)
ApplicationPropertiesBuilder {
- a.defaultMutableProperties = defaultMutableProperties
+func (a *applicationPropertiesBuilder)
WithDefaultManagedProperties(defaultManagedProperties *properties.Properties)
ApplicationPropertiesBuilder {
+ a.defaultManagedProperties = defaultManagedProperties
return a
}
@@ -67,14 +67,14 @@ func (a *applicationPropertiesBuilder) Build()
*properties.Properties {
// Property expansion means resolving ${} within the properties and
environment context. Quarkus will do that in runtime.
props.DisableExpansion = true
- if a.defaultMutableProperties != nil {
- defaultMutableProps := a.defaultMutableProperties
- for _, k := range defaultMutableProps.Keys() {
+ if a.defaultManagedProperties != nil {
+ defaultManagedProperties := a.defaultManagedProperties
+ for _, k := range defaultManagedProperties.Keys() {
if _, ok := props.Get(k); ok {
- defaultMutableProps.Delete(k)
+ defaultManagedProperties.Delete(k)
}
}
- props.Merge(defaultMutableProps)
+ props.Merge(defaultManagedProperties)
}
if a.immutableProperties != nil {
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]