subStep2 = &fakes.FakeStep{ PerformStub: func() error { running.Done() running.Wait() thingHappened <- true return nil }, CancelStub: func() { cancelled <- true }, } }) Describe("Perform", func() { JustBeforeEach(func() { step = steps.NewCodependent([]steps.Step{subStep1, subStep2}, errorOnExit) }) It("performs its substeps in parallel", func() { err := step.Perform() Expect(err).NotTo(HaveOccurred()) Eventually(thingHappened).Should(Receive()) Eventually(thingHappened).Should(Receive()) }) Context("when one of the substeps fails", func() { disaster := errors.New("oh no!") BeforeEach(func() { subStep1 = &fakes.FakeStep{
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 }