Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
228 changes: 228 additions & 0 deletions config.yaml.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
# config.yaml.example — Complete virtwork configuration reference
#
# Pass to virtwork with: virtwork run --config config.yaml
#
# Priority chain (highest wins):
# CLI flags > environment variables (VIRTWORK_*) > this YAML file > built-in defaults
#
# All keys are optional. Unset keys fall back to built-in defaults.
# YAML keys use underscores (e.g., cpu_cores); the equivalent CLI flags
# and env vars use hyphens and SCREAMING_SNAKE_CASE respectively:
# YAML: cpu_cores | Flag: --cpu-cores | Env: VIRTWORK_CPU_CORES

# ---------------------------------------------------------------------------
# Cluster connection
# ---------------------------------------------------------------------------

# Kubernetes namespace where VMs and supporting resources are created.
# Env: VIRTWORK_NAMESPACE | Flag: --namespace
# namespace: virtwork

# Path to kubeconfig file. When empty, virtwork uses in-cluster config
# (if running inside a pod) or falls back to ~/.kube/config.
# Env: VIRTWORK_KUBECONFIG | Flag: --kubeconfig
# kubeconfig: ""

# ---------------------------------------------------------------------------
# VM defaults (global — per-workload overrides are in the workloads section)
# ---------------------------------------------------------------------------

# Container disk image used as the boot volume for every VM.
# Set to a golden image with pre-installed packages for faster boot.
# Env: VIRTWORK_CONTAINER_DISK_IMAGE | Flag: --container-disk-image
# container_disk_image: quay.io/containerdisks/fedora:41

# Size of the additional data disk attached to storage-backed workloads
# (disk, database, chaos-disk).
# Env: VIRTWORK_DATA_DISK_SIZE | Flag: --data-disk-size
# data_disk_size: 10Gi

# Default CPU cores allocated to each VM.
# Env: VIRTWORK_CPU_CORES | Flag: --cpu-cores
# cpu_cores: 2

# Default memory allocated to each VM (Kubernetes quantity, e.g., 2Gi).
# Env: VIRTWORK_MEMORY | Flag: --memory
# memory: 2Gi

# ---------------------------------------------------------------------------
# Run behavior
# ---------------------------------------------------------------------------

# Print VM YAML specs and exit without creating any cluster resources.
# Env: VIRTWORK_DRY_RUN | Flag: --dry-run
# dry_run: false

# Enable DEBUG-level structured logging (default is INFO).
# Env: VIRTWORK_VERBOSE | Flag: --verbose
# verbose: false

# Wait for all VMs to reach the Ready condition after creation.
# Set to false (or use --no-wait) to skip readiness polling.
# Env: VIRTWORK_WAIT_FOR_READY | Flag: --no-wait (inverts this value)
# wait_for_ready: true

# Maximum seconds to wait for VM readiness before timing out.
# Env: VIRTWORK_TIMEOUT | Flag: --timeout
# timeout: 600

# ---------------------------------------------------------------------------
# SSH access (optional)
#
# When at least one SSH credential (password or key) is provided, virtwork
# creates an in-VM user account with the given username. When all SSH fields
# are empty, no user account is created and VMs are headless.
# ---------------------------------------------------------------------------

# Username for the in-VM SSH user account.
# Env: VIRTWORK_SSH_USER | Flag: --ssh-user
# ssh_user: virtwork

# Password for the SSH user (plain-text in the VM spec — prefer keys).
# Env: VIRTWORK_SSH_PASSWORD | Flag: --ssh-password
# ssh_password: ""

# List of SSH public keys injected into the VM's authorized_keys.
# In YAML, provide a list. Via env var, provide a comma-separated string.
# Via CLI, use --ssh-key (repeatable) or --ssh-key-file (path, repeatable).
# Env: VIRTWORK_SSH_AUTHORIZED_KEYS (comma-separated)
# Flag: --ssh-key / --ssh-key-file
# ssh_authorized_keys: []
# - ssh-ed25519 AAAAC3Nz... user@host
# - ssh-rsa AAAAB3NzaC1yc2E... user@host

# ---------------------------------------------------------------------------
# Audit
#
# Virtwork records each run in a local SQLite database for post-run analysis.
# ---------------------------------------------------------------------------

# Enable or disable audit tracking. Override with --no-audit to hard-disable.
# Env: VIRTWORK_AUDIT | Flag: --audit / --no-audit
# audit: true

# Path to the SQLite audit database file.
# In-cluster, mount a PVC and set to /data/virtwork.db.
# Env: VIRTWORK_AUDIT_DB | Flag: --audit-db
# audit_db: virtwork.db

# ---------------------------------------------------------------------------
# Per-workload overrides
#
# Each key under "workloads" is a workload name. Available workloads:
# chaos-disk, chaos-network, chaos-process, cpu, database, disk,
# memory, network, tps
#
# Every field is optional — unspecified fields inherit the global defaults.
# The "params" sub-map accepts string-valued, workload-specific tuning knobs.
# Workloads not listed here still run (unless filtered via --workloads flag).
# ---------------------------------------------------------------------------

# workloads:

# --- CPU stress workload ---
# Drives all allocated cores to 100% utilization.
# cpu:
# enabled: true
# vm_count: 1
# cpu_cores: 2
# memory: 2Gi
# No workload-specific params.

# --- Memory stress workload ---
# Allocates and touches memory to stress the VM's memory subsystem.
# memory:
# enabled: true
# vm_count: 1
# cpu_cores: 2
# memory: 2Gi
# No workload-specific params.

# --- Disk I/O workload ---
# Performs sequential/random I/O against the data disk.
# disk:
# enabled: true
# vm_count: 1
# cpu_cores: 2
# memory: 2Gi
# No workload-specific params.

# --- Database workload ---
# Runs a database benchmark against a local database instance.
# database:
# enabled: true
# vm_count: 1
# cpu_cores: 2
# memory: 4Gi
# No workload-specific params.

# --- Network throughput workload ---
# Client/server pair measuring network throughput.
# vm_count is per-role: 1 creates 1 server + 1 client = 2 VMs total.
# network:
# enabled: true
# vm_count: 1
# cpu_cores: 2
# memory: 2Gi
# No workload-specific params.

# --- TPS (transactions per second) workload ---
# HTTP-based throughput test between a server and client VM.
# vm_count is per-role: 1 creates 1 server + 1 client = 2 VMs total.
# tps:
# enabled: true
# vm_count: 1
# cpu_cores: 2
# memory: 2Gi
# params:
# Size of the HTTP test file. Accepts K/M/G suffixes.
# file-size: "10M"
# Number of test iterations to run.
# iterations: "30"
# Seconds per iteration.
# duration: "60"

# --- Chaos disk workload ---
# Fills a data disk to a target percentage, holds, releases, and repeats.
# chaos-disk:
# enabled: true
# vm_count: 1
# cpu_cores: 2
# memory: 2Gi
# params:
# Mountpoint of the data disk to fill.
# mount: "/mnt/data"
# Target fill percentage (0-100).
# fill-percent: "90"
# Seconds the disk is held at the target fill level.
# fill-sleep: "60"
# Seconds the disk is empty before refilling.
# release-sleep: "30"

# --- Chaos network workload ---
# Injects latency and packet loss via tc/netem on the VM's default interface.
# chaos-network:
# enabled: true
# vm_count: 1
# cpu_cores: 1
# memory: 1Gi
# params:
# Egress delay in milliseconds added via netem.
# latency-ms: "100"
# Egress packet drop rate (percentage, e.g., "5.0" for 5%).
# packet-loss-percent: "5.0"

# --- Chaos process workload ---
# Periodically sends a signal to a random non-essential process in the VM.
# chaos-process:
# enabled: true
# vm_count: 1
# cpu_cores: 2
# memory: 2Gi
# params:
# Signal sent to the randomly selected victim process.
# signal: "SIGTERM"
# Seconds between kills.
# interval: "30"
# Minimum PID considered eligible for the kill (filters out system processes).
# min-pid: "1000"
72 changes: 63 additions & 9 deletions internal/workloads/chaos_disk.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,22 @@
package workloads

import (
"fmt"

kubevirtv1 "kubevirt.io/api/core/v1"

"github.com/opdev/virtwork/internal/config"
"github.com/opdev/virtwork/internal/vm"
)

const chaosDiskScript = `#!/bin/bash
const chaosDiskScriptTemplate = `#!/bin/bash
set -euo pipefail

MOUNT_POINT="${CHAOS_DISK_MOUNT:-/mnt/data}"
FILL_PERCENT="${CHAOS_DISK_FILL_PERCENT:-90}"
MOUNT_POINT="%s"
FILL_PERCENT="%s"
FILL_FILE="${MOUNT_POINT}/chaos-disk-fill"
RELEASE_SLEEP="${CHAOS_DISK_RELEASE_SLEEP:-30}"
FILL_SLEEP="${CHAOS_DISK_FILL_SLEEP:-60}"
RELEASE_SLEEP="%s"
FILL_SLEEP="%s"

while true; do
TOTAL_KB=$(df -k "${MOUNT_POINT}" | awk 'NR==2 {print $2}')
Expand All @@ -37,12 +39,16 @@ while true; do
done
`

const chaosDiskSystemdUnit = `[Unit]
const chaosDiskSystemdUnitTemplate = `[Unit]
Description=Virtwork chaos-disk fill/release workload
After=network.target local-fs.target

[Service]
Type=simple
Environment="CHAOS_DISK_MOUNT=%s"
Environment="CHAOS_DISK_FILL_PERCENT=%s"
Environment="CHAOS_DISK_FILL_SLEEP=%s"
Environment="CHAOS_DISK_RELEASE_SLEEP=%s"
ExecStart=/usr/local/bin/chaos-disk.sh
Restart=always
RestartSec=10
Expand Down Expand Up @@ -76,6 +82,42 @@ func NewChaosDiskWorkload(
}
}

func (w *ChaosDiskWorkload) mount() string {
if w.Config.Params != nil {
if val, ok := w.Config.Params["mount"]; ok && val != "" {
return val
}
}
return "/mnt/data"
}

func (w *ChaosDiskWorkload) fillPercent() string {
if w.Config.Params != nil {
if val, ok := w.Config.Params["fill-percent"]; ok && val != "" {
return val
}
}
return "90"
}

func (w *ChaosDiskWorkload) fillSleep() string {
if w.Config.Params != nil {
if val, ok := w.Config.Params["fill-sleep"]; ok && val != "" {
return val
}
}
return "60"
}

func (w *ChaosDiskWorkload) releaseSleep() string {
if w.Config.Params != nil {
if val, ok := w.Config.Params["release-sleep"]; ok && val != "" {
return val
}
}
return "30"
}

// Name returns "chaos-disk".
func (w *ChaosDiskWorkload) Name() string {
return "chaos-disk"
Expand All @@ -84,21 +126,33 @@ func (w *ChaosDiskWorkload) Name() string {
// CloudInitUserdata returns cloud-init YAML that writes a fill/release script
// and a systemd service that runs it in a loop.
func (w *ChaosDiskWorkload) CloudInitUserdata() (string, error) {
mountPoint := w.mount()
script := fmt.Sprintf(chaosDiskScriptTemplate,
mountPoint,
w.fillPercent(),
w.releaseSleep(),
w.fillSleep())
unit := fmt.Sprintf(chaosDiskSystemdUnitTemplate,
mountPoint,
w.fillPercent(),
w.fillSleep(),
w.releaseSleep())

return w.BuildCloudConfig(CloudConfigOpts{
WriteFiles: []WriteFile{
{
Path: "/usr/local/bin/virtwork-disk-setup.sh",
Content: diskSetupScript("virtwork-chdisk", "/mnt/data"),
Content: diskSetupScript("virtwork-chdisk", mountPoint),
Permissions: "0755",
},
{
Path: "/usr/local/bin/chaos-disk.sh",
Content: chaosDiskScript,
Content: script,
Permissions: "0755",
},
{
Path: "/etc/systemd/system/virtwork-chaos-disk.service",
Content: chaosDiskSystemdUnit,
Content: unit,
Permissions: "0644",
},
},
Expand Down
Loading
Loading