feat: add dual-host IM pressure test tool
This commit is contained in:
@@ -0,0 +1,146 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
log.SetFlags(log.LstdFlags | log.Lmicroseconds | log.LUTC)
|
||||
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
|
||||
defer stop()
|
||||
if len(os.Args) < 2 {
|
||||
usage()
|
||||
os.Exit(2)
|
||||
}
|
||||
var err error
|
||||
switch os.Args[1] {
|
||||
case "prepare":
|
||||
err = prepareCommand(ctx, os.Args[2:])
|
||||
case "verify":
|
||||
err = verifyCommand(ctx, os.Args[2:])
|
||||
case "coordinator":
|
||||
err = coordinatorCommand(ctx, os.Args[2:])
|
||||
case "agent":
|
||||
err = agentCommand(ctx, os.Args[2:])
|
||||
case "merge":
|
||||
err = mergeCommand(os.Args[2:])
|
||||
case "collect":
|
||||
err = collectCommand(ctx, os.Args[2:])
|
||||
default:
|
||||
usage()
|
||||
os.Exit(2)
|
||||
}
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func prepareCommand(ctx context.Context, args []string) error {
|
||||
fs := flag.NewFlagSet("prepare", flag.ContinueOnError)
|
||||
configPath := fs.String("config", "loadtest/im-pressure/config.example.json", "JSON configuration path")
|
||||
manifestPath := fs.String("manifest", "loadtest/im-pressure/manifest.json", "manifest output path")
|
||||
if err := fs.Parse(args); err != nil {
|
||||
return err
|
||||
}
|
||||
cfg, err := loadConfig(*configPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return runPrepare(ctx, cfg, *manifestPath)
|
||||
}
|
||||
|
||||
func verifyCommand(ctx context.Context, args []string) error {
|
||||
fs := flag.NewFlagSet("verify", flag.ContinueOnError)
|
||||
configPath := fs.String("config", "loadtest/im-pressure/config.example.json", "JSON configuration path")
|
||||
manifestPath := fs.String("manifest", "loadtest/im-pressure/manifest.json", "manifest path")
|
||||
if err := fs.Parse(args); err != nil {
|
||||
return err
|
||||
}
|
||||
cfg, err := loadConfig(*configPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
manifest, err := loadManifest(*manifestPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
apiKey, err := cfg.apiKey()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return runVerify(ctx, cfg, manifest, newAPIClient(cfg, apiKey))
|
||||
}
|
||||
|
||||
func coordinatorCommand(ctx context.Context, args []string) error {
|
||||
fs := flag.NewFlagSet("coordinator", flag.ContinueOnError)
|
||||
listen := fs.String("listen", ":8090", "coordinator listen address")
|
||||
runID := fs.String("run-id", "", "unique run ID, max 24 characters")
|
||||
scenario := fs.String("scenario", "", "p2p, group, or mixed")
|
||||
output := fs.String("output", "loadtest/im-pressure/results/coordinator.json", "coordinator result path")
|
||||
expected := fs.Int("expected-agents", 2, "number of agents")
|
||||
delay := fs.Duration("start-delay", 30*time.Second, "delay after all agents are ready")
|
||||
if err := fs.Parse(args); err != nil {
|
||||
return err
|
||||
}
|
||||
return runCoordinator(ctx, *listen, *runID, *scenario, *output, *expected, *delay)
|
||||
}
|
||||
|
||||
func agentCommand(ctx context.Context, args []string) error {
|
||||
fs := flag.NewFlagSet("agent", flag.ContinueOnError)
|
||||
configPath := fs.String("config", "loadtest/im-pressure/config.example.json", "JSON configuration path")
|
||||
manifestPath := fs.String("manifest", "loadtest/im-pressure/manifest.json", "manifest path")
|
||||
machine := fs.String("machine", "", "a or b")
|
||||
coordinatorURL := fs.String("coordinator", "", "coordinator base URL")
|
||||
output := fs.String("output", "loadtest/im-pressure/results/agent-summary.json", "agent result path")
|
||||
metricsListen := fs.String("metrics-listen", ":9105", "Prometheus listen address; empty disables it")
|
||||
if err := fs.Parse(args); err != nil {
|
||||
return err
|
||||
}
|
||||
if *coordinatorURL == "" {
|
||||
return fmt.Errorf("--coordinator is required")
|
||||
}
|
||||
cfg, err := loadConfig(*configPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
manifest, err := loadManifest(*manifestPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return runAgent(ctx, cfg, manifest, *machine, *coordinatorURL, *output, *metricsListen)
|
||||
}
|
||||
|
||||
func mergeCommand(args []string) error {
|
||||
fs := flag.NewFlagSet("merge", flag.ContinueOnError)
|
||||
a := fs.String("a", "loadtest/im-pressure/results/agent-a-summary.json", "machine A summary")
|
||||
b := fs.String("b", "loadtest/im-pressure/results/agent-b-summary.json", "machine B summary")
|
||||
output := fs.String("output", "loadtest/im-pressure/results/report.json", "combined report")
|
||||
if err := fs.Parse(args); err != nil {
|
||||
return err
|
||||
}
|
||||
return runMerge(*a, *b, *output)
|
||||
}
|
||||
|
||||
func collectCommand(ctx context.Context, args []string) error {
|
||||
fs := flag.NewFlagSet("collect", flag.ContinueOnError)
|
||||
var urls namedURLs
|
||||
fs.Var(&urls, "url", "repeatable name=https://host/metrics source")
|
||||
output := fs.String("output", "loadtest/im-pressure/results/metrics.jsonl", "snapshot output")
|
||||
interval := fs.Duration("interval", 5*time.Second, "collection interval")
|
||||
duration := fs.Duration("duration", 10*time.Minute, "collection duration")
|
||||
if err := fs.Parse(args); err != nil {
|
||||
return err
|
||||
}
|
||||
return runCollector(ctx, urls, *output, *interval, *duration)
|
||||
}
|
||||
|
||||
func usage() {
|
||||
fmt.Fprintln(os.Stderr, "usage: im-pressure <prepare|verify|coordinator|agent|merge|collect> [flags]")
|
||||
}
|
||||
Reference in New Issue
Block a user