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