concourse/atc/resource/resource_instance_fetch_sou...

206 lines
5.2 KiB
Go

package resource
import (
"context"
"code.cloudfoundry.org/lager"
"github.com/concourse/concourse/atc"
"github.com/concourse/concourse/atc/db"
"github.com/concourse/concourse/atc/worker"
)
//go:generate counterfeiter . FetchSource
type FetchSource interface {
LockName() (string, error)
Find() (VersionedSource, bool, error)
Create(context.Context) (VersionedSource, error)
}
//go:generate counterfeiter . FetchSourceFactory
type FetchSourceFactory interface {
NewFetchSource(
logger lager.Logger,
worker worker.Worker,
resourceInstance ResourceInstance,
resourceTypes atc.VersionedResourceTypes,
containerSpec worker.ContainerSpec,
session Session,
imageFetchingDelegate worker.ImageFetchingDelegate,
) FetchSource
}
type fetchSourceFactory struct {
resourceCacheFactory db.ResourceCacheFactory
resourceFactory ResourceFactory
}
func NewFetchSourceFactory(
resourceCacheFactory db.ResourceCacheFactory,
resourceFactory ResourceFactory,
) FetchSourceFactory {
return &fetchSourceFactory{
resourceCacheFactory: resourceCacheFactory,
resourceFactory: resourceFactory,
}
}
func (r *fetchSourceFactory) NewFetchSource(
logger lager.Logger,
worker worker.Worker,
resourceInstance ResourceInstance,
resourceTypes atc.VersionedResourceTypes,
containerSpec worker.ContainerSpec,
session Session,
imageFetchingDelegate worker.ImageFetchingDelegate,
) FetchSource {
return &resourceInstanceFetchSource{
logger: logger,
worker: worker,
resourceInstance: resourceInstance,
resourceTypes: resourceTypes,
containerSpec: containerSpec,
session: session,
imageFetchingDelegate: imageFetchingDelegate,
dbResourceCacheFactory: r.resourceCacheFactory,
resourceFactory: r.resourceFactory,
}
}
type resourceInstanceFetchSource struct {
logger lager.Logger
worker worker.Worker
resourceInstance ResourceInstance
resourceTypes atc.VersionedResourceTypes
containerSpec worker.ContainerSpec
session Session
imageFetchingDelegate worker.ImageFetchingDelegate
dbResourceCacheFactory db.ResourceCacheFactory
resourceFactory ResourceFactory
}
func (s *resourceInstanceFetchSource) LockName() (string, error) {
return s.resourceInstance.LockName(s.worker.Name())
}
func (s *resourceInstanceFetchSource) Find() (VersionedSource, bool, error) {
sLog := s.logger.Session("find")
volume, found, err := s.resourceInstance.FindOn(s.logger, s.worker)
if err != nil {
sLog.Error("failed-to-find-initialized-on", err)
return nil, false, err
}
if !found {
return nil, false, nil
}
metadata, err := s.dbResourceCacheFactory.ResourceCacheMetadata(s.resourceInstance.ResourceCache())
if err != nil {
sLog.Error("failed-to-get-resource-cache-metadata", err)
return nil, false, err
}
s.logger.Debug("found-initialized-versioned-source", lager.Data{"version": s.resourceInstance.Version(), "metadata": metadata.ToATCMetadata()})
return NewGetVersionedSource(
volume,
s.resourceInstance.Version(),
metadata.ToATCMetadata(),
), true, nil
}
// Create runs under the lock but we need to make sure volume does not exist
// yet before creating it under the lock
func (s *resourceInstanceFetchSource) Create(ctx context.Context) (VersionedSource, error) {
sLog := s.logger.Session("create")
versionedSource, found, err := s.Find()
if err != nil {
return nil, err
}
if found {
return versionedSource, nil
}
s.containerSpec.BindMounts = []worker.BindMountSource{
&worker.CertsVolumeMount{Logger: s.logger},
}
err = s.worker.EnsureDBContainerExists(
ctx,
s.logger,
s.resourceInstance.ContainerOwner(),
s.session.Metadata,
)
if err != nil {
return nil, err
}
container, err := s.worker.FindOrCreateContainer(
ctx,
s.logger,
s.imageFetchingDelegate,
s.resourceInstance.ContainerOwner(),
s.containerSpec,
s.resourceTypes,
)
if err != nil {
return nil, err
}
if err != nil {
sLog.Error("failed-to-construct-resource", err)
return nil, err
}
mountPath := ResourcesDir("get")
var volume worker.Volume
for _, mount := range container.VolumeMounts() {
if mount.MountPath == mountPath {
volume = mount.Volume
break
}
}
resource := s.resourceFactory.NewResourceForContainer(container)
versionedSource, err = resource.Get(
ctx,
volume,
IOConfig{
Stdout: s.imageFetchingDelegate.Stdout(),
Stderr: s.imageFetchingDelegate.Stderr(),
},
s.resourceInstance.Source(),
s.resourceInstance.Params(),
s.resourceInstance.Version(),
)
if err != nil {
sLog.Error("failed-to-fetch-resource", err)
return nil, err
}
err = volume.SetPrivileged(false)
if err != nil {
sLog.Error("failed-to-set-volume-unprivileged", err)
return nil, err
}
err = volume.InitializeResourceCache(s.resourceInstance.ResourceCache())
if err != nil {
sLog.Error("failed-to-initialize-cache", err)
return nil, err
}
err = s.dbResourceCacheFactory.UpdateResourceCacheMetadata(s.resourceInstance.ResourceCache(), versionedSource.Metadata())
if err != nil {
s.logger.Error("failed-to-update-resource-cache-metadata", err, lager.Data{"resource-cache": s.resourceInstance.ResourceCache()})
return nil, err
}
return versionedSource, nil
}