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

     1  package exec
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"io"
     7  
     8  	"code.cloudfoundry.org/lager"
     9  	"code.cloudfoundry.org/lager/lagerctx"
    10  	"github.com/pf-qiu/concourse/v6/atc"
    11  	"github.com/pf-qiu/concourse/v6/atc/creds"
    12  	"github.com/pf-qiu/concourse/v6/atc/db"
    13  	"github.com/pf-qiu/concourse/v6/atc/exec/build"
    14  	"github.com/pf-qiu/concourse/v6/atc/resource"
    15  	"github.com/pf-qiu/concourse/v6/atc/runtime"
    16  	"github.com/pf-qiu/concourse/v6/atc/worker"
    17  	"github.com/pf-qiu/concourse/v6/tracing"
    18  	"go.opentelemetry.io/otel/api/trace"
    19  )
    20  
    21  type ErrPipelineNotFound struct {
    22  	PipelineName string
    23  }
    24  
    25  func (e ErrPipelineNotFound) Error() string {
    26  	return fmt.Sprintf("pipeline '%s' not found", e.PipelineName)
    27  }
    28  
    29  type ErrResourceNotFound struct {
    30  	ResourceName string
    31  }
    32  
    33  func (e ErrResourceNotFound) Error() string {
    34  	return fmt.Sprintf("resource '%s' not found", e.ResourceName)
    35  }
    36  
    37  //go:generate counterfeiter . GetDelegateFactory
    38  
    39  type GetDelegateFactory interface {
    40  	GetDelegate(state RunState) GetDelegate
    41  }
    42  
    43  //go:generate counterfeiter . GetDelegate
    44  
    45  type GetDelegate interface {
    46  	StartSpan(context.Context, string, tracing.Attrs) (context.Context, trace.Span)
    47  
    48  	FetchImage(context.Context, atc.ImageResource, atc.VersionedResourceTypes, bool) (worker.ImageSpec, error)
    49  
    50  	Stdout() io.Writer
    51  	Stderr() io.Writer
    52  
    53  	Initializing(lager.Logger)
    54  	Starting(lager.Logger)
    55  	Finished(lager.Logger, ExitStatus, runtime.VersionResult)
    56  	SelectedWorker(lager.Logger, string)
    57  	Errored(lager.Logger, string)
    58  
    59  	UpdateVersion(lager.Logger, atc.GetPlan, runtime.VersionResult)
    60  }
    61  
    62  // GetStep will fetch a version of a resource on a worker that supports the
    63  // resource type.
    64  type GetStep struct {
    65  	planID               atc.PlanID
    66  	plan                 atc.GetPlan
    67  	metadata             StepMetadata
    68  	containerMetadata    db.ContainerMetadata
    69  	resourceFactory      resource.ResourceFactory
    70  	resourceCacheFactory db.ResourceCacheFactory
    71  	strategy             worker.ContainerPlacementStrategy
    72  	workerClient         worker.Client
    73  	delegateFactory      GetDelegateFactory
    74  }
    75  
    76  func NewGetStep(
    77  	planID atc.PlanID,
    78  	plan atc.GetPlan,
    79  	metadata StepMetadata,
    80  	containerMetadata db.ContainerMetadata,
    81  	resourceFactory resource.ResourceFactory,
    82  	resourceCacheFactory db.ResourceCacheFactory,
    83  	strategy worker.ContainerPlacementStrategy,
    84  	delegateFactory GetDelegateFactory,
    85  	client worker.Client,
    86  ) Step {
    87  	return &GetStep{
    88  		planID:               planID,
    89  		plan:                 plan,
    90  		metadata:             metadata,
    91  		containerMetadata:    containerMetadata,
    92  		resourceFactory:      resourceFactory,
    93  		resourceCacheFactory: resourceCacheFactory,
    94  		strategy:             strategy,
    95  		delegateFactory:      delegateFactory,
    96  		workerClient:         client,
    97  	}
    98  }
    99  
   100  func (step *GetStep) Run(ctx context.Context, state RunState) (bool, error) {
   101  	delegate := step.delegateFactory.GetDelegate(state)
   102  	ctx, span := delegate.StartSpan(ctx, "get", tracing.Attrs{
   103  		"name":     step.plan.Name,
   104  		"resource": step.plan.Resource,
   105  	})
   106  
   107  	ok, err := step.run(ctx, state, delegate)
   108  	tracing.End(span, err)
   109  
   110  	return ok, err
   111  }
   112  
   113  func (step *GetStep) run(ctx context.Context, state RunState, delegate GetDelegate) (bool, error) {
   114  	logger := lagerctx.FromContext(ctx)
   115  	logger = logger.Session("get-step", lager.Data{
   116  		"step-name": step.plan.Name,
   117  	})
   118  
   119  	delegate.Initializing(logger)
   120  
   121  	source, err := creds.NewSource(state, step.plan.Source).Evaluate()
   122  	if err != nil {
   123  		return false, err
   124  	}
   125  
   126  	params, err := creds.NewParams(state, step.plan.Params).Evaluate()
   127  	if err != nil {
   128  		return false, err
   129  	}
   130  
   131  	workerSpec := worker.WorkerSpec{
   132  		Tags:         step.plan.Tags,
   133  		TeamID:       step.metadata.TeamID,
   134  		ResourceType: step.plan.VersionedResourceTypes.Base(step.plan.Type),
   135  	}
   136  
   137  	var imageSpec worker.ImageSpec
   138  	resourceType, found := step.plan.VersionedResourceTypes.Lookup(step.plan.Type)
   139  	if found {
   140  		image := atc.ImageResource{
   141  			Name:    resourceType.Name,
   142  			Type:    resourceType.Type,
   143  			Source:  resourceType.Source,
   144  			Params:  resourceType.Params,
   145  			Version: resourceType.Version,
   146  			Tags:    resourceType.Tags,
   147  		}
   148  		if len(image.Tags) == 0 {
   149  			image.Tags = step.plan.Tags
   150  		}
   151  
   152  		types := step.plan.VersionedResourceTypes.Without(step.plan.Type)
   153  
   154  		var err error
   155  		imageSpec, err = delegate.FetchImage(ctx, image, types, resourceType.Privileged)
   156  		if err != nil {
   157  			return false, err
   158  		}
   159  	} else {
   160  		imageSpec.ResourceType = step.plan.Type
   161  	}
   162  
   163  	resourceTypes, err := creds.NewVersionedResourceTypes(state, step.plan.VersionedResourceTypes).Evaluate()
   164  	if err != nil {
   165  		return false, err
   166  	}
   167  
   168  	version, err := NewVersionSourceFromPlan(&step.plan).Version(state)
   169  	if err != nil {
   170  		return false, err
   171  	}
   172  
   173  	containerSpec := worker.ContainerSpec{
   174  		ImageSpec: imageSpec,
   175  		TeamID:    step.metadata.TeamID,
   176  		Env:       step.metadata.Env(),
   177  	}
   178  	tracing.Inject(ctx, &containerSpec)
   179  
   180  	resourceCache, err := step.resourceCacheFactory.FindOrCreateResourceCache(
   181  		db.ForBuild(step.metadata.BuildID),
   182  		step.plan.Type,
   183  		version,
   184  		source,
   185  		params,
   186  		resourceTypes,
   187  	)
   188  	if err != nil {
   189  		logger.Error("failed-to-create-resource-cache", err)
   190  		return false, err
   191  	}
   192  
   193  	processSpec := runtime.ProcessSpec{
   194  		Path:         "/opt/resource/in",
   195  		Args:         []string{resource.ResourcesDir("get")},
   196  		StdoutWriter: delegate.Stdout(),
   197  		StderrWriter: delegate.Stderr(),
   198  	}
   199  
   200  	resourceToGet := step.resourceFactory.NewResource(
   201  		source,
   202  		params,
   203  		version,
   204  	)
   205  
   206  	containerOwner := db.NewBuildStepContainerOwner(step.metadata.BuildID, step.planID, step.metadata.TeamID)
   207  
   208  	getResult, err := step.workerClient.RunGetStep(
   209  		ctx,
   210  		logger,
   211  		containerOwner,
   212  		containerSpec,
   213  		workerSpec,
   214  		step.strategy,
   215  		step.containerMetadata,
   216  		processSpec,
   217  		delegate,
   218  		resourceCache,
   219  		resourceToGet,
   220  	)
   221  	if err != nil {
   222  		return false, err
   223  	}
   224  
   225  	var succeeded bool
   226  	if getResult.ExitStatus == 0 {
   227  		state.StoreResult(step.planID, resourceCache)
   228  
   229  		state.ArtifactRepository().RegisterArtifact(
   230  			build.ArtifactName(step.plan.Name),
   231  			getResult.GetArtifact,
   232  		)
   233  
   234  		if step.plan.Resource != "" {
   235  			delegate.UpdateVersion(logger, step.plan, getResult.VersionResult)
   236  		}
   237  
   238  		succeeded = true
   239  	}
   240  
   241  	delegate.Finished(
   242  		logger,
   243  		ExitStatus(getResult.ExitStatus),
   244  		getResult.VersionResult,
   245  	)
   246  
   247  	return succeeded, nil
   248  }