From 026e8a72a371933944eca835c0ba49f6a3ae4c5b Mon Sep 17 00:00:00 2001 From: Chris Selzo Date: Mon, 12 Aug 2024 15:54:16 -0700 Subject: [PATCH] Allow package cache dir to be overriden for create/delete env commands When the bosh cli deploys a bosh director, it typically has a cache under "$HOME/.bosh/installations//packages". This works fine if you are compiling the CPI releases locally, as the same CPI release is used both for creating the Director VM and for the Director VM to use to create other VMs. We want to be able to shorten the create-env time by using compiled CPI releases. For Ruby-based CPIs, the location on the filesystem of their packages when they are invoked matters. Since the CPI release is compiled on stemcell, and is intended to be used on a Director VM, also based on a stemcell, the Ruby-based CPIs NEED to be located in a particular directory ("/var/vcap/packges") to function. By allowing the bosh cli to use "/var/vcap/packages" as the package cache directory, the create-env command can use the same compiled CPI as the Director VM itself, with no modifications to the CPI. [TPCF-9087] Co-authored-by: Ming Xiao Co-authored-by: Nitin Ravindran --- cmd/cmd.go | 8 ++++---- cmd/create_env_test.go | 3 ++- cmd/deployment_deleter_test.go | 5 +++-- cmd/env_factory.go | 3 ++- cmd/opts/opts.go | 6 ++++-- cmd/opts/opts_test.go | 12 ++++++++++++ cpi/release/installer_test.go | 2 +- installation/installer_test.go | 2 +- installation/target.go | 12 +++++++++--- installation/target_provider.go | 5 ++++- installation/target_provider_test.go | 19 ++++++++++++++++++- installation/target_test.go | 20 +++++++++++++++++--- installation/uninstaller_test.go | 4 ++-- integration/create_env_test.go | 3 ++- 14 files changed, 81 insertions(+), 23 deletions(-) diff --git a/cmd/cmd.go b/cmd/cmd.go index 978391f71..3f0832b6a 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -72,7 +72,7 @@ func (c Cmd) Execute() (cmdErr error) { case *CreateEnvOpts: envProvider := func(manifestPath string, statePath string, vars boshtpl.Variables, op patch.Op) DeploymentPreparer { - return NewEnvFactory(deps, manifestPath, statePath, vars, op, opts.RecreatePersistentDisks).Preparer() + return NewEnvFactory(deps, manifestPath, statePath, vars, op, opts.RecreatePersistentDisks, opts.PackageDir).Preparer() } stage := boshui.NewStage(deps.UI, deps.Time, deps.Logger) @@ -80,7 +80,7 @@ func (c Cmd) Execute() (cmdErr error) { case *DeleteEnvOpts: envProvider := func(manifestPath string, statePath string, vars boshtpl.Variables, op patch.Op) DeploymentDeleter { - return NewEnvFactory(deps, manifestPath, statePath, vars, op, false).Deleter() + return NewEnvFactory(deps, manifestPath, statePath, vars, op, false, opts.PackageDir).Deleter() } stage := boshui.NewStage(deps.UI, deps.Time, deps.Logger) @@ -88,7 +88,7 @@ func (c Cmd) Execute() (cmdErr error) { case *StopEnvOpts: envProvider := func(manifestPath string, statePath string, vars boshtpl.Variables, op patch.Op) DeploymentStateManager { - return NewEnvFactory(deps, manifestPath, statePath, vars, op, false).StateManager() + return NewEnvFactory(deps, manifestPath, statePath, vars, op, false, "").StateManager() } stage := boshui.NewStage(deps.UI, deps.Time, deps.Logger) @@ -96,7 +96,7 @@ func (c Cmd) Execute() (cmdErr error) { case *StartEnvOpts: envProvider := func(manifestPath string, statePath string, vars boshtpl.Variables, op patch.Op) DeploymentStateManager { - return NewEnvFactory(deps, manifestPath, statePath, vars, op, false).StateManager() + return NewEnvFactory(deps, manifestPath, statePath, vars, op, false, "").StateManager() } stage := boshui.NewStage(deps.UI, deps.Time, deps.Logger) diff --git a/cmd/create_env_test.go b/cmd/create_env_test.go index e8d021abf..1156a0ca2 100644 --- a/cmd/create_env_test.go +++ b/cmd/create_env_test.go @@ -347,6 +347,7 @@ var _ = Describe("CreateEnvCmd", func() { deploymentStateService, fakeInstallationUUIDGenerator, filepath.Join("fake-install-dir"), + "", ) tempRootConfigurator := cmd.NewTempRootConfigurator(fs) @@ -418,7 +419,7 @@ var _ = Describe("CreateEnvCmd", func() { fakeInstallationParser.ParseManifest = installationManifest installationPath := filepath.Join("fake-install-dir", "fake-installation-id") - target := biinstall.NewTarget(installationPath) + target := biinstall.NewTarget(installationPath, "") installedJob := biinstall.NewInstalledJob( biinstall.RenderedJobRef{ diff --git a/cmd/deployment_deleter_test.go b/cmd/deployment_deleter_test.go index b56bed541..3eab01878 100644 --- a/cmd/deployment_deleter_test.go +++ b/cmd/deployment_deleter_test.go @@ -193,7 +193,7 @@ cloud_provider: }, } - target := biinstall.NewTarget(filepath.Join("fake-install-dir", "fake-installation-id")) + target := biinstall.NewTarget(filepath.Join("fake-install-dir", "fake-installation-id"), "") mockInstallerFactory.EXPECT().NewInstaller(target).Return(mockCpiInstaller).AnyTimes() expectCPIInstall = mockCpiInstaller.EXPECT().Install(installationManifest, gomock.Any()).Do(func(_ biinstallmanifest.Manifest, stage boshui.Stage) { @@ -229,6 +229,7 @@ cloud_provider: deploymentStateService, fakeInstallationUUIDGenerator, filepath.Join("fake-install-dir"), + "", ) tempRootConfigurator := cmd.NewTempRootConfigurator(fs) @@ -536,7 +537,7 @@ cloud_provider: }, } - target := biinstall.NewTarget(filepath.Join("fake-install-dir", "fake-installation-id")) + target := biinstall.NewTarget(filepath.Join("fake-install-dir", "fake-installation-id"), "") mockInstallerFactory.EXPECT().NewInstaller(target).Return(mockCpiInstaller).AnyTimes() fakeInstallation := &fakecmd.FakeInstallation{} diff --git a/cmd/env_factory.go b/cmd/env_factory.go index 555e54e22..c0a50f4c1 100644 --- a/cmd/env_factory.go +++ b/cmd/env_factory.go @@ -71,6 +71,7 @@ func NewEnvFactory( manifestVars boshtpl.Variables, manifestOp patch.Op, recreatePersistentDisks bool, + packageDir string, ) *envFactory { f := envFactory{ deps: deps, @@ -126,7 +127,7 @@ func NewEnvFactory( } f.targetProvider = boshinst.NewTargetProvider( - f.deploymentStateService, deps.UUIDGen, filepath.Join(workspaceRootPath, "installations")) + f.deploymentStateService, deps.UUIDGen, filepath.Join(workspaceRootPath, "installations"), packageDir) { diskRepo := biconfig.NewDiskRepo(f.deploymentStateService, deps.UUIDGen) diff --git a/cmd/opts/opts.go b/cmd/opts/opts.go index b57e2fba4..a8766e599 100644 --- a/cmd/opts/opts.go +++ b/cmd/opts/opts.go @@ -197,6 +197,7 @@ type CreateEnvOpts struct { StatePath string `long:"state" value-name:"PATH" description:"State file path"` Recreate bool `long:"recreate" description:"Recreate VM in deployment"` RecreatePersistentDisks bool `long:"recreate-persistent-disks" description:"Recreate persistent disks in the deployment"` + PackageDir string `long:"package-dir" value-name:"DIR" description:"Package cache location override"` cmd } @@ -208,8 +209,9 @@ type DeleteEnvOpts struct { Args DeleteEnvArgs `positional-args:"true" required:"true"` VarFlags OpsFlags - SkipDrain bool `long:"skip-drain" description:"Skip running drain and pre-stop scripts"` - StatePath string `long:"state" value-name:"PATH" description:"State file path"` + SkipDrain bool `long:"skip-drain" description:"Skip running drain and pre-stop scripts"` + StatePath string `long:"state" value-name:"PATH" description:"State file path"` + PackageDir string `long:"package-dir" value-name:"DIR" description:"Package cache location override"` cmd } diff --git a/cmd/opts/opts_test.go b/cmd/opts/opts_test.go index 6cb8c96b9..41842daf1 100644 --- a/cmd/opts/opts_test.go +++ b/cmd/opts/opts_test.go @@ -845,6 +845,12 @@ var _ = Describe("Opts", func() { )) }) + It("has --package-dir", func() { + Expect(getStructTagForName("PackageDir", opts)).To(Equal( + `long:"package-dir" value-name:"DIR" description:"Package cache location override"`, + )) + }) + It("has --recreate", func() { Expect(getStructTagForName("Recreate", opts)).To(Equal( `long:"recreate" description:"Recreate VM in deployment"`, @@ -899,6 +905,12 @@ var _ = Describe("Opts", func() { )) }) + It("has --package-dir", func() { + Expect(getStructTagForName("PackageDir", opts)).To(Equal( + `long:"package-dir" value-name:"DIR" description:"Package cache location override"`, + )) + }) + It("has --skip-drain", func() { Expect(getStructTagForName("SkipDrain", opts)).To(Equal( `long:"skip-drain" description:"Skip running drain and pre-stop scripts"`, diff --git a/cpi/release/installer_test.go b/cpi/release/installer_test.go index a9aeeeb0f..7f5ecec94 100644 --- a/cpi/release/installer_test.go +++ b/cpi/release/installer_test.go @@ -46,7 +46,7 @@ var _ = Describe("Installer", func() { installStage = fakeui.NewFakeStage() installation = mocks.NewMockInstallation(mockCtrl) - target = biinstallation.NewTarget("fake-installation-path") + target = biinstallation.NewTarget("fake-installation-path", "") mockInstallerFactory.EXPECT().NewInstaller(target).Return(mockInstaller).AnyTimes() expectInstall = mockInstaller.EXPECT().Install(installationManifest, gomock.Any()) expectCleanup = mockInstaller.EXPECT().Cleanup(installation).Return(nil) diff --git a/installation/installer_test.go b/installation/installer_test.go index fd04d0a4a..896c99a17 100644 --- a/installation/installer_test.go +++ b/installation/installer_test.go @@ -50,7 +50,7 @@ var _ = Describe("Installer", func() { mockPackageCompiler = mock_install.NewMockPackageCompiler(mockCtrl) fakeExtractor = &blobextractfakes.FakeExtractor{} - target = NewTarget("fake-installation-path") + target = NewTarget("fake-installation-path", "") installationManifest = biinstallmanifest.Manifest{ Name: "fake-installation-name", Properties: biproperty.Map{}, diff --git a/installation/target.go b/installation/target.go index 31e8725e1..a9e008844 100644 --- a/installation/target.go +++ b/installation/target.go @@ -5,12 +5,14 @@ import ( ) type Target struct { - path string + path string + packageDir string } -func NewTarget(path string) Target { +func NewTarget(path string, packageDir string) Target { return Target{ path, + packageDir, } } @@ -31,7 +33,11 @@ func (t Target) TemplatesIndexPath() string { } func (t Target) PackagesPath() string { - return filepath.Join(t.path, "packages") + if t.packageDir != "" { + return t.packageDir + } else { + return filepath.Join(t.path, "packages") + } } func (t Target) JobsPath() string { diff --git a/installation/target_provider.go b/installation/target_provider.go index decb3d2ae..916acffd2 100644 --- a/installation/target_provider.go +++ b/installation/target_provider.go @@ -17,17 +17,20 @@ type targetProvider struct { deploymentStateService biconfig.DeploymentStateService uuidGenerator boshuuid.Generator installationsRootPath string + packageDir string } func NewTargetProvider( deploymentStateService biconfig.DeploymentStateService, uuidGenerator boshuuid.Generator, installationsRootPath string, + packageDir string, ) TargetProvider { return &targetProvider{ deploymentStateService: deploymentStateService, uuidGenerator: uuidGenerator, installationsRootPath: installationsRootPath, + packageDir: packageDir, } } @@ -51,5 +54,5 @@ func (p *targetProvider) NewTarget() (Target, error) { } } - return NewTarget(filepath.Join(p.installationsRootPath, installationID)), nil + return NewTarget(filepath.Join(p.installationsRootPath, installationID), p.packageDir), nil } diff --git a/installation/target_provider_test.go b/installation/target_provider_test.go index cb170939f..5b5aa1d3d 100644 --- a/installation/target_provider_test.go +++ b/installation/target_provider_test.go @@ -36,7 +36,24 @@ var _ = Describe("TargetProvider", func() { logger, configPath, ) - targetProvider = NewTargetProvider(deploymentStateService, fakeUUIDGenerator, installationsRootPath) + targetProvider = NewTargetProvider(deploymentStateService, fakeUUIDGenerator, installationsRootPath, "") + }) + + Context("when a packageDir is passed in", func() { + var packageDir string + + BeforeEach(func() { + packageDir = "/some/good/dir" + + targetProvider = NewTargetProvider(deploymentStateService, fakeUUIDGenerator, installationsRootPath, packageDir) + }) + + It("is passed through to the target", func() { + target, err := targetProvider.NewTarget() + Expect(err).ToNot(HaveOccurred()) + + Expect(target.PackagesPath()).To(Equal(packageDir)) + }) }) Context("when the installation_id exists in the deployment state", func() { diff --git a/installation/target_test.go b/installation/target_test.go index f47072666..a28b5a56c 100644 --- a/installation/target_test.go +++ b/installation/target_test.go @@ -13,7 +13,7 @@ var _ = Describe("Target", func() { Describe("Paths", func() { var target Target BeforeEach(func() { - target = NewTarget("/home/fake/madcow") + target = NewTarget("/home/fake/madcow", "") }) It("returns the blobstore path", func() { @@ -28,8 +28,22 @@ var _ = Describe("Target", func() { Expect(target.TemplatesIndexPath()).To(Equal(filepath.Join("/", "home", "fake", "madcow", "templates.json"))) }) - It("returns the packages path", func() { - Expect(target.PackagesPath()).To(Equal(filepath.Join("/", "home", "fake", "madcow", "packages"))) + Context("packageDir is NOT provided", func() { + It("returns the packages path as a subdirectory of the path", func() { + Expect(target.PackagesPath()).To(Equal(filepath.Join("/", "home", "fake", "madcow", "packages"))) + }) + }) + + Context("packageDir is provided", func() { + var packagesDir string + BeforeEach(func() { + packagesDir = "/some/good/path" + target = NewTarget("/home/fake/madcow", packagesDir) + }) + + It("returns the provided packages path", func() { + Expect(target.PackagesPath()).To(Equal(packagesDir)) + }) }) It("returns the temp path", func() { diff --git a/installation/uninstaller_test.go b/installation/uninstaller_test.go index f4cda3951..7bf14c690 100644 --- a/installation/uninstaller_test.go +++ b/installation/uninstaller_test.go @@ -30,7 +30,7 @@ var _ = Describe("Uninstaller", func() { err = fs.WriteFileString(filepath.Join(installationPath, "some-installation-artifact"), "something-blah") Expect(err).ToNot(HaveOccurred()) - installationTarget := installation.NewTarget(installationPath) + installationTarget := installation.NewTarget(installationPath, "") uninstaller := installation.NewUninstaller(fs, boshlogger) @@ -53,7 +53,7 @@ var _ = Describe("Uninstaller", func() { return errors.New("can't remove that") } - installationTarget := installation.NewTarget("/not/a/path") + installationTarget := installation.NewTarget("/not/a/path", "") uninstaller := installation.NewUninstaller(fs, boshlogger) diff --git a/integration/create_env_test.go b/integration/create_env_test.go index 6c1544ce7..aeca93f2d 100644 --- a/integration/create_env_test.go +++ b/integration/create_env_test.go @@ -302,7 +302,7 @@ cloud_provider: Properties: biproperty.Map{}, } installationPath := filepath.Join("fake-install-dir", "fake-installation-id") - target := biinstall.NewTarget(installationPath) + target := biinstall.NewTarget(installationPath, "") installedJob := biinstall.InstalledJob{} installedJob.Name = "fake-cpi-release-job-name" @@ -450,6 +450,7 @@ cloud_provider: deploymentStateService, installationUuidGenerator, filepath.Join("fake-install-dir"), + "", ) tempRootConfigurator := cmd.NewTempRootConfigurator(fs)