func NewRand(name string) *rand.Rand {
	source := fmt.Sprintf("%s-%d", name, Seed())
	image := sha1.Sum([]byte(source))
	b := bytes.NewReader(image[:])
	n, err := realrand.Int(b, big.NewInt(math.MaxInt64))
	if err != nil {
		log.Fatalf("Bug in seed derivation: %s", err)
	}
	log.Debugf("Seed for %v (source %v) is %v", name, source, n.Int64())
	return rand.New(rand.NewSource(n.Int64()))
}
Beispiel #2
0
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()
}
Beispiel #3
0
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()
}