github.com/pf-qiu/concourse/v6@v6.7.3-0.20201207032516-1f455d73275f/atc/worker/image/image_test.go (about)

     1  package image_test
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"io/ioutil"
     7  	"strings"
     8  
     9  	"code.cloudfoundry.org/lager/lagertest"
    10  	"github.com/concourse/baggageclaim"
    11  	"github.com/concourse/baggageclaim/baggageclaimfakes"
    12  	"github.com/pf-qiu/concourse/v6/atc"
    13  	"github.com/pf-qiu/concourse/v6/atc/db/dbfakes"
    14  	"github.com/pf-qiu/concourse/v6/atc/worker"
    15  	"github.com/pf-qiu/concourse/v6/atc/worker/image"
    16  	"github.com/pf-qiu/concourse/v6/atc/worker/workerfakes"
    17  	. "github.com/onsi/ginkgo"
    18  	. "github.com/onsi/gomega"
    19  )
    20  
    21  var _ = Describe("Image", func() {
    22  	var (
    23  		imageFactory     worker.ImageFactory
    24  		img              worker.Image
    25  		ctx              context.Context
    26  		logger           *lagertest.TestLogger
    27  		fakeWorker       *workerfakes.FakeWorker
    28  		fakeVolumeClient *workerfakes.FakeVolumeClient
    29  		fakeContainer    *dbfakes.FakeCreatingContainer
    30  	)
    31  
    32  	BeforeEach(func() {
    33  		logger = lagertest.NewTestLogger("image-tests")
    34  		fakeWorker = new(workerfakes.FakeWorker)
    35  		fakeWorker.TagsReturns(atc.Tags{"worker", "tags"})
    36  
    37  		ctx = context.Background()
    38  		fakeVolumeClient = new(workerfakes.FakeVolumeClient)
    39  		fakeContainer = new(dbfakes.FakeCreatingContainer)
    40  		imageFactory = image.NewImageFactory()
    41  	})
    42  
    43  	Describe("imageProvidedByPreviousStepOnSameWorker", func() {
    44  		var fakeArtifactVolume *workerfakes.FakeVolume
    45  		var cowStrategy baggageclaim.COWStrategy
    46  
    47  		BeforeEach(func() {
    48  			fakeArtifactVolume = new(workerfakes.FakeVolume)
    49  			cowStrategy = baggageclaim.COWStrategy{
    50  				Parent: new(baggageclaimfakes.FakeVolume),
    51  			}
    52  			fakeArtifactVolume.COWStrategyReturns(cowStrategy)
    53  
    54  			fakeImageArtifactSource := new(workerfakes.FakeStreamableArtifactSource)
    55  			fakeImageArtifactSource.ExistsOnReturns(fakeArtifactVolume, true, nil)
    56  			metadataReader := ioutil.NopCloser(strings.NewReader(
    57  				`{"env": ["A=1", "B=2"], "user":"image-volume-user"}`,
    58  			))
    59  			fakeImageArtifactSource.StreamFileReturns(metadataReader, nil)
    60  
    61  			fakeContainerRootfsVolume := new(workerfakes.FakeVolume)
    62  			fakeContainerRootfsVolume.PathReturns("some-path")
    63  			fakeVolumeClient.FindOrCreateCOWVolumeForContainerReturns(fakeContainerRootfsVolume, nil)
    64  
    65  			var err error
    66  			img, err = imageFactory.GetImage(
    67  				logger,
    68  				fakeWorker,
    69  				fakeVolumeClient,
    70  				worker.ImageSpec{
    71  					ImageArtifactSource: fakeImageArtifactSource,
    72  					Privileged:          true,
    73  				},
    74  				42,
    75  			)
    76  			Expect(err).NotTo(HaveOccurred())
    77  		})
    78  
    79  		It("finds or creates cow volume", func() {
    80  			_, err := img.FetchForContainer(ctx, logger, fakeContainer)
    81  			Expect(err).NotTo(HaveOccurred())
    82  			Expect(fakeVolumeClient.FindOrCreateCOWVolumeForContainerCallCount()).To(Equal(1))
    83  			_, volumeSpec, container, volume, teamID, path := fakeVolumeClient.FindOrCreateCOWVolumeForContainerArgsForCall(0)
    84  			Expect(volumeSpec).To(Equal(worker.VolumeSpec{
    85  				Strategy:   cowStrategy,
    86  				Privileged: true,
    87  			}))
    88  			Expect(container).To(Equal(fakeContainer))
    89  			Expect(volume).To(Equal(fakeArtifactVolume))
    90  			Expect(teamID).To(Equal(42))
    91  			Expect(path).To(Equal("/"))
    92  		})
    93  
    94  		It("returns fetched image", func() {
    95  			fetchedImage, err := img.FetchForContainer(ctx, logger, fakeContainer)
    96  			Expect(err).NotTo(HaveOccurred())
    97  
    98  			Expect(fetchedImage).To(Equal(worker.FetchedImage{
    99  				Metadata: worker.ImageMetadata{
   100  					Env:  []string{"A=1", "B=2"},
   101  					User: "image-volume-user",
   102  				},
   103  				URL:        "raw://some-path/rootfs",
   104  				Privileged: true,
   105  			}))
   106  		})
   107  	})
   108  
   109  	Describe("imageProvidedByPreviousStepOnDifferentWorker", func() {
   110  		var (
   111  			fakeArtifactVolume        *workerfakes.FakeVolume
   112  			fakeImageArtifactSource   *workerfakes.FakeStreamableArtifactSource
   113  			fakeContainerRootfsVolume *workerfakes.FakeVolume
   114  		)
   115  
   116  		BeforeEach(func() {
   117  			fakeArtifactVolume = new(workerfakes.FakeVolume)
   118  			fakeImageArtifactSource = new(workerfakes.FakeStreamableArtifactSource)
   119  			fakeImageArtifactSource.ExistsOnReturns(fakeArtifactVolume, false, nil)
   120  			metadataReader := ioutil.NopCloser(strings.NewReader(
   121  				`{"env": ["A=1", "B=2"], "user":"image-volume-user"}`,
   122  			))
   123  			fakeImageArtifactSource.StreamFileReturns(metadataReader, nil)
   124  
   125  			fakeContainerRootfsVolume = new(workerfakes.FakeVolume)
   126  			fakeContainerRootfsVolume.PathReturns("some-path")
   127  			fakeVolumeClient.FindOrCreateVolumeForContainerReturns(fakeContainerRootfsVolume, nil)
   128  
   129  			var err error
   130  			img, err = imageFactory.GetImage(
   131  				logger,
   132  				fakeWorker,
   133  				fakeVolumeClient,
   134  				worker.ImageSpec{
   135  					ImageArtifactSource: fakeImageArtifactSource,
   136  					Privileged:          true,
   137  				},
   138  				42,
   139  			)
   140  			Expect(err).NotTo(HaveOccurred())
   141  		})
   142  
   143  		It("finds or creates volume", func() {
   144  			_, err := img.FetchForContainer(ctx, logger, fakeContainer)
   145  			Expect(err).NotTo(HaveOccurred())
   146  			Expect(fakeVolumeClient.FindOrCreateVolumeForContainerCallCount()).To(Equal(1))
   147  			_, volumeSpec, container, teamID, path := fakeVolumeClient.FindOrCreateVolumeForContainerArgsForCall(0)
   148  			Expect(volumeSpec).To(Equal(worker.VolumeSpec{
   149  				Strategy:   baggageclaim.EmptyStrategy{},
   150  				Privileged: true,
   151  			}))
   152  			Expect(container).To(Equal(fakeContainer))
   153  			Expect(teamID).To(Equal(42))
   154  			Expect(path).To(Equal("/"))
   155  		})
   156  
   157  		Context("when VolumeClient fails to create a volume", func() {
   158  			BeforeEach(func() {
   159  				fakeVolumeClient.FindOrCreateVolumeForContainerReturns(nil, errors.New("some error"))
   160  			})
   161  
   162  			It("returns an error", func() {
   163  				_, err := img.FetchForContainer(ctx, logger, fakeContainer)
   164  				Expect(err).To(HaveOccurred())
   165  				Expect(fakeVolumeClient.FindOrCreateVolumeForContainerCallCount()).To(Equal(1))
   166  			})
   167  		})
   168  
   169  		It("streams the volume from another worker", func() {
   170  			_, err := img.FetchForContainer(ctx, logger, fakeContainer)
   171  			Expect(err).NotTo(HaveOccurred())
   172  
   173  			Expect(fakeImageArtifactSource.StreamToCallCount()).To(Equal(1))
   174  
   175  			_, artifactDestination := fakeImageArtifactSource.StreamToArgsForCall(0)
   176  			artifactDestination.StreamIn(context.TODO(), "fake-path", baggageclaim.GzipEncoding, strings.NewReader("fake-tar-stream"))
   177  			Expect(fakeContainerRootfsVolume.StreamInCallCount()).To(Equal(1))
   178  		})
   179  
   180  		Context("when streamTo fails", func() {
   181  			BeforeEach(func() {
   182  				fakeImageArtifactSource.StreamFileReturns(nil, errors.New("some error"))
   183  			})
   184  
   185  			It("returns an error", func() {
   186  				_, err := img.FetchForContainer(ctx, logger, fakeContainer)
   187  				Expect(err).To(HaveOccurred())
   188  				Expect(fakeImageArtifactSource.StreamToCallCount()).To(Equal(1))
   189  			})
   190  		})
   191  
   192  		It("returns fetched image", func() {
   193  			fetchedImage, err := img.FetchForContainer(ctx, logger, fakeContainer)
   194  			Expect(err).NotTo(HaveOccurred())
   195  
   196  			Expect(fetchedImage).To(Equal(worker.FetchedImage{
   197  				Metadata: worker.ImageMetadata{
   198  					Env:  []string{"A=1", "B=2"},
   199  					User: "image-volume-user",
   200  				},
   201  				URL:        "raw://some-path/rootfs",
   202  				Privileged: true,
   203  			}))
   204  		})
   205  	})
   206  
   207  	Describe("imageFromBaseResourceType", func() {
   208  		var cowStrategy baggageclaim.COWStrategy
   209  		var workerResourceType atc.WorkerResourceType
   210  		var fakeContainerRootfsVolume *workerfakes.FakeVolume
   211  		var fakeImportVolume *workerfakes.FakeVolume
   212  
   213  		BeforeEach(func() {
   214  			fakeContainerRootfsVolume = new(workerfakes.FakeVolume)
   215  			fakeContainerRootfsVolume.PathReturns("some-path")
   216  			fakeVolumeClient.FindOrCreateCOWVolumeForContainerReturns(fakeContainerRootfsVolume, nil)
   217  
   218  			fakeImportVolume = new(workerfakes.FakeVolume)
   219  			cowStrategy = baggageclaim.COWStrategy{
   220  				Parent: new(baggageclaimfakes.FakeVolume),
   221  			}
   222  			fakeImportVolume.COWStrategyReturns(cowStrategy)
   223  			fakeVolumeClient.FindOrCreateVolumeForBaseResourceTypeReturns(fakeImportVolume, nil)
   224  
   225  			workerResourceType = atc.WorkerResourceType{
   226  				Type:       "some-base-resource-type",
   227  				Image:      "some-base-image-path",
   228  				Version:    "some-base-version",
   229  				Privileged: false,
   230  			}
   231  
   232  			fakeWorker.ResourceTypesReturns([]atc.WorkerResourceType{workerResourceType})
   233  
   234  			fakeWorker.NameReturns("some-worker-name")
   235  
   236  			var err error
   237  			img, err = imageFactory.GetImage(
   238  				logger,
   239  				fakeWorker,
   240  				fakeVolumeClient,
   241  				worker.ImageSpec{
   242  					ResourceType: "some-base-resource-type",
   243  				},
   244  				42,
   245  			)
   246  			Expect(err).NotTo(HaveOccurred())
   247  		})
   248  
   249  		It("finds or creates unprivileged import volume", func() {
   250  			_, err := img.FetchForContainer(ctx, logger, fakeContainer)
   251  			Expect(err).NotTo(HaveOccurred())
   252  			Expect(fakeVolumeClient.FindOrCreateVolumeForBaseResourceTypeCallCount()).To(Equal(1))
   253  			_, volumeSpec, teamID, resourceTypeName := fakeVolumeClient.FindOrCreateVolumeForBaseResourceTypeArgsForCall(0)
   254  			Expect(volumeSpec).To(Equal(worker.VolumeSpec{
   255  				Strategy: baggageclaim.ImportStrategy{
   256  					Path: "some-base-image-path",
   257  				},
   258  				Privileged: false,
   259  			}))
   260  			Expect(teamID).To(Equal(42))
   261  			Expect(resourceTypeName).To(Equal("some-base-resource-type"))
   262  		})
   263  
   264  		It("finds or creates unprivileged cow volume", func() {
   265  			_, err := img.FetchForContainer(ctx, logger, fakeContainer)
   266  			Expect(err).NotTo(HaveOccurred())
   267  			Expect(fakeVolumeClient.FindOrCreateCOWVolumeForContainerCallCount()).To(Equal(1))
   268  			_, volumeSpec, container, volume, teamID, path := fakeVolumeClient.FindOrCreateCOWVolumeForContainerArgsForCall(0)
   269  			Expect(volumeSpec).To(Equal(worker.VolumeSpec{
   270  				Strategy:   cowStrategy,
   271  				Privileged: false,
   272  			}))
   273  			Expect(teamID).To(Equal(42))
   274  			Expect(container).To(Equal(fakeContainer))
   275  			Expect(volume).To(Equal(fakeImportVolume))
   276  			Expect(path).To(Equal("/"))
   277  		})
   278  
   279  		It("returns fetched image", func() {
   280  			fetchedImage, err := img.FetchForContainer(ctx, logger, fakeContainer)
   281  			Expect(err).NotTo(HaveOccurred())
   282  
   283  			Expect(fetchedImage).To(Equal(worker.FetchedImage{
   284  				Metadata:   worker.ImageMetadata{},
   285  				URL:        "raw://some-path",
   286  				Version:    atc.Version{"some-base-resource-type": "some-base-version"},
   287  				Privileged: false,
   288  			}))
   289  		})
   290  
   291  		Context("when the worker base resource type is privileged", func() {
   292  			BeforeEach(func() {
   293  				workerResourceType.Privileged = true
   294  				fakeWorker.ResourceTypesReturns([]atc.WorkerResourceType{workerResourceType})
   295  			})
   296  
   297  			It("finds or creates privileged import volume", func() {
   298  				_, err := img.FetchForContainer(ctx, logger, fakeContainer)
   299  				Expect(err).NotTo(HaveOccurred())
   300  				Expect(fakeVolumeClient.FindOrCreateVolumeForBaseResourceTypeCallCount()).To(Equal(1))
   301  				_, volumeSpec, teamID, resourceTypeName := fakeVolumeClient.FindOrCreateVolumeForBaseResourceTypeArgsForCall(0)
   302  				Expect(volumeSpec).To(Equal(worker.VolumeSpec{
   303  					Strategy: baggageclaim.ImportStrategy{
   304  						Path: "some-base-image-path",
   305  					},
   306  					Privileged: true,
   307  				}))
   308  				Expect(teamID).To(Equal(42))
   309  				Expect(resourceTypeName).To(Equal("some-base-resource-type"))
   310  			})
   311  
   312  			It("finds or creates privileged cow volume", func() {
   313  				_, err := img.FetchForContainer(ctx, logger, fakeContainer)
   314  				Expect(err).NotTo(HaveOccurred())
   315  				Expect(fakeVolumeClient.FindOrCreateCOWVolumeForContainerCallCount()).To(Equal(1))
   316  				_, volumeSpec, container, volume, teamID, path := fakeVolumeClient.FindOrCreateCOWVolumeForContainerArgsForCall(0)
   317  				Expect(volumeSpec).To(Equal(worker.VolumeSpec{
   318  					Strategy:   cowStrategy,
   319  					Privileged: true,
   320  				}))
   321  				Expect(teamID).To(Equal(42))
   322  				Expect(container).To(Equal(fakeContainer))
   323  				Expect(volume).To(Equal(fakeImportVolume))
   324  				Expect(path).To(Equal("/"))
   325  			})
   326  
   327  			It("returns privileged fetched image", func() {
   328  				fetchedImage, err := img.FetchForContainer(ctx, logger, fakeContainer)
   329  				Expect(err).NotTo(HaveOccurred())
   330  
   331  				Expect(fetchedImage).To(Equal(worker.FetchedImage{
   332  					Metadata:   worker.ImageMetadata{},
   333  					URL:        "raw://some-path",
   334  					Version:    atc.Version{"some-base-resource-type": "some-base-version"},
   335  					Privileged: true,
   336  				}))
   337  			})
   338  		})
   339  	})
   340  
   341  	Describe("imageFromRootfsURI", func() {
   342  		BeforeEach(func() {
   343  			var err error
   344  			img, err = imageFactory.GetImage(
   345  				logger,
   346  				fakeWorker,
   347  				fakeVolumeClient,
   348  				worker.ImageSpec{
   349  					ImageURL: "some-image-url",
   350  				},
   351  				42,
   352  			)
   353  			Expect(err).NotTo(HaveOccurred())
   354  		})
   355  
   356  		It("returns the fetched image", func() {
   357  			fetchedImage, err := img.FetchForContainer(ctx, logger, fakeContainer)
   358  			Expect(err).NotTo(HaveOccurred())
   359  
   360  			Expect(fetchedImage).To(Equal(worker.FetchedImage{
   361  				URL: "some-image-url",
   362  			}))
   363  		})
   364  	})
   365  })