github.com/pf-qiu/concourse/v6@v6.7.3-0.20201207032516-1f455d73275f/atc/worker/fetch_source.go (about) 1 package worker 2 3 // this file takes in a resource and returns a source (Volume) 4 // we might not need to model this way 5 6 import ( 7 "context" 8 9 "code.cloudfoundry.org/lager" 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/resource" 13 "github.com/pf-qiu/concourse/v6/atc/runtime" 14 ) 15 16 //go:generate counterfeiter . FetchSource 17 18 type FetchSource interface { 19 Find() (GetResult, Volume, bool, error) 20 Create(context.Context) (GetResult, Volume, error) 21 } 22 23 //go:generate counterfeiter . FetchSourceFactory 24 25 type FetchSourceFactory interface { 26 NewFetchSource( 27 logger lager.Logger, 28 worker Worker, 29 owner db.ContainerOwner, 30 cache db.UsedResourceCache, 31 resource resource.Resource, 32 containerSpec ContainerSpec, 33 processSpec runtime.ProcessSpec, 34 containerMetadata db.ContainerMetadata, 35 ) FetchSource 36 } 37 38 type fetchSourceFactory struct { 39 resourceCacheFactory db.ResourceCacheFactory 40 } 41 42 func NewFetchSourceFactory( 43 resourceCacheFactory db.ResourceCacheFactory, 44 ) FetchSourceFactory { 45 return &fetchSourceFactory{ 46 resourceCacheFactory: resourceCacheFactory, 47 } 48 } 49 50 func (r *fetchSourceFactory) NewFetchSource( 51 logger lager.Logger, 52 worker Worker, 53 owner db.ContainerOwner, 54 cache db.UsedResourceCache, 55 resource resource.Resource, 56 containerSpec ContainerSpec, 57 processSpec runtime.ProcessSpec, 58 containerMetadata db.ContainerMetadata, 59 ) FetchSource { 60 return &fetchSource{ 61 logger: logger, 62 worker: worker, 63 owner: owner, 64 cache: cache, 65 resource: resource, 66 containerSpec: containerSpec, 67 processSpec: processSpec, 68 containerMetadata: containerMetadata, 69 dbResourceCacheFactory: r.resourceCacheFactory, 70 } 71 } 72 73 type fetchSource struct { 74 logger lager.Logger 75 worker Worker 76 owner db.ContainerOwner 77 cache db.UsedResourceCache 78 resource resource.Resource 79 containerSpec ContainerSpec 80 processSpec runtime.ProcessSpec 81 containerMetadata db.ContainerMetadata 82 dbResourceCacheFactory db.ResourceCacheFactory 83 } 84 85 func (s *fetchSource) Find() (GetResult, Volume, bool, error) { 86 sLog := s.logger.Session("find") 87 result := GetResult{} 88 89 volume, found, err := s.worker.FindVolumeForResourceCache(s.logger, s.cache) 90 if err != nil { 91 sLog.Error("failed-to-find-initialized-on", err) 92 return result, nil, false, err 93 } 94 95 if !found { 96 return result, nil, false, nil 97 } 98 99 metadata, err := s.dbResourceCacheFactory.ResourceCacheMetadata(s.cache) 100 if err != nil { 101 sLog.Error("failed-to-get-resource-cache-metadata", err) 102 return result, nil, false, err 103 } 104 105 s.logger.Debug("found-initialized-versioned-source", lager.Data{ 106 "version": s.cache.Version(), 107 "metadata": metadata.ToATCMetadata(), 108 }) 109 110 atcMetaData := []atc.MetadataField{} 111 for _, m := range metadata { 112 atcMetaData = append(atcMetaData, atc.MetadataField{ 113 Name: m.Name, 114 Value: m.Value, 115 }) 116 } 117 118 return GetResult{ 119 ExitStatus: 0, 120 VersionResult: runtime.VersionResult{ 121 Version: s.cache.Version(), 122 Metadata: atcMetaData, 123 }, 124 GetArtifact: runtime.GetArtifact{VolumeHandle: volume.Handle()}, 125 }, 126 volume, true, nil 127 } 128 129 // Create runs under the lock but we need to make sure volume does not exist 130 // yet before creating it under the lock 131 func (s *fetchSource) Create(ctx context.Context) (GetResult, Volume, error) { 132 sLog := s.logger.Session("create") 133 134 findResult, volume, found, err := s.Find() 135 if err != nil { 136 return GetResult{}, nil, err 137 } 138 139 if found { 140 return findResult, volume, nil 141 } 142 143 s.containerSpec.BindMounts = []BindMountSource{ 144 &CertsVolumeMount{Logger: s.logger}, 145 } 146 147 container, err := s.worker.FindOrCreateContainer( 148 ctx, 149 s.logger, 150 s.owner, 151 s.containerMetadata, 152 s.containerSpec, 153 ) 154 155 if err != nil { 156 sLog.Error("failed-to-construct-resource", err) 157 return GetResult{}, nil, err 158 } 159 160 vr, err := s.resource.Get(ctx, s.processSpec, container) 161 if err != nil { 162 sLog.Error("failed-to-fetch-resource", err) 163 // TODO: Is this compatible with previous behaviour of returning a nil when error type is NOT ErrResourceScriptFailed 164 165 if failErr, ok := err.(runtime.ErrResourceScriptFailed); ok { 166 return GetResult{ 167 ExitStatus: failErr.ExitStatus, 168 }, nil, nil 169 } 170 return GetResult{}, nil, err 171 } 172 173 volume = volumeWithFetchedBits(s.processSpec.Args[0], container) 174 175 err = volume.SetPrivileged(false) 176 if err != nil { 177 sLog.Error("failed-to-set-volume-unprivileged", err) 178 return GetResult{}, nil, err 179 } 180 181 err = volume.InitializeResourceCache(s.cache) 182 if err != nil { 183 sLog.Error("failed-to-initialize-cache", err) 184 return GetResult{}, nil, err 185 } 186 187 err = s.dbResourceCacheFactory.UpdateResourceCacheMetadata(s.cache, vr.Metadata) 188 if err != nil { 189 s.logger.Error("failed-to-update-resource-cache-metadata", err, lager.Data{"resource-cache": s.cache}) 190 return GetResult{}, nil, err 191 } 192 193 return GetResult{ 194 ExitStatus: 0, 195 VersionResult: vr, 196 GetArtifact: runtime.GetArtifact{ 197 VolumeHandle: volume.Handle(), 198 }, 199 }, volume, nil 200 } 201 202 func volumeWithFetchedBits(bitsDestinationPath string, container Container) Volume { 203 for _, mount := range container.VolumeMounts() { 204 if mount.MountPath == bitsDestinationPath { 205 return mount.Volume 206 } 207 } 208 return nil 209 }