diff --git a/internal/workloads/cpu.go b/internal/workloads/cpu.go index 26cf10c..d54e644 100644 --- a/internal/workloads/cpu.go +++ b/internal/workloads/cpu.go @@ -4,16 +4,18 @@ package workloads import ( + "fmt" + "github.com/opdev/virtwork/internal/config" ) -const cpuSystemdUnit = `[Unit] +const cpuSystemdUnitTemplate = `[Unit] Description=Virtwork CPU stress workload After=network.target [Service] Type=simple -ExecStart=/usr/bin/stress-ng --cpu 0 --cpu-method all --timeout 0 +ExecStart=/usr/bin/stress-ng --cpu 0 --cpu-load %s --cpu-method %s --timeout 0 Restart=always RestartSec=10 @@ -28,7 +30,11 @@ type CPUWorkload struct { } // NewCPUWorkload creates a CPUWorkload with the given configuration and SSH credentials. -func NewCPUWorkload(cfg config.WorkloadConfig, sshUser, sshPassword string, sshKeys []string) *CPUWorkload { +func NewCPUWorkload( + cfg config.WorkloadConfig, + sshUser, sshPassword string, + sshKeys []string, +) *CPUWorkload { return &CPUWorkload{ BaseWorkload: BaseWorkload{ Config: cfg, @@ -39,6 +45,24 @@ func NewCPUWorkload(cfg config.WorkloadConfig, sshUser, sshPassword string, sshK } } +func (w *CPUWorkload) cpuLoadPercent() string { + if w.Config.Params != nil { + if val, ok := w.Config.Params["cpu-load-percent"]; ok && val != "" { + return val + } + } + return "100" +} + +func (w *CPUWorkload) cpuMethod() string { + if w.Config.Params != nil { + if val, ok := w.Config.Params["cpu-method"]; ok && val != "" { + return val + } + } + return "all" +} + // Name returns "cpu". func (w *CPUWorkload) Name() string { return "cpu" @@ -47,12 +71,13 @@ func (w *CPUWorkload) Name() string { // CloudInitUserdata returns cloud-init YAML that installs stress-ng and runs a // continuous CPU stress workload via systemd. func (w *CPUWorkload) CloudInitUserdata() (string, error) { + unit := fmt.Sprintf(cpuSystemdUnitTemplate, w.cpuLoadPercent(), w.cpuMethod()) return w.BuildCloudConfig(CloudConfigOpts{ Packages: []string{"stress-ng"}, WriteFiles: []WriteFile{ { Path: "/etc/systemd/system/virtwork-cpu.service", - Content: cpuSystemdUnit, + Content: unit, Permissions: "0644", }, }, diff --git a/internal/workloads/cpu_test.go b/internal/workloads/cpu_test.go index ea28021..f0004d4 100644 --- a/internal/workloads/cpu_test.go +++ b/internal/workloads/cpu_test.go @@ -52,6 +52,7 @@ var _ = Describe("CPUWorkload", func() { content := file["content"].(string) Expect(content).To(ContainSubstring("stress-ng")) Expect(content).To(ContainSubstring("--cpu 0")) + Expect(content).To(ContainSubstring("--cpu-load 100")) Expect(content).To(ContainSubstring("--cpu-method all")) Expect(content).To(ContainSubstring("--timeout 0")) }) @@ -79,4 +80,66 @@ var _ = Describe("CPUWorkload", func() { Expect(res.CPUCores).To(Equal(2)) Expect(res.Memory).To(Equal("2Gi")) }) + + Context("param wiring", func() { + It("should use default param values when Params is nil", func() { + result, err := w.CloudInitUserdata() + Expect(err).NotTo(HaveOccurred()) + + parsed := parseYAML(result) + files := parsed["write_files"].([]interface{}) + file := files[0].(map[string]interface{}) + content := file["content"].(string) + + Expect(content).To(ContainSubstring("--cpu-load 100")) + Expect(content).To(ContainSubstring("--cpu-method all")) + }) + + It("should wire custom params from WorkloadConfig.Params", func() { + custom := workloads.NewCPUWorkload(config.WorkloadConfig{ + Enabled: new(true), + VMCount: 1, + CPUCores: 2, + Memory: "2Gi", + Params: map[string]string{ + "cpu-load-percent": "50", + "cpu-method": "matrixprod", + }, + }, "virtwork", "", nil) + + result, err := custom.CloudInitUserdata() + Expect(err).NotTo(HaveOccurred()) + + parsed := parseYAML(result) + files := parsed["write_files"].([]interface{}) + file := files[0].(map[string]interface{}) + content := file["content"].(string) + + Expect(content).To(ContainSubstring("--cpu-load 50")) + Expect(content).To(ContainSubstring("--cpu-method matrixprod")) + }) + + It("should use defaults for missing individual params", func() { + partial := workloads.NewCPUWorkload(config.WorkloadConfig{ + Enabled: new(true), + VMCount: 1, + CPUCores: 2, + Memory: "2Gi", + Params: map[string]string{ + "cpu-load-percent": "75", + }, + }, "virtwork", "", nil) + + result, err := partial.CloudInitUserdata() + Expect(err).NotTo(HaveOccurred()) + + parsed := parseYAML(result) + files := parsed["write_files"].([]interface{}) + file := files[0].(map[string]interface{}) + content := file["content"].(string) + + Expect(content).To(ContainSubstring("--cpu-load 75")) + Expect(content).To(ContainSubstring("--cpu-method all")) + }) + }) }) diff --git a/internal/workloads/database.go b/internal/workloads/database.go index 02af572..60a8fbb 100644 --- a/internal/workloads/database.go +++ b/internal/workloads/database.go @@ -4,6 +4,8 @@ package workloads import ( + "fmt" + kubevirtv1 "kubevirt.io/api/core/v1" "github.com/opdev/virtwork/internal/config" @@ -11,7 +13,7 @@ import ( "github.com/opdev/virtwork/internal/vm" ) -const dbSetupScript = `#!/bin/bash +const dbSetupScriptTemplate = `#!/bin/bash set -euo pipefail DATA_DIR="/var/lib/pgsql/data" @@ -55,9 +57,9 @@ postgresql-setup --initdb # Start PostgreSQL temporarily for pgbench init systemctl start postgresql -# Create pgbench database with scale factor 50 +# Create pgbench database with configured scale factor sudo -u postgres createdb pgbench -sudo -u postgres pgbench -i -s 50 pgbench +sudo -u postgres pgbench -i -s %s pgbench # Stop PostgreSQL (systemd will manage it) systemctl stop postgresql @@ -67,7 +69,7 @@ touch "${MARKER}" chown postgres:postgres "${MARKER}" ` -const dbSystemdUnit = `[Unit] +const dbSystemdUnitTemplate = `[Unit] Description=Virtwork database benchmark workload After=network.target local-fs.target postgresql.service Requires=postgresql.service @@ -76,7 +78,7 @@ Requires=postgresql.service Type=simple User=postgres ExecStartPre=/usr/local/bin/virtwork-db-setup.sh -ExecStart=/bin/bash -c 'while true; do pgbench -c 10 -j 2 -T 300 pgbench; sleep 10; done' +ExecStart=/bin/bash -c 'while true; do pgbench -c %s -j 2 -T %s pgbench; sleep 10; done' Restart=always RestartSec=10 @@ -111,6 +113,33 @@ func NewDatabaseWorkload( } } +func (w *DatabaseWorkload) scaleFactor() string { + if w.Config.Params != nil { + if val, ok := w.Config.Params["scale-factor"]; ok && val != "" { + return val + } + } + return "50" +} + +func (w *DatabaseWorkload) clients() string { + if w.Config.Params != nil { + if val, ok := w.Config.Params["clients"]; ok && val != "" { + return val + } + } + return "10" +} + +func (w *DatabaseWorkload) duration() string { + if w.Config.Params != nil { + if val, ok := w.Config.Params["duration"]; ok && val != "" { + return val + } + } + return "300" +} + // Name returns "database". func (w *DatabaseWorkload) Name() string { return "database" @@ -120,17 +149,19 @@ func (w *DatabaseWorkload) Name() string { // a setup script for one-time database initialization, and creates a systemd // service that runs continuous pgbench benchmarks. func (w *DatabaseWorkload) CloudInitUserdata() (string, error) { + setupScript := fmt.Sprintf(dbSetupScriptTemplate, w.scaleFactor()) + serviceUnit := fmt.Sprintf(dbSystemdUnitTemplate, w.clients(), w.duration()) return w.BuildCloudConfig(CloudConfigOpts{ Packages: []string{"postgresql-server"}, WriteFiles: []WriteFile{ { Path: "/usr/local/bin/virtwork-db-setup.sh", - Content: dbSetupScript, + Content: setupScript, Permissions: "0755", }, { Path: "/etc/systemd/system/virtwork-database.service", - Content: dbSystemdUnit, + Content: serviceUnit, Permissions: "0644", }, }, diff --git a/internal/workloads/database_test.go b/internal/workloads/database_test.go index dc189e3..fe6297b 100644 --- a/internal/workloads/database_test.go +++ b/internal/workloads/database_test.go @@ -165,4 +165,91 @@ var _ = Describe("DatabaseWorkload", func() { Expect(res.CPUCores).To(Equal(2)) Expect(res.Memory).To(Equal("4Gi")) }) + + Context("param wiring", func() { + It("should use default param values when Params is nil", func() { + result, err := w.CloudInitUserdata() + Expect(err).NotTo(HaveOccurred()) + + parsed := parseYAML(result) + files := parsed["write_files"].([]interface{}) + + filesByPath := map[string]string{} + for _, f := range files { + fm := f.(map[string]interface{}) + filesByPath[fm["path"].(string)] = fm["content"].(string) + } + + setupScript := filesByPath["/usr/local/bin/virtwork-db-setup.sh"] + Expect(setupScript).To(ContainSubstring("pgbench -i -s 50")) + + serviceUnit := filesByPath["/etc/systemd/system/virtwork-database.service"] + Expect(serviceUnit).To(ContainSubstring("-c 10")) + Expect(serviceUnit).To(ContainSubstring("-T 300")) + }) + + It("should wire custom params from WorkloadConfig.Params", func() { + custom := workloads.NewDatabaseWorkload(config.WorkloadConfig{ + Enabled: new(true), + VMCount: 1, + CPUCores: 2, + Memory: "4Gi", + Params: map[string]string{ + "scale-factor": "100", + "clients": "20", + "duration": "600", + }, + }, "10Gi", "virtwork", "", nil) + + result, err := custom.CloudInitUserdata() + Expect(err).NotTo(HaveOccurred()) + + parsed := parseYAML(result) + files := parsed["write_files"].([]interface{}) + + filesByPath := map[string]string{} + for _, f := range files { + fm := f.(map[string]interface{}) + filesByPath[fm["path"].(string)] = fm["content"].(string) + } + + setupScript := filesByPath["/usr/local/bin/virtwork-db-setup.sh"] + Expect(setupScript).To(ContainSubstring("pgbench -i -s 100")) + + serviceUnit := filesByPath["/etc/systemd/system/virtwork-database.service"] + Expect(serviceUnit).To(ContainSubstring("-c 20")) + Expect(serviceUnit).To(ContainSubstring("-T 600")) + }) + + It("should use defaults for missing individual params", func() { + partial := workloads.NewDatabaseWorkload(config.WorkloadConfig{ + Enabled: new(true), + VMCount: 1, + CPUCores: 2, + Memory: "4Gi", + Params: map[string]string{ + "clients": "16", + }, + }, "10Gi", "virtwork", "", nil) + + result, err := partial.CloudInitUserdata() + Expect(err).NotTo(HaveOccurred()) + + parsed := parseYAML(result) + files := parsed["write_files"].([]interface{}) + + filesByPath := map[string]string{} + for _, f := range files { + fm := f.(map[string]interface{}) + filesByPath[fm["path"].(string)] = fm["content"].(string) + } + + setupScript := filesByPath["/usr/local/bin/virtwork-db-setup.sh"] + Expect(setupScript).To(ContainSubstring("pgbench -i -s 50")) + + serviceUnit := filesByPath["/etc/systemd/system/virtwork-database.service"] + Expect(serviceUnit).To(ContainSubstring("-c 16")) + Expect(serviceUnit).To(ContainSubstring("-T 300")) + }) + }) }) diff --git a/internal/workloads/disk.go b/internal/workloads/disk.go index 940b8da..a5e18ec 100644 --- a/internal/workloads/disk.go +++ b/internal/workloads/disk.go @@ -4,6 +4,8 @@ package workloads import ( + "fmt" + kubevirtv1 "kubevirt.io/api/core/v1" "github.com/opdev/virtwork/internal/config" @@ -11,7 +13,7 @@ import ( "github.com/opdev/virtwork/internal/vm" ) -const fioMixedRWProfile = `[global] +const fioMixedRWProfileTemplate = `[global] ioengine=libaio direct=1 directory=/mnt/data @@ -19,15 +21,15 @@ size=1G [mixed-rw] rw=randrw -rwmixread=70 -bs=4k -numjobs=4 -runtime=300 +rwmixread=%s +bs=%s +numjobs=%s +runtime=%s time_based group_reporting ` -const fioSeqWriteProfile = `[global] +const fioSeqWriteProfileTemplate = `[global] ioengine=libaio direct=1 directory=/mnt/data @@ -35,9 +37,9 @@ size=1G [seq-write] rw=write -bs=128k +bs=%s numjobs=2 -runtime=300 +runtime=%s time_based group_reporting ` @@ -81,6 +83,51 @@ func NewDiskWorkload( } } +func (w *DiskWorkload) blockSizeRW() string { + if w.Config.Params != nil { + if val, ok := w.Config.Params["block-size-rw"]; ok && val != "" { + return val + } + } + return "4k" +} + +func (w *DiskWorkload) blockSizeSeq() string { + if w.Config.Params != nil { + if val, ok := w.Config.Params["block-size-seq"]; ok && val != "" { + return val + } + } + return "128k" +} + +func (w *DiskWorkload) rwMixRead() string { + if w.Config.Params != nil { + if val, ok := w.Config.Params["rwmixread"]; ok && val != "" { + return val + } + } + return "70" +} + +func (w *DiskWorkload) numJobs() string { + if w.Config.Params != nil { + if val, ok := w.Config.Params["numjobs"]; ok && val != "" { + return val + } + } + return "4" +} + +func (w *DiskWorkload) fioRuntime() string { + if w.Config.Params != nil { + if val, ok := w.Config.Params["runtime"]; ok && val != "" { + return val + } + } + return "300" +} + // Name returns "disk". func (w *DiskWorkload) Name() string { return "disk" @@ -89,6 +136,10 @@ func (w *DiskWorkload) Name() string { // CloudInitUserdata returns cloud-init YAML that installs fio, writes two job // profiles, and creates a systemd service that alternates between them. func (w *DiskWorkload) CloudInitUserdata() (string, error) { + mixedRW := fmt.Sprintf(fioMixedRWProfileTemplate, + w.rwMixRead(), w.blockSizeRW(), w.numJobs(), w.fioRuntime()) + seqWrite := fmt.Sprintf(fioSeqWriteProfileTemplate, + w.blockSizeSeq(), w.fioRuntime()) return w.BuildCloudConfig(CloudConfigOpts{ Packages: []string{"fio"}, WriteFiles: []WriteFile{ @@ -99,12 +150,12 @@ func (w *DiskWorkload) CloudInitUserdata() (string, error) { }, { Path: "/etc/fio/mixed-rw.fio", - Content: fioMixedRWProfile, + Content: mixedRW, Permissions: "0644", }, { Path: "/etc/fio/seq-write.fio", - Content: fioSeqWriteProfile, + Content: seqWrite, Permissions: "0644", }, { diff --git a/internal/workloads/disk_test.go b/internal/workloads/disk_test.go index 7132040..be3b9d4 100644 --- a/internal/workloads/disk_test.go +++ b/internal/workloads/disk_test.go @@ -100,4 +100,103 @@ var _ = Describe("DiskWorkload", func() { Expect(w.RequiresService()).To(BeFalse()) Expect(w.ServiceSpec()).To(BeNil()) }) + + Context("param wiring", func() { + It("should use default param values when Params is nil", func() { + result, err := w.CloudInitUserdata() + Expect(err).NotTo(HaveOccurred()) + + parsed := parseYAML(result) + files := parsed["write_files"].([]interface{}) + + filesByPath := map[string]string{} + for _, f := range files { + fm := f.(map[string]interface{}) + filesByPath[fm["path"].(string)] = fm["content"].(string) + } + + mixedRW := filesByPath["/etc/fio/mixed-rw.fio"] + Expect(mixedRW).To(ContainSubstring("bs=4k")) + Expect(mixedRW).To(ContainSubstring("rwmixread=70")) + Expect(mixedRW).To(ContainSubstring("numjobs=4")) + Expect(mixedRW).To(ContainSubstring("runtime=300")) + + seqWrite := filesByPath["/etc/fio/seq-write.fio"] + Expect(seqWrite).To(ContainSubstring("bs=128k")) + Expect(seqWrite).To(ContainSubstring("runtime=300")) + }) + + It("should wire custom params from WorkloadConfig.Params", func() { + custom := workloads.NewDiskWorkload(config.WorkloadConfig{ + Enabled: new(true), + VMCount: 1, + CPUCores: 2, + Memory: "2Gi", + Params: map[string]string{ + "block-size-rw": "8k", + "block-size-seq": "256k", + "rwmixread": "50", + "numjobs": "8", + "runtime": "600", + }, + }, "10Gi", "virtwork", "", nil) + + result, err := custom.CloudInitUserdata() + Expect(err).NotTo(HaveOccurred()) + + parsed := parseYAML(result) + files := parsed["write_files"].([]interface{}) + + filesByPath := map[string]string{} + for _, f := range files { + fm := f.(map[string]interface{}) + filesByPath[fm["path"].(string)] = fm["content"].(string) + } + + mixedRW := filesByPath["/etc/fio/mixed-rw.fio"] + Expect(mixedRW).To(ContainSubstring("bs=8k")) + Expect(mixedRW).To(ContainSubstring("rwmixread=50")) + Expect(mixedRW).To(ContainSubstring("numjobs=8")) + Expect(mixedRW).To(ContainSubstring("runtime=600")) + + seqWrite := filesByPath["/etc/fio/seq-write.fio"] + Expect(seqWrite).To(ContainSubstring("bs=256k")) + Expect(seqWrite).To(ContainSubstring("runtime=600")) + }) + + It("should use defaults for missing individual params", func() { + partial := workloads.NewDiskWorkload(config.WorkloadConfig{ + Enabled: new(true), + VMCount: 1, + CPUCores: 2, + Memory: "2Gi", + Params: map[string]string{ + "block-size-rw": "16k", + "runtime": "120", + }, + }, "10Gi", "virtwork", "", nil) + + result, err := partial.CloudInitUserdata() + Expect(err).NotTo(HaveOccurred()) + + parsed := parseYAML(result) + files := parsed["write_files"].([]interface{}) + + filesByPath := map[string]string{} + for _, f := range files { + fm := f.(map[string]interface{}) + filesByPath[fm["path"].(string)] = fm["content"].(string) + } + + mixedRW := filesByPath["/etc/fio/mixed-rw.fio"] + Expect(mixedRW).To(ContainSubstring("bs=16k")) + Expect(mixedRW).To(ContainSubstring("rwmixread=70")) + Expect(mixedRW).To(ContainSubstring("numjobs=4")) + Expect(mixedRW).To(ContainSubstring("runtime=120")) + + seqWrite := filesByPath["/etc/fio/seq-write.fio"] + Expect(seqWrite).To(ContainSubstring("bs=128k")) + Expect(seqWrite).To(ContainSubstring("runtime=120")) + }) + }) }) diff --git a/internal/workloads/memory.go b/internal/workloads/memory.go index 273fcda..ca175e2 100644 --- a/internal/workloads/memory.go +++ b/internal/workloads/memory.go @@ -4,16 +4,18 @@ package workloads import ( + "fmt" + "github.com/opdev/virtwork/internal/config" ) -const memorySystemdUnit = `[Unit] +const memorySystemdUnitTemplate = `[Unit] Description=Virtwork memory stress workload After=network.target [Service] Type=simple -ExecStart=/usr/bin/stress-ng --vm 1 --vm-bytes 80% --vm-method all --timeout 0 +ExecStart=/usr/bin/stress-ng --vm %s --vm-bytes %s%% --vm-method %s --timeout 0 Restart=always RestartSec=10 @@ -29,7 +31,11 @@ type MemoryWorkload struct { } // NewMemoryWorkload creates a MemoryWorkload with the given configuration and SSH credentials. -func NewMemoryWorkload(cfg config.WorkloadConfig, sshUser, sshPassword string, sshKeys []string) *MemoryWorkload { +func NewMemoryWorkload( + cfg config.WorkloadConfig, + sshUser, sshPassword string, + sshKeys []string, +) *MemoryWorkload { return &MemoryWorkload{ BaseWorkload: BaseWorkload{ Config: cfg, @@ -40,6 +46,33 @@ func NewMemoryWorkload(cfg config.WorkloadConfig, sshUser, sshPassword string, s } } +func (w *MemoryWorkload) memoryPercent() string { + if w.Config.Params != nil { + if val, ok := w.Config.Params["memory-percent"]; ok && val != "" { + return val + } + } + return "80" +} + +func (w *MemoryWorkload) vmStressors() string { + if w.Config.Params != nil { + if val, ok := w.Config.Params["vm-stressors"]; ok && val != "" { + return val + } + } + return "1" +} + +func (w *MemoryWorkload) vmMethod() string { + if w.Config.Params != nil { + if val, ok := w.Config.Params["vm-method"]; ok && val != "" { + return val + } + } + return "all" +} + // Name returns "memory". func (w *MemoryWorkload) Name() string { return "memory" @@ -48,12 +81,13 @@ func (w *MemoryWorkload) Name() string { // CloudInitUserdata returns cloud-init YAML that installs stress-ng and runs a // continuous memory pressure workload via systemd. func (w *MemoryWorkload) CloudInitUserdata() (string, error) { + unit := fmt.Sprintf(memorySystemdUnitTemplate, w.vmStressors(), w.memoryPercent(), w.vmMethod()) return w.BuildCloudConfig(CloudConfigOpts{ Packages: []string{"stress-ng"}, WriteFiles: []WriteFile{ { Path: "/etc/systemd/system/virtwork-memory.service", - Content: memorySystemdUnit, + Content: unit, Permissions: "0644", }, }, diff --git a/internal/workloads/memory_test.go b/internal/workloads/memory_test.go index 3a3446f..425c9aa 100644 --- a/internal/workloads/memory_test.go +++ b/internal/workloads/memory_test.go @@ -101,4 +101,70 @@ var _ = Describe("MemoryWorkload", func() { Expect(res.CPUCores).To(Equal(2)) Expect(res.Memory).To(Equal("4Gi")) }) + + Context("param wiring", func() { + It("should use default param values when Params is nil", func() { + result, err := w.CloudInitUserdata() + Expect(err).NotTo(HaveOccurred()) + + parsed := parseYAML(result) + files := parsed["write_files"].([]interface{}) + file := files[0].(map[string]interface{}) + content := file["content"].(string) + + Expect(content).To(ContainSubstring("--vm 1")) + Expect(content).To(ContainSubstring("--vm-bytes 80%")) + Expect(content).To(ContainSubstring("--vm-method all")) + }) + + It("should wire custom params from WorkloadConfig.Params", func() { + custom := workloads.NewMemoryWorkload(config.WorkloadConfig{ + Enabled: new(true), + VMCount: 1, + CPUCores: 2, + Memory: "4Gi", + Params: map[string]string{ + "memory-percent": "60", + "vm-stressors": "2", + "vm-method": "flip", + }, + }, "virtwork", "", nil) + + result, err := custom.CloudInitUserdata() + Expect(err).NotTo(HaveOccurred()) + + parsed := parseYAML(result) + files := parsed["write_files"].([]interface{}) + file := files[0].(map[string]interface{}) + content := file["content"].(string) + + Expect(content).To(ContainSubstring("--vm 2")) + Expect(content).To(ContainSubstring("--vm-bytes 60%")) + Expect(content).To(ContainSubstring("--vm-method flip")) + }) + + It("should use defaults for missing individual params", func() { + partial := workloads.NewMemoryWorkload(config.WorkloadConfig{ + Enabled: new(true), + VMCount: 1, + CPUCores: 2, + Memory: "4Gi", + Params: map[string]string{ + "memory-percent": "50", + }, + }, "virtwork", "", nil) + + result, err := partial.CloudInitUserdata() + Expect(err).NotTo(HaveOccurred()) + + parsed := parseYAML(result) + files := parsed["write_files"].([]interface{}) + file := files[0].(map[string]interface{}) + content := file["content"].(string) + + Expect(content).To(ContainSubstring("--vm 1")) + Expect(content).To(ContainSubstring("--vm-bytes 50%")) + Expect(content).To(ContainSubstring("--vm-method all")) + }) + }) }) diff --git a/internal/workloads/network.go b/internal/workloads/network.go index 0b2fd2e..a61653a 100644 --- a/internal/workloads/network.go +++ b/internal/workloads/network.go @@ -58,6 +58,24 @@ func NewNetworkWorkload( } } +func (w *NetworkWorkload) parallelStreams() string { + if w.Config.Params != nil { + if val, ok := w.Config.Params["parallel-streams"]; ok && val != "" { + return val + } + } + return "4" +} + +func (w *NetworkWorkload) testDuration() string { + if w.Config.Params != nil { + if val, ok := w.Config.Params["test-duration"]; ok && val != "" { + return val + } + } + return "60" +} + // Name returns "network". func (w *NetworkWorkload) Name() string { return "network" @@ -161,13 +179,13 @@ After=network.target [Service] Type=simple -ExecStart=/bin/bash -c 'while true; do iperf3 -c %s -t 60 -P 4 --bidir; sleep 10; done' +ExecStart=/bin/bash -c 'while true; do iperf3 -c %s -t %s -P %s --bidir; sleep 10; done' Restart=always RestartSec=10 [Install] WantedBy=multi-user.target -`, dnsName) +`, dnsName, w.testDuration(), w.parallelStreams()) return w.BuildCloudConfig(CloudConfigOpts{ Packages: []string{"iperf3"}, diff --git a/internal/workloads/network_test.go b/internal/workloads/network_test.go index 1ea8b87..2646094 100644 --- a/internal/workloads/network_test.go +++ b/internal/workloads/network_test.go @@ -87,7 +87,9 @@ var _ = Describe("NetworkWorkload", func() { } Expect(serviceContent).NotTo(BeEmpty()) Expect(serviceContent).To(ContainSubstring("iperf3 -c")) - Expect(serviceContent).To(ContainSubstring("virtwork-iperf3-server.virtwork.svc.cluster.local")) + Expect( + serviceContent, + ).To(ContainSubstring("virtwork-iperf3-server.virtwork.svc.cluster.local")) Expect(serviceContent).To(ContainSubstring("--bidir")) }) @@ -106,7 +108,9 @@ var _ = Describe("NetworkWorkload", func() { break } } - Expect(serviceContent).To(ContainSubstring("virtwork-iperf3-server.custom-ns.svc.cluster.local")) + Expect( + serviceContent, + ).To(ContainSubstring("virtwork-iperf3-server.custom-ns.svc.cluster.local")) }) It("should return error for unknown role", func() { @@ -204,4 +208,66 @@ var _ = Describe("NetworkWorkload", func() { It("should implement MultiVMWorkload interface", func() { var _ workloads.MultiVMWorkload = w }) + + Context("param wiring", func() { + It("should use default param values when Params is nil", func() { + result, err := w.UserdataForRole("client", "virtwork") + Expect(err).NotTo(HaveOccurred()) + + parsed := parseYAML(result) + files := parsed["write_files"].([]interface{}) + file := files[0].(map[string]interface{}) + content := file["content"].(string) + + Expect(content).To(ContainSubstring("-t 60")) + Expect(content).To(ContainSubstring("-P 4")) + }) + + It("should wire custom params from WorkloadConfig.Params", func() { + custom := workloads.NewNetworkWorkload(config.WorkloadConfig{ + Enabled: new(true), + VMCount: 1, + CPUCores: 2, + Memory: "2Gi", + Params: map[string]string{ + "parallel-streams": "8", + "test-duration": "120", + }, + }, "virtwork", "virtwork", "", nil) + + result, err := custom.UserdataForRole("client", "virtwork") + Expect(err).NotTo(HaveOccurred()) + + parsed := parseYAML(result) + files := parsed["write_files"].([]interface{}) + file := files[0].(map[string]interface{}) + content := file["content"].(string) + + Expect(content).To(ContainSubstring("-t 120")) + Expect(content).To(ContainSubstring("-P 8")) + }) + + It("should use defaults for missing individual params", func() { + partial := workloads.NewNetworkWorkload(config.WorkloadConfig{ + Enabled: new(true), + VMCount: 1, + CPUCores: 2, + Memory: "2Gi", + Params: map[string]string{ + "test-duration": "30", + }, + }, "virtwork", "virtwork", "", nil) + + result, err := partial.UserdataForRole("client", "virtwork") + Expect(err).NotTo(HaveOccurred()) + + parsed := parseYAML(result) + files := parsed["write_files"].([]interface{}) + file := files[0].(map[string]interface{}) + content := file["content"].(string) + + Expect(content).To(ContainSubstring("-t 30")) + Expect(content).To(ContainSubstring("-P 4")) + }) + }) })