Merge pull request #4202 from concourse/feature/3788-checks

lidar: tracking checks in the database
This commit is contained in:
Joshua Winters 2019-09-06 11:10:47 -04:00 committed by GitHub
commit ba9bad2c15
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
139 changed files with 9732 additions and 899 deletions

View File

@ -146,6 +146,7 @@ var requiredRoles = map[string]string{
atc.GetConfig: "viewer",
atc.GetCC: "viewer",
atc.GetBuild: "viewer",
atc.GetCheck: "viewer",
atc.GetBuildPlan: "viewer",
atc.CreateBuild: "member",
atc.ListBuilds: "viewer",

View File

@ -15,7 +15,6 @@ import (
"github.com/concourse/concourse/atc/api/accessor/accessorfakes"
"github.com/concourse/concourse/atc/api/auth"
"github.com/concourse/concourse/atc/api/containerserver/containerserverfakes"
"github.com/concourse/concourse/atc/api/resourceserver/resourceserverfakes"
"github.com/concourse/concourse/atc/auditor/auditorfakes"
"github.com/concourse/concourse/atc/creds"
"github.com/concourse/concourse/atc/creds/credsfakes"
@ -51,8 +50,8 @@ var (
build *dbfakes.FakeBuild
dbBuildFactory *dbfakes.FakeBuildFactory
dbUserFactory *dbfakes.FakeUserFactory
dbCheckFactory *dbfakes.FakeCheckFactory
dbTeam *dbfakes.FakeTeam
fakeScannerFactory *resourceserverfakes.FakeScannerFactory
fakeSecretManager *credsfakes.FakeSecrets
credsManagers creds.Managers
interceptTimeoutFactory *containerserverfakes.FakeInterceptTimeoutFactory
@ -96,6 +95,7 @@ var _ = BeforeEach(func() {
dbResourceConfigFactory = new(dbfakes.FakeResourceConfigFactory)
dbBuildFactory = new(dbfakes.FakeBuildFactory)
dbUserFactory = new(dbfakes.FakeUserFactory)
dbCheckFactory = new(dbfakes.FakeCheckFactory)
interceptTimeoutFactory = new(containerserverfakes.FakeInterceptTimeoutFactory)
interceptTimeout = new(containerserverfakes.FakeInterceptTimeout)
@ -118,8 +118,6 @@ var _ = BeforeEach(func() {
fakeWorkerClient = new(workerfakes.FakeClient)
fakeScannerFactory = new(resourceserverfakes.FakeScannerFactory)
fakeVolumeRepository = new(dbfakes.FakeVolumeRepository)
fakeContainerRepository = new(dbfakes.FakeContainerRepository)
fakeDestroyer = new(gcfakes.FakeDestroyer)
@ -173,6 +171,7 @@ var _ = BeforeEach(func() {
fakeContainerRepository,
fakeDestroyer,
dbBuildFactory,
dbCheckFactory,
dbResourceConfigFactory,
dbUserFactory,
@ -180,8 +179,6 @@ var _ = BeforeEach(func() {
fakeWorkerClient,
fakeScannerFactory,
sink,
isTLSEnabled,

166
atc/api/checks_test.go Normal file
View File

@ -0,0 +1,166 @@
package api_test
import (
"errors"
"io/ioutil"
"net/http"
"time"
"github.com/concourse/concourse/atc/db"
"github.com/concourse/concourse/atc/db/dbfakes"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
var _ = Describe("Checks API", func() {
Describe("GET /api/v1/checks/:check_id", func() {
var err error
var path string
var response *http.Response
BeforeEach(func() {
path = "/api/v1/checks/10"
})
JustBeforeEach(func() {
response, err = client.Get(server.URL + path)
Expect(err).NotTo(HaveOccurred())
})
Context("when not authenticated", func() {
BeforeEach(func() {
fakeAccess.HasTokenReturns(true)
fakeAccess.IsAuthenticatedReturns(false)
})
It("returns 401", func() {
Expect(response.StatusCode).To(Equal(http.StatusUnauthorized))
})
})
Context("when authenticated", func() {
BeforeEach(func() {
fakeAccess.IsAuthenticatedReturns(true)
})
Context("when parsing the check_id fails", func() {
BeforeEach(func() {
path = "/api/v1/checks/nope"
})
It("returns 400", func() {
Expect(response.StatusCode).To(Equal(http.StatusBadRequest))
})
})
Context("when parsing the check_id succeeds", func() {
BeforeEach(func() {
path = "/api/v1/checks/10"
})
Context("when calling the database fails", func() {
BeforeEach(func() {
dbCheckFactory.CheckReturns(nil, false, errors.New("disaster"))
})
It("returns 500", func() {
Expect(response.StatusCode).To(Equal(http.StatusInternalServerError))
})
})
Context("when the check cannot be found", func() {
BeforeEach(func() {
dbCheckFactory.CheckReturns(nil, false, nil)
})
It("returns 404", func() {
Expect(response.StatusCode).To(Equal(http.StatusNotFound))
})
})
Context("when the check can be found", func() {
var fakeCheck *dbfakes.FakeCheck
BeforeEach(func() {
fakeCheck = new(dbfakes.FakeCheck)
fakeCheck.IDReturns(10)
fakeCheck.StatusReturns("errored")
fakeCheck.CreateTimeReturns(time.Date(2000, 01, 01, 0, 0, 0, 0, time.UTC))
fakeCheck.StartTimeReturns(time.Date(2001, 01, 01, 0, 0, 0, 0, time.UTC))
fakeCheck.EndTimeReturns(time.Date(2002, 01, 01, 0, 0, 0, 0, time.UTC))
fakeCheck.CheckErrorReturns(errors.New("nope"))
dbCheckFactory.CheckReturns(fakeCheck, true, nil)
})
Context("when fetching checkables errors", func() {
BeforeEach(func() {
fakeCheck.AllCheckablesReturns(nil, errors.New("nope"))
})
It("returns 500", func() {
Expect(response.StatusCode).To(Equal(http.StatusInternalServerError))
})
})
Context("when fetching checkables returns no results", func() {
BeforeEach(func() {
fakeCheck.AllCheckablesReturns([]db.Checkable{}, nil)
})
It("returns 403", func() {
Expect(response.StatusCode).To(Equal(http.StatusForbidden))
})
})
Context("when fetching checkables returns results", func() {
var fakeResource1 *dbfakes.FakeResource
var fakeResource2 *dbfakes.FakeResource
BeforeEach(func() {
fakeResource1 = new(dbfakes.FakeResource)
fakeResource2 = new(dbfakes.FakeResource)
fakeCheck.AllCheckablesReturns([]db.Checkable{fakeResource1, fakeResource2}, nil)
})
Context("when not authorized for either team", func() {
BeforeEach(func() {
fakeAccess.IsAuthorizedReturns(false)
})
It("returns 403", func() {
Expect(response.StatusCode).To(Equal(http.StatusForbidden))
})
})
Context("when authorized for any team", func() {
BeforeEach(func() {
fakeAccess.IsAuthorizedReturns(true)
})
It("returns 200", func() {
Expect(response.StatusCode).To(Equal(http.StatusOK))
})
It("returns application/json", func() {
Expect(response.Header.Get("Content-Type")).To(Equal("application/json"))
})
It("returns the check", func() {
Expect(ioutil.ReadAll(response.Body)).To(MatchJSON(`{
"id": 10,
"status": "errored",
"create_time": 946684800,
"start_time": 978307200,
"end_time": 1009843200,
"check_error": "nope"
}`))
})
})
})
})
})
})
})
})

View File

@ -0,0 +1,60 @@
package checkserver
import (
"encoding/json"
"net/http"
"strconv"
"github.com/concourse/concourse/atc/api/accessor"
"github.com/concourse/concourse/atc/api/present"
)
func (s *Server) GetCheck(w http.ResponseWriter, r *http.Request) {
logger := s.logger.Session("get-check")
checkID, err := strconv.Atoi(r.FormValue(":check_id"))
if err != nil {
w.WriteHeader(http.StatusBadRequest)
return
}
check, found, err := s.checkFactory.Check(checkID)
if err != nil {
logger.Error("could-not-get-check", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
if !found {
w.WriteHeader(http.StatusNotFound)
return
}
checkables, err := check.AllCheckables()
if err != nil {
logger.Error("failed-to-get-checkables", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
acc := accessor.GetAccessor(r)
for _, checkable := range checkables {
if acc.IsAuthorized(checkable.TeamName()) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
err = json.NewEncoder(w).Encode(present.Check(check))
if err != nil {
logger.Error("failed-to-encode-check", err)
w.WriteHeader(http.StatusInternalServerError)
}
return
}
}
w.WriteHeader(http.StatusForbidden)
}

View File

@ -0,0 +1,23 @@
package checkserver
import (
"code.cloudfoundry.org/lager"
"github.com/concourse/concourse/atc/db"
)
type Server struct {
logger lager.Logger
checkFactory db.CheckFactory
}
func NewServer(
logger lager.Logger,
checkFactory db.CheckFactory,
) *Server {
return &Server{
logger: logger,
checkFactory: checkFactory,
}
}

View File

@ -11,6 +11,7 @@ import (
"github.com/concourse/concourse/atc/api/artifactserver"
"github.com/concourse/concourse/atc/api/buildserver"
"github.com/concourse/concourse/atc/api/ccserver"
"github.com/concourse/concourse/atc/api/checkserver"
"github.com/concourse/concourse/atc/api/cliserver"
"github.com/concourse/concourse/atc/api/configserver"
"github.com/concourse/concourse/atc/api/containerserver"
@ -49,6 +50,7 @@ func NewHandler(
containerRepository db.ContainerRepository,
destroyer gc.Destroyer,
dbBuildFactory db.BuildFactory,
dbCheckFactory db.CheckFactory,
dbResourceConfigFactory db.ResourceConfigFactory,
dbUserFactory db.UserFactory,
@ -56,8 +58,6 @@ func NewHandler(
workerClient worker.Client,
scannerFactory resourceserver.ScannerFactory,
sink *lager.ReconfigurableSink,
isTLSEnabled bool,
@ -80,8 +80,9 @@ func NewHandler(
teamHandlerFactory := NewTeamScopedHandlerFactory(logger, dbTeamFactory)
buildServer := buildserver.NewServer(logger, externalURL, dbTeamFactory, dbBuildFactory, eventHandlerFactory)
jobServer := jobserver.NewServer(logger, externalURL, secretManager, dbJobFactory)
resourceServer := resourceserver.NewServer(logger, scannerFactory, secretManager, dbResourceFactory, dbResourceConfigFactory)
checkServer := checkserver.NewServer(logger, dbCheckFactory)
jobServer := jobserver.NewServer(logger, externalURL, secretManager, dbJobFactory, dbCheckFactory)
resourceServer := resourceserver.NewServer(logger, secretManager, dbCheckFactory, dbResourceFactory, dbResourceConfigFactory)
versionServer := versionserver.NewServer(logger, externalURL)
pipelineServer := pipelineserver.NewServer(logger, dbTeamFactory, dbPipelineFactory, externalURL)
@ -113,6 +114,8 @@ func NewHandler(
atc.BuildEvents: buildHandlerFactory.HandlerFor(buildServer.BuildEvents),
atc.ListBuildArtifacts: buildHandlerFactory.HandlerFor(buildServer.GetBuildArtifacts),
atc.GetCheck: http.HandlerFunc(checkServer.GetCheck),
atc.ListAllJobs: http.HandlerFunc(jobServer.ListAllJobs),
atc.ListJobs: pipelineHandlerFactory.HandlerFor(jobServer.ListJobs),
atc.GetJob: pipelineHandlerFactory.HandlerFor(jobServer.GetJob),

View File

@ -1527,27 +1527,57 @@ var _ = Describe("Jobs API", func() {
BeforeEach(func() {
fakeResource = new(dbfakes.FakeResource)
fakeResource.NameReturns("some-input")
fakeResource.CurrentPinnedVersionReturns(atc.Version{"some": "version"})
fakePipeline.ResourcesReturns([]db.Resource{fakeResource}, nil)
})
It("returns 200 OK", func() {
Expect(response.StatusCode).To(Equal(http.StatusOK))
Context("when finding the pipeline resource types fails", func() {
BeforeEach(func() {
fakePipeline.ResourceTypesReturns(nil, errors.New("nope"))
})
It("returns a 500", func() {
Expect(response.StatusCode).To(Equal(http.StatusInternalServerError))
})
})
It("returns Content-Type 'application/json'", func() {
Expect(response.Header.Get("Content-Type")).To(Equal("application/json"))
})
Context("when finding the pipeline resources types succeeds", func() {
var fakeResourceType *dbfakes.FakeResourceType
It("notifies a scan of the resource", func() {
Expect(fakeResource.NotifyScanCallCount()).To(Equal(1))
})
BeforeEach(func() {
fakeResourceType = new(dbfakes.FakeResourceType)
fakeResourceType.NameReturns("some-input")
It("returns the build", func() {
body, err := ioutil.ReadAll(response.Body)
Expect(err).NotTo(HaveOccurred())
fakePipeline.ResourceTypesReturns([]db.ResourceType{fakeResourceType}, nil)
})
Expect(body).To(MatchJSON(`{
It("returns 200 OK", func() {
Expect(response.StatusCode).To(Equal(http.StatusOK))
})
It("returns Content-Type 'application/json'", func() {
Expect(response.Header.Get("Content-Type")).To(Equal("application/json"))
})
It("creates a check for the resource", func() {
Expect(dbCheckFactory.TryCreateCheckCallCount()).To(Equal(1))
})
It("runs the check from the current pinned version", func() {
_, _, fromVersion, _ := dbCheckFactory.TryCreateCheckArgsForCall(0)
Expect(fromVersion).To(Equal(atc.Version{"some": "version"}))
})
It("notifies the checker to run", func() {
Expect(dbCheckFactory.NotifyCheckerCallCount()).To(Equal(1))
})
It("returns the build", func() {
body, err := ioutil.ReadAll(response.Body)
Expect(err).NotTo(HaveOccurred())
Expect(body).To(MatchJSON(`{
"id": 42,
"name": "1",
"job_name": "some-job",
@ -1558,6 +1588,7 @@ var _ = Describe("Jobs API", func() {
"start_time": 1,
"end_time": 100
}`))
})
})
})
})

View File

@ -41,7 +41,14 @@ func (s *Server) CreateJobBuild(pipeline db.Pipeline) http.Handler {
resources, err := pipeline.Resources()
if err != nil {
logger.Error("failed-to-create-job-build", err)
logger.Error("failed-to-get-resources", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
resourceTypes, err := pipeline.ResourceTypes()
if err != nil {
logger.Error("failed-to-get-resource-types", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
@ -49,12 +56,19 @@ func (s *Server) CreateJobBuild(pipeline db.Pipeline) http.Handler {
for _, input := range job.Config().Inputs() {
resource, found := resources.Lookup(input.Resource)
if found {
if err = resource.NotifyScan(); err != nil {
logger.Error("failed-to-notify-scan", err)
version := resource.CurrentPinnedVersion()
_, _, err := s.checkFactory.TryCreateCheck(resource, resourceTypes, version, true)
if err != nil {
logger.Error("failed-to-create-check", err)
}
}
}
err = s.checkFactory.NotifyChecker()
if err != nil {
logger.Error("failed-to-notify-checker", err)
}
err = json.NewEncoder(w).Encode(present.Build(build))
if err != nil {
logger.Error("failed-to-encode-build", err)

View File

@ -14,6 +14,7 @@ type Server struct {
rejector auth.Rejector
secretManager creds.Secrets
jobFactory db.JobFactory
checkFactory db.CheckFactory
}
func NewServer(
@ -21,6 +22,7 @@ func NewServer(
externalURL string,
secretManager creds.Secrets,
jobFactory db.JobFactory,
checkFactory db.CheckFactory,
) *Server {
return &Server{
logger: logger,
@ -28,5 +30,6 @@ func NewServer(
rejector: auth.UnauthorizedRejector{},
secretManager: secretManager,
jobFactory: jobFactory,
checkFactory: checkFactory,
}
}

32
atc/api/present/check.go Normal file
View File

@ -0,0 +1,32 @@
package present
import (
"github.com/concourse/concourse/atc"
"github.com/concourse/concourse/atc/db"
)
func Check(check db.Check) atc.Check {
atcCheck := atc.Check{
ID: check.ID(),
Status: string(check.Status()),
}
if !check.CreateTime().IsZero() {
atcCheck.CreateTime = check.CreateTime().Unix()
}
if !check.StartTime().IsZero() {
atcCheck.StartTime = check.StartTime().Unix()
}
if !check.EndTime().IsZero() {
atcCheck.EndTime = check.EndTime().Unix()
}
if err := check.CheckError(); err != nil {
atcCheck.CheckError = err.Error()
}
return atcCheck
}

View File

@ -9,7 +9,6 @@ import (
"net/http"
"time"
"github.com/google/jsonapi"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
@ -18,8 +17,6 @@ import (
"github.com/concourse/concourse/atc/creds"
"github.com/concourse/concourse/atc/db"
"github.com/concourse/concourse/atc/db/dbfakes"
"github.com/concourse/concourse/atc/radar/radarfakes"
"github.com/concourse/concourse/atc/resource"
"github.com/concourse/concourse/vars"
)
@ -561,14 +558,10 @@ var _ = Describe("Resources API", func() {
})
Describe("POST /api/v1/teams/:team_name/pipelines/:pipeline_name/resources/:resource_name/check", func() {
var fakeScanner *radarfakes.FakeScanner
var checkRequestBody atc.CheckRequestBody
var response *http.Response
BeforeEach(func() {
fakeScanner = new(radarfakes.FakeScanner)
fakeScannerFactory.NewResourceScannerReturns(fakeScanner)
checkRequestBody = atc.CheckRequestBody{}
})
@ -609,108 +602,107 @@ var _ = Describe("Resources API", func() {
})
Context("when it finds the resource", func() {
var fakeResource *dbfakes.FakeResource
BeforeEach(func() {
fakeResource := new(dbfakes.FakeResource)
fakeResource = new(dbfakes.FakeResource)
fakeResource.IDReturns(1)
fakePipeline.ResourceReturns(fakeResource, true, nil)
})
It("injects the proper pipelineDB", func() {
Expect(dbTeam.PipelineCallCount()).To(Equal(1))
pipelineName := dbTeam.PipelineArgsForCall(0)
Expect(pipelineName).To(Equal("a-pipeline"))
})
It("tries to scan with no version specified", func() {
Expect(fakeScanner.ScanFromVersionCallCount()).To(Equal(1))
_, actualResourceID, actualFromVersion := fakeScanner.ScanFromVersionArgsForCall(0)
Expect(actualResourceID).To(Equal(1))
Expect(actualFromVersion).To(BeNil())
})
It("returns 200", func() {
Expect(response.StatusCode).To(Equal(http.StatusOK))
})
Context("when checking with a version specified", func() {
Context("when looking up the resource types fails", func() {
BeforeEach(func() {
checkRequestBody = atc.CheckRequestBody{
From: atc.Version{
"some-version-key": "some-version-value",
},
}
fakePipeline.ResourceTypesReturns(nil, errors.New("nope"))
})
It("tries to scan with the version specified", func() {
Expect(fakeScanner.ScanFromVersionCallCount()).To(Equal(1))
_, actualResourceID, actualFromVersion := fakeScanner.ScanFromVersionArgsForCall(0)
Expect(actualResourceID).To(Equal(1))
Expect(actualFromVersion).To(Equal(checkRequestBody.From))
})
})
Context("when checking fails with ResourceNotFoundError", func() {
BeforeEach(func() {
fakeScanner.ScanFromVersionReturns(db.ResourceNotFoundError{})
})
It("returns 404", func() {
Expect(response.StatusCode).To(Equal(http.StatusNotFound))
})
})
Context("when checking the resource fails with ResourceTypeNotFoundError", func() {
BeforeEach(func() {
fakeScanner.ScanFromVersionReturns(db.ResourceTypeNotFoundError{ID: 13})
})
It("returns jsonapi 400", func() {
Expect(response.StatusCode).To(Equal(http.StatusBadRequest))
Expect(response.Header.Get("Content-Type")).To(Equal(jsonapi.MediaType))
})
})
Context("when checking the resource fails internally", func() {
BeforeEach(func() {
fakeScanner.ScanFromVersionReturns(errors.New("welp"))
})
It("returns 500", func() {
Expect(response.StatusCode).To(Equal(http.StatusInternalServerError))
buf := new(bytes.Buffer)
_, err := buf.ReadFrom(response.Body)
Expect(err).ToNot(HaveOccurred())
body := buf.String()
Expect(body).To(Equal("welp"))
})
})
Context("when checking the resource fails with ErrResourceScriptFailed", func() {
Context("when looking up the resource types succeeds", func() {
var fakeResourceTypes db.ResourceTypes
BeforeEach(func() {
fakeScanner.ScanFromVersionReturns(
resource.ErrResourceScriptFailed{
ExitStatus: 42,
Stderr: "my tooth",
},
)
fakeResourceTypes = db.ResourceTypes{}
fakePipeline.ResourceTypesReturns(fakeResourceTypes, nil)
})
It("returns 400", func() {
Expect(response.StatusCode).To(Equal(http.StatusBadRequest))
It("checks with no version specified", func() {
Expect(dbCheckFactory.TryCreateCheckCallCount()).To(Equal(1))
actualResource, actualResourceTypes, actualFromVersion, manuallyTriggered := dbCheckFactory.TryCreateCheckArgsForCall(0)
Expect(actualResource).To(Equal(fakeResource))
Expect(actualResourceTypes).To(Equal(fakeResourceTypes))
Expect(actualFromVersion).To(BeNil())
Expect(manuallyTriggered).To(BeTrue())
})
It("returns the script's exit status and stderr", func() {
body, err := ioutil.ReadAll(response.Body)
Expect(err).NotTo(HaveOccurred())
Context("when checking with a version specified", func() {
BeforeEach(func() {
checkRequestBody = atc.CheckRequestBody{
From: atc.Version{
"some-version-key": "some-version-value",
},
}
})
Expect(body).To(MatchJSON(`{
"exit_status": 42,
"stderr": "my tooth"
}`))
It("checks with the version specified", func() {
Expect(dbCheckFactory.TryCreateCheckCallCount()).To(Equal(1))
actualResource, actualResourceTypes, actualFromVersion, manuallyTriggered := dbCheckFactory.TryCreateCheckArgsForCall(0)
Expect(actualResource).To(Equal(fakeResource))
Expect(actualResourceTypes).To(Equal(fakeResourceTypes))
Expect(actualFromVersion).To(Equal(checkRequestBody.From))
Expect(manuallyTriggered).To(BeTrue())
})
})
It("returns application/json", func() {
Expect(response.Header.Get("Content-Type")).To(Equal("application/json"))
Context("when checking fails", func() {
BeforeEach(func() {
dbCheckFactory.TryCreateCheckReturns(nil, false, errors.New("nope"))
})
It("returns 500", func() {
Expect(response.StatusCode).To(Equal(http.StatusInternalServerError))
})
})
Context("when checking does not create a new check", func() {
BeforeEach(func() {
dbCheckFactory.TryCreateCheckReturns(nil, false, nil)
})
It("returns 500", func() {
Expect(response.StatusCode).To(Equal(http.StatusInternalServerError))
})
})
Context("when checking creates a new check", func() {
var fakeCheck *dbfakes.FakeCheck
BeforeEach(func() {
fakeCheck = new(dbfakes.FakeCheck)
fakeCheck.IDReturns(10)
fakeCheck.StatusReturns("started")
fakeCheck.CreateTimeReturns(time.Date(2000, 01, 01, 0, 0, 0, 0, time.UTC))
fakeCheck.StartTimeReturns(time.Date(2001, 01, 01, 0, 0, 0, 0, time.UTC))
fakeCheck.EndTimeReturns(time.Date(2002, 01, 01, 0, 0, 0, 0, time.UTC))
dbCheckFactory.TryCreateCheckReturns(fakeCheck, true, nil)
})
It("notify checker", func() {
Expect(dbCheckFactory.NotifyCheckerCallCount()).To(Equal(1))
})
It("returns 201", func() {
Expect(response.StatusCode).To(Equal(http.StatusCreated))
Expect(ioutil.ReadAll(response.Body)).To(MatchJSON(`{
"id": 10,
"status": "started",
"create_time": 946684800,
"start_time": 978307200,
"end_time": 1009843200
}`))
})
})
})
})
@ -1228,14 +1220,10 @@ var _ = Describe("Resources API", func() {
})
Context("when authenticated and authorized", func() {
var fakeScanner *radarfakes.FakeScanner
BeforeEach(func() {
fakeaccess.IsAuthenticatedReturns(true)
fakeaccess.IsAuthorizedReturns(true)
fakeScanner = new(radarfakes.FakeScanner)
fakeScannerFactory.NewResourceTypeScannerReturns(fakeScanner)
})
Context("when looking up the resource type fails", func() {
@ -1257,83 +1245,128 @@ var _ = Describe("Resources API", func() {
})
Context("when it finds the resource type", func() {
var fakeResourceType *dbfakes.FakeResourceType
BeforeEach(func() {
fakeResourceType := new(dbfakes.FakeResourceType)
fakeResourceType = new(dbfakes.FakeResourceType)
fakeResourceType.IDReturns(1)
fakePipeline.ResourceTypeReturns(fakeResourceType, true, nil)
})
It("returns 200", func() {
Expect(response.StatusCode).To(Equal(http.StatusOK))
})
It("calls Scan", func() {
Expect(fakeScanner.ScanFromVersionCallCount()).To(Equal(1))
})
Context("when checking with a version specified", func() {
Context("when looking up the resource types fails", func() {
BeforeEach(func() {
checkRequestBody = atc.CheckRequestBody{
From: atc.Version{
"some-version-key": "some-version-value",
},
}
})
It("tries to scan with the version specified", func() {
Expect(fakeScanner.ScanFromVersionCallCount()).To(Equal(1))
_, actualResourceID, actualFromVersion := fakeScanner.ScanFromVersionArgsForCall(0)
Expect(actualResourceID).To(Equal(1))
Expect(actualFromVersion).To(Equal(checkRequestBody.From))
})
})
Context("when resource type checking fails with ResourceNotFoundError", func() {
BeforeEach(func() {
fakeScanner.ScanFromVersionReturns(db.ResourceTypeNotFoundError{})
})
It("returns 404", func() {
Expect(response.StatusCode).To(Equal(http.StatusNotFound))
})
})
Context("when resource type fails with unexpected error", func() {
BeforeEach(func() {
err := errors.New("some-error")
fakeScanner.ScanFromVersionReturns(err)
fakePipeline.ResourceTypesReturns(nil, errors.New("nope"))
})
It("returns 500", func() {
Expect(response.StatusCode).To(Equal(http.StatusInternalServerError))
})
})
Context("when looking up the resource types succeeds", func() {
var fakeResourceTypes db.ResourceTypes
BeforeEach(func() {
fakeResourceTypes = db.ResourceTypes{}
fakePipeline.ResourceTypesReturns(fakeResourceTypes, nil)
})
It("checks with no version specified", func() {
Expect(dbCheckFactory.TryCreateCheckCallCount()).To(Equal(1))
actualResourceType, actualResourceTypes, actualFromVersion, manuallyTriggered := dbCheckFactory.TryCreateCheckArgsForCall(0)
Expect(actualResourceType).To(Equal(fakeResourceType))
Expect(actualResourceTypes).To(Equal(fakeResourceTypes))
Expect(actualFromVersion).To(BeNil())
Expect(manuallyTriggered).To(BeTrue())
})
Context("when checking with a version specified", func() {
BeforeEach(func() {
checkRequestBody = atc.CheckRequestBody{
From: atc.Version{
"some-version-key": "some-version-value",
},
}
})
It("checks with no version specified", func() {
Expect(dbCheckFactory.TryCreateCheckCallCount()).To(Equal(1))
actualResourceType, actualResourceTypes, actualFromVersion, manuallyTriggered := dbCheckFactory.TryCreateCheckArgsForCall(0)
Expect(actualResourceType).To(Equal(fakeResourceType))
Expect(actualResourceTypes).To(Equal(fakeResourceTypes))
Expect(actualFromVersion).To(Equal(checkRequestBody.From))
Expect(manuallyTriggered).To(BeTrue())
})
})
Context("when checking fails", func() {
BeforeEach(func() {
dbCheckFactory.TryCreateCheckReturns(nil, false, errors.New("nope"))
})
It("returns 500", func() {
Expect(response.StatusCode).To(Equal(http.StatusInternalServerError))
})
})
Context("when checking does not create a new check", func() {
BeforeEach(func() {
dbCheckFactory.TryCreateCheckReturns(nil, false, nil)
})
It("returns 500", func() {
Expect(response.StatusCode).To(Equal(http.StatusInternalServerError))
})
})
Context("when checking creates a new check", func() {
var fakeCheck *dbfakes.FakeCheck
BeforeEach(func() {
fakeCheck = new(dbfakes.FakeCheck)
fakeCheck.IDReturns(10)
fakeCheck.StatusReturns("started")
fakeCheck.CreateTimeReturns(time.Date(2000, 01, 01, 0, 0, 0, 0, time.UTC))
fakeCheck.StartTimeReturns(time.Date(2001, 01, 01, 0, 0, 0, 0, time.UTC))
fakeCheck.EndTimeReturns(time.Date(2002, 01, 01, 0, 0, 0, 0, time.UTC))
dbCheckFactory.TryCreateCheckReturns(fakeCheck, true, nil)
})
It("notify checker", func() {
Expect(dbCheckFactory.NotifyCheckerCallCount()).To(Equal(1))
})
It("returns 201", func() {
Expect(response.StatusCode).To(Equal(http.StatusCreated))
Expect(ioutil.ReadAll(response.Body)).To(MatchJSON(`{
"id": 10,
"status": "started",
"create_time": 946684800,
"start_time": 978307200,
"end_time": 1009843200
}`))
})
})
})
})
})
})
Describe("POST /api/v1/teams/:team_name/pipelines/:pipeline_name/resources/:resource_name/check/webhook", func() {
var (
fakeScanner *radarfakes.FakeScanner
checkRequestBody atc.CheckRequestBody
response *http.Response
fakeResource *dbfakes.FakeResource
fakeResourceConfig *dbfakes.FakeResourceConfig
fakeResourceConfigVersion *dbfakes.FakeResourceConfigVersion
fakeResourceConfigScope *dbfakes.FakeResourceConfigScope
checkRequestBody atc.CheckRequestBody
response *http.Response
fakeResource *dbfakes.FakeResource
)
BeforeEach(func() {
fakeScanner = new(radarfakes.FakeScanner)
fakeScannerFactory.NewResourceScannerReturns(fakeScanner)
checkRequestBody = atc.CheckRequestBody{}
fakeResource = new(dbfakes.FakeResource)
fakeResource.NameReturns("resource-name")
fakeResource.IDReturns(10)
fakeResourceConfig = new(dbfakes.FakeResourceConfig)
fakeResourceConfigVersion = new(dbfakes.FakeResourceConfigVersion)
fakeResourceConfigScope = new(dbfakes.FakeResourceConfigScope)
})
JustBeforeEach(func() {
@ -1377,101 +1410,81 @@ var _ = Describe("Resources API", func() {
fakePipeline.ResourceReturns(fakeResource, true, nil)
})
It("tries to find the resource config using the resource config id", func() {
Eventually(dbResourceConfigFactory.FindResourceConfigByIDCallCount).Should(Equal(1))
Expect(dbResourceConfigFactory.FindResourceConfigByIDArgsForCall(0)).To(Equal(1))
})
Context("when finding the resource config succeeds", func() {
Context("when finding the resource types fails", func() {
BeforeEach(func() {
dbResourceConfigFactory.FindResourceConfigByIDReturns(fakeResourceConfig, true, nil)
fakePipeline.ResourceTypesReturns(nil, errors.New("oops"))
})
It("tries to find the resource config scope using the resource config scope id", func() {
Eventually(fakeResourceConfig.FindResourceConfigScopeByIDCallCount).Should(Equal(1))
resourceConfigScopeID, resource := fakeResourceConfig.FindResourceConfigScopeByIDArgsForCall(0)
Expect(resourceConfigScopeID).To(Equal(2))
Expect(resource).To(Equal(fakeResource))
})
Context("when finding the resource config scope succeeds", func() {
BeforeEach(func() {
fakeResourceConfig.FindResourceConfigScopeByIDReturns(fakeResourceConfigScope, true, nil)
})
Context("when the latest version is found", func() {
BeforeEach(func() {
fakeResourceConfigVersion.IDReturns(4)
fakeResourceConfigVersion.VersionReturns(db.Version{"some": "version"})
fakeResourceConfigVersion.MetadataReturns([]db.ResourceConfigMetadataField{
{
Name: "some",
Value: "metadata",
},
})
fakeResourceConfigScope.LatestVersionReturns(fakeResourceConfigVersion, true, nil)
})
It("tries to scan with the latest version", func() {
Eventually(fakeScanner.ScanFromVersionCallCount).Should(Equal(1))
_, actualResourceID, actualFromVersion := fakeScanner.ScanFromVersionArgsForCall(0)
Expect(actualResourceID).To(Equal(10))
Expect(actualFromVersion).To(Equal(atc.Version{"some": "version"}))
})
It("returns 200", func() {
Expect(response.StatusCode).To(Equal(http.StatusOK))
})
})
Context("when the latest version is not found", func() {
BeforeEach(func() {
fakeResourceConfigScope.LatestVersionReturns(nil, false, nil)
})
It("tries to scan with no version specified", func() {
Eventually(fakeScanner.ScanFromVersionCallCount).Should(Equal(1))
_, actualResourceID, actualFromVersion := fakeScanner.ScanFromVersionArgsForCall(0)
Expect(actualResourceID).To(Equal(10))
Expect(actualFromVersion).To(BeNil())
})
It("returns 200", func() {
Expect(response.StatusCode).To(Equal(http.StatusOK))
})
})
Context("when failing to get latest version for resource", func() {
BeforeEach(func() {
fakeResourceConfigScope.LatestVersionReturns(nil, false, errors.New("disaster"))
})
It("does not scan from version", func() {
Consistently(fakeScanner.ScanFromVersionCallCount).Should(Equal(0))
})
})
})
Context("when the resource config scope is not found", func() {
BeforeEach(func() {
fakeResourceConfig.FindResourceConfigScopeByIDReturns(nil, false, nil)
})
It("tries to scan", func() {
Eventually(fakeScanner.ScanFromVersionCallCount).Should(Equal(1))
})
It("returns 500", func() {
Expect(response.StatusCode).To(Equal(http.StatusInternalServerError))
})
})
Context("when the resource config is not found", func() {
Context("when finding the resource types succeeds", func() {
var fakeResourceTypes db.ResourceTypes
BeforeEach(func() {
dbResourceConfigFactory.FindResourceConfigByIDReturns(nil, false, nil)
fakeResourceTypes = db.ResourceTypes{}
fakePipeline.ResourceTypesReturns(fakeResourceTypes, nil)
})
It("tries to scan", func() {
Eventually(fakeScanner.ScanFromVersionCallCount).Should(Equal(1))
It("checks with a nil version", func() {
Expect(dbCheckFactory.TryCreateCheckCallCount()).To(Equal(1))
actualResource, actualResourceTypes, actualFromVersion, manuallyTriggered := dbCheckFactory.TryCreateCheckArgsForCall(0)
Expect(actualResource).To(Equal(fakeResource))
Expect(actualResourceTypes).To(Equal(fakeResourceTypes))
Expect(actualFromVersion).To(BeNil())
Expect(manuallyTriggered).To(BeTrue())
})
Context("when checking fails", func() {
BeforeEach(func() {
dbCheckFactory.TryCreateCheckReturns(nil, false, errors.New("nope"))
})
It("returns 500", func() {
Expect(response.StatusCode).To(Equal(http.StatusInternalServerError))
})
})
Context("when checking does not create a new check", func() {
BeforeEach(func() {
dbCheckFactory.TryCreateCheckReturns(nil, false, nil)
})
It("returns 500", func() {
Expect(response.StatusCode).To(Equal(http.StatusInternalServerError))
})
})
Context("when checking creates a new check", func() {
var fakeCheck *dbfakes.FakeCheck
BeforeEach(func() {
fakeCheck = new(dbfakes.FakeCheck)
fakeCheck.IDReturns(10)
fakeCheck.StatusReturns("started")
fakeCheck.CreateTimeReturns(time.Date(2000, 01, 01, 0, 0, 0, 0, time.UTC))
fakeCheck.StartTimeReturns(time.Date(2001, 01, 01, 0, 0, 0, 0, time.UTC))
fakeCheck.EndTimeReturns(time.Date(2002, 01, 01, 0, 0, 0, 0, time.UTC))
dbCheckFactory.TryCreateCheckReturns(fakeCheck, true, nil)
})
It("notify checker", func() {
Expect(dbCheckFactory.NotifyCheckerCallCount()).To(Equal(1))
})
It("returns 201", func() {
Expect(response.StatusCode).To(Equal(http.StatusCreated))
Expect(ioutil.ReadAll(response.Body)).To(MatchJSON(`{
"id": 10,
"status": "started",
"create_time": 946684800,
"start_time": 978307200,
"end_time": 1009843200
}`))
})
})
})
})
@ -1495,7 +1508,6 @@ var _ = Describe("Resources API", func() {
Expect(response.StatusCode).To(Equal(http.StatusNotFound))
})
})
})
Context("when unauthorized", func() {

View File

@ -6,9 +6,8 @@ import (
"code.cloudfoundry.org/lager"
"github.com/concourse/concourse/atc"
"github.com/concourse/concourse/atc/api/present"
"github.com/concourse/concourse/atc/db"
"github.com/concourse/concourse/atc/resource"
"github.com/google/jsonapi"
"github.com/tedsuo/rata"
)
@ -39,39 +38,40 @@ func (s *Server) CheckResource(dbPipeline db.Pipeline) http.Handler {
return
}
scanner := s.scannerFactory.NewResourceScanner(dbPipeline)
err = scanner.ScanFromVersion(logger, dbResource.ID(), reqBody.From)
switch scanErr := err.(type) {
case resource.ErrResourceScriptFailed:
checkResponseBody := atc.CheckResponseBody{
ExitStatus: scanErr.ExitStatus,
Stderr: scanErr.Stderr,
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusBadRequest)
err = json.NewEncoder(w).Encode(checkResponseBody)
if err != nil {
logger.Error("failed-to-encode-check-response-body", err)
w.WriteHeader(http.StatusInternalServerError)
_, _ = w.Write([]byte(err.Error()))
}
case db.ResourceNotFoundError:
w.WriteHeader(http.StatusNotFound)
case db.ResourceTypeNotFoundError:
w.Header().Set("Content-Type", jsonapi.MediaType)
w.WriteHeader(http.StatusBadRequest)
_ = jsonapi.MarshalErrors(w, []*jsonapi.ErrorObject{{
Title: "Resource Type Not Found Error",
Detail: err.Error(),
Status: "400",
}})
case error:
dbResourceTypes, err := dbPipeline.ResourceTypes()
if err != nil {
logger.Error("failed-to-get-resource-types", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
check, created, err := s.checkFactory.TryCreateCheck(dbResource, dbResourceTypes, reqBody.From, true)
if err != nil {
s.logger.Error("failed-to-create-check", err)
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(err.Error()))
return
}
if !created {
s.logger.Info("check-not-created")
w.WriteHeader(http.StatusInternalServerError)
return
}
err = s.checkFactory.NotifyChecker()
if err != nil {
s.logger.Error("failed-to-notify-checker", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusCreated)
err = json.NewEncoder(w).Encode(present.Check(check))
if err != nil {
logger.Error("failed-to-encode-check", err)
w.WriteHeader(http.StatusInternalServerError)
_, _ = w.Write([]byte(err.Error()))
default:
w.WriteHeader(http.StatusOK)
}
})
}

View File

@ -6,6 +6,7 @@ import (
"code.cloudfoundry.org/lager"
"github.com/concourse/concourse/atc"
"github.com/concourse/concourse/atc/api/present"
"github.com/concourse/concourse/atc/db"
"github.com/tedsuo/rata"
)
@ -37,17 +38,40 @@ func (s *Server) CheckResourceType(dbPipeline db.Pipeline) http.Handler {
return
}
scanner := s.scannerFactory.NewResourceTypeScanner(dbPipeline)
err = scanner.ScanFromVersion(logger, dbResourceType.ID(), reqBody.From)
switch err.(type) {
case db.ResourceTypeNotFoundError:
w.WriteHeader(http.StatusNotFound)
case error:
dbResourceTypes, err := dbPipeline.ResourceTypes()
if err != nil {
logger.Error("failed-to-get-resource-types", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
check, created, err := s.checkFactory.TryCreateCheck(dbResourceType, dbResourceTypes, reqBody.From, true)
if err != nil {
s.logger.Error("failed-to-create-check", err)
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(err.Error()))
return
}
if !created {
s.logger.Info("check-not-created")
w.WriteHeader(http.StatusInternalServerError)
return
}
err = s.checkFactory.NotifyChecker()
if err != nil {
s.logger.Error("failed-to-notify-checker", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusCreated)
err = json.NewEncoder(w).Encode(present.Check(check))
if err != nil {
logger.Error("failed-to-encode-check", err)
w.WriteHeader(http.StatusInternalServerError)
_, _ = w.Write([]byte(err.Error()))
default:
w.WriteHeader(http.StatusOK)
}
})
}

View File

@ -1,11 +1,12 @@
package resourceserver
import (
"encoding/json"
"fmt"
"net/http"
"code.cloudfoundry.org/lager"
"github.com/concourse/concourse/atc"
"github.com/concourse/concourse/atc/api/present"
"github.com/concourse/concourse/atc/creds"
"github.com/concourse/concourse/atc/db"
"github.com/tedsuo/rata"
@ -25,7 +26,7 @@ func (s *Server) CheckResourceWebHook(dbPipeline db.Pipeline) http.Handler {
return
}
pipelineResource, found, err := dbPipeline.Resource(resourceName)
dbResource, found, err := dbPipeline.Resource(resourceName)
if err != nil {
logger.Error("database-error", err, lager.Data{"resource-name": resourceName})
w.WriteHeader(http.StatusInternalServerError)
@ -39,45 +40,47 @@ func (s *Server) CheckResourceWebHook(dbPipeline db.Pipeline) http.Handler {
}
variables := creds.NewVariables(s.secretManager, dbPipeline.TeamName(), dbPipeline.Name())
token, err := creds.NewString(variables, pipelineResource.WebhookToken()).Evaluate()
token, err := creds.NewString(variables, dbResource.WebhookToken()).Evaluate()
if token != webhookToken {
logger.Info("invalid-token", lager.Data{"error": fmt.Sprintf("invalid token for webhook %s", webhookToken)})
w.WriteHeader(http.StatusUnauthorized)
return
}
go func() {
var fromVersion atc.Version
resourceConfigID := pipelineResource.ResourceConfigID()
resourceConfig, found, err := s.resourceConfigFactory.FindResourceConfigByID(resourceConfigID)
if err != nil {
logger.Error("failed-to-get-resource-config", err, lager.Data{"resource-config-id": resourceConfigID})
return
}
dbResourceTypes, err := dbPipeline.ResourceTypes()
if err != nil {
logger.Error("failed-to-get-resource-types", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
if found {
resourceConfigScope, found, err := resourceConfig.FindResourceConfigScopeByID(pipelineResource.ResourceConfigScopeID(), pipelineResource)
if err != nil {
logger.Error("failed-to-get-resource-config-scope", err, lager.Data{"resource-config-scope-id": pipelineResource.ResourceConfigScopeID()})
return
}
check, created, err := s.checkFactory.TryCreateCheck(dbResource, dbResourceTypes, nil, true)
if err != nil {
s.logger.Error("failed-to-create-check", err)
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(err.Error()))
return
}
if found {
latestVersion, found, err := resourceConfigScope.LatestVersion()
if err != nil {
logger.Error("failed-to-get-latest-resource-version", err, lager.Data{"resource-config-id": resourceConfigID})
return
}
if found {
fromVersion = atc.Version(latestVersion.Version())
}
}
}
if !created {
s.logger.Info("check-not-created")
w.WriteHeader(http.StatusInternalServerError)
return
}
scanner := s.scannerFactory.NewResourceScanner(dbPipeline)
scanner.ScanFromVersion(logger, pipelineResource.ID(), fromVersion)
}()
err = s.checkFactory.NotifyChecker()
if err != nil {
s.logger.Error("failed-to-notify-checker", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusOK)
w.WriteHeader(http.StatusCreated)
err = json.NewEncoder(w).Encode(present.Check(check))
if err != nil {
logger.Error("failed-to-encode-check", err)
w.WriteHeader(http.StatusInternalServerError)
}
})
}

View File

@ -0,0 +1,13 @@
package resourceserver_test
import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"testing"
)
func TestResourceserver(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Resourceserver Suite")
}

View File

@ -1,185 +0,0 @@
// Code generated by counterfeiter. DO NOT EDIT.
package resourceserverfakes
import (
"sync"
"github.com/concourse/concourse/atc/api/resourceserver"
"github.com/concourse/concourse/atc/db"
"github.com/concourse/concourse/atc/radar"
)
type FakeScannerFactory struct {
NewResourceScannerStub func(db.Pipeline) radar.Scanner
newResourceScannerMutex sync.RWMutex
newResourceScannerArgsForCall []struct {
arg1 db.Pipeline
}
newResourceScannerReturns struct {
result1 radar.Scanner
}
newResourceScannerReturnsOnCall map[int]struct {
result1 radar.Scanner
}
NewResourceTypeScannerStub func(db.Pipeline) radar.Scanner
newResourceTypeScannerMutex sync.RWMutex
newResourceTypeScannerArgsForCall []struct {
arg1 db.Pipeline
}
newResourceTypeScannerReturns struct {
result1 radar.Scanner
}
newResourceTypeScannerReturnsOnCall map[int]struct {
result1 radar.Scanner
}
invocations map[string][][]interface{}
invocationsMutex sync.RWMutex
}
func (fake *FakeScannerFactory) NewResourceScanner(arg1 db.Pipeline) radar.Scanner {
fake.newResourceScannerMutex.Lock()
ret, specificReturn := fake.newResourceScannerReturnsOnCall[len(fake.newResourceScannerArgsForCall)]
fake.newResourceScannerArgsForCall = append(fake.newResourceScannerArgsForCall, struct {
arg1 db.Pipeline
}{arg1})
fake.recordInvocation("NewResourceScanner", []interface{}{arg1})
fake.newResourceScannerMutex.Unlock()
if fake.NewResourceScannerStub != nil {
return fake.NewResourceScannerStub(arg1)
}
if specificReturn {
return ret.result1
}
fakeReturns := fake.newResourceScannerReturns
return fakeReturns.result1
}
func (fake *FakeScannerFactory) NewResourceScannerCallCount() int {
fake.newResourceScannerMutex.RLock()
defer fake.newResourceScannerMutex.RUnlock()
return len(fake.newResourceScannerArgsForCall)
}
func (fake *FakeScannerFactory) NewResourceScannerCalls(stub func(db.Pipeline) radar.Scanner) {
fake.newResourceScannerMutex.Lock()
defer fake.newResourceScannerMutex.Unlock()
fake.NewResourceScannerStub = stub
}
func (fake *FakeScannerFactory) NewResourceScannerArgsForCall(i int) db.Pipeline {
fake.newResourceScannerMutex.RLock()
defer fake.newResourceScannerMutex.RUnlock()
argsForCall := fake.newResourceScannerArgsForCall[i]
return argsForCall.arg1
}
func (fake *FakeScannerFactory) NewResourceScannerReturns(result1 radar.Scanner) {
fake.newResourceScannerMutex.Lock()
defer fake.newResourceScannerMutex.Unlock()
fake.NewResourceScannerStub = nil
fake.newResourceScannerReturns = struct {
result1 radar.Scanner
}{result1}
}
func (fake *FakeScannerFactory) NewResourceScannerReturnsOnCall(i int, result1 radar.Scanner) {
fake.newResourceScannerMutex.Lock()
defer fake.newResourceScannerMutex.Unlock()
fake.NewResourceScannerStub = nil
if fake.newResourceScannerReturnsOnCall == nil {
fake.newResourceScannerReturnsOnCall = make(map[int]struct {
result1 radar.Scanner
})
}
fake.newResourceScannerReturnsOnCall[i] = struct {
result1 radar.Scanner
}{result1}
}
func (fake *FakeScannerFactory) NewResourceTypeScanner(arg1 db.Pipeline) radar.Scanner {
fake.newResourceTypeScannerMutex.Lock()
ret, specificReturn := fake.newResourceTypeScannerReturnsOnCall[len(fake.newResourceTypeScannerArgsForCall)]
fake.newResourceTypeScannerArgsForCall = append(fake.newResourceTypeScannerArgsForCall, struct {
arg1 db.Pipeline
}{arg1})
fake.recordInvocation("NewResourceTypeScanner", []interface{}{arg1})
fake.newResourceTypeScannerMutex.Unlock()
if fake.NewResourceTypeScannerStub != nil {
return fake.NewResourceTypeScannerStub(arg1)
}
if specificReturn {
return ret.result1
}
fakeReturns := fake.newResourceTypeScannerReturns
return fakeReturns.result1
}
func (fake *FakeScannerFactory) NewResourceTypeScannerCallCount() int {
fake.newResourceTypeScannerMutex.RLock()
defer fake.newResourceTypeScannerMutex.RUnlock()
return len(fake.newResourceTypeScannerArgsForCall)
}
func (fake *FakeScannerFactory) NewResourceTypeScannerCalls(stub func(db.Pipeline) radar.Scanner) {
fake.newResourceTypeScannerMutex.Lock()
defer fake.newResourceTypeScannerMutex.Unlock()
fake.NewResourceTypeScannerStub = stub
}
func (fake *FakeScannerFactory) NewResourceTypeScannerArgsForCall(i int) db.Pipeline {
fake.newResourceTypeScannerMutex.RLock()
defer fake.newResourceTypeScannerMutex.RUnlock()
argsForCall := fake.newResourceTypeScannerArgsForCall[i]
return argsForCall.arg1
}
func (fake *FakeScannerFactory) NewResourceTypeScannerReturns(result1 radar.Scanner) {
fake.newResourceTypeScannerMutex.Lock()
defer fake.newResourceTypeScannerMutex.Unlock()
fake.NewResourceTypeScannerStub = nil
fake.newResourceTypeScannerReturns = struct {
result1 radar.Scanner
}{result1}
}
func (fake *FakeScannerFactory) NewResourceTypeScannerReturnsOnCall(i int, result1 radar.Scanner) {
fake.newResourceTypeScannerMutex.Lock()
defer fake.newResourceTypeScannerMutex.Unlock()
fake.NewResourceTypeScannerStub = nil
if fake.newResourceTypeScannerReturnsOnCall == nil {
fake.newResourceTypeScannerReturnsOnCall = make(map[int]struct {
result1 radar.Scanner
})
}
fake.newResourceTypeScannerReturnsOnCall[i] = struct {
result1 radar.Scanner
}{result1}
}
func (fake *FakeScannerFactory) Invocations() map[string][][]interface{} {
fake.invocationsMutex.RLock()
defer fake.invocationsMutex.RUnlock()
fake.newResourceScannerMutex.RLock()
defer fake.newResourceScannerMutex.RUnlock()
fake.newResourceTypeScannerMutex.RLock()
defer fake.newResourceTypeScannerMutex.RUnlock()
copiedInvocations := map[string][][]interface{}{}
for key, value := range fake.invocations {
copiedInvocations[key] = value
}
return copiedInvocations
}
func (fake *FakeScannerFactory) recordInvocation(key string, args []interface{}) {
fake.invocationsMutex.Lock()
defer fake.invocationsMutex.Unlock()
if fake.invocations == nil {
fake.invocations = map[string][][]interface{}{}
}
if fake.invocations[key] == nil {
fake.invocations[key] = [][]interface{}{}
}
fake.invocations[key] = append(fake.invocations[key], args)
}
var _ resourceserver.ScannerFactory = new(FakeScannerFactory)

View File

@ -4,35 +4,27 @@ import (
"code.cloudfoundry.org/lager"
"github.com/concourse/concourse/atc/creds"
"github.com/concourse/concourse/atc/db"
"github.com/concourse/concourse/atc/radar"
)
//go:generate counterfeiter . ScannerFactory
type ScannerFactory interface {
NewResourceScanner(pipeline db.Pipeline) radar.Scanner
NewResourceTypeScanner(dbPipeline db.Pipeline) radar.Scanner
}
type Server struct {
logger lager.Logger
scannerFactory ScannerFactory
secretManager creds.Secrets
checkFactory db.CheckFactory
resourceFactory db.ResourceFactory
resourceConfigFactory db.ResourceConfigFactory
}
func NewServer(
logger lager.Logger,
scannerFactory ScannerFactory,
secretManager creds.Secrets,
checkFactory db.CheckFactory,
resourceFactory db.ResourceFactory,
resourceConfigFactory db.ResourceConfigFactory,
) *Server {
return &Server{
logger: logger,
scannerFactory: scannerFactory,
secretManager: secretManager,
checkFactory: checkFactory,
resourceFactory: resourceFactory,
resourceConfigFactory: resourceConfigFactory,
}

View File

@ -35,6 +35,7 @@ import (
"github.com/concourse/concourse/atc/engine/builder"
"github.com/concourse/concourse/atc/fetcher"
"github.com/concourse/concourse/atc/gc"
"github.com/concourse/concourse/atc/lidar"
"github.com/concourse/concourse/atc/lockrunner"
"github.com/concourse/concourse/atc/metric"
"github.com/concourse/concourse/atc/pipelines"
@ -113,6 +114,7 @@ type RunCommand struct {
InterceptIdleTimeout time.Duration `long:"intercept-idle-timeout" default:"0m" description:"Length of time for a intercepted session to be idle before terminating."`
EnableGlobalResources bool `long:"enable-global-resources" description:"Enable equivalent resources across pipelines and teams to share a single version history."`
EnableLidar bool `long:"enable-lidar" description:"The Future™ of resource checking."`
GlobalResourceCheckTimeout time.Duration `long:"global-resource-check-timeout" default:"1h" description:"Time limit on checking for new versions of resources."`
ResourceCheckingInterval time.Duration `long:"resource-checking-interval" default:"1m" description:"Interval on which to check for new versions of resources."`
@ -153,6 +155,7 @@ type RunCommand struct {
OneOffBuildGracePeriod time.Duration `long:"one-off-grace-period" default:"5m" description:"Period after which one-off build containers will be garbage-collected."`
MissingGracePeriod time.Duration `long:"missing-grace-period" default:"5m" description:"Period after which to reap containers and volumes that were created but went missing from the worker."`
CheckRecyclePeriod time.Duration `long:"check-recycle-period" default:"6h" description:"Period after which to reap checks that are completed."`
} `group:"Garbage Collection" namespace:"gc"`
BuildTrackerInterval time.Duration `long:"build-tracker-interval" default:"10s" description:"Interval on which to run build tracking."`
@ -571,19 +574,6 @@ func (cmd *RunCommand) constructAPIMembers(
pool := worker.NewPool(workerProvider)
workerClient := worker.NewClient(pool, workerProvider)
checkContainerStrategy := worker.NewRandomPlacementStrategy()
radarScannerFactory := radar.NewScannerFactory(
pool,
resourceFactory,
dbResourceConfigFactory,
cmd.ResourceTypeCheckingInterval,
cmd.ResourceCheckingInterval,
cmd.ExternalURL.String(),
secretManager,
checkContainerStrategy,
)
credsManagers := cmd.CredentialManagers
dbPipelineFactory := db.NewPipelineFactory(dbConn, lockFactory)
dbJobFactory := db.NewJobFactory(dbConn, lockFactory)
@ -591,6 +581,7 @@ func (cmd *RunCommand) constructAPIMembers(
dbContainerRepository := db.NewContainerRepository(dbConn)
gcContainerDestroyer := gc.NewDestroyer(logger, dbContainerRepository, dbVolumeRepository)
dbBuildFactory := db.NewBuildFactory(dbConn, lockFactory, cmd.GC.OneOffBuildGracePeriod)
dbCheckFactory := db.NewCheckFactory(dbConn, lockFactory, secretManager, cmd.GlobalResourceCheckTimeout)
accessFactory := accessor.NewAccessFactory(authHandler.PublicKey())
apiHandler, err := cmd.constructAPIHandler(
@ -605,10 +596,10 @@ func (cmd *RunCommand) constructAPIMembers(
dbContainerRepository,
gcContainerDestroyer,
dbBuildFactory,
dbCheckFactory,
dbResourceConfigFactory,
userFactory,
workerClient,
radarScannerFactory,
secretManager,
credsManagers,
accessFactory,
@ -787,10 +778,14 @@ func (cmd *RunCommand) constructBackendMembers(
dbResourceCacheLifecycle := db.NewResourceCacheLifecycle(dbConn)
dbContainerRepository := db.NewContainerRepository(dbConn)
dbArtifactLifecycle := db.NewArtifactLifecycle(dbConn)
dbCheckLifecycle := db.NewCheckLifecycle(dbConn)
resourceConfigCheckSessionLifecycle := db.NewResourceConfigCheckSessionLifecycle(dbConn)
dbBuildFactory := db.NewBuildFactory(dbConn, lockFactory, cmd.GC.OneOffBuildGracePeriod)
bus := dbConn.Bus()
dbCheckFactory := db.NewCheckFactory(dbConn, lockFactory, secretManager, cmd.GlobalResourceCheckTimeout)
dbPipelineFactory := db.NewPipelineFactory(dbConn, lockFactory)
bus := dbConn.Bus()
members := []grouper.Member{
{Name: "pipelines", Runner: pipelines.SyncRunner{
Syncer: cmd.constructPipelineSyncer(
@ -823,6 +818,10 @@ func (cmd *RunCommand) constructBackendMembers(
gc.NewResourceConfigCollector(dbResourceConfigFactory),
gc.NewResourceCacheCollector(dbResourceCacheLifecycle),
gc.NewArtifactCollector(dbArtifactLifecycle),
gc.NewCheckCollector(
dbCheckLifecycle,
cmd.GC.CheckRecyclePeriod,
),
gc.NewVolumeCollector(
dbVolumeRepository,
cmd.GC.MissingGracePeriod,
@ -866,7 +865,46 @@ func (cmd *RunCommand) constructBackendMembers(
)},
}
//Syslog Drainer Configuration
var lidarRunner ifrit.Runner
if cmd.EnableLidar {
lidarRunner = lidar.NewRunner(
logger.Session("lidar"),
clock.NewClock(),
lidar.NewScanner(
logger.Session("lidar-scanner"),
dbCheckFactory,
secretManager,
cmd.GlobalResourceCheckTimeout,
cmd.ResourceCheckingInterval,
),
time.Minute,
lidar.NewChecker(
logger.Session("lidar-checker"),
dbCheckFactory,
engine,
),
10*time.Second,
bus,
)
} else {
lidarRunner = lidar.NewCheckerRunner(
logger.Session("lidar"),
clock.NewClock(),
lidar.NewChecker(
logger.Session("lidar-checker"),
dbCheckFactory,
engine,
),
10*time.Second,
bus,
)
}
members = append(members, grouper.Member{
Name: "lidar", Runner: lidarRunner,
})
if syslogDrainConfigured {
members = append(members, grouper.Member{
Name: "syslog", Runner: lockrunner.NewRunner(
@ -1267,13 +1305,13 @@ func (cmd *RunCommand) constructEngine(
defaultLimits,
strategy,
resourceFactory,
lockFactory,
)
stepBuilder := builder.NewStepBuilder(
stepFactory,
builder.NewDelegateFactory(),
cmd.ExternalURL.String(),
lockFactory,
)
return engine.NewEngine(stepBuilder)
@ -1322,10 +1360,10 @@ func (cmd *RunCommand) constructAPIHandler(
dbContainerRepository db.ContainerRepository,
gcContainerDestroyer gc.Destroyer,
dbBuildFactory db.BuildFactory,
dbCheckFactory db.CheckFactory,
resourceConfigFactory db.ResourceConfigFactory,
dbUserFactory db.UserFactory,
workerClient worker.Client,
radarScannerFactory radar.ScannerFactory,
secretManager creds.Secrets,
credsManagers creds.Managers,
accessFactory accessor.AccessFactory,
@ -1375,13 +1413,13 @@ func (cmd *RunCommand) constructAPIHandler(
dbContainerRepository,
gcContainerDestroyer,
dbBuildFactory,
dbCheckFactory,
resourceConfigFactory,
dbUserFactory,
buildserver.NewEventHandler,
workerClient,
radarScannerFactory,
reconfigurableSink,
@ -1437,7 +1475,7 @@ func (cmd *RunCommand) constructPipelineSyncer(
"team": pipeline.TeamName(),
"pipeline": pipeline.Name(),
}),
cmd.Developer.Noop,
(cmd.Developer.Noop || cmd.EnableLidar),
radarSchedulerFactory.BuildScanRunnerFactory(pipeline, cmd.ExternalURL.String(), variables, bus),
pipeline,
1*time.Minute,

10
atc/check.go Normal file
View File

@ -0,0 +1,10 @@
package atc
type Check struct {
ID int `json:"id"`
Status string `json:"status"`
CreateTime int64 `json:"create_time,omitempty"`
StartTime int64 `json:"start_time,omitempty"`
EndTime int64 `json:"end_time,omitempty"`
CheckError string `json:"check_error,omitempty"`
}

View File

@ -886,7 +886,7 @@ func (b *build) SaveOutput(
return err
}
newVersion, err := saveResourceVersion(tx, resourceConfigScope, version, metadata)
newVersion, err := saveResourceVersion(tx, resourceConfigScope.ID(), version, metadata)
if err != nil {
return err
}
@ -899,7 +899,7 @@ func (b *build) SaveOutput(
versionJSON := string(versionBytes)
if newVersion {
err = incrementCheckOrder(tx, resourceConfigScope, versionJSON)
err = incrementCheckOrder(tx, resourceConfigScope.ID(), versionJSON)
if err != nil {
return err
}

333
atc/db/check.go Normal file
View File

@ -0,0 +1,333 @@
package db
import (
"database/sql"
"encoding/json"
"errors"
"time"
"code.cloudfoundry.org/lager"
sq "github.com/Masterminds/squirrel"
"github.com/concourse/concourse/atc"
"github.com/concourse/concourse/atc/db/lock"
"github.com/lib/pq"
)
type CheckStatus string
const (
CheckStatusStarted CheckStatus = "started"
CheckStatusSucceeded CheckStatus = "succeeded"
CheckStatusErrored CheckStatus = "errored"
)
//go:generate counterfeiter . Check
type Check interface {
ID() int
TeamID() int
ResourceConfigScopeID() int
ResourceConfigID() int
BaseResourceTypeID() int
Schema() string
Plan() atc.Plan
CreateTime() time.Time
StartTime() time.Time
EndTime() time.Time
Status() CheckStatus
CheckError() error
Start() error
Finish() error
FinishWithError(err error) error
SaveVersions([]atc.Version) error
AllCheckables() ([]Checkable, error)
AcquireTrackingLock(lager.Logger) (lock.Lock, bool, error)
Reload() (bool, error)
}
var checksQuery = psql.Select(
"c.id",
"c.resource_config_scope_id",
"c.status",
"c.schema",
"c.create_time",
"c.start_time",
"c.end_time",
"c.plan",
"c.nonce",
"c.check_error",
"(c.metadata->>'team_id')::int",
"(c.metadata->>'resource_config_id')::int",
"(c.metadata->>'base_resource_type_id')::int",
).
From("checks c")
type check struct {
id int
teamID int
resourceConfigScopeID int
resourceConfigID int
baseResourceTypeID int
status CheckStatus
schema string
plan atc.Plan
checkError error
createTime time.Time
startTime time.Time
endTime time.Time
conn Conn
lockFactory lock.LockFactory
}
func (c *check) ID() int { return c.id }
func (c *check) TeamID() int { return c.teamID }
func (c *check) ResourceConfigScopeID() int { return c.resourceConfigScopeID }
func (c *check) ResourceConfigID() int { return c.resourceConfigID }
func (c *check) BaseResourceTypeID() int { return c.baseResourceTypeID }
func (c *check) Status() CheckStatus { return c.status }
func (c *check) Schema() string { return c.schema }
func (c *check) Plan() atc.Plan { return c.plan }
func (c *check) CreateTime() time.Time { return c.createTime }
func (c *check) StartTime() time.Time { return c.startTime }
func (c *check) EndTime() time.Time { return c.endTime }
func (c *check) CheckError() error { return c.checkError }
func (c *check) Reload() (bool, error) {
row := checksQuery.Where(sq.Eq{"c.id": c.id}).
RunWith(c.conn).
QueryRow()
err := scanCheck(c, row)
if err != nil {
if err == sql.ErrNoRows {
return false, nil
}
return false, err
}
return true, nil
}
func (c *check) Start() error {
tx, err := c.conn.Begin()
if err != nil {
return err
}
defer Rollback(tx)
_, err = psql.Update("checks").
Set("start_time", sq.Expr("now()")).
Where(sq.Eq{
"id": c.id,
}).
RunWith(tx).
Exec()
if err != nil {
return err
}
_, err = psql.Update("resource_config_scopes").
Set("last_check_start_time", sq.Expr("now()")).
Where(sq.Eq{
"id": c.resourceConfigScopeID,
}).
RunWith(tx).
Exec()
if err != nil {
return err
}
err = tx.Commit()
if err != nil {
return err
}
return nil
}
func (c *check) Finish() error {
return c.finish(CheckStatusSucceeded, nil)
}
func (c *check) FinishWithError(err error) error {
return c.finish(CheckStatusErrored, err)
}
func (c *check) finish(status CheckStatus, checkError error) error {
tx, err := c.conn.Begin()
if err != nil {
return err
}
defer Rollback(tx)
builder := psql.Update("checks").
Set("status", status).
Set("end_time", sq.Expr("now()")).
Where(sq.Eq{
"id": c.id,
})
if checkError != nil {
builder = builder.Set("check_error", checkError.Error())
}
_, err = builder.
RunWith(tx).
Exec()
if err != nil {
return err
}
builder = psql.Update("resource_config_scopes").
Set("last_check_end_time", sq.Expr("now()")).
Where(sq.Eq{
"id": c.resourceConfigScopeID,
})
if checkError != nil {
builder = builder.Set("check_error", checkError.Error())
} else {
builder = builder.Set("check_error", nil)
}
_, err = builder.
RunWith(tx).
Exec()
if err != nil {
return err
}
err = tx.Commit()
if err != nil {
return err
}
return nil
}
func (c *check) AcquireTrackingLock(logger lager.Logger) (lock.Lock, bool, error) {
return c.lockFactory.Acquire(
logger,
lock.NewResourceConfigCheckingLockID(c.ResourceConfigID()),
)
}
func (c *check) AllCheckables() ([]Checkable, error) {
var checkables []Checkable
rows, err := resourcesQuery.
Where(sq.Eq{
"r.resource_config_scope_id": c.resourceConfigScopeID,
}).
RunWith(c.conn).
Query()
if err != nil {
return nil, err
}
defer Close(rows)
for rows.Next() {
r := &resource{
conn: c.conn,
lockFactory: c.lockFactory,
}
err = scanResource(r, rows)
if err != nil {
return nil, err
}
checkables = append(checkables, r)
}
rows, err = resourceTypesQuery.
Where(sq.Eq{
"ro.id": c.resourceConfigScopeID,
}).
RunWith(c.conn).
Query()
if err != nil {
return nil, err
}
defer Close(rows)
for rows.Next() {
r := &resourceType{
conn: c.conn,
lockFactory: c.lockFactory,
}
err = scanResourceType(r, rows)
if err != nil {
return nil, err
}
checkables = append(checkables, r)
}
return checkables, nil
}
func (c *check) SaveVersions(versions []atc.Version) error {
return saveVersions(c.conn, c.resourceConfigScopeID, versions)
}
func scanCheck(c *check, row scannable) error {
var (
createTime, startTime, endTime pq.NullTime
schema, plan, nonce, checkError sql.NullString
status string
teamID, resourceConfigID, baseResourceTypeID sql.NullInt64
)
err := row.Scan(&c.id, &c.resourceConfigScopeID, &status, &schema, &createTime, &startTime, &endTime, &plan, &nonce, &checkError, &teamID, &resourceConfigID, &baseResourceTypeID)
if err != nil {
return err
}
var noncense *string
if nonce.Valid {
noncense = &nonce.String
}
es := c.conn.EncryptionStrategy()
decryptedPlan, err := es.Decrypt(string(plan.String), noncense)
if err != nil {
return err
}
if len(decryptedPlan) > 0 {
err = json.Unmarshal(decryptedPlan, &c.plan)
if err != nil {
return err
}
}
if checkError.Valid {
c.checkError = errors.New(checkError.String)
} else {
c.checkError = nil
}
c.status = CheckStatus(status)
c.schema = schema.String
c.createTime = createTime.Time
c.startTime = startTime.Time
c.endTime = endTime.Time
c.teamID = int(teamID.Int64)
c.resourceConfigID = int(resourceConfigID.Int64)
c.baseResourceTypeID = int(baseResourceTypeID.Int64)
return nil
}

360
atc/db/check_factory.go Normal file
View File

@ -0,0 +1,360 @@
package db
import (
"database/sql"
"encoding/json"
"errors"
"time"
"code.cloudfoundry.org/lager"
sq "github.com/Masterminds/squirrel"
"github.com/concourse/concourse/atc"
"github.com/concourse/concourse/atc/creds"
"github.com/concourse/concourse/atc/db/lock"
)
//go:generate counterfeiter . Checkable
type Checkable interface {
Name() string
TeamID() int
TeamName() string
PipelineID() int
PipelineName() string
Type() string
Source() atc.Source
Tags() atc.Tags
CheckEvery() string
CheckTimeout() string
LastCheckEndTime() time.Time
CurrentPinnedVersion() atc.Version
SetResourceConfig(
atc.Source,
atc.VersionedResourceTypes,
) (ResourceConfigScope, error)
SetCheckSetupError(error) error
}
//go:generate counterfeiter . CheckFactory
type CheckFactory interface {
Check(int) (Check, bool, error)
StartedChecks() ([]Check, error)
CreateCheck(int, int, int, int, bool, atc.Plan) (Check, bool, error)
TryCreateCheck(Checkable, ResourceTypes, atc.Version, bool) (Check, bool, error)
Resources() ([]Resource, error)
ResourceTypes() ([]ResourceType, error)
AcquireScanningLock(lager.Logger) (lock.Lock, bool, error)
NotifyChecker() error
}
type checkFactory struct {
conn Conn
lockFactory lock.LockFactory
secrets creds.Secrets
defaultCheckTimeout time.Duration
}
func NewCheckFactory(
conn Conn,
lockFactory lock.LockFactory,
secrets creds.Secrets,
defaultCheckTimeout time.Duration,
) CheckFactory {
return &checkFactory{
conn: conn,
lockFactory: lockFactory,
secrets: secrets,
defaultCheckTimeout: defaultCheckTimeout,
}
}
func (c *checkFactory) NotifyChecker() error {
return c.conn.Bus().Notify("checker")
}
func (c *checkFactory) AcquireScanningLock(
logger lager.Logger,
) (lock.Lock, bool, error) {
return c.lockFactory.Acquire(
logger,
lock.NewResourceScanningLockID(),
)
}
func (c *checkFactory) Check(id int) (Check, bool, error) {
check := &check{
conn: c.conn,
lockFactory: c.lockFactory,
}
row := checksQuery.
Where(sq.Eq{"c.id": id}).
RunWith(c.conn).
QueryRow()
err := scanCheck(check, row)
if err != nil {
if err == sql.ErrNoRows {
return nil, false, nil
}
return nil, false, err
}
return check, true, nil
}
func (c *checkFactory) StartedChecks() ([]Check, error) {
rows, err := checksQuery.
Where(sq.Eq{"status": CheckStatusStarted}).
OrderBy("c.id").
RunWith(c.conn).
Query()
if err != nil {
return nil, err
}
var checks []Check
for rows.Next() {
check := &check{conn: c.conn, lockFactory: c.lockFactory}
err := scanCheck(check, rows)
if err != nil {
return nil, err
}
checks = append(checks, check)
}
return checks, nil
}
func (c *checkFactory) TryCreateCheck(checkable Checkable, resourceTypes ResourceTypes, fromVersion atc.Version, manuallyTriggered bool) (Check, bool, error) {
var err error
parentType, found := resourceTypes.Parent(checkable)
if found {
if parentType.Version() == nil {
return nil, false, errors.New("parent type has no version")
}
}
timeout := c.defaultCheckTimeout
if to := checkable.CheckTimeout(); to != "" {
timeout, err = time.ParseDuration(to)
if err != nil {
return nil, false, err
}
}
variables := creds.NewVariables(
c.secrets,
checkable.TeamName(),
checkable.PipelineName(),
)
source, err := creds.NewSource(variables, checkable.Source()).Evaluate()
if err != nil {
return nil, false, err
}
filteredTypes := resourceTypes.Filter(checkable).Deserialize()
versionedResourceTypes, err := creds.NewVersionedResourceTypes(variables, filteredTypes).Evaluate()
if err != nil {
return nil, false, err
}
// This could have changed based on new variable interpolation so update it
resourceConfigScope, err := checkable.SetResourceConfig(source, versionedResourceTypes)
if err != nil {
return nil, false, err
}
if fromVersion == nil {
rcv, found, err := resourceConfigScope.LatestVersion()
if err != nil {
return nil, false, err
}
if found {
fromVersion = atc.Version(rcv.Version())
}
}
plan := atc.Plan{
Check: &atc.CheckPlan{
Name: checkable.Name(),
Type: checkable.Type(),
Source: source,
Tags: checkable.Tags(),
Timeout: timeout.String(),
FromVersion: fromVersion,
VersionedResourceTypes: versionedResourceTypes,
},
}
check, created, err := c.CreateCheck(
resourceConfigScope.ID(),
resourceConfigScope.ResourceConfig().ID(),
resourceConfigScope.ResourceConfig().OriginBaseResourceType().ID,
checkable.TeamID(),
manuallyTriggered,
plan,
)
if err != nil {
return nil, false, err
}
return check, created, nil
}
func (c *checkFactory) CreateCheck(resourceConfigScopeID, resourceConfigID, baseResourceTypeID, teamID int, manuallyTriggered bool, plan atc.Plan) (Check, bool, error) {
tx, err := c.conn.Begin()
if err != nil {
return nil, false, err
}
defer Rollback(tx)
planPayload, err := json.Marshal(plan)
if err != nil {
return nil, false, err
}
es := c.conn.EncryptionStrategy()
encryptedPayload, nonce, err := es.Encrypt(planPayload)
if err != nil {
return nil, false, err
}
metadata, err := json.Marshal(map[string]interface{}{
"team_id": teamID,
"resource_config_id": resourceConfigID,
"base_resource_type_id": baseResourceTypeID,
})
if err != nil {
return nil, false, err
}
var id int
var createTime time.Time
err = psql.Insert("checks").
Columns(
"resource_config_scope_id",
"schema",
"status",
"manually_triggered",
"plan",
"nonce",
"metadata",
).
Values(
resourceConfigScopeID,
schema,
CheckStatusStarted,
manuallyTriggered,
encryptedPayload,
nonce,
metadata,
).
Suffix(`
ON CONFLICT DO NOTHING
RETURNING id, create_time
`).
RunWith(tx).
QueryRow().
Scan(&id, &createTime)
if err != nil {
if err == sql.ErrNoRows {
return nil, false, nil
}
return nil, false, err
}
err = tx.Commit()
if err != nil {
return nil, false, err
}
return &check{
id: id,
teamID: teamID,
resourceConfigScopeID: resourceConfigScopeID,
resourceConfigID: resourceConfigID,
baseResourceTypeID: baseResourceTypeID,
schema: schema,
status: CheckStatusStarted,
plan: plan,
createTime: createTime,
conn: c.conn,
lockFactory: c.lockFactory,
}, true, err
}
func (c *checkFactory) Resources() ([]Resource, error) {
var resources []Resource
rows, err := resourcesQuery.
Where(sq.Eq{"p.paused": false}).
RunWith(c.conn).
Query()
if err != nil {
return nil, err
}
defer Close(rows)
for rows.Next() {
r := &resource{
conn: c.conn,
lockFactory: c.lockFactory,
}
err = scanResource(r, rows)
if err != nil {
return nil, err
}
resources = append(resources, r)
}
return resources, nil
}
func (c *checkFactory) ResourceTypes() ([]ResourceType, error) {
var resourceTypes []ResourceType
rows, err := resourceTypesQuery.
RunWith(c.conn).
Query()
if err != nil {
return nil, err
}
defer Close(rows)
for rows.Next() {
r := &resourceType{
conn: c.conn,
lockFactory: c.lockFactory,
}
err = scanResourceType(r, rows)
if err != nil {
return nil, err
}
resourceTypes = append(resourceTypes, r)
}
return resourceTypes, nil
}

View File

@ -0,0 +1,481 @@
package db_test
import (
"errors"
"time"
"github.com/concourse/concourse/atc"
"github.com/concourse/concourse/atc/db"
"github.com/concourse/concourse/atc/db/dbfakes"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
var _ = Describe("CheckFactory", func() {
var (
err error
resourceConfigScope db.ResourceConfigScope
)
BeforeEach(func() {
setupTx, err := dbConn.Begin()
Expect(err).ToNot(HaveOccurred())
brt := db.BaseResourceType{
Name: "some-base-resource-type",
}
_, err = brt.FindOrCreate(setupTx, false)
Expect(err).NotTo(HaveOccurred())
Expect(setupTx.Commit()).To(Succeed())
resourceConfigScope, err = defaultResource.SetResourceConfig(atc.Source{"some": "repository"}, atc.VersionedResourceTypes{})
Expect(err).NotTo(HaveOccurred())
})
Describe("Check", func() {
var created, found bool
var check, foundCheck db.Check
BeforeEach(func() {
check, created, err = checkFactory.CreateCheck(
resourceConfigScope.ID(),
resourceConfigScope.ResourceConfig().ID(),
resourceConfigScope.ResourceConfig().OriginBaseResourceType().ID,
defaultTeam.ID(),
false,
atc.Plan{Check: &atc.CheckPlan{Name: "some-name", Type: "some-type"}},
)
Expect(created).To(BeTrue())
Expect(err).NotTo(HaveOccurred())
})
JustBeforeEach(func() {
foundCheck, found, err = checkFactory.Check(check.ID())
})
It("succeeds", func() {
Expect(found).To(BeTrue())
Expect(err).NotTo(HaveOccurred())
})
It("returns the db check", func() {
Expect(foundCheck).To(Equal(check))
})
})
Describe("TryCreateCheck", func() {
var (
created bool
check db.Check
fakeResource *dbfakes.FakeResource
fakeResourceType *dbfakes.FakeResourceType
fakeResourceTypes []db.ResourceType
fromVersion atc.Version
manuallyTriggered bool
)
BeforeEach(func() {
fromVersion = atc.Version{"from": "version"}
fakeResource = new(dbfakes.FakeResource)
fakeResource.NameReturns("some-name")
fakeResource.TagsReturns([]string{"tag-a", "tag-b"})
fakeResource.SourceReturns(atc.Source{"some": "source"})
fakeResourceType = new(dbfakes.FakeResourceType)
fakeResourceType.NameReturns("some-type")
fakeResourceType.TypeReturns("some-base-type")
fakeResourceType.TagsReturns([]string{"some-tag"})
fakeResourceType.SourceReturns(atc.Source{"some": "type-source"})
fakeResourceTypes = []db.ResourceType{fakeResourceType}
manuallyTriggered = true
})
JustBeforeEach(func() {
check, created, err = checkFactory.TryCreateCheck(fakeResource, fakeResourceTypes, fromVersion, manuallyTriggered)
})
Context("when the resource parent type is not a custom type", func() {
BeforeEach(func() {
fakeResource.TypeReturns("base-type")
})
Context("when the configured timeout is not parseable", func() {
BeforeEach(func() {
fakeResource.CheckTimeoutReturns("not-a-duration")
})
It("errors", func() {
Expect(err).To(HaveOccurred())
})
})
Context("when the configured timeout is parseable", func() {
BeforeEach(func() {
fakeResource.CheckTimeoutReturns("10s")
})
Context("when evaluating the source fails", func() {
BeforeEach(func() {
fakeResource.SourceReturns(atc.Source{"some": "((secret))"})
fakeSecrets.GetReturns("", nil, false, nil)
})
It("errors", func() {
Expect(err).To(HaveOccurred())
})
})
Context("when evaluating the source succeeds", func() {
BeforeEach(func() {
fakeResource.SourceReturns(atc.Source{"some": "((secret))"})
fakeSecrets.GetReturns("source", nil, true, nil)
})
Context("when evaluating the resource types source fails", func() {
BeforeEach(func() {
fakeResourceType.SourceReturns(atc.Source{"some": "((other-secret))"})
fakeSecrets.GetReturns("", nil, false, nil)
})
It("errors", func() {
Expect(err).To(HaveOccurred())
})
})
Context("when evaluating the resource types source succeeds", func() {
BeforeEach(func() {
fakeResourceType.SourceReturns(atc.Source{"some": "((other-secret))"})
fakeSecrets.GetReturns("source", nil, true, nil)
})
Context("when updating the resource config scope fails", func() {
BeforeEach(func() {
fakeResource.SetResourceConfigReturns(nil, errors.New("nope"))
})
It("errors", func() {
Expect(err).To(HaveOccurred())
})
})
Context("when updating the resource config scope succeeds", func() {
BeforeEach(func() {
fakeResource.SetResourceConfigReturns(resourceConfigScope, nil)
})
Context("when fromVersion is not nil", func() {
BeforeEach(func() {
fromVersion = atc.Version{"version": "a"}
})
It("creates a check", func() {
Expect(err).NotTo(HaveOccurred())
Expect(created).To(BeTrue())
Expect(check).NotTo(BeNil())
})
It("creates a plan with a version", func() {
Expect(check.Plan().Check.FromVersion).To(Equal(atc.Version{"version": "a"}))
Expect(check.Plan().Check.Name).To(Equal("some-name"))
Expect(check.Plan().Check.Type).To(Equal("base-type"))
Expect(check.Plan().Check.Source).To(Equal(atc.Source{"some": "source"}))
Expect(check.Plan().Check.Tags).To(ConsistOf("tag-a", "tag-b"))
Expect(check.Plan().Check.Timeout).To(Equal("10s"))
})
})
Context("when fromVersion is nil", func() {
BeforeEach(func() {
fromVersion = nil
})
Context("when fetching the latest version returns not found", func() {
BeforeEach(func() {
_, err = dbConn.Exec("DELETE FROM resource_config_versions")
Expect(err).NotTo(HaveOccurred())
})
It("creates a check", func() {
Expect(err).NotTo(HaveOccurred())
Expect(created).To(BeTrue())
Expect(check).NotTo(BeNil())
})
It("creates a plan with a nil version", func() {
Expect(check.Plan().Check.FromVersion).To(BeNil())
Expect(check.Plan().Check.Name).To(Equal("some-name"))
Expect(check.Plan().Check.Type).To(Equal("base-type"))
Expect(check.Plan().Check.Source).To(Equal(atc.Source{"some": "source"}))
Expect(check.Plan().Check.Tags).To(ConsistOf("tag-a", "tag-b"))
Expect(check.Plan().Check.Timeout).To(Equal("10s"))
})
})
Context("when fetching the latest version returns a version", func() {
BeforeEach(func() {
err = resourceConfigScope.SaveVersions([]atc.Version{{"some": "version"}})
Expect(err).NotTo(HaveOccurred())
})
It("creates a check", func() {
Expect(err).NotTo(HaveOccurred())
Expect(created).To(BeTrue())
Expect(check).NotTo(BeNil())
})
It("creates a plan with a version", func() {
Expect(check.Plan().Check.FromVersion).To(Equal(atc.Version{"some": "version"}))
Expect(check.Plan().Check.Name).To(Equal("some-name"))
Expect(check.Plan().Check.Type).To(Equal("base-type"))
Expect(check.Plan().Check.Source).To(Equal(atc.Source{"some": "source"}))
Expect(check.Plan().Check.Tags).To(ConsistOf("tag-a", "tag-b"))
Expect(check.Plan().Check.Timeout).To(Equal("10s"))
})
})
})
})
})
})
})
})
Context("when the resource has a parent type", func() {
BeforeEach(func() {
fakeResource.TypeReturns("custom-type")
fakeResource.PipelineIDReturns(1)
fakeResourceType.NameReturns("custom-type")
fakeResourceType.PipelineIDReturns(1)
})
Context("when the resource and type are properly configured", func() {
BeforeEach(func() {
fakeResourceType.LastCheckEndTimeReturns(time.Now().Add(-time.Hour))
fakeResource.LastCheckEndTimeReturns(time.Now().Add(-time.Hour))
fakeResource.SetResourceConfigReturns(resourceConfigScope, nil)
})
Context("when the parent type has no version", func() {
BeforeEach(func() {
fakeResourceType.VersionReturns(nil)
})
It("errors", func() {
Expect(err).To(HaveOccurred())
})
})
Context("when the parent type has a version", func() {
BeforeEach(func() {
fakeResourceType.VersionReturns(atc.Version{"some": "version"})
})
It("creates a check", func() {
Expect(err).NotTo(HaveOccurred())
Expect(created).To(BeTrue())
Expect(check).NotTo(BeNil())
})
It("creates a plan for the resource", func() {
Expect(check.Plan().Check.FromVersion).To(Equal(atc.Version{"from": "version"}))
Expect(check.Plan().Check.Name).To(Equal("some-name"))
Expect(check.Plan().Check.Type).To(Equal("custom-type"))
Expect(check.Plan().Check.Source).To(Equal(atc.Source{"some": "source"}))
Expect(check.Plan().Check.Tags).To(ConsistOf("tag-a", "tag-b"))
Expect(check.Plan().Check.Timeout).To(Equal("1m0s"))
})
})
})
})
})
Describe("CreateCheck", func() {
var created bool
var check db.Check
JustBeforeEach(func() {
check, created, err = checkFactory.CreateCheck(
resourceConfigScope.ID(),
resourceConfigScope.ResourceConfig().ID(),
resourceConfigScope.ResourceConfig().OriginBaseResourceType().ID,
defaultTeam.ID(),
false,
atc.Plan{Check: &atc.CheckPlan{Name: "some-name", Type: "some-type"}},
)
})
It("succeeds", func() {
Expect(created).To(BeTrue())
Expect(err).NotTo(HaveOccurred())
})
It("returns the resource check", func() {
Expect(check.ID()).To(Equal(1))
Expect(check.TeamID()).To(Equal(defaultTeam.ID()))
Expect(check.Status()).To(Equal(db.CheckStatusStarted))
Expect(check.Schema()).To(Equal("exec.v2"))
Expect(check.Plan().Check.Name).To(Equal("some-name"))
Expect(check.Plan().Check.Type).To(Equal("some-type"))
Expect(check.CreateTime()).To(BeTemporally("~", time.Now(), time.Second))
Expect(check.ResourceConfigScopeID()).To(Equal(resourceConfigScope.ID()))
Expect(check.ResourceConfigID()).To(Equal(resourceConfigScope.ResourceConfig().ID()))
Expect(check.BaseResourceTypeID()).To(Equal(resourceConfigScope.ResourceConfig().OriginBaseResourceType().ID))
})
Context("when a check is already pending", func() {
BeforeEach(func() {
_, created, err := checkFactory.CreateCheck(
resourceConfigScope.ID(),
resourceConfigScope.ResourceConfig().ID(),
resourceConfigScope.ResourceConfig().OriginBaseResourceType().ID,
defaultTeam.ID(),
false,
atc.Plan{},
)
Expect(created).To(BeTrue())
Expect(err).NotTo(HaveOccurred())
})
It("doesn't create a check", func() {
Expect(created).To(BeFalse())
Expect(err).NotTo(HaveOccurred())
})
})
})
Describe("StartedChecks", func() {
var (
checks []db.Check
)
JustBeforeEach(func() {
checks, err = checkFactory.StartedChecks()
Expect(err).NotTo(HaveOccurred())
})
Context("when looking up the resource check returns no results", func() {
BeforeEach(func() {
_, err = dbConn.Exec(`DELETE FROM checks`)
Expect(err).NotTo(HaveOccurred())
})
It("is not found", func() {
Expect(checks).To(HaveLen(0))
})
})
Context("when a check has no metadata", func() {
BeforeEach(func() {
_, err = dbConn.Exec(`INSERT INTO checks(resource_config_scope_id, status, schema) VALUES ($1, 'started', 'some-schema')`, resourceConfigScope.ID())
Expect(err).NotTo(HaveOccurred())
})
It("returns the check", func() {
Expect(checks).To(HaveLen(1))
Expect(checks[0].ID()).To(Equal(1))
Expect(checks[0].Status()).To(Equal(db.CheckStatusStarted))
Expect(checks[0].Schema()).To(Equal("some-schema"))
Expect(checks[0].TeamID()).To(Equal(0))
Expect(checks[0].ResourceConfigScopeID()).To(Equal(resourceConfigScope.ID()))
Expect(checks[0].ResourceConfigID()).To(Equal(0))
Expect(checks[0].BaseResourceTypeID()).To(Equal(0))
})
})
Context("when looking up the resource check succeeds", func() {
var check db.Check
BeforeEach(func() {
var created bool
check, created, err = checkFactory.CreateCheck(
resourceConfigScope.ID(),
resourceConfigScope.ResourceConfig().ID(),
resourceConfigScope.ResourceConfig().OriginBaseResourceType().ID,
defaultTeam.ID(),
false,
atc.Plan{},
)
Expect(created).To(BeTrue())
Expect(err).NotTo(HaveOccurred())
})
It("returns the resource checks", func() {
Expect(checks).To(HaveLen(1))
Expect(checks[0]).To(Equal(check))
})
})
})
Describe("Resources", func() {
var (
resources []db.Resource
)
JustBeforeEach(func() {
resources, err = checkFactory.Resources()
Expect(err).NotTo(HaveOccurred())
})
It("include resources in return", func() {
Expect(resources).To(HaveLen(1))
Expect(resources[0].Name()).To(Equal("some-resource"))
})
Context("when the resource is not active", func() {
BeforeEach(func() {
_, err = dbConn.Exec(`UPDATE resources SET active = false`)
Expect(err).NotTo(HaveOccurred())
})
It("does not return the resource", func() {
Expect(resources).To(HaveLen(0))
})
})
Context("when the resource pipeline is paused", func() {
BeforeEach(func() {
_, err = dbConn.Exec(`UPDATE pipelines SET paused = true`)
Expect(err).NotTo(HaveOccurred())
})
It("does not return the resource", func() {
Expect(resources).To(HaveLen(0))
})
})
})
Describe("ResourceTypes", func() {
var (
resourceTypes db.ResourceTypes
)
JustBeforeEach(func() {
resourceTypes, err = checkFactory.ResourceTypes()
Expect(err).NotTo(HaveOccurred())
})
It("include resource types in return", func() {
Expect(resourceTypes).To(HaveLen(1))
Expect(resourceTypes[0].Name()).To(Equal("some-type"))
})
Context("when the resource type is not active", func() {
BeforeEach(func() {
_, err = dbConn.Exec(`UPDATE resource_types SET active = false`)
Expect(err).NotTo(HaveOccurred())
})
It("does not return the resource type", func() {
Expect(resourceTypes).To(HaveLen(0))
})
})
})
})

41
atc/db/check_lifecycle.go Normal file
View File

@ -0,0 +1,41 @@
package db
import (
"fmt"
"time"
sq "github.com/Masterminds/squirrel"
)
//go:generate counterfeiter . CheckLifecycle
type CheckLifecycle interface {
RemoveExpiredChecks(time.Duration) error
}
type checkLifecycle struct {
conn Conn
}
func NewCheckLifecycle(conn Conn) *checkLifecycle {
return &checkLifecycle{
conn: conn,
}
}
func (lifecycle *checkLifecycle) RemoveExpiredChecks(recyclePeriod time.Duration) error {
_, err := psql.Delete("checks").
Where(
sq.And{
sq.Gt{
"Now() - create_time": fmt.Sprintf("%.0f seconds", recyclePeriod.Seconds()),
},
sq.NotEq{"status": CheckStatusStarted},
},
).
RunWith(lifecycle.conn).
Exec()
return err
}

View File

@ -0,0 +1,72 @@
package db_test
import (
"time"
"github.com/concourse/concourse/atc/db"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
var _ = Describe("CheckLifecycle", func() {
var checkLifecycle db.CheckLifecycle
BeforeEach(func() {
checkLifecycle = db.NewCheckLifecycle(dbConn)
})
Describe("RemoveExpiredChecks", func() {
JustBeforeEach(func() {
err := checkLifecycle.RemoveExpiredChecks(time.Hour * 24)
Expect(err).ToNot(HaveOccurred())
})
Context("removes checks created more than 24 hours ago", func() {
BeforeEach(func() {
_, err := dbConn.Exec("INSERT INTO checks(schema, status, create_time) VALUES('some-schema', 'succeeded', NOW() - '25 hours'::interval)")
Expect(err).ToNot(HaveOccurred())
})
It("removes the record", func() {
var count int
err := dbConn.QueryRow("SELECT count(*) from checks").Scan(&count)
Expect(err).ToNot(HaveOccurred())
Expect(count).To(Equal(0))
})
})
Context("doesn't remove check is not finished", func() {
BeforeEach(func() {
_, err := dbConn.Exec("INSERT INTO checks(schema, status, create_time) VALUES('some-schema', 'started', NOW() - '25 hours'::interval)")
Expect(err).ToNot(HaveOccurred())
})
It("does not remove the record", func() {
var count int
err := dbConn.QueryRow("SELECT count(*) from checks").Scan(&count)
Expect(err).ToNot(HaveOccurred())
Expect(count).To(Equal(1))
})
})
Context("keeps checks for 24 hours", func() {
BeforeEach(func() {
_, err := dbConn.Exec("INSERT INTO checks(schema, status, create_time) VALUES('some-schema', 'succeeded', NOW() - '25 hours'::interval)")
Expect(err).ToNot(HaveOccurred())
_, err = dbConn.Exec("INSERT INTO checks(schema, status, create_time) VALUES('some-schema', 'succeeded', NOW() - '23 hours'::interval)")
Expect(err).ToNot(HaveOccurred())
})
It("does not remove the record", func() {
var count int
err := dbConn.QueryRow("SELECT count(*) from checks").Scan(&count)
Expect(err).ToNot(HaveOccurred())
Expect(count).To(Equal(1))
})
})
})
})

197
atc/db/check_test.go Normal file
View File

@ -0,0 +1,197 @@
package db_test
import (
"errors"
"time"
"github.com/concourse/concourse/atc"
"github.com/concourse/concourse/atc/db"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
var _ = Describe("Check", func() {
var (
err error
created bool
check db.Check
resourceConfigScope db.ResourceConfigScope
resourceTypeConfigScope db.ResourceConfigScope
)
BeforeEach(func() {
setupTx, err := dbConn.Begin()
Expect(err).ToNot(HaveOccurred())
brt := db.BaseResourceType{
Name: "some-base-resource-type",
}
_, err = brt.FindOrCreate(setupTx, false)
Expect(err).NotTo(HaveOccurred())
Expect(setupTx.Commit()).To(Succeed())
resourceConfigScope, err = defaultResource.SetResourceConfig(atc.Source{"some": "repository"}, atc.VersionedResourceTypes{})
Expect(err).NotTo(HaveOccurred())
resourceTypeConfigScope, err = defaultResourceType.SetResourceConfig(atc.Source{"some": "type-repository"}, atc.VersionedResourceTypes{})
Expect(err).NotTo(HaveOccurred())
check, created, err = checkFactory.CreateCheck(
resourceConfigScope.ID(),
resourceConfigScope.ResourceConfig().ID(),
resourceConfigScope.ResourceConfig().OriginBaseResourceType().ID,
defaultTeam.ID(),
false,
atc.Plan{},
)
Expect(created).To(BeTrue())
Expect(err).NotTo(HaveOccurred())
})
Describe("Start", func() {
JustBeforeEach(func() {
err = check.Start()
})
It("succeeds", func() {
Expect(err).NotTo(HaveOccurred())
})
It("starts the check", func() {
check.Reload()
Expect(check.StartTime()).To(BeTemporally("~", time.Now(), time.Second))
})
It("updates resource last check start time", func() {
defaultResource.Reload()
Expect(defaultResource.LastCheckStartTime()).To(BeTemporally("~", time.Now(), time.Second))
})
})
Describe("Finish", func() {
JustBeforeEach(func() {
err = check.Finish()
})
It("succeeds", func() {
Expect(err).NotTo(HaveOccurred())
})
It("finishes the check", func() {
check.Reload()
Expect(check.Status()).To(Equal(db.CheckStatusSucceeded))
Expect(check.EndTime()).To(BeTemporally("~", time.Now(), time.Second))
Expect(check.CheckError()).To(BeNil())
})
It("updates resource last check end time", func() {
defaultResource.Reload()
Expect(defaultResource.LastCheckEndTime()).To(BeTemporally("~", time.Now(), time.Second))
})
It("clears out the check error", func() {
defaultResource.Reload()
Expect(defaultResource.CheckError()).To(BeNil())
})
})
Describe("FinishWithError", func() {
JustBeforeEach(func() {
err = check.FinishWithError(errors.New("nope"))
})
It("succeeds", func() {
Expect(err).NotTo(HaveOccurred())
})
It("finishes the check", func() {
check.Reload()
Expect(check.Status()).To(Equal(db.CheckStatusErrored))
Expect(check.EndTime()).To(BeTemporally("~", time.Now(), time.Second))
Expect(check.CheckError()).To(Equal(errors.New("nope")))
})
It("updates resource last check end time", func() {
defaultResource.Reload()
Expect(defaultResource.LastCheckEndTime()).To(BeTemporally("~", time.Now(), time.Second))
Expect(defaultResource.CheckError()).To(Equal(errors.New("nope")))
})
})
Describe("AllCheckables", func() {
var checkables []db.Checkable
Context("with resources", func() {
JustBeforeEach(func() {
checkables, err = check.AllCheckables()
})
It("succeeds", func() {
Expect(err).NotTo(HaveOccurred())
})
It("includes any resources that point to the scope", func() {
defaultResource.Reload()
Expect(checkables).To(HaveLen(1))
Expect(checkables[0]).To(Equal(defaultResource))
})
})
Context("with resource types", func() {
BeforeEach(func() {
check, created, err = checkFactory.CreateCheck(
resourceTypeConfigScope.ID(),
resourceTypeConfigScope.ResourceConfig().ID(),
resourceTypeConfigScope.ResourceConfig().OriginBaseResourceType().ID,
defaultTeam.ID(),
false,
atc.Plan{},
)
Expect(created).To(BeTrue())
Expect(err).NotTo(HaveOccurred())
})
JustBeforeEach(func() {
checkables, err = check.AllCheckables()
})
It("succeeds", func() {
Expect(err).NotTo(HaveOccurred())
})
It("includes any resource type that point to the scope", func() {
defaultResourceType.Reload()
Expect(checkables).To(HaveLen(1))
Expect(checkables[0]).To(Equal(defaultResourceType))
})
})
})
Describe("SaveVersions", func() {
JustBeforeEach(func() {
err = check.SaveVersions([]atc.Version{{"some": "version"}})
})
It("succeeds", func() {
Expect(err).NotTo(HaveOccurred())
})
It("saves the versions on the resource config scope", func() {
version, found, err := resourceConfigScope.LatestVersion()
Expect(err).NotTo(HaveOccurred())
Expect(found).To(BeTrue())
Expect(version.Version()).To(Equal(db.Version{"some": "version"}))
})
})
})

View File

@ -125,18 +125,21 @@ func (c buildStepContainerOwner) sqlMap() map[string]interface{} {
// worker base resource type disappear, or the expiry is reached, the container
// can be removed.
func NewResourceConfigCheckSessionContainerOwner(
resourceConfig ResourceConfig,
resourceConfigID int,
baseResourceTypeID int,
expiries ContainerOwnerExpiries,
) ContainerOwner {
return resourceConfigCheckSessionContainerOwner{
resourceConfig: resourceConfig,
expiries: expiries,
resourceConfigID: resourceConfigID,
baseResourceTypeID: baseResourceTypeID,
expiries: expiries,
}
}
type resourceConfigCheckSessionContainerOwner struct {
resourceConfig ResourceConfig
expiries ContainerOwnerExpiries
resourceConfigID int
baseResourceTypeID int
expiries ContainerOwnerExpiries
}
type ContainerOwnerExpiries struct {
@ -149,7 +152,7 @@ func (c resourceConfigCheckSessionContainerOwner) Find(conn Conn) (sq.Eq, bool,
rows, err := psql.Select("id").
From("resource_config_check_sessions").
Where(sq.And{
sq.Eq{"resource_config_id": c.resourceConfig.ID()},
sq.Eq{"resource_config_id": c.resourceConfigID},
sq.Expr("expires_at > NOW()"),
}).
RunWith(conn).
@ -183,7 +186,7 @@ func (c resourceConfigCheckSessionContainerOwner) Create(tx Tx, workerName strin
From("worker_base_resource_types").
Where(sq.Eq{
"worker_name": workerName,
"base_resource_type_id": c.resourceConfig.OriginBaseResourceType().ID,
"base_resource_type_id": c.baseResourceTypeID,
}).
Suffix("FOR SHARE").
RunWith(tx).
@ -202,7 +205,7 @@ func (c resourceConfigCheckSessionContainerOwner) Create(tx Tx, workerName strin
var rccsID int
err = psql.Insert("resource_config_check_sessions").
SetMap(map[string]interface{}{
"resource_config_id": c.resourceConfig.ID(),
"resource_config_id": c.resourceConfigID,
"worker_base_resource_type_id": wbrtID,
"expires_at": sq.Expr("(SELECT " + expiryStmt + " FROM workers)"),
}).
@ -211,7 +214,7 @@ func (c resourceConfigCheckSessionContainerOwner) Create(tx Tx, workerName strin
resource_config_id = ?,
worker_base_resource_type_id = ?
RETURNING id
`, c.resourceConfig.ID(), wbrtID).
`, c.resourceConfigID, wbrtID).
RunWith(tx).
QueryRow().
Scan(&rccsID)

View File

@ -52,7 +52,8 @@ var _ = Describe("ContainerOwner", func() {
JustBeforeEach(func() {
owner = db.NewResourceConfigCheckSessionContainerOwner(
resourceConfig,
resourceConfig.ID(),
resourceConfig.OriginBaseResourceType().ID,
ownerExpiries,
)
})
@ -71,7 +72,8 @@ var _ = Describe("ContainerOwner", func() {
BeforeEach(func() {
existingOwner := db.NewResourceConfigCheckSessionContainerOwner(
resourceConfig,
resourceConfig.ID(),
resourceConfig.OriginBaseResourceType().ID,
ownerExpiries,
)
@ -97,7 +99,8 @@ var _ = Describe("ContainerOwner", func() {
BeforeEach(func() {
existingOwner := db.NewResourceConfigCheckSessionContainerOwner(
resourceConfig,
resourceConfig.ID(),
resourceConfig.OriginBaseResourceType().ID,
ownerExpiries,
)

View File

@ -34,7 +34,14 @@ var _ = Describe("ContainerRepository", func() {
)
Expect(err).NotTo(HaveOccurred())
creatingContainer, err = defaultWorker.CreateContainer(db.NewResourceConfigCheckSessionContainerOwner(resourceConfig, expiries), fullMetadata)
creatingContainer, err = defaultWorker.CreateContainer(
db.NewResourceConfigCheckSessionContainerOwner(
resourceConfig.ID(),
resourceConfig.OriginBaseResourceType().ID,
expiries,
),
fullMetadata,
)
Expect(err).NotTo(HaveOccurred())
})

View File

@ -12,6 +12,7 @@ import (
. "github.com/onsi/gomega"
"github.com/concourse/concourse/atc"
"github.com/concourse/concourse/atc/creds/credsfakes"
"github.com/concourse/concourse/atc/db"
"github.com/concourse/concourse/atc/db/lock"
"github.com/concourse/concourse/atc/metric"
@ -29,6 +30,7 @@ var (
dbProcess ifrit.Process
dbConn db.Conn
fakeSecrets *credsfakes.FakeSecrets
buildFactory db.BuildFactory
volumeRepository db.VolumeRepository
containerRepository db.ContainerRepository
@ -39,6 +41,7 @@ var (
resourceConfigFactory db.ResourceConfigFactory
resourceCacheFactory db.ResourceCacheFactory
taskCacheFactory db.TaskCacheFactory
checkFactory db.CheckFactory
workerBaseResourceTypeFactory db.WorkerBaseResourceTypeFactory
workerTaskCacheFactory db.WorkerTaskCacheFactory
userFactory db.UserFactory
@ -94,6 +97,7 @@ var _ = BeforeEach(func() {
lockFactory = lock.NewLockFactory(postgresRunner.OpenSingleton(), metric.LogLockAcquired, metric.LogLockReleased)
fakeSecrets = new(credsfakes.FakeSecrets)
buildFactory = db.NewBuildFactory(dbConn, lockFactory, 5*time.Minute)
volumeRepository = db.NewVolumeRepository(dbConn)
containerRepository = db.NewContainerRepository(dbConn)
@ -104,6 +108,7 @@ var _ = BeforeEach(func() {
resourceConfigFactory = db.NewResourceConfigFactory(dbConn, lockFactory)
resourceCacheFactory = db.NewResourceCacheFactory(dbConn, lockFactory)
taskCacheFactory = db.NewTaskCacheFactory(dbConn)
checkFactory = db.NewCheckFactory(dbConn, lockFactory, fakeSecrets, time.Minute)
workerBaseResourceTypeFactory = db.NewWorkerBaseResourceTypeFactory(dbConn)
workerTaskCacheFactory = db.NewWorkerTaskCacheFactory(dbConn)
userFactory = db.NewUserFactory(dbConn)

1309
atc/db/dbfakes/fake_check.go Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,659 @@
// Code generated by counterfeiter. DO NOT EDIT.
package dbfakes
import (
"sync"
"code.cloudfoundry.org/lager"
"github.com/concourse/concourse/atc"
"github.com/concourse/concourse/atc/db"
"github.com/concourse/concourse/atc/db/lock"
)
type FakeCheckFactory struct {
AcquireScanningLockStub func(lager.Logger) (lock.Lock, bool, error)
acquireScanningLockMutex sync.RWMutex
acquireScanningLockArgsForCall []struct {
arg1 lager.Logger
}
acquireScanningLockReturns struct {
result1 lock.Lock
result2 bool
result3 error
}
acquireScanningLockReturnsOnCall map[int]struct {
result1 lock.Lock
result2 bool
result3 error
}
CheckStub func(int) (db.Check, bool, error)
checkMutex sync.RWMutex
checkArgsForCall []struct {
arg1 int
}
checkReturns struct {
result1 db.Check
result2 bool
result3 error
}
checkReturnsOnCall map[int]struct {
result1 db.Check
result2 bool
result3 error
}
CreateCheckStub func(int, int, int, int, bool, atc.Plan) (db.Check, bool, error)
createCheckMutex sync.RWMutex
createCheckArgsForCall []struct {
arg1 int
arg2 int
arg3 int
arg4 int
arg5 bool
arg6 atc.Plan
}
createCheckReturns struct {
result1 db.Check
result2 bool
result3 error
}
createCheckReturnsOnCall map[int]struct {
result1 db.Check
result2 bool
result3 error
}
NotifyCheckerStub func() error
notifyCheckerMutex sync.RWMutex
notifyCheckerArgsForCall []struct {
}
notifyCheckerReturns struct {
result1 error
}
notifyCheckerReturnsOnCall map[int]struct {
result1 error
}
ResourceTypesStub func() ([]db.ResourceType, error)
resourceTypesMutex sync.RWMutex
resourceTypesArgsForCall []struct {
}
resourceTypesReturns struct {
result1 []db.ResourceType
result2 error
}
resourceTypesReturnsOnCall map[int]struct {
result1 []db.ResourceType
result2 error
}
ResourcesStub func() ([]db.Resource, error)
resourcesMutex sync.RWMutex
resourcesArgsForCall []struct {
}
resourcesReturns struct {
result1 []db.Resource
result2 error
}
resourcesReturnsOnCall map[int]struct {
result1 []db.Resource
result2 error
}
StartedChecksStub func() ([]db.Check, error)
startedChecksMutex sync.RWMutex
startedChecksArgsForCall []struct {
}
startedChecksReturns struct {
result1 []db.Check
result2 error
}
startedChecksReturnsOnCall map[int]struct {
result1 []db.Check
result2 error
}
TryCreateCheckStub func(db.Checkable, db.ResourceTypes, atc.Version, bool) (db.Check, bool, error)
tryCreateCheckMutex sync.RWMutex
tryCreateCheckArgsForCall []struct {
arg1 db.Checkable
arg2 db.ResourceTypes
arg3 atc.Version
arg4 bool
}
tryCreateCheckReturns struct {
result1 db.Check
result2 bool
result3 error
}
tryCreateCheckReturnsOnCall map[int]struct {
result1 db.Check
result2 bool
result3 error
}
invocations map[string][][]interface{}
invocationsMutex sync.RWMutex
}
func (fake *FakeCheckFactory) AcquireScanningLock(arg1 lager.Logger) (lock.Lock, bool, error) {
fake.acquireScanningLockMutex.Lock()
ret, specificReturn := fake.acquireScanningLockReturnsOnCall[len(fake.acquireScanningLockArgsForCall)]
fake.acquireScanningLockArgsForCall = append(fake.acquireScanningLockArgsForCall, struct {
arg1 lager.Logger
}{arg1})
fake.recordInvocation("AcquireScanningLock", []interface{}{arg1})
fake.acquireScanningLockMutex.Unlock()
if fake.AcquireScanningLockStub != nil {
return fake.AcquireScanningLockStub(arg1)
}
if specificReturn {
return ret.result1, ret.result2, ret.result3
}
fakeReturns := fake.acquireScanningLockReturns
return fakeReturns.result1, fakeReturns.result2, fakeReturns.result3
}
func (fake *FakeCheckFactory) AcquireScanningLockCallCount() int {
fake.acquireScanningLockMutex.RLock()
defer fake.acquireScanningLockMutex.RUnlock()
return len(fake.acquireScanningLockArgsForCall)
}
func (fake *FakeCheckFactory) AcquireScanningLockCalls(stub func(lager.Logger) (lock.Lock, bool, error)) {
fake.acquireScanningLockMutex.Lock()
defer fake.acquireScanningLockMutex.Unlock()
fake.AcquireScanningLockStub = stub
}
func (fake *FakeCheckFactory) AcquireScanningLockArgsForCall(i int) lager.Logger {
fake.acquireScanningLockMutex.RLock()
defer fake.acquireScanningLockMutex.RUnlock()
argsForCall := fake.acquireScanningLockArgsForCall[i]
return argsForCall.arg1
}
func (fake *FakeCheckFactory) AcquireScanningLockReturns(result1 lock.Lock, result2 bool, result3 error) {
fake.acquireScanningLockMutex.Lock()
defer fake.acquireScanningLockMutex.Unlock()
fake.AcquireScanningLockStub = nil
fake.acquireScanningLockReturns = struct {
result1 lock.Lock
result2 bool
result3 error
}{result1, result2, result3}
}
func (fake *FakeCheckFactory) AcquireScanningLockReturnsOnCall(i int, result1 lock.Lock, result2 bool, result3 error) {
fake.acquireScanningLockMutex.Lock()
defer fake.acquireScanningLockMutex.Unlock()
fake.AcquireScanningLockStub = nil
if fake.acquireScanningLockReturnsOnCall == nil {
fake.acquireScanningLockReturnsOnCall = make(map[int]struct {
result1 lock.Lock
result2 bool
result3 error
})
}
fake.acquireScanningLockReturnsOnCall[i] = struct {
result1 lock.Lock
result2 bool
result3 error
}{result1, result2, result3}
}
func (fake *FakeCheckFactory) Check(arg1 int) (db.Check, bool, error) {
fake.checkMutex.Lock()
ret, specificReturn := fake.checkReturnsOnCall[len(fake.checkArgsForCall)]
fake.checkArgsForCall = append(fake.checkArgsForCall, struct {
arg1 int
}{arg1})
fake.recordInvocation("Check", []interface{}{arg1})
fake.checkMutex.Unlock()
if fake.CheckStub != nil {
return fake.CheckStub(arg1)
}
if specificReturn {
return ret.result1, ret.result2, ret.result3
}
fakeReturns := fake.checkReturns
return fakeReturns.result1, fakeReturns.result2, fakeReturns.result3
}
func (fake *FakeCheckFactory) CheckCallCount() int {
fake.checkMutex.RLock()
defer fake.checkMutex.RUnlock()
return len(fake.checkArgsForCall)
}
func (fake *FakeCheckFactory) CheckCalls(stub func(int) (db.Check, bool, error)) {
fake.checkMutex.Lock()
defer fake.checkMutex.Unlock()
fake.CheckStub = stub
}
func (fake *FakeCheckFactory) CheckArgsForCall(i int) int {
fake.checkMutex.RLock()
defer fake.checkMutex.RUnlock()
argsForCall := fake.checkArgsForCall[i]
return argsForCall.arg1
}
func (fake *FakeCheckFactory) CheckReturns(result1 db.Check, result2 bool, result3 error) {
fake.checkMutex.Lock()
defer fake.checkMutex.Unlock()
fake.CheckStub = nil
fake.checkReturns = struct {
result1 db.Check
result2 bool
result3 error
}{result1, result2, result3}
}
func (fake *FakeCheckFactory) CheckReturnsOnCall(i int, result1 db.Check, result2 bool, result3 error) {
fake.checkMutex.Lock()
defer fake.checkMutex.Unlock()
fake.CheckStub = nil
if fake.checkReturnsOnCall == nil {
fake.checkReturnsOnCall = make(map[int]struct {
result1 db.Check
result2 bool
result3 error
})
}
fake.checkReturnsOnCall[i] = struct {
result1 db.Check
result2 bool
result3 error
}{result1, result2, result3}
}
func (fake *FakeCheckFactory) CreateCheck(arg1 int, arg2 int, arg3 int, arg4 int, arg5 bool, arg6 atc.Plan) (db.Check, bool, error) {
fake.createCheckMutex.Lock()
ret, specificReturn := fake.createCheckReturnsOnCall[len(fake.createCheckArgsForCall)]
fake.createCheckArgsForCall = append(fake.createCheckArgsForCall, struct {
arg1 int
arg2 int
arg3 int
arg4 int
arg5 bool
arg6 atc.Plan
}{arg1, arg2, arg3, arg4, arg5, arg6})
fake.recordInvocation("CreateCheck", []interface{}{arg1, arg2, arg3, arg4, arg5, arg6})
fake.createCheckMutex.Unlock()
if fake.CreateCheckStub != nil {
return fake.CreateCheckStub(arg1, arg2, arg3, arg4, arg5, arg6)
}
if specificReturn {
return ret.result1, ret.result2, ret.result3
}
fakeReturns := fake.createCheckReturns
return fakeReturns.result1, fakeReturns.result2, fakeReturns.result3
}
func (fake *FakeCheckFactory) CreateCheckCallCount() int {
fake.createCheckMutex.RLock()
defer fake.createCheckMutex.RUnlock()
return len(fake.createCheckArgsForCall)
}
func (fake *FakeCheckFactory) CreateCheckCalls(stub func(int, int, int, int, bool, atc.Plan) (db.Check, bool, error)) {
fake.createCheckMutex.Lock()
defer fake.createCheckMutex.Unlock()
fake.CreateCheckStub = stub
}
func (fake *FakeCheckFactory) CreateCheckArgsForCall(i int) (int, int, int, int, bool, atc.Plan) {
fake.createCheckMutex.RLock()
defer fake.createCheckMutex.RUnlock()
argsForCall := fake.createCheckArgsForCall[i]
return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3, argsForCall.arg4, argsForCall.arg5, argsForCall.arg6
}
func (fake *FakeCheckFactory) CreateCheckReturns(result1 db.Check, result2 bool, result3 error) {
fake.createCheckMutex.Lock()
defer fake.createCheckMutex.Unlock()
fake.CreateCheckStub = nil
fake.createCheckReturns = struct {
result1 db.Check
result2 bool
result3 error
}{result1, result2, result3}
}
func (fake *FakeCheckFactory) CreateCheckReturnsOnCall(i int, result1 db.Check, result2 bool, result3 error) {
fake.createCheckMutex.Lock()
defer fake.createCheckMutex.Unlock()
fake.CreateCheckStub = nil
if fake.createCheckReturnsOnCall == nil {
fake.createCheckReturnsOnCall = make(map[int]struct {
result1 db.Check
result2 bool
result3 error
})
}
fake.createCheckReturnsOnCall[i] = struct {
result1 db.Check
result2 bool
result3 error
}{result1, result2, result3}
}
func (fake *FakeCheckFactory) NotifyChecker() error {
fake.notifyCheckerMutex.Lock()
ret, specificReturn := fake.notifyCheckerReturnsOnCall[len(fake.notifyCheckerArgsForCall)]
fake.notifyCheckerArgsForCall = append(fake.notifyCheckerArgsForCall, struct {
}{})
fake.recordInvocation("NotifyChecker", []interface{}{})
fake.notifyCheckerMutex.Unlock()
if fake.NotifyCheckerStub != nil {
return fake.NotifyCheckerStub()
}
if specificReturn {
return ret.result1
}
fakeReturns := fake.notifyCheckerReturns
return fakeReturns.result1
}
func (fake *FakeCheckFactory) NotifyCheckerCallCount() int {
fake.notifyCheckerMutex.RLock()
defer fake.notifyCheckerMutex.RUnlock()
return len(fake.notifyCheckerArgsForCall)
}
func (fake *FakeCheckFactory) NotifyCheckerCalls(stub func() error) {
fake.notifyCheckerMutex.Lock()
defer fake.notifyCheckerMutex.Unlock()
fake.NotifyCheckerStub = stub
}
func (fake *FakeCheckFactory) NotifyCheckerReturns(result1 error) {
fake.notifyCheckerMutex.Lock()
defer fake.notifyCheckerMutex.Unlock()
fake.NotifyCheckerStub = nil
fake.notifyCheckerReturns = struct {
result1 error
}{result1}
}
func (fake *FakeCheckFactory) NotifyCheckerReturnsOnCall(i int, result1 error) {
fake.notifyCheckerMutex.Lock()
defer fake.notifyCheckerMutex.Unlock()
fake.NotifyCheckerStub = nil
if fake.notifyCheckerReturnsOnCall == nil {
fake.notifyCheckerReturnsOnCall = make(map[int]struct {
result1 error
})
}
fake.notifyCheckerReturnsOnCall[i] = struct {
result1 error
}{result1}
}
func (fake *FakeCheckFactory) ResourceTypes() ([]db.ResourceType, error) {
fake.resourceTypesMutex.Lock()
ret, specificReturn := fake.resourceTypesReturnsOnCall[len(fake.resourceTypesArgsForCall)]
fake.resourceTypesArgsForCall = append(fake.resourceTypesArgsForCall, struct {
}{})
fake.recordInvocation("ResourceTypes", []interface{}{})
fake.resourceTypesMutex.Unlock()
if fake.ResourceTypesStub != nil {
return fake.ResourceTypesStub()
}
if specificReturn {
return ret.result1, ret.result2
}
fakeReturns := fake.resourceTypesReturns
return fakeReturns.result1, fakeReturns.result2
}
func (fake *FakeCheckFactory) ResourceTypesCallCount() int {
fake.resourceTypesMutex.RLock()
defer fake.resourceTypesMutex.RUnlock()
return len(fake.resourceTypesArgsForCall)
}
func (fake *FakeCheckFactory) ResourceTypesCalls(stub func() ([]db.ResourceType, error)) {
fake.resourceTypesMutex.Lock()
defer fake.resourceTypesMutex.Unlock()
fake.ResourceTypesStub = stub
}
func (fake *FakeCheckFactory) ResourceTypesReturns(result1 []db.ResourceType, result2 error) {
fake.resourceTypesMutex.Lock()
defer fake.resourceTypesMutex.Unlock()
fake.ResourceTypesStub = nil
fake.resourceTypesReturns = struct {
result1 []db.ResourceType
result2 error
}{result1, result2}
}
func (fake *FakeCheckFactory) ResourceTypesReturnsOnCall(i int, result1 []db.ResourceType, result2 error) {
fake.resourceTypesMutex.Lock()
defer fake.resourceTypesMutex.Unlock()
fake.ResourceTypesStub = nil
if fake.resourceTypesReturnsOnCall == nil {
fake.resourceTypesReturnsOnCall = make(map[int]struct {
result1 []db.ResourceType
result2 error
})
}
fake.resourceTypesReturnsOnCall[i] = struct {
result1 []db.ResourceType
result2 error
}{result1, result2}
}
func (fake *FakeCheckFactory) Resources() ([]db.Resource, error) {
fake.resourcesMutex.Lock()
ret, specificReturn := fake.resourcesReturnsOnCall[len(fake.resourcesArgsForCall)]
fake.resourcesArgsForCall = append(fake.resourcesArgsForCall, struct {
}{})
fake.recordInvocation("Resources", []interface{}{})
fake.resourcesMutex.Unlock()
if fake.ResourcesStub != nil {
return fake.ResourcesStub()
}
if specificReturn {
return ret.result1, ret.result2
}
fakeReturns := fake.resourcesReturns
return fakeReturns.result1, fakeReturns.result2
}
func (fake *FakeCheckFactory) ResourcesCallCount() int {
fake.resourcesMutex.RLock()
defer fake.resourcesMutex.RUnlock()
return len(fake.resourcesArgsForCall)
}
func (fake *FakeCheckFactory) ResourcesCalls(stub func() ([]db.Resource, error)) {
fake.resourcesMutex.Lock()
defer fake.resourcesMutex.Unlock()
fake.ResourcesStub = stub
}
func (fake *FakeCheckFactory) ResourcesReturns(result1 []db.Resource, result2 error) {
fake.resourcesMutex.Lock()
defer fake.resourcesMutex.Unlock()
fake.ResourcesStub = nil
fake.resourcesReturns = struct {
result1 []db.Resource
result2 error
}{result1, result2}
}
func (fake *FakeCheckFactory) ResourcesReturnsOnCall(i int, result1 []db.Resource, result2 error) {
fake.resourcesMutex.Lock()
defer fake.resourcesMutex.Unlock()
fake.ResourcesStub = nil
if fake.resourcesReturnsOnCall == nil {
fake.resourcesReturnsOnCall = make(map[int]struct {
result1 []db.Resource
result2 error
})
}
fake.resourcesReturnsOnCall[i] = struct {
result1 []db.Resource
result2 error
}{result1, result2}
}
func (fake *FakeCheckFactory) StartedChecks() ([]db.Check, error) {
fake.startedChecksMutex.Lock()
ret, specificReturn := fake.startedChecksReturnsOnCall[len(fake.startedChecksArgsForCall)]
fake.startedChecksArgsForCall = append(fake.startedChecksArgsForCall, struct {
}{})
fake.recordInvocation("StartedChecks", []interface{}{})
fake.startedChecksMutex.Unlock()
if fake.StartedChecksStub != nil {
return fake.StartedChecksStub()
}
if specificReturn {
return ret.result1, ret.result2
}
fakeReturns := fake.startedChecksReturns
return fakeReturns.result1, fakeReturns.result2
}
func (fake *FakeCheckFactory) StartedChecksCallCount() int {
fake.startedChecksMutex.RLock()
defer fake.startedChecksMutex.RUnlock()
return len(fake.startedChecksArgsForCall)
}
func (fake *FakeCheckFactory) StartedChecksCalls(stub func() ([]db.Check, error)) {
fake.startedChecksMutex.Lock()
defer fake.startedChecksMutex.Unlock()
fake.StartedChecksStub = stub
}
func (fake *FakeCheckFactory) StartedChecksReturns(result1 []db.Check, result2 error) {
fake.startedChecksMutex.Lock()
defer fake.startedChecksMutex.Unlock()
fake.StartedChecksStub = nil
fake.startedChecksReturns = struct {
result1 []db.Check
result2 error
}{result1, result2}
}
func (fake *FakeCheckFactory) StartedChecksReturnsOnCall(i int, result1 []db.Check, result2 error) {
fake.startedChecksMutex.Lock()
defer fake.startedChecksMutex.Unlock()
fake.StartedChecksStub = nil
if fake.startedChecksReturnsOnCall == nil {
fake.startedChecksReturnsOnCall = make(map[int]struct {
result1 []db.Check
result2 error
})
}
fake.startedChecksReturnsOnCall[i] = struct {
result1 []db.Check
result2 error
}{result1, result2}
}
func (fake *FakeCheckFactory) TryCreateCheck(arg1 db.Checkable, arg2 db.ResourceTypes, arg3 atc.Version, arg4 bool) (db.Check, bool, error) {
fake.tryCreateCheckMutex.Lock()
ret, specificReturn := fake.tryCreateCheckReturnsOnCall[len(fake.tryCreateCheckArgsForCall)]
fake.tryCreateCheckArgsForCall = append(fake.tryCreateCheckArgsForCall, struct {
arg1 db.Checkable
arg2 db.ResourceTypes
arg3 atc.Version
arg4 bool
}{arg1, arg2, arg3, arg4})
fake.recordInvocation("TryCreateCheck", []interface{}{arg1, arg2, arg3, arg4})
fake.tryCreateCheckMutex.Unlock()
if fake.TryCreateCheckStub != nil {
return fake.TryCreateCheckStub(arg1, arg2, arg3, arg4)
}
if specificReturn {
return ret.result1, ret.result2, ret.result3
}
fakeReturns := fake.tryCreateCheckReturns
return fakeReturns.result1, fakeReturns.result2, fakeReturns.result3
}
func (fake *FakeCheckFactory) TryCreateCheckCallCount() int {
fake.tryCreateCheckMutex.RLock()
defer fake.tryCreateCheckMutex.RUnlock()
return len(fake.tryCreateCheckArgsForCall)
}
func (fake *FakeCheckFactory) TryCreateCheckCalls(stub func(db.Checkable, db.ResourceTypes, atc.Version, bool) (db.Check, bool, error)) {
fake.tryCreateCheckMutex.Lock()
defer fake.tryCreateCheckMutex.Unlock()
fake.TryCreateCheckStub = stub
}
func (fake *FakeCheckFactory) TryCreateCheckArgsForCall(i int) (db.Checkable, db.ResourceTypes, atc.Version, bool) {
fake.tryCreateCheckMutex.RLock()
defer fake.tryCreateCheckMutex.RUnlock()
argsForCall := fake.tryCreateCheckArgsForCall[i]
return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3, argsForCall.arg4
}
func (fake *FakeCheckFactory) TryCreateCheckReturns(result1 db.Check, result2 bool, result3 error) {
fake.tryCreateCheckMutex.Lock()
defer fake.tryCreateCheckMutex.Unlock()
fake.TryCreateCheckStub = nil
fake.tryCreateCheckReturns = struct {
result1 db.Check
result2 bool
result3 error
}{result1, result2, result3}
}
func (fake *FakeCheckFactory) TryCreateCheckReturnsOnCall(i int, result1 db.Check, result2 bool, result3 error) {
fake.tryCreateCheckMutex.Lock()
defer fake.tryCreateCheckMutex.Unlock()
fake.TryCreateCheckStub = nil
if fake.tryCreateCheckReturnsOnCall == nil {
fake.tryCreateCheckReturnsOnCall = make(map[int]struct {
result1 db.Check
result2 bool
result3 error
})
}
fake.tryCreateCheckReturnsOnCall[i] = struct {
result1 db.Check
result2 bool
result3 error
}{result1, result2, result3}
}
func (fake *FakeCheckFactory) Invocations() map[string][][]interface{} {
fake.invocationsMutex.RLock()
defer fake.invocationsMutex.RUnlock()
fake.acquireScanningLockMutex.RLock()
defer fake.acquireScanningLockMutex.RUnlock()
fake.checkMutex.RLock()
defer fake.checkMutex.RUnlock()
fake.createCheckMutex.RLock()
defer fake.createCheckMutex.RUnlock()
fake.notifyCheckerMutex.RLock()
defer fake.notifyCheckerMutex.RUnlock()
fake.resourceTypesMutex.RLock()
defer fake.resourceTypesMutex.RUnlock()
fake.resourcesMutex.RLock()
defer fake.resourcesMutex.RUnlock()
fake.startedChecksMutex.RLock()
defer fake.startedChecksMutex.RUnlock()
fake.tryCreateCheckMutex.RLock()
defer fake.tryCreateCheckMutex.RUnlock()
copiedInvocations := map[string][][]interface{}{}
for key, value := range fake.invocations {
copiedInvocations[key] = value
}
return copiedInvocations
}
func (fake *FakeCheckFactory) recordInvocation(key string, args []interface{}) {
fake.invocationsMutex.Lock()
defer fake.invocationsMutex.Unlock()
if fake.invocations == nil {
fake.invocations = map[string][][]interface{}{}
}
if fake.invocations[key] == nil {
fake.invocations[key] = [][]interface{}{}
}
fake.invocations[key] = append(fake.invocations[key], args)
}
var _ db.CheckFactory = new(FakeCheckFactory)

View File

@ -0,0 +1,111 @@
// Code generated by counterfeiter. DO NOT EDIT.
package dbfakes
import (
sync "sync"
time "time"
db "github.com/concourse/concourse/atc/db"
)
type FakeCheckLifecycle struct {
RemoveExpiredChecksStub func(time.Duration) error
removeExpiredChecksMutex sync.RWMutex
removeExpiredChecksArgsForCall []struct {
arg1 time.Duration
}
removeExpiredChecksReturns struct {
result1 error
}
removeExpiredChecksReturnsOnCall map[int]struct {
result1 error
}
invocations map[string][][]interface{}
invocationsMutex sync.RWMutex
}
func (fake *FakeCheckLifecycle) RemoveExpiredChecks(arg1 time.Duration) error {
fake.removeExpiredChecksMutex.Lock()
ret, specificReturn := fake.removeExpiredChecksReturnsOnCall[len(fake.removeExpiredChecksArgsForCall)]
fake.removeExpiredChecksArgsForCall = append(fake.removeExpiredChecksArgsForCall, struct {
arg1 time.Duration
}{arg1})
fake.recordInvocation("RemoveExpiredChecks", []interface{}{arg1})
fake.removeExpiredChecksMutex.Unlock()
if fake.RemoveExpiredChecksStub != nil {
return fake.RemoveExpiredChecksStub(arg1)
}
if specificReturn {
return ret.result1
}
fakeReturns := fake.removeExpiredChecksReturns
return fakeReturns.result1
}
func (fake *FakeCheckLifecycle) RemoveExpiredChecksCallCount() int {
fake.removeExpiredChecksMutex.RLock()
defer fake.removeExpiredChecksMutex.RUnlock()
return len(fake.removeExpiredChecksArgsForCall)
}
func (fake *FakeCheckLifecycle) RemoveExpiredChecksCalls(stub func(time.Duration) error) {
fake.removeExpiredChecksMutex.Lock()
defer fake.removeExpiredChecksMutex.Unlock()
fake.RemoveExpiredChecksStub = stub
}
func (fake *FakeCheckLifecycle) RemoveExpiredChecksArgsForCall(i int) time.Duration {
fake.removeExpiredChecksMutex.RLock()
defer fake.removeExpiredChecksMutex.RUnlock()
argsForCall := fake.removeExpiredChecksArgsForCall[i]
return argsForCall.arg1
}
func (fake *FakeCheckLifecycle) RemoveExpiredChecksReturns(result1 error) {
fake.removeExpiredChecksMutex.Lock()
defer fake.removeExpiredChecksMutex.Unlock()
fake.RemoveExpiredChecksStub = nil
fake.removeExpiredChecksReturns = struct {
result1 error
}{result1}
}
func (fake *FakeCheckLifecycle) RemoveExpiredChecksReturnsOnCall(i int, result1 error) {
fake.removeExpiredChecksMutex.Lock()
defer fake.removeExpiredChecksMutex.Unlock()
fake.RemoveExpiredChecksStub = nil
if fake.removeExpiredChecksReturnsOnCall == nil {
fake.removeExpiredChecksReturnsOnCall = make(map[int]struct {
result1 error
})
}
fake.removeExpiredChecksReturnsOnCall[i] = struct {
result1 error
}{result1}
}
func (fake *FakeCheckLifecycle) Invocations() map[string][][]interface{} {
fake.invocationsMutex.RLock()
defer fake.invocationsMutex.RUnlock()
fake.removeExpiredChecksMutex.RLock()
defer fake.removeExpiredChecksMutex.RUnlock()
copiedInvocations := map[string][][]interface{}{}
for key, value := range fake.invocations {
copiedInvocations[key] = value
}
return copiedInvocations
}
func (fake *FakeCheckLifecycle) recordInvocation(key string, args []interface{}) {
fake.invocationsMutex.Lock()
defer fake.invocationsMutex.Unlock()
if fake.invocations == nil {
fake.invocations = map[string][][]interface{}{}
}
if fake.invocations[key] == nil {
fake.invocations[key] = [][]interface{}{}
}
fake.invocations[key] = append(fake.invocations[key], args)
}
var _ db.CheckLifecycle = new(FakeCheckLifecycle)

View File

@ -332,6 +332,16 @@ type FakeResource struct {
tagsReturnsOnCall map[int]struct {
result1 atc.Tags
}
TeamIDStub func() int
teamIDMutex sync.RWMutex
teamIDArgsForCall []struct {
}
teamIDReturns struct {
result1 int
}
teamIDReturnsOnCall map[int]struct {
result1 int
}
TeamNameStub func() string
teamNameMutex sync.RWMutex
teamNameArgsForCall []struct {
@ -2051,6 +2061,58 @@ func (fake *FakeResource) TagsReturnsOnCall(i int, result1 atc.Tags) {
}{result1}
}
func (fake *FakeResource) TeamID() int {
fake.teamIDMutex.Lock()
ret, specificReturn := fake.teamIDReturnsOnCall[len(fake.teamIDArgsForCall)]
fake.teamIDArgsForCall = append(fake.teamIDArgsForCall, struct {
}{})
fake.recordInvocation("TeamID", []interface{}{})
fake.teamIDMutex.Unlock()
if fake.TeamIDStub != nil {
return fake.TeamIDStub()
}
if specificReturn {
return ret.result1
}
fakeReturns := fake.teamIDReturns
return fakeReturns.result1
}
func (fake *FakeResource) TeamIDCallCount() int {
fake.teamIDMutex.RLock()
defer fake.teamIDMutex.RUnlock()
return len(fake.teamIDArgsForCall)
}
func (fake *FakeResource) TeamIDCalls(stub func() int) {
fake.teamIDMutex.Lock()
defer fake.teamIDMutex.Unlock()
fake.TeamIDStub = stub
}
func (fake *FakeResource) TeamIDReturns(result1 int) {
fake.teamIDMutex.Lock()
defer fake.teamIDMutex.Unlock()
fake.TeamIDStub = nil
fake.teamIDReturns = struct {
result1 int
}{result1}
}
func (fake *FakeResource) TeamIDReturnsOnCall(i int, result1 int) {
fake.teamIDMutex.Lock()
defer fake.teamIDMutex.Unlock()
fake.TeamIDStub = nil
if fake.teamIDReturnsOnCall == nil {
fake.teamIDReturnsOnCall = make(map[int]struct {
result1 int
})
}
fake.teamIDReturnsOnCall[i] = struct {
result1 int
}{result1}
}
func (fake *FakeResource) TeamName() string {
fake.teamNameMutex.Lock()
ret, specificReturn := fake.teamNameReturnsOnCall[len(fake.teamNameArgsForCall)]
@ -2456,6 +2518,8 @@ func (fake *FakeResource) Invocations() map[string][][]interface{} {
defer fake.sourceMutex.RUnlock()
fake.tagsMutex.RLock()
defer fake.tagsMutex.RUnlock()
fake.teamIDMutex.RLock()
defer fake.teamIDMutex.RUnlock()
fake.teamNameMutex.RLock()
defer fake.teamNameMutex.RUnlock()
fake.typeMutex.RLock()

View File

@ -27,6 +27,18 @@ type FakeResourceConfigScope struct {
result2 bool
result3 error
}
AnyResourceStub func() (db.Resource, error)
anyResourceMutex sync.RWMutex
anyResourceArgsForCall []struct {
}
anyResourceReturns struct {
result1 db.Resource
result2 error
}
anyResourceReturnsOnCall map[int]struct {
result1 db.Resource
result2 error
}
CheckErrorStub func() error
checkErrorMutex sync.RWMutex
checkErrorArgsForCall []struct {
@ -214,6 +226,61 @@ func (fake *FakeResourceConfigScope) AcquireResourceCheckingLockReturnsOnCall(i
}{result1, result2, result3}
}
func (fake *FakeResourceConfigScope) AnyResource() (db.Resource, error) {
fake.anyResourceMutex.Lock()
ret, specificReturn := fake.anyResourceReturnsOnCall[len(fake.anyResourceArgsForCall)]
fake.anyResourceArgsForCall = append(fake.anyResourceArgsForCall, struct {
}{})
fake.recordInvocation("AnyResource", []interface{}{})
fake.anyResourceMutex.Unlock()
if fake.AnyResourceStub != nil {
return fake.AnyResourceStub()
}
if specificReturn {
return ret.result1, ret.result2
}
fakeReturns := fake.anyResourceReturns
return fakeReturns.result1, fakeReturns.result2
}
func (fake *FakeResourceConfigScope) AnyResourceCallCount() int {
fake.anyResourceMutex.RLock()
defer fake.anyResourceMutex.RUnlock()
return len(fake.anyResourceArgsForCall)
}
func (fake *FakeResourceConfigScope) AnyResourceCalls(stub func() (db.Resource, error)) {
fake.anyResourceMutex.Lock()
defer fake.anyResourceMutex.Unlock()
fake.AnyResourceStub = stub
}
func (fake *FakeResourceConfigScope) AnyResourceReturns(result1 db.Resource, result2 error) {
fake.anyResourceMutex.Lock()
defer fake.anyResourceMutex.Unlock()
fake.AnyResourceStub = nil
fake.anyResourceReturns = struct {
result1 db.Resource
result2 error
}{result1, result2}
}
func (fake *FakeResourceConfigScope) AnyResourceReturnsOnCall(i int, result1 db.Resource, result2 error) {
fake.anyResourceMutex.Lock()
defer fake.anyResourceMutex.Unlock()
fake.AnyResourceStub = nil
if fake.anyResourceReturnsOnCall == nil {
fake.anyResourceReturnsOnCall = make(map[int]struct {
result1 db.Resource
result2 error
})
}
fake.anyResourceReturnsOnCall[i] = struct {
result1 db.Resource
result2 error
}{result1, result2}
}
func (fake *FakeResourceConfigScope) CheckError() error {
fake.checkErrorMutex.Lock()
ret, specificReturn := fake.checkErrorReturnsOnCall[len(fake.checkErrorArgsForCall)]
@ -795,6 +862,8 @@ func (fake *FakeResourceConfigScope) Invocations() map[string][][]interface{} {
defer fake.invocationsMutex.RUnlock()
fake.acquireResourceCheckingLockMutex.RLock()
defer fake.acquireResourceCheckingLockMutex.RUnlock()
fake.anyResourceMutex.RLock()
defer fake.anyResourceMutex.RUnlock()
fake.checkErrorMutex.RLock()
defer fake.checkErrorMutex.RUnlock()
fake.findVersionMutex.RLock()

View File

@ -20,6 +20,21 @@ type FakeResourceFactory struct {
result1 []db.Resource
result2 error
}
ResourceStub func(int) (db.Resource, bool, error)
resourceMutex sync.RWMutex
resourceArgsForCall []struct {
arg1 int
}
resourceReturns struct {
result1 db.Resource
result2 bool
result3 error
}
resourceReturnsOnCall map[int]struct {
result1 db.Resource
result2 bool
result3 error
}
VisibleResourcesStub func([]string) ([]db.Resource, error)
visibleResourcesMutex sync.RWMutex
visibleResourcesArgsForCall []struct {
@ -92,6 +107,72 @@ func (fake *FakeResourceFactory) AllResourcesReturnsOnCall(i int, result1 []db.R
}{result1, result2}
}
func (fake *FakeResourceFactory) Resource(arg1 int) (db.Resource, bool, error) {
fake.resourceMutex.Lock()
ret, specificReturn := fake.resourceReturnsOnCall[len(fake.resourceArgsForCall)]
fake.resourceArgsForCall = append(fake.resourceArgsForCall, struct {
arg1 int
}{arg1})
fake.recordInvocation("Resource", []interface{}{arg1})
fake.resourceMutex.Unlock()
if fake.ResourceStub != nil {
return fake.ResourceStub(arg1)
}
if specificReturn {
return ret.result1, ret.result2, ret.result3
}
fakeReturns := fake.resourceReturns
return fakeReturns.result1, fakeReturns.result2, fakeReturns.result3
}
func (fake *FakeResourceFactory) ResourceCallCount() int {
fake.resourceMutex.RLock()
defer fake.resourceMutex.RUnlock()
return len(fake.resourceArgsForCall)
}
func (fake *FakeResourceFactory) ResourceCalls(stub func(int) (db.Resource, bool, error)) {
fake.resourceMutex.Lock()
defer fake.resourceMutex.Unlock()
fake.ResourceStub = stub
}
func (fake *FakeResourceFactory) ResourceArgsForCall(i int) int {
fake.resourceMutex.RLock()
defer fake.resourceMutex.RUnlock()
argsForCall := fake.resourceArgsForCall[i]
return argsForCall.arg1
}
func (fake *FakeResourceFactory) ResourceReturns(result1 db.Resource, result2 bool, result3 error) {
fake.resourceMutex.Lock()
defer fake.resourceMutex.Unlock()
fake.ResourceStub = nil
fake.resourceReturns = struct {
result1 db.Resource
result2 bool
result3 error
}{result1, result2, result3}
}
func (fake *FakeResourceFactory) ResourceReturnsOnCall(i int, result1 db.Resource, result2 bool, result3 error) {
fake.resourceMutex.Lock()
defer fake.resourceMutex.Unlock()
fake.ResourceStub = nil
if fake.resourceReturnsOnCall == nil {
fake.resourceReturnsOnCall = make(map[int]struct {
result1 db.Resource
result2 bool
result3 error
})
}
fake.resourceReturnsOnCall[i] = struct {
result1 db.Resource
result2 bool
result3 error
}{result1, result2, result3}
}
func (fake *FakeResourceFactory) VisibleResources(arg1 []string) ([]db.Resource, error) {
var arg1Copy []string
if arg1 != nil {
@ -165,6 +246,8 @@ func (fake *FakeResourceFactory) Invocations() map[string][][]interface{} {
defer fake.invocationsMutex.RUnlock()
fake.allResourcesMutex.RLock()
defer fake.allResourcesMutex.RUnlock()
fake.resourceMutex.RLock()
defer fake.resourceMutex.RUnlock()
fake.visibleResourcesMutex.RLock()
defer fake.visibleResourcesMutex.RUnlock()
copiedInvocations := map[string][][]interface{}{}

View File

@ -3,6 +3,7 @@ package dbfakes
import (
"sync"
"time"
"github.com/concourse/concourse/atc"
"github.com/concourse/concourse/atc/db"
@ -39,6 +40,26 @@ type FakeResourceType struct {
checkSetupErrorReturnsOnCall map[int]struct {
result1 error
}
CheckTimeoutStub func() string
checkTimeoutMutex sync.RWMutex
checkTimeoutArgsForCall []struct {
}
checkTimeoutReturns struct {
result1 string
}
checkTimeoutReturnsOnCall map[int]struct {
result1 string
}
CurrentPinnedVersionStub func() atc.Version
currentPinnedVersionMutex sync.RWMutex
currentPinnedVersionArgsForCall []struct {
}
currentPinnedVersionReturns struct {
result1 atc.Version
}
currentPinnedVersionReturnsOnCall map[int]struct {
result1 atc.Version
}
IDStub func() int
iDMutex sync.RWMutex
iDArgsForCall []struct {
@ -49,6 +70,26 @@ type FakeResourceType struct {
iDReturnsOnCall map[int]struct {
result1 int
}
LastCheckEndTimeStub func() time.Time
lastCheckEndTimeMutex sync.RWMutex
lastCheckEndTimeArgsForCall []struct {
}
lastCheckEndTimeReturns struct {
result1 time.Time
}
lastCheckEndTimeReturnsOnCall map[int]struct {
result1 time.Time
}
LastCheckStartTimeStub func() time.Time
lastCheckStartTimeMutex sync.RWMutex
lastCheckStartTimeArgsForCall []struct {
}
lastCheckStartTimeReturns struct {
result1 time.Time
}
lastCheckStartTimeReturnsOnCall map[int]struct {
result1 time.Time
}
NameStub func() string
nameMutex sync.RWMutex
nameArgsForCall []struct {
@ -69,6 +110,26 @@ type FakeResourceType struct {
paramsReturnsOnCall map[int]struct {
result1 atc.Params
}
PipelineIDStub func() int
pipelineIDMutex sync.RWMutex
pipelineIDArgsForCall []struct {
}
pipelineIDReturns struct {
result1 int
}
pipelineIDReturnsOnCall map[int]struct {
result1 int
}
PipelineNameStub func() string
pipelineNameMutex sync.RWMutex
pipelineNameArgsForCall []struct {
}
pipelineNameReturns struct {
result1 string
}
pipelineNameReturnsOnCall map[int]struct {
result1 string
}
PrivilegedStub func() bool
privilegedMutex sync.RWMutex
privilegedArgsForCall []struct {
@ -136,6 +197,26 @@ type FakeResourceType struct {
tagsReturnsOnCall map[int]struct {
result1 atc.Tags
}
TeamIDStub func() int
teamIDMutex sync.RWMutex
teamIDArgsForCall []struct {
}
teamIDReturns struct {
result1 int
}
teamIDReturnsOnCall map[int]struct {
result1 int
}
TeamNameStub func() string
teamNameMutex sync.RWMutex
teamNameArgsForCall []struct {
}
teamNameReturns struct {
result1 string
}
teamNameReturnsOnCall map[int]struct {
result1 string
}
TypeStub func() string
typeMutex sync.RWMutex
typeArgsForCall []struct {
@ -326,6 +407,110 @@ func (fake *FakeResourceType) CheckSetupErrorReturnsOnCall(i int, result1 error)
}{result1}
}
func (fake *FakeResourceType) CheckTimeout() string {
fake.checkTimeoutMutex.Lock()
ret, specificReturn := fake.checkTimeoutReturnsOnCall[len(fake.checkTimeoutArgsForCall)]
fake.checkTimeoutArgsForCall = append(fake.checkTimeoutArgsForCall, struct {
}{})
fake.recordInvocation("CheckTimeout", []interface{}{})
fake.checkTimeoutMutex.Unlock()
if fake.CheckTimeoutStub != nil {
return fake.CheckTimeoutStub()
}
if specificReturn {
return ret.result1
}
fakeReturns := fake.checkTimeoutReturns
return fakeReturns.result1
}
func (fake *FakeResourceType) CheckTimeoutCallCount() int {
fake.checkTimeoutMutex.RLock()
defer fake.checkTimeoutMutex.RUnlock()
return len(fake.checkTimeoutArgsForCall)
}
func (fake *FakeResourceType) CheckTimeoutCalls(stub func() string) {
fake.checkTimeoutMutex.Lock()
defer fake.checkTimeoutMutex.Unlock()
fake.CheckTimeoutStub = stub
}
func (fake *FakeResourceType) CheckTimeoutReturns(result1 string) {
fake.checkTimeoutMutex.Lock()
defer fake.checkTimeoutMutex.Unlock()
fake.CheckTimeoutStub = nil
fake.checkTimeoutReturns = struct {
result1 string
}{result1}
}
func (fake *FakeResourceType) CheckTimeoutReturnsOnCall(i int, result1 string) {
fake.checkTimeoutMutex.Lock()
defer fake.checkTimeoutMutex.Unlock()
fake.CheckTimeoutStub = nil
if fake.checkTimeoutReturnsOnCall == nil {
fake.checkTimeoutReturnsOnCall = make(map[int]struct {
result1 string
})
}
fake.checkTimeoutReturnsOnCall[i] = struct {
result1 string
}{result1}
}
func (fake *FakeResourceType) CurrentPinnedVersion() atc.Version {
fake.currentPinnedVersionMutex.Lock()
ret, specificReturn := fake.currentPinnedVersionReturnsOnCall[len(fake.currentPinnedVersionArgsForCall)]
fake.currentPinnedVersionArgsForCall = append(fake.currentPinnedVersionArgsForCall, struct {
}{})
fake.recordInvocation("CurrentPinnedVersion", []interface{}{})
fake.currentPinnedVersionMutex.Unlock()
if fake.CurrentPinnedVersionStub != nil {
return fake.CurrentPinnedVersionStub()
}
if specificReturn {
return ret.result1
}
fakeReturns := fake.currentPinnedVersionReturns
return fakeReturns.result1
}
func (fake *FakeResourceType) CurrentPinnedVersionCallCount() int {
fake.currentPinnedVersionMutex.RLock()
defer fake.currentPinnedVersionMutex.RUnlock()
return len(fake.currentPinnedVersionArgsForCall)
}
func (fake *FakeResourceType) CurrentPinnedVersionCalls(stub func() atc.Version) {
fake.currentPinnedVersionMutex.Lock()
defer fake.currentPinnedVersionMutex.Unlock()
fake.CurrentPinnedVersionStub = stub
}
func (fake *FakeResourceType) CurrentPinnedVersionReturns(result1 atc.Version) {
fake.currentPinnedVersionMutex.Lock()
defer fake.currentPinnedVersionMutex.Unlock()
fake.CurrentPinnedVersionStub = nil
fake.currentPinnedVersionReturns = struct {
result1 atc.Version
}{result1}
}
func (fake *FakeResourceType) CurrentPinnedVersionReturnsOnCall(i int, result1 atc.Version) {
fake.currentPinnedVersionMutex.Lock()
defer fake.currentPinnedVersionMutex.Unlock()
fake.CurrentPinnedVersionStub = nil
if fake.currentPinnedVersionReturnsOnCall == nil {
fake.currentPinnedVersionReturnsOnCall = make(map[int]struct {
result1 atc.Version
})
}
fake.currentPinnedVersionReturnsOnCall[i] = struct {
result1 atc.Version
}{result1}
}
func (fake *FakeResourceType) ID() int {
fake.iDMutex.Lock()
ret, specificReturn := fake.iDReturnsOnCall[len(fake.iDArgsForCall)]
@ -378,6 +563,110 @@ func (fake *FakeResourceType) IDReturnsOnCall(i int, result1 int) {
}{result1}
}
func (fake *FakeResourceType) LastCheckEndTime() time.Time {
fake.lastCheckEndTimeMutex.Lock()
ret, specificReturn := fake.lastCheckEndTimeReturnsOnCall[len(fake.lastCheckEndTimeArgsForCall)]
fake.lastCheckEndTimeArgsForCall = append(fake.lastCheckEndTimeArgsForCall, struct {
}{})
fake.recordInvocation("LastCheckEndTime", []interface{}{})
fake.lastCheckEndTimeMutex.Unlock()
if fake.LastCheckEndTimeStub != nil {
return fake.LastCheckEndTimeStub()
}
if specificReturn {
return ret.result1
}
fakeReturns := fake.lastCheckEndTimeReturns
return fakeReturns.result1
}
func (fake *FakeResourceType) LastCheckEndTimeCallCount() int {
fake.lastCheckEndTimeMutex.RLock()
defer fake.lastCheckEndTimeMutex.RUnlock()
return len(fake.lastCheckEndTimeArgsForCall)
}
func (fake *FakeResourceType) LastCheckEndTimeCalls(stub func() time.Time) {
fake.lastCheckEndTimeMutex.Lock()
defer fake.lastCheckEndTimeMutex.Unlock()
fake.LastCheckEndTimeStub = stub
}
func (fake *FakeResourceType) LastCheckEndTimeReturns(result1 time.Time) {
fake.lastCheckEndTimeMutex.Lock()
defer fake.lastCheckEndTimeMutex.Unlock()
fake.LastCheckEndTimeStub = nil
fake.lastCheckEndTimeReturns = struct {
result1 time.Time
}{result1}
}
func (fake *FakeResourceType) LastCheckEndTimeReturnsOnCall(i int, result1 time.Time) {
fake.lastCheckEndTimeMutex.Lock()
defer fake.lastCheckEndTimeMutex.Unlock()
fake.LastCheckEndTimeStub = nil
if fake.lastCheckEndTimeReturnsOnCall == nil {
fake.lastCheckEndTimeReturnsOnCall = make(map[int]struct {
result1 time.Time
})
}
fake.lastCheckEndTimeReturnsOnCall[i] = struct {
result1 time.Time
}{result1}
}
func (fake *FakeResourceType) LastCheckStartTime() time.Time {
fake.lastCheckStartTimeMutex.Lock()
ret, specificReturn := fake.lastCheckStartTimeReturnsOnCall[len(fake.lastCheckStartTimeArgsForCall)]
fake.lastCheckStartTimeArgsForCall = append(fake.lastCheckStartTimeArgsForCall, struct {
}{})
fake.recordInvocation("LastCheckStartTime", []interface{}{})
fake.lastCheckStartTimeMutex.Unlock()
if fake.LastCheckStartTimeStub != nil {
return fake.LastCheckStartTimeStub()
}
if specificReturn {
return ret.result1
}
fakeReturns := fake.lastCheckStartTimeReturns
return fakeReturns.result1
}
func (fake *FakeResourceType) LastCheckStartTimeCallCount() int {
fake.lastCheckStartTimeMutex.RLock()
defer fake.lastCheckStartTimeMutex.RUnlock()
return len(fake.lastCheckStartTimeArgsForCall)
}
func (fake *FakeResourceType) LastCheckStartTimeCalls(stub func() time.Time) {
fake.lastCheckStartTimeMutex.Lock()
defer fake.lastCheckStartTimeMutex.Unlock()
fake.LastCheckStartTimeStub = stub
}
func (fake *FakeResourceType) LastCheckStartTimeReturns(result1 time.Time) {
fake.lastCheckStartTimeMutex.Lock()
defer fake.lastCheckStartTimeMutex.Unlock()
fake.LastCheckStartTimeStub = nil
fake.lastCheckStartTimeReturns = struct {
result1 time.Time
}{result1}
}
func (fake *FakeResourceType) LastCheckStartTimeReturnsOnCall(i int, result1 time.Time) {
fake.lastCheckStartTimeMutex.Lock()
defer fake.lastCheckStartTimeMutex.Unlock()
fake.LastCheckStartTimeStub = nil
if fake.lastCheckStartTimeReturnsOnCall == nil {
fake.lastCheckStartTimeReturnsOnCall = make(map[int]struct {
result1 time.Time
})
}
fake.lastCheckStartTimeReturnsOnCall[i] = struct {
result1 time.Time
}{result1}
}
func (fake *FakeResourceType) Name() string {
fake.nameMutex.Lock()
ret, specificReturn := fake.nameReturnsOnCall[len(fake.nameArgsForCall)]
@ -482,6 +771,110 @@ func (fake *FakeResourceType) ParamsReturnsOnCall(i int, result1 atc.Params) {
}{result1}
}
func (fake *FakeResourceType) PipelineID() int {
fake.pipelineIDMutex.Lock()
ret, specificReturn := fake.pipelineIDReturnsOnCall[len(fake.pipelineIDArgsForCall)]
fake.pipelineIDArgsForCall = append(fake.pipelineIDArgsForCall, struct {
}{})
fake.recordInvocation("PipelineID", []interface{}{})
fake.pipelineIDMutex.Unlock()
if fake.PipelineIDStub != nil {
return fake.PipelineIDStub()
}
if specificReturn {
return ret.result1
}
fakeReturns := fake.pipelineIDReturns
return fakeReturns.result1
}
func (fake *FakeResourceType) PipelineIDCallCount() int {
fake.pipelineIDMutex.RLock()
defer fake.pipelineIDMutex.RUnlock()
return len(fake.pipelineIDArgsForCall)
}
func (fake *FakeResourceType) PipelineIDCalls(stub func() int) {
fake.pipelineIDMutex.Lock()
defer fake.pipelineIDMutex.Unlock()
fake.PipelineIDStub = stub
}
func (fake *FakeResourceType) PipelineIDReturns(result1 int) {
fake.pipelineIDMutex.Lock()
defer fake.pipelineIDMutex.Unlock()
fake.PipelineIDStub = nil
fake.pipelineIDReturns = struct {
result1 int
}{result1}
}
func (fake *FakeResourceType) PipelineIDReturnsOnCall(i int, result1 int) {
fake.pipelineIDMutex.Lock()
defer fake.pipelineIDMutex.Unlock()
fake.PipelineIDStub = nil
if fake.pipelineIDReturnsOnCall == nil {
fake.pipelineIDReturnsOnCall = make(map[int]struct {
result1 int
})
}
fake.pipelineIDReturnsOnCall[i] = struct {
result1 int
}{result1}
}
func (fake *FakeResourceType) PipelineName() string {
fake.pipelineNameMutex.Lock()
ret, specificReturn := fake.pipelineNameReturnsOnCall[len(fake.pipelineNameArgsForCall)]
fake.pipelineNameArgsForCall = append(fake.pipelineNameArgsForCall, struct {
}{})
fake.recordInvocation("PipelineName", []interface{}{})
fake.pipelineNameMutex.Unlock()
if fake.PipelineNameStub != nil {
return fake.PipelineNameStub()
}
if specificReturn {
return ret.result1
}
fakeReturns := fake.pipelineNameReturns
return fakeReturns.result1
}
func (fake *FakeResourceType) PipelineNameCallCount() int {
fake.pipelineNameMutex.RLock()
defer fake.pipelineNameMutex.RUnlock()
return len(fake.pipelineNameArgsForCall)
}
func (fake *FakeResourceType) PipelineNameCalls(stub func() string) {
fake.pipelineNameMutex.Lock()
defer fake.pipelineNameMutex.Unlock()
fake.PipelineNameStub = stub
}
func (fake *FakeResourceType) PipelineNameReturns(result1 string) {
fake.pipelineNameMutex.Lock()
defer fake.pipelineNameMutex.Unlock()
fake.PipelineNameStub = nil
fake.pipelineNameReturns = struct {
result1 string
}{result1}
}
func (fake *FakeResourceType) PipelineNameReturnsOnCall(i int, result1 string) {
fake.pipelineNameMutex.Lock()
defer fake.pipelineNameMutex.Unlock()
fake.PipelineNameStub = nil
if fake.pipelineNameReturnsOnCall == nil {
fake.pipelineNameReturnsOnCall = make(map[int]struct {
result1 string
})
}
fake.pipelineNameReturnsOnCall[i] = struct {
result1 string
}{result1}
}
func (fake *FakeResourceType) Privileged() bool {
fake.privilegedMutex.Lock()
ret, specificReturn := fake.privilegedReturnsOnCall[len(fake.privilegedArgsForCall)]
@ -817,6 +1210,110 @@ func (fake *FakeResourceType) TagsReturnsOnCall(i int, result1 atc.Tags) {
}{result1}
}
func (fake *FakeResourceType) TeamID() int {
fake.teamIDMutex.Lock()
ret, specificReturn := fake.teamIDReturnsOnCall[len(fake.teamIDArgsForCall)]
fake.teamIDArgsForCall = append(fake.teamIDArgsForCall, struct {
}{})
fake.recordInvocation("TeamID", []interface{}{})
fake.teamIDMutex.Unlock()
if fake.TeamIDStub != nil {
return fake.TeamIDStub()
}
if specificReturn {
return ret.result1
}
fakeReturns := fake.teamIDReturns
return fakeReturns.result1
}
func (fake *FakeResourceType) TeamIDCallCount() int {
fake.teamIDMutex.RLock()
defer fake.teamIDMutex.RUnlock()
return len(fake.teamIDArgsForCall)
}
func (fake *FakeResourceType) TeamIDCalls(stub func() int) {
fake.teamIDMutex.Lock()
defer fake.teamIDMutex.Unlock()
fake.TeamIDStub = stub
}
func (fake *FakeResourceType) TeamIDReturns(result1 int) {
fake.teamIDMutex.Lock()
defer fake.teamIDMutex.Unlock()
fake.TeamIDStub = nil
fake.teamIDReturns = struct {
result1 int
}{result1}
}
func (fake *FakeResourceType) TeamIDReturnsOnCall(i int, result1 int) {
fake.teamIDMutex.Lock()
defer fake.teamIDMutex.Unlock()
fake.TeamIDStub = nil
if fake.teamIDReturnsOnCall == nil {
fake.teamIDReturnsOnCall = make(map[int]struct {
result1 int
})
}
fake.teamIDReturnsOnCall[i] = struct {
result1 int
}{result1}
}
func (fake *FakeResourceType) TeamName() string {
fake.teamNameMutex.Lock()
ret, specificReturn := fake.teamNameReturnsOnCall[len(fake.teamNameArgsForCall)]
fake.teamNameArgsForCall = append(fake.teamNameArgsForCall, struct {
}{})
fake.recordInvocation("TeamName", []interface{}{})
fake.teamNameMutex.Unlock()
if fake.TeamNameStub != nil {
return fake.TeamNameStub()
}
if specificReturn {
return ret.result1
}
fakeReturns := fake.teamNameReturns
return fakeReturns.result1
}
func (fake *FakeResourceType) TeamNameCallCount() int {
fake.teamNameMutex.RLock()
defer fake.teamNameMutex.RUnlock()
return len(fake.teamNameArgsForCall)
}
func (fake *FakeResourceType) TeamNameCalls(stub func() string) {
fake.teamNameMutex.Lock()
defer fake.teamNameMutex.Unlock()
fake.TeamNameStub = stub
}
func (fake *FakeResourceType) TeamNameReturns(result1 string) {
fake.teamNameMutex.Lock()
defer fake.teamNameMutex.Unlock()
fake.TeamNameStub = nil
fake.teamNameReturns = struct {
result1 string
}{result1}
}
func (fake *FakeResourceType) TeamNameReturnsOnCall(i int, result1 string) {
fake.teamNameMutex.Lock()
defer fake.teamNameMutex.Unlock()
fake.TeamNameStub = nil
if fake.teamNameReturnsOnCall == nil {
fake.teamNameReturnsOnCall = make(map[int]struct {
result1 string
})
}
fake.teamNameReturnsOnCall[i] = struct {
result1 string
}{result1}
}
func (fake *FakeResourceType) Type() string {
fake.typeMutex.Lock()
ret, specificReturn := fake.typeReturnsOnCall[len(fake.typeArgsForCall)]
@ -982,12 +1479,24 @@ func (fake *FakeResourceType) Invocations() map[string][][]interface{} {
defer fake.checkEveryMutex.RUnlock()
fake.checkSetupErrorMutex.RLock()
defer fake.checkSetupErrorMutex.RUnlock()
fake.checkTimeoutMutex.RLock()
defer fake.checkTimeoutMutex.RUnlock()
fake.currentPinnedVersionMutex.RLock()
defer fake.currentPinnedVersionMutex.RUnlock()
fake.iDMutex.RLock()
defer fake.iDMutex.RUnlock()
fake.lastCheckEndTimeMutex.RLock()
defer fake.lastCheckEndTimeMutex.RUnlock()
fake.lastCheckStartTimeMutex.RLock()
defer fake.lastCheckStartTimeMutex.RUnlock()
fake.nameMutex.RLock()
defer fake.nameMutex.RUnlock()
fake.paramsMutex.RLock()
defer fake.paramsMutex.RUnlock()
fake.pipelineIDMutex.RLock()
defer fake.pipelineIDMutex.RUnlock()
fake.pipelineNameMutex.RLock()
defer fake.pipelineNameMutex.RUnlock()
fake.privilegedMutex.RLock()
defer fake.privilegedMutex.RUnlock()
fake.reloadMutex.RLock()
@ -1000,6 +1509,10 @@ func (fake *FakeResourceType) Invocations() map[string][][]interface{} {
defer fake.sourceMutex.RUnlock()
fake.tagsMutex.RLock()
defer fake.tagsMutex.RUnlock()
fake.teamIDMutex.RLock()
defer fake.teamIDMutex.RUnlock()
fake.teamNameMutex.RLock()
defer fake.teamNameMutex.RUnlock()
fake.typeMutex.RLock()
defer fake.typeMutex.RUnlock()
fake.uniqueVersionHistoryMutex.RLock()

View File

@ -21,6 +21,7 @@ const (
LockTypeContainerCreating
LockTypeDatabaseMigration
LockTypeActiveTasks
LockTypeResourceScanning
)
var ErrLostLock = errors.New("lock was lost while held, possibly due to connection breakage")
@ -53,6 +54,10 @@ func NewActiveTasksLockID() LockID {
return LockID{LockTypeActiveTasks}
}
func NewResourceScanningLockID() LockID {
return LockID{LockTypeResourceScanning}
}
//go:generate counterfeiter . LockFactory
type LockFactory interface {

View File

@ -0,0 +1,3 @@
BEGIN;
DROP TABLE checks;
COMMIT;

View File

@ -0,0 +1,20 @@
BEGIN;
CREATE TABLE checks (
id bigserial PRIMARY KEY,
resource_config_scope_id integer REFERENCES resource_config_scopes(id) ON DELETE CASCADE,
schema text NOT NULL,
status text NOT NULL,
manually_triggered boolean DEFAULT false,
plan text,
nonce text,
check_error text,
metadata jsonb,
create_time timestamp WITH TIME ZONE DEFAULT now() NOT NULL,
start_time timestamp WITH TIME ZONE,
end_time timestamp WITH TIME ZONE
);
CREATE UNIQUE INDEX resource_config_scope_id_key ON checks (resource_config_scope_id) WHERE status = 'started' AND manually_triggered = false;
COMMIT;

View File

@ -127,6 +127,7 @@ var encryptedColumns = []encryptedColumn{
{"resource_types", "config", "id"},
{"builds", "private_plan", "id"},
{"cert_cache", "cert", "domain"},
{"checks", "plan", "id"},
}
func encryptPlaintext(logger lager.Logger, sqlDB *sql.DB, key *encryption.Key) error {

View File

@ -22,6 +22,7 @@ type Resource interface {
Public() bool
PipelineID() int
PipelineName() string
TeamID() int
TeamName() string
Type() string
Source() atc.Source
@ -61,7 +62,25 @@ type Resource interface {
Reload() (bool, error)
}
var resourcesQuery = psql.Select("r.id, r.name, r.type, r.config, r.check_error, rs.last_check_start_time, rs.last_check_end_time, r.pipeline_id, r.nonce, r.resource_config_id, r.resource_config_scope_id, p.name, t.name, rs.check_error, rp.version, rp.comment_text").
var resourcesQuery = psql.Select(
"r.id",
"r.name",
"r.type",
"r.config",
"r.check_error",
"rs.last_check_start_time",
"rs.last_check_end_time",
"r.pipeline_id",
"r.nonce",
"r.resource_config_id",
"r.resource_config_scope_id",
"p.name",
"t.id",
"t.name",
"rs.check_error",
"rp.version",
"rp.comment_text",
).
From("resources r").
Join("pipelines p ON p.id = r.pipeline_id").
Join("teams t ON t.id = p.team_id").
@ -75,6 +94,7 @@ type resource struct {
public bool
pipelineID int
pipelineName string
teamID int
teamName string
type_ string
source atc.Source
@ -142,6 +162,7 @@ func (r *resource) Name() string { return r.name }
func (r *resource) Public() bool { return r.public }
func (r *resource) PipelineID() int { return r.pipelineID }
func (r *resource) PipelineName() string { return r.pipelineName }
func (r *resource) TeamID() int { return r.teamID }
func (r *resource) TeamName() string { return r.teamName }
func (r *resource) Type() string { return r.type_ }
func (r *resource) Source() atc.Source { return r.source }
@ -265,15 +286,7 @@ func (r *resource) SetCheckSetupError(cause error) error {
return err
}
// SaveUncheckedVersion is used by the "get" and "put" step to find or create of a
// resource config version. We want to do an upsert because there will be cases
// where resource config versions can become outdated while the versions
// associated to it are still valid. This will be special case where we save
// the version with a check order of 0 in order to avoid using this version
// until we do a proper check. Note that this method will not bump the cache
// index for the pipeline because we want to ignore these versions until the
// check orders get updated. The bumping of the index will be done in
// SaveOutput for the put step.
// XXX: only used for tests
func (r *resource) SaveUncheckedVersion(version atc.Version, metadata ResourceConfigMetadataFields, resourceConfig ResourceConfig, resourceTypes atc.VersionedResourceTypes) (bool, error) {
tx, err := r.conn.Begin()
if err != nil {
@ -287,7 +300,7 @@ func (r *resource) SaveUncheckedVersion(version atc.Version, metadata ResourceCo
return false, err
}
newVersion, err := saveResourceVersion(tx, resourceConfigScope, version, metadata)
newVersion, err := saveResourceVersion(tx, resourceConfigScope.ID(), version, metadata)
if err != nil {
return false, err
}
@ -650,7 +663,7 @@ func scanResource(r *resource, row scannable) error {
lastCheckStartTime, lastCheckEndTime pq.NullTime
)
err := row.Scan(&r.id, &r.name, &r.type_, &configBlob, &checkErr, &lastCheckStartTime, &lastCheckEndTime, &r.pipelineID, &nonce, &rcID, &rcScopeID, &r.pipelineName, &r.teamName, &rcsCheckErr, &apiPinnedVersion, &pinComment)
err := row.Scan(&r.id, &r.name, &r.type_, &configBlob, &checkErr, &lastCheckStartTime, &lastCheckEndTime, &r.pipelineID, &nonce, &rcID, &rcScopeID, &r.pipelineName, &r.teamID, &r.teamName, &rcsCheckErr, &apiPinnedVersion, &pinComment)
if err != nil {
return err
}

View File

@ -181,7 +181,11 @@ var _ = Describe("ResourceCacheLifecycle", func() {
)
Expect(err).ToNot(HaveOccurred())
containerOwner = db.NewResourceConfigCheckSessionContainerOwner(resourceConfig, db.ContainerOwnerExpiries{})
containerOwner = db.NewResourceConfigCheckSessionContainerOwner(
resourceConfig.ID(),
resourceConfig.OriginBaseResourceType().ID,
db.ContainerOwnerExpiries{},
)
container, err = defaultWorker.CreateContainer(containerOwner, db.ContainerMetadata{})
Expect(err).ToNot(HaveOccurred())
@ -297,7 +301,11 @@ var _ = Describe("ResourceCacheLifecycle", func() {
)
Expect(err).ToNot(HaveOccurred())
containerOwner := db.NewResourceConfigCheckSessionContainerOwner(resourceConfigScope.ResourceConfig(), db.ContainerOwnerExpiries{})
containerOwner := db.NewResourceConfigCheckSessionContainerOwner(
resourceConfigScope.ResourceConfig().ID(),
resourceConfigScope.ResourceConfig().OriginBaseResourceType().ID,
db.ContainerOwnerExpiries{},
)
container, err := defaultWorker.CreateContainer(containerOwner, db.ContainerMetadata{})
Expect(err).ToNot(HaveOccurred())

View File

@ -31,7 +31,11 @@ var _ = Describe("ResourceConfigCheckSessionLifecycle", func() {
resourceConfigScope, err := defaultResource.SetResourceConfig(defaultResource.Source(), atc.VersionedResourceTypes{})
Expect(err).ToNot(HaveOccurred())
owner := db.NewResourceConfigCheckSessionContainerOwner(resourceConfigScope.ResourceConfig(), expiry)
owner := db.NewResourceConfigCheckSessionContainerOwner(
resourceConfigScope.ResourceConfig().ID(),
resourceConfigScope.ResourceConfig().OriginBaseResourceType().ID,
expiry,
)
var query sq.Eq
var found bool
@ -128,7 +132,11 @@ var _ = Describe("ResourceConfigCheckSessionLifecycle", func() {
)
Expect(err).ToNot(HaveOccurred())
owner := db.NewResourceConfigCheckSessionContainerOwner(resourceConfigScope.ResourceConfig(), expiry)
owner := db.NewResourceConfigCheckSessionContainerOwner(
resourceConfigScope.ResourceConfig().ID(),
resourceConfigScope.ResourceConfig().OriginBaseResourceType().ID,
expiry,
)
var query sq.Eq
var found bool

View File

@ -67,7 +67,11 @@ func (r *resourceConfigScope) CheckError() error { return r.checkEr
// that already exist in the DB will be re-ordered using
// incrementCheckOrderWhenNewerVersion to input the correct check order
func (r *resourceConfigScope) SaveVersions(versions []atc.Version) error {
tx, err := r.conn.Begin()
return saveVersions(r.conn, r.ID(), versions)
}
func saveVersions(conn Conn, rcsID int, versions []atc.Version) error {
tx, err := conn.Begin()
if err != nil {
return err
}
@ -75,7 +79,7 @@ func (r *resourceConfigScope) SaveVersions(versions []atc.Version) error {
defer Rollback(tx)
for _, version := range versions {
_, err = saveResourceVersion(tx, r, version, nil)
_, err = saveResourceVersion(tx, rcsID, version, nil)
if err != nil {
return err
}
@ -85,7 +89,7 @@ func (r *resourceConfigScope) SaveVersions(versions []atc.Version) error {
return err
}
err = incrementCheckOrder(tx, r, string(versionJSON))
err = incrementCheckOrder(tx, rcsID, string(versionJSON))
if err != nil {
return err
}
@ -96,7 +100,7 @@ func (r *resourceConfigScope) SaveVersions(versions []atc.Version) error {
return err
}
err = bumpCacheIndexForPipelinesUsingResourceConfigScope(r.conn, r.id)
err = bumpCacheIndexForPipelinesUsingResourceConfigScope(conn, rcsID)
if err != nil {
return err
}
@ -256,7 +260,7 @@ func (r *resourceConfigScope) UpdateLastCheckEndTime() (bool, error) {
return true, nil
}
func saveResourceVersion(tx Tx, r ResourceConfigScope, version atc.Version, metadata ResourceConfigMetadataFields) (bool, error) {
func saveResourceVersion(tx Tx, rcsID int, version atc.Version, metadata ResourceConfigMetadataFields) (bool, error) {
versionJSON, err := json.Marshal(version)
if err != nil {
return false, err
@ -274,7 +278,7 @@ func saveResourceVersion(tx Tx, r ResourceConfigScope, version atc.Version, meta
ON CONFLICT (resource_config_scope_id, version_md5)
DO UPDATE SET metadata = COALESCE(NULLIF(excluded.metadata, 'null'::jsonb), resource_config_versions.metadata)
RETURNING check_order
`, r.ID(), string(versionJSON), string(versionJSON), string(metadataJSON)).Scan(&checkOrder)
`, rcsID, string(versionJSON), string(versionJSON), string(metadataJSON)).Scan(&checkOrder)
if err != nil {
return false, err
}
@ -286,7 +290,7 @@ func saveResourceVersion(tx Tx, r ResourceConfigScope, version atc.Version, meta
// current max. This will fix the case of a check from an old version causing
// the desired order to change; existing versions will be re-ordered since
// we add them in the desired order.
func incrementCheckOrder(tx Tx, r ResourceConfigScope, version string) error {
func incrementCheckOrder(tx Tx, rcsID int, version string) error {
_, err := tx.Exec(`
WITH max_checkorder AS (
SELECT max(check_order) co
@ -299,7 +303,7 @@ func incrementCheckOrder(tx Tx, r ResourceConfigScope, version string) error {
FROM max_checkorder mc
WHERE resource_config_scope_id = $1
AND version = $2
AND check_order <= mc.co;`, r.ID(), version)
AND check_order <= mc.co;`, rcsID, version)
return err
}

View File

@ -10,6 +10,7 @@ import (
//go:generate counterfeiter . ResourceFactory
type ResourceFactory interface {
Resource(int) (Resource, bool, error)
VisibleResources([]string) ([]Resource, error)
AllResources() ([]Resource, error)
}
@ -26,16 +27,37 @@ func NewResourceFactory(conn Conn, lockFactory lock.LockFactory) ResourceFactory
}
}
func (r *resourceFactory) Resource(resourceID int) (Resource, bool, error) {
resource := &resource{
conn: r.conn,
lockFactory: r.lockFactory,
}
row := resourcesQuery.
Where(sq.Eq{"r.id": resourceID}).
RunWith(r.conn).
QueryRow()
err := scanResource(resource, row)
if err != nil {
if err == sql.ErrNoRows {
return nil, false, nil
}
return nil, false, err
}
return resource, true, nil
}
func (r *resourceFactory) VisibleResources(teamNames []string) ([]Resource, error) {
rows, err := resourcesQuery.
Where(
sq.Or{
sq.Eq{"t.name": teamNames},
sq.And{
sq.NotEq{"t.name": teamNames},
sq.Eq{"p.public": true},
},
}).
Where(sq.Or{
sq.Eq{"t.name": teamNames},
sq.And{
sq.NotEq{"t.name": teamNames},
sq.Eq{"p.public": true},
},
}).
OrderBy("r.id ASC").
RunWith(r.conn).
Query()

View File

@ -5,10 +5,12 @@ import (
"encoding/json"
"errors"
"fmt"
"time"
sq "github.com/Masterminds/squirrel"
"github.com/concourse/concourse/atc"
"github.com/concourse/concourse/atc/db/lock"
"github.com/lib/pq"
)
type ResourceTypeNotFoundError struct {
@ -23,6 +25,10 @@ func (e ResourceTypeNotFoundError) Error() string {
type ResourceType interface {
ID() int
PipelineID() int
PipelineName() string
TeamID() int
TeamName() string
Name() string
Type() string
Privileged() bool
@ -30,9 +36,13 @@ type ResourceType interface {
Params() atc.Params
Tags() atc.Tags
CheckEvery() string
CheckTimeout() string
LastCheckStartTime() time.Time
LastCheckEndTime() time.Time
CheckSetupError() error
CheckError() error
UniqueVersionHistory() bool
CurrentPinnedVersion() atc.Version
SetResourceConfig(atc.Source, atc.VersionedResourceTypes) (ResourceConfigScope, error)
SetCheckSetupError(error) error
@ -44,6 +54,31 @@ type ResourceType interface {
type ResourceTypes []ResourceType
func (resourceTypes ResourceTypes) Parent(checkable Checkable) (ResourceType, bool) {
for _, t := range resourceTypes {
if t.PipelineID() == checkable.PipelineID() {
if t.Name() != checkable.Name() && t.Name() == checkable.Type() {
return t, true
}
}
}
return nil, false
}
func (resourceTypes ResourceTypes) Filter(checkable Checkable) ResourceTypes {
var result ResourceTypes
for {
resourceType, found := resourceTypes.Parent(checkable)
if !found {
return result
}
result = append(result, resourceType)
checkable = resourceType
}
}
func (resourceTypes ResourceTypes) Deserialize() atc.VersionedResourceTypes {
var versionedResourceTypes atc.VersionedResourceTypes
@ -85,8 +120,25 @@ func (resourceTypes ResourceTypes) Configs() atc.ResourceTypes {
return configs
}
var resourceTypesQuery = psql.Select("r.id, r.name, r.type, r.config, rcv.version, r.nonce, r.check_error, ro.check_error").
var resourceTypesQuery = psql.Select(
"r.id",
"r.pipeline_id",
"r.name",
"r.type",
"r.config",
"rcv.version",
"r.nonce",
"r.check_error",
"p.name",
"t.id",
"t.name",
"ro.check_error",
"ro.last_check_start_time",
"ro.last_check_end_time",
).
From("resource_types r").
Join("pipelines p ON p.id = r.pipeline_id").
Join("teams t ON t.id = p.team_id").
LeftJoin("resource_configs c ON c.id = r.resource_config_id").
LeftJoin("resource_config_scopes ro ON ro.resource_config_id = c.id").
LeftJoin(`LATERAL (
@ -100,6 +152,10 @@ var resourceTypesQuery = psql.Select("r.id, r.name, r.type, r.config, rcv.versio
type resourceType struct {
id int
pipelineID int
pipelineName string
teamID int
teamName string
name string
type_ string
privileged bool
@ -108,6 +164,8 @@ type resourceType struct {
tags atc.Tags
version atc.Version
checkEvery string
lastCheckStartTime time.Time
lastCheckEndTime time.Time
checkSetupError error
checkError error
uniqueVersionHistory bool
@ -116,19 +174,27 @@ type resourceType struct {
lockFactory lock.LockFactory
}
func (t *resourceType) ID() int { return t.id }
func (t *resourceType) Name() string { return t.name }
func (t *resourceType) Type() string { return t.type_ }
func (t *resourceType) Privileged() bool { return t.privileged }
func (t *resourceType) CheckEvery() string { return t.checkEvery }
func (t *resourceType) Source() atc.Source { return t.source }
func (t *resourceType) Params() atc.Params { return t.params }
func (t *resourceType) Tags() atc.Tags { return t.tags }
func (t *resourceType) CheckSetupError() error { return t.checkSetupError }
func (t *resourceType) CheckError() error { return t.checkError }
func (t *resourceType) UniqueVersionHistory() bool { return t.uniqueVersionHistory }
func (t *resourceType) ID() int { return t.id }
func (t *resourceType) PipelineID() int { return t.pipelineID }
func (t *resourceType) PipelineName() string { return t.pipelineName }
func (t *resourceType) TeamID() int { return t.teamID }
func (t *resourceType) TeamName() string { return t.teamName }
func (t *resourceType) Name() string { return t.name }
func (t *resourceType) Type() string { return t.type_ }
func (t *resourceType) Privileged() bool { return t.privileged }
func (t *resourceType) CheckEvery() string { return t.checkEvery }
func (t *resourceType) CheckTimeout() string { return "" }
func (r *resourceType) LastCheckStartTime() time.Time { return r.lastCheckStartTime }
func (r *resourceType) LastCheckEndTime() time.Time { return r.lastCheckEndTime }
func (t *resourceType) Source() atc.Source { return t.source }
func (t *resourceType) Params() atc.Params { return t.params }
func (t *resourceType) Tags() atc.Tags { return t.tags }
func (t *resourceType) CheckSetupError() error { return t.checkSetupError }
func (t *resourceType) CheckError() error { return t.checkError }
func (t *resourceType) UniqueVersionHistory() bool { return t.uniqueVersionHistory }
func (t *resourceType) Version() atc.Version { return t.version }
func (t *resourceType) Version() atc.Version { return t.version }
func (t *resourceType) CurrentPinnedVersion() atc.Version { return nil }
func (t *resourceType) Reload() (bool, error) {
row := resourceTypesQuery.Where(sq.Eq{"r.id": t.id}).RunWith(t.conn).QueryRow()
@ -211,13 +277,17 @@ func scanResourceType(t *resourceType, row scannable) error {
var (
configJSON []byte
checkErr, rcsCheckErr, version, nonce sql.NullString
lastCheckStartTime, lastCheckEndTime pq.NullTime
)
err := row.Scan(&t.id, &t.name, &t.type_, &configJSON, &version, &nonce, &checkErr, &rcsCheckErr)
err := row.Scan(&t.id, &t.pipelineID, &t.name, &t.type_, &configJSON, &version, &nonce, &checkErr, &t.pipelineName, &t.teamID, &t.teamName, &rcsCheckErr, &lastCheckStartTime, &lastCheckEndTime)
if err != nil {
return err
}
t.lastCheckStartTime = lastCheckStartTime.Time
t.lastCheckEndTime = lastCheckEndTime.Time
if version.Valid {
err = json.Unmarshal([]byte(version.String), &t.version)
if err != nil {

View File

@ -55,7 +55,7 @@ var _ = Describe("ResourceType", func() {
})
Describe("(Pipeline).ResourceTypes", func() {
var resourceTypes []db.ResourceType
var resourceTypes db.ResourceTypes
JustBeforeEach(func() {
var err error
@ -129,6 +129,109 @@ var _ = Describe("ResourceType", func() {
Expect(resourceTypes[0].Name()).To(Equal("some-type"))
})
})
Context("when building the dependency tree from resource types list", func() {
BeforeEach(func() {
var (
created bool
err error
)
otherPipeline, created, err := defaultTeam.SavePipeline(
"pipeline-with-duplicate-type-name",
atc.Config{
ResourceTypes: atc.ResourceTypes{
{
Name: "some-custom-type",
Type: "some-different-foo-type",
Source: atc.Source{"some": "repository"},
CheckEvery: "10ms",
},
},
},
db.ConfigVersion(0),
false,
)
Expect(err).ToNot(HaveOccurred())
Expect(created).To(BeTrue())
Expect(otherPipeline).NotTo(BeNil())
pipeline, created, err = defaultTeam.SavePipeline(
"pipeline-with-types",
atc.Config{
Resources: atc.ResourceConfigs{
{
Name: "some-resource",
Type: "some-custom-type",
Source: atc.Source{},
},
},
ResourceTypes: atc.ResourceTypes{
{
Name: "registry-image",
Type: "registry-image",
Source: atc.Source{"some": "repository"},
},
{
Name: "some-other-type",
Type: "registry-image",
Privileged: true,
Source: atc.Source{"some": "other-repository"},
},
{
Name: "some-type-with-params",
Type: "s3",
Source: atc.Source{"some": "repository"},
Params: atc.Params{"unpack": "true"},
},
{
Name: "some-type-with-custom-check",
Type: "registry-image",
Source: atc.Source{"some": "repository"},
CheckEvery: "10ms",
},
{
Name: "some-custom-type",
Type: "some-other-foo-type",
Source: atc.Source{"some": "repository"},
CheckEvery: "10ms",
},
{
Name: "some-other-foo-type",
Type: "some-other-type",
Source: atc.Source{"some": "repository"},
CheckEvery: "10ms",
},
},
},
pipeline.ConfigVersion(),
false,
)
Expect(err).ToNot(HaveOccurred())
Expect(created).To(BeFalse())
})
It("returns the resource types tree given a resource", func() {
resource, found, err := pipeline.Resource("some-resource")
Expect(err).NotTo(HaveOccurred())
Expect(found).To(BeTrue())
tree := resourceTypes.Filter(resource)
Expect(len(tree)).To(Equal(4))
Expect(tree[0].Name()).To(Equal("some-custom-type"))
Expect(tree[0].Type()).To(Equal("some-other-foo-type"))
Expect(tree[1].Name()).To(Equal("some-other-foo-type"))
Expect(tree[1].Type()).To(Equal("some-other-type"))
Expect(tree[2].Name()).To(Equal("some-other-type"))
Expect(tree[2].Type()).To(Equal("registry-image"))
Expect(tree[3].Name()).To(Equal("registry-image"))
Expect(tree[3].Type()).To(Equal("registry-image"))
})
})
})
Describe("SetCheckError", func() {

View File

@ -439,7 +439,11 @@ var _ = Describe("Team", func() {
Expect(err).ToNot(HaveOccurred())
resourceContainer, err = defaultWorker.CreateContainer(
db.NewResourceConfigCheckSessionContainerOwner(resourceConfigScope.ResourceConfig(), expiries),
db.NewResourceConfigCheckSessionContainerOwner(
resourceConfigScope.ResourceConfig().ID(),
resourceConfigScope.ResourceConfig().OriginBaseResourceType().ID,
expiries,
),
db.ContainerMetadata{},
)
Expect(err).ToNot(HaveOccurred())
@ -485,12 +489,15 @@ var _ = Describe("Team", func() {
Expect(err).ToNot(HaveOccurred())
resourceContainer, err = worker.CreateContainer(
db.NewResourceConfigCheckSessionContainerOwner(resourceConfigScope.ResourceConfig(), expiries),
db.NewResourceConfigCheckSessionContainerOwner(
resourceConfigScope.ResourceConfig().ID(),
resourceConfigScope.ResourceConfig().OriginBaseResourceType().ID,
expiries,
),
db.ContainerMetadata{
Type: "check",
},
)
Expect(err).ToNot(HaveOccurred())
})
It("finds the container", func() {
@ -563,12 +570,15 @@ var _ = Describe("Team", func() {
Expect(err).ToNot(HaveOccurred())
resource2Container, err = worker.CreateContainer(
db.NewResourceConfigCheckSessionContainerOwner(resourceConfigScope.ResourceConfig(), expiries),
db.NewResourceConfigCheckSessionContainerOwner(
resourceConfigScope.ResourceConfig().ID(),
resourceConfigScope.ResourceConfig().OriginBaseResourceType().ID,
expiries,
),
db.ContainerMetadata{
Type: "check",
},
)
Expect(err).ToNot(HaveOccurred())
})
It("returns the container only from the team", func() {
@ -595,7 +605,11 @@ var _ = Describe("Team", func() {
Expect(err).ToNot(HaveOccurred())
globalResourceContainer, err = defaultWorker.CreateContainer(
db.NewResourceConfigCheckSessionContainerOwner(resourceConfigScope.ResourceConfig(), expiries),
db.NewResourceConfigCheckSessionContainerOwner(
resourceConfigScope.ResourceConfig().ID(),
resourceConfigScope.ResourceConfig().OriginBaseResourceType().ID,
expiries,
),
db.ContainerMetadata{
Type: "check",
},
@ -626,7 +640,11 @@ var _ = Describe("Team", func() {
Expect(err).ToNot(HaveOccurred())
resourceContainer, err = defaultWorker.CreateContainer(
db.NewResourceConfigCheckSessionContainerOwner(resourceConfigScope.ResourceConfig(), expiries),
db.NewResourceConfigCheckSessionContainerOwner(
resourceConfigScope.ResourceConfig().ID(),
resourceConfigScope.ResourceConfig().OriginBaseResourceType().ID,
expiries,
),
db.ContainerMetadata{
Type: "check",
},
@ -2484,7 +2502,11 @@ var _ = Describe("Team", func() {
Expect(err).ToNot(HaveOccurred())
resourceContainer, err = defaultWorker.CreateContainer(
db.NewResourceConfigCheckSessionContainerOwner(resourceConfig, expiries),
db.NewResourceConfigCheckSessionContainerOwner(
resourceConfig.ID(),
resourceConfig.OriginBaseResourceType().ID,
expiries,
),
db.ContainerMetadata{},
)
Expect(err).ToNot(HaveOccurred())
@ -2534,7 +2556,11 @@ var _ = Describe("Team", func() {
Expect(err).ToNot(HaveOccurred())
otherResourceContainer, _, err = defaultWorker.FindContainer(
db.NewResourceConfigCheckSessionContainerOwner(resourceConfig, expiries),
db.NewResourceConfigCheckSessionContainerOwner(
resourceConfig.ID(),
resourceConfig.OriginBaseResourceType().ID,
expiries,
),
)
Expect(err).ToNot(HaveOccurred())
})
@ -2597,7 +2623,11 @@ var _ = Describe("Team", func() {
Expect(err).ToNot(HaveOccurred())
resourceContainer, err = defaultWorker.CreateContainer(
db.NewResourceConfigCheckSessionContainerOwner(resourceConfigScope.ResourceConfig(), expiries),
db.NewResourceConfigCheckSessionContainerOwner(
resourceConfigScope.ResourceConfig().ID(),
resourceConfigScope.ResourceConfig().OriginBaseResourceType().ID,
expiries,
),
db.ContainerMetadata{},
)
Expect(err).ToNot(HaveOccurred())

View File

@ -22,7 +22,14 @@ var _ = Describe("Volume", func() {
resourceConfig, err := resourceConfigFactory.FindOrCreateResourceConfig("some-base-resource-type", atc.Source{}, atc.VersionedResourceTypes{})
Expect(err).ToNot(HaveOccurred())
defaultCreatingContainer, err = defaultWorker.CreateContainer(db.NewResourceConfigCheckSessionContainerOwner(resourceConfig, expiries), db.ContainerMetadata{Type: "check"})
defaultCreatingContainer, err = defaultWorker.CreateContainer(
db.NewResourceConfigCheckSessionContainerOwner(
resourceConfig.ID(),
resourceConfig.OriginBaseResourceType().ID,
expiries,
),
db.ContainerMetadata{Type: "check"},
)
Expect(err).ToNot(HaveOccurred())
defaultCreatedContainer, err = defaultCreatingContainer.Created()

View File

@ -626,7 +626,11 @@ var _ = Describe("WorkerFactory", func() {
rcs, err := otherResource.SetResourceConfig(atc.Source{"some": "source"}, atc.VersionedResourceTypes{})
Expect(err).NotTo(HaveOccurred())
owner = db.NewResourceConfigCheckSessionContainerOwner(rcs.ResourceConfig(), ownerExpiries)
owner = db.NewResourceConfigCheckSessionContainerOwner(
rcs.ResourceConfig().ID(),
rcs.ResourceConfig().OriginBaseResourceType().ID,
ownerExpiries,
)
_, err = defaultWorker.CreateContainer(owner, containerMetadata)
Expect(err).ToNot(HaveOccurred())

View File

@ -242,7 +242,11 @@ var _ = Describe("Worker", func() {
)
Expect(err).ToNot(HaveOccurred())
containerOwner = NewResourceConfigCheckSessionContainerOwner(resourceConfig, expiries)
containerOwner = NewResourceConfigCheckSessionContainerOwner(
resourceConfig.ID(),
resourceConfig.OriginBaseResourceType().ID,
expiries,
)
})
JustBeforeEach(func() {

View File

@ -7,7 +7,6 @@ import (
"github.com/concourse/concourse/atc"
"github.com/concourse/concourse/atc/db"
"github.com/concourse/concourse/atc/db/lock"
"github.com/concourse/concourse/atc/exec"
)
@ -18,7 +17,8 @@ const supportedSchema = "exec.v2"
type StepFactory interface {
GetStep(atc.Plan, exec.StepMetadata, db.ContainerMetadata, exec.GetDelegate) exec.Step
PutStep(atc.Plan, exec.StepMetadata, db.ContainerMetadata, exec.PutDelegate) exec.Step
TaskStep(atc.Plan, exec.StepMetadata, db.ContainerMetadata, exec.TaskDelegate, lock.LockFactory) exec.Step
TaskStep(atc.Plan, exec.StepMetadata, db.ContainerMetadata, exec.TaskDelegate) exec.Step
CheckStep(atc.Plan, exec.StepMetadata, db.ContainerMetadata, exec.CheckDelegate) exec.Step
ArtifactInputStep(atc.Plan, db.Build, exec.BuildStepDelegate) exec.Step
ArtifactOutputStep(atc.Plan, db.Build, exec.BuildStepDelegate) exec.Step
}
@ -29,6 +29,7 @@ type DelegateFactory interface {
GetDelegate(db.Build, atc.PlanID) exec.GetDelegate
PutDelegate(db.Build, atc.PlanID) exec.PutDelegate
TaskDelegate(db.Build, atc.PlanID) exec.TaskDelegate
CheckDelegate(db.Check, atc.PlanID) exec.CheckDelegate
BuildStepDelegate(db.Build, atc.PlanID) exec.BuildStepDelegate
}
@ -36,13 +37,11 @@ func NewStepBuilder(
stepFactory StepFactory,
delegateFactory DelegateFactory,
externalURL string,
lockFactory lock.LockFactory,
) *stepBuilder {
return &stepBuilder{
stepFactory: stepFactory,
delegateFactory: delegateFactory,
externalURL: externalURL,
lockFactory: lockFactory,
}
}
@ -50,7 +49,6 @@ type stepBuilder struct {
stepFactory StepFactory
delegateFactory DelegateFactory
externalURL string
lockFactory lock.LockFactory
}
func (builder *stepBuilder) BuildStep(build db.Build) (exec.Step, error) {
@ -66,6 +64,19 @@ func (builder *stepBuilder) BuildStep(build db.Build) (exec.Step, error) {
return builder.buildStep(build, build.PrivatePlan()), nil
}
func (builder *stepBuilder) CheckStep(check db.Check) (exec.Step, error) {
if check == nil {
return exec.IdentityStep{}, errors.New("Must provide a check")
}
if check.Schema() != supportedSchema {
return exec.IdentityStep{}, errors.New("Schema not supported")
}
return builder.buildCheckStep(check, check.Plan()), nil
}
func (builder *stepBuilder) buildStep(build db.Build, plan atc.Plan) exec.Step {
if plan.Aggregate != nil {
return builder.buildAggregateStep(build, plan)
@ -285,6 +296,28 @@ func (builder *stepBuilder) buildPutStep(build db.Build, plan atc.Plan) exec.Ste
)
}
func (builder *stepBuilder) buildCheckStep(check db.Check, plan atc.Plan) exec.Step {
containerMetadata := db.ContainerMetadata{
Type: db.ContainerTypeCheck,
}
stepMetadata := exec.StepMetadata{
TeamID: check.TeamID(),
ResourceConfigScopeID: check.ResourceConfigScopeID(),
ResourceConfigID: check.ResourceConfigID(),
BaseResourceTypeID: check.BaseResourceTypeID(),
ExternalURL: builder.externalURL,
}
return builder.stepFactory.CheckStep(
plan,
stepMetadata,
containerMetadata,
builder.delegateFactory.CheckDelegate(check, plan.ID),
)
}
func (builder *stepBuilder) buildTaskStep(build db.Build, plan atc.Plan) exec.Step {
containerMetadata := builder.containerMetadata(
@ -304,7 +337,6 @@ func (builder *stepBuilder) buildTaskStep(build db.Build, plan atc.Plan) exec.St
stepMetadata,
containerMetadata,
builder.delegateFactory.TaskDelegate(build, plan.ID),
builder.lockFactory,
)
}

View File

@ -4,8 +4,6 @@ import (
"github.com/concourse/concourse/atc"
"github.com/concourse/concourse/atc/db"
"github.com/concourse/concourse/atc/db/dbfakes"
"github.com/concourse/concourse/atc/db/lock"
"github.com/concourse/concourse/atc/db/lock/lockfakes"
"github.com/concourse/concourse/atc/engine/builder"
"github.com/concourse/concourse/atc/engine/builder/builderfakes"
"github.com/concourse/concourse/atc/exec"
@ -16,6 +14,7 @@ import (
type StepBuilder interface {
BuildStep(db.Build) (exec.Step, error)
CheckStep(db.Check) (exec.Step, error)
}
var _ = Describe("Builder", func() {
@ -27,8 +26,6 @@ var _ = Describe("Builder", func() {
fakeStepFactory *builderfakes.FakeStepFactory
fakeDelegateFactory *builderfakes.FakeDelegateFactory
fakeLockDB *lockfakes.FakeLockDB
fakeLockFactory lock.LockFactory
planFactory atc.PlanFactory
stepBuilder StepBuilder
@ -37,13 +34,11 @@ var _ = Describe("Builder", func() {
BeforeEach(func() {
fakeStepFactory = new(builderfakes.FakeStepFactory)
fakeDelegateFactory = new(builderfakes.FakeDelegateFactory)
fakeLockFactory = lock.NewTestLockFactory(fakeLockDB)
stepBuilder = builder.NewStepBuilder(
fakeStepFactory,
fakeDelegateFactory,
"http://example.com",
fakeLockFactory,
)
planFactory = atc.NewPlanFactory(123)
@ -361,7 +356,7 @@ var _ = Describe("Builder", func() {
})
It("constructs nested steps correctly", func() {
plan, stepMetadata, containerMetadata, _, _ := fakeStepFactory.TaskStepArgsForCall(0)
plan, stepMetadata, containerMetadata, _ := fakeStepFactory.TaskStepArgsForCall(0)
expectedPlan := taskPlan
expectedPlan.Attempts = []int{2, 1}
Expect(plan).To(Equal(expectedPlan))
@ -378,7 +373,7 @@ var _ = Describe("Builder", func() {
Attempt: "2.1",
}))
plan, stepMetadata, containerMetadata, _, _ = fakeStepFactory.TaskStepArgsForCall(1)
plan, stepMetadata, containerMetadata, _ = fakeStepFactory.TaskStepArgsForCall(1)
expectedPlan = taskPlan
expectedPlan.Attempts = []int{2, 2}
Expect(plan).To(Equal(expectedPlan))
@ -448,15 +443,15 @@ var _ = Describe("Builder", func() {
It("constructs nested steps correctly", func() {
Expect(fakeStepFactory.TaskStepCallCount()).To(Equal(6))
_, _, containerMetadata, _, _ := fakeStepFactory.TaskStepArgsForCall(0)
_, _, containerMetadata, _ := fakeStepFactory.TaskStepArgsForCall(0)
Expect(containerMetadata.Attempt).To(Equal("1"))
_, _, containerMetadata, _, _ = fakeStepFactory.TaskStepArgsForCall(1)
_, _, containerMetadata, _ = fakeStepFactory.TaskStepArgsForCall(1)
Expect(containerMetadata.Attempt).To(Equal("1"))
_, _, containerMetadata, _, _ = fakeStepFactory.TaskStepArgsForCall(2)
_, _, containerMetadata, _ = fakeStepFactory.TaskStepArgsForCall(2)
Expect(containerMetadata.Attempt).To(Equal("1"))
_, _, containerMetadata, _, _ = fakeStepFactory.TaskStepArgsForCall(3)
_, _, containerMetadata, _ = fakeStepFactory.TaskStepArgsForCall(3)
Expect(containerMetadata.Attempt).To(Equal("1"))
_, _, containerMetadata, _, _ = fakeStepFactory.TaskStepArgsForCall(4)
_, _, containerMetadata, _ = fakeStepFactory.TaskStepArgsForCall(4)
Expect(containerMetadata.Attempt).To(Equal("1"))
})
})
@ -504,7 +499,7 @@ var _ = Describe("Builder", func() {
})
It("constructs tasks correctly", func() {
plan, stepMetadata, containerMetadata, _, _ := fakeStepFactory.TaskStepArgsForCall(0)
plan, stepMetadata, containerMetadata, _ := fakeStepFactory.TaskStepArgsForCall(0)
Expect(plan).To(Equal(expectedPlan))
Expect(stepMetadata).To(Equal(expectedMetadata))
Expect(containerMetadata).To(Equal(db.ContainerMetadata{
@ -651,7 +646,7 @@ var _ = Describe("Builder", func() {
It("constructs the completion hook correctly", func() {
Expect(fakeStepFactory.TaskStepCallCount()).To(Equal(4))
plan, stepMetadata, containerMetadata, _, _ := fakeStepFactory.TaskStepArgsForCall(2)
plan, stepMetadata, containerMetadata, _ := fakeStepFactory.TaskStepArgsForCall(2)
Expect(plan).To(Equal(completionTaskPlan))
Expect(stepMetadata).To(Equal(expectedMetadata))
Expect(containerMetadata).To(Equal(db.ContainerMetadata{
@ -668,7 +663,7 @@ var _ = Describe("Builder", func() {
It("constructs the failure hook correctly", func() {
Expect(fakeStepFactory.TaskStepCallCount()).To(Equal(4))
plan, stepMetadata, containerMetadata, _, _ := fakeStepFactory.TaskStepArgsForCall(0)
plan, stepMetadata, containerMetadata, _ := fakeStepFactory.TaskStepArgsForCall(0)
Expect(plan).To(Equal(failureTaskPlan))
Expect(stepMetadata).To(Equal(expectedMetadata))
Expect(containerMetadata).To(Equal(db.ContainerMetadata{
@ -685,7 +680,7 @@ var _ = Describe("Builder", func() {
It("constructs the success hook correctly", func() {
Expect(fakeStepFactory.TaskStepCallCount()).To(Equal(4))
plan, stepMetadata, containerMetadata, _, _ := fakeStepFactory.TaskStepArgsForCall(1)
plan, stepMetadata, containerMetadata, _ := fakeStepFactory.TaskStepArgsForCall(1)
Expect(plan).To(Equal(successTaskPlan))
Expect(stepMetadata).To(Equal(expectedMetadata))
Expect(containerMetadata).To(Equal(db.ContainerMetadata{
@ -702,7 +697,7 @@ var _ = Describe("Builder", func() {
It("constructs the next step correctly", func() {
Expect(fakeStepFactory.TaskStepCallCount()).To(Equal(4))
plan, stepMetadata, containerMetadata, _, _ := fakeStepFactory.TaskStepArgsForCall(3)
plan, stepMetadata, containerMetadata, _ := fakeStepFactory.TaskStepArgsForCall(3)
Expect(plan).To(Equal(nextTaskPlan))
Expect(stepMetadata).To(Equal(expectedMetadata))
Expect(containerMetadata).To(Equal(db.ContainerMetadata{
@ -753,4 +748,106 @@ var _ = Describe("Builder", func() {
})
})
Describe("CheckStep", func() {
var (
err error
fakeStepFactory *builderfakes.FakeStepFactory
fakeDelegateFactory *builderfakes.FakeDelegateFactory
planFactory atc.PlanFactory
stepBuilder StepBuilder
)
BeforeEach(func() {
fakeStepFactory = new(builderfakes.FakeStepFactory)
fakeDelegateFactory = new(builderfakes.FakeDelegateFactory)
stepBuilder = builder.NewStepBuilder(
fakeStepFactory,
fakeDelegateFactory,
"http://example.com",
)
planFactory = atc.NewPlanFactory(123)
})
Context("with no check", func() {
JustBeforeEach(func() {
_, err = stepBuilder.CheckStep(nil)
})
It("errors", func() {
Expect(err).To(HaveOccurred())
})
})
Context("with a check", func() {
var (
fakeCheck *dbfakes.FakeCheck
expectedPlan atc.Plan
expectedMetadata exec.StepMetadata
)
BeforeEach(func() {
fakeCheck = new(dbfakes.FakeCheck)
fakeCheck.ResourceConfigScopeIDReturns(4444)
fakeCheck.BaseResourceTypeIDReturns(2222)
expectedMetadata = exec.StepMetadata{
ResourceConfigScopeID: 4444,
BaseResourceTypeID: 2222,
ExternalURL: "http://example.com",
}
})
JustBeforeEach(func() {
fakeCheck.PlanReturns(expectedPlan)
_, err = stepBuilder.CheckStep(fakeCheck)
})
Context("when the check has the wrong schema", func() {
BeforeEach(func() {
fakeCheck.SchemaReturns("not-schema")
})
It("errors", func() {
Expect(err).To(HaveOccurred())
})
})
Context("when the build has the right schema", func() {
BeforeEach(func() {
fakeCheck.SchemaReturns("exec.v2")
})
It("always returns a plan", func() {
Expect(err).NotTo(HaveOccurred())
})
Context("with a check plan", func() {
BeforeEach(func() {
expectedPlan = planFactory.NewPlan(atc.CheckPlan{
Name: "some-check",
Type: "git",
Source: atc.Source{"some": "source"},
})
})
It("constructs the put correctly", func() {
plan, stepMetadata, containerMetadata, _ := fakeStepFactory.CheckStepArgsForCall(0)
Expect(plan).To(Equal(expectedPlan))
Expect(stepMetadata).To(Equal(expectedMetadata))
Expect(containerMetadata).To(Equal(db.ContainerMetadata{
Type: db.ContainerTypeCheck,
}))
})
})
})
})
})
})

View File

@ -23,6 +23,18 @@ type FakeDelegateFactory struct {
buildStepDelegateReturnsOnCall map[int]struct {
result1 exec.BuildStepDelegate
}
CheckDelegateStub func(db.Check, atc.PlanID) exec.CheckDelegate
checkDelegateMutex sync.RWMutex
checkDelegateArgsForCall []struct {
arg1 db.Check
arg2 atc.PlanID
}
checkDelegateReturns struct {
result1 exec.CheckDelegate
}
checkDelegateReturnsOnCall map[int]struct {
result1 exec.CheckDelegate
}
GetDelegateStub func(db.Build, atc.PlanID) exec.GetDelegate
getDelegateMutex sync.RWMutex
getDelegateArgsForCall []struct {
@ -124,6 +136,67 @@ func (fake *FakeDelegateFactory) BuildStepDelegateReturnsOnCall(i int, result1 e
}{result1}
}
func (fake *FakeDelegateFactory) CheckDelegate(arg1 db.Check, arg2 atc.PlanID) exec.CheckDelegate {
fake.checkDelegateMutex.Lock()
ret, specificReturn := fake.checkDelegateReturnsOnCall[len(fake.checkDelegateArgsForCall)]
fake.checkDelegateArgsForCall = append(fake.checkDelegateArgsForCall, struct {
arg1 db.Check
arg2 atc.PlanID
}{arg1, arg2})
fake.recordInvocation("CheckDelegate", []interface{}{arg1, arg2})
fake.checkDelegateMutex.Unlock()
if fake.CheckDelegateStub != nil {
return fake.CheckDelegateStub(arg1, arg2)
}
if specificReturn {
return ret.result1
}
fakeReturns := fake.checkDelegateReturns
return fakeReturns.result1
}
func (fake *FakeDelegateFactory) CheckDelegateCallCount() int {
fake.checkDelegateMutex.RLock()
defer fake.checkDelegateMutex.RUnlock()
return len(fake.checkDelegateArgsForCall)
}
func (fake *FakeDelegateFactory) CheckDelegateCalls(stub func(db.Check, atc.PlanID) exec.CheckDelegate) {
fake.checkDelegateMutex.Lock()
defer fake.checkDelegateMutex.Unlock()
fake.CheckDelegateStub = stub
}
func (fake *FakeDelegateFactory) CheckDelegateArgsForCall(i int) (db.Check, atc.PlanID) {
fake.checkDelegateMutex.RLock()
defer fake.checkDelegateMutex.RUnlock()
argsForCall := fake.checkDelegateArgsForCall[i]
return argsForCall.arg1, argsForCall.arg2
}
func (fake *FakeDelegateFactory) CheckDelegateReturns(result1 exec.CheckDelegate) {
fake.checkDelegateMutex.Lock()
defer fake.checkDelegateMutex.Unlock()
fake.CheckDelegateStub = nil
fake.checkDelegateReturns = struct {
result1 exec.CheckDelegate
}{result1}
}
func (fake *FakeDelegateFactory) CheckDelegateReturnsOnCall(i int, result1 exec.CheckDelegate) {
fake.checkDelegateMutex.Lock()
defer fake.checkDelegateMutex.Unlock()
fake.CheckDelegateStub = nil
if fake.checkDelegateReturnsOnCall == nil {
fake.checkDelegateReturnsOnCall = make(map[int]struct {
result1 exec.CheckDelegate
})
}
fake.checkDelegateReturnsOnCall[i] = struct {
result1 exec.CheckDelegate
}{result1}
}
func (fake *FakeDelegateFactory) GetDelegate(arg1 db.Build, arg2 atc.PlanID) exec.GetDelegate {
fake.getDelegateMutex.Lock()
ret, specificReturn := fake.getDelegateReturnsOnCall[len(fake.getDelegateArgsForCall)]
@ -312,6 +385,8 @@ func (fake *FakeDelegateFactory) Invocations() map[string][][]interface{} {
defer fake.invocationsMutex.RUnlock()
fake.buildStepDelegateMutex.RLock()
defer fake.buildStepDelegateMutex.RUnlock()
fake.checkDelegateMutex.RLock()
defer fake.checkDelegateMutex.RUnlock()
fake.getDelegateMutex.RLock()
defer fake.getDelegateMutex.RUnlock()
fake.putDelegateMutex.RLock()

View File

@ -6,7 +6,6 @@ import (
"github.com/concourse/concourse/atc"
"github.com/concourse/concourse/atc/db"
"github.com/concourse/concourse/atc/db/lock"
"github.com/concourse/concourse/atc/engine/builder"
"github.com/concourse/concourse/atc/exec"
)
@ -38,6 +37,20 @@ type FakeStepFactory struct {
artifactOutputStepReturnsOnCall map[int]struct {
result1 exec.Step
}
CheckStepStub func(atc.Plan, exec.StepMetadata, db.ContainerMetadata, exec.CheckDelegate) exec.Step
checkStepMutex sync.RWMutex
checkStepArgsForCall []struct {
arg1 atc.Plan
arg2 exec.StepMetadata
arg3 db.ContainerMetadata
arg4 exec.CheckDelegate
}
checkStepReturns struct {
result1 exec.Step
}
checkStepReturnsOnCall map[int]struct {
result1 exec.Step
}
GetStepStub func(atc.Plan, exec.StepMetadata, db.ContainerMetadata, exec.GetDelegate) exec.Step
getStepMutex sync.RWMutex
getStepArgsForCall []struct {
@ -66,14 +79,13 @@ type FakeStepFactory struct {
putStepReturnsOnCall map[int]struct {
result1 exec.Step
}
TaskStepStub func(atc.Plan, exec.StepMetadata, db.ContainerMetadata, exec.TaskDelegate, lock.LockFactory) exec.Step
TaskStepStub func(atc.Plan, exec.StepMetadata, db.ContainerMetadata, exec.TaskDelegate) exec.Step
taskStepMutex sync.RWMutex
taskStepArgsForCall []struct {
arg1 atc.Plan
arg2 exec.StepMetadata
arg3 db.ContainerMetadata
arg4 exec.TaskDelegate
arg5 lock.LockFactory
}
taskStepReturns struct {
result1 exec.Step
@ -209,6 +221,69 @@ func (fake *FakeStepFactory) ArtifactOutputStepReturnsOnCall(i int, result1 exec
}{result1}
}
func (fake *FakeStepFactory) CheckStep(arg1 atc.Plan, arg2 exec.StepMetadata, arg3 db.ContainerMetadata, arg4 exec.CheckDelegate) exec.Step {
fake.checkStepMutex.Lock()
ret, specificReturn := fake.checkStepReturnsOnCall[len(fake.checkStepArgsForCall)]
fake.checkStepArgsForCall = append(fake.checkStepArgsForCall, struct {
arg1 atc.Plan
arg2 exec.StepMetadata
arg3 db.ContainerMetadata
arg4 exec.CheckDelegate
}{arg1, arg2, arg3, arg4})
fake.recordInvocation("CheckStep", []interface{}{arg1, arg2, arg3, arg4})
fake.checkStepMutex.Unlock()
if fake.CheckStepStub != nil {
return fake.CheckStepStub(arg1, arg2, arg3, arg4)
}
if specificReturn {
return ret.result1
}
fakeReturns := fake.checkStepReturns
return fakeReturns.result1
}
func (fake *FakeStepFactory) CheckStepCallCount() int {
fake.checkStepMutex.RLock()
defer fake.checkStepMutex.RUnlock()
return len(fake.checkStepArgsForCall)
}
func (fake *FakeStepFactory) CheckStepCalls(stub func(atc.Plan, exec.StepMetadata, db.ContainerMetadata, exec.CheckDelegate) exec.Step) {
fake.checkStepMutex.Lock()
defer fake.checkStepMutex.Unlock()
fake.CheckStepStub = stub
}
func (fake *FakeStepFactory) CheckStepArgsForCall(i int) (atc.Plan, exec.StepMetadata, db.ContainerMetadata, exec.CheckDelegate) {
fake.checkStepMutex.RLock()
defer fake.checkStepMutex.RUnlock()
argsForCall := fake.checkStepArgsForCall[i]
return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3, argsForCall.arg4
}
func (fake *FakeStepFactory) CheckStepReturns(result1 exec.Step) {
fake.checkStepMutex.Lock()
defer fake.checkStepMutex.Unlock()
fake.CheckStepStub = nil
fake.checkStepReturns = struct {
result1 exec.Step
}{result1}
}
func (fake *FakeStepFactory) CheckStepReturnsOnCall(i int, result1 exec.Step) {
fake.checkStepMutex.Lock()
defer fake.checkStepMutex.Unlock()
fake.CheckStepStub = nil
if fake.checkStepReturnsOnCall == nil {
fake.checkStepReturnsOnCall = make(map[int]struct {
result1 exec.Step
})
}
fake.checkStepReturnsOnCall[i] = struct {
result1 exec.Step
}{result1}
}
func (fake *FakeStepFactory) GetStep(arg1 atc.Plan, arg2 exec.StepMetadata, arg3 db.ContainerMetadata, arg4 exec.GetDelegate) exec.Step {
fake.getStepMutex.Lock()
ret, specificReturn := fake.getStepReturnsOnCall[len(fake.getStepArgsForCall)]
@ -335,7 +410,7 @@ func (fake *FakeStepFactory) PutStepReturnsOnCall(i int, result1 exec.Step) {
}{result1}
}
func (fake *FakeStepFactory) TaskStep(arg1 atc.Plan, arg2 exec.StepMetadata, arg3 db.ContainerMetadata, arg4 exec.TaskDelegate, arg5 lock.LockFactory) exec.Step {
func (fake *FakeStepFactory) TaskStep(arg1 atc.Plan, arg2 exec.StepMetadata, arg3 db.ContainerMetadata, arg4 exec.TaskDelegate) exec.Step {
fake.taskStepMutex.Lock()
ret, specificReturn := fake.taskStepReturnsOnCall[len(fake.taskStepArgsForCall)]
fake.taskStepArgsForCall = append(fake.taskStepArgsForCall, struct {
@ -343,12 +418,11 @@ func (fake *FakeStepFactory) TaskStep(arg1 atc.Plan, arg2 exec.StepMetadata, arg
arg2 exec.StepMetadata
arg3 db.ContainerMetadata
arg4 exec.TaskDelegate
arg5 lock.LockFactory
}{arg1, arg2, arg3, arg4, arg5})
fake.recordInvocation("TaskStep", []interface{}{arg1, arg2, arg3, arg4, arg5})
}{arg1, arg2, arg3, arg4})
fake.recordInvocation("TaskStep", []interface{}{arg1, arg2, arg3, arg4})
fake.taskStepMutex.Unlock()
if fake.TaskStepStub != nil {
return fake.TaskStepStub(arg1, arg2, arg3, arg4, arg5)
return fake.TaskStepStub(arg1, arg2, arg3, arg4)
}
if specificReturn {
return ret.result1
@ -363,17 +437,17 @@ func (fake *FakeStepFactory) TaskStepCallCount() int {
return len(fake.taskStepArgsForCall)
}
func (fake *FakeStepFactory) TaskStepCalls(stub func(atc.Plan, exec.StepMetadata, db.ContainerMetadata, exec.TaskDelegate, lock.LockFactory) exec.Step) {
func (fake *FakeStepFactory) TaskStepCalls(stub func(atc.Plan, exec.StepMetadata, db.ContainerMetadata, exec.TaskDelegate) exec.Step) {
fake.taskStepMutex.Lock()
defer fake.taskStepMutex.Unlock()
fake.TaskStepStub = stub
}
func (fake *FakeStepFactory) TaskStepArgsForCall(i int) (atc.Plan, exec.StepMetadata, db.ContainerMetadata, exec.TaskDelegate, lock.LockFactory) {
func (fake *FakeStepFactory) TaskStepArgsForCall(i int) (atc.Plan, exec.StepMetadata, db.ContainerMetadata, exec.TaskDelegate) {
fake.taskStepMutex.RLock()
defer fake.taskStepMutex.RUnlock()
argsForCall := fake.taskStepArgsForCall[i]
return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3, argsForCall.arg4, argsForCall.arg5
return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3, argsForCall.arg4
}
func (fake *FakeStepFactory) TaskStepReturns(result1 exec.Step) {
@ -406,6 +480,8 @@ func (fake *FakeStepFactory) Invocations() map[string][][]interface{} {
defer fake.artifactInputStepMutex.RUnlock()
fake.artifactOutputStepMutex.RLock()
defer fake.artifactOutputStepMutex.RUnlock()
fake.checkStepMutex.RLock()
defer fake.checkStepMutex.RUnlock()
fake.getStepMutex.RLock()
defer fake.getStepMutex.RUnlock()
fake.putStepMutex.RLock()

View File

@ -2,6 +2,7 @@ package builder
import (
"io"
"io/ioutil"
"time"
"unicode/utf8"
@ -31,6 +32,10 @@ func (delegate *delegateFactory) TaskDelegate(build db.Build, planID atc.PlanID)
return NewTaskDelegate(build, planID, clock.NewClock())
}
func (delegate *delegateFactory) CheckDelegate(check db.Check, planID atc.PlanID) exec.CheckDelegate {
return NewCheckDelegate(check, planID, clock.NewClock())
}
func (delegate *delegateFactory) BuildStepDelegate(build db.Build, planID atc.PlanID) exec.BuildStepDelegate {
return NewBuildStepDelegate(build, planID, clock.NewClock())
}
@ -274,6 +279,29 @@ func (d *taskDelegate) Finished(logger lager.Logger, exitStatus exec.ExitStatus)
logger.Info("finished", lager.Data{"exit-status": exitStatus})
}
func NewCheckDelegate(check db.Check, planID atc.PlanID, clock clock.Clock) exec.CheckDelegate {
return &checkDelegate{
eventOrigin: event.Origin{ID: event.OriginID(planID)},
check: check,
clock: clock,
}
}
type checkDelegate struct {
check db.Check
eventOrigin event.Origin
clock clock.Clock
}
func (d *checkDelegate) SaveVersions(versions []atc.Version) error {
return d.check.SaveVersions(versions)
}
func (*checkDelegate) Stdout() io.Writer { return ioutil.Discard }
func (*checkDelegate) Stderr() io.Writer { return ioutil.Discard }
func (*checkDelegate) ImageVersionDetermined(db.UsedResourceCache) error { return nil }
func (*checkDelegate) Errored(lager.Logger, string) { return }
func NewBuildStepDelegate(
build db.Build,
planID atc.PlanID,

View File

@ -259,6 +259,33 @@ var _ = Describe("DelegateFactory", func() {
})
})
Describe("CheckDelegate", func() {
var (
delegate exec.CheckDelegate
fakeCheck *dbfakes.FakeCheck
versions []atc.Version
)
BeforeEach(func() {
fakeCheck = new(dbfakes.FakeCheck)
delegate = builder.NewCheckDelegate(fakeCheck, "some-plan-id", fakeClock)
versions = []atc.Version{{"some": "version"}}
})
Describe("SaveVersions", func() {
JustBeforeEach(func() {
Expect(delegate.SaveVersions(versions)).To(Succeed())
})
It("saves an event", func() {
Expect(fakeCheck.SaveVersionsCallCount()).To(Equal(1))
actualVersions := fakeCheck.SaveVersionsArgsForCall(0)
Expect(actualVersions).To(Equal(versions))
})
})
})
Describe("BuildStepDelegate", func() {
var (
delegate exec.BuildStepDelegate

View File

@ -25,6 +25,7 @@ type stepFactory struct {
defaultLimits atc.ContainerLimits
strategy worker.ContainerPlacementStrategy
resourceFactory resource.ResourceFactory
lockFactory lock.LockFactory
}
func NewStepFactory(
@ -37,6 +38,7 @@ func NewStepFactory(
defaultLimits atc.ContainerLimits,
strategy worker.ContainerPlacementStrategy,
resourceFactory resource.ResourceFactory,
lockFactory lock.LockFactory,
) *stepFactory {
return &stepFactory{
pool: pool,
@ -48,6 +50,7 @@ func NewStepFactory(
defaultLimits: defaultLimits,
strategy: strategy,
resourceFactory: resourceFactory,
lockFactory: lockFactory,
}
}
@ -99,12 +102,34 @@ func (factory *stepFactory) PutStep(
return exec.LogError(putStep, delegate)
}
func (factory *stepFactory) CheckStep(
plan atc.Plan,
stepMetadata exec.StepMetadata,
containerMetadata db.ContainerMetadata,
delegate exec.CheckDelegate,
) exec.Step {
containerMetadata.WorkingDirectory = resource.ResourcesDir("check")
checkStep := exec.NewCheckStep(
plan.ID,
*plan.Check,
stepMetadata,
containerMetadata,
factory.secretManager,
factory.resourceFactory,
worker.NewRandomPlacementStrategy(),
factory.pool,
delegate,
)
return checkStep
}
func (factory *stepFactory) TaskStep(
plan atc.Plan,
stepMetadata exec.StepMetadata,
containerMetadata db.ContainerMetadata,
delegate exec.TaskDelegate,
lockFactory lock.LockFactory,
) exec.Step {
sum := sha1.Sum([]byte(plan.Task.Name))
containerMetadata.WorkingDirectory = filepath.Join("/tmp", "build", fmt.Sprintf("%x", sum[:4]))
@ -119,7 +144,7 @@ func (factory *stepFactory) TaskStep(
factory.strategy,
factory.client,
delegate,
lockFactory,
factory.lockFactory,
)
return exec.LogError(taskStep, delegate)

View File

@ -2,6 +2,7 @@ package engine
import (
"context"
"fmt"
"sync"
"time"
@ -17,6 +18,7 @@ import (
type Engine interface {
NewBuild(db.Build) Runnable
NewCheck(db.Check) Runnable
ReleaseAll(lager.Logger)
}
@ -30,6 +32,7 @@ type Runnable interface {
type StepBuilder interface {
BuildStep(db.Build) (exec.Step, error)
CheckStep(db.Check) (exec.Step, error)
}
func NewEngine(builder StepBuilder) Engine {
@ -77,6 +80,21 @@ func (engine *engine) NewBuild(build db.Build) Runnable {
)
}
func (engine *engine) NewCheck(check db.Check) Runnable {
ctx, cancel := context.WithCancel(context.Background())
return NewCheck(
ctx,
cancel,
check,
engine.builder,
engine.release,
engine.trackedStates,
engine.waitGroup,
)
}
func NewBuild(
ctx context.Context,
cancel func(),
@ -259,11 +277,119 @@ func (b *engineBuild) trackFinished(logger lager.Logger) {
}
}
func (build *engineBuild) runState() exec.RunState {
existingState, _ := build.trackedStates.LoadOrStore(build.build.ID(), exec.NewRunState())
func (b *engineBuild) runState() exec.RunState {
id := fmt.Sprintf("build:%v", b.build.ID())
existingState, _ := b.trackedStates.LoadOrStore(id, exec.NewRunState())
return existingState.(exec.RunState)
}
func (build *engineBuild) clearRunState() {
build.trackedStates.Delete(build.build.ID())
func (b *engineBuild) clearRunState() {
id := fmt.Sprintf("build:%v", b.build.ID())
b.trackedStates.Delete(id)
}
func NewCheck(
ctx context.Context,
cancel func(),
check db.Check,
builder StepBuilder,
release chan bool,
trackedStates *sync.Map,
waitGroup *sync.WaitGroup,
) Runnable {
return &engineCheck{
ctx: ctx,
cancel: cancel,
check: check,
builder: builder,
release: release,
trackedStates: trackedStates,
waitGroup: waitGroup,
}
}
type engineCheck struct {
ctx context.Context
cancel func()
check db.Check
builder StepBuilder
release chan bool
trackedStates *sync.Map
waitGroup *sync.WaitGroup
}
func (c *engineCheck) Run(logger lager.Logger) {
c.waitGroup.Add(1)
defer c.waitGroup.Done()
logger = logger.WithData(lager.Data{
"check": c.check.ID(),
})
lock, acquired, err := c.check.AcquireTrackingLock(logger)
if err != nil {
logger.Error("failed-to-get-lock", err)
return
}
if !acquired {
logger.Debug("check-already-tracked")
return
}
defer lock.Release()
err = c.check.Start()
if err != nil {
logger.Error("failed-to-start-check", err)
return
}
step, err := c.builder.CheckStep(c.check)
if err != nil {
logger.Error("failed-to-create-check-step", err)
return
}
logger.Info("running")
state := c.runState()
defer c.clearRunState()
done := make(chan error)
go func() {
ctx := lagerctx.NewContext(c.ctx, logger)
done <- step.Run(ctx, state)
}()
select {
case <-c.release:
logger.Info("releasing")
case err = <-done:
if err != nil {
logger.Info("errored", lager.Data{"error": err.Error()})
c.check.FinishWithError(err)
} else {
logger.Info("succeeded")
if err = c.check.Finish(); err != nil {
logger.Error("failed-to-finish-check", err)
}
}
}
}
func (c *engineCheck) runState() exec.RunState {
id := fmt.Sprintf("check:%v", c.check.ID())
existingState, _ := c.trackedStates.LoadOrStore(id, exec.NewRunState())
return existingState.(exec.RunState)
}
func (c *engineCheck) clearRunState() {
id := fmt.Sprintf("check:%v", c.check.ID())
c.trackedStates.Delete(id)
}

View File

@ -23,6 +23,7 @@ import (
var _ = Describe("Engine", func() {
var (
fakeBuild *dbfakes.FakeBuild
fakeCheck *dbfakes.FakeCheck
fakeStepBuilder *enginefakes.FakeStepBuilder
)
@ -30,6 +31,9 @@ var _ = Describe("Engine", func() {
fakeBuild = new(dbfakes.FakeBuild)
fakeBuild.IDReturns(128)
fakeCheck = new(dbfakes.FakeCheck)
fakeCheck.IDReturns(128)
fakeStepBuilder = new(enginefakes.FakeStepBuilder)
})
@ -47,15 +51,30 @@ var _ = Describe("Engine", func() {
build = engine.NewBuild(fakeBuild)
})
// It("succeeds", func() {
// Expect(err).NotTo(HaveOccurred())
// })
It("returns a build", func() {
Expect(build).NotTo(BeNil())
})
})
Describe("NewCheck", func() {
var (
check Runnable
engine Engine
)
BeforeEach(func() {
engine = NewEngine(fakeStepBuilder)
})
JustBeforeEach(func() {
check = engine.NewCheck(fakeCheck)
})
It("returns a build", func() {
Expect(check).NotTo(BeNil())
})
})
Describe("Build", func() {
var (
build Runnable
@ -325,4 +344,164 @@ var _ = Describe("Engine", func() {
})
})
})
Describe("Check", func() {
var (
check Runnable
release chan bool
cancel chan bool
waitGroup *sync.WaitGroup
)
BeforeEach(func() {
ctx := context.Background()
cancel = make(chan bool)
release = make(chan bool)
trackedStates := new(sync.Map)
waitGroup = new(sync.WaitGroup)
check = NewCheck(
ctx,
func() { cancel <- true },
fakeCheck,
fakeStepBuilder,
release,
trackedStates,
waitGroup,
)
})
Describe("Run", func() {
var logger lager.Logger
BeforeEach(func() {
logger = lagertest.NewTestLogger("test")
})
JustBeforeEach(func() {
check.Run(logger)
})
Context("when acquiring the lock succeeds", func() {
var fakeLock *lockfakes.FakeLock
BeforeEach(func() {
fakeLock = new(lockfakes.FakeLock)
fakeCheck.AcquireTrackingLockReturns(fakeLock, true, nil)
})
Context("when the check is started", func() {
BeforeEach(func() {
fakeCheck.StartReturns(nil)
})
Context("when converting the plan to a step succeeds", func() {
var fakeStep *execfakes.FakeStep
BeforeEach(func() {
fakeStep = new(execfakes.FakeStep)
fakeStepBuilder.CheckStepReturns(fakeStep, nil)
})
It("releases the lock", func() {
waitGroup.Wait()
Expect(fakeLock.ReleaseCallCount()).To(Equal(1))
})
Context("when the check is released", func() {
BeforeEach(func() {
readyToRelease := make(chan bool)
go func() {
<-readyToRelease
release <- true
}()
fakeStep.RunStub = func(context.Context, exec.RunState) error {
close(readyToRelease)
<-time.After(time.Hour)
return nil
}
})
It("does not finish the check", func() {
waitGroup.Wait()
Expect(fakeCheck.FinishCallCount()).To(Equal(0))
})
})
Context("when the check finishes without error", func() {
BeforeEach(func() {
fakeStep.RunReturns(nil)
})
It("finishes the check", func() {
waitGroup.Wait()
Expect(fakeCheck.FinishCallCount()).To(Equal(1))
})
})
Context("when the check finishes with error", func() {
BeforeEach(func() {
fakeStep.RunReturns(errors.New("nope"))
})
It("finishes the check", func() {
waitGroup.Wait()
Expect(fakeCheck.FinishWithErrorCallCount()).To(Equal(1))
})
})
Context("when the check finishes with cancelled error", func() {
BeforeEach(func() {
fakeStep.RunReturns(context.Canceled)
})
It("finishes the check", func() {
waitGroup.Wait()
Expect(fakeCheck.FinishWithErrorCallCount()).To(Equal(1))
})
})
})
Context("when converting the plan to a step fails", func() {
BeforeEach(func() {
fakeStepBuilder.CheckStepReturns(nil, errors.New("nope"))
})
It("releases the lock", func() {
Expect(fakeLock.ReleaseCallCount()).To(Equal(1))
})
})
})
Context("when the check can't be started", func() {
BeforeEach(func() {
fakeCheck.StartReturns(errors.New("nope"))
})
It("does not create the check step", func() {
Expect(fakeStepBuilder.CheckStepCallCount()).To(BeZero())
})
It("releases the lock", func() {
Expect(fakeLock.ReleaseCallCount()).To(Equal(1))
})
})
})
})
Context("when acquiring the lock fails", func() {
BeforeEach(func() {
fakeCheck.AcquireTrackingLockReturns(nil, false, errors.New("no lock for you"))
})
It("does not create the check step", func() {
Expect(fakeStepBuilder.CheckStepCallCount()).To(BeZero())
})
})
})
})

View File

@ -21,6 +21,17 @@ type FakeEngine struct {
newBuildReturnsOnCall map[int]struct {
result1 engine.Runnable
}
NewCheckStub func(db.Check) engine.Runnable
newCheckMutex sync.RWMutex
newCheckArgsForCall []struct {
arg1 db.Check
}
newCheckReturns struct {
result1 engine.Runnable
}
newCheckReturnsOnCall map[int]struct {
result1 engine.Runnable
}
ReleaseAllStub func(lager.Logger)
releaseAllMutex sync.RWMutex
releaseAllArgsForCall []struct {
@ -90,6 +101,66 @@ func (fake *FakeEngine) NewBuildReturnsOnCall(i int, result1 engine.Runnable) {
}{result1}
}
func (fake *FakeEngine) NewCheck(arg1 db.Check) engine.Runnable {
fake.newCheckMutex.Lock()
ret, specificReturn := fake.newCheckReturnsOnCall[len(fake.newCheckArgsForCall)]
fake.newCheckArgsForCall = append(fake.newCheckArgsForCall, struct {
arg1 db.Check
}{arg1})
fake.recordInvocation("NewCheck", []interface{}{arg1})
fake.newCheckMutex.Unlock()
if fake.NewCheckStub != nil {
return fake.NewCheckStub(arg1)
}
if specificReturn {
return ret.result1
}
fakeReturns := fake.newCheckReturns
return fakeReturns.result1
}
func (fake *FakeEngine) NewCheckCallCount() int {
fake.newCheckMutex.RLock()
defer fake.newCheckMutex.RUnlock()
return len(fake.newCheckArgsForCall)
}
func (fake *FakeEngine) NewCheckCalls(stub func(db.Check) engine.Runnable) {
fake.newCheckMutex.Lock()
defer fake.newCheckMutex.Unlock()
fake.NewCheckStub = stub
}
func (fake *FakeEngine) NewCheckArgsForCall(i int) db.Check {
fake.newCheckMutex.RLock()
defer fake.newCheckMutex.RUnlock()
argsForCall := fake.newCheckArgsForCall[i]
return argsForCall.arg1
}
func (fake *FakeEngine) NewCheckReturns(result1 engine.Runnable) {
fake.newCheckMutex.Lock()
defer fake.newCheckMutex.Unlock()
fake.NewCheckStub = nil
fake.newCheckReturns = struct {
result1 engine.Runnable
}{result1}
}
func (fake *FakeEngine) NewCheckReturnsOnCall(i int, result1 engine.Runnable) {
fake.newCheckMutex.Lock()
defer fake.newCheckMutex.Unlock()
fake.NewCheckStub = nil
if fake.newCheckReturnsOnCall == nil {
fake.newCheckReturnsOnCall = make(map[int]struct {
result1 engine.Runnable
})
}
fake.newCheckReturnsOnCall[i] = struct {
result1 engine.Runnable
}{result1}
}
func (fake *FakeEngine) ReleaseAll(arg1 lager.Logger) {
fake.releaseAllMutex.Lock()
fake.releaseAllArgsForCall = append(fake.releaseAllArgsForCall, struct {
@ -126,6 +197,8 @@ func (fake *FakeEngine) Invocations() map[string][][]interface{} {
defer fake.invocationsMutex.RUnlock()
fake.newBuildMutex.RLock()
defer fake.newBuildMutex.RUnlock()
fake.newCheckMutex.RLock()
defer fake.newCheckMutex.RUnlock()
fake.releaseAllMutex.RLock()
defer fake.releaseAllMutex.RUnlock()
copiedInvocations := map[string][][]interface{}{}

View File

@ -23,6 +23,19 @@ type FakeStepBuilder struct {
result1 exec.Step
result2 error
}
CheckStepStub func(db.Check) (exec.Step, error)
checkStepMutex sync.RWMutex
checkStepArgsForCall []struct {
arg1 db.Check
}
checkStepReturns struct {
result1 exec.Step
result2 error
}
checkStepReturnsOnCall map[int]struct {
result1 exec.Step
result2 error
}
invocations map[string][][]interface{}
invocationsMutex sync.RWMutex
}
@ -90,11 +103,76 @@ func (fake *FakeStepBuilder) BuildStepReturnsOnCall(i int, result1 exec.Step, re
}{result1, result2}
}
func (fake *FakeStepBuilder) CheckStep(arg1 db.Check) (exec.Step, error) {
fake.checkStepMutex.Lock()
ret, specificReturn := fake.checkStepReturnsOnCall[len(fake.checkStepArgsForCall)]
fake.checkStepArgsForCall = append(fake.checkStepArgsForCall, struct {
arg1 db.Check
}{arg1})
fake.recordInvocation("CheckStep", []interface{}{arg1})
fake.checkStepMutex.Unlock()
if fake.CheckStepStub != nil {
return fake.CheckStepStub(arg1)
}
if specificReturn {
return ret.result1, ret.result2
}
fakeReturns := fake.checkStepReturns
return fakeReturns.result1, fakeReturns.result2
}
func (fake *FakeStepBuilder) CheckStepCallCount() int {
fake.checkStepMutex.RLock()
defer fake.checkStepMutex.RUnlock()
return len(fake.checkStepArgsForCall)
}
func (fake *FakeStepBuilder) CheckStepCalls(stub func(db.Check) (exec.Step, error)) {
fake.checkStepMutex.Lock()
defer fake.checkStepMutex.Unlock()
fake.CheckStepStub = stub
}
func (fake *FakeStepBuilder) CheckStepArgsForCall(i int) db.Check {
fake.checkStepMutex.RLock()
defer fake.checkStepMutex.RUnlock()
argsForCall := fake.checkStepArgsForCall[i]
return argsForCall.arg1
}
func (fake *FakeStepBuilder) CheckStepReturns(result1 exec.Step, result2 error) {
fake.checkStepMutex.Lock()
defer fake.checkStepMutex.Unlock()
fake.CheckStepStub = nil
fake.checkStepReturns = struct {
result1 exec.Step
result2 error
}{result1, result2}
}
func (fake *FakeStepBuilder) CheckStepReturnsOnCall(i int, result1 exec.Step, result2 error) {
fake.checkStepMutex.Lock()
defer fake.checkStepMutex.Unlock()
fake.CheckStepStub = nil
if fake.checkStepReturnsOnCall == nil {
fake.checkStepReturnsOnCall = make(map[int]struct {
result1 exec.Step
result2 error
})
}
fake.checkStepReturnsOnCall[i] = struct {
result1 exec.Step
result2 error
}{result1, result2}
}
func (fake *FakeStepBuilder) Invocations() map[string][][]interface{} {
fake.invocationsMutex.RLock()
defer fake.invocationsMutex.RUnlock()
fake.buildStepMutex.RLock()
defer fake.buildStepMutex.RUnlock()
fake.checkStepMutex.RLock()
defer fake.checkStepMutex.RUnlock()
copiedInvocations := map[string][][]interface{}{}
for key, value := range fake.invocations {
copiedInvocations[key] = value

165
atc/exec/check_step.go Normal file
View File

@ -0,0 +1,165 @@
package exec
import (
"context"
"fmt"
"strconv"
"time"
"code.cloudfoundry.org/lager"
"code.cloudfoundry.org/lager/lagerctx"
"github.com/concourse/concourse/atc"
"github.com/concourse/concourse/atc/creds"
"github.com/concourse/concourse/atc/db"
"github.com/concourse/concourse/atc/metric"
"github.com/concourse/concourse/atc/resource"
"github.com/concourse/concourse/atc/worker"
)
type CheckStep struct {
planID atc.PlanID
plan atc.CheckPlan
metadata StepMetadata
containerMetadata db.ContainerMetadata
secrets creds.Secrets
resourceFactory resource.ResourceFactory
strategy worker.ContainerPlacementStrategy
pool worker.Pool
delegate CheckDelegate
succeeded bool
}
type CheckDelegate interface {
BuildStepDelegate
SaveVersions([]atc.Version) error
}
func NewCheckStep(
planID atc.PlanID,
plan atc.CheckPlan,
metadata StepMetadata,
containerMetadata db.ContainerMetadata,
secrets creds.Secrets,
resourceFactory resource.ResourceFactory,
strategy worker.ContainerPlacementStrategy,
pool worker.Pool,
delegate CheckDelegate,
) *CheckStep {
return &CheckStep{
planID: planID,
plan: plan,
metadata: metadata,
secrets: secrets,
containerMetadata: containerMetadata,
resourceFactory: resourceFactory,
pool: pool,
strategy: strategy,
delegate: delegate,
}
}
func (step *CheckStep) Run(ctx context.Context, state RunState) error {
logger := lagerctx.FromContext(ctx)
logger = logger.Session("check-step", lager.Data{
"step-name": step.plan.Name,
})
resourceTypes := step.plan.VersionedResourceTypes
containerSpec := worker.ContainerSpec{
ImageSpec: worker.ImageSpec{
ResourceType: step.plan.Type,
},
BindMounts: []worker.BindMountSource{
&worker.CertsVolumeMount{Logger: logger},
},
Tags: step.plan.Tags,
TeamID: step.metadata.TeamID,
Env: step.metadata.Env(),
}
workerSpec := worker.WorkerSpec{
ResourceType: step.plan.Type,
Tags: step.plan.Tags,
ResourceTypes: resourceTypes,
TeamID: step.metadata.TeamID,
}
expires := db.ContainerOwnerExpiries{
Min: 5 * time.Minute,
Max: 1 * time.Hour,
}
owner := db.NewResourceConfigCheckSessionContainerOwner(
step.metadata.ResourceConfigID,
step.metadata.BaseResourceTypeID,
expires,
)
chosenWorker, err := step.pool.FindOrChooseWorkerForContainer(
ctx,
logger,
owner,
containerSpec,
workerSpec,
step.strategy,
)
if err != nil {
logger.Error("failed-to-find-or-choose-worker", err)
return err
}
container, err := chosenWorker.FindOrCreateContainer(
ctx,
logger,
step.delegate,
owner,
step.containerMetadata,
containerSpec,
resourceTypes,
)
if err != nil {
logger.Error("failed-to-find-or-create-container", err)
return err
}
timeout, err := time.ParseDuration(step.plan.Timeout)
if err != nil {
logger.Error("failed-to-parse-timeout", err)
return err
}
deadline, cancel := context.WithTimeout(ctx, timeout)
defer cancel()
checkable := step.resourceFactory.NewResourceForContainer(container)
versions, err := checkable.Check(deadline, step.plan.Source, step.plan.FromVersion)
if err != nil {
if err == context.DeadlineExceeded {
return fmt.Errorf("Timed out after %v while checking for new versions", timeout)
}
return err
}
metric.CheckFinished{
CheckName: step.plan.Name,
ResourceConfigScopeID: strconv.Itoa(step.metadata.ResourceConfigScopeID),
Success: err == nil,
}.Emit(logger)
err = step.delegate.SaveVersions(versions)
if err != nil {
logger.Error("failed-to-save-versions", err)
return err
}
step.succeeded = true
return nil
}
func (step *CheckStep) Succeeded() bool {
return step.succeeded
}

256
atc/exec/check_step_test.go Normal file
View File

@ -0,0 +1,256 @@
package exec_test
import (
"context"
"errors"
"time"
"github.com/concourse/concourse/atc"
"github.com/concourse/concourse/atc/creds/credsfakes"
"github.com/concourse/concourse/atc/db"
"github.com/concourse/concourse/atc/exec"
"github.com/concourse/concourse/atc/exec/artifact"
"github.com/concourse/concourse/atc/exec/execfakes"
"github.com/concourse/concourse/atc/resource/resourcefakes"
"github.com/concourse/concourse/atc/worker"
"github.com/concourse/concourse/atc/worker/workerfakes"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
var _ = Describe("CheckStep", func() {
var (
ctx context.Context
cancel func()
fakeWorker *workerfakes.FakeWorker
fakePool *workerfakes.FakePool
fakeStrategy *workerfakes.FakeContainerPlacementStrategy
fakeResourceFactory *resourcefakes.FakeResourceFactory
fakeSecretManager *credsfakes.FakeSecrets
fakeDelegate *execfakes.FakeCheckDelegate
checkPlan *atc.CheckPlan
interpolatedResourceTypes atc.VersionedResourceTypes
containerMetadata = db.ContainerMetadata{
Type: db.ContainerTypeCheck,
StepName: "some-step",
}
stepMetadata = exec.StepMetadata{
ResourceConfigID: 1,
BaseResourceTypeID: 1,
TeamID: 123,
}
owner = db.NewResourceConfigCheckSessionContainerOwner(stepMetadata.ResourceConfigID, stepMetadata.BaseResourceTypeID, db.ContainerOwnerExpiries{
Min: 5 * time.Minute,
Max: 1 * time.Hour,
})
repo *artifact.Repository
state *execfakes.FakeRunState
checkStep *exec.CheckStep
stepErr error
planID atc.PlanID
)
BeforeEach(func() {
ctx, cancel = context.WithCancel(context.Background())
planID = atc.PlanID("some-plan-id")
fakeStrategy = new(workerfakes.FakeContainerPlacementStrategy)
fakePool = new(workerfakes.FakePool)
fakeWorker = new(workerfakes.FakeWorker)
fakeResourceFactory = new(resourcefakes.FakeResourceFactory)
fakeSecretManager = new(credsfakes.FakeSecrets)
fakeSecretManager.GetReturnsOnCall(0, "super-secret-source", nil, true, nil)
fakeSecretManager.GetReturnsOnCall(1, "source", nil, true, nil)
fakeDelegate = new(execfakes.FakeCheckDelegate)
repo = artifact.NewRepository()
state = new(execfakes.FakeRunState)
state.ArtifactsReturns(repo)
interpolatedResourceTypes = atc.VersionedResourceTypes{
{
ResourceType: atc.ResourceType{
Name: "custom-resource",
Type: "custom-type",
Source: atc.Source{"some-custom": "super-secret-source"},
},
Version: atc.Version{"some-custom": "version"},
},
}
checkPlan = &atc.CheckPlan{
Name: "some-name",
Type: "some-resource-type",
Source: atc.Source{"some": "super-secret-source"},
Tags: []string{"some", "tags"},
Timeout: "10s",
FromVersion: atc.Version{"some-custom": "version"},
VersionedResourceTypes: interpolatedResourceTypes,
}
})
AfterEach(func() {
cancel()
})
JustBeforeEach(func() {
plan := atc.Plan{
ID: atc.PlanID(planID),
Check: checkPlan,
}
checkStep = exec.NewCheckStep(
plan.ID,
*plan.Check,
stepMetadata,
containerMetadata,
fakeSecretManager,
fakeResourceFactory,
fakeStrategy,
fakePool,
fakeDelegate,
)
stepErr = checkStep.Run(ctx, state)
})
Context("when find or choosing worker succeeds", func() {
var (
fakeResource *resourcefakes.FakeResource
versions []atc.Version
)
BeforeEach(func() {
fakeWorker.NameReturns("some-worker")
fakePool.FindOrChooseWorkerForContainerReturns(fakeWorker, nil)
fakeResource = new(resourcefakes.FakeResource)
fakeResourceFactory.NewResourceForContainerReturns(fakeResource)
})
It("finds or chooses a worker", func() {
Expect(fakePool.FindOrChooseWorkerForContainerCallCount()).To(Equal(1))
_, _, actualOwner, actualContainerSpec, actualWorkerSpec, strategy := fakePool.FindOrChooseWorkerForContainerArgsForCall(0)
Expect(actualOwner).To(Equal(owner))
Expect(actualContainerSpec.ImageSpec).To(Equal(worker.ImageSpec{
ResourceType: "some-resource-type",
}))
Expect(actualContainerSpec.Tags).To(Equal([]string{"some", "tags"}))
Expect(actualContainerSpec.TeamID).To(Equal(123))
Expect(actualContainerSpec.Env).To(Equal(stepMetadata.Env()))
Expect(actualWorkerSpec).To(Equal(worker.WorkerSpec{
ResourceType: "some-resource-type",
Tags: atc.Tags{"some", "tags"},
TeamID: stepMetadata.TeamID,
ResourceTypes: interpolatedResourceTypes,
}))
Expect(strategy).To(Equal(fakeStrategy))
})
It("creates a container with the correct type and owner", func() {
_, _, delegate, actualOwner, actualContainerMetadata, actualContainerSpec, actualResourceTypes := fakeWorker.FindOrCreateContainerArgsForCall(0)
Expect(actualOwner).To(Equal(owner))
Expect(actualContainerSpec.ImageSpec).To(Equal(worker.ImageSpec{
ResourceType: "some-resource-type",
}))
Expect(actualContainerMetadata).To(Equal(containerMetadata))
Expect(actualContainerSpec.Tags).To(Equal([]string{"some", "tags"}))
Expect(actualContainerSpec.TeamID).To(Equal(123))
Expect(actualContainerSpec.Env).To(Equal(stepMetadata.Env()))
Expect(actualResourceTypes).To(Equal(interpolatedResourceTypes))
Expect(delegate).To(Equal(fakeDelegate))
})
Context("when the timeout cannot be parsed", func() {
BeforeEach(func() {
checkPlan.Timeout = "bad-value"
})
It("fails to parse the timeout and returns the error", func() {
Expect(stepErr).To(HaveOccurred())
Expect(stepErr).To(MatchError("time: invalid duration bad-value"))
})
})
It("times out after the specified timeout", func() {
now := time.Now()
ctx, _, _ := fakeResource.CheckArgsForCall(0)
deadline, _ := ctx.Deadline()
Expect(deadline).Should(BeTemporally("~", now.Add(10*time.Second), time.Second))
})
It("runs the check resource action", func() {
Expect(fakeResource.CheckCallCount()).To(Equal(1))
})
Context("when resource check succeeds", func() {
BeforeEach(func() {
fakeResource.CheckReturns(versions, nil)
})
It("saves the versions", func() {
Expect(fakeDelegate.SaveVersionsCallCount()).To(Equal(1))
actualVersions := fakeDelegate.SaveVersionsArgsForCall(0)
Expect(actualVersions).To(Equal(versions))
})
})
Context("when performing the check fails", func() {
BeforeEach(func() {
fakeResource.CheckReturns(nil, errors.New("nope"))
})
It("returns error", func() {
Expect(stepErr).To(HaveOccurred())
})
It("is not successful", func() {
Expect(checkStep.Succeeded()).To(BeFalse())
})
})
Context("when find or choosing a worker fails", func() {
disaster := errors.New("nope")
BeforeEach(func() {
fakePool.FindOrChooseWorkerForContainerReturns(nil, disaster)
})
It("returns the failure", func() {
Expect(stepErr).To(Equal(disaster))
})
})
Context("when find or creating a container fails", func() {
disaster := errors.New("nope")
BeforeEach(func() {
fakePool.FindOrChooseWorkerForContainerReturns(fakeWorker, nil)
fakeWorker.FindOrCreateContainerReturns(nil, disaster)
})
It("returns the failure", func() {
Expect(stepErr).To(Equal(disaster))
})
})
})
})

View File

@ -0,0 +1,360 @@
// Code generated by counterfeiter. DO NOT EDIT.
package execfakes
import (
"io"
"sync"
"code.cloudfoundry.org/lager"
"github.com/concourse/concourse/atc"
"github.com/concourse/concourse/atc/db"
"github.com/concourse/concourse/atc/exec"
)
type FakeCheckDelegate struct {
ErroredStub func(lager.Logger, string)
erroredMutex sync.RWMutex
erroredArgsForCall []struct {
arg1 lager.Logger
arg2 string
}
ImageVersionDeterminedStub func(db.UsedResourceCache) error
imageVersionDeterminedMutex sync.RWMutex
imageVersionDeterminedArgsForCall []struct {
arg1 db.UsedResourceCache
}
imageVersionDeterminedReturns struct {
result1 error
}
imageVersionDeterminedReturnsOnCall map[int]struct {
result1 error
}
SaveVersionsStub func([]atc.Version) error
saveVersionsMutex sync.RWMutex
saveVersionsArgsForCall []struct {
arg1 []atc.Version
}
saveVersionsReturns struct {
result1 error
}
saveVersionsReturnsOnCall map[int]struct {
result1 error
}
StderrStub func() io.Writer
stderrMutex sync.RWMutex
stderrArgsForCall []struct {
}
stderrReturns struct {
result1 io.Writer
}
stderrReturnsOnCall map[int]struct {
result1 io.Writer
}
StdoutStub func() io.Writer
stdoutMutex sync.RWMutex
stdoutArgsForCall []struct {
}
stdoutReturns struct {
result1 io.Writer
}
stdoutReturnsOnCall map[int]struct {
result1 io.Writer
}
invocations map[string][][]interface{}
invocationsMutex sync.RWMutex
}
func (fake *FakeCheckDelegate) Errored(arg1 lager.Logger, arg2 string) {
fake.erroredMutex.Lock()
fake.erroredArgsForCall = append(fake.erroredArgsForCall, struct {
arg1 lager.Logger
arg2 string
}{arg1, arg2})
fake.recordInvocation("Errored", []interface{}{arg1, arg2})
fake.erroredMutex.Unlock()
if fake.ErroredStub != nil {
fake.ErroredStub(arg1, arg2)
}
}
func (fake *FakeCheckDelegate) ErroredCallCount() int {
fake.erroredMutex.RLock()
defer fake.erroredMutex.RUnlock()
return len(fake.erroredArgsForCall)
}
func (fake *FakeCheckDelegate) ErroredCalls(stub func(lager.Logger, string)) {
fake.erroredMutex.Lock()
defer fake.erroredMutex.Unlock()
fake.ErroredStub = stub
}
func (fake *FakeCheckDelegate) ErroredArgsForCall(i int) (lager.Logger, string) {
fake.erroredMutex.RLock()
defer fake.erroredMutex.RUnlock()
argsForCall := fake.erroredArgsForCall[i]
return argsForCall.arg1, argsForCall.arg2
}
func (fake *FakeCheckDelegate) ImageVersionDetermined(arg1 db.UsedResourceCache) error {
fake.imageVersionDeterminedMutex.Lock()
ret, specificReturn := fake.imageVersionDeterminedReturnsOnCall[len(fake.imageVersionDeterminedArgsForCall)]
fake.imageVersionDeterminedArgsForCall = append(fake.imageVersionDeterminedArgsForCall, struct {
arg1 db.UsedResourceCache
}{arg1})
fake.recordInvocation("ImageVersionDetermined", []interface{}{arg1})
fake.imageVersionDeterminedMutex.Unlock()
if fake.ImageVersionDeterminedStub != nil {
return fake.ImageVersionDeterminedStub(arg1)
}
if specificReturn {
return ret.result1
}
fakeReturns := fake.imageVersionDeterminedReturns
return fakeReturns.result1
}
func (fake *FakeCheckDelegate) ImageVersionDeterminedCallCount() int {
fake.imageVersionDeterminedMutex.RLock()
defer fake.imageVersionDeterminedMutex.RUnlock()
return len(fake.imageVersionDeterminedArgsForCall)
}
func (fake *FakeCheckDelegate) ImageVersionDeterminedCalls(stub func(db.UsedResourceCache) error) {
fake.imageVersionDeterminedMutex.Lock()
defer fake.imageVersionDeterminedMutex.Unlock()
fake.ImageVersionDeterminedStub = stub
}
func (fake *FakeCheckDelegate) ImageVersionDeterminedArgsForCall(i int) db.UsedResourceCache {
fake.imageVersionDeterminedMutex.RLock()
defer fake.imageVersionDeterminedMutex.RUnlock()
argsForCall := fake.imageVersionDeterminedArgsForCall[i]
return argsForCall.arg1
}
func (fake *FakeCheckDelegate) ImageVersionDeterminedReturns(result1 error) {
fake.imageVersionDeterminedMutex.Lock()
defer fake.imageVersionDeterminedMutex.Unlock()
fake.ImageVersionDeterminedStub = nil
fake.imageVersionDeterminedReturns = struct {
result1 error
}{result1}
}
func (fake *FakeCheckDelegate) ImageVersionDeterminedReturnsOnCall(i int, result1 error) {
fake.imageVersionDeterminedMutex.Lock()
defer fake.imageVersionDeterminedMutex.Unlock()
fake.ImageVersionDeterminedStub = nil
if fake.imageVersionDeterminedReturnsOnCall == nil {
fake.imageVersionDeterminedReturnsOnCall = make(map[int]struct {
result1 error
})
}
fake.imageVersionDeterminedReturnsOnCall[i] = struct {
result1 error
}{result1}
}
func (fake *FakeCheckDelegate) SaveVersions(arg1 []atc.Version) error {
var arg1Copy []atc.Version
if arg1 != nil {
arg1Copy = make([]atc.Version, len(arg1))
copy(arg1Copy, arg1)
}
fake.saveVersionsMutex.Lock()
ret, specificReturn := fake.saveVersionsReturnsOnCall[len(fake.saveVersionsArgsForCall)]
fake.saveVersionsArgsForCall = append(fake.saveVersionsArgsForCall, struct {
arg1 []atc.Version
}{arg1Copy})
fake.recordInvocation("SaveVersions", []interface{}{arg1Copy})
fake.saveVersionsMutex.Unlock()
if fake.SaveVersionsStub != nil {
return fake.SaveVersionsStub(arg1)
}
if specificReturn {
return ret.result1
}
fakeReturns := fake.saveVersionsReturns
return fakeReturns.result1
}
func (fake *FakeCheckDelegate) SaveVersionsCallCount() int {
fake.saveVersionsMutex.RLock()
defer fake.saveVersionsMutex.RUnlock()
return len(fake.saveVersionsArgsForCall)
}
func (fake *FakeCheckDelegate) SaveVersionsCalls(stub func([]atc.Version) error) {
fake.saveVersionsMutex.Lock()
defer fake.saveVersionsMutex.Unlock()
fake.SaveVersionsStub = stub
}
func (fake *FakeCheckDelegate) SaveVersionsArgsForCall(i int) []atc.Version {
fake.saveVersionsMutex.RLock()
defer fake.saveVersionsMutex.RUnlock()
argsForCall := fake.saveVersionsArgsForCall[i]
return argsForCall.arg1
}
func (fake *FakeCheckDelegate) SaveVersionsReturns(result1 error) {
fake.saveVersionsMutex.Lock()
defer fake.saveVersionsMutex.Unlock()
fake.SaveVersionsStub = nil
fake.saveVersionsReturns = struct {
result1 error
}{result1}
}
func (fake *FakeCheckDelegate) SaveVersionsReturnsOnCall(i int, result1 error) {
fake.saveVersionsMutex.Lock()
defer fake.saveVersionsMutex.Unlock()
fake.SaveVersionsStub = nil
if fake.saveVersionsReturnsOnCall == nil {
fake.saveVersionsReturnsOnCall = make(map[int]struct {
result1 error
})
}
fake.saveVersionsReturnsOnCall[i] = struct {
result1 error
}{result1}
}
func (fake *FakeCheckDelegate) Stderr() io.Writer {
fake.stderrMutex.Lock()
ret, specificReturn := fake.stderrReturnsOnCall[len(fake.stderrArgsForCall)]
fake.stderrArgsForCall = append(fake.stderrArgsForCall, struct {
}{})
fake.recordInvocation("Stderr", []interface{}{})
fake.stderrMutex.Unlock()
if fake.StderrStub != nil {
return fake.StderrStub()
}
if specificReturn {
return ret.result1
}
fakeReturns := fake.stderrReturns
return fakeReturns.result1
}
func (fake *FakeCheckDelegate) StderrCallCount() int {
fake.stderrMutex.RLock()
defer fake.stderrMutex.RUnlock()
return len(fake.stderrArgsForCall)
}
func (fake *FakeCheckDelegate) StderrCalls(stub func() io.Writer) {
fake.stderrMutex.Lock()
defer fake.stderrMutex.Unlock()
fake.StderrStub = stub
}
func (fake *FakeCheckDelegate) StderrReturns(result1 io.Writer) {
fake.stderrMutex.Lock()
defer fake.stderrMutex.Unlock()
fake.StderrStub = nil
fake.stderrReturns = struct {
result1 io.Writer
}{result1}
}
func (fake *FakeCheckDelegate) StderrReturnsOnCall(i int, result1 io.Writer) {
fake.stderrMutex.Lock()
defer fake.stderrMutex.Unlock()
fake.StderrStub = nil
if fake.stderrReturnsOnCall == nil {
fake.stderrReturnsOnCall = make(map[int]struct {
result1 io.Writer
})
}
fake.stderrReturnsOnCall[i] = struct {
result1 io.Writer
}{result1}
}
func (fake *FakeCheckDelegate) Stdout() io.Writer {
fake.stdoutMutex.Lock()
ret, specificReturn := fake.stdoutReturnsOnCall[len(fake.stdoutArgsForCall)]
fake.stdoutArgsForCall = append(fake.stdoutArgsForCall, struct {
}{})
fake.recordInvocation("Stdout", []interface{}{})
fake.stdoutMutex.Unlock()
if fake.StdoutStub != nil {
return fake.StdoutStub()
}
if specificReturn {
return ret.result1
}
fakeReturns := fake.stdoutReturns
return fakeReturns.result1
}
func (fake *FakeCheckDelegate) StdoutCallCount() int {
fake.stdoutMutex.RLock()
defer fake.stdoutMutex.RUnlock()
return len(fake.stdoutArgsForCall)
}
func (fake *FakeCheckDelegate) StdoutCalls(stub func() io.Writer) {
fake.stdoutMutex.Lock()
defer fake.stdoutMutex.Unlock()
fake.StdoutStub = stub
}
func (fake *FakeCheckDelegate) StdoutReturns(result1 io.Writer) {
fake.stdoutMutex.Lock()
defer fake.stdoutMutex.Unlock()
fake.StdoutStub = nil
fake.stdoutReturns = struct {
result1 io.Writer
}{result1}
}
func (fake *FakeCheckDelegate) StdoutReturnsOnCall(i int, result1 io.Writer) {
fake.stdoutMutex.Lock()
defer fake.stdoutMutex.Unlock()
fake.StdoutStub = nil
if fake.stdoutReturnsOnCall == nil {
fake.stdoutReturnsOnCall = make(map[int]struct {
result1 io.Writer
})
}
fake.stdoutReturnsOnCall[i] = struct {
result1 io.Writer
}{result1}
}
func (fake *FakeCheckDelegate) Invocations() map[string][][]interface{} {
fake.invocationsMutex.RLock()
defer fake.invocationsMutex.RUnlock()
fake.erroredMutex.RLock()
defer fake.erroredMutex.RUnlock()
fake.imageVersionDeterminedMutex.RLock()
defer fake.imageVersionDeterminedMutex.RUnlock()
fake.saveVersionsMutex.RLock()
defer fake.saveVersionsMutex.RUnlock()
fake.stderrMutex.RLock()
defer fake.stderrMutex.RUnlock()
fake.stdoutMutex.RLock()
defer fake.stdoutMutex.RUnlock()
copiedInvocations := map[string][][]interface{}{}
for key, value := range fake.invocations {
copiedInvocations[key] = value
}
return copiedInvocations
}
func (fake *FakeCheckDelegate) recordInvocation(key string, args []interface{}) {
fake.invocationsMutex.Lock()
defer fake.invocationsMutex.Unlock()
if fake.invocations == nil {
fake.invocations = map[string][][]interface{}{}
}
if fake.invocations[key] == nil {
fake.invocations[key] = [][]interface{}{}
}
fake.invocations[key] = append(fake.invocations[key], args)
}
var _ exec.CheckDelegate = new(FakeCheckDelegate)

View File

@ -5,19 +5,26 @@ import (
)
type StepMetadata struct {
BuildID int
BuildName string
TeamID int
TeamName string
JobID int
JobName string
PipelineID int
PipelineName string
ExternalURL string
BuildID int
BuildName string
TeamID int
TeamName string
JobID int
JobName string
PipelineID int
PipelineName string
ResourceConfigScopeID int
ResourceConfigID int
BaseResourceTypeID int
ExternalURL string
}
func (metadata StepMetadata) Env() []string {
env := []string{fmt.Sprintf("BUILD_ID=%d", metadata.BuildID)}
env := []string{}
if metadata.BuildID != 0 {
env = append(env, fmt.Sprintf("BUILD_ID=%d", metadata.BuildID))
}
if metadata.BuildName != "" {
env = append(env, "BUILD_NAME="+metadata.BuildName)

View File

@ -0,0 +1,30 @@
package gc
import (
"context"
"time"
"code.cloudfoundry.org/lager/lagerctx"
"github.com/concourse/concourse/atc/db"
)
type checkCollector struct {
checkLifecycle db.CheckLifecycle
recyclePeriod time.Duration
}
func NewCheckCollector(checkLifecycle db.CheckLifecycle, recyclePeriod time.Duration) *checkCollector {
return &checkCollector{
checkLifecycle: checkLifecycle,
recyclePeriod: recyclePeriod,
}
}
func (c *checkCollector) Run(ctx context.Context) error {
logger := lagerctx.FromContext(ctx).Session("check-collector")
logger.Debug("start")
defer logger.Debug("done")
return c.checkLifecycle.RemoveExpiredChecks(c.recyclePeriod)
}

View File

@ -0,0 +1,33 @@
package gc_test
import (
"context"
"time"
"github.com/concourse/concourse/atc/db/dbfakes"
"github.com/concourse/concourse/atc/gc"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
var _ = Describe("CheckCollector", func() {
var collector gc.Collector
var fakeCheckLifecycle *dbfakes.FakeCheckLifecycle
BeforeEach(func() {
fakeCheckLifecycle = new(dbfakes.FakeCheckLifecycle)
collector = gc.NewCheckCollector(fakeCheckLifecycle, time.Hour*24)
})
Describe("Run", func() {
It("tells the check lifecycle to remove expired checks", func() {
err := collector.Run(context.TODO())
Expect(err).NotTo(HaveOccurred())
Expect(fakeCheckLifecycle.RemoveExpiredChecksCallCount()).To(Equal(1))
recyclePeriod := fakeCheckLifecycle.RemoveExpiredChecksArgsForCall(0)
Expect(recyclePeriod).To(Equal(time.Hour * 24))
})
})
})

View File

@ -22,6 +22,7 @@ type aggregateCollector struct {
containerCollector Collector
resourceConfigCheckSessionCollector Collector
artifactCollector Collector
checkCollector Collector
}
func NewCollector(
@ -31,6 +32,7 @@ func NewCollector(
resourceConfigs Collector,
resourceCaches Collector,
artifactCollector Collector,
checkCollector Collector,
volumes Collector,
containers Collector,
resourceConfigCheckSessionCollector Collector,
@ -42,6 +44,7 @@ func NewCollector(
resourceConfigCollector: resourceConfigs,
resourceCacheCollector: resourceCaches,
artifactCollector: artifactCollector,
checkCollector: checkCollector,
volumeCollector: volumes,
containerCollector: containers,
resourceConfigCheckSessionCollector: resourceConfigCheckSessionCollector,
@ -88,6 +91,11 @@ func (c *aggregateCollector) Run(ctx context.Context) error {
logger.Error("artifact-collector", err)
}
err = c.checkCollector.Run(ctx)
if err != nil {
logger.Error("check-collector", err)
}
err = c.containerCollector.Run(ctx)
if err != nil {
logger.Error("container-collector", err)

View File

@ -20,6 +20,7 @@ var _ = Describe("Aggregate Collector", func() {
fakeResourceConfigCollector *gcfakes.FakeCollector
fakeResourceCacheCollector *gcfakes.FakeCollector
fakeArtifactCollector *gcfakes.FakeCollector
fakeCheckCollector *gcfakes.FakeCollector
fakeVolumeCollector *gcfakes.FakeCollector
fakeContainerCollector *gcfakes.FakeCollector
fakeResourceConfigCheckSessionCollector *gcfakes.FakeCollector
@ -35,6 +36,7 @@ var _ = Describe("Aggregate Collector", func() {
fakeResourceConfigCollector = new(gcfakes.FakeCollector)
fakeResourceCacheCollector = new(gcfakes.FakeCollector)
fakeArtifactCollector = new(gcfakes.FakeCollector)
fakeCheckCollector = new(gcfakes.FakeCollector)
fakeVolumeCollector = new(gcfakes.FakeCollector)
fakeContainerCollector = new(gcfakes.FakeCollector)
fakeResourceConfigCheckSessionCollector = new(gcfakes.FakeCollector)
@ -46,6 +48,7 @@ var _ = Describe("Aggregate Collector", func() {
fakeResourceConfigCollector,
fakeResourceCacheCollector,
fakeArtifactCollector,
fakeCheckCollector,
fakeVolumeCollector,
fakeContainerCollector,
fakeResourceConfigCheckSessionCollector,
@ -78,6 +81,7 @@ var _ = Describe("Aggregate Collector", func() {
Expect(fakeResourceConfigCollector.RunCallCount()).To(Equal(1))
Expect(fakeResourceCacheCollector.RunCallCount()).To(Equal(1))
Expect(fakeArtifactCollector.RunCallCount()).To(Equal(1))
Expect(fakeCheckCollector.RunCallCount()).To(Equal(1))
Expect(fakeVolumeCollector.RunCallCount()).To(Equal(1))
Expect(fakeContainerCollector.RunCallCount()).To(Equal(1))
Expect(fakeResourceConfigCheckSessionCollector.RunCallCount()).To(Equal(1))
@ -103,6 +107,7 @@ var _ = Describe("Aggregate Collector", func() {
Expect(fakeResourceConfigCollector.RunCallCount()).To(Equal(1))
Expect(fakeResourceCacheCollector.RunCallCount()).To(Equal(1))
Expect(fakeArtifactCollector.RunCallCount()).To(Equal(1))
Expect(fakeCheckCollector.RunCallCount()).To(Equal(1))
Expect(fakeVolumeCollector.RunCallCount()).To(Equal(1))
Expect(fakeContainerCollector.RunCallCount()).To(Equal(1))
Expect(fakeResourceConfigCheckSessionCollector.RunCallCount()).To(Equal(1))
@ -128,6 +133,7 @@ var _ = Describe("Aggregate Collector", func() {
Expect(fakeResourceConfigCollector.RunCallCount()).To(Equal(1))
Expect(fakeResourceCacheCollector.RunCallCount()).To(Equal(1))
Expect(fakeArtifactCollector.RunCallCount()).To(Equal(1))
Expect(fakeCheckCollector.RunCallCount()).To(Equal(1))
Expect(fakeVolumeCollector.RunCallCount()).To(Equal(1))
Expect(fakeContainerCollector.RunCallCount()).To(Equal(1))
Expect(fakeResourceConfigCheckSessionCollector.RunCallCount()).To(Equal(1))
@ -153,6 +159,7 @@ var _ = Describe("Aggregate Collector", func() {
Expect(fakeResourceCacheUseCollector.RunCallCount()).To(Equal(1))
Expect(fakeResourceCacheCollector.RunCallCount()).To(Equal(1))
Expect(fakeArtifactCollector.RunCallCount()).To(Equal(1))
Expect(fakeCheckCollector.RunCallCount()).To(Equal(1))
Expect(fakeVolumeCollector.RunCallCount()).To(Equal(1))
Expect(fakeContainerCollector.RunCallCount()).To(Equal(1))
Expect(fakeResourceConfigCheckSessionCollector.RunCallCount()).To(Equal(1))
@ -178,6 +185,7 @@ var _ = Describe("Aggregate Collector", func() {
Expect(fakeResourceCacheUseCollector.RunCallCount()).To(Equal(1))
Expect(fakeResourceConfigCollector.RunCallCount()).To(Equal(1))
Expect(fakeArtifactCollector.RunCallCount()).To(Equal(1))
Expect(fakeCheckCollector.RunCallCount()).To(Equal(1))
Expect(fakeVolumeCollector.RunCallCount()).To(Equal(1))
Expect(fakeContainerCollector.RunCallCount()).To(Equal(1))
Expect(fakeResourceConfigCheckSessionCollector.RunCallCount()).To(Equal(1))
@ -204,6 +212,7 @@ var _ = Describe("Aggregate Collector", func() {
Expect(fakeResourceConfigCollector.RunCallCount()).To(Equal(1))
Expect(fakeResourceCacheCollector.RunCallCount()).To(Equal(1))
Expect(fakeArtifactCollector.RunCallCount()).To(Equal(1))
Expect(fakeCheckCollector.RunCallCount()).To(Equal(1))
Expect(fakeContainerCollector.RunCallCount()).To(Equal(1))
Expect(fakeResourceConfigCheckSessionCollector.RunCallCount()).To(Equal(1))
})
@ -228,6 +237,7 @@ var _ = Describe("Aggregate Collector", func() {
Expect(fakeResourceCacheUseCollector.RunCallCount()).To(Equal(1))
Expect(fakeResourceConfigCollector.RunCallCount()).To(Equal(1))
Expect(fakeArtifactCollector.RunCallCount()).To(Equal(1))
Expect(fakeCheckCollector.RunCallCount()).To(Equal(1))
Expect(fakeResourceCacheCollector.RunCallCount()).To(Equal(1))
Expect(fakeVolumeCollector.RunCallCount()).To(Equal(1))
Expect(fakeResourceConfigCheckSessionCollector.RunCallCount()).To(Equal(1))
@ -252,10 +262,12 @@ var _ = Describe("Aggregate Collector", func() {
Expect(fakeResourceCacheUseCollector.RunCallCount()).To(Equal(1))
Expect(fakeResourceConfigCollector.RunCallCount()).To(Equal(1))
Expect(fakeArtifactCollector.RunCallCount()).To(Equal(1))
Expect(fakeCheckCollector.RunCallCount()).To(Equal(1))
Expect(fakeResourceCacheCollector.RunCallCount()).To(Equal(1))
Expect(fakeVolumeCollector.RunCallCount()).To(Equal(1))
})
})
Context("when the artifact collector succeeds", func() {
It("attempts to collect", func() {
Expect(fakeArtifactCollector.RunCallCount()).To(Equal(1))
@ -274,6 +286,33 @@ var _ = Describe("Aggregate Collector", func() {
Expect(fakeWorkerCollector.RunCallCount()).To(Equal(1))
Expect(fakeResourceCacheUseCollector.RunCallCount()).To(Equal(1))
Expect(fakeResourceConfigCollector.RunCallCount()).To(Equal(1))
Expect(fakeCheckCollector.RunCallCount()).To(Equal(1))
Expect(fakeResourceCacheCollector.RunCallCount()).To(Equal(1))
Expect(fakeResourceConfigCheckSessionCollector.RunCallCount()).To(Equal(1))
Expect(fakeVolumeCollector.RunCallCount()).To(Equal(1))
})
})
})
Context("when the check collector succeeds", func() {
It("attempts to collect", func() {
Expect(fakeCheckCollector.RunCallCount()).To(Equal(1))
})
Context("when the collector errors", func() {
BeforeEach(func() {
fakeCheckCollector.RunReturns(disaster)
})
It("does not return an error", func() {
Expect(err).NotTo(HaveOccurred())
})
It("runs the rest of collectors", func() {
Expect(fakeWorkerCollector.RunCallCount()).To(Equal(1))
Expect(fakeResourceCacheUseCollector.RunCallCount()).To(Equal(1))
Expect(fakeResourceConfigCollector.RunCallCount()).To(Equal(1))
Expect(fakeArtifactCollector.RunCallCount()).To(Equal(1))
Expect(fakeResourceCacheCollector.RunCallCount()).To(Equal(1))
Expect(fakeResourceConfigCheckSessionCollector.RunCallCount()).To(Equal(1))
Expect(fakeVolumeCollector.RunCallCount()).To(Equal(1))

View File

@ -51,7 +51,8 @@ var _ = Describe("ResourceConfigCheckSessionCollector", func() {
atc.VersionedResourceTypes{})
Expect(err).ToNot(HaveOccurred())
owner = db.NewResourceConfigCheckSessionContainerOwner(resourceConfigScope.ResourceConfig(), ownerExpiries)
resourceConfig := resourceConfigScope.ResourceConfig()
owner = db.NewResourceConfigCheckSessionContainerOwner(resourceConfig.ID(), resourceConfig.OriginBaseResourceType().ID, ownerExpiries)
workerFactory := db.NewWorkerFactory(dbConn)
defaultWorkerPayload := atc.Worker{

View File

@ -69,7 +69,7 @@ var _ = Describe("ResourceConfigCollector", func() {
worker, err := workerFactory.SaveWorker(defaultWorkerPayload, 0)
Expect(err).NotTo(HaveOccurred())
_, err = worker.CreateContainer(db.NewResourceConfigCheckSessionContainerOwner(resourceConfig, ownerExpiries), db.ContainerMetadata{})
_, err = worker.CreateContainer(db.NewResourceConfigCheckSessionContainerOwner(resourceConfig.ID(), resourceConfig.OriginBaseResourceType().ID, ownerExpiries), db.ContainerMetadata{})
Expect(err).NotTo(HaveOccurred())
})
@ -112,7 +112,7 @@ var _ = Describe("ResourceConfigCollector", func() {
worker, err := workerFactory.SaveWorker(defaultWorkerPayload, 0)
Expect(err).NotTo(HaveOccurred())
_, err = worker.CreateContainer(db.NewResourceConfigCheckSessionContainerOwner(resourceConfig, ownerExpiries), db.ContainerMetadata{})
_, err = worker.CreateContainer(db.NewResourceConfigCheckSessionContainerOwner(resourceConfig.ID(), resourceConfig.OriginBaseResourceType().ID, ownerExpiries), db.ContainerMetadata{})
Expect(err).NotTo(HaveOccurred())
tx, err := dbConn.Begin()

52
atc/lidar/checker.go Normal file
View File

@ -0,0 +1,52 @@
package lidar
import (
"context"
"code.cloudfoundry.org/lager"
"github.com/concourse/concourse/atc/db"
"github.com/concourse/concourse/atc/engine"
)
func NewChecker(
logger lager.Logger,
checkFactory db.CheckFactory,
engine engine.Engine,
) *checker {
return &checker{
logger: logger,
checkFactory: checkFactory,
engine: engine,
}
}
type checker struct {
logger lager.Logger
checkFactory db.CheckFactory
engine engine.Engine
}
func (c *checker) Run(ctx context.Context) error {
cLog := c.logger.Session("check")
cLog.Debug("start")
defer cLog.Debug("done")
checks, err := c.checkFactory.StartedChecks()
if err != nil {
c.logger.Error("failed-to-fetch-resource-checks", err)
return err
}
for _, check := range checks {
btLog := cLog.WithData(lager.Data{
"check": check.ID(),
})
engineCheck := c.engine.NewCheck(check)
go engineCheck.Run(btLog)
}
return nil
}

91
atc/lidar/checker_test.go Normal file
View File

@ -0,0 +1,91 @@
package lidar_test
import (
"context"
"errors"
"code.cloudfoundry.org/lager/lagertest"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/concourse/concourse/atc/db"
"github.com/concourse/concourse/atc/db/dbfakes"
"github.com/concourse/concourse/atc/engine"
"github.com/concourse/concourse/atc/engine/enginefakes"
"github.com/concourse/concourse/atc/lidar"
)
type Checker interface {
Run(context.Context) error
}
var _ = Describe("Checker", func() {
var (
err error
fakeCheckFactory *dbfakes.FakeCheckFactory
fakeEngine *enginefakes.FakeEngine
checker Checker
logger *lagertest.TestLogger
)
BeforeEach(func() {
fakeCheckFactory = new(dbfakes.FakeCheckFactory)
fakeEngine = new(enginefakes.FakeEngine)
logger = lagertest.NewTestLogger("test")
checker = lidar.NewChecker(
logger,
fakeCheckFactory,
fakeEngine,
)
})
JustBeforeEach(func() {
err = checker.Run(context.TODO())
})
Describe("Run", func() {
Context("when retrieving checks fails", func() {
BeforeEach(func() {
fakeCheckFactory.StartedChecksReturns(nil, errors.New("nope"))
})
It("errors", func() {
Expect(err).To(HaveOccurred())
})
})
Context("when retrieving checks succeeds", func() {
var engineChecks []*enginefakes.FakeRunnable
BeforeEach(func() {
fakeCheckFactory.StartedChecksReturns([]db.Check{
new(dbfakes.FakeCheck),
new(dbfakes.FakeCheck),
new(dbfakes.FakeCheck),
}, nil)
engineChecks = []*enginefakes.FakeRunnable{}
fakeEngine.NewCheckStub = func(build db.Check) engine.Runnable {
engineCheck := new(enginefakes.FakeRunnable)
engineChecks = append(engineChecks, engineCheck)
return engineCheck
}
})
It("succeeds", func() {
Expect(err).NotTo(HaveOccurred())
})
It("runs all pendingg checks", func() {
Eventually(engineChecks[0].RunCallCount).Should(Equal(1))
Eventually(engineChecks[1].RunCallCount).Should(Equal(1))
Eventually(engineChecks[2].RunCallCount).Should(Equal(1))
})
})
})
})

View File

@ -0,0 +1,88 @@
package lidar
import (
"context"
"os"
"time"
"code.cloudfoundry.org/clock"
"code.cloudfoundry.org/lager"
"github.com/tedsuo/ifrit"
)
//go:generate counterfeiter . Runner
type Runner interface {
Run(context.Context) error
}
//go:generate counterfeiter . Notifications
type Notifications interface {
Listen(string) (chan bool, error)
Unlisten(string, chan bool) error
}
func NewIntervalRunner(
logger lager.Logger,
clock clock.Clock,
runner Runner,
interval time.Duration,
notifications Notifications,
channel string,
) ifrit.Runner {
return &intervalRunner{
logger: logger,
clock: clock,
runner: runner,
interval: interval,
notifications: notifications,
channel: channel,
}
}
type intervalRunner struct {
logger lager.Logger
clock clock.Clock
runner Runner
interval time.Duration
notifications Notifications
channel string
}
func (r *intervalRunner) Run(signals <-chan os.Signal, ready chan<- struct{}) error {
r.logger.Info("start")
defer r.logger.Info("done")
close(ready)
notifier, err := r.notifications.Listen(r.channel)
if err != nil {
return err
}
defer r.notifications.Unlisten(r.channel, notifier)
ticker := r.clock.NewTicker(r.interval)
ctx, cancel := context.WithCancel(context.Background())
if err := r.runner.Run(ctx); err != nil {
r.logger.Error("failed-to-run", err)
}
for {
select {
case <-ticker.C():
if err := r.runner.Run(ctx); err != nil {
r.logger.Error("failed-to-run", err)
}
case <-notifier:
if err := r.runner.Run(ctx); err != nil {
r.logger.Error("failed-to-run", err)
}
case <-signals:
cancel()
return nil
}
}
}

View File

@ -0,0 +1,93 @@
package lidar_test
import (
"context"
"os"
"time"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"code.cloudfoundry.org/clock/fakeclock"
"code.cloudfoundry.org/lager/lagertest"
"github.com/concourse/concourse/atc/lidar"
"github.com/concourse/concourse/atc/lidar/lidarfakes"
"github.com/tedsuo/ifrit"
)
var _ = Describe("IntervalRunner", func() {
var (
intervalRunner ifrit.Runner
process ifrit.Process
logger *lagertest.TestLogger
interval time.Duration
notifier chan bool
fakeRunner *lidarfakes.FakeRunner
fakeNotifications *lidarfakes.FakeNotifications
runAt time.Time
runTimes chan time.Time
fakeClock *fakeclock.FakeClock
)
BeforeEach(func() {
logger = lagertest.NewTestLogger("test")
interval = time.Minute
notifier = make(chan bool)
fakeRunner = new(lidarfakes.FakeRunner)
fakeNotifications = new(lidarfakes.FakeNotifications)
fakeNotifications.ListenReturns(notifier, nil)
runAt = time.Unix(111, 111).UTC()
runTimes = make(chan time.Time, 100)
fakeClock = fakeclock.NewFakeClock(runAt)
fakeRunner.RunStub = func(ctx context.Context) error {
runTimes <- fakeClock.Now()
return nil
}
intervalRunner = lidar.NewIntervalRunner(
logger,
fakeClock,
fakeRunner,
interval,
fakeNotifications,
"some-channel",
)
})
JustBeforeEach(func() {
process = ifrit.Invoke(intervalRunner)
})
AfterEach(func() {
process.Signal(os.Interrupt)
Eventually(process.Wait()).Should(Receive())
})
Context("when created", func() {
It("runs", func() {
Expect(<-runTimes).To(Equal(runAt))
})
})
Context("when the interval elapses", func() {
It("runs again", func() {
Expect(<-runTimes).To(Equal(runAt))
fakeClock.WaitForWatcherAndIncrement(interval)
Expect(<-runTimes).To(Equal(runAt.Add(interval)))
})
})
Context("when it receives a notification", func() {
It("runs again", func() {
Expect(<-runTimes).To(Equal(runAt))
notifier <- true
Expect(<-runTimes).To(Equal(runAt))
})
})
})

53
atc/lidar/lidar.go Normal file
View File

@ -0,0 +1,53 @@
package lidar
import (
"os"
"time"
"code.cloudfoundry.org/clock"
"code.cloudfoundry.org/lager"
"github.com/tedsuo/ifrit"
"github.com/tedsuo/ifrit/grouper"
)
func NewRunner(
logger lager.Logger,
clock clock.Clock,
scanRunner Runner,
scanInterval time.Duration,
checkRunner Runner,
checkInterval time.Duration,
notifications Notifications,
) ifrit.Runner {
return grouper.NewParallel(
os.Interrupt,
[]grouper.Member{
{
Name: "scanner",
Runner: NewIntervalRunner(logger, clock, scanRunner, scanInterval, notifications, "scanner"),
},
{
Name: "checker",
Runner: NewIntervalRunner(logger, clock, checkRunner, checkInterval, notifications, "checker"),
},
},
)
}
func NewCheckerRunner(
logger lager.Logger,
clock clock.Clock,
checkRunner Runner,
checkInterval time.Duration,
notifications Notifications,
) ifrit.Runner {
return grouper.NewParallel(
os.Interrupt,
[]grouper.Member{
{
Name: "checker",
Runner: NewIntervalRunner(logger, clock, checkRunner, checkInterval, notifications, "checker"),
},
},
)
}

View File

@ -0,0 +1,13 @@
package lidar_test
import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"testing"
)
func TestLidar(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Lidar Suite")
}

1
atc/lidar/lidar_test.go Normal file
View File

@ -0,0 +1 @@
package lidar_test

View File

@ -0,0 +1,190 @@
// Code generated by counterfeiter. DO NOT EDIT.
package lidarfakes
import (
"sync"
"github.com/concourse/concourse/atc/lidar"
)
type FakeNotifications struct {
ListenStub func(string) (chan bool, error)
listenMutex sync.RWMutex
listenArgsForCall []struct {
arg1 string
}
listenReturns struct {
result1 chan bool
result2 error
}
listenReturnsOnCall map[int]struct {
result1 chan bool
result2 error
}
UnlistenStub func(string, chan bool) error
unlistenMutex sync.RWMutex
unlistenArgsForCall []struct {
arg1 string
arg2 chan bool
}
unlistenReturns struct {
result1 error
}
unlistenReturnsOnCall map[int]struct {
result1 error
}
invocations map[string][][]interface{}
invocationsMutex sync.RWMutex
}
func (fake *FakeNotifications) Listen(arg1 string) (chan bool, error) {
fake.listenMutex.Lock()
ret, specificReturn := fake.listenReturnsOnCall[len(fake.listenArgsForCall)]
fake.listenArgsForCall = append(fake.listenArgsForCall, struct {
arg1 string
}{arg1})
fake.recordInvocation("Listen", []interface{}{arg1})
fake.listenMutex.Unlock()
if fake.ListenStub != nil {
return fake.ListenStub(arg1)
}
if specificReturn {
return ret.result1, ret.result2
}
fakeReturns := fake.listenReturns
return fakeReturns.result1, fakeReturns.result2
}
func (fake *FakeNotifications) ListenCallCount() int {
fake.listenMutex.RLock()
defer fake.listenMutex.RUnlock()
return len(fake.listenArgsForCall)
}
func (fake *FakeNotifications) ListenCalls(stub func(string) (chan bool, error)) {
fake.listenMutex.Lock()
defer fake.listenMutex.Unlock()
fake.ListenStub = stub
}
func (fake *FakeNotifications) ListenArgsForCall(i int) string {
fake.listenMutex.RLock()
defer fake.listenMutex.RUnlock()
argsForCall := fake.listenArgsForCall[i]
return argsForCall.arg1
}
func (fake *FakeNotifications) ListenReturns(result1 chan bool, result2 error) {
fake.listenMutex.Lock()
defer fake.listenMutex.Unlock()
fake.ListenStub = nil
fake.listenReturns = struct {
result1 chan bool
result2 error
}{result1, result2}
}
func (fake *FakeNotifications) ListenReturnsOnCall(i int, result1 chan bool, result2 error) {
fake.listenMutex.Lock()
defer fake.listenMutex.Unlock()
fake.ListenStub = nil
if fake.listenReturnsOnCall == nil {
fake.listenReturnsOnCall = make(map[int]struct {
result1 chan bool
result2 error
})
}
fake.listenReturnsOnCall[i] = struct {
result1 chan bool
result2 error
}{result1, result2}
}
func (fake *FakeNotifications) Unlisten(arg1 string, arg2 chan bool) error {
fake.unlistenMutex.Lock()
ret, specificReturn := fake.unlistenReturnsOnCall[len(fake.unlistenArgsForCall)]
fake.unlistenArgsForCall = append(fake.unlistenArgsForCall, struct {
arg1 string
arg2 chan bool
}{arg1, arg2})
fake.recordInvocation("Unlisten", []interface{}{arg1, arg2})
fake.unlistenMutex.Unlock()
if fake.UnlistenStub != nil {
return fake.UnlistenStub(arg1, arg2)
}
if specificReturn {
return ret.result1
}
fakeReturns := fake.unlistenReturns
return fakeReturns.result1
}
func (fake *FakeNotifications) UnlistenCallCount() int {
fake.unlistenMutex.RLock()
defer fake.unlistenMutex.RUnlock()
return len(fake.unlistenArgsForCall)
}
func (fake *FakeNotifications) UnlistenCalls(stub func(string, chan bool) error) {
fake.unlistenMutex.Lock()
defer fake.unlistenMutex.Unlock()
fake.UnlistenStub = stub
}
func (fake *FakeNotifications) UnlistenArgsForCall(i int) (string, chan bool) {
fake.unlistenMutex.RLock()
defer fake.unlistenMutex.RUnlock()
argsForCall := fake.unlistenArgsForCall[i]
return argsForCall.arg1, argsForCall.arg2
}
func (fake *FakeNotifications) UnlistenReturns(result1 error) {
fake.unlistenMutex.Lock()
defer fake.unlistenMutex.Unlock()
fake.UnlistenStub = nil
fake.unlistenReturns = struct {
result1 error
}{result1}
}
func (fake *FakeNotifications) UnlistenReturnsOnCall(i int, result1 error) {
fake.unlistenMutex.Lock()
defer fake.unlistenMutex.Unlock()
fake.UnlistenStub = nil
if fake.unlistenReturnsOnCall == nil {
fake.unlistenReturnsOnCall = make(map[int]struct {
result1 error
})
}
fake.unlistenReturnsOnCall[i] = struct {
result1 error
}{result1}
}
func (fake *FakeNotifications) Invocations() map[string][][]interface{} {
fake.invocationsMutex.RLock()
defer fake.invocationsMutex.RUnlock()
fake.listenMutex.RLock()
defer fake.listenMutex.RUnlock()
fake.unlistenMutex.RLock()
defer fake.unlistenMutex.RUnlock()
copiedInvocations := map[string][][]interface{}{}
for key, value := range fake.invocations {
copiedInvocations[key] = value
}
return copiedInvocations
}
func (fake *FakeNotifications) recordInvocation(key string, args []interface{}) {
fake.invocationsMutex.Lock()
defer fake.invocationsMutex.Unlock()
if fake.invocations == nil {
fake.invocations = map[string][][]interface{}{}
}
if fake.invocations[key] == nil {
fake.invocations[key] = [][]interface{}{}
}
fake.invocations[key] = append(fake.invocations[key], args)
}
var _ lidar.Notifications = new(FakeNotifications)

View File

@ -0,0 +1,111 @@
// Code generated by counterfeiter. DO NOT EDIT.
package lidarfakes
import (
"context"
"sync"
"github.com/concourse/concourse/atc/lidar"
)
type FakeRunner struct {
RunStub func(context.Context) error
runMutex sync.RWMutex
runArgsForCall []struct {
arg1 context.Context
}
runReturns struct {
result1 error
}
runReturnsOnCall map[int]struct {
result1 error
}
invocations map[string][][]interface{}
invocationsMutex sync.RWMutex
}
func (fake *FakeRunner) Run(arg1 context.Context) error {
fake.runMutex.Lock()
ret, specificReturn := fake.runReturnsOnCall[len(fake.runArgsForCall)]
fake.runArgsForCall = append(fake.runArgsForCall, struct {
arg1 context.Context
}{arg1})
fake.recordInvocation("Run", []interface{}{arg1})
fake.runMutex.Unlock()
if fake.RunStub != nil {
return fake.RunStub(arg1)
}
if specificReturn {
return ret.result1
}
fakeReturns := fake.runReturns
return fakeReturns.result1
}
func (fake *FakeRunner) RunCallCount() int {
fake.runMutex.RLock()
defer fake.runMutex.RUnlock()
return len(fake.runArgsForCall)
}
func (fake *FakeRunner) RunCalls(stub func(context.Context) error) {
fake.runMutex.Lock()
defer fake.runMutex.Unlock()
fake.RunStub = stub
}
func (fake *FakeRunner) RunArgsForCall(i int) context.Context {
fake.runMutex.RLock()
defer fake.runMutex.RUnlock()
argsForCall := fake.runArgsForCall[i]
return argsForCall.arg1
}
func (fake *FakeRunner) RunReturns(result1 error) {
fake.runMutex.Lock()
defer fake.runMutex.Unlock()
fake.RunStub = nil
fake.runReturns = struct {
result1 error
}{result1}
}
func (fake *FakeRunner) RunReturnsOnCall(i int, result1 error) {
fake.runMutex.Lock()
defer fake.runMutex.Unlock()
fake.RunStub = nil
if fake.runReturnsOnCall == nil {
fake.runReturnsOnCall = make(map[int]struct {
result1 error
})
}
fake.runReturnsOnCall[i] = struct {
result1 error
}{result1}
}
func (fake *FakeRunner) Invocations() map[string][][]interface{} {
fake.invocationsMutex.RLock()
defer fake.invocationsMutex.RUnlock()
fake.runMutex.RLock()
defer fake.runMutex.RUnlock()
copiedInvocations := map[string][][]interface{}{}
for key, value := range fake.invocations {
copiedInvocations[key] = value
}
return copiedInvocations
}
func (fake *FakeRunner) recordInvocation(key string, args []interface{}) {
fake.invocationsMutex.Lock()
defer fake.invocationsMutex.Unlock()
if fake.invocations == nil {
fake.invocations = map[string][][]interface{}{}
}
if fake.invocations[key] == nil {
fake.invocations[key] = [][]interface{}{}
}
fake.invocations[key] = append(fake.invocations[key], args)
}
var _ lidar.Runner = new(FakeRunner)

134
atc/lidar/scanner.go Normal file
View File

@ -0,0 +1,134 @@
package lidar
import (
"context"
"sync"
"time"
"code.cloudfoundry.org/lager"
"github.com/concourse/concourse/atc/creds"
"github.com/concourse/concourse/atc/db"
"github.com/pkg/errors"
)
func NewScanner(
logger lager.Logger,
checkFactory db.CheckFactory,
secrets creds.Secrets,
defaultCheckTimeout time.Duration,
defaultCheckInterval time.Duration,
) *scanner {
return &scanner{
logger: logger,
checkFactory: checkFactory,
secrets: secrets,
defaultCheckTimeout: defaultCheckTimeout,
defaultCheckInterval: defaultCheckInterval,
}
}
type scanner struct {
logger lager.Logger
checkFactory db.CheckFactory
secrets creds.Secrets
defaultCheckTimeout time.Duration
defaultCheckInterval time.Duration
}
func (s *scanner) Run(ctx context.Context) error {
lock, acquired, err := s.checkFactory.AcquireScanningLock(s.logger)
if err != nil {
s.logger.Error("failed-to-get-scanning-lock", err)
return err
}
if !acquired {
s.logger.Debug("scanning-already-in-progress")
return nil
}
defer lock.Release()
resources, err := s.checkFactory.Resources()
if err != nil {
s.logger.Error("failed-to-get-resources", err)
return err
}
resourceTypes, err := s.checkFactory.ResourceTypes()
if err != nil {
s.logger.Error("failed-to-get-resources", err)
return err
}
waitGroup := new(sync.WaitGroup)
for _, resource := range resources {
waitGroup.Add(1)
go func(resource db.Resource, resourceTypes db.ResourceTypes) {
defer waitGroup.Done()
err = s.check(resource, resourceTypes)
s.setCheckError(s.logger, resource, err)
}(resource, resourceTypes)
}
waitGroup.Wait()
return s.checkFactory.NotifyChecker()
}
func (s *scanner) check(checkable db.Checkable, resourceTypes db.ResourceTypes) error {
var err error
parentType, found := resourceTypes.Parent(checkable)
if found {
err = s.check(parentType, resourceTypes)
s.setCheckError(s.logger, parentType, err)
if err != nil {
s.logger.Error("failed-to-create-type-check", err)
return errors.Wrapf(err, "parent type '%v' error", parentType.Name())
}
}
interval := s.defaultCheckInterval
if every := checkable.CheckEvery(); every != "" {
interval, err = time.ParseDuration(every)
if err != nil {
s.logger.Error("failed-to-parse-check-every", err)
return err
}
}
if time.Now().Before(checkable.LastCheckEndTime().Add(interval)) {
s.logger.Debug("interval-not-reached", lager.Data{"interval": interval})
return nil
}
version := checkable.CurrentPinnedVersion()
_, created, err := s.checkFactory.TryCreateCheck(checkable, resourceTypes, version, false)
if err != nil {
s.logger.Error("failed-to-create-check", err)
return err
}
if !created {
s.logger.Info("check-already-exists")
}
return nil
}
func (s *scanner) setCheckError(logger lager.Logger, checkable db.Checkable, err error) {
setErr := checkable.SetCheckSetupError(err)
if setErr != nil {
logger.Error("failed-to-set-check-error", setErr)
}
}

280
atc/lidar/scanner_test.go Normal file
View File

@ -0,0 +1,280 @@
package lidar_test
import (
"context"
"errors"
"time"
"code.cloudfoundry.org/lager/lagertest"
"github.com/concourse/concourse/atc"
"github.com/concourse/concourse/atc/creds/credsfakes"
"github.com/concourse/concourse/atc/db"
"github.com/concourse/concourse/atc/db/dbfakes"
"github.com/concourse/concourse/atc/db/lock/lockfakes"
"github.com/concourse/concourse/atc/lidar"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
type Scanner interface {
Run(ctx context.Context) error
}
var _ = Describe("Scanner", func() {
var (
err error
fakeCheckFactory *dbfakes.FakeCheckFactory
fakeSecrets *credsfakes.FakeSecrets
logger *lagertest.TestLogger
scanner Scanner
)
BeforeEach(func() {
fakeCheckFactory = new(dbfakes.FakeCheckFactory)
fakeSecrets = new(credsfakes.FakeSecrets)
logger = lagertest.NewTestLogger("test")
scanner = lidar.NewScanner(
logger,
fakeCheckFactory,
fakeSecrets,
time.Minute*1,
time.Minute*1,
)
})
JustBeforeEach(func() {
err = scanner.Run(context.TODO())
})
Describe("Run", func() {
Context("when acquiring scanning lock fails", func() {
BeforeEach(func() {
fakeCheckFactory.AcquireScanningLockReturns(nil, false, errors.New("nope"))
})
It("errors", func() {
Expect(err).To(HaveOccurred())
})
})
Context("when scanning lock is already held", func() {
BeforeEach(func() {
fakeCheckFactory.AcquireScanningLockReturns(nil, false, nil)
})
It("does not error", func() {
Expect(err).NotTo(HaveOccurred())
})
It("does not continue", func() {
Expect(fakeCheckFactory.ResourcesCallCount()).To(Equal(0))
})
})
Context("when acquiring the lock succeeds", func() {
var fakeLock *lockfakes.FakeLock
BeforeEach(func() {
fakeLock = new(lockfakes.FakeLock)
fakeCheckFactory.AcquireScanningLockReturns(fakeLock, true, nil)
})
It("releases the lock", func() {
Expect(fakeLock.ReleaseCallCount()).To(Equal(1))
})
Context("when fetching resources fails", func() {
BeforeEach(func() {
fakeCheckFactory.ResourcesReturns(nil, errors.New("nope"))
})
It("errors", func() {
Expect(err).To(HaveOccurred())
})
})
Context("when fetching resources succeeds", func() {
var fakeResource *dbfakes.FakeResource
BeforeEach(func() {
fakeResource = new(dbfakes.FakeResource)
fakeResource.NameReturns("some-name")
fakeResource.TagsReturns([]string{"tag-a", "tag-b"})
fakeResource.SourceReturns(atc.Source{"some": "source"})
fakeCheckFactory.ResourcesReturns([]db.Resource{fakeResource}, nil)
})
Context("when fetching resource types fails", func() {
BeforeEach(func() {
fakeCheckFactory.ResourceTypesReturns(nil, errors.New("nope"))
})
It("errors", func() {
Expect(err).To(HaveOccurred())
})
})
Context("when fetching resources types succeeds", func() {
var fakeResourceType *dbfakes.FakeResourceType
BeforeEach(func() {
fakeResourceType = new(dbfakes.FakeResourceType)
fakeResourceType.NameReturns("some-type")
fakeResourceType.TypeReturns("some-base-type")
fakeResourceType.TagsReturns([]string{"some-tag"})
fakeResourceType.SourceReturns(atc.Source{"some": "type-source"})
fakeCheckFactory.ResourceTypesReturns([]db.ResourceType{fakeResourceType}, nil)
})
Context("when the resource parent type is a base type", func() {
BeforeEach(func() {
fakeResource.TypeReturns("base-type")
})
Context("when the check interval is parseable", func() {
BeforeEach(func() {
fakeResource.CheckEveryReturns("10s")
})
Context("when the last check end time is within our interval", func() {
BeforeEach(func() {
fakeResource.LastCheckEndTimeReturns(time.Now())
})
It("does not check", func() {
Expect(fakeCheckFactory.CreateCheckCallCount()).To(Equal(0))
})
It("clears the check error", func() {
Expect(fakeResource.SetCheckSetupErrorCallCount()).To(Equal(1))
Expect(fakeResource.SetCheckSetupErrorArgsForCall(0)).To(BeNil())
})
})
Context("when the last check end time is past our interval", func() {
BeforeEach(func() {
fakeResource.LastCheckEndTimeReturns(time.Now().Add(-time.Hour))
})
It("creates a check", func() {
Expect(fakeCheckFactory.TryCreateCheckCallCount()).To(Equal(1))
})
It("clears the check error", func() {
Expect(fakeResource.SetCheckSetupErrorCallCount()).To(Equal(1))
Expect(fakeResource.SetCheckSetupErrorArgsForCall(0)).To(BeNil())
})
It("sends a notification for the checker to run", func() {
Expect(fakeCheckFactory.NotifyCheckerCallCount()).To(Equal(1))
})
})
Context("when the checkable has a pinned version", func() {
BeforeEach(func() {
fakeResource.CurrentPinnedVersionReturns(atc.Version{"some": "version"})
})
It("creates a check", func() {
Expect(fakeCheckFactory.TryCreateCheckCallCount()).To(Equal(1))
_, _, fromVersion, _ := fakeCheckFactory.TryCreateCheckArgsForCall(0)
Expect(fromVersion).To(Equal(atc.Version{"some": "version"}))
})
It("clears the check error", func() {
Expect(fakeResource.SetCheckSetupErrorCallCount()).To(Equal(1))
Expect(fakeResource.SetCheckSetupErrorArgsForCall(0)).To(BeNil())
})
It("sends a notification for the checker to run", func() {
Expect(fakeCheckFactory.NotifyCheckerCallCount()).To(Equal(1))
})
})
Context("when the checkable does not have a pinned version", func() {
BeforeEach(func() {
fakeResource.CurrentPinnedVersionReturns(nil)
})
It("creates a check", func() {
Expect(fakeCheckFactory.TryCreateCheckCallCount()).To(Equal(1))
_, _, fromVersion, _ := fakeCheckFactory.TryCreateCheckArgsForCall(0)
Expect(fromVersion).To(BeNil())
})
It("clears the check error", func() {
Expect(fakeResource.SetCheckSetupErrorCallCount()).To(Equal(1))
Expect(fakeResource.SetCheckSetupErrorArgsForCall(0)).To(BeNil())
})
It("sends a notification for the checker to run", func() {
Expect(fakeCheckFactory.NotifyCheckerCallCount()).To(Equal(1))
})
})
})
})
Context("when the resource has a parent type", func() {
BeforeEach(func() {
fakeResource.TypeReturns("custom-type")
fakeResource.PipelineIDReturns(1)
fakeResourceType.NameReturns("custom-type")
fakeResourceType.PipelineIDReturns(1)
})
Context("when it fails to create a check for parent resource", func() {
BeforeEach(func() {
fakeResourceType.CheckEveryReturns("not-a-duration")
})
It("sets the check error", func() {
Expect(fakeResourceType.SetCheckSetupErrorCallCount()).To(Equal(1))
Expect(fakeResource.SetCheckSetupErrorCallCount()).To(Equal(1))
err := fakeResource.SetCheckSetupErrorArgsForCall(0)
Expect(err.Error()).To(ContainSubstring("parent type 'custom-type' error:"))
})
It("does not create a check", func() {
Expect(fakeCheckFactory.TryCreateCheckCallCount()).To(Equal(0))
})
})
Context("when the parent type requires a check", func() {
BeforeEach(func() {
fakeResourceType.LastCheckEndTimeReturns(time.Now().Add(-time.Hour))
fakeResource.LastCheckEndTimeReturns(time.Now().Add(-time.Hour))
})
Context("when the parent type has a version", func() {
BeforeEach(func() {
fakeResourceType.VersionReturns(atc.Version{"some": "version"})
})
It("creates a check for both the parent and the resource", func() {
Expect(fakeCheckFactory.TryCreateCheckCallCount()).To(Equal(2))
checkable, _, _, manuallyTriggered := fakeCheckFactory.TryCreateCheckArgsForCall(0)
Expect(checkable).To(Equal(fakeResourceType))
Expect(manuallyTriggered).To(BeFalse())
checkable, _, _, manuallyTriggered = fakeCheckFactory.TryCreateCheckArgsForCall(1)
Expect(checkable).To(Equal(fakeResource))
Expect(manuallyTriggered).To(BeFalse())
})
It("sends a notification for the checker to run", func() {
Expect(fakeCheckFactory.NotifyCheckerCallCount()).To(Equal(1))
})
})
})
})
})
})
})
})
})

View File

@ -469,6 +469,31 @@ func (event ResourceCheck) Emit(logger lager.Logger) {
)
}
type CheckFinished struct {
ResourceConfigScopeID string
CheckName string
Success bool
}
func (event CheckFinished) Emit(logger lager.Logger) {
state := EventStateOK
if !event.Success {
state = EventStateWarning
}
emit(
logger.Session("check-finished"),
Event{
Name: "check finished",
Value: 1,
State: state,
Attributes: map[string]string{
"scope_id": event.ResourceConfigScopeID,
"check_name": event.CheckName,
},
},
)
}
var lockTypeNames = map[int]string{
lock.LockTypeResourceConfigChecking: "ResourceConfigChecking",
lock.LockTypeBuildTracking: "BuildTracking",

View File

@ -79,7 +79,6 @@ func (rsf *radarSchedulerFactory) BuildScheduler(pipeline db.Pipeline) scheduler
pipeline,
maxinflight.NewUpdater(pipeline),
factory.NewBuildFactory(
pipeline.ID(),
atc.NewPlanFactory(time.Now().Unix()),
),
inputMapper,

View File

@ -9,6 +9,7 @@ type Plan struct {
Do *DoPlan `json:"do,omitempty"`
Get *GetPlan `json:"get,omitempty"`
Put *PutPlan `json:"put,omitempty"`
Check *CheckPlan `json:"check,omitempty"`
Task *TaskPlan `json:"task,omitempty"`
OnAbort *OnAbortPlan `json:"on_abort,omitempty"`
OnError *OnErrorPlan `json:"on_error,omitempty"`
@ -107,6 +108,17 @@ type PutPlan struct {
VersionedResourceTypes VersionedResourceTypes `json:"resource_types,omitempty"`
}
type CheckPlan struct {
Type string `json:"type"`
Name string `json:"name,omitempty"`
Source Source `json:"source"`
Tags Tags `json:"tags,omitempty"`
Timeout string `json:"timeout,omitempty"`
FromVersion Version `json:"from_version,omitempty"`
VersionedResourceTypes VersionedResourceTypes `json:"resource_types,omitempty"`
}
type TaskPlan struct {
Name string `json:"name,omitempty"`

View File

@ -37,6 +37,8 @@ func (factory PlanFactory) NewPlan(step Step) Plan {
plan.Put = &t
case TaskPlan:
plan.Task = &t
case CheckPlan:
plan.Check = &t
case OnAbortPlan:
plan.OnAbort = &t
case OnErrorPlan:

View File

@ -11,6 +11,7 @@ func (plan Plan) Public() *json.RawMessage {
Do *json.RawMessage `json:"do,omitempty"`
Get *json.RawMessage `json:"get,omitempty"`
Put *json.RawMessage `json:"put,omitempty"`
Check *json.RawMessage `json:"check,omitempty"`
Task *json.RawMessage `json:"task,omitempty"`
OnAbort *json.RawMessage `json:"on_abort,omitempty"`
OnError *json.RawMessage `json:"on_error,omitempty"`
@ -47,6 +48,10 @@ func (plan Plan) Public() *json.RawMessage {
public.Put = plan.Put.Public()
}
if plan.Check != nil {
public.Check = plan.Check.Public()
}
if plan.Task != nil {
public.Task = plan.Task.Public()
}
@ -224,6 +229,16 @@ func (plan PutPlan) Public() *json.RawMessage {
})
}
func (plan CheckPlan) Public() *json.RawMessage {
return enc(struct {
Type string `json:"type"`
Name string `json:"name,omitempty"`
}{
Type: plan.Type,
Name: plan.Name,
})
}
func (plan TaskPlan) Public() *json.RawMessage {
return enc(struct {
Name string `json:"name"`

View File

@ -53,6 +53,16 @@ var _ = Describe("Plan", func() {
},
},
atc.Plan{
ID: "4.2",
Check: &atc.CheckPlan{
Type: "type",
Name: "name",
Source: atc.Source{"some": "source"},
Tags: atc.Tags{"tags"},
},
},
atc.Plan{
ID: "5",
Task: &atc.TaskPlan{
@ -379,6 +389,13 @@ var _ = Describe("Plan", func() {
"resource": "resource"
}
},
{
"id": "4.2",
"check": {
"type": "type",
"name": "name"
}
},
{
"id": "5",
"task": {

View File

@ -320,7 +320,11 @@ func (scanner *resourceScanner) check(
TeamID: scanner.dbPipeline.TeamID(),
}
owner := db.NewResourceConfigCheckSessionContainerOwner(resourceConfigScope.ResourceConfig(), ContainerExpiries)
owner := db.NewResourceConfigCheckSessionContainerOwner(
resourceConfigScope.ResourceConfig().ID(),
resourceConfigScope.ResourceConfig().OriginBaseResourceType().ID,
ContainerExpiries,
)
chosenWorker, err := scanner.pool.FindOrChooseWorkerForContainer(
context.Background(),

View File

@ -94,6 +94,7 @@ var _ = Describe("ResourceScanner", func() {
fakeDBPipeline = new(dbfakes.FakePipeline)
fakeResourceConfig = new(dbfakes.FakeResourceConfig)
fakeResourceConfig.IDReturns(123)
fakeResourceConfig.OriginBaseResourceTypeReturns(&db.UsedBaseResourceType{ID: 456})
fakeResourceConfigScope = new(dbfakes.FakeResourceConfigScope)
fakeResourceConfigScope.IDReturns(456)
fakeResourceConfigScope.ResourceConfigReturns(fakeResourceConfig)
@ -238,7 +239,7 @@ var _ = Describe("ResourceScanner", func() {
Expect(err).To(BeNil())
_, _, owner, containerSpec, workerSpec, _ := fakePool.FindOrChooseWorkerForContainerArgsForCall(0)
Expect(owner).To(Equal(db.NewResourceConfigCheckSessionContainerOwner(fakeResourceConfig, radar.ContainerExpiries)))
Expect(owner).To(Equal(db.NewResourceConfigCheckSessionContainerOwner(123, 456, radar.ContainerExpiries)))
Expect(containerSpec.ImageSpec).To(Equal(worker.ImageSpec{
ResourceType: "git",
}))
@ -259,7 +260,7 @@ var _ = Describe("ResourceScanner", func() {
var metadata db.ContainerMetadata
Expect(fakeWorker.FindOrCreateContainerCallCount()).To(Equal(1))
_, _, _, owner, metadata, containerSpec, resourceTypes = fakeWorker.FindOrCreateContainerArgsForCall(0)
Expect(owner).To(Equal(db.NewResourceConfigCheckSessionContainerOwner(fakeResourceConfig, radar.ContainerExpiries)))
Expect(owner).To(Equal(db.NewResourceConfigCheckSessionContainerOwner(123, 456, radar.ContainerExpiries)))
Expect(metadata).To(Equal(db.ContainerMetadata{
Type: db.ContainerTypeCheck,
}))
@ -661,7 +662,7 @@ var _ = Describe("ResourceScanner", func() {
Expect(err).To(BeNil())
_, _, owner, containerSpec, workerSpec, _ := fakePool.FindOrChooseWorkerForContainerArgsForCall(0)
Expect(owner).To(Equal(db.NewResourceConfigCheckSessionContainerOwner(fakeResourceConfig, radar.ContainerExpiries)))
Expect(owner).To(Equal(db.NewResourceConfigCheckSessionContainerOwner(123, 456, radar.ContainerExpiries)))
Expect(containerSpec.ImageSpec).To(Equal(worker.ImageSpec{
ResourceType: "git",
}))
@ -681,7 +682,7 @@ var _ = Describe("ResourceScanner", func() {
var metadata db.ContainerMetadata
_, _, _, owner, metadata, containerSpec, resourceTypes = fakeWorker.FindOrCreateContainerArgsForCall(0)
Expect(owner).To(Equal(db.NewResourceConfigCheckSessionContainerOwner(fakeResourceConfig, radar.ContainerExpiries)))
Expect(owner).To(Equal(db.NewResourceConfigCheckSessionContainerOwner(123, 456, radar.ContainerExpiries)))
Expect(metadata).To(Equal(db.ContainerMetadata{
Type: db.ContainerTypeCheck,
}))

View File

@ -255,7 +255,11 @@ func (scanner *resourceTypeScanner) check(
TeamID: scanner.dbPipeline.TeamID(),
}
owner := db.NewResourceConfigCheckSessionContainerOwner(resourceConfigScope.ResourceConfig(), ContainerExpiries)
owner := db.NewResourceConfigCheckSessionContainerOwner(
resourceConfigScope.ResourceConfig().ID(),
resourceConfigScope.ResourceConfig().OriginBaseResourceType().ID,
ContainerExpiries,
)
chosenWorker, err := scanner.pool.FindOrChooseWorkerForContainer(
context.Background(),
@ -278,7 +282,11 @@ func (scanner *resourceTypeScanner) check(
context.Background(),
logger,
worker.NoopImageFetchingDelegate{},
db.NewResourceConfigCheckSessionContainerOwner(resourceConfigScope.ResourceConfig(), ContainerExpiries),
db.NewResourceConfigCheckSessionContainerOwner(
resourceConfigScope.ResourceConfig().ID(),
resourceConfigScope.ResourceConfig().OriginBaseResourceType().ID,
ContainerExpiries,
),
db.ContainerMetadata{
Type: db.ContainerTypeCheck,
},

View File

@ -82,6 +82,7 @@ var _ = Describe("ResourceTypeScanner", func() {
fakeDBPipeline = new(dbfakes.FakePipeline)
fakeResourceConfig = new(dbfakes.FakeResourceConfig)
fakeResourceConfig.IDReturns(123)
fakeResourceConfig.OriginBaseResourceTypeReturns(&db.UsedBaseResourceType{ID: 456})
fakeResourceConfigScope = new(dbfakes.FakeResourceConfigScope)
fakeResourceConfigScope.IDReturns(123)
fakeResourceConfigScope.ResourceConfigReturns(fakeResourceConfig)
@ -187,7 +188,7 @@ var _ = Describe("ResourceTypeScanner", func() {
Expect(resourceTypes).To(Equal(atc.VersionedResourceTypes{}))
_, _, owner, containerSpec, workerSpec, _ := fakePool.FindOrChooseWorkerForContainerArgsForCall(0)
Expect(owner).To(Equal(db.NewResourceConfigCheckSessionContainerOwner(fakeResourceConfig, ContainerExpiries)))
Expect(owner).To(Equal(db.NewResourceConfigCheckSessionContainerOwner(123, 456, ContainerExpiries)))
Expect(containerSpec.ImageSpec).To(Equal(worker.ImageSpec{
ResourceType: "registry-image",
}))
@ -201,8 +202,9 @@ var _ = Describe("ResourceTypeScanner", func() {
}))
Expect(fakeWorker.FindOrCreateContainerCallCount()).To(Equal(1))
_, _, _, owner, metadata, containerSpec, resourceTypes = fakeWorker.FindOrCreateContainerArgsForCall(0)
Expect(owner).To(Equal(db.NewResourceConfigCheckSessionContainerOwner(fakeResourceConfig, ContainerExpiries)))
Expect(owner).To(Equal(db.NewResourceConfigCheckSessionContainerOwner(123, 456, ContainerExpiries)))
Expect(metadata).To(Equal(db.ContainerMetadata{
Type: db.ContainerTypeCheck,
}))
@ -244,7 +246,7 @@ var _ = Describe("ResourceTypeScanner", func() {
Expect(err).To(BeNil())
_, _, owner, containerSpec, workerSpec, _ := fakePool.FindOrChooseWorkerForContainerArgsForCall(0)
Expect(owner).To(Equal(db.NewResourceConfigCheckSessionContainerOwner(fakeResourceConfig, ContainerExpiries)))
Expect(owner).To(Equal(db.NewResourceConfigCheckSessionContainerOwner(123, 456, ContainerExpiries)))
Expect(containerSpec.ImageSpec).To(Equal(worker.ImageSpec{
ResourceType: "registry-image",
}))
@ -257,7 +259,7 @@ var _ = Describe("ResourceTypeScanner", func() {
Expect(fakeWorker.FindOrCreateContainerCallCount()).To(Equal(1))
_, _, _, owner, metadata, containerSpec, resourceTypes = fakeWorker.FindOrCreateContainerArgsForCall(0)
Expect(owner).To(Equal(db.NewResourceConfigCheckSessionContainerOwner(fakeResourceConfig, ContainerExpiries)))
Expect(owner).To(Equal(db.NewResourceConfigCheckSessionContainerOwner(123, 456, ContainerExpiries)))
Expect(metadata).To(Equal(db.ContainerMetadata{
Type: db.ContainerTypeCheck,
}))
@ -470,7 +472,7 @@ var _ = Describe("ResourceTypeScanner", func() {
Expect(err).To(BeNil())
_, _, owner, containerSpec, workerSpec, _ := fakePool.FindOrChooseWorkerForContainerArgsForCall(0)
Expect(owner).To(Equal(db.NewResourceConfigCheckSessionContainerOwner(fakeResourceConfig, ContainerExpiries)))
Expect(owner).To(Equal(db.NewResourceConfigCheckSessionContainerOwner(123, 456, ContainerExpiries)))
Expect(containerSpec.ImageSpec).To(Equal(worker.ImageSpec{
ResourceType: "registry-image",
}))
@ -485,7 +487,7 @@ var _ = Describe("ResourceTypeScanner", func() {
Expect(fakeWorker.FindOrCreateContainerCallCount()).To(Equal(1))
_, _, _, owner, metadata, containerSpec, resourceTypes = fakeWorker.FindOrCreateContainerArgsForCall(0)
Expect(owner).To(Equal(db.NewResourceConfigCheckSessionContainerOwner(fakeResourceConfig, ContainerExpiries)))
Expect(owner).To(Equal(db.NewResourceConfigCheckSessionContainerOwner(123, 456, ContainerExpiries)))
Expect(metadata).To(Equal(db.ContainerMetadata{
Type: db.ContainerTypeCheck,
}))
@ -594,7 +596,7 @@ var _ = Describe("ResourceTypeScanner", func() {
Expect(resourceTypes).To(Equal(interpolatedResourceTypes))
_, _, owner, containerSpec, workerSpec, _ := fakePool.FindOrChooseWorkerForContainerArgsForCall(0)
Expect(owner).To(Equal(db.NewResourceConfigCheckSessionContainerOwner(fakeResourceConfig, ContainerExpiries)))
Expect(owner).To(Equal(db.NewResourceConfigCheckSessionContainerOwner(123, 456, ContainerExpiries)))
Expect(containerSpec.ImageSpec).To(Equal(worker.ImageSpec{
ResourceType: "registry-image",
}))
@ -607,7 +609,7 @@ var _ = Describe("ResourceTypeScanner", func() {
Expect(fakeWorker.FindOrCreateContainerCallCount()).To(Equal(1))
_, _, _, owner, metadata, containerSpec, resourceTypes = fakeWorker.FindOrCreateContainerArgsForCall(0)
Expect(owner).To(Equal(db.NewResourceConfigCheckSessionContainerOwner(fakeResourceConfig, ContainerExpiries)))
Expect(owner).To(Equal(db.NewResourceConfigCheckSessionContainerOwner(123, 456, ContainerExpiries)))
Expect(metadata).To(Equal(db.ContainerMetadata{
Type: db.ContainerTypeCheck,
}))

View File

@ -9,6 +9,12 @@ import (
"github.com/concourse/concourse/atc/worker"
)
//go:generate counterfeiter . ResourceFactory
type ResourceFactory interface {
NewResourceForContainer(container worker.Container) Resource
}
//go:generate counterfeiter . Resource
type Resource interface {
@ -33,28 +39,24 @@ func ResourcesDir(suffix string) string {
return filepath.Join("/tmp", "build", suffix)
}
func NewResource(container worker.Container) *resource {
return &resource{
container: container,
}
}
type resource struct {
container worker.Container
ScriptFailure bool
}
//go:generate counterfeiter . ResourceFactory
type ResourceFactory interface {
NewResourceForContainer(worker.Container) Resource
}
func NewResourceFactory() ResourceFactory {
func NewResourceFactory() *resourceFactory {
return &resourceFactory{}
}
// TODO: This factory is purely used for testing and faking out the Resource
// object. Please remove asap if possible.
type resourceFactory struct{}
func (rf *resourceFactory) NewResourceForContainer(container worker.Container) Resource {
return &resource{
container: container,
}
return NewResource(container)
}

View File

@ -19,8 +19,7 @@ var (
var _ = BeforeEach(func() {
fakeContainer = new(workerfakes.FakeContainer)
resourceFactory := resource.NewResourceFactory()
resourceForContainer = resourceFactory.NewResourceForContainer(fakeContainer)
resourceForContainer = resource.NewResource(fakeContainer)
})
func TestResource(t *testing.T) {

View File

@ -3,8 +3,3 @@ package atc
type CheckRequestBody struct {
From Version `json:"from"`
}
type CheckResponseBody struct {
ExitStatus int `json:"exit_status"`
Stderr string `json:"stderr"`
}

View File

@ -15,6 +15,8 @@ const (
AbortBuild = "AbortBuild"
GetBuildPreparation = "GetBuildPreparation"
GetCheck = "GetCheck"
GetJob = "GetJob"
CreateJobBuild = "CreateJobBuild"
ListAllJobs = "ListAllJobs"
@ -124,6 +126,8 @@ var Routes = rata.Routes([]rata.Route{
{Path: "/api/v1/builds/:build_id/preparation", Method: "GET", Name: GetBuildPreparation},
{Path: "/api/v1/builds/:build_id/artifacts", Method: "GET", Name: ListBuildArtifacts},
{Path: "/api/v1/checks/:check_id", Method: "GET", Name: GetCheck},
{Path: "/api/v1/jobs", Method: "GET", Name: ListAllJobs},
{Path: "/api/v1/teams/:team_name/pipelines/:pipeline_name/jobs", Method: "GET", Name: ListJobs},
{Path: "/api/v1/teams/:team_name/pipelines/:pipeline_name/jobs/:job_name", Method: "GET", Name: GetJob},

View File

@ -16,13 +16,11 @@ type BuildFactory interface {
}
type buildFactory struct {
PipelineID int
planFactory atc.PlanFactory
}
func NewBuildFactory(pipelineID int, planFactory atc.PlanFactory) BuildFactory {
func NewBuildFactory(planFactory atc.PlanFactory) BuildFactory {
return &buildFactory{
PipelineID: pipelineID,
planFactory: planFactory,
}
}

View File

@ -21,7 +21,7 @@ var _ = Describe("Factory Aggregate", func() {
actualPlanFactory = atc.NewPlanFactory(123)
expectedPlanFactory = atc.NewPlanFactory(123)
buildFactory = factory.NewBuildFactory(42, actualPlanFactory)
buildFactory = factory.NewBuildFactory(actualPlanFactory)
resources = atc.ResourceConfigs{
{

Some files were not shown because too many files have changed in this diff Show More