You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@yunikorn.apache.org by ch...@apache.org on 2024/01/14 18:06:12 UTC

(yunikorn-k8shim) branch master updated: [YUNIKORN-2287] Decompress function doesn't need to decode base64 (#752)

This is an automated email from the ASF dual-hosted git repository.

chia7712 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/yunikorn-k8shim.git


The following commit(s) were added to refs/heads/master by this push:
     new 57f11dc3 [YUNIKORN-2287] Decompress function doesn't need to decode base64 (#752)
57f11dc3 is described below

commit 57f11dc351a8300f5374fd53b97426b2adf7632e
Author: PoAn Yang <pa...@apache.org>
AuthorDate: Mon Jan 15 02:05:53 2024 +0800

    [YUNIKORN-2287] Decompress function doesn't need to decode base64 (#752)
    
    Closes: #752
    
    Signed-off-by: Chia-Ping Tsai <ch...@gmail.com>
---
 pkg/common/utils/utils_test.go                     |   5 +-
 pkg/conf/schedulerconf.go                          |  11 +-
 pkg/conf/schedulerconf_test.go                     |   6 +-
 test/e2e/configmap/configmap_suite_test.go         |  88 ++++++++++++++++
 test/e2e/configmap/configmap_test.go               | 112 +++++++++++++++++++++
 test/e2e/framework/configmanager/constants.go      |   1 +
 .../framework/helpers/yunikorn/rest_api_utils.go   |  10 ++
 test/e2e/framework/helpers/yunikorn/wrappers.go    |   2 +
 test/e2e/testdata/compressed_yunikorn-configs.yaml |  35 +++++++
 test/e2e/testdata/yunikorn-configs.yaml            |  32 ++++++
 10 files changed, 284 insertions(+), 18 deletions(-)

diff --git a/pkg/common/utils/utils_test.go b/pkg/common/utils/utils_test.go
index 4f98d2bd..c7e8a45b 100644
--- a/pkg/common/utils/utils_test.go
+++ b/pkg/common/utils/utils_test.go
@@ -21,7 +21,6 @@ package utils
 import (
 	"bytes"
 	"compress/gzip"
-	"encoding/base64"
 	"fmt"
 	"strings"
 	"testing"
@@ -1059,11 +1058,9 @@ func TestGzipCompressedConfigMap(t *testing.T) {
 	if err := gzWriter.Close(); err != nil {
 		t.Fatal("expected nil, got error")
 	}
-	encodedConfigString := make([]byte, base64.StdEncoding.EncodedLen(len(b.Bytes())))
-	base64.StdEncoding.Encode(encodedConfigString, b.Bytes())
 	confMap := conf.FlattenConfigMaps([]*v1.ConfigMap{
 		{Data: map[string]string{}},
-		{Data: map[string]string{conf.CMSvcClusterID: "new"}, BinaryData: map[string][]byte{"queues.yaml.gz": encodedConfigString}},
+		{Data: map[string]string{conf.CMSvcClusterID: "new"}, BinaryData: map[string][]byte{"queues.yaml.gz": b.Bytes()}},
 	})
 	config := GetCoreSchedulerConfigFromConfigMap(confMap)
 	assert.Equal(t, configs.DefaultSchedulerConfig, config)
diff --git a/pkg/conf/schedulerconf.go b/pkg/conf/schedulerconf.go
index b9d986ef..cd46c27e 100644
--- a/pkg/conf/schedulerconf.go
+++ b/pkg/conf/schedulerconf.go
@@ -21,7 +21,6 @@ package conf
 import (
 	"bytes"
 	"compress/gzip"
-	"encoding/base64"
 	"encoding/json"
 	"errors"
 	"flag"
@@ -452,18 +451,10 @@ func DumpConfiguration() {
 
 func Decompress(key string, value []byte) (string, string) {
 	var uncompressedData string
-	decodedValue := make([]byte, base64.StdEncoding.DecodedLen(len(value)))
-	n, err := base64.StdEncoding.Decode(decodedValue, value)
-	if err != nil {
-		log.Log(log.ShimConfig).Error("failed to decode schedulerConfig entry", zap.Error(err))
-		return "", ""
-	}
-	decodedValue = decodedValue[:n]
 	splitKey := strings.Split(key, ".")
 	compressionAlgo := splitKey[len(splitKey)-1]
 	if strings.EqualFold(compressionAlgo, constants.GzipSuffix) {
-		reader := bytes.NewReader(decodedValue)
-		gzReader, err := gzip.NewReader(reader)
+		gzReader, err := gzip.NewReader(bytes.NewReader(value))
 		if err != nil {
 			log.Log(log.ShimConfig).Error("failed to decompress decoded schedulerConfig entry", zap.Error(err))
 			return "", ""
diff --git a/pkg/conf/schedulerconf_test.go b/pkg/conf/schedulerconf_test.go
index e9c0a091..ef16dff3 100644
--- a/pkg/conf/schedulerconf_test.go
+++ b/pkg/conf/schedulerconf_test.go
@@ -87,9 +87,7 @@ func TestDecompress(t *testing.T) {
 		assert.NilError(t, err, "expected nil, got error")
 		t.Fatal("expected nil, got error")
 	}
-	encodedConfigString := make([]byte, base64.StdEncoding.EncodedLen(len(b.Bytes())))
-	base64.StdEncoding.Encode(encodedConfigString, b.Bytes())
-	key, decodedConfigString := Decompress("queues.yaml."+constants.GzipSuffix, encodedConfigString)
+	key, decodedConfigString := Decompress("queues.yaml."+constants.GzipSuffix, b.Bytes())
 	assert.Equal(t, "queues.yaml", key)
 	assert.Equal(t, configs.DefaultSchedulerConfig, decodedConfigString)
 }
@@ -97,7 +95,7 @@ func TestDecompress(t *testing.T) {
 func TestDecompressUnknownKey(t *testing.T) {
 	encodedConfigString := make([]byte, base64.StdEncoding.EncodedLen(len([]byte(configs.DefaultSchedulerConfig))))
 	base64.StdEncoding.Encode(encodedConfigString, []byte(configs.DefaultSchedulerConfig))
-	key, decodedConfigString := Decompress("queues.yaml.bin", encodedConfigString)
+	key, decodedConfigString := Decompress("queues.yaml.bin", []byte(configs.DefaultSchedulerConfig))
 	assert.Equal(t, "queues.yaml", key)
 	assert.Assert(t, len(decodedConfigString) == 0, "expected decodedConfigString to be nil")
 }
diff --git a/test/e2e/configmap/configmap_suite_test.go b/test/e2e/configmap/configmap_suite_test.go
new file mode 100644
index 00000000..5257bfa6
--- /dev/null
+++ b/test/e2e/configmap/configmap_suite_test.go
@@ -0,0 +1,88 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you 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 configmap
+
+import (
+	"path/filepath"
+	"testing"
+
+	"github.com/onsi/ginkgo/v2"
+	"github.com/onsi/ginkgo/v2/reporters"
+	"github.com/onsi/gomega"
+
+	"github.com/apache/yunikorn-k8shim/test/e2e/framework/configmanager"
+	"github.com/apache/yunikorn-k8shim/test/e2e/framework/helpers/common"
+	"github.com/apache/yunikorn-k8shim/test/e2e/framework/helpers/k8s"
+	"github.com/apache/yunikorn-k8shim/test/e2e/framework/helpers/yunikorn"
+)
+
+func init() {
+	configmanager.YuniKornTestConfig.ParseFlags()
+}
+
+func TestConfigMap(t *testing.T) {
+	ginkgo.ReportAfterSuite("TestConfigMap", func(report ginkgo.Report) {
+		err := common.CreateJUnitReportDir()
+		Ω(err).NotTo(gomega.HaveOccurred())
+		err = reporters.GenerateJUnitReportWithConfig(
+			report,
+			filepath.Join(configmanager.YuniKornTestConfig.LogDir, "TEST-configmap_junit.xml"),
+			reporters.JunitReportConfig{OmitSpecLabels: true},
+		)
+		Ω(err).NotTo(HaveOccurred())
+	})
+	gomega.RegisterFailHandler(ginkgo.Fail)
+	ginkgo.RunSpecs(t, "TestConfigMap", ginkgo.Label("TestConfigMap"))
+}
+
+var (
+	kClient    k8s.KubeCtl
+	restClient yunikorn.RClient
+)
+
+var _ = BeforeSuite(func() {
+
+	kClient = k8s.KubeCtl{}
+	Ω(kClient.SetClient()).To(BeNil())
+
+	restClient = yunikorn.RClient{}
+	Ω(restClient).NotTo(BeNil())
+
+	yunikorn.EnsureYuniKornConfigsPresent()
+
+	By("Port-forward the scheduler pod")
+	err := kClient.PortForwardYkSchedulerPod()
+	Ω(err).NotTo(HaveOccurred())
+})
+
+var _ = AfterSuite(func() {})
+
+var Describe = ginkgo.Describe
+var It = ginkgo.It
+var By = ginkgo.By
+var BeforeEach = ginkgo.BeforeEach
+var AfterEach = ginkgo.AfterEach
+var BeforeSuite = ginkgo.BeforeSuite
+var AfterSuite = ginkgo.AfterSuite
+
+// Declarations for Gomega Matchers
+var Equal = gomega.Equal
+var Ω = gomega.Expect
+var BeNil = gomega.BeNil
+var HaveOccurred = gomega.HaveOccurred
diff --git a/test/e2e/configmap/configmap_test.go b/test/e2e/configmap/configmap_test.go
new file mode 100644
index 00000000..49aa2120
--- /dev/null
+++ b/test/e2e/configmap/configmap_test.go
@@ -0,0 +1,112 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you 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 configmap
+
+import (
+	"bytes"
+	"compress/gzip"
+	"io"
+	"time"
+
+	v1 "k8s.io/api/core/v1"
+
+	"github.com/apache/yunikorn-core/pkg/common/configs"
+	"github.com/apache/yunikorn-k8shim/test/e2e/framework/configmanager"
+	"github.com/apache/yunikorn-k8shim/test/e2e/framework/helpers/k8s"
+	"github.com/apache/yunikorn-k8shim/test/e2e/framework/helpers/yunikorn"
+)
+
+var oldConfigMap = new(v1.ConfigMap)
+
+var _ = Describe("ConfigMap", func() {
+	BeforeEach(func() {
+		By("Get previous config")
+		var err error
+		oldConfigMap, err = kClient.GetConfigMaps(configmanager.YuniKornTestConfig.YkNamespace,
+			configmanager.DefaultYuniKornConfigMap)
+		Ω(err).NotTo(HaveOccurred())
+		Ω(oldConfigMap).NotTo(BeNil())
+	})
+
+	It("Verify_ConfigMap_File", func() {
+		configMap, err := k8s.GetConfigMapObj("../testdata/yunikorn-configs.yaml")
+		Ω(err).NotTo(HaveOccurred())
+		Ω(configMap).NotTo(BeNil())
+
+		By("Updating the config map with BinaryData")
+		configMap.Namespace = configmanager.YuniKornTestConfig.YkNamespace
+		_, err = kClient.UpdateConfigMap(configMap, configmanager.YuniKornTestConfig.YkNamespace)
+		Ω(err).NotTo(HaveOccurred())
+
+		queues := configMap.Data[configmanager.DefaultPolicyGroup]
+
+		schedulerConfig, err := configs.LoadSchedulerConfigFromByteArray([]byte(queues))
+		Ω(err).NotTo(HaveOccurred())
+		Ω(len(schedulerConfig.Partitions)).To(Equal(1))
+		Ω(len(schedulerConfig.Partitions[0].Queues)).To(Equal(1))
+
+		ts := schedulerConfig.Partitions[0].Queues[0].Properties["timestamp"]
+		err = yunikorn.WaitForQueueTS("root", ts, 30*time.Second)
+		Ω(err).NotTo(HaveOccurred())
+
+		checkSchedulerConfig(schedulerConfig)
+	})
+
+	It("Verify_Compressed_ConfigMap_File", func() {
+		configMap, err := k8s.GetConfigMapObj("../testdata/compressed_yunikorn-configs.yaml")
+		Ω(err).NotTo(HaveOccurred())
+		Ω(configMap).NotTo(BeNil())
+
+		By("Updating the config map with BinaryData")
+		configMap.Namespace = configmanager.YuniKornTestConfig.YkNamespace
+		_, err = kClient.UpdateConfigMap(configMap, configmanager.YuniKornTestConfig.YkNamespace)
+		Ω(err).NotTo(HaveOccurred())
+
+		queuesGz := configMap.BinaryData[configmanager.DefaultPolicyGroup+".gz"]
+		Ω(len(queuesGz)).NotTo(Equal(0))
+		gzReader, err := gzip.NewReader(bytes.NewReader(queuesGz))
+		Ω(err).NotTo(HaveOccurred())
+		decompressedBytes, err := io.ReadAll(gzReader)
+		Ω(err).NotTo(HaveOccurred())
+		err = gzReader.Close()
+		Ω(err).NotTo(HaveOccurred())
+
+		schedulerConfig, err := configs.LoadSchedulerConfigFromByteArray(decompressedBytes)
+		Ω(err).NotTo(HaveOccurred())
+		Ω(len(schedulerConfig.Partitions)).To(Equal(1))
+		Ω(len(schedulerConfig.Partitions[0].Queues)).To(Equal(1))
+
+		ts := schedulerConfig.Partitions[0].Queues[0].Properties["timestamp"]
+		err = yunikorn.WaitForQueueTS("root", ts, 30*time.Second)
+		Ω(err).NotTo(HaveOccurred())
+
+		checkSchedulerConfig(schedulerConfig)
+	})
+
+	AfterEach(func() {
+		yunikorn.RestoreConfigMapWrapper(oldConfigMap, "")
+	})
+})
+
+func checkSchedulerConfig(schedulerConfig *configs.SchedulerConfig) {
+	configDAOInfo, err := restClient.GetConfig()
+	Ω(err).NotTo(HaveOccurred())
+	Ω(configDAOInfo).NotTo(BeNil())
+	Ω(configDAOInfo.Partitions).To(Equal(schedulerConfig.Partitions))
+}
diff --git a/test/e2e/framework/configmanager/constants.go b/test/e2e/framework/configmanager/constants.go
index 0eeeda08..8b5cb791 100644
--- a/test/e2e/framework/configmanager/constants.go
+++ b/test/e2e/framework/configmanager/constants.go
@@ -39,6 +39,7 @@ const (
 	AppsPath          = "ws/v1/partition/%s/queue/%s/applications"
 	AppPath           = "ws/v1/partition/%s/queue/%s/application/%s"
 	CompletedAppsPath = "ws/v1/partition/%s/applications/completed"
+	ConfigPath        = "ws/v1/config"
 	ClustersPath      = "ws/v1/clusters"
 	NodesPath         = "ws/v1/partition/%s/nodes"
 	UserUsagePath     = "ws/v1/partition/%s/usage/user/%s"
diff --git a/test/e2e/framework/helpers/yunikorn/rest_api_utils.go b/test/e2e/framework/helpers/yunikorn/rest_api_utils.go
index 732807d2..1db748dd 100644
--- a/test/e2e/framework/helpers/yunikorn/rest_api_utils.go
+++ b/test/e2e/framework/helpers/yunikorn/rest_api_utils.go
@@ -110,6 +110,16 @@ func (c *RClient) GetQueues(partition string) (*dao.PartitionQueueDAOInfo, error
 	return queues, err
 }
 
+func (c *RClient) GetConfig() (*dao.ConfigDAOInfo, error) {
+	req, err := c.newRequest("GET", configmanager.ConfigPath, nil)
+	if err != nil {
+		return nil, err
+	}
+	var config *dao.ConfigDAOInfo
+	_, err = c.do(req, &config)
+	return config, err
+}
+
 func (c *RClient) GetHealthCheck() (dao.SchedulerHealthDAOInfo, error) {
 	req, err := c.newRequest("GET", configmanager.HealthCheckPath, nil)
 	if err != nil {
diff --git a/test/e2e/framework/helpers/yunikorn/wrappers.go b/test/e2e/framework/helpers/yunikorn/wrappers.go
index d11877c3..07476eb4 100644
--- a/test/e2e/framework/helpers/yunikorn/wrappers.go
+++ b/test/e2e/framework/helpers/yunikorn/wrappers.go
@@ -112,6 +112,7 @@ func UpdateCustomConfigMapWrapperWithMap(oldConfigMap *v1.ConfigMap, schedPolicy
 	for k, v := range customMap {
 		c.Data[k] = v
 	}
+	c.BinaryData = nil
 	var d, err3 = k.UpdateConfigMap(c, configmanager.YuniKornTestConfig.YkNamespace)
 	Ω(err3).NotTo(HaveOccurred())
 	Ω(d).NotTo(BeNil())
@@ -134,6 +135,7 @@ func RestoreConfigMapWrapper(oldConfigMap *v1.ConfigMap, annotation string) {
 	ts, tsErr := common.SetQueueTimestamp(oldSC, "default", "root")
 	Ω(tsErr).NotTo(HaveOccurred())
 	c.Data = oldConfigMap.Data
+	c.BinaryData = oldConfigMap.BinaryData
 	c.Data[configmanager.DefaultPolicyGroup], err = common.ToYAML(oldSC)
 	Ω(err).NotTo(HaveOccurred())
 
diff --git a/test/e2e/testdata/compressed_yunikorn-configs.yaml b/test/e2e/testdata/compressed_yunikorn-configs.yaml
new file mode 100644
index 00000000..24ede4ce
--- /dev/null
+++ b/test/e2e/testdata/compressed_yunikorn-configs.yaml
@@ -0,0 +1,35 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you 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: v1
+kind: ConfigMap
+metadata:
+  name: yunikorn-configs
+binaryData:
+# Following command is used to generate queues.yaml which is compressed by gzip and encoded by base64.
+# The result is like the value in queues.yaml.gz. If updating the queues.yaml, please also update the queues.yaml.gz.
+# echo "
+# partitions:
+#   - name: default
+#     queues:
+#       - name: root
+#         submitacl: '*'
+#         parent: true
+#         properties:
+#           timestamp: '1257894000'
+#         queues:
+#           - name: parent
+#             submitacl: '*'" | gzip | base64
+  queues.yaml.gz: H4sIANGBiWUAA2WO2wrCMBBE3/sV81YQhCiKmr9ZdQuB5mKy+/+maptK5/Hscma6RFmcuBiK7YA9Anm2ePJAOkolwEtZ+XOdMn/kGOWHgKJ374Qeo0W/6xdc3RzEQrJygzkmrp1NOUWc5yLkUzUcjufL9XYyxjTV/4j1kG/J6rCZ8wavmg4s5AAAAA==
diff --git a/test/e2e/testdata/yunikorn-configs.yaml b/test/e2e/testdata/yunikorn-configs.yaml
new file mode 100644
index 00000000..5cbf9e74
--- /dev/null
+++ b/test/e2e/testdata/yunikorn-configs.yaml
@@ -0,0 +1,32 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you 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: v1
+kind: ConfigMap
+metadata:
+  name: yunikorn-configs
+data:
+  queues.yaml: |
+    partitions:
+      - name: default
+        queues:
+          - name: root
+            submitacl: '*'
+            parent: true
+            properties:
+              timestamp: '1705067238'
+            queues:
+              - name: parent
+                submitacl: '*'


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscribe@yunikorn.apache.org
For additional commands, e-mail: issues-help@yunikorn.apache.org