func scriptDir() string { executable, err := osext.Executable() if err != nil { log.Fatal(err) } dir := filepath.Dir(executable) return dir }
func AfterParse() { conf.args = flag.Args() if conf.seed == 0 { conf.seed = randomSeed() } if conf.nodeCount < 2 { log.Fatal("You need at least two agents") } if conf.sqlcluster == "" { conf.sqlcluster = sqlclusterPath() if conf.sqlcluster == "" { log.Fatalf("No `sqlcluster' binary provided, and could not find one heuristically. Please provide a `-r <sqlcluster>' argument, or move your stripe-ctf.com/sqlcluster Go package into your GOPATH.", scriptDir()) } else { log.Printf("Found sqlcluster binary at %s", conf.sqlcluster) } } if conf.containerRoot == "" { conf.containerRoot = conf.root } if conf.containerIds == "" { conf.parsedContainerIds = make([]string, 0) } else { conf.parsedContainerIds = strings.Split(conf.containerIds, ",") } log.SetVerbose(conf.verbose) log.Printf("Using seed %v", conf.seed) // Always seed the default RNG. It controls comparatively little, so // don't worry about exposing it rand.Seed(randomSeed()) conf.wg = exit.NewWaitGroup() conf.gotRequest = make(chan int, 1) recordConfig() }
func main() { flag.Usage = func() { fmt.Fprintf(os.Stderr, ` Usage: %s [options] [...args] Octopus will run your sqlcluster and issue queries to it. It simulates a lossy network, and to make things even more fun, will turn loose the following chaotic monkeys: NET MONKEYS - latency: adjusts base latency between nodes - jitter: adjusts latency variance between nodes - lagsplit: spikes latency along a network partition - link: destroys individual links between nodes - netsplit: destroys links along a network partition NODE MONKEYS - freeze: stops nodes (by sending SIGTSTP) - murder: ruthlessly murders nodes (by sending SIGTERM) Any positional arguments given to Octopus will be passed through to SQLCluster. This should be mostly useful for passing a -v flag, like so: ./octopus -- -v OPTIONS: `, os.Args[0]) flag.PrintDefaults() } state.AddFlags() flag.Parse() state.AfterParse() // Handle SIGINT sigchan := make(chan os.Signal) signal.Notify(sigchan, syscall.SIGINT, syscall.SIGTERM) d := director.NewDirector() if state.Dryrun() { d.Dryrun() return } // Create the working directory if err := os.MkdirAll(state.Root(), os.ModeDir|0755); err != nil { log.Fatal(err) } d.Start() go func() { select { case <-sigchan: log.Println("Terminating due to signal") case <-state.WaitGroup().Quit: // Someone else requested an exit case <-time.After(state.Duration()): // Time's up! log.Printf("The allotted %s have elapsed. Exiting!", state.Duration()) } state.WaitGroup().Exit() }() h := harness.New(d.Agents()) h.Start() d.StartMonkeys() <-state.WaitGroup().Quit if state.Write() != "" { results := state.JSONResults() if err := ioutil.WriteFile(state.Write(), results, 0755); err != nil { log.Fatalf("Could not write resuts: %s", err) } } else { results := state.PrettyPrintResults() log.Println(results) } state.WaitGroup().Exit() }
func EnsureAbsent(path string) { err := os.Remove(path) if err != nil && !os.IsNotExist(err) { log.Fatal(err) } }