How the ChaosBlade Experiment Model Works Internally: Target-Action-Flag Architecture

ChaosBlade represents every chaos experiment as a target-action-flag triple that maps to a SQLite record, enabling reversible conversion between CLI commands and persisted experiment state.

The chaosblade-io/chaosblade repository implements a unified experiment model that decouples user-facing CLI syntax from internal execution logic. Understanding how the target-action-flag pattern persists in the data layer and reconstructs at runtime clarifies how ChaosBlade creates, destroys, and tracks experiments across Docker, Kubernetes, and host environments.

Understanding the Target-Action-Flag Triple

The ChaosBlade experiment model consists of three hierarchical components that define what resource to attack, which fault to inject, and how to parameterize that fault.

Target: The Resource Type

The target specifies the primary resource category under test. Valid values include docker, k8s, network, cpu, or disk. Internally, this maps to spec.ExpModel.Target and persists in the SQLite experiment table as the command column.

Action: The Specific Fault

The action defines the precise failure mode to inject against the target. Examples include delay (network latency), load (CPU stress), or remove (container deletion). This value populates spec.ExpModel.ActionName and stores as the sub_command column in the database.

Flag: Parameter Key-Value Pairs

Flags provide action-specific configuration through command-line key-value pairs such as --time=3000 or --interface=eth0. The CLI collects these into spec.ExpModel.ActionFlags (a map[string]string), serializes them to a raw string for storage in the flag column, and parses them back during retrieval.

Data Layer Representation in SQLite

ChaosBlade persists experiments using a lightweight SQLite backend defined in data/experiment.go.

The ExperimentModel Struct

The ExperimentModel struct maps directly to the database schema:

type ExperimentModel struct {
    Uid        string // unique ID
    Command    string // target (e.g., "docker")
    SubCommand string // action (e.g., "remove")
    Flag       string // raw flag string, e.g. "--time=3000 --interface=eth0"
    Status     string
    Error      string
    CreateTime string
    UpdateTime string
}

Persistence and Retrieval Flow

The data layer handles bidirectional conversion between structured models and raw storage:

  • InsertingInsertExperimentModel writes the Flag string directly to the database without parsing.
  • QueryingQueryExperimentModelsByCommand retrieves the raw flag string, then delegates to spec.ConvertCommandsToExpModel to reconstruct the ExpModel.

CLI to Model Conversion

When users execute blade create, the CLI constructs an ExpModel from Cobra command flags.

Building the Model from CLI Input

The createExpModel function in cli/cmd/exp.go transforms CLI input into the internal representation:

func createExpModel(target, scope, actionName string, cmd *cobra.Command) *spec.ExpModel {
    expModel := &spec.ExpModel{
        Target:      target,
        Scope:       scope,
        ActionName:  actionName,
        ActionFlags: make(map[string]string, 0),
    }

    // Collect all non-false flag values from the cobra.Command
    cmd.Flags().VisitAll(func(flag *pflag.Flag) {
        if flag.Value.String() == "false" { return }
        expModel.ActionFlags[flag.Name] = flag.Value.String()
    })
    return expModel
}

Parsing Raw Flag Strings

The external chaosblade-spec-go module provides the reverse conversion. The ConvertCommandsToExpModel function in spec/convert.go parses stored flag strings:

// ConvertCommandsToExpModel parses the raw flag string and returns a fully-filled ExpModel.
//   action  – the sub-command (e.g. "delay")
//   target  – the primary command (e.g. "network")
//   flags   – raw flag string, e.g. "--time=3000 --interface=eth0"
func ConvertCommandsToExpModel(action, target, flags string) *ExpModel {
    // 1. split flags on spaces while respecting quoted values
    // 2. support both "--key=value" and "--key value"
    // 3. populate map[string]string ActionFlags
    // 4. return &ExpModel{Target: target, ActionName: action, ActionFlags: parsed}
}

Validation tests in cli/cmd/destroy_test.go confirm the parsing logic:

got := spec.ConvertCommandsToExpModel("network delay", "docker",
        "--time=3000 --interface=eth0")

This produces:

&spec.ExpModel{
    Target:      "docker",
    ActionName:  "network delay",
    ActionFlags: map[string]string{"time":"3000","interface":"eth0"},
}

Persistence and Retrieval in Practice

Creating Experiments

The createExperiment function in cli/cmd/create.go orchestrates persistence:

expModel := createExpModel(target, scope, actionCommandSpec.Name(), cmd)
uid, err := GetDS().InsertExperimentModel(&data.ExperimentModel{
    Uid:        uuid.NewString(),
    Command:    target,
    SubCommand: actionCommandSpec.Name(),
    Flag:       model2FlagString(expModel.ActionFlags), // joins map into raw string
    Status:     data.StatusPrepared,
})

The model2FlagString helper serializes the flag map to "--key=value …" format before storage.

Destroying Experiments

The destroy flow reverses the process. In cli/cmd/destroy.go, getExecutorAndExpModelByRecord retrieves and reconstructs the model:

record, _ := GetDS().QueryExperimentModelByUid(uid)
expModel := spec.ConvertCommandsToExpModel(
    record.SubCommand, // action
    record.Command,    // target
    record.Flag)       // raw flag string

// Pass expModel to the appropriate executor
executor, _ := GetExecutor(expModel.Target)
executor.Exec(uid, ctx, expModel)

Execution Path and Flag Iteration

Concrete executors receive the reconstructed ExpModel and translate ActionFlags into system commands. For example, in exec/docker/executor.go:

for k, v := range model.ActionFlags {
    argsArray = append(argsArray, fmt.Sprintf("--%s=%s", k, v))
}

This iteration constructs the final ChaosBlade command line, ensuring that flags specified during creation (e.g., --container-id=abc123) propagate accurately through the entire lifecycle.

Summary

  • ChaosBlade experiment model uses a target-action-flag triple to define chaos experiments consistently across CLI, storage, and execution layers.
  • Data persistence stores the raw flag string in SQLite (data/experiment.go), while target and action map to command and sub_command columns.
  • Model conversion relies on createExpModel (CLI → struct) and spec.ConvertCommandsToExpModel (string → struct) to maintain bidirectional integrity.
  • Lifecycle management creates experiments via cli/cmd/create.go, retrieves them via cli/cmd/destroy.go, and executes them through target-specific executors that iterate over ActionFlags.

Frequently Asked Questions

How does ChaosBlade store experiment flags in the database?

ChaosBlade serializes the ActionFlags map to a raw string (e.g., "--time=3000 --interface=eth0") and stores it in the flag column of the SQLite experiment table defined in data/experiment.go. The target and action are stored separately in the command and sub_command columns.

What happens when I run blade destroy?

The destroy command queries the SQLite database for the experiment UID, retrieves the raw target-action-flag data, and calls spec.ConvertCommandsToExpModel in the external chaosblade-spec-go module to reconstruct the ExpModel. This model is then passed to the appropriate executor (e.g., Docker or Kubernetes) to trigger the recovery logic.

Where is the target-action-flag parsing logic implemented?

Core parsing logic resides in the external module chaosblade-spec-go within spec/convert.go. The function ConvertCommandsToExpModel handles splitting flag strings, respecting quoted values, and supporting both --key=value and --key value syntax. The ChaosBlade repository itself manages the CLI-to-model conversion in cli/cmd/exp.go via createExpModel.

Can I manually construct an experiment model programmatically?

Yes. You can construct an ExpModel directly by populating the Target, ActionName, and ActionFlags fields, then pass it to the data layer. For example, calling spec.ConvertCommandsToExpModel("delay", "network", "--time=3000") returns a fully populated model that can be inserted via InsertExperimentModel in data/experiment.go or executed directly through the appropriate executor.

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 →