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  }