func main() { flag.Parse() //make the out dir logger.Component = "SIMULATOR" if outDir == "" { logger.Fatal("out.dir.unspecified") } err := os.MkdirAll(outDir, 0777) if err != nil { logger.Fatal("out.dir.creation.failed", err) } //set up logging outputFile, err := os.Create(filepath.Join(outDir, "simulator.log")) if err != nil { logger.Fatal("failed.to.create.simulator.log", err) } logger.Writer = io.MultiWriter(os.Stdout, outputFile) cleanup.Register(func() { outputFile.Sync() }) //compile the executor logger.Info("compiling.executor") output, err := exec.Command("go", "install", "github.com/cloudfoundry-incubator/simulator/game_executor").CombinedOutput() if err != nil { logger.Fatal("failed.to.compile.executor", string(output)) } //write info to the output dir writeInfo() //start etcd logger.Info("starting.etcd", etcdNodes) etcd = etcdstorerunner.NewETCDClusterRunner(4001, etcdNodes) etcd.Start() //set up the bbs pool := workerpool.NewWorkerPool(50) etcdAdapter = etcdstoreadapter.NewETCDStoreAdapter(etcd.NodeURLS(), pool) etcdAdapter.Connect() bbs = Bbs.New(etcdAdapter, timeprovider.NewTimeProvider()) //monitor etcd monitorETCD() //start executors startExecutors() cleanup.Register(func() { logger.Info("stopping.etcd", etcdNodes) etcd.Stop() }) //run the simulator runSimulation() cleanup.Exit(0) }
func sleepForRunInterval() { runSleep := strings.Split(*runSleepRange, ",") minRunSleep, err := strconv.Atoi(runSleep[0]) if err != nil { logger.Fatal("run.sleep.min.parse.fatal", err) } maxRunSleep, err := strconv.Atoi(runSleep[1]) if err != nil { logger.Fatal("run.sleep.min.parse.fatal", err) } sleepForARandomInterval("sleep.run", minRunSleep, maxRunSleep) }
func sleepForContainerCreationInterval() { containerCreationSleep := strings.Split(*containerCreationSleepRange, ",") minContainerCreationSleep, err := strconv.Atoi(containerCreationSleep[0]) if err != nil { logger.Fatal("container.creation.sleep.min.parse.fatal", err) } maxContainerCreationSleep, err := strconv.Atoi(containerCreationSleep[1]) if err != nil { logger.Fatal("container.creation.sleep.min.parse.fatal", err) } sleepForARandomInterval("sleep.create", minContainerCreationSleep, maxContainerCreationSleep) }
func convergeRunOnces(bbs Bbs.ExecutorBBS) { statusChannel, releaseLock, err := bbs.MaintainConvergeLock(*convergenceInterval, *executorID) if err != nil { logger.Fatal("executor.converge-lock.acquire-failed", err) } tasks.Add(1) for { select { case locked, ok := <-statusChannel: if !ok { tasks.Done() return } if locked { t := time.Now() logger.Info("converging") bbs.ConvergeRunOnce(*timeToClaimRunOnce) logger.Info("converged", time.Since(t)) } else { logger.Error("lost.convergence.lock") } case <-stop: releaseLock <- nil } } }
func main() { flag.Parse() cleanup.Register(func() { logger.Info("executor.shuttingdown") close(stop) tasks.Wait() logger.Info("executor.shutdown") }) logger.Component = fmt.Sprintf("EXECUTOR %s", *executorID) lock = &sync.Mutex{} currentMemory = *maxMemory etcdAdapter := etcdstoreadapter.NewETCDStoreAdapter( strings.Split(*etcdCluster, ","), workerpool.NewWorkerPool(10), ) err := etcdAdapter.Connect() if err != nil { logger.Fatal("etcd.connect.fatal", err) } tasks = &sync.WaitGroup{} stop = make(chan bool) bbs := Bbs.New(etcdAdapter, timeprovider.NewTimeProvider()) ready := make(chan bool, 1) err = maintainPresence(bbs, ready) if err != nil { logger.Fatal("executor.initializing-presence.failed", err) } go handleRunOnces(bbs) go convergeRunOnces(bbs) <-ready logger.Info("executor.up") select {} }
func monitorETCD() { outputFile, err := os.Create(filepath.Join(outDir, "etcdstats.log")) if err != nil { logger.Fatal("etcd.log.creation.failure", err) } cleanup.Register(func() { outputFile.Sync() }) go monitorRunOnces(outputFile) }
func startExecutors() { executorOutput, err := os.Create(filepath.Join(outDir, "executors.log")) if err != nil { logger.Fatal("executor.output.file.create.failed", err) } cleanup.Register(func() { executorOutput.Sync() }) logger.Info("starting.all.executors", nExecutors) allExecutorsStarted := &sync.WaitGroup{} for index := 1; index <= nExecutors; index++ { allExecutorsStarted.Add(1) go startAndMonitorExecutor(index, executorOutput, allExecutorsStarted) } allExecutorsStarted.Wait() logger.Info("started.all.executors", nExecutors) }
func maintainPresence(bbs Bbs.ExecutorBBS, ready chan<- bool) error { p, statusChannel, err := bbs.MaintainExecutorPresence(*heartbeatInterval, *executorID) if err != nil { ready <- false return err } tasks.Add(1) go func() { for { select { case locked, ok := <-statusChannel: if locked && ready != nil { ready <- true ready = nil } if !locked && ok { tasks.Done() logger.Fatal("maintain.presence.fatal", err) } if !ok { tasks.Done() return } case <-stop: p.Remove() tasks.Done() } } }() return nil }