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]

Reply via email to