var _ = Describe("SerialStep", func() { Describe("Perform", func() { It("performs them all in order and returns nil", func() { seq := make(chan int, 3) sequence := steps.NewSerial([]steps.Step{ &fakes.FakeStep{ PerformStub: func() error { seq <- 1 return nil }, }, &fakes.FakeStep{ PerformStub: func() error { seq <- 2 return nil }, }, &fakes.FakeStep{ PerformStub: func() error { seq <- 3 return nil }, }, }) result := make(chan error) go func() { result <- sequence.Perform() }() Eventually(seq).Should(Receive(Equal(1))) Eventually(seq).Should(Receive(Equal(2)))
func (transformer *Transformer) StepFor( logStreamer log_streamer.LogStreamer, action *models.Action, container garden.Container, externalIP string, ports []executor.PortMapping, logger lager.Logger, ) steps.Step { a := action.GetValue() switch actionModel := a.(type) { case *models.RunAction: return steps.NewRun( container, *actionModel, logStreamer.WithSource(actionModel.LogSource), logger, externalIP, ports, transformer.exportNetworkEnvVars, transformer.clock, ) case *models.DownloadAction: return steps.NewDownload( container, *actionModel, transformer.cachedDownloader, transformer.downloadLimiter, logStreamer.WithSource(actionModel.LogSource), logger, ) case *models.UploadAction: return steps.NewUpload( container, *actionModel, transformer.uploader, transformer.compressor, transformer.tempDir, logStreamer.WithSource(actionModel.LogSource), transformer.uploadLimiter, logger, ) case *models.EmitProgressAction: return steps.NewEmitProgress( transformer.StepFor( logStreamer, actionModel.Action, container, externalIP, ports, logger, ), actionModel.StartMessage, actionModel.SuccessMessage, actionModel.FailureMessagePrefix, logStreamer.WithSource(actionModel.LogSource), logger, ) case *models.TimeoutAction: return steps.NewTimeout( transformer.StepFor( logStreamer.WithSource(actionModel.LogSource), actionModel.Action, container, externalIP, ports, logger, ), time.Duration(actionModel.Timeout), logger, ) case *models.TryAction: return steps.NewTry( transformer.StepFor( logStreamer.WithSource(actionModel.LogSource), actionModel.Action, container, externalIP, ports, logger, ), logger, ) case *models.ParallelAction: subSteps := make([]steps.Step, len(actionModel.Actions)) for i, action := range actionModel.Actions { subSteps[i] = transformer.StepFor( logStreamer.WithSource(actionModel.LogSource), action, container, externalIP, ports, logger, ) } return steps.NewParallel(subSteps) case *models.CodependentAction: subSteps := make([]steps.Step, len(actionModel.Actions)) for i, action := range actionModel.Actions { subSteps[i] = transformer.StepFor( logStreamer.WithSource(actionModel.LogSource), action, container, externalIP, ports, logger, ) } errorOnExit := true return steps.NewCodependent(subSteps, errorOnExit) case *models.SerialAction: subSteps := make([]steps.Step, len(actionModel.Actions)) for i, action := range actionModel.Actions { subSteps[i] = transformer.StepFor( logStreamer, action, container, externalIP, ports, logger, ) } return steps.NewSerial(subSteps) } panic(fmt.Sprintf("unknown action: %T", action)) }
func (store *GardenStore) Run(logger lager.Logger, container executor.Container) error { logger = logger.Session("run", lager.Data{ "guid": container.Guid, }) logger.Info("started") defer logger.Info("finished") gardenContainer, err := store.lookup(logger, container.Guid) if err != nil { return err } logger.Debug("found-garden-container") if container.State != executor.StateCreated { logger.Debug("container-invalid-state-transition", lager.Data{ "current_state": container.State, "expected_state": executor.StateCreated, }) transitionErr := executor.ErrInvalidTransition result := executor.ContainerRunResult{ Failed: true, FailureReason: transitionErr.Error(), } err := store.transitionToComplete(logger, gardenContainer, result) if err != nil { logger.Error("failed-transition-to-complete", err) } return transitionErr } logStreamer := log_streamer.New( container.LogConfig.Guid, container.LogConfig.SourceName, container.LogConfig.Index, ) var setupStep, actionStep, monitorStep steps.Step if container.Setup != nil { setupStep = store.transformer.StepFor( logStreamer, container.Setup, gardenContainer, container.ExternalIP, container.Ports, logger.Session("setup"), ) } actionStep = store.transformer.StepFor( logStreamer, container.Action, gardenContainer, container.ExternalIP, container.Ports, logger.Session("action"), ) hasStartedRunning := make(chan struct{}, 1) if container.Monitor != nil { monitorStep = steps.NewMonitor( func() steps.Step { return store.transformer.StepFor( logStreamer, container.Monitor, gardenContainer, container.ExternalIP, container.Ports, logger.Session("monitor-run"), ) }, hasStartedRunning, logger.Session("monitor"), store.clock, logStreamer, time.Duration(container.StartTimeout)*time.Second, store.healthyMonitoringInterval, store.unhealthyMonitoringInterval, store.workPool, ) } var longLivedAction steps.Step if monitorStep != nil { longLivedAction = steps.NewCodependent([]steps.Step{actionStep, monitorStep}, false) } else { longLivedAction = actionStep // this container isn't monitored, so we mark it running right away hasStartedRunning <- struct{}{} } var step steps.Step if setupStep != nil { step = steps.NewSerial([]steps.Step{setupStep, longLivedAction}) } else { step = longLivedAction } store.runStepProcess(logger, step, hasStartedRunning, gardenContainer, container.Guid) return nil }