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 a7a158f3 [KOGITO-9890] Generate safe volume naming based on DNS 1035 
(#272)
a7a158f3 is described below

commit a7a158f36536250d65bab68d741085f8ebfe56ae
Author: Ricardo Zanini <[email protected]>
AuthorDate: Fri Oct 13 11:15:30 2023 -0300

    [KOGITO-9890] Generate safe volume naming based on DNS 1035 (#272)
    
    * [KOGITO-9890] Generate safe volume naming based on DNS 1035
    
    Signed-off-by: Ricardo Zanini <[email protected]>
    
    * Remove flacky test, and unused function
    
    Signed-off-by: Ricardo Zanini <[email protected]>
    
    ---------
    
    Signed-off-by: Ricardo Zanini <[email protected]>
---
 controllers/profiles/dev/object_creators_dev.go    |  3 +-
 controllers/profiles/dev/profile_dev_test.go       | 33 ++++++++++--
 controllers/profiles/dev/states_dev.go             |  3 +-
 ...onataflow.org_v1alpha08_sonataflow-metainf.yaml | 62 ++++++++++++++++++++++
 .../v1_configmap_greetings_staticfiles.yaml        | 24 +++++++++
 test/yaml.go                                       | 21 +++++---
 utils/kubernetes/naming.go                         | 49 +++++++++++++++++
 utils/strings.go                                   |  7 ---
 8 files changed, 179 insertions(+), 23 deletions(-)

diff --git a/controllers/profiles/dev/object_creators_dev.go 
b/controllers/profiles/dev/object_creators_dev.go
index 9b760b7d..609621c7 100644
--- a/controllers/profiles/dev/object_creators_dev.go
+++ b/controllers/profiles/dev/object_creators_dev.go
@@ -26,7 +26,6 @@ import (
        "github.com/kiegroup/kogito-serverless-operator/controllers/profiles"
        
"github.com/kiegroup/kogito-serverless-operator/controllers/profiles/common"
        "github.com/kiegroup/kogito-serverless-operator/controllers/workflowdef"
-       "github.com/kiegroup/kogito-serverless-operator/utils"
        kubeutil 
"github.com/kiegroup/kogito-serverless-operator/utils/kubernetes"
        "github.com/kiegroup/kogito-serverless-operator/workflowproj"
 )
@@ -139,7 +138,7 @@ func mountDevConfigMapsMutateVisitor(flowDefCM, propsCM 
*corev1.ConfigMap, workf
                                }
                                // the resource configMap needs a specific dir, 
inside the src/main/resources
                                // to avoid clashing with other configMaps 
trying to mount on the same dir, we create one projected per path
-                               volumeMountName := 
configMapExternalResourcesVolumeNamePrefix + 
utils.PathToString(workflowResCM.WorkflowPath)
+                               volumeMountName := 
kubeutil.MustSafeDNS1035(configMapExternalResourcesVolumeNamePrefix, 
workflowResCM.WorkflowPath)
                                volumeMounts = 
kubeutil.VolumeMountAdd(volumeMounts, volumeMountName, 
path.Join(quarkusDevConfigMountPath, workflowResCM.WorkflowPath))
                                resourceVolumes = 
kubeutil.VolumeAddVolumeProjectionConfigMap(resourceVolumes, 
workflowResCM.ConfigMap.Name, volumeMountName)
                        }
diff --git a/controllers/profiles/dev/profile_dev_test.go 
b/controllers/profiles/dev/profile_dev_test.go
index c9ad1860..d5a6a379 100644
--- a/controllers/profiles/dev/profile_dev_test.go
+++ b/controllers/profiles/dev/profile_dev_test.go
@@ -22,6 +22,8 @@ import (
        corev1 "k8s.io/api/core/v1"
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 
+       kubeutil 
"github.com/kiegroup/kogito-serverless-operator/utils/kubernetes"
+
        
"github.com/kiegroup/kogito-serverless-operator/controllers/profiles/common"
 
        operatorapi 
"github.com/kiegroup/kogito-serverless-operator/api/v1alpha08"
@@ -296,12 +298,11 @@ func Test_newDevProfileWithExternalConfigMaps(t 
*testing.T) {
        assert.Equal(t, 2, len(deployment.Spec.Template.Spec.Volumes))
        sortVolumeMounts(&deployment.Spec.Template.Spec.Containers[0])
 
-       wd := deployment.Spec.Template.Spec.Containers[0].VolumeMounts[0]
-       extCamel := deployment.Spec.Template.Spec.Containers[0].VolumeMounts[1]
+       wd := deployment.Spec.Template.Spec.Containers[0].VolumeMounts[1]
+       extCamel := deployment.Spec.Template.Spec.Containers[0].VolumeMounts[0]
        assert.Equal(t, configMapResourcesVolumeName, wd.Name)
        assert.Equal(t, quarkusDevConfigMountPath, wd.MountPath)
 
-       assert.Equal(t, configMapExternalResourcesVolumeNamePrefix+"routes", 
extCamel.Name)
        assert.Equal(t, extCamel.MountPath, quarkusDevConfigMountPath+"/routes")
 
        cmData[camelYamlRouteFileName] = yamlRoute
@@ -323,8 +324,7 @@ func Test_newDevProfileWithExternalConfigMaps(t *testing.T) 
{
        assert.Equal(t, 2, len(deployment.Spec.Template.Spec.Volumes))
        sortVolumeMounts(&deployment.Spec.Template.Spec.Containers[0])
 
-       extCamelRouteOne := 
deployment.Spec.Template.Spec.Containers[0].VolumeMounts[1]
-       assert.Equal(t, configMapExternalResourcesVolumeNamePrefix+"routes", 
extCamelRouteOne.Name)
+       extCamelRouteOne := 
deployment.Spec.Template.Spec.Containers[0].VolumeMounts[0]
        assert.Equal(t, quarkusDevConfigMountPath+"/routes", 
extCamelRouteOne.MountPath)
 
        workflow.Status.Manager().MarkTrue(api.RunningConditionType)
@@ -368,6 +368,29 @@ func Test_newDevProfileWithExternalConfigMaps(t 
*testing.T) {
        assert.Equal(t, wd.MountPath, quarkusDevConfigMountPath)
 }
 
+func Test_VolumeWithCapitalizedPaths(t *testing.T) {
+       configMap := &v1.ConfigMap{}
+       test.GetKubernetesResource(test.SonataFlowGreetingsStaticFilesConfig, 
configMap)
+       configMap.Namespace = t.Name()
+       workflow := 
test.GetSonataFlow(test.SonataFlowGreetingsWithStaticResourcesCR, t.Name())
+
+       client := test.NewKogitoClientBuilder().WithRuntimeObjects(workflow, 
configMap).WithStatusSubresource(workflow, configMap).Build()
+
+       devReconciler := NewProfileReconciler(client)
+
+       result, err := devReconciler.Reconcile(context.TODO(), workflow)
+       assert.NoError(t, err)
+       assert.NotNil(t, result)
+
+       deployment := test.MustGetDeployment(t, client, workflow)
+       assert.NotNil(t, deployment)
+
+       container, _ := 
kubeutil.GetContainerByName(operatorapi.DefaultContainerName, 
&deployment.Spec.Template.Spec)
+       // properties, definitions, and the capitalized value
+       assert.Len(t, container.VolumeMounts, 2)
+       assert.Len(t, deployment.Spec.Template.Spec.Volumes, 2)
+}
+
 func sortVolumeMounts(container *v1.Container) {
        sort.SliceStable(container.VolumeMounts, func(i, j int) bool {
                return container.VolumeMounts[i].Name < 
container.VolumeMounts[j].Name
diff --git a/controllers/profiles/dev/states_dev.go 
b/controllers/profiles/dev/states_dev.go
index df7cd329..2c30e0b3 100644
--- a/controllers/profiles/dev/states_dev.go
+++ b/controllers/profiles/dev/states_dev.go
@@ -38,8 +38,7 @@ import (
 
 const (
        configMapResourcesVolumeName               = "resources"
-       configMapExternalResourcesVolumeNamePrefix = 
configMapResourcesVolumeName + "-"
-
+       configMapExternalResourcesVolumeNamePrefix = "res-"
        // quarkusDevConfigMountPath mount path for application properties file 
in the Workflow Quarkus Application
        // See: 
https://quarkus.io/guides/config-reference#application-properties-file
        quarkusDevConfigMountPath = 
"/home/kogito/serverless-workflow-project/src/main/resources"
diff --git a/test/testdata/sonataflow.org_v1alpha08_sonataflow-metainf.yaml 
b/test/testdata/sonataflow.org_v1alpha08_sonataflow-metainf.yaml
new file mode 100644
index 00000000..3b2c7a32
--- /dev/null
+++ b/test/testdata/sonataflow.org_v1alpha08_sonataflow-metainf.yaml
@@ -0,0 +1,62 @@
+# Copyright 2023 Red Hat, Inc. and/or its affiliates
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+apiVersion: sonataflow.org/v1alpha08
+kind: SonataFlow
+metadata:
+  name: greeting
+  annotations:
+    sonataflow.org/description: Greeting example on k8s!
+    sonataflow.org/version: 0.0.1
+    sonataflow.org/profile: dev
+spec:
+  resources:
+    configMaps:
+      - configMap:
+          name: greetings-staticfiles
+        workflowPath: META-INF/resources
+  flow:
+    start: ChooseOnLanguage
+    functions:
+      - name: greetFunction
+        type: custom
+        operation: sysout
+    states:
+      - name: ChooseOnLanguage
+        type: switch
+        dataConditions:
+          - condition: "${ .language == \"English\" }"
+            transition: GreetInEnglish
+          - condition: "${ .language == \"Spanish\" }"
+            transition: GreetInSpanish
+        defaultCondition: GreetInEnglish
+      - name: GreetInEnglish
+        type: inject
+        data:
+          greeting: "Hello from JSON Workflow, "
+        transition: GreetPerson
+      - name: GreetInSpanish
+        type: inject
+        data:
+          greeting: "Saludos desde JSON Workflow, "
+        transition: GreetPerson
+      - name: GreetPerson
+        type: operation
+        actions:
+          - name: greetAction
+            functionRef:
+              refName: greetFunction
+              arguments:
+                message:  ".greeting+.name"
+        end: true
diff --git a/test/testdata/v1_configmap_greetings_staticfiles.yaml 
b/test/testdata/v1_configmap_greetings_staticfiles.yaml
new file mode 100644
index 00000000..ccfe04c7
--- /dev/null
+++ b/test/testdata/v1_configmap_greetings_staticfiles.yaml
@@ -0,0 +1,24 @@
+# Copyright 2023 Red Hat, Inc. and/or its affiliates
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+kind: ConfigMap
+apiVersion: v1
+metadata:
+  name: greetings-staticfiles
+data:
+  index.html: |-
+    <html>
+        <title>Greetings!</title>
+        <body>Greetings stranger!</body>
+    </html>
\ No newline at end of file
diff --git a/test/yaml.go b/test/yaml.go
index f5fe97bc..ed01f7c1 100644
--- a/test/yaml.go
+++ b/test/yaml.go
@@ -24,6 +24,7 @@ import (
 
        "github.com/davecgh/go-spew/spew"
        "k8s.io/klog/v2"
+       "sigs.k8s.io/controller-runtime/pkg/client"
 
        "github.com/kiegroup/kogito-serverless-operator/api"
 
@@ -40,8 +41,10 @@ const (
        sonataFlowOrderProcessingFolder           = "order-processing"
        sonataFlowSampleYamlCR                    = 
"sonataflow.org_v1alpha08_sonataflow.yaml"
        SonataFlowGreetingsWithDataInputSchemaCR  = 
"sonataflow.org_v1alpha08_sonataflow_greetings_datainput.yaml"
+       SonataFlowGreetingsWithStaticResourcesCR  = 
"sonataflow.org_v1alpha08_sonataflow-metainf.yaml"
        SonataFlowSimpleOpsYamlCR                 = 
"sonataflow.org_v1alpha08_sonataflow-simpleops.yaml"
        SonataFlowGreetingsDataInputSchemaConfig  = 
"v1_configmap_greetings_datainput.yaml"
+       SonataFlowGreetingsStaticFilesConfig      = 
"v1_configmap_greetings_staticfiles.yaml"
        sonataFlowPlatformYamlCR                  = 
"sonataflow.org_v1alpha08_sonataflowplatform.yaml"
        sonataFlowPlatformWithCacheMinikubeYamlCR = 
"sonataflow.org_v1alpha08_sonataflowplatform_withCache_minikube.yaml"
        sonataFlowPlatformForOpenshift            = 
"sonataflow.org_v1alpha08_sonataflowplatform_openshift.yaml"
@@ -54,9 +57,16 @@ const (
 
 var projectDir = ""
 
-func getSonataFlow(testFile, namespace string) *operatorapi.SonataFlow {
+func GetSonataFlow(testFile, namespace string) *operatorapi.SonataFlow {
        ksw := &operatorapi.SonataFlow{}
 
+       GetKubernetesResource(testFile, ksw)
+       klog.V(log.D).InfoS("Successfully read KSW", "ksw", spew.Sprint(ksw))
+       ksw.Namespace = namespace
+       return ksw
+}
+
+func GetKubernetesResource(testFile string, resource client.Object) {
        yamlFile, err := os.ReadFile(path.Join(getTestDataDir(), testFile))
        if err != nil {
                klog.V(log.E).ErrorS(err, "yamlFile.Get")
@@ -64,14 +74,11 @@ func getSonataFlow(testFile, namespace string) 
*operatorapi.SonataFlow {
        }
 
        // Important: Here we are reading the CR deployment file from a given 
path and creating an &operatorapi.SonataFlow struct
-       err = yaml.NewYAMLOrJSONDecoder(bytes.NewReader(yamlFile), 
100).Decode(ksw)
+       err = yaml.NewYAMLOrJSONDecoder(bytes.NewReader(yamlFile), 
100).Decode(resource)
        if err != nil {
                klog.V(log.E).ErrorS(err, "Unmarshal")
                panic(err)
        }
-       klog.V(log.D).InfoS("Successfully read KSW", "ksw", spew.Sprint(ksw))
-       ksw.Namespace = namespace
-       return ksw
 }
 
 func getSonataFlowPlatform(testFile string) *operatorapi.SonataFlowPlatform {
@@ -149,7 +156,7 @@ func GetSonataFlowBuilderConfig(namespace string) 
*corev1.ConfigMap {
 }
 
 func GetBaseSonataFlow(namespace string) *operatorapi.SonataFlow {
-       return getSonataFlow(sonataFlowSampleYamlCR, namespace)
+       return GetSonataFlow(sonataFlowSampleYamlCR, namespace)
 }
 
 func GetBaseSonataFlowWithDevProfile(namespace string) *operatorapi.SonataFlow 
{
@@ -165,7 +172,7 @@ func GetBaseSonataFlowWithProdProfile(namespace string) 
*operatorapi.SonataFlow
 }
 
 func GetBaseSonataFlowWithProdOpsProfile(namespace string) 
*operatorapi.SonataFlow {
-       workflow := getSonataFlow(SonataFlowSimpleOpsYamlCR, namespace)
+       workflow := GetSonataFlow(SonataFlowSimpleOpsYamlCR, namespace)
        return workflow
 }
 
diff --git a/utils/kubernetes/naming.go b/utils/kubernetes/naming.go
new file mode 100644
index 00000000..9f78df37
--- /dev/null
+++ b/utils/kubernetes/naming.go
@@ -0,0 +1,49 @@
+// Copyright 2023 Red Hat, Inc. and/or its affiliates
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package kubernetes
+
+import (
+       "fmt"
+
+       "k8s.io/apimachinery/pkg/api/validation"
+       "k8s.io/apimachinery/pkg/util/rand"
+)
+
+const dns1035MaxChar int = 63
+
+// SafeDNS1035 generates a safe encoded string based on "s" with the given 
prefix.
+// Ideally used with internal generated names.
+//
+// See 
https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#rfc-1035-label-names
+func SafeDNS1035(prefix, s string) (string, error) {
+       safeNaming := prefix + rand.SafeEncodeString(s)
+       if len(safeNaming) > dns1035MaxChar {
+               safeNaming = safeNaming[:dns1035MaxChar]
+       }
+       errMsgs := validation.NameIsDNS1035Label(safeNaming, false)
+       if len(errMsgs) > 0 {
+               return "", fmt.Errorf("failed to generate a safe name for %s 
with prefix %s: %v", s, prefix, errMsgs)
+       }
+       return safeNaming, nil
+}
+
+// MustSafeDNS1035 see SafeDNS1035. Use this function only if you control the 
prefix.
+func MustSafeDNS1035(prefix, s string) string {
+       name, err := SafeDNS1035(prefix, s)
+       if err != nil {
+               panic(err)
+       }
+       return name
+}
diff --git a/utils/strings.go b/utils/strings.go
index 61ba1a61..41b785f7 100644
--- a/utils/strings.go
+++ b/utils/strings.go
@@ -15,8 +15,6 @@
 package utils
 
 import (
-       "os"
-       "path"
        "strings"
 )
 
@@ -33,8 +31,3 @@ func RemoveKnownExtension(fileName, extension string) string {
        }
        return fileName
 }
-
-// PathToString replaces the PathSeparator from a given path.
-func PathToString(pathRef string) string {
-       return strings.ReplaceAll(path.Clean(pathRef), 
string(os.PathSeparator), "")
-}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to