diff --git a/README.md b/README.md index c7ab0575e..4d0d02dfb 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # BOSH Deployment Resource -A resource that will deploy releases and stemcells using the [BOSH CLI v2](https://bosh.io/docs/cli-v2.html). +A resource that will deploy releases and stemcells using the [BOSH CLI v2](https://bosh.io/docs/cli-v2.html). ## Differences from original BOSH Deployment Resource @@ -16,7 +16,7 @@ uses the Ruby CLI and does not support newer BOSH features. To use the BOSH Deployment Resource, you must declare it in your pipeline as a resource type: -``` +```yaml resource_types: - name: bosh-deployment type: docker-image @@ -41,7 +41,7 @@ resource_types: * `vars_store`: *Optional.* Configuration for a persisted variables store. Currently only the Google Cloud Storage (GCS) provider is supported. `json_key` must be the the JSON key for your service account. Example: - ``` + ```yaml provider: gcs config: bucket: my-bucket @@ -81,7 +81,7 @@ _Notes_: #### Example -``` +```yaml - put: staging params: source_file: path/to/sourcefile @@ -89,7 +89,7 @@ _Notes_: Sample source file: -``` +```json { "target": "dynamic-director.example.com", "client_secret": "generated-secret", @@ -114,7 +114,7 @@ _Note_: Only the most recent version is fetchable #### Parameters -* `compiled_releases`: *Optional.* List of compiled releases to download. Deployment can only have one stemcell. +* `compiled_releases`: *Optional.* List of compiled releases to download and optionally specified jobs. Deployment can only have one stemcell. ``` yaml - get: staging @@ -122,6 +122,9 @@ _Note_: Only the most recent version is fetchable compiled_releases: - name: release-one - name: release-two + jobs: + - job-one + - job-two ``` ### `out`: Deploy or Delete a BOSH deployment (defaults to deploy) @@ -139,8 +142,8 @@ deployment manifest and then deploy. stemcell versions. * `releases`: *Optional.* An array of globs that should point to where the - releases used in the deployment can be found. Release entries in the - manifest with version 'latest' will be updated to the actual provided + releases used in the deployment can be found. Release entries in the + manifest with version 'latest' will be updated to the actual provided release versions. * `vars`: *Optional.* A collection of variables to be set in the deployment manifest. diff --git a/bosh/boshfakes/fake_director.go b/bosh/boshfakes/fake_director.go index 1cd32c55b..7626536ca 100644 --- a/bosh/boshfakes/fake_director.go +++ b/bosh/boshfakes/fake_director.go @@ -56,11 +56,11 @@ type FakeDirector struct { result1 []byte result2 error } - ExportReleasesStub func(targetDirectory string, releases []string) error + ExportReleasesStub func(targetDirectory string, releases []bosh.ReleaseSpec) error exportReleasesMutex sync.RWMutex exportReleasesArgsForCall []struct { targetDirectory string - releases []string + releases []bosh.ReleaseSpec } exportReleasesReturns struct { result1 error @@ -305,17 +305,17 @@ func (fake *FakeDirector) DownloadManifestReturnsOnCall(i int, result1 []byte, r }{result1, result2} } -func (fake *FakeDirector) ExportReleases(targetDirectory string, releases []string) error { - var releasesCopy []string +func (fake *FakeDirector) ExportReleases(targetDirectory string, releases []bosh.ReleaseSpec) error { + var releasesCopy []bosh.ReleaseSpec if releases != nil { - releasesCopy = make([]string, len(releases)) + releasesCopy = make([]bosh.ReleaseSpec, len(releases)) copy(releasesCopy, releases) } fake.exportReleasesMutex.Lock() ret, specificReturn := fake.exportReleasesReturnsOnCall[len(fake.exportReleasesArgsForCall)] fake.exportReleasesArgsForCall = append(fake.exportReleasesArgsForCall, struct { targetDirectory string - releases []string + releases []bosh.ReleaseSpec }{targetDirectory, releasesCopy}) fake.recordInvocation("ExportReleases", []interface{}{targetDirectory, releasesCopy}) fake.exportReleasesMutex.Unlock() @@ -334,7 +334,7 @@ func (fake *FakeDirector) ExportReleasesCallCount() int { return len(fake.exportReleasesArgsForCall) } -func (fake *FakeDirector) ExportReleasesArgsForCall(i int) (string, []string) { +func (fake *FakeDirector) ExportReleasesArgsForCall(i int) (string, []bosh.ReleaseSpec) { fake.exportReleasesMutex.RLock() defer fake.exportReleasesMutex.RUnlock() return fake.exportReleasesArgsForCall[i].targetDirectory, fake.exportReleasesArgsForCall[i].releases diff --git a/bosh/director.go b/bosh/director.go index 0dab065b3..2a2502987 100644 --- a/bosh/director.go +++ b/bosh/director.go @@ -37,13 +37,18 @@ type InterpolateParams struct { VarsStore string } +type ReleaseSpec struct { + Name string + Jobs []string +} + //go:generate counterfeiter . Director type Director interface { Delete(force bool) error Deploy(manifestBytes []byte, deployParams DeployParams) error Interpolate(manifestBytes []byte, interpolateParams InterpolateParams) ([]byte, error) DownloadManifest() ([]byte, error) - ExportReleases(targetDirectory string, releases []string) error + ExportReleases(targetDirectory string, releases []ReleaseSpec) error UploadRelease(releaseURL string) error UploadStemcell(stemcellURL string) error WaitForDeployLock() error @@ -215,7 +220,7 @@ func (d BoshDirector) deploymentIsLocked() (bool, error) { return false, nil } -func (d BoshDirector) ExportReleases(targetDirectory string, releases []string) error { +func (d BoshDirector) ExportReleases(targetDirectory string, releases []ReleaseSpec) error { deploymentReleases, stemcell, err := d.releasesAndStemcell() if err != nil { return fmt.Errorf("could not export releases: %s", err) @@ -226,18 +231,18 @@ func (d BoshDirector) ExportReleases(targetDirectory string, releases []string) for _, release := range releases { foundRelease := false for _, deploymentRelease := range deploymentReleases { - if deploymentRelease.Name() == release { + if deploymentRelease.Name() == release.Name { releasesToDownload = append(releasesToDownload, deploymentRelease) foundRelease = true } } if !foundRelease { - return fmt.Errorf("could not find release %s in deployment", release) + return fmt.Errorf("could not find release %s in deployment", release.Name) } } - for _, deploymentRelease := range releasesToDownload { + for i, deploymentRelease := range releasesToDownload { releaseSlug := boshdir.NewReleaseSlug(deploymentRelease.Name(), deploymentRelease.Version().AsString()) osVersionSlug := boshdir.NewOSVersionSlug(stemcell.OSName(), stemcell.Version().AsString()) @@ -253,6 +258,7 @@ func (d BoshDirector) ExportReleases(targetDirectory string, releases []string) } err = d.commandRunner.ExecuteWithDefaultOverride(&boshcmd.ExportReleaseOpts{ Args: boshcmd.ExportReleaseArgs{ReleaseSlug: releaseSlug, OSVersionSlug: osVersionSlug}, + Jobs: releases[i].Jobs, Directory: directory, }, directoryFixFunction, nil) if err != nil { diff --git a/bosh/director_test.go b/bosh/director_test.go index c2628a3bc..26271de75 100644 --- a/bosh/director_test.go +++ b/bosh/director_test.go @@ -390,7 +390,16 @@ var _ = Describe("BoshDirector", func() { }) It("downloads the given releases", func() { - err := director.ExportReleases("/tmp/foo", []string{"cool-release", "awesome-release"}) + err := director.ExportReleases("/tmp/foo", []bosh.ReleaseSpec{ + {Name: "cool-release"}, + { + Name: "awesome-release", + Jobs: []string{ + "nice-job", + "well-done", + }, + }, + }) Expect(err).ToNot(HaveOccurred()) Expect(fakeBoshDirector.FindDeploymentCallCount()).To(Equal(1)) @@ -415,11 +424,19 @@ var _ = Describe("BoshDirector", func() { Expect(string(exportReleaseOpts.Args.ReleaseSlug.Version())).To(Equal("987.65")) Expect(string(exportReleaseOpts.Args.OSVersionSlug.OS())).To(Equal("minix")) Expect(string(exportReleaseOpts.Args.OSVersionSlug.Version())).To(Equal("3.4.0")) + Expect(exportReleaseOpts.Jobs).To(Equal([]string{ + "nice-job", + "well-done", + })) }) Context("when requesting a release not in the manifest", func() { It("errors before downloading any releases", func() { - err := director.ExportReleases("/tmp/foo", []string{"cool-release", "awesome-release", "missing-release"}) + err := director.ExportReleases("/tmp/foo", []bosh.ReleaseSpec{ + {Name: "cool-release"}, + {Name: "awesome-release"}, + {Name: "missing-release"}, + }) Expect(err).To(MatchError(ContainSubstring("could not find release missing-release"))) Expect(commandRunner.ExecuteCallCount()).To(Equal(0)) @@ -429,8 +446,10 @@ var _ = Describe("BoshDirector", func() { Context("when there is more than one stemcell in the manifest", func() { It("errors before downloading any releases", func() { fakeDeployment.StemcellsReturns([]boshdir.Stemcell{fakeDeploymentStemcell, fakeDeploymentStemcell}, nil) - - err := director.ExportReleases("/tmp/foo", []string{"cool-release", "awesome-release"}) + err := director.ExportReleases("/tmp/foo", []bosh.ReleaseSpec{ + {Name: "cool-release"}, + {Name: "awesome-release"}, + }) Expect(err).To(MatchError(ContainSubstring("exporting releases from a deployment with multiple stemcells is unsupported"))) Expect(commandRunner.ExecuteCallCount()).To(Equal(0)) @@ -441,7 +460,9 @@ var _ = Describe("BoshDirector", func() { It("returns an error", func() { fakeBoshDirector.FindDeploymentReturns(fakeDeployment, errors.New("foo")) - err := director.ExportReleases("/tmp/foo", []string{"cool-release"}) + err := director.ExportReleases("/tmp/foo", []bosh.ReleaseSpec{ + {Name: "cool-release"}, + }) Expect(err).To(MatchError(ContainSubstring("could not export releases: could not fetch deployment cool-deployment: foo"))) }) }) @@ -450,7 +471,9 @@ var _ = Describe("BoshDirector", func() { It("returns an error", func() { commandRunner.ExecuteWithDefaultOverrideReturns(errors.New("failed communicating with director")) - err := director.ExportReleases("/tmp/foo", []string{"cool-release"}) + err := director.ExportReleases("/tmp/foo", []bosh.ReleaseSpec{ + {Name: "cool-release"}, + }) Expect(err).To(MatchError(ContainSubstring("could not export release cool-release: failed communicating with director"))) }) }) @@ -459,7 +482,9 @@ var _ = Describe("BoshDirector", func() { It("returns an error", func() { fakeDeployment.ReleasesReturns([]boshdir.Release{}, errors.New("foo")) - err := director.ExportReleases("/tmp/foo", []string{"cool-release"}) + err := director.ExportReleases("/tmp/foo", []bosh.ReleaseSpec{ + {Name: "cool-release"}, + }) Expect(err).To(MatchError(ContainSubstring("could not export releases: could not fetch releases: foo"))) }) }) @@ -469,7 +494,9 @@ var _ = Describe("BoshDirector", func() { It("returns an error", func() { fakeDeployment.StemcellsReturns([]boshdir.Stemcell{}, errors.New("foo")) - err := director.ExportReleases("/tmp/foo", []string{"cool-release"}) + err := director.ExportReleases("/tmp/foo", []bosh.ReleaseSpec{ + {Name: "cool-release"}, + }) Expect(err).To(MatchError(ContainSubstring("could not export releases: could not fetch stemcells: foo"))) }) }) @@ -478,7 +505,9 @@ var _ = Describe("BoshDirector", func() { It("returns an error", func() { fakeBoshDirector.StemcellsReturns([]boshdir.Stemcell{}, errors.New("foo")) - err := director.ExportReleases("/tmp/foo", []string{"cool-release"}) + err := director.ExportReleases("/tmp/foo", []bosh.ReleaseSpec{ + {Name: "cool-release"}, + }) Expect(err).To(MatchError(ContainSubstring("could not export releases: could not fetch stemcells: foo"))) }) }) diff --git a/concourse/in_params.go b/concourse/in_params.go index 9d6f8455f..64b71fe0c 100644 --- a/concourse/in_params.go +++ b/concourse/in_params.go @@ -1,7 +1,8 @@ package concourse type CompiledRelease struct { - Name string `json:"name"` + Name string `json:"name"` + Jobs []string `json:"jobs"` } type InParams struct { diff --git a/in/in_command.go b/in/in_command.go index c1e250089..8e062ddaf 100644 --- a/in/in_command.go +++ b/in/in_command.go @@ -47,9 +47,12 @@ func (c InCommand) Run(inRequest concourse.InRequest, targetDir string) (InRespo } if len(inRequest.Params.CompiledReleases) > 0 { - releases := []string{} + var releases []bosh.ReleaseSpec for _, compiledRelease := range inRequest.Params.CompiledReleases { - releases = append(releases, compiledRelease.Name) + releases = append(releases, bosh.ReleaseSpec{ + Name: compiledRelease.Name, + Jobs: compiledRelease.Jobs, + }) } if err := c.director.ExportReleases(targetDir, releases); err != nil { return InResponse{}, err diff --git a/in/in_command_test.go b/in/in_command_test.go index 2a1f81589..8d9b7a9fc 100644 --- a/in/in_command_test.go +++ b/in/in_command_test.go @@ -10,6 +10,7 @@ import ( "io/ioutil" "path/filepath" + "github.com/cloudfoundry/bosh-deployment-resource/bosh" "github.com/cloudfoundry/bosh-deployment-resource/bosh/boshfakes" "github.com/cloudfoundry/bosh-deployment-resource/concourse" "github.com/cloudfoundry/bosh-deployment-resource/in" @@ -138,7 +139,10 @@ var _ = Describe("InCommand", func() { inRequest.Version.ManifestSha1 = fmt.Sprintf("%x", sha1.Sum(manifest)) inRequest.Params.CompiledReleases = []concourse.CompiledRelease{ {Name: "real-one"}, - {Name: "real-two"}, + { + Name: "real-two", + Jobs: []string{"nice-job"}, + }, } }) @@ -150,7 +154,13 @@ var _ = Describe("InCommand", func() { targetDir, releases := director.ExportReleasesArgsForCall(0) Expect(targetDir).To(Equal(targetDir)) - Expect(releases).To(Equal([]string{"real-one", "real-two"})) + Expect(releases).To(Equal([]bosh.ReleaseSpec{ + {Name: "real-one"}, + { + Name: "real-two", + Jobs: []string{"nice-job"}, + }, + })) }) Context("when exporting releases fails", func() {