github.com/pf-qiu/concourse/v6@v6.7.3-0.20201207032516-1f455d73275f/atc/engine/builder.go (about)

     1  package engine
     2  
     3  import (
     4  	"encoding/json"
     5  
     6  	"errors"
     7  	"strconv"
     8  	"strings"
     9  
    10  	"github.com/pf-qiu/concourse/v6/atc"
    11  	"github.com/pf-qiu/concourse/v6/atc/db"
    12  	"github.com/pf-qiu/concourse/v6/atc/exec"
    13  	"github.com/pf-qiu/concourse/v6/atc/policy"
    14  )
    15  
    16  const supportedSchema = "exec.v2"
    17  
    18  //go:generate counterfeiter . CoreStepFactory
    19  
    20  type CoreStepFactory interface {
    21  	GetStep(atc.Plan, exec.StepMetadata, db.ContainerMetadata, DelegateFactory) exec.Step
    22  	PutStep(atc.Plan, exec.StepMetadata, db.ContainerMetadata, DelegateFactory) exec.Step
    23  	TaskStep(atc.Plan, exec.StepMetadata, db.ContainerMetadata, DelegateFactory) exec.Step
    24  	CheckStep(atc.Plan, exec.StepMetadata, db.ContainerMetadata, DelegateFactory) exec.Step
    25  	SetPipelineStep(atc.Plan, exec.StepMetadata, DelegateFactory) exec.Step
    26  	LoadVarStep(atc.Plan, exec.StepMetadata, DelegateFactory) exec.Step
    27  	ArtifactInputStep(atc.Plan, db.Build) exec.Step
    28  	ArtifactOutputStep(atc.Plan, db.Build) exec.Step
    29  }
    30  
    31  //go:generate counterfeiter . StepperFactory
    32  
    33  type StepperFactory interface {
    34  	StepperForBuild(db.Build) (exec.Stepper, error)
    35  }
    36  
    37  func NewStepperFactory(
    38  	coreFactory CoreStepFactory,
    39  	externalURL string,
    40  	rateLimiter RateLimiter,
    41  	policyChecker policy.Checker,
    42  ) StepperFactory {
    43  	return &stepperFactory{
    44  		coreFactory:   coreFactory,
    45  		externalURL:   externalURL,
    46  		rateLimiter:   rateLimiter,
    47  		policyChecker: policyChecker,
    48  	}
    49  }
    50  
    51  type stepperFactory struct {
    52  	coreFactory     CoreStepFactory
    53  	delegateFactory DelegateFactory
    54  	externalURL     string
    55  	rateLimiter     RateLimiter
    56  	policyChecker   policy.Checker
    57  }
    58  
    59  func (factory *stepperFactory) StepperForBuild(build db.Build) (exec.Stepper, error) {
    60  	if build.Schema() != supportedSchema {
    61  		return nil, errors.New("schema not supported")
    62  	}
    63  
    64  	return func(plan atc.Plan) exec.Step {
    65  		return factory.buildStep(build, plan)
    66  	}, nil
    67  }
    68  
    69  func (factory *stepperFactory) buildStep(build db.Build, plan atc.Plan) exec.Step {
    70  	if plan.Aggregate != nil {
    71  		return factory.buildAggregateStep(build, plan)
    72  	}
    73  
    74  	if plan.InParallel != nil {
    75  		return factory.buildParallelStep(build, plan)
    76  	}
    77  
    78  	if plan.Across != nil {
    79  		return factory.buildAcrossStep(build, plan)
    80  	}
    81  
    82  	if plan.Do != nil {
    83  		return factory.buildDoStep(build, plan)
    84  	}
    85  
    86  	if plan.Timeout != nil {
    87  		return factory.buildTimeoutStep(build, plan)
    88  	}
    89  
    90  	if plan.Try != nil {
    91  		return factory.buildTryStep(build, plan)
    92  	}
    93  
    94  	if plan.OnAbort != nil {
    95  		return factory.buildOnAbortStep(build, plan)
    96  	}
    97  
    98  	if plan.OnError != nil {
    99  		return factory.buildOnErrorStep(build, plan)
   100  	}
   101  
   102  	if plan.OnSuccess != nil {
   103  		return factory.buildOnSuccessStep(build, plan)
   104  	}
   105  
   106  	if plan.OnFailure != nil {
   107  		return factory.buildOnFailureStep(build, plan)
   108  	}
   109  
   110  	if plan.Ensure != nil {
   111  		return factory.buildEnsureStep(build, plan)
   112  	}
   113  
   114  	if plan.Task != nil {
   115  		return factory.buildTaskStep(build, plan)
   116  	}
   117  
   118  	if plan.SetPipeline != nil {
   119  		return factory.buildSetPipelineStep(build, plan)
   120  	}
   121  
   122  	if plan.LoadVar != nil {
   123  		return factory.buildLoadVarStep(build, plan)
   124  	}
   125  
   126  	if plan.Check != nil {
   127  		return factory.buildCheckStep(build, plan)
   128  	}
   129  
   130  	if plan.Get != nil {
   131  		return factory.buildGetStep(build, plan)
   132  	}
   133  
   134  	if plan.Put != nil {
   135  		return factory.buildPutStep(build, plan)
   136  	}
   137  
   138  	if plan.Retry != nil {
   139  		return factory.buildRetryStep(build, plan)
   140  	}
   141  
   142  	if plan.ArtifactInput != nil {
   143  		return factory.buildArtifactInputStep(build, plan)
   144  	}
   145  
   146  	if plan.ArtifactOutput != nil {
   147  		return factory.buildArtifactOutputStep(build, plan)
   148  	}
   149  
   150  	return exec.IdentityStep{}
   151  }
   152  
   153  func (factory *stepperFactory) buildAggregateStep(build db.Build, plan atc.Plan) exec.Step {
   154  
   155  	agg := exec.AggregateStep{}
   156  
   157  	for _, innerPlan := range *plan.Aggregate {
   158  		innerPlan.Attempts = plan.Attempts
   159  		step := factory.buildStep(build, innerPlan)
   160  		agg = append(agg, step)
   161  	}
   162  
   163  	return agg
   164  }
   165  
   166  func (factory *stepperFactory) buildParallelStep(build db.Build, plan atc.Plan) exec.Step {
   167  
   168  	var steps []exec.Step
   169  
   170  	for _, innerPlan := range plan.InParallel.Steps {
   171  		innerPlan.Attempts = plan.Attempts
   172  		step := factory.buildStep(build, innerPlan)
   173  		steps = append(steps, step)
   174  	}
   175  
   176  	return exec.InParallel(steps, plan.InParallel.Limit, plan.InParallel.FailFast)
   177  }
   178  
   179  func (factory *stepperFactory) buildAcrossStep(build db.Build, plan atc.Plan) exec.Step {
   180  	stepMetadata := factory.stepMetadata(
   181  		build,
   182  		factory.externalURL,
   183  	)
   184  
   185  	steps := make([]exec.ScopedStep, len(plan.Across.Steps))
   186  	for i, s := range plan.Across.Steps {
   187  		steps[i] = exec.ScopedStep{
   188  			Step:   factory.buildStep(build, s.Step),
   189  			Values: s.Values,
   190  		}
   191  	}
   192  
   193  	return exec.Across(
   194  		plan.Across.Vars,
   195  		steps,
   196  		plan.Across.FailFast,
   197  		buildDelegateFactory(build, plan, factory.rateLimiter, factory.policyChecker),
   198  		stepMetadata,
   199  	)
   200  }
   201  
   202  func (factory *stepperFactory) buildDoStep(build db.Build, plan atc.Plan) exec.Step {
   203  	var step exec.Step = exec.IdentityStep{}
   204  
   205  	for i := len(*plan.Do) - 1; i >= 0; i-- {
   206  		innerPlan := (*plan.Do)[i]
   207  		innerPlan.Attempts = plan.Attempts
   208  		previous := factory.buildStep(build, innerPlan)
   209  		step = exec.OnSuccess(previous, step)
   210  	}
   211  
   212  	return step
   213  }
   214  
   215  func (factory *stepperFactory) buildTimeoutStep(build db.Build, plan atc.Plan) exec.Step {
   216  	innerPlan := plan.Timeout.Step
   217  	innerPlan.Attempts = plan.Attempts
   218  	step := factory.buildStep(build, innerPlan)
   219  	return exec.Timeout(step, plan.Timeout.Duration)
   220  }
   221  
   222  func (factory *stepperFactory) buildTryStep(build db.Build, plan atc.Plan) exec.Step {
   223  	innerPlan := plan.Try.Step
   224  	innerPlan.Attempts = plan.Attempts
   225  	step := factory.buildStep(build, innerPlan)
   226  	return exec.Try(step)
   227  }
   228  
   229  func (factory *stepperFactory) buildOnAbortStep(build db.Build, plan atc.Plan) exec.Step {
   230  	plan.OnAbort.Step.Attempts = plan.Attempts
   231  	step := factory.buildStep(build, plan.OnAbort.Step)
   232  	plan.OnAbort.Next.Attempts = plan.Attempts
   233  	next := factory.buildStep(build, plan.OnAbort.Next)
   234  	return exec.OnAbort(step, next)
   235  }
   236  
   237  func (factory *stepperFactory) buildOnErrorStep(build db.Build, plan atc.Plan) exec.Step {
   238  	plan.OnError.Step.Attempts = plan.Attempts
   239  	step := factory.buildStep(build, plan.OnError.Step)
   240  	plan.OnError.Next.Attempts = plan.Attempts
   241  	next := factory.buildStep(build, plan.OnError.Next)
   242  	return exec.OnError(step, next)
   243  }
   244  
   245  func (factory *stepperFactory) buildOnSuccessStep(build db.Build, plan atc.Plan) exec.Step {
   246  	plan.OnSuccess.Step.Attempts = plan.Attempts
   247  	step := factory.buildStep(build, plan.OnSuccess.Step)
   248  	plan.OnSuccess.Next.Attempts = plan.Attempts
   249  	next := factory.buildStep(build, plan.OnSuccess.Next)
   250  	return exec.OnSuccess(step, next)
   251  }
   252  
   253  func (factory *stepperFactory) buildOnFailureStep(build db.Build, plan atc.Plan) exec.Step {
   254  	plan.OnFailure.Step.Attempts = plan.Attempts
   255  	step := factory.buildStep(build, plan.OnFailure.Step)
   256  	plan.OnFailure.Next.Attempts = plan.Attempts
   257  	next := factory.buildStep(build, plan.OnFailure.Next)
   258  	return exec.OnFailure(step, next)
   259  }
   260  
   261  func (factory *stepperFactory) buildEnsureStep(build db.Build, plan atc.Plan) exec.Step {
   262  	plan.Ensure.Step.Attempts = plan.Attempts
   263  	step := factory.buildStep(build, plan.Ensure.Step)
   264  	plan.Ensure.Next.Attempts = plan.Attempts
   265  	next := factory.buildStep(build, plan.Ensure.Next)
   266  	return exec.Ensure(step, next)
   267  }
   268  
   269  func (factory *stepperFactory) buildRetryStep(build db.Build, plan atc.Plan) exec.Step {
   270  	steps := []exec.Step{}
   271  
   272  	for index, innerPlan := range *plan.Retry {
   273  		innerPlan.Attempts = append(plan.Attempts, index+1)
   274  
   275  		step := factory.buildStep(build, innerPlan)
   276  		steps = append(steps, step)
   277  	}
   278  
   279  	return exec.Retry(steps...)
   280  }
   281  
   282  func (factory *stepperFactory) buildGetStep(build db.Build, plan atc.Plan) exec.Step {
   283  
   284  	containerMetadata := factory.containerMetadata(
   285  		build,
   286  		db.ContainerTypeGet,
   287  		plan.Get.Name,
   288  		plan.Attempts,
   289  	)
   290  
   291  	stepMetadata := factory.stepMetadata(
   292  		build,
   293  		factory.externalURL,
   294  	)
   295  
   296  	return factory.coreFactory.GetStep(
   297  		plan,
   298  		stepMetadata,
   299  		containerMetadata,
   300  		buildDelegateFactory(build, plan, factory.rateLimiter, factory.policyChecker),
   301  	)
   302  }
   303  
   304  func (factory *stepperFactory) buildPutStep(build db.Build, plan atc.Plan) exec.Step {
   305  
   306  	containerMetadata := factory.containerMetadata(
   307  		build,
   308  		db.ContainerTypePut,
   309  		plan.Put.Name,
   310  		plan.Attempts,
   311  	)
   312  
   313  	stepMetadata := factory.stepMetadata(
   314  		build,
   315  		factory.externalURL,
   316  	)
   317  
   318  	return factory.coreFactory.PutStep(
   319  		plan,
   320  		stepMetadata,
   321  		containerMetadata,
   322  		buildDelegateFactory(build, plan, factory.rateLimiter, factory.policyChecker),
   323  	)
   324  }
   325  
   326  func (factory *stepperFactory) buildCheckStep(build db.Build, plan atc.Plan) exec.Step {
   327  	containerMetadata := factory.containerMetadata(
   328  		build,
   329  		db.ContainerTypeCheck,
   330  		plan.Check.Name,
   331  		plan.Attempts,
   332  	)
   333  
   334  	stepMetadata := factory.stepMetadata(
   335  		build,
   336  		factory.externalURL,
   337  	)
   338  
   339  	return factory.coreFactory.CheckStep(
   340  		plan,
   341  		stepMetadata,
   342  		containerMetadata,
   343  		buildDelegateFactory(build, plan, factory.rateLimiter, factory.policyChecker),
   344  	)
   345  }
   346  
   347  func (factory *stepperFactory) buildTaskStep(build db.Build, plan atc.Plan) exec.Step {
   348  
   349  	containerMetadata := factory.containerMetadata(
   350  		build,
   351  		db.ContainerTypeTask,
   352  		plan.Task.Name,
   353  		plan.Attempts,
   354  	)
   355  
   356  	stepMetadata := factory.stepMetadata(
   357  		build,
   358  		factory.externalURL,
   359  	)
   360  
   361  	return factory.coreFactory.TaskStep(
   362  		plan,
   363  		stepMetadata,
   364  		containerMetadata,
   365  		buildDelegateFactory(build, plan, factory.rateLimiter, factory.policyChecker),
   366  	)
   367  }
   368  
   369  func (factory *stepperFactory) buildSetPipelineStep(build db.Build, plan atc.Plan) exec.Step {
   370  
   371  	stepMetadata := factory.stepMetadata(
   372  		build,
   373  		factory.externalURL,
   374  	)
   375  
   376  	return factory.coreFactory.SetPipelineStep(
   377  		plan,
   378  		stepMetadata,
   379  		buildDelegateFactory(build, plan, factory.rateLimiter, factory.policyChecker),
   380  	)
   381  }
   382  
   383  func (factory *stepperFactory) buildLoadVarStep(build db.Build, plan atc.Plan) exec.Step {
   384  
   385  	stepMetadata := factory.stepMetadata(
   386  		build,
   387  		factory.externalURL,
   388  	)
   389  
   390  	return factory.coreFactory.LoadVarStep(
   391  		plan,
   392  		stepMetadata,
   393  		buildDelegateFactory(build, plan, factory.rateLimiter, factory.policyChecker),
   394  	)
   395  }
   396  
   397  func (factory *stepperFactory) buildArtifactInputStep(build db.Build, plan atc.Plan) exec.Step {
   398  	return factory.coreFactory.ArtifactInputStep(
   399  		plan,
   400  		build,
   401  	)
   402  }
   403  
   404  func (factory *stepperFactory) buildArtifactOutputStep(build db.Build, plan atc.Plan) exec.Step {
   405  	return factory.coreFactory.ArtifactOutputStep(
   406  		plan,
   407  		build,
   408  	)
   409  }
   410  
   411  func (factory *stepperFactory) containerMetadata(
   412  	build db.Build,
   413  	containerType db.ContainerType,
   414  	stepName string,
   415  	attempts []int,
   416  ) db.ContainerMetadata {
   417  	attemptStrs := []string{}
   418  	for _, a := range attempts {
   419  		attemptStrs = append(attemptStrs, strconv.Itoa(a))
   420  	}
   421  
   422  	var pipelineInstanceVars string
   423  	if build.PipelineInstanceVars() != nil {
   424  		instanceVars, _ := json.Marshal(build.PipelineInstanceVars())
   425  		pipelineInstanceVars = string(instanceVars)
   426  	}
   427  
   428  	return db.ContainerMetadata{
   429  		Type: containerType,
   430  
   431  		PipelineID: build.PipelineID(),
   432  		JobID:      build.JobID(),
   433  		BuildID:    build.ID(),
   434  
   435  		PipelineName:         build.PipelineName(),
   436  		PipelineInstanceVars: pipelineInstanceVars,
   437  		JobName:              build.JobName(),
   438  		BuildName:            build.Name(),
   439  
   440  		StepName: stepName,
   441  		Attempt:  strings.Join(attemptStrs, "."),
   442  	}
   443  }
   444  
   445  func (factory *stepperFactory) stepMetadata(
   446  	build db.Build,
   447  	externalURL string,
   448  ) exec.StepMetadata {
   449  	return exec.StepMetadata{
   450  		BuildID:              build.ID(),
   451  		BuildName:            build.Name(),
   452  		TeamID:               build.TeamID(),
   453  		TeamName:             build.TeamName(),
   454  		JobID:                build.JobID(),
   455  		JobName:              build.JobName(),
   456  		PipelineID:           build.PipelineID(),
   457  		PipelineName:         build.PipelineName(),
   458  		PipelineInstanceVars: build.PipelineInstanceVars(),
   459  		ExternalURL:          externalURL,
   460  	}
   461  }