This is an automated email from the ASF dual-hosted git repository.
wwei pushed a commit to branch soak-test
in repository https://gitbox.apache.org/repos/asf/yunikorn-release.git
The following commit(s) were added to refs/heads/soak-test by this push:
new 3133721 [YUNIKORN-3023] Soak testing framework initial commit with
directory structure and config parsing (#186)
3133721 is described below
commit 3133721b54b0c2d091866a766037687023cdb6d1
Author: Shravan Achar <[email protected]>
AuthorDate: Tue Feb 11 15:06:32 2025 -0800
[YUNIKORN-3023] Soak testing framework initial commit with directory
structure and config parsing (#186)
This PR adds the init commit for the soak testing framework, it adds the
definition of the config object
and defines the logic to parse the config.
Co-authored-by: Shravan Achar <[email protected]>
---
soak/conf.yaml | 165 +++++++++++++++++++++++++++++++++++++++++++++++
soak/framework/config.go | 121 ++++++++++++++++++++++++++++++++++
soak/main.go | 39 +++++++++++
3 files changed, 325 insertions(+)
diff --git a/soak/conf.yaml b/soak/conf.yaml
new file mode 100644
index 0000000..a469951
--- /dev/null
+++ b/soak/conf.yaml
@@ -0,0 +1,165 @@
+#
+# 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.
+
+tests:
+- name: autoscaling
+ template:
+ kubeconfig:
+ path: ../templates/kubeconfig
+ node:
+ - path: ../templates/nodeGroupTemplates.yaml
+ maxCount: "$nodesMaxCount"
+ desiredCount: "$nodesDesiredCount"
+ job:
+ - path: ../templates/jobATemplate.yaml
+ count: "$numJobs"
+ podCount: "$numPods"
+ mode: "always" #one of ["always", "random-max-percent",
"fixed-percent"]
+ value: "50" # when mode is "random-max-percent" or "fixed-percent"
+ - path: ../templates/jobBTemplate.yaml
+ count: "$numJobs"
+ podCount: "$numPods"
+ scheduler:
+ - path: ../templates/autoscaling-queues.yaml
+ vcoreRequests: 2
+ vcoreLimits: 2
+ memoryRequests: 16Gi
+ memoryLimits: 16Gi
+ testCases:
+ - name: "1000-nodes-cluster"
+ params:
+ nodesMaxCount: 1000
+ nodesDesiredCount: 20
+ numPods: 5000
+ numJobs: 200
+ schedule: once
+ labels: ["short"]
+ # labels: ["soak-test"]
+ threshold:
+ maxRuntime: "10m"
+ pendingPods: 0
+ metrics:
+ maxAllocationDelay: "5s"
+ - name: "5000-nodes-cluster"
+ params:
+ nodesMaxCount: 5000
+ nodesDesiredCount: 20
+ numPods: 20000
+ numJobs: 700
+ schedule: once
+ runs: 1
+ # labels: ["soak-test", "benchmark-test"]
+ labels: ["short"]
+ threshold:
+ maxRuntime: "60m"
+ pendingPods: 0
+ maxAllocationDelay: "20s"
+ - name: "300-nodes-cluster-schedule"
+ params:
+ nodesMaxCount: 300
+ nodesDesiredCount: 0
+ numPods: 2000
+ numJobs: 150
+ schedule: "*/15 * * * *"
+ runs: 10
+ #labels: ["soak-test"]
+ labels: ["super-long"]
+ threshold:
+ maxRuns: 10
+ pendingPods: 0
+ metrics:
+ maxAllocationDelay: "5s"
+- name: chaos-faults
+ template:
+ kubeconfig:
+ path: ../templates/kubeconfig
+ node:
+ - path: ../templates/nodeGroupTemplates.yaml
+ maxCount: "$nodesMaxCount"
+ desiredCount: "$nodesDesiredCount"
+ job:
+ - path: ../templates/jobATemplate.yaml
+ count: "$numJobs"
+ podCount: "$numPods"
+ choas:
+ - path: ../templates/chaos.yaml
+ count: "$numChaos"
+ scheduler:
+ - path: ../templates/chaos-queues.yaml
+ vcoreRequests: 2
+ vcoreLimits: 2
+ memoryRequests: 16Gi
+ memoryLimits: 16Gi
+ testCases:
+ - name: "1000-nodes-cluster"
+ params:
+ nodesMaxCount: 1000
+ nodesDesiredCount: 20
+ numPods: 5000
+ numJobs: 200
+ numChaos: 0
+ schedule: once
+ labels: ["short"]
+ # labels: ["soak-test", "benchmark-test", "integration-test"]
+ threshold:
+ maxRuntime: "10m"
+ pendingPods: 0
+ detectDeadlock: false
+ metrics:
+ schedulerRestarts: 0
+ maxAllocationDelay: "10s"
+ - name: "5000-nodes-cluster"
+ params:
+ nodesMaxCount: 5000
+ nodesDesiredCount: 20
+ numPods: 20000
+ numJobs: 700
+ numChaos: 200
+ schedule: once
+ runs: 1
+ labels: ["long"]
+ # labels: ["soak-test", "benchmark-test"]
+ threshold:
+ maxRuntime: "60m"
+ pendingPods: 0
+ detectDeadlock: true
+ metrics:
+ schedulerRestarts: 1
+ maxAllocationDelay: "60s"
+ - name: "300-nodes-cluster-schedule"
+ params:
+ nodesMaxCount: 300
+ nodesDesiredCount: 0
+ numPods: 2000
+ numJobs: 150
+ numChaos: 10
+ schedule: "*/15 * * * *"
+ runs: 10
+ # labels: ["soak-test"]
+ labels: ["super-long"]
+ threshold:
+ maxRuntime: "60m"
+ pendingPods: 0
+ detectDeadlock: true
+ metrics:
+ schedulerRestarts: 5
+ maxAllocationDelay: "60s"
+ prom:
+ - query:
'sum(rate(go_memstats_heap_inuse_bytes{service="yunikorn"}[60m])) by (service)'
+ expression: 'sprintf("%.0f", query_result / 1000000)'
+ value: '20'
+ op: '<='
\ No newline at end of file
diff --git a/soak/framework/config.go b/soak/framework/config.go
new file mode 100644
index 0000000..1de9b14
--- /dev/null
+++ b/soak/framework/config.go
@@ -0,0 +1,121 @@
+/*
+ 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 framework
+
+import (
+ "fmt"
+ "gopkg.in/yaml.v3"
+ "os"
+)
+
+type KubeconfigFields struct {
+ Path string `yaml:"path,omitempty"`
+}
+
+type NodeFields struct {
+ Path string `yaml:"path,omitempty"`
+ MaxCount string `yaml:"maxCount,omitempty"`
+ DesiredCount string `yaml:"desiredCount,omitempty"`
+}
+
+type JobFields struct {
+ Path string `yaml:"path,omitempty"`
+ Count string `yaml:"count,omitempty"`
+ PodCount string `yaml:"podCount,omitempty"`
+}
+
+type SchedulerFields struct {
+ Path string `yaml:"path,omitempty"`
+ VcoreRequests string `yaml:"vcoreRequests,omitempty"`
+ VcoreLimits string `yaml:"vcoreLimits,omitempty"`
+ MemoryRequests string `yaml:"memoryRequests,omitempty"`
+ MemoryLimits string `yaml:"memoryLimits,omitempty"`
+}
+
+type ChaosFields struct {
+ Path string `yaml:"path,omitempty"`
+ Count string `yaml:"count,omitempty"`
+}
+
+type Template struct {
+ Kubeconfig KubeconfigFields `yaml:"kubeconfig,omitempty"`
+ Node []NodeFields `yaml:"node,omitempty"`
+ Job []JobFields `yaml:"job,omitempty"`
+ Scheduler []SchedulerFields `yaml:"scheduler,omitempty"`
+ Chaos []ChaosFields `yaml:"chaos,omitempty"`
+}
+
+type TestCaseParams struct {
+ NodeMaxCount int `yaml:"nodeMaxCount,omitempty"`
+ NodesDesiredCount int `yaml:"nodesDesiredCount,omitempty"`
+ NumPods int `yaml:"numPods,omitempty"`
+ NumJobs int `yaml:"numJobs,omitempty"`
+}
+
+type Prom struct {
+ Query string `yaml:"query,omitempty"`
+ Expression string `yaml:"expression,omitempty"`
+ Value string `yaml:"value,omitempty"`
+ Op string `yaml:"op,omitempty"`
+}
+
+type Metrics struct {
+ SchedulerRestarts int `yaml:"schedulerRestarts,omitempty"`
+ MaxAllocationDelay string `yaml:"maxAllocationDelay,omitempty"`
+ Prom []Prom `yaml:"prom,omitempty"`
+}
+
+type Threshold struct {
+ MaxRuntime string `yaml:"maxRuntime,omitempty"`
+ PendingPods int `yaml:"pendingPods,omitempty"`
+ DetectDeadlock bool `yaml:"detectDeadlock,omitempty"`
+ Metrics Metrics `yaml:"metrics,omitempty"`
+}
+
+type TestCase struct {
+ Name string `yaml:"name,omitempty"`
+ Params TestCaseParams `yaml:"params,omitempty"`
+ Schedule string `yaml:"schedule,omitempty"`
+ Runs int `yaml:"runs,omitempty"`
+ Labels []string `yaml:"labels,omitempty"`
+ Threshold Threshold `yaml:"threshold,omitempty"`
+}
+
+type Test struct {
+ Name string `yaml:"name,omitempty"`
+ Template Template `yaml:"template,omitempty"`
+ TestCases []TestCase `yaml:"testCases,omitempty"`
+}
+
+type Config struct {
+ Tests []Test `yaml:"tests,omitempty"`
+}
+
+func InitConfig(configFile string) (*Config, error) {
+ yamlContent, err := os.ReadFile(configFile)
+ if err != nil {
+ return nil, fmt.Errorf("Failed to read config file: %s ",
err.Error())
+ }
+ conf := Config{}
+ err = yaml.Unmarshal(yamlContent, &conf)
+ if err != nil {
+ return nil, fmt.Errorf("Failed to parse config file: %s ",
err.Error())
+ }
+ return &conf, nil
+}
diff --git a/soak/main.go b/soak/main.go
new file mode 100644
index 0000000..c048fbb
--- /dev/null
+++ b/soak/main.go
@@ -0,0 +1,39 @@
+/*
+ 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 main
+
+import (
+ "github.com/apache/yunikorn-core/pkg/log"
+ "github.com/apache/yunikorn-release/soak/framework"
+ "go.uber.org/zap"
+)
+
+const (
+ ConfigFileName = "conf.yaml"
+)
+
+var logger *zap.Logger = log.Log(log.Test)
+
+func main() {
+ conf, err := framework.InitConfig(ConfigFileName)
+ if err != nil {
+ logger.Fatal("failed to parse config", zap.Error(err))
+ }
+ logger.Info("config successully loaded", zap.Any("conf", conf))
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]