How to Create Custom Chaos Experiment Scenarios for New Targets in ChaosBlade

To create custom chaos experiment scenarios for new targets in ChaosBlade, implement the spec.Executor interface with Create, Destroy, and optional Query methods, define a command model spec in exec/<target>/spec.go, and register the executor in cli/cmd/exp.go using the createExecutorKey function.

ChaosBlade models every chaos experiment as a target → action → flags triple. Extending the framework to support new infrastructure or services requires implementing the executor interface and registering your components in the CLI. This guide walks through the exact source code locations and implementation patterns used in the chaosblade-io/chaosblade repository to add a custom target like myservice.

Step 1: Define the Command Model Spec

Create exec/<target>/spec.go to declare the target's metadata, default flags, and examples. This file must implement the spec.ExpModelCommandSpec interface, which provides the CLI with the target's name and usage information.

package myservice

import "github.com/chaosblade-io/chaosblade-spec-go/spec"

type CommandModelSpec struct {
    spec.BaseExpModelCommandSpec
}

func NewCommandModelSpec() spec.ExpModelCommandSpec {
    return &CommandModelSpec{
        spec.BaseExpModelCommandSpec{
            ExpActions: []spec.ExpActionCommandSpec{},
            ExpFlags: []spec.ExpFlagSpec{
                &spec.ExpFlag{
                    Name: "endpoint",
                    Desc: "myservice endpoint (host:port)",
                },
            },
        },
    }
}

func (*CommandModelSpec) Name() string        { return "myservice" }
func (*CommandModelSpec) ShortDesc() string   { return "MyService experiment" }
func (*CommandModelSpec) LongDesc() string    { return "Chaos experiments for MyService" }
func (*CommandModelSpec) Example() string    {
    return "blade create myservice latency --delay 1000 --endpoint 127.0.0.1:8080"
}

The Example() method returns the command string users will run, while ExpFlags defines common flags available to all actions under this target.

Step 2: Implement the Executor Interface

Create exec/<target>/executor.go to handle the actual chaos injection and cleanup. The executor must satisfy the spec.Executor interface defined in the ChaosBlade specification, which requires Create, Destroy, and optional Query methods.

package myservice

import (
    "context"

    "github.com/chaosblade-io/chaosblade-spec-go/spec"
    "github.com/chaosblade-io/chaosblade-spec-go/log"
)

type Executor struct{}

// NewExecutor returns an executor that implements spec.Executor.
func NewExecutor() spec.Executor { return &Executor{} }

func (e *Executor) Name() string { return "myservice" }

func (e *Executor) SetChannel(c spec.Channel) {}

func (e *Executor) Create(ctx context.Context, model *spec.ExpModel) *spec.Response {
    // Parse flags from the experiment model
    delay := model.ActionFlags["delay"]
    endpoint := model.ActionFlags["endpoint"]
    
    // Insert real injection logic here (e.g., call myservice API)
    log.Infof(ctx, "Injecting latency %s ms to %s", delay, endpoint)
    return spec.ReturnSuccess("")
}

func (e *Executor) Destroy(ctx context.Context, model *spec.ExpModel) *spec.Response {
    // Cleanup logic to remove the chaos injection
    log.Infof(ctx, "Removing latency injection from %s", model.ActionFlags["endpoint"])
    return spec.ReturnSuccess("")
}

func (e *Executor) Query(ctx context.Context, model *spec.ExpModel) *spec.Response {
    // Optional: return current status of the experiment
    return spec.ReturnSuccess("")
}

The Create method receives an ExpModel containing parsed flags from the CLI and returns a spec.Response indicating success or failure.

Step 3: Register the Target in the CLI

In cli/cmd/exp.go, register the executor so the blade create command can resolve it. The registration uses createExecutorKey(target, actionTarget, action) to build a unique lookup key for the executors map.

Add the following initialization code where target specs are loaded:

myserviceSpec := myservice.NewCommandModelSpec()
myserviceExecutor := myservice.NewExecutor()

// Register the target command
ec.registerExpCommand(myserviceSpec, "")

// Map the specific action to the executor
ec.executors[createExecutorKey("myservice", "", "latency")] = myserviceExecutor

If your target implements dynamic spec loading, this registration happens automatically when the action command is created (see lines 65‑70 in cli/cmd/exp.go). The createExecutorKey function concatenates the target name, action target, and action to generate the map key used by GetExecutor.

Step 4: Create YAML Scenario Specifications

Write a YAML file describing your target's actions, flags, and matchers. The blade CLI reads these definitions from chaosblade.spec.yaml, which is generated by merging all scenario files.

Create scenario/myservice.yaml:

name: myservice
shortDesc: MyService experiment
longDesc: |
  Chaos experiments for MyService, such as injecting latency,
  CPU overload, or killing processes.
actions:
  - name: latency
    shortDesc: Add network latency
    longDesc: |
      Injects a fixed latency (ms) to the communication channel of the target
      MyService instance.
    flags:
      - name: delay
        desc: "latency in milliseconds"
        required: true
      - name: endpoint
        desc: "myservice endpoint (host:port)"
        required: true
    matchers: []   # optional, for complex targeting logic

Place this file in a scenario directory that will be processed by the spec builder tool.

Step 5: Build and Test the Custom Target

Rebuild the aggregated specification to include your new target's YAML definitions. Run the spec merger tool from the repository root:

go run ./build/spec <scenario-dir> <target-dir>

For example, if your YAML is in ./scenario and you want the output in the current directory:

go run ./build/spec scenario ./

This executes the merging logic in build/spec/spec.go, which writes the combined chaosblade.spec.yaml file containing all registered targets. The blade CLI reads this file at startup to populate available commands.

Test your implementation by creating an experiment:

blade create myservice latency --delay 2000 --endpoint 127.0.0.1:8080 --duration 30s

The CLI parses the flags, builds an ExpModel via createExpModel in exp.go, looks up your executor using the generated key, and invokes the Create method with the experiment context.

Summary

  • Define the spec: Implement spec.ExpModelCommandSpec in exec/<target>/spec.go to declare target metadata and default flags.
  • Implement the executor: Create exec/<target>/executor.go satisfying the spec.Executor interface with Create, Destroy, and Query methods.
  • Register with CLI: Modify cli/cmd/exp.go to register the spec and add the executor to the executors map using createExecutorKey.
  • Provide YAML specs: Define actions and flags in YAML files processed by build/spec/spec.go to generate chaosblade.spec.yaml.
  • Rebuild specs: Run go run ./build/spec to regenerate the master specification when adding or modifying YAML scenarios.

Frequently Asked Questions

What interface must a custom target executor implement?

Your executor must implement the spec.Executor interface from chaosblade-spec-go. This requires three methods: Create(ctx context.Context, model *spec.ExpModel) *spec.Response for injection logic, Destroy for cleanup and rollback, and Query for status checking. Each method receives the experiment model containing parsed CLI flags and must return a response indicating success or failure.

How does ChaosBlade map CLI commands to executors?

The GetExecutor function in cli/cmd/exp.go builds a lookup key using createExecutorKey(target, actionTarget, action), which concatenates the target name, action target, and action into a unique string. This key retrieves the appropriate executor from the ec.executors map. When you run blade create myservice latency, the CLI generates the key for the myservice target and latency action, then invokes the matching executor's Create method.

Where should YAML scenario files be placed for custom targets?

Place YAML files in any directory of your choice, then pass this directory as the first argument to the spec builder: go run ./build/spec <scenario-dir> <output-dir>. The tool merges all YAML files in the scenario directory into a single chaosblade.spec.yaml file that the blade CLI reads at runtime to discover available actions and their flags.

Is rebuilding the spec required for every code change?

No. Rebuilding the specification via build/spec/spec.go is only necessary when adding new YAML scenario files or modifying action definitions. Changes to Go source code in your executor or spec files require recompiling the blade binary itself, as the CLI loads executor implementations directly from compiled code, while the YAML specs provide metadata for CLI argument parsing.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →