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
1 change: 1 addition & 0 deletions build/golden-image/Containerfile
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ RUN dnf install -y \
postgresql-server \
iproute-tc \
iptables-nft \
kernel-modules-extra \
netperf \
python3 \
&& dnf clean all \
Expand Down
3 changes: 2 additions & 1 deletion build/golden-image/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ The golden image is based on `quay.io/containerdisks/fedora:41` and includes all
- **python3** — HTTP file server for the tps workload's application-layer transfers
- **postgresql-server** — PostgreSQL database with pgbench (database workload)
- **procps-ng** — `ps`, `pkill`, `kill` for chaos-process
- **iproute-tc** — Traffic control (`tc`) and the `sch_netem` kernel module hooks used by the chaos-network workload to inject latency and packet loss
- **iproute-tc** — Traffic control (`tc`) used by the chaos-network workload to inject latency and packet loss
- **kernel-modules-extra** — Provides the `sch_netem` kernel module required by chaos-network; pre-installing means the cloud-init `dnf install` completes instantly (package already present) instead of fetching over the network
- **iptables-nft** — Firewall rules; reserved for future network partition / blackhole scenarios

Additional tools like `fallocate` and `dd` (used by chaos-disk) are already present in the base Fedora image.
Expand Down
2 changes: 1 addition & 1 deletion docs/chaos-workloads.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ workloads:

### Dependencies

The workload installs `iproute-tc` and loads the `sch_netem` kernel module on start. The base Fedora container disk has both available; the golden image (`build/golden-image/`) pre-installs `iproute-tc` to avoid the first-boot package install. `sch_netem` is loaded from the `kernel-modules-extra` package, which the cloud-init runs `dnf install` for on first boot.
The workload requires `iproute-tc` and the `sch_netem` kernel module. The golden image (`build/golden-image/`) pre-installs both `iproute-tc` and `kernel-modules-extra` (which provides `sch_netem`), so the cloud-init `dnf install` completes instantly (package already present) and no network fetch is needed. On the default Fedora container disk, cloud-init installs `iproute-tc` via `packages` and `kernel-modules-extra-$(uname -r)` via `runcmd`, which ensures the module version matches the running kernel. The start script runs `modprobe sch_netem` to load the module before applying the qdisc.

### Example

Expand Down
3 changes: 2 additions & 1 deletion internal/workloads/chaos_network.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,8 @@ func (w *ChaosNetworkWorkload) Name() string {
}

// CloudInitUserdata returns cloud-init YAML that configures tc/netem for network chaos
// injection via systemd. Assumes iproute-tc is pre-installed (golden image dependency).
// injection via systemd. The golden image pre-installs iproute-tc and kernel-modules-extra
// (sch_netem); the start script runs modprobe as a fallback for non-golden images.
func (w *ChaosNetworkWorkload) CloudInitUserdata() (string, error) {
startScript := fmt.Sprintf(chaosNetworkStartScript,
w.latencyMs(),
Expand Down
42 changes: 21 additions & 21 deletions internal/workloads/chaos_network_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
package workloads_test

import (
"strings"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"

Expand Down Expand Up @@ -72,32 +74,30 @@ var _ = Describe("ChaosNetworkWorkload", func() {
Expect(parsed).To(HaveKey("runcmd"))
runcmds := parsed["runcmd"].([]interface{})

foundKernelModules := false
foundDnf := false
foundDaemonReload := false
foundEnable := false
kernelModulesIdx := -1
enableIdx := -1
for i, cmd := range runcmds {
for _, cmd := range runcmds {
cmdSlice := cmd.([]interface{})
if len(cmdSlice) >= 3 {
if cmdSlice[0] == "bash" && cmdSlice[1] == "-c" {
cmdStr := cmdSlice[2].(string)
if cmdStr == "dnf install -y kernel-modules-extra-$(uname -r)" {
foundKernelModules = true
kernelModulesIdx = i
}
}
if cmdSlice[0] == "systemctl" && cmdSlice[1] == "enable" {
foundEnable = true
enableIdx = i
Expect(cmdSlice[2]).To(Equal("--now"))
if len(cmdSlice) >= 3 && cmdSlice[0] == "bash" && cmdSlice[1] == "-c" {
script, _ := cmdSlice[2].(string)
if strings.Contains(script, "kernel-modules-extra") {
foundDnf = true
Expect(script).To(ContainSubstring("$(uname -r)"),
"should install kernel-modules-extra matching the running kernel")
}
}
if len(cmdSlice) >= 2 && cmdSlice[0] == "systemctl" && cmdSlice[1] == "daemon-reload" {
foundDaemonReload = true
}
if len(cmdSlice) >= 3 && cmdSlice[0] == "systemctl" && cmdSlice[1] == "enable" {
foundEnable = true
Expect(cmdSlice[2]).To(Equal("--now"))
}
}
Expect(foundKernelModules).To(BeTrue(), "should install kernel-modules-extra for running kernel")
Expect(foundEnable).To(BeTrue(), "should have systemctl enable command")
Expect(kernelModulesIdx).To(
BeNumerically("<", enableIdx),
"kernel modules install should come before service enable")
Expect(foundDnf).To(BeTrue(), "should have dnf install kernel-modules-extra")
Expect(foundDaemonReload).To(BeTrue(), "should have systemctl daemon-reload")
Expect(foundEnable).To(BeTrue(), "should have systemctl enable --now")
})

It("should produce valid YAML", func() {
Expand Down
Loading