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{
示例#2
0
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))
}
示例#3
0
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
}