package cmd
import (
"context"
"math/rand"
"os"
"os/signal"
"syscall"
"github.com/Pallinder/go-randomdata"
toxiproxy "github.com/Shopify/toxiproxy/client"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"github.com/gitpod-io/gitpod/blowtorch/pkg/dart"
)
var ablazeCmd = &cobra.Command{
Use: "ablaze",
Short: "Adds a toxiproxy intermediate for a random service, adds some random toxics and restarts all pods",
Args: cobra.ExactArgs(0),
Run: func(cmd *cobra.Command, args []string) {
cfg, ns, err := getKubeconfig()
if err != nil {
log.WithError(err).Fatal("cannot get Kubernetes client config")
}
client, err := kubernetes.NewForConfig(cfg)
if err != nil {
log.WithError(err).Fatal("cannot connect to Kubernetes")
}
services, err := client.CoreV1().Services(ns).List(context.Background(), metav1.ListOptions{})
if err != nil {
log.WithError(err).Fatal("cannot list services")
}
if len(services.Items) == 0 {
log.WithError(err).Fatal("no services available")
}
srv := services.Items[rand.Intn(len(services.Items))]
targetService := srv.Name
log.WithField("targetService", targetService).Info("found service to mess with")
defer func() {
err = dart.Remove(cfg, ns, targetService)
if err != nil {
log.WithError(err).Fatal("cannot remove toxiproxy")
}
}()
tpc, err := dart.Inject(cfg, ns, targetService)
if err != nil {
log.WithError(err).Fatal("cannot inject toxiproxy")
}
defer tpc.Close()
proxies, err := tpc.Proxies()
if err != nil {
log.WithError(err).Fatal("cannot list proxies")
}
for pn, px := range proxies {
err = addRandomToxic(pn, px)
if err != nil {
log.WithError(err).WithField("proxy", pn).Fatal("cannot add random toxic")
}
}
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM)
log.Info("🎯 blowtorch up and running. Stop with SIGINT or CTRL+C")
<-sigChan
log.Info("received SIGINT - shutting down")
},
}
var (
toxicTypes = []string{"latency", "bandwidth", "slow_close", "timeout", "slicer"}
toxicStreams = []string{"upstream", "downstream"}
)
func addRandomToxic(name string, proxy *toxiproxy.Proxy) error {
var (
tname = randomdata.SillyName()
ttype = toxicTypes[rand.Intn(len(toxicTypes))]
tstream = toxicStreams[rand.Intn(len(toxicStreams))]
tattr toxiproxy.Attributes = make(toxiproxy.Attributes)
)
switch ttype {
case "latency":
tattr["latency"] = rand.Intn(30000)
tattr["jitter"] = rand.Intn(5000)
case "bandwidth":
tattr["rate"] = rand.Intn(1024)
case "slow_close":
tattr["delay"] = rand.Intn(5000)
case "timeout":
tattr["timeout"] = rand.Intn(5000)
case "slicer":
tattr["average_size"] = rand.Intn(256) + 1
tattr["size_variation"] = rand.Intn(64)
tattr["delay"] = rand.Intn(5000)
}
_, err := proxy.AddToxic(tname, ttype, tstream, 1.0, tattr)
if err != nil {
return err
}
log.WithFields(log.Fields{
"proxy": name,
"name": tname,
"type": ttype,
"attrs": tattr,
"stream": tstream,
}).Info("adding toxic")
return nil
}
func init() {
rootCmd.AddCommand(ablazeCmd)
}