Example #1
0
// Release releases the created container for either SuccessfulStepTTL or
// FailedStepTTL.
func (step *PutStep) Release() {
	if step.resource == nil {
		return
	}

	if step.succeeded {
		step.resource.Release(worker.FinalTTL(SuccessfulStepTTL))
	} else {
		step.resource.Release(worker.FinalTTL(FailedStepTTL))
	}
}
Example #2
0
// Release releases the created container for either the configured
// containerSuccessTTL or containerFailureTTL.
func (step *TaskStep) Release() {
	if step.container == nil {
		return
	}

	if step.exitStatus == 0 {
		step.container.Release(worker.FinalTTL(step.containerSuccessTTL))
	} else {
		step.container.Release(worker.FinalTTL(step.containerFailureTTL))
	}
}
Example #3
0
// Release releases the created container for either SuccessfulStepTTL or
// FailedStepTTL.
func (step *TaskStep) Release() {
	if step.container == nil {
		return
	}

	if step.exitStatus == 0 {
		step.container.Release(worker.FinalTTL(SuccessfulStepTTL))
	} else {
		step.container.Release(worker.FinalTTL(FailedStepTTL))
	}
}
Example #4
0
// Release releases the created container for either the configured
// containerSuccessTTL or containerFailureTTL.
func (step *PutStep) Release() {
	if step.resource == nil {
		return
	}

	if step.succeeded {
		step.resource.Release(worker.FinalTTL(step.containerSuccessTTL))
	} else {
		step.resource.Release(worker.FinalTTL(step.containerFailureTTL))
	}
}
Example #5
0
func selectLowestAlphabeticalVolume(logger lager.Logger, volumes []worker.Volume) worker.Volume {
	var lowestVolume worker.Volume

	for _, v := range volumes {
		if lowestVolume == nil {
			lowestVolume = v
		} else if v.Handle() < lowestVolume.Handle() {
			lowestVolume = v
		}
	}

	for _, v := range volumes {
		if v != lowestVolume {
			v.Release(worker.FinalTTL(reapExtraVolumeTTL))
		}
	}

	return lowestVolume
}
Example #6
0
				})

				It("calls the Initializing method on the delegate", func() {
					Expect(<-callCountDuringInit).To(Equal(1))
				})
			})

			Describe("releasing", func() {
				It("releases the resource with a ttl of 5 minutes", func() {
					<-process.Wait()

					Expect(fakeResource.ReleaseCallCount()).To(BeZero())

					step.Release()
					Expect(fakeResource.ReleaseCallCount()).To(Equal(1))
					Expect(fakeResource.ReleaseArgsForCall(0)).To(Equal(worker.FinalTTL(5 * time.Minute)))
				})
			})

			Describe("signalling", func() {
				var receivedSignals <-chan os.Signal

				BeforeEach(func() {
					sigs := make(chan os.Signal)
					receivedSignals = sigs

					fakeVersionedSource.RunStub = func(signals <-chan os.Signal, ready chan<- struct{}) error {
						close(ready)
						sigs <- <-signals
						return nil
					}
				bVolume = new(bfakes.FakeVolume)
				bVolume.HandleReturns("b")
			})

			Context("with a, b order", func() {
				BeforeEach(func() {
					fakeBaggageclaimClient.ListVolumesReturns([]baggageclaim.Volume{aVolume, bVolume}, nil)
				})

				It("selects the volume based on the lowest alphabetical name", func() {
					Expect(foundVolume).To(Equal(aVolume))
					Expect(found).To(BeTrue())

					Expect(aVolume.SetTTLCallCount()).To(Equal(0))
					Expect(bVolume.ReleaseCallCount()).To(Equal(1))
					Expect(bVolume.ReleaseArgsForCall(0)).To(Equal(worker.FinalTTL(time.Minute)))
				})
			})

			Context("with b, a order", func() {
				BeforeEach(func() {
					fakeBaggageclaimClient.ListVolumesReturns([]baggageclaim.Volume{bVolume, aVolume}, nil)
				})

				It("selects the volume based on the lowest alphabetical name", func() {
					Expect(foundVolume).To(Equal(aVolume))
					Expect(found).To(BeTrue())

					Expect(aVolume.SetTTLCallCount()).To(Equal(0))
					Expect(bVolume.ReleaseCallCount()).To(Equal(1))
					Expect(bVolume.ReleaseArgsForCall(0)).To(Equal(worker.FinalTTL(time.Minute)))
			Expect(fakePipelineDB.GetJobFinishedAndNextBuildArgsForCall(0)).To(Equal("my-precious-job"))
			Expect(fakeBaggageCollectorDB.GetImageVolumeIdentifiersByBuildIDCallCount()).To(Equal(1))
			Expect(fakeBaggageCollectorDB.GetImageVolumeIdentifiersByBuildIDArgsForCall(0)).To(Equal(2))
			Expect(fakeBaggageCollectorDB.GetVolumesCallCount()).To(Equal(1))
			Expect(fakeWorkerClient.GetWorkerCallCount()).To(Equal(3))

			Expect(workerA.VolumeManagerCallCount()).To(Equal(0))
			Expect(workerB.VolumeManagerCallCount()).To(Equal(1))
			Expect(workerC.VolumeManagerCallCount()).To(Equal(1))

			var handle string
			Expect(workerBBaggageClaimClient.LookupVolumeCallCount()).To(Equal(1))
			_, handle = workerBBaggageClaimClient.LookupVolumeArgsForCall(0)
			Expect(handle).To(Equal("docker-volume-handle"))
			Expect(dockerVolume.ReleaseCallCount()).To(Equal(1))
			Expect(dockerVolume.ReleaseArgsForCall(0)).To(Equal(worker.FinalTTL(expectedLatestVersionTTL)))

			Expect(workerCBaggageClaimClient.LookupVolumeCallCount()).To(Equal(1))
			_, handle = workerCBaggageClaimClient.LookupVolumeArgsForCall(0)
			Expect(handle).To(Equal("crossed-wires-volume-handle"))
			Expect(crossedWiresVolume.ReleaseCallCount()).To(Equal(1))
			Expect(crossedWiresVolume.ReleaseArgsForCall(0)).To(Equal(worker.FinalTTL(expectedOldVersionTTL)))

			Expect(fakeBaggageCollectorDB.SetVolumeTTLCallCount()).To(Equal(2))

			type setVolumeTTLArgs struct {
				Handle string
				TTL    time.Duration
			}

			expectedSetVolumeTTLArgs := []setVolumeTTLArgs{
	It("sets the ttl of each volume used in a one-off build to at least 24 hours", func() {
		err := baggageCollector.Collect()
		Expect(err).NotTo(HaveOccurred())
		Expect(fakeBaggageCollectorDB.GetAllPipelinesCallCount()).To(Equal(1))
		Expect(fakePipelineDBFactory.BuildCallCount()).To(Equal(1))
		Expect(fakePipelineDBFactory.BuildArgsForCall(0)).To(Equal(savedPipeline))
		Expect(fakePipelineDB.GetJobFinishedAndNextBuildCallCount()).To(Equal(1))
		Expect(fakePipelineDB.GetJobFinishedAndNextBuildArgsForCall(0)).To(Equal("my-precious-job"))
		Expect(fakeBaggageCollectorDB.GetImageVolumeIdentifiersByBuildIDCallCount()).To(Equal(1))
		Expect(fakeBaggageCollectorDB.GetImageVolumeIdentifiersByBuildIDArgsForCall(0)).To(Equal(2))
		Expect(fakeBaggageCollectorDB.GetVolumesForOneOffBuildImageResourcesCallCount()).To(Equal(1))
		Expect(fakeBaggageCollectorDB.GetVolumesCallCount()).To(Equal(1))
		Expect(fakeWorkerClient.GetWorkerCallCount()).To(Equal(2))

		Expect(worker1.VolumeManagerCallCount()).To(Equal(0))
		Expect(worker2.VolumeManagerCallCount()).To(Equal(1))

		Expect(baggageClaimClient2.LookupVolumeCallCount()).To(Equal(1))
		_, handle := baggageClaimClient2.LookupVolumeArgsForCall(0)
		Expect(handle).To(Equal("volume2"))
		Expect(volume2.ReleaseCallCount()).To(Equal(1))
		Expect(volume2.ReleaseArgsForCall(0)).To(Equal(worker.FinalTTL(expectedLatestVersionTTL)))

		Expect(fakeBaggageCollectorDB.SetVolumeTTLCallCount()).To(Equal(1))
		handle, ttl := fakeBaggageCollectorDB.SetVolumeTTLArgsForCall(0)
		Expect(handle).To(Equal("volume2"))
		Expect(ttl).To(Equal(expectedLatestVersionTTL))
	})
})
Example #10
0
import (
	"time"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"

	. "github.com/concourse/atc/resource"
	"github.com/concourse/atc/worker"
	bfakes "github.com/concourse/baggageclaim/fakes"
)

var _ = Describe("Resource", func() {
	Describe("Release", func() {
		It("releases the container", func() {
			resource.Release(worker.FinalTTL(time.Hour))

			Expect(fakeContainer.ReleaseCallCount()).To(Equal(1))
			Expect(fakeContainer.ReleaseArgsForCall(0)).To(Equal(worker.FinalTTL(time.Hour)))
		})
	})

	Describe("CacheVolume", func() {
		Context("when the container has a volume mount for /tmp/build/get", func() {
			var vol1 *bfakes.FakeVolume
			var vol2 *bfakes.FakeVolume

			BeforeEach(func() {
				vol1 = new(bfakes.FakeVolume)
				vol2 = new(bfakes.FakeVolume)
				fakeContainer.VolumeMountsReturns([]worker.VolumeMount{
Example #11
0
			Expect(actualTTL).To(Equal(expectedTTL2))

			Eventually(fakeDB.SetVolumeTTLCallCount).Should(Equal(2))
			actualHandle, actualTTL = fakeDB.SetVolumeTTLArgsForCall(1)
			Expect(actualHandle).To(Equal(vol.Handle()))
			Expect(actualTTL).To(Equal(expectedTTL2))

			By("being resiliant to db errors")
			fakeDB.GetVolumeTTLReturns(0, errors.New("disaster"))
			fakeClock.Increment(30 * time.Second)
			Eventually(fakeVolume.SetTTLCallCount).Should(Equal(3))
			actualTTL = fakeVolume.SetTTLArgsForCall(2)
			Expect(actualTTL).To(Equal(expectedTTL2))

			By("releasing the volume with a final ttl")
			vol.Release(worker.FinalTTL(2 * time.Second))
			Eventually(fakeVolume.SetTTLCallCount).Should(Equal(4))
			actualTTL = fakeVolume.SetTTLArgsForCall(3)
			Expect(actualTTL).To(Equal(2 * time.Second))

			Eventually(fakeDB.SetVolumeTTLCallCount).Should(Equal(4))
			actualHandle, actualTTL = fakeDB.SetVolumeTTLArgsForCall(3)
			Expect(actualHandle).To(Equal(vol.Handle()))
			Expect(actualTTL).To(Equal(2 * time.Second))
		})

		It("is resiliant to errors while heartbeating", func() {
			By("using the baggage claim volumes ttl if the initial db lookup fails")
			fakeVolume.ExpirationReturns(expectedTTL, time.Now(), nil)
			fakeDB.GetVolumeTTLReturns(0, errors.New("disaster"))
			_, err := volumeFactory.Build(logger, fakeVolume)
Example #12
0
func (bc *baggageCollector) expireVolumes(latestVersions hashedVersionSet) error {
	volumesToExpire, err := bc.getSortedVolumes()

	seenVolumeIdentifierAndWorkerNameCombos := volumeIdentifierAndWorkerNameSet{}

	if err != nil {
		bc.logger.Error("could-not-get-volume-data", err)
		return err
	}

	for _, volumeToExpire := range volumesToExpire {
		version, _ := json.Marshal(volumeToExpire.ResourceVersion)
		hashKey := string(version) + volumeToExpire.ResourceHash

		var ttlForVol time.Duration

		volumeIdentifierAndWorkerNameCombo := hashKey + volumeToExpire.WorkerName
		if contains(seenVolumeIdentifierAndWorkerNameCombos, volumeIdentifierAndWorkerNameCombo) {
			ttlForVol = bc.oldResourceGracePeriod
		} else {
			seenVolumeIdentifierAndWorkerNameCombos[volumeIdentifierAndWorkerNameCombo] = true
			ttlForVol = getWithDefault(latestVersions, hashKey, bc.oldResourceGracePeriod)
		}

		volumeWorker, err := bc.workerClient.GetWorker(volumeToExpire.WorkerName)
		if err != nil {
			bc.logger.Info("could-not-locate-worker", lager.Data{
				"error":     err.Error(),
				"worker-id": volumeToExpire.WorkerName,
			})
			bc.db.ReapVolume(volumeToExpire.Handle)
			continue
		}

		if volumeToExpire.TTL == ttlForVol {
			continue
		}

		baggageClaimClient, found := volumeWorker.VolumeManager()
		if !found {
			bc.logger.Info("no-volume-manager-on-worker", lager.Data{
				"worker-id": volumeToExpire.WorkerName,
			})
			bc.db.ReapVolume(volumeToExpire.Handle)
			continue
		}

		volume, found, err := baggageClaimClient.LookupVolume(bc.logger, volumeToExpire.Handle)
		if !found || err != nil {
			var e string
			if err != nil {
				e = err.Error()
			}
			bc.logger.Info("could-not-locate-volume", lager.Data{
				"error":     e,
				"worker-id": volumeToExpire.WorkerName,
				"handle":    volumeToExpire.Handle,
			})
			continue
		}

		volume.Release(worker.FinalTTL(ttlForVol))

		err = bc.db.SetVolumeTTL(volumeToExpire.Handle, ttlForVol)
		if err != nil {
			bc.logger.Error("failed-to-update-ttl-in-db", err)
		}
	}

	return nil
}
				err = baggageCollector.Collect()
				Expect(err).NotTo(HaveOccurred())

				Expect(fakeBaggageClaimClient.LookupVolumeCallCount()).To(Equal(len(example.expectedTTLs)))
				var actualHandles []string
				for i := 0; i < fakeBaggageClaimClient.LookupVolumeCallCount(); i++ {
					_, actualHandle := fakeBaggageClaimClient.LookupVolumeArgsForCall(i)
					actualHandles = append(actualHandles, actualHandle)
				}

				var expectedHandles []string
				for handle, expectedTTL := range example.expectedTTLs {
					Expect(fakeVolumes[handle].ReleaseCallCount()).To(Equal(1))
					actualTTL := fakeVolumes[handle].ReleaseArgsForCall(0)
					Expect(actualTTL).To(Equal(worker.FinalTTL(expectedTTL)))
					expectedHandles = append(expectedHandles, handle)
				}

				Expect(actualHandles).To(ConsistOf(expectedHandles))
				Expect(fakeBaggageCollectorDB.SetVolumeTTLCallCount()).To(Equal(len(example.expectedTTLs)))
				actualHandles = nil

				for i := 0; i < fakeBaggageCollectorDB.SetVolumeTTLCallCount(); i++ {
					actualHandle, actualTTL := fakeBaggageCollectorDB.SetVolumeTTLArgsForCall(i)
					actualHandles = append(actualHandles, actualHandle)

					Expect(actualTTL).To(Equal(example.expectedTTLs[actualHandle]))
				}

				Expect(actualHandles).To(ConsistOf(expectedHandles))
Example #14
0
func (bc *baggageCollector) expireVolumes(latestVersions hashedVersionSet) error {
	volumesToExpire, err := bc.getSortedVolumes()

	seenResourceCacheIdentifierAndWorkerNameCombos := resourceCacheIdentifierAndWorkerNameSet{}

	if err != nil {
		bc.logger.Error("could-not-get-volume-data", err)
		return err
	}

	for _, volumeToExpire := range volumesToExpire {
		hashKey, isResourceCache := resourceCacheHashKey(volumeToExpire)
		if !isResourceCache {
			continue
		}

		var ttlForVol time.Duration

		resourceCacheIdentifierAndWorkerNameCombo := hashKey + volumeToExpire.WorkerName
		if contains(seenResourceCacheIdentifierAndWorkerNameCombos, resourceCacheIdentifierAndWorkerNameCombo) {
			ttlForVol = bc.oldResourceGracePeriod
		} else {
			seenResourceCacheIdentifierAndWorkerNameCombos[resourceCacheIdentifierAndWorkerNameCombo] = true
			ttlForVol = getWithDefault(latestVersions, hashKey, bc.oldResourceGracePeriod)
		}

		volumeWorker, err := bc.workerClient.GetWorker(volumeToExpire.WorkerName)
		if err != nil {
			bc.logger.Info("could-not-locate-worker", lager.Data{
				"error":     err.Error(),
				"worker-id": volumeToExpire.WorkerName,
			})
			bc.db.ReapVolume(volumeToExpire.Handle)
			continue
		}

		if volumeToExpire.TTL == ttlForVol {
			continue
		}

		vLogger := bc.logger.Session("volume", lager.Data{
			"worker-name": volumeToExpire.WorkerName,
			"handle":      volumeToExpire.Handle,
		})

		volume, found, err := volumeWorker.LookupVolume(bc.logger, volumeToExpire.Handle)
		if err != nil {
			vLogger.Error("failed-to-lookup-volume", err)
			continue
		}

		if !found {
			vLogger.Info("volume-not-found")
			bc.db.ReapVolume(volumeToExpire.Handle)
			continue
		}

		vLogger.Debug("releasing", lager.Data{
			"ttl": ttlForVol,
		})

		volume.Release(worker.FinalTTL(ttlForVol))
	}

	return nil
}