func buildSSHAction(settingsService boshsettings.Service) (*fakeplatform.FakePlatform, SSHAction) { platform := fakeplatform.NewFakePlatform() dirProvider := boshdirs.NewProvider("/foo") logger := boshlog.NewLogger(boshlog.LevelNone) action := NewSSH(settingsService, platform, dirProvider, logger) return platform, action }
func describeDummyPlatform() { var ( platform Platform collector boshstats.Collector fs boshsys.FileSystem cmdRunner boshsys.CmdRunner dirProvider boshdirs.Provider devicePathResolver boshdpresolv.DevicePathResolver logger boshlog.Logger ) BeforeEach(func() { collector = &fakestats.FakeCollector{} fs = fakesys.NewFakeFileSystem() cmdRunner = fakesys.NewFakeCmdRunner() dirProvider = boshdirs.NewProvider("/fake-dir") devicePathResolver = fakedpresolv.NewFakeDevicePathResolver() logger = boshlog.NewLogger(boshlog.LevelNone) }) JustBeforeEach(func() { platform = NewDummyPlatform( collector, fs, cmdRunner, dirProvider, devicePathResolver, logger, ) }) Describe("GetDefaultNetwork", func() { It("returns the contents of dummy-defaults-network-settings.json since that's what the dummy cpi writes", func() { settingsFilePath := "/fake-dir/bosh/dummy-default-network-settings.json" fs.WriteFileString(settingsFilePath, `{"IP": "1.2.3.4"}`) network, err := platform.GetDefaultNetwork() Expect(err).NotTo(HaveOccurred()) Expect(network.IP).To(Equal("1.2.3.4")) }) }) Describe("GetCertManager", func() { It("returs a dummy cert manager", func() { certManager := platform.GetCertManager() Expect(certManager.UpdateCertificates("")).Should(BeNil()) }) }) }
func init() { Describe("GenericScriptProvider", func() { It("produces script paths relative to the base directory", func() { runner := fakesys.NewFakeCmdRunner() fs := fakesys.NewFakeFileSystem() dirProvider := boshdir.NewProvider("/the/base/dir") scriptProvider := scriptrunner.NewJobScriptProvider(runner, fs, dirProvider) script := scriptProvider.Get("myjob", "the-best-hook-ever") Expect(script.Path()).To(Equal("/the/base/dir/jobs/myjob/bin/the-best-hook-ever")) }) }) }
func init() { Describe("Testing with Ginkgo", func() { It("new drain script", func() { runner := fakesys.NewFakeCmdRunner() fs := fakesys.NewFakeFileSystem() dirProvider := boshdir.NewProvider("/var/vcap") scriptProvider := NewConcreteScriptProvider(runner, fs, dirProvider) script := scriptProvider.NewScript("foo") Expect(script.Path()).To(Equal("/var/vcap/jobs/foo/bin/drain")) }) }) }
func buildVitalsService() (statsCollector *fakestats.FakeCollector, service Service) { dirProvider := boshdirs.NewProvider("/fake/base/dir") statsCollector = &fakestats.FakeCollector{ CPULoad: boshstats.CPULoad{ One: 0.2, Five: 4.55, Fifteen: 1.123, }, StartCollectingCPUStats: boshstats.CPUStats{ User: 56, Sys: 10, Wait: 1, Total: 100, }, MemStats: boshstats.Usage{ Used: 700 * 1024, Total: 1000 * 1024, }, SwapStats: boshstats.Usage{ Used: 600 * 1024, Total: 1000 * 1024, }, DiskStats: map[string]boshstats.DiskStats{ "/": boshstats.DiskStats{ DiskUsage: boshstats.Usage{Used: 100, Total: 200}, InodeUsage: boshstats.Usage{Used: 50, Total: 500}, }, dirProvider.DataDir(): boshstats.DiskStats{ DiskUsage: boshstats.Usage{Used: 15, Total: 20}, InodeUsage: boshstats.Usage{Used: 10, Total: 50}, }, dirProvider.StoreDir(): boshstats.DiskStats{ DiskUsage: boshstats.Usage{Used: 2, Total: 2}, InodeUsage: boshstats.Usage{Used: 3, Total: 4}, }, }, } service = NewService(statsCollector, dirProvider) statsCollector.StartCollecting(1*time.Millisecond, nil) return }
func (p *FakePlatform) GetDirProvider() (dirProvider boshdir.Provider) { return boshdir.NewProvider("/var/vcap") }
func describeDrbd() { var ( dualDCSupport *DualDCSupport cmdRunner *fakesys.FakeCmdRunner fs *fakesys.FakeFileSystem dirProvider boshdir.Provider specService *fakeas.FakeV1Service settingsService *fakesettings.FakeSettingsService logger boshlog.Logger spec boshas.V1ApplySpec ) BeforeEach(func() { fs = fakesys.NewFakeFileSystem() cmdRunner = fakesys.NewFakeCmdRunner() specService = fakeas.NewFakeV1Service() settingsService = &fakesettings.FakeSettingsService{} dirProvider = boshdir.NewProvider("/var/vcap") logger = boshlog.NewLogger(boshlog.LevelNone) dualDCSupport = NewDualDCSupport( cmdRunner, fs, dirProvider, specService, settingsService, logger, ) spec = boshas.V1ApplySpec{} spec.DrbdEnabled = true spec.Passive = "enabled" specService.Spec = spec }) Context("DNS updates", func() { It("", func() { s, e := specService.Get() fmt.Printf("spec: %#v, err: %v", s, e) }) }) Describe("Drbd", func() { It("renders config file", func() { expectedOutput := ` resource r0 { net { protocol A; shared-secret OIUncfjJsbhInuic1243d; verify-alg sha1; } disk { resync-rate 24M; } handlers { before-resync-target "/lib/drbd/snapshot-resync-target-lvm.sh"; after-resync-target "/lib/drbd/unsnapshot-resync-target-lvm.sh"; } startup { wfc-timeout 3; degr-wfc-timeout 3; outdated-wfc-timeout 2; } on dff85535-580a-4bfb-bf49-5efbc017b5bb { device drbd1; disk /dev/mapper/vgStoreData-StoreData; address 10.76.245.71:7789; meta-disk internal; } on host2 { device drbd1; disk /dev/mapper/vgStoreData-StoreData; address 10.92.245.71:7789; meta-disk internal; } } ` // TODO: fix the test - sort out the fakes // out := drbdConfig("A", "OIUncfjJsbhInuic1243d", "dff85535-580a-4bfb-bf49-5efbc017b5bb", "10.76.245.71", "10.92.245.71") Expect("").NotTo(Equal(expectedOutput)) }) }) }
func describeDummyPlatform() { var ( platform Platform collector boshstats.Collector fs boshsys.FileSystem cmdRunner boshsys.CmdRunner dirProvider boshdirs.Provider devicePathResolver boshdpresolv.DevicePathResolver logger boshlog.Logger ) BeforeEach(func() { collector = &fakestats.FakeCollector{} fs = fakesys.NewFakeFileSystem() cmdRunner = fakesys.NewFakeCmdRunner() dirProvider = boshdirs.NewProvider("/fake-dir") devicePathResolver = fakedpresolv.NewFakeDevicePathResolver() logger = boshlog.NewLogger(boshlog.LevelNone) }) JustBeforeEach(func() { platform = NewDummyPlatform( collector, fs, cmdRunner, dirProvider, devicePathResolver, logger, ) }) Describe("GetDefaultNetwork", func() { It("returns the contents of dummy-defaults-network-settings.json since that's what the dummy cpi writes", func() { settingsFilePath := "/fake-dir/bosh/dummy-default-network-settings.json" fs.WriteFileString(settingsFilePath, `{"IP": "1.2.3.4"}`) network, err := platform.GetDefaultNetwork() Expect(err).NotTo(HaveOccurred()) Expect(network.IP).To(Equal("1.2.3.4")) }) }) Describe("GetCertManager", func() { It("returs a dummy cert manager", func() { certManager := platform.GetCertManager() Expect(certManager.UpdateCertificates("")).Should(BeNil()) }) }) Describe("UnmountPersistentDisk", func() { Context("when there are two mounted persistent disks in the mounts json", func() { BeforeEach(func() { var mounts []mount mounts = append(mounts, mount{MountDir: "dir1", DiskCid: "cid1"}) mounts = append(mounts, mount{MountDir: "dir2", DiskCid: "cid2"}) mountsJSON, _ := json.Marshal(mounts) mountsPath := path.Join(dirProvider.BoshDir(), "mounts.json") fs.WriteFile(mountsPath, mountsJSON) }) It("removes one of the disks from the mounts json", func() { unmounted, err := platform.UnmountPersistentDisk(settings.DiskSettings{ID: "cid1"}) Expect(err).NotTo(HaveOccurred()) Expect(unmounted).To(Equal(true)) Expect(platform.IsMountPoint("dir1")).To(Equal(false)) Expect(platform.IsMountPoint("dir2")).To(Equal(true)) }) }) }) }
func init() { Describe("provider", func() { var ( platform *fakeplatform.FakePlatform client *fakemonit.FakeMonitClient logger boshlog.Logger dirProvider boshdir.Provider jobFailuresServerPort int handler *fakembus.FakeHandler provider Provider timeService clock.Clock ) BeforeEach(func() { platform = fakeplatform.NewFakePlatform() client = fakemonit.NewFakeMonitClient() logger = boshlog.NewLogger(boshlog.LevelNone) dirProvider = boshdir.NewProvider("/fake-base-dir") jobFailuresServerPort = 2825 handler = &fakembus.FakeHandler{} timeService = clock.NewClock() provider = NewProvider( platform, client, logger, dirProvider, handler, ) }) It("provides a monit job supervisor", func() { actualSupervisor, err := provider.Get("monit") Expect(err).ToNot(HaveOccurred()) expectedSupervisor := NewMonitJobSupervisor( platform.Fs, platform.Runner, client, logger, dirProvider, jobFailuresServerPort, MonitReloadOptions{ MaxTries: 3, MaxCheckTries: 6, DelayBetweenCheckTries: 5 * time.Second, }, timeService, ) Expect(actualSupervisor).To(Equal(expectedSupervisor)) }) It("provides a dummy job supervisor", func() { actualSupervisor, err := provider.Get("dummy") Expect(err).ToNot(HaveOccurred()) expectedSupervisor := NewDummyJobSupervisor() Expect(actualSupervisor).To(Equal(expectedSupervisor)) }) It("provides a dummy nats job supervisor", func() { actualSupervisor, err := provider.Get("dummy-nats") Expect(err).NotTo(HaveOccurred()) expectedSupervisor := NewDummyNatsJobSupervisor(handler) Expect(actualSupervisor).To(Equal(expectedSupervisor)) }) It("returns an error when the supervisor is not found", func() { _, err := provider.Get("does-not-exist") Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("does-not-exist could not be found")) }) }) }
) var _ = Describe("HandlerProvider", func() { var ( settingsService *fakesettings.FakeSettingsService platform *fakeplatform.FakePlatform dirProvider boshdir.Provider logger boshlog.Logger provider HandlerProvider ) BeforeEach(func() { settingsService = &fakesettings.FakeSettingsService{} logger = boshlog.NewLogger(boshlog.LevelNone) platform = fakeplatform.NewFakePlatform() dirProvider = boshdir.NewProvider("/var/vcap") provider = NewHandlerProvider(settingsService, logger) }) Describe("Get", func() { It("returns nats handler", func() { settingsService.Settings.Mbus = "nats://lol" handler, err := provider.Get(platform, dirProvider) Expect(err).ToNot(HaveOccurred()) // yagnats.NewClient returns new object every time expectedHandler := NewNatsHandler(settingsService, yagnats.NewClient(), logger) Expect(reflect.TypeOf(handler)).To(Equal(reflect.TypeOf(expectedHandler))) }) It("returns https handler", func() {
func init() { Describe("ApplyAction", func() { var ( applier *fakeappl.FakeApplier specService *fakeas.FakeV1Service settingsService *fakesettings.FakeSettingsService dirProvider boshdir.Provider action ApplyAction fs boshsys.FileSystem ) BeforeEach(func() { applier = fakeappl.NewFakeApplier() specService = fakeas.NewFakeV1Service() settingsService = &fakesettings.FakeSettingsService{} dirProvider = boshdir.NewProvider("/var/vcap") fs = fakesys.NewFakeFileSystem() action = NewApply(applier, specService, settingsService, dirProvider.InstanceDir(), fs) }) It("apply should be asynchronous", func() { Expect(action.IsAsynchronous()).To(BeTrue()) }) It("is not persistent", func() { Expect(action.IsPersistent()).To(BeFalse()) }) Describe("Run", func() { settings := boshsettings.Settings{AgentID: "fake-agent-id"} BeforeEach(func() { settingsService.Settings = settings }) Context("when desired spec has configuration hash", func() { currentApplySpec := boshas.V1ApplySpec{ConfigurationHash: "fake-current-config-hash"} desiredApplySpec := boshas.V1ApplySpec{ConfigurationHash: "fake-desired-config-hash"} populatedDesiredApplySpec := boshas.V1ApplySpec{ ConfigurationHash: "fake-populated-desired-config-hash", } Context("when current spec can be retrieved", func() { BeforeEach(func() { specService.Spec = currentApplySpec }) It("populates dynamic networks in desired spec", func() { _, err := action.Run(desiredApplySpec) Expect(err).ToNot(HaveOccurred()) Expect(specService.PopulateDHCPNetworksSpec).To(Equal(desiredApplySpec)) Expect(specService.PopulateDHCPNetworksSettings).To(Equal(settings)) }) Context("when resolving dynamic networks succeeds", func() { BeforeEach(func() { specService.PopulateDHCPNetworksResultSpec = populatedDesiredApplySpec }) It("runs applier with populated desired spec", func() { _, err := action.Run(desiredApplySpec) Expect(err).ToNot(HaveOccurred()) Expect(applier.Applied).To(BeTrue()) Expect(applier.ApplyCurrentApplySpec).To(Equal(currentApplySpec)) Expect(applier.ApplyDesiredApplySpec).To(Equal(populatedDesiredApplySpec)) }) Context("when applier succeeds applying desired spec", func() { Context("when saving desires spec as current spec succeeds", func() { It("returns 'applied' after setting populated desired spec as current spec", func() { value, err := action.Run(desiredApplySpec) Expect(err).ToNot(HaveOccurred()) Expect(value).To(Equal("applied")) Expect(specService.Spec).To(Equal(populatedDesiredApplySpec)) }) Context("desired spec has id, instance name, deployment name, and az", func() { BeforeEach(func() { desiredApplySpec = boshas.V1ApplySpec{ConfigurationHash: "fake-desired-config-hash", NodeID: "node-id01-123f-r2344", AvailabilityZone: "ex-az", Deployment: "deployment-name", Name: "instance-name"} specService.PopulateDHCPNetworksResultSpec = desiredApplySpec }) It("returns 'applied' and writes the id, instance name, deployment name, and az to files in the instance directory", func() { value, err := action.Run(desiredApplySpec) Expect(err).ToNot(HaveOccurred()) Expect(value).To(Equal("applied")) instanceDir := dirProvider.InstanceDir() id, err := fs.ReadFileString(path.Join(instanceDir, "id")) Expect(err).ToNot(HaveOccurred()) Expect(id).To(Equal(desiredApplySpec.NodeID)) az, err := fs.ReadFileString(path.Join(instanceDir, "az")) Expect(err).ToNot(HaveOccurred()) Expect(az).To(Equal(desiredApplySpec.AvailabilityZone)) instanceName, err := fs.ReadFileString(path.Join(instanceDir, "name")) Expect(err).ToNot(HaveOccurred()) Expect(instanceName).To(Equal(desiredApplySpec.Name)) deploymentName, err := fs.ReadFileString(path.Join(instanceDir, "deployment")) Expect(err).ToNot(HaveOccurred()) Expect(deploymentName).To(Equal(desiredApplySpec.Deployment)) }) }) }) Context("when saving populated desires spec as current spec fails", func() { It("returns error because agent was not able to remember that is converged to desired spec", func() { specService.SetErr = errors.New("fake-set-error") _, err := action.Run(desiredApplySpec) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-set-error")) }) }) }) Context("when applier fails applying desired spec", func() { BeforeEach(func() { applier.ApplyError = errors.New("fake-apply-error") }) It("returns error", func() { _, err := action.Run(desiredApplySpec) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-apply-error")) }) It("does not save desired spec as current spec", func() { _, err := action.Run(desiredApplySpec) Expect(err).To(HaveOccurred()) Expect(specService.Spec).To(Equal(currentApplySpec)) }) }) }) Context("when resolving dynamic networks fails", func() { BeforeEach(func() { specService.PopulateDHCPNetworksErr = errors.New("fake-populate-dynamic-networks-err") }) It("returns error", func() { _, err := action.Run(desiredApplySpec) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-populate-dynamic-networks-err")) }) It("does not apply desired spec as current spec", func() { _, err := action.Run(desiredApplySpec) Expect(err).To(HaveOccurred()) Expect(applier.Applied).To(BeFalse()) }) It("does not save desired spec as current spec", func() { _, err := action.Run(desiredApplySpec) Expect(err).To(HaveOccurred()) Expect(specService.Spec).To(Equal(currentApplySpec)) }) }) }) Context("when current spec cannot be retrieved", func() { BeforeEach(func() { specService.Spec = currentApplySpec specService.GetErr = errors.New("fake-get-error") }) It("returns error and does not apply desired spec", func() { _, err := action.Run(desiredApplySpec) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-get-error")) }) It("does not run applier with desired spec", func() { _, err := action.Run(desiredApplySpec) Expect(err).To(HaveOccurred()) Expect(applier.Applied).To(BeFalse()) }) It("does not save desired spec as current spec", func() { _, err := action.Run(desiredApplySpec) Expect(err).To(HaveOccurred()) Expect(specService.Spec).To(Equal(currentApplySpec)) }) }) }) Context("when desired spec does not have a configuration hash", func() { desiredApplySpec := boshas.V1ApplySpec{ JobSpec: boshas.JobSpec{ Template: "fake-job-template", }, } populatedDesiredApplySpec := boshas.V1ApplySpec{ JobSpec: boshas.JobSpec{ Template: "fake-populated-job-template", }, } It("populates dynamic networks in desired spec", func() { _, err := action.Run(desiredApplySpec) Expect(err).ToNot(HaveOccurred()) Expect(specService.PopulateDHCPNetworksSpec).To(Equal(desiredApplySpec)) Expect(specService.PopulateDHCPNetworksSettings).To(Equal(settings)) }) Context("when resolving dynamic networks succeeds", func() { BeforeEach(func() { specService.PopulateDHCPNetworksResultSpec = populatedDesiredApplySpec }) Context("when saving desires spec as current spec succeeds", func() { It("returns 'applied' after setting desired spec as current spec", func() { value, err := action.Run(desiredApplySpec) Expect(err).ToNot(HaveOccurred()) Expect(value).To(Equal("applied")) Expect(specService.Spec).To(Equal(populatedDesiredApplySpec)) }) It("does not try to apply desired spec since it does not have jobs and packages", func() { _, err := action.Run(desiredApplySpec) Expect(err).ToNot(HaveOccurred()) Expect(applier.Applied).To(BeFalse()) }) }) Context("when saving desires spec as current spec fails", func() { BeforeEach(func() { specService.SetErr = errors.New("fake-set-error") }) It("returns error because agent was not able to remember that is converged to desired spec", func() { _, err := action.Run(desiredApplySpec) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-set-error")) }) It("does not try to apply desired spec since it does not have jobs and packages", func() { _, err := action.Run(desiredApplySpec) Expect(err).To(HaveOccurred()) Expect(applier.Applied).To(BeFalse()) }) }) }) Context("when resolving dynamic networks fails", func() { BeforeEach(func() { specService.PopulateDHCPNetworksErr = errors.New("fake-populate-dynamic-networks-err") }) It("returns error", func() { _, err := action.Run(desiredApplySpec) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-populate-dynamic-networks-err")) }) It("does not apply desired spec as current spec", func() { _, err := action.Run(desiredApplySpec) Expect(err).To(HaveOccurred()) Expect(applier.Applied).To(BeFalse()) }) It("does not save desired spec as current spec", func() { _, err := action.Run(desiredApplySpec) Expect(err).To(HaveOccurred()) Expect(specService.Spec).ToNot(Equal(desiredApplySpec)) }) }) }) }) }) }
binPath := filepath.Join(basePath, "bosh", "bin") fs.MkdirAll(binPath, 0755) logDir = path.Join(basePath, "sys", "log") fs.MkdirAll(binPath, 0755) exePath = filepath.Join(binPath, "job-service-wrapper.exe") err = fs.CopyFile(testExtPath, exePath) Expect(err).ToNot(HaveOccurred()) logDir = path.Join(basePath, "sys", "log") }) WriteJobConfig := func(configContents WindowsProcessConfig) (string, error) { dirProvider := boshdirs.NewProvider(basePath) runner = boshsys.NewExecCmdRunner(logger) jobSupervisor = NewWindowsJobSupervisor(runner, dirProvider, fs, logger, jobFailuresServerPort, make(chan bool), DefaultMachineIP) if err := jobSupervisor.RemoveAllJobs(); err != nil { return "", err } processConfigContents, err := json.Marshal(configContents) if err != nil { return "", err } jobDir, err = fs.TempDir("testWindowsJobSupervisor") processConfigPath = filepath.Join(jobDir, "monit") err = fs.WriteFile(processConfigPath, processConfigContents)
fakescript "github.com/cloudfoundry/bosh-agent/agent/script/fakes" boshdir "github.com/cloudfoundry/bosh-agent/settings/directories" boshlog "github.com/cloudfoundry/bosh-utils/logger" fakesys "github.com/cloudfoundry/bosh-utils/system/fakes" ) var _ = Describe("ConcreteJobScriptProvider", func() { var ( logger boshlog.Logger scriptProvider boshscript.ConcreteJobScriptProvider ) BeforeEach(func() { runner := fakesys.NewFakeCmdRunner() fs := fakesys.NewFakeFileSystem() dirProvider := boshdir.NewProvider("/the/base/dir") logger = boshlog.NewLogger(boshlog.LevelNone) scriptProvider = boshscript.NewConcreteJobScriptProvider( runner, fs, dirProvider, &fakesys.FakeCommandFactory{}, &fakeaction.FakeClock{}, logger, ) }) Describe("NewScript", func() { It("returns script with relative job paths to the base directory", func() { script := scriptProvider.NewScript("myjob", "the-best-hook-ever") Expect(script.Tag()).To(Equal("myjob"))
func describeDummyPlatform() { var ( platform Platform collector boshstats.Collector fs *fakesys.FakeFileSystem cmdRunner boshsys.CmdRunner dirProvider boshdirs.Provider devicePathResolver boshdpresolv.DevicePathResolver logger boshlog.Logger ) BeforeEach(func() { collector = &fakestats.FakeCollector{} fs = fakesys.NewFakeFileSystem() cmdRunner = fakesys.NewFakeCmdRunner() dirProvider = boshdirs.NewProvider("/fake-dir") devicePathResolver = fakedpresolv.NewFakeDevicePathResolver() logger = boshlog.NewLogger(boshlog.LevelNone) }) JustBeforeEach(func() { platform = NewDummyPlatform( collector, fs, cmdRunner, dirProvider, devicePathResolver, logger, ) }) Describe("GetDefaultNetwork", func() { It("returns the contents of dummy-defaults-network-settings.json since that's what the dummy cpi writes", func() { settingsFilePath := "/fake-dir/bosh/dummy-default-network-settings.json" fs.WriteFileString(settingsFilePath, `{"IP": "1.2.3.4"}`) network, err := platform.GetDefaultNetwork() Expect(err).NotTo(HaveOccurred()) Expect(network.IP).To(Equal("1.2.3.4")) }) }) Describe("GetCertManager", func() { It("returns a dummy cert manager", func() { certManager := platform.GetCertManager() Expect(certManager.UpdateCertificates("")).Should(BeNil()) }) }) Describe("MountPersistentDisk", func() { var diskSettings boshsettings.DiskSettings var mountsPath, managedSettingsPath, formattedDisksPath string BeforeEach(func() { diskSettings = boshsettings.DiskSettings{ID: "somediskid"} mountsPath = filepath.Join(dirProvider.BoshDir(), "mounts.json") managedSettingsPath = filepath.Join(dirProvider.BoshDir(), "managed_disk_settings.json") formattedDisksPath = filepath.Join(dirProvider.BoshDir(), "formatted_disks.json") }) It("Mounts a persistent disk", func() { mountsContent, _ := fs.ReadFileString(mountsPath) Expect(mountsContent).To(Equal("")) err := platform.MountPersistentDisk(diskSettings, "/dev/potato") Expect(err).NotTo(HaveOccurred()) mountsContent, _ = fs.ReadFileString(mountsPath) Expect(mountsContent).To(Equal(`[{"MountDir":"/dev/potato","DiskCid":"somediskid"}]`)) }) It("Updates the managed disk settings", func() { lastMountedCid, _ := fs.ReadFileString(managedSettingsPath) Expect(lastMountedCid).To(Equal("")) err := platform.MountPersistentDisk(diskSettings, "/dev/potato") Expect(err).NotTo(HaveOccurred()) lastMountedCid, _ = fs.ReadFileString(managedSettingsPath) Expect(lastMountedCid).To(Equal("somediskid")) }) It("Updates the formatted disks", func() { formattedDisks, _ := fs.ReadFileString(formattedDisksPath) Expect(formattedDisks).To(Equal("")) err := platform.MountPersistentDisk(diskSettings, "/dev/potato") Expect(err).NotTo(HaveOccurred()) formattedDisks, _ = fs.ReadFileString(formattedDisksPath) Expect(formattedDisks).To(Equal(`[{"DiskCid":"somediskid"}]`)) }) Context("Device has already been mounted as expected", func() { BeforeEach(func() { fs.WriteFileString(managedSettingsPath, "somediskid") fs.WriteFileString(mountsPath, `[{"MountDir":"/dev/potato","DiskCid":"somediskid"}]`) }) It("Does not mount in new location", func() { err := platform.MountPersistentDisk(diskSettings, "/dev/potato") Expect(err).NotTo(HaveOccurred()) mountsContent, _ := fs.ReadFileString(mountsPath) Expect(mountsContent).To(Equal(`[{"MountDir":"/dev/potato","DiskCid":"somediskid"}]`)) }) }) }) Describe("UnmountPersistentDisk", func() { Context("when there are two mounted persistent disks in the mounts json", func() { BeforeEach(func() { var mounts []mount mounts = append(mounts, mount{MountDir: "dir1", DiskCid: "cid1"}) mounts = append(mounts, mount{MountDir: "dir2", DiskCid: "cid2"}) mountsJSON, err := json.Marshal(mounts) Expect(err).NotTo(HaveOccurred()) mountsPath := filepath.Join(dirProvider.BoshDir(), "mounts.json") fs.WriteFile(mountsPath, mountsJSON) }) It("removes one of the disks from the mounts json", func() { unmounted, err := platform.UnmountPersistentDisk(settings.DiskSettings{ID: "cid1"}) Expect(err).NotTo(HaveOccurred()) Expect(unmounted).To(Equal(true)) _, isMountPoint, err := platform.IsMountPoint("dir1") Expect(err).NotTo(HaveOccurred()) Expect(isMountPoint).To(Equal(false)) _, isMountPoint, err = platform.IsMountPoint("dir2") Expect(err).NotTo(HaveOccurred()) Expect(isMountPoint).To(Equal(true)) }) }) }) Describe("SetDiskAssociations", func() { It("writes the associations to the file", func() { diskName1 := "disk1" diskName2 := "disk2" err := platform.AssociateDisk(diskName1, boshsettings.DiskSettings{}) Expect(err).NotTo(HaveOccurred()) err = platform.AssociateDisk(diskName2, boshsettings.DiskSettings{}) Expect(err).NotTo(HaveOccurred()) diskAssociationsPath := filepath.Join(dirProvider.BoshDir(), "disk_associations.json") actualDiskNames := []string{} fileContent, err := fs.ReadFile(diskAssociationsPath) Expect(err).NotTo(HaveOccurred()) err = json.Unmarshal(fileContent, &actualDiskNames) Expect(err).NotTo(HaveOccurred()) Expect(actualDiskNames).To(ConsistOf([]string{ diskName1, diskName2, })) }) }) Describe("IsPersistentDiskMountable", func() { BeforeEach(func() { formattedDisksPath := filepath.Join(dirProvider.BoshDir(), "formatted_disks.json") fs.WriteFileString(formattedDisksPath, `[{"DiskCid": "my-disk-id"}]`) }) Context("when disk has been formatted", func() { It("returns true with no error", func() { diskSettings := boshsettings.DiskSettings{ID: "my-disk-id"} mountable, err := platform.IsPersistentDiskMountable(diskSettings) Expect(err).ToNot(HaveOccurred()) Expect(mountable).To(Equal(true)) }) }) Context("when disk has NOT been formatted", func() { It("returns false with no error", func() { diskSettings := boshsettings.DiskSettings{ID: "some-other-disk-id"} mountable, err := platform.IsPersistentDiskMountable(diskSettings) Expect(err).ToNot(HaveOccurred()) Expect(mountable).To(Equal(false)) }) }) }) Describe("SetUserPassword", func() { It("writes the password to a file", func() { err := platform.SetUserPassword("user-name", "fake-password") Expect(err).NotTo(HaveOccurred()) userPasswordsPath := filepath.Join(dirProvider.BoshDir(), "user-name", CredentialFileName) password, err := fs.ReadFileString(userPasswordsPath) Expect(err).NotTo(HaveOccurred()) Expect(password).To(Equal("fake-password")) }) It("writes the passwords to different files for each user", func() { err := platform.SetUserPassword("user-name1", "fake-password1") Expect(err).NotTo(HaveOccurred()) err = platform.SetUserPassword("user-name2", "fake-password2") Expect(err).NotTo(HaveOccurred()) userPasswordsPath := filepath.Join(dirProvider.BoshDir(), "user-name1", CredentialFileName) password, err := fs.ReadFileString(userPasswordsPath) Expect(err).NotTo(HaveOccurred()) Expect(password).To(Equal("fake-password1")) userPasswordsPath = filepath.Join(dirProvider.BoshDir(), "user-name2", CredentialFileName) password, err = fs.ReadFileString(userPasswordsPath) Expect(err).NotTo(HaveOccurred()) Expect(password).To(Equal("fake-password2")) }) }) Describe("SetupDataDir", func() { It("creates a link from BASEDIR/sys to BASEDIR/data/sys", func() { err := platform.SetupDataDir() Expect(err).NotTo(HaveOccurred()) stat := fs.GetFileTestStat(filepath.Clean("/fake-dir/sys")) Expect(stat).ToNot(BeNil()) Expect(stat.SymlinkTarget).To(Equal("/fake-dir/data/sys")) }) }) Describe("SetupBlobsDir", func() { It("creates a blobs folder under BASEDIR/DATADIR with correct permissions", func() { err := platform.SetupBlobsDir() Expect(err).NotTo(HaveOccurred()) stat := fs.GetFileTestStat(filepath.Clean("/fake-dir/data/blobs")) Expect(stat.FileType).To(Equal(fakesys.FakeFileTypeDir)) Expect(stat.FileMode).To(Equal(os.FileMode(0700))) }) }) }
func init() { Describe("concreteApplier", func() { var ( jobApplier *fakejobs.FakeApplier packageApplier *fakepackages.FakeApplier logRotateDelegate *FakeLogRotateDelegate jobSupervisor *fakejobsuper.FakeJobSupervisor applier Applier ) BeforeEach(func() { jobApplier = fakejobs.NewFakeApplier() packageApplier = fakepackages.NewFakeApplier() logRotateDelegate = &FakeLogRotateDelegate{} jobSupervisor = fakejobsuper.NewFakeJobSupervisor() applier = NewConcreteApplier( jobApplier, packageApplier, logRotateDelegate, jobSupervisor, boshdirs.NewProvider("/fake-base-dir"), ) }) Describe("Prepare", func() { It("prepares each jobs", func() { job := buildJob() err := applier.Prepare( &fakeas.FakeApplySpec{JobResults: []models.Job{job}}, ) Expect(err).ToNot(HaveOccurred()) Expect(jobApplier.PreparedJobs).To(Equal([]models.Job{job})) }) It("returns error when preparing jobs fails", func() { job := buildJob() jobApplier.PrepareError = errors.New("fake-prepare-job-error") err := applier.Prepare( &fakeas.FakeApplySpec{JobResults: []models.Job{job}}, ) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-prepare-job-error")) }) It("prepares each packages", func() { pkg1 := buildPackage() pkg2 := buildPackage() err := applier.Prepare( &fakeas.FakeApplySpec{PackageResults: []models.Package{pkg1, pkg2}}, ) Expect(err).ToNot(HaveOccurred()) Expect(packageApplier.PreparedPackages).To(Equal([]models.Package{pkg1, pkg2})) }) It("returns error when preparing packages fails", func() { pkg := buildPackage() packageApplier.PrepareError = errors.New("fake-prepare-package-error") err := applier.Prepare( &fakeas.FakeApplySpec{PackageResults: []models.Package{pkg}}, ) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-prepare-package-error")) }) }) Describe("Configure jobs", func() { It("reloads job supervisor", func() { job1 := models.Job{Name: "fake-job-name-1", Version: "fake-version-name-1"} job2 := models.Job{Name: "fake-job-name-2", Version: "fake-version-name-2"} jobs := []models.Job{job1, job2} err := applier.ConfigureJobs(&fakeas.FakeApplySpec{JobResults: jobs}) Expect(err).ToNot(HaveOccurred()) Expect(jobSupervisor.Reloaded).To(BeTrue()) }) It("configures jobs", func() { job1 := models.Job{Name: "fake-job-name-1", Version: "fake-version-name-1"} job2 := models.Job{Name: "fake-job-name-2", Version: "fake-version-name-2"} jobs := []models.Job{job1, job2} err := applier.ConfigureJobs(&fakeas.FakeApplySpec{JobResults: jobs}) Expect(err).ToNot(HaveOccurred()) Expect(jobApplier.ConfiguredJobs).To(ConsistOf(job1, job2)) }) }) Describe("Apply", func() { It("removes all jobs from job supervisor", func() { err := applier.Apply(&fakeas.FakeApplySpec{}, &fakeas.FakeApplySpec{}) Expect(err).ToNot(HaveOccurred()) Expect(jobSupervisor.RemovedAllJobs).To(BeTrue()) }) It("removes all previous jobs from job supervisor before starting to apply jobs", func() { // force remove all error jobSupervisor.RemovedAllJobsErr = errors.New("fake-remove-all-jobs-error") job := buildJob() applier.Apply( &fakeas.FakeApplySpec{}, &fakeas.FakeApplySpec{JobResults: []models.Job{job}}, ) // check that jobs were not applied before removing all other jobs Expect(jobApplier.AppliedJobs).To(Equal([]models.Job{})) }) It("returns error if removing all jobs from job supervisor fails", func() { jobSupervisor.RemovedAllJobsErr = errors.New("fake-remove-all-jobs-error") err := applier.Apply(&fakeas.FakeApplySpec{}, &fakeas.FakeApplySpec{}) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-remove-all-jobs-error")) }) It("apply applies jobs", func() { job := buildJob() err := applier.Apply( &fakeas.FakeApplySpec{}, &fakeas.FakeApplySpec{JobResults: []models.Job{job}}, ) Expect(err).ToNot(HaveOccurred()) Expect(jobApplier.AppliedJobs).To(Equal([]models.Job{job})) }) It("apply errs when applying jobs errs", func() { job := buildJob() jobApplier.ApplyError = errors.New("fake-apply-job-error") err := applier.Apply( &fakeas.FakeApplySpec{}, &fakeas.FakeApplySpec{JobResults: []models.Job{job}}, ) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-apply-job-error")) }) It("asked jobApplier to keep only the jobs in the desired and current specs", func() { currentJob := buildJob() desiredJob := buildJob() err := applier.Apply( &fakeas.FakeApplySpec{JobResults: []models.Job{currentJob}}, &fakeas.FakeApplySpec{JobResults: []models.Job{desiredJob}}, ) Expect(err).ToNot(HaveOccurred()) Expect(jobApplier.KeepOnlyJobs).To(Equal([]models.Job{currentJob, desiredJob})) }) It("returns error when jobApplier fails to keep only the jobs in the desired and current specs", func() { jobApplier.KeepOnlyErr = errors.New("fake-keep-only-error") currentJob := buildJob() desiredJob := buildJob() err := applier.Apply( &fakeas.FakeApplySpec{JobResults: []models.Job{currentJob}}, &fakeas.FakeApplySpec{JobResults: []models.Job{desiredJob}}, ) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-keep-only-error")) }) It("apply applies packages", func() { pkg1 := buildPackage() pkg2 := buildPackage() err := applier.Apply( &fakeas.FakeApplySpec{}, &fakeas.FakeApplySpec{PackageResults: []models.Package{pkg1, pkg2}}, ) Expect(err).ToNot(HaveOccurred()) Expect(packageApplier.AppliedPackages).To(Equal([]models.Package{pkg1, pkg2})) }) It("apply errs when applying packages errs", func() { pkg := buildPackage() packageApplier.ApplyError = errors.New("fake-apply-package-error") err := applier.Apply( &fakeas.FakeApplySpec{}, &fakeas.FakeApplySpec{PackageResults: []models.Package{pkg}}, ) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-apply-package-error")) }) It("asked packageApplier to keep only the packages in the desired and current specs", func() { currentPkg := buildPackage() desiredPkg := buildPackage() err := applier.Apply( &fakeas.FakeApplySpec{PackageResults: []models.Package{currentPkg}}, &fakeas.FakeApplySpec{PackageResults: []models.Package{desiredPkg}}, ) Expect(err).ToNot(HaveOccurred()) Expect(packageApplier.KeptOnlyPackages).To(Equal([]models.Package{currentPkg, desiredPkg})) }) It("returns error when packageApplier fails to keep only the packages in the desired and current specs", func() { packageApplier.KeepOnlyErr = errors.New("fake-keep-only-error") currentPkg := buildPackage() desiredPkg := buildPackage() err := applier.Apply( &fakeas.FakeApplySpec{PackageResults: []models.Package{currentPkg}}, &fakeas.FakeApplySpec{PackageResults: []models.Package{desiredPkg}}, ) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-keep-only-error")) }) It("apply does not configure jobs", func() { job1 := models.Job{Name: "fake-job-name-1", Version: "fake-version-name-1"} job2 := models.Job{Name: "fake-job-name-2", Version: "fake-version-name-2"} jobs := []models.Job{job1, job2} err := applier.Apply(&fakeas.FakeApplySpec{}, &fakeas.FakeApplySpec{JobResults: jobs}) Expect(err).ToNot(HaveOccurred()) Expect(jobApplier.ConfiguredJobs).To(BeEmpty()) Expect(jobSupervisor.Reloaded).To(BeTrue()) }) It("apply errs if monitor fails reload", func() { jobs := []models.Job{} jobSupervisor.ReloadErr = errors.New("error reloading monit") err := applier.Apply(&fakeas.FakeApplySpec{}, &fakeas.FakeApplySpec{JobResults: jobs}) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("error reloading monit")) }) It("apply sets up logrotation", func() { err := applier.Apply( &fakeas.FakeApplySpec{}, &fakeas.FakeApplySpec{MaxLogFileSizeResult: "fake-size"}, ) Expect(err).ToNot(HaveOccurred()) assert.Equal(GinkgoT(), logRotateDelegate.SetupLogrotateArgs, SetupLogrotateArgs{ GroupName: boshsettings.VCAPUsername, BasePath: "/fake-base-dir", Size: "fake-size", }) }) It("apply errs if setup logrotate fails", func() { logRotateDelegate.SetupLogrotateErr = errors.New("fake-set-up-logrotate-error") err := applier.Apply(&fakeas.FakeApplySpec{}, &fakeas.FakeApplySpec{}) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-set-up-logrotate-error")) }) }) }) }
boshassert "github.com/cloudfoundry/bosh-utils/assert" boshlog "github.com/cloudfoundry/bosh-utils/logger" ) var _ = Describe("MountDiskAction", func() { var ( settingsService *fakesettings.FakeSettingsService platform *fakeplatform.FakePlatform action MountDiskAction logger boshlog.Logger ) BeforeEach(func() { settingsService = &fakesettings.FakeSettingsService{} platform = fakeplatform.NewFakePlatform() dirProvider := boshdirs.NewProvider("/fake-base-dir") logger = boshlog.NewLogger(boshlog.LevelNone) action = NewMountDisk(settingsService, platform, dirProvider, logger) }) AssertActionIsAsynchronous(action) AssertActionIsNotPersistent(action) AssertActionIsLoggable(action) AssertActionIsNotResumable(action) AssertActionIsNotCancelable(action) Describe("Run", func() { Context("when settings can be loaded", func() { Context("when disk cid can be resolved to a device path from infrastructure settings", func() { BeforeEach(func() {
func buildMigrateDiskAction() (platform *fakeplatform.FakePlatform, action MigrateDiskAction) { platform = fakeplatform.NewFakePlatform() dirProvider := boshdirs.NewProvider("/foo") action = NewMigrateDisk(platform, dirProvider) return }
specService, jobScriptProvider, logger, ) }) It("returns error if action cannot be created", func() { action, err := factory.Create("fake-unknown-action") Expect(err).To(HaveOccurred()) Expect(action).To(BeNil()) }) It("apply", func() { action, err := factory.Create("apply") Expect(err).ToNot(HaveOccurred()) Expect(action).To(Equal(NewApply(applier, specService, settingsService, boshdir.NewProvider("/var/vcap").InstanceDir(), platform.GetFs()))) }) It("drain", func() { action, err := factory.Create("drain") Expect(err).ToNot(HaveOccurred()) // Cannot do equality check since channel is used in initializer Expect(action).To(BeAssignableToTypeOf(DrainAction{})) }) It("fetch_logs", func() { action, err := factory.Create("fetch_logs") Expect(err).ToNot(HaveOccurred()) Expect(action).To(Equal(NewFetchLogs(platform.GetCompressor(), platform.GetCopier(), blobstore, platform.GetDirProvider()))) })
func init() { Describe("App", func() { var ( baseDir string agentConfPath string agentConfJSON string app App ) BeforeEach(func() { var err error baseDir, err = ioutil.TempDir("", "go-agent-test") Expect(err).ToNot(HaveOccurred()) err = os.Mkdir(filepath.Join(baseDir, "bosh"), os.ModePerm) Expect(err).ToNot(HaveOccurred()) }) BeforeEach(func() { agentConfPath = filepath.Join(baseDir, "bosh", "agent.json") agentConfJSON = `{ "Infrastructure": { "Settings": { "Sources": [{ "Type": "CDROM", "FileName": "/fake-file-name" }] } } }` settingsPath := filepath.Join(baseDir, "bosh", "settings.json") settingsJSON := `{ "agent_id": "my-agent-id", "blobstore": { "options": { "bucket_name": "george", "encryption_key": "optional encryption key", "access_key_id": "optional access key id", "secret_access_key": "optional secret access key" }, "provider": "dummy" }, "disks": { "ephemeral": "/dev/sdb", "persistent": { "vol-xxxxxx": "/dev/sdf" }, "system": "/dev/sda1" }, "env": { "bosh": { "password": "******" } }, "networks": { "netA": { "default": ["dns", "gateway"], "ip": "ww.ww.ww.ww", "dns": [ "xx.xx.xx.xx", "yy.yy.yy.yy" ] }, "netB": { "dns": [ "zz.zz.zz.zz" ] } }, "Mbus": "https://*****:*****@0.0.0.0:6868", "ntp": [ "0.north-america.pool.ntp.org", "1.north-america.pool.ntp.org" ], "vm": { "name": "vm-abc-def" } }` err := ioutil.WriteFile(settingsPath, []byte(settingsJSON), 0640) Expect(err).ToNot(HaveOccurred()) }) JustBeforeEach(func() { err := ioutil.WriteFile(agentConfPath, []byte(agentConfJSON), 0640) Expect(err).ToNot(HaveOccurred()) logger := boshlog.NewLogger(boshlog.LevelNone) fakefs := boshsys.NewOsFileSystem(logger) app = New(logger, fakefs) }) AfterEach(func() { os.RemoveAll(baseDir) }) It("Sets up device path resolver on platform specific to infrastructure", func() { err := app.Setup([]string{"bosh-agent", "-P", "dummy", "-C", agentConfPath, "-b", baseDir}) Expect(err).ToNot(HaveOccurred()) Expect(app.GetPlatform().GetDevicePathResolver()).To(Equal(devicepathresolver.NewIdentityDevicePathResolver())) }) Context("when DevicePathResolutionType is 'virtio'", func() { BeforeEach(func() { agentConfJSON = `{ "Platform": { "Linux": { "DevicePathResolutionType": "virtio" } }, "Infrastructure": { "Settings": { "Sources": [{ "Type": "CDROM", "FileName": "/fake-file-name" }] } } }` }) It("uses a VirtioDevicePathResolver", func() { err := app.Setup([]string{"bosh-agent", "-P", "dummy", "-C", agentConfPath, "-b", baseDir}) Expect(err).ToNot(HaveOccurred()) logLevel, err := boshlog.Levelify("DEBUG") Expect(err).NotTo(HaveOccurred()) Expect(app.GetPlatform().GetDevicePathResolver()).To( BeAssignableToTypeOf(devicepathresolver.NewVirtioDevicePathResolver(nil, nil, boshlog.NewLogger(logLevel)))) }) }) Context("when DevicePathResolutionType is 'scsi'", func() { BeforeEach(func() { agentConfJSON = `{ "Platform": { "Linux": { "DevicePathResolutionType": "scsi" } }, "Infrastructure": { "Settings": { "Sources": [{ "Type": "CDROM", "FileName": "/fake-file-name" }] } } }` }) It("uses a VirtioDevicePathResolver", func() { err := app.Setup([]string{"bosh-agent", "-P", "dummy", "-C", agentConfPath, "-b", baseDir}) Expect(err).ToNot(HaveOccurred()) Expect(app.GetPlatform().GetDevicePathResolver()).To( BeAssignableToTypeOf(devicepathresolver.NewScsiDevicePathResolver(nil, nil, nil))) }) }) Context("logging stemcell version and git sha", func() { var ( logger boshlog.Logger outBuf *bytes.Buffer fakeFs boshsys.FileSystem stemcellVersionFilePath string stemcellSha1FilePath string ) JustBeforeEach(func() { outBuf = bytes.NewBufferString("") errBuf := bytes.NewBufferString("") logger = boshlog.NewWriterLogger(boshlog.LevelDebug, outBuf, errBuf) fakeFs = fakesys.NewFakeFileSystem() dirProvider := boshdirs.NewProvider(baseDir) stemcellVersionFilePath = filepath.Join(dirProvider.EtcDir(), "stemcell_version") stemcellSha1FilePath = filepath.Join(dirProvider.EtcDir(), "stemcell_git_sha1") app = New(logger, fakeFs) }) Context("when stemcell version and sha files are present", func() { It("should print out the stemcell version and sha in the logs", func() { fakeFs.WriteFileString(stemcellVersionFilePath, "version-blah") fakeFs.WriteFileString(stemcellSha1FilePath, "sha1-blah") app.Setup([]string{"bosh-agent", "-P", "dummy", "-C", agentConfPath, "-b", baseDir}) Expect(string(outBuf.Bytes())).To(ContainSubstring("Running on stemcell version 'version-blah' (git: sha1-blah)")) }) }) Context("when stemcell version file is NOT present", func() { It("should print out the sha in the logs", func() { fakeFs.WriteFileString(stemcellSha1FilePath, "sha1-blah") app.Setup([]string{"bosh-agent", "-P", "dummy", "-C", agentConfPath, "-b", baseDir}) Expect(string(outBuf.Bytes())).To(ContainSubstring("Running on stemcell version '?' (git: sha1-blah)")) }) }) Context("when sha version file is NOT present", func() { It("should print out the stemcell version in the logs", func() { fakeFs.WriteFileString(stemcellVersionFilePath, "version-blah") app.Setup([]string{"bosh-agent", "-P", "dummy", "-C", agentConfPath, "-b", baseDir}) Expect(string(outBuf.Bytes())).To(ContainSubstring("Running on stemcell version 'version-blah' (git: ?)")) }) }) Context("when stemcell version file is empty", func() { It("should print out the sha in the logs", func() { fakeFs.WriteFileString(stemcellVersionFilePath, "") fakeFs.WriteFileString(stemcellSha1FilePath, "sha1-blah") app.Setup([]string{"bosh-agent", "-P", "dummy", "-C", agentConfPath, "-b", baseDir}) Expect(string(outBuf.Bytes())).To(ContainSubstring("Running on stemcell version '?' (git: sha1-blah)")) }) }) Context("when sha version file is empty", func() { It("should print out the stemcell version in the logs", func() { fakeFs.WriteFileString(stemcellVersionFilePath, "version-blah") fakeFs.WriteFileString(stemcellSha1FilePath, "") app.Setup([]string{"bosh-agent", "-P", "dummy", "-C", agentConfPath, "-b", baseDir}) Expect(string(outBuf.Bytes())).To(ContainSubstring("Running on stemcell version 'version-blah' (git: ?)")) }) }) Context("when stemcell version and sha files are NOT present", func() { It("should print unknown version and sha in the logs", func() { app.Setup([]string{"bosh-agent", "-P", "dummy", "-C", agentConfPath, "-b", baseDir}) Expect(string(outBuf.Bytes())).To(ContainSubstring("Running on stemcell version '?' (git: ?)")) }) }) }) }) }
}` var tempDir string var dirProvider boshdir.Provider var fs boshsys.FileSystem BeforeEach(func() { if runtime.GOOS != "windows" { Skip("Only run on Windows") } fs = boshsys.NewOsFileSystem(log) var err error tempDir, err = fs.TempDir("") Expect(err).To(BeNil()) dirProvider = boshdir.NewProvider(tempDir) certManager = cert.NewWindowsCertManager(fs, boshsys.NewExecCmdRunner(log), dirProvider, log) }) AfterEach(func() { for _, thumbprint := range certThumbprints { cmd := exec.Command("powershell", "-Command", fmt.Sprintf(removeCertScript, `Cert:\LocalMachine\Root\`+thumbprint)) session, err := gexec.Start(cmd, GinkgoWriter, GinkgoWriter) Expect(err).To(BeNil()) Eventually(session).Should(gexec.Exit(0)) } os.RemoveAll(tempDir) }) It("should create the tmpDir if doesn't exist", func() { _, err := os.Stat(dirProvider.TmpDir())
func init() { Describe("bootstrap", func() { Describe("Run", func() { var ( platform *fakeplatform.FakePlatform dirProvider boshdir.Provider settingsSource *fakeinf.FakeSettingsSource settingsService *fakesettings.FakeSettingsService ) BeforeEach(func() { platform = fakeplatform.NewFakePlatform() dirProvider = boshdir.NewProvider("/var/vcap") settingsSource = &fakeinf.FakeSettingsSource{} settingsService = &fakesettings.FakeSettingsService{} }) bootstrap := func() error { logger := boshlog.NewLogger(boshlog.LevelNone) return NewBootstrap(platform, dirProvider, settingsService, logger).Run() } It("sets up runtime configuration", func() { err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(platform.SetupRuntimeConfigurationWasInvoked).To(BeTrue()) }) Describe("SSH tunnel setup for registry", func() { It("returns error without configuring ssh on the platform if getting public key fails", func() { settingsService.PublicKeyErr = errors.New("fake-get-public-key-err") err := bootstrap() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-get-public-key-err")) Expect(platform.SetupSSHCalled).To(BeFalse()) }) Context("when public key is not empty", func() { BeforeEach(func() { settingsService.PublicKey = "fake-public-key" }) It("gets the public key and sets up ssh via the platform", func() { err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(platform.SetupSSHPublicKey).To(Equal("fake-public-key")) Expect(platform.SetupSSHUsername).To(Equal("vcap")) }) It("returns error if configuring ssh on the platform fails", func() { platform.SetupSSHErr = errors.New("fake-setup-ssh-err") err := bootstrap() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-setup-ssh-err")) }) }) Context("when public key key is empty", func() { BeforeEach(func() { settingsSource.PublicKey = "" }) It("gets the public key and does not setup SSH", func() { err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(platform.SetupSSHCalled).To(BeFalse()) }) }) }) It("sets up hostname", func() { settingsService.Settings.AgentID = "foo-bar-baz-123" err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(platform.SetupHostnameHostname).To(Equal("foo-bar-baz-123")) }) It("fetches initial settings", func() { err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(settingsService.SettingsWereLoaded).To(BeTrue()) }) It("returns error from loading initial settings", func() { settingsService.LoadSettingsError = errors.New("fake-load-error") err := bootstrap() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-load-error")) }) It("sets up networking", func() { networks := boshsettings.Networks{ "bosh": boshsettings.Network{}, } settingsService.Settings.Networks = networks err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(platform.SetupNetworkingNetworks).To(Equal(networks)) }) It("sets up ephemeral disk", func() { settingsService.Settings.Disks = boshsettings.Disks{ Ephemeral: "fake-ephemeral-disk-setting", } platform.GetEphemeralDiskPathRealPath = "/dev/sda" err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(platform.SetupEphemeralDiskWithPathDevicePath).To(Equal("/dev/sda")) Expect(platform.GetEphemeralDiskPathSettings).To(Equal(boshsettings.DiskSettings{ VolumeID: "fake-ephemeral-disk-setting", Path: "fake-ephemeral-disk-setting", })) }) It("returns error if setting ephemeral disk fails", func() { platform.SetupEphemeralDiskWithPathErr = errors.New("fake-setup-ephemeral-disk-err") err := bootstrap() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-setup-ephemeral-disk-err")) }) It("sets up raw ephemeral disks if paths exist", func() { settingsService.Settings.Disks = boshsettings.Disks{ RawEphemeral: []boshsettings.DiskSettings{{Path: "/dev/xvdb"}, {Path: "/dev/xvdc"}}, } err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(platform.SetupRawEphemeralDisksCallCount).To(Equal(1)) Expect(len(platform.SetupRawEphemeralDisksDevices)).To(Equal(2)) Expect(platform.SetupRawEphemeralDisksDevices[0].Path).To(Equal("/dev/xvdb")) Expect(platform.SetupRawEphemeralDisksDevices[1].Path).To(Equal("/dev/xvdc")) }) It("returns error if setting raw ephemeral disks fails", func() { platform.SetupRawEphemeralDisksErr = errors.New("fake-setup-raw-ephemeral-disks-err") err := bootstrap() Expect(platform.SetupRawEphemeralDisksCallCount).To(Equal(1)) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-setup-raw-ephemeral-disks-err")) }) It("sets up data dir", func() { err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(platform.SetupDataDirCalled).To(BeTrue()) }) It("returns error if set up of data dir fails", func() { platform.SetupDataDirErr = errors.New("fake-setup-data-dir-err") err := bootstrap() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-setup-data-dir-err")) }) It("sets up tmp dir", func() { err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(platform.SetupTmpDirCalled).To(BeTrue()) }) It("returns error if set up of tmp dir fails", func() { platform.SetupTmpDirErr = errors.New("fake-setup-tmp-dir-err") err := bootstrap() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-setup-tmp-dir-err")) }) It("mounts persistent disk", func() { settingsService.Settings.Disks = boshsettings.Disks{ Persistent: map[string]interface{}{ "vol-123": map[string]interface{}{ "volume_id": "2", "path": "/dev/sdb", }, }, } err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(platform.MountPersistentDiskSettings).To(Equal(boshsettings.DiskSettings{ ID: "vol-123", VolumeID: "2", Path: "/dev/sdb", })) Expect(platform.MountPersistentDiskMountPoint).To(Equal(dirProvider.StoreDir())) }) It("errors if there is more than one persistent disk", func() { settingsService.Settings.Disks = boshsettings.Disks{ Persistent: map[string]interface{}{ "vol-123": "/dev/sdb", "vol-456": "/dev/sdc", }, } err := bootstrap() Expect(err).To(HaveOccurred()) }) It("does not try to mount when no persistent disk", func() { settingsService.Settings.Disks = boshsettings.Disks{ Persistent: map[string]interface{}{}, } err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(platform.MountPersistentDiskSettings).To(Equal(boshsettings.DiskSettings{})) Expect(platform.MountPersistentDiskMountPoint).To(Equal("")) }) It("grows the root filesystem", func() { err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(platform.SetupRootDiskCalledTimes).To(Equal(1)) }) It("returns an error if growing the root filesystem fails", func() { platform.SetupRootDiskError = errors.New("growfs failed") err := bootstrap() Expect(err).To(HaveOccurred()) Expect(platform.SetupRootDiskCalledTimes).To(Equal(1)) Expect(err.Error()).To(ContainSubstring("growfs failed")) }) It("sets root and vcap passwords", func() { settingsService.Settings.Env.Bosh.Password = "******" settingsService.Settings.Env.Bosh.KeepRootPassword = false err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(2).To(Equal(len(platform.UserPasswords))) Expect("some-encrypted-password").To(Equal(platform.UserPasswords["root"])) Expect("some-encrypted-password").To(Equal(platform.UserPasswords["vcap"])) }) It("does not change root password if keep_root_password is set to true", func() { settingsService.Settings.Env.Bosh.Password = "******" settingsService.Settings.Env.Bosh.KeepRootPassword = true err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(1).To(Equal(len(platform.UserPasswords))) Expect("some-encrypted-password").ToNot(Equal(platform.UserPasswords["root"])) Expect("some-encrypted-password").To(Equal(platform.UserPasswords["vcap"])) }) It("does not set password if not provided", func() { settingsService.Settings.Env.Bosh.KeepRootPassword = false err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(0).To(Equal(len(platform.UserPasswords))) }) It("sets ntp", func() { settingsService.Settings.Ntp = []string{ "0.north-america.pool.ntp.org", "1.north-america.pool.ntp.org", } err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(2).To(Equal(len(platform.SetTimeWithNtpServersServers))) Expect("0.north-america.pool.ntp.org").To(Equal(platform.SetTimeWithNtpServersServers[0])) Expect("1.north-america.pool.ntp.org").To(Equal(platform.SetTimeWithNtpServersServers[1])) }) It("setups up monit user", func() { err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(platform.SetupMonitUserSetup).To(BeTrue()) }) It("starts monit", func() { err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(platform.StartMonitStarted).To(BeTrue()) }) }) Describe("Network setup exercised by Run", func() { var ( settingsJSON string fs *fakesys.FakeFileSystem platform boshplatform.Platform boot Bootstrap defaultNetworkResolver boshsettings.DefaultNetworkResolver logger boshlog.Logger dirProvider boshdirs.Provider interfaceAddrsProvider *fakeip.FakeInterfaceAddressesProvider ) writeNetworkDevice := func(iface string, macAddress string, isPhysical bool) string { interfacePath := fmt.Sprintf("/sys/class/net/%s", iface) fs.WriteFile(interfacePath, []byte{}) if isPhysical { fs.WriteFile(fmt.Sprintf("/sys/class/net/%s/device", iface), []byte{}) } fs.WriteFileString(fmt.Sprintf("/sys/class/net/%s/address", iface), fmt.Sprintf("%s\n", macAddress)) return interfacePath } stubInterfaces := func(interfaces [][]string) { var interfacePaths []string for _, iface := range interfaces { interfaceName := iface[0] interfaceMAC := iface[1] interfaceType := iface[2] isPhysical := interfaceType == "physical" interfacePaths = append(interfacePaths, writeNetworkDevice(interfaceName, interfaceMAC, isPhysical)) } fs.SetGlob("/sys/class/net/*", interfacePaths) } BeforeEach(func() { fs = fakesys.NewFakeFileSystem() runner := fakesys.NewFakeCmdRunner() dirProvider = boshdirs.NewProvider("/var/vcap/bosh") linuxOptions := boshplatform.LinuxOptions{ CreatePartitionIfNoEphemeralDisk: true, } logger = boshlog.NewLogger(boshlog.LevelNone) diskManager := fakedisk.NewFakeDiskManager() diskManager.FakeMountsSearcher.SearchMountsMounts = []boshdisk.Mount{ {MountPoint: "/", PartitionPath: "rootfs"}, {MountPoint: "/", PartitionPath: "/dev/vda1"}, } // for the GrowRootFS call to findRootDevicePath runner.AddCmdResult( "readlink -f /dev/vda1", fakesys.FakeCmdResult{Stdout: "/dev/vda1"}, ) // for the createEphemeralPartitionsOnRootDevice call to findRootDevicePath runner.AddCmdResult( "readlink -f /dev/vda1", fakesys.FakeCmdResult{Stdout: "/dev/vda1"}, ) diskManager.FakeRootDevicePartitioner.GetDeviceSizeInBytesSizes["/dev/vda"] = 1024 * 1024 * 1024 udev := boshudev.NewConcreteUdevDevice(runner, logger) linuxCdrom := boshcdrom.NewLinuxCdrom("/dev/sr0", udev, runner) linuxCdutil := boshcdrom.NewCdUtil(dirProvider.SettingsDir(), fs, linuxCdrom, logger) compressor := boshcmd.NewTarballCompressor(runner, fs) copier := boshcmd.NewCpCopier(runner, fs, logger) sigarCollector := boshsigar.NewSigarStatsCollector(&sigar.ConcreteSigar{}) vitalsService := boshvitals.NewService(sigarCollector, dirProvider) ipResolver := boship.NewResolver(boship.NetworkInterfaceToAddrsFunc) arping := bosharp.NewArping(runner, fs, logger, boshplatform.ArpIterations, boshplatform.ArpIterationDelay, boshplatform.ArpInterfaceCheckDelay) interfaceConfigurationCreator := boshnet.NewInterfaceConfigurationCreator(logger) interfaceAddrsProvider = &fakeip.FakeInterfaceAddressesProvider{} interfaceAddressesValidator := boship.NewInterfaceAddressesValidator(interfaceAddrsProvider) dnsValidator := boshnet.NewDNSValidator(fs) fs.WriteFileString("/etc/resolv.conf", "8.8.8.8 4.4.4.4") ubuntuNetManager := boshnet.NewUbuntuNetManager(fs, runner, ipResolver, interfaceConfigurationCreator, interfaceAddressesValidator, dnsValidator, arping, logger) ubuntuCertManager := boshcert.NewUbuntuCertManager(fs, runner, 1, logger) monitRetryable := boshplatform.NewMonitRetryable(runner) monitRetryStrategy := boshretry.NewAttemptRetryStrategy(10, 1*time.Second, monitRetryable, logger) devicePathResolver := devicepathresolver.NewIdentityDevicePathResolver() routesSearcher := boshnet.NewCmdRoutesSearcher(runner) defaultNetworkResolver = boshnet.NewDefaultNetworkResolver(routesSearcher, ipResolver) state, err := boshplatform.NewBootstrapState(fs, "/tmp/agent_state.json") Expect(err).NotTo(HaveOccurred()) platform = boshplatform.NewLinuxPlatform( fs, runner, sigarCollector, compressor, copier, dirProvider, vitalsService, linuxCdutil, diskManager, ubuntuNetManager, ubuntuCertManager, monitRetryStrategy, devicePathResolver, 500*time.Millisecond, state, linuxOptions, logger, defaultNetworkResolver, ) }) JustBeforeEach(func() { settingsPath := filepath.Join("bosh", "settings.json") var settings boshsettings.Settings json.Unmarshal([]byte(settingsJSON), &settings) settingsSource := fakeinf.FakeSettingsSource{ PublicKey: "123", SettingsValue: settings, } settingsService := boshsettings.NewService( platform.GetFs(), settingsPath, settingsSource, platform, logger, ) boot = NewBootstrap( platform, dirProvider, settingsService, logger, ) }) Context("when a single network configuration is provided, with a MAC address", func() { BeforeEach(func() { settingsJSON = `{ "networks": { "netA": { "default": ["dns", "gateway"], "ip": "2.2.2.2", "dns": [ "8.8.8.8", "4.4.4.4" ], "netmask": "255.255.255.0", "gateway": "2.2.2.0", "mac": "aa:bb:cc" } } }` }) Context("and no physical network interfaces exist", func() { Context("and a single virtual network interface exists", func() { BeforeEach(func() { stubInterfaces([][]string{[]string{"lo", "aa:bb:cc", "virtual"}}) }) It("raises an error", func() { err := boot.Run() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Number of network settings '1' is greater than the number of network devices '0")) }) }) }) Context("and a single physical network interface exists", func() { BeforeEach(func() { stubInterfaces([][]string{[]string{"eth0", "aa:bb:cc", "physical"}}) interfaceAddrsProvider.GetInterfaceAddresses = []boship.InterfaceAddress{ boship.NewSimpleInterfaceAddress("eth0", "2.2.2.2"), } }) It("succeeds", func() { err := boot.Run() Expect(err).NotTo(HaveOccurred()) }) }) Context("and extra physical network interfaces exist", func() { BeforeEach(func() { stubInterfaces([][]string{[]string{"eth0", "aa:bb:cc", "physical"}, []string{"eth1", "aa:bb:dd", "physical"}}) interfaceAddrsProvider.GetInterfaceAddresses = []boship.InterfaceAddress{ boship.NewSimpleInterfaceAddress("eth0", "2.2.2.2"), } }) It("succeeds", func() { err := boot.Run() Expect(err).NotTo(HaveOccurred()) }) }) Context("and extra virtual network interfaces exist", func() { BeforeEach(func() { stubInterfaces([][]string{[]string{"eth0", "aa:bb:cc", "physical"}, []string{"lo", "aa:bb:ee", "virtual"}}) interfaceAddrsProvider.GetInterfaceAddresses = []boship.InterfaceAddress{ boship.NewSimpleInterfaceAddress("eth0", "2.2.2.2"), } }) It("succeeds", func() { err := boot.Run() Expect(err).ToNot(HaveOccurred()) }) }) }) Context("when a single network configuration is provided, without a MAC address", func() { BeforeEach(func() { settingsJSON = `{ "networks": { "netA": { "default": ["dns", "gateway"], "ip": "2.2.2.2", "dns": [ "8.8.8.8", "4.4.4.4" ], "netmask": "255.255.255.0", "gateway": "2.2.2.0" } } }` }) Context("and no physical network interfaces exist", func() { Context("and a single virtual network interface exists", func() { BeforeEach(func() { stubInterfaces([][]string{[]string{"lo", "aa:bb:cc", "virtual"}}) }) It("raises an error", func() { err := boot.Run() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Number of network settings '1' is greater than the number of network devices '0")) }) }) }) Context("and a single physical network interface exists", func() { BeforeEach(func() { stubInterfaces([][]string{[]string{"eth0", "aa:bb:cc", "physical"}}) interfaceAddrsProvider.GetInterfaceAddresses = []boship.InterfaceAddress{ boship.NewSimpleInterfaceAddress("eth0", "2.2.2.2"), } }) It("succeeds", func() { err := boot.Run() Expect(err).NotTo(HaveOccurred()) }) }) Context("and extra physical network interfaces exist", func() { BeforeEach(func() { stubInterfaces([][]string{[]string{"eth0", "aa:bb:cc", "physical"}, []string{"eth1", "aa:bb:dd", "physical"}}) interfaceAddrsProvider.GetInterfaceAddresses = []boship.InterfaceAddress{ boship.NewSimpleInterfaceAddress("eth0", "2.2.2.2"), } }) It("succeeds", func() { err := boot.Run() Expect(err).NotTo(HaveOccurred()) }) }) Context("and an extra virtual network interface exists", func() { BeforeEach(func() { stubInterfaces([][]string{[]string{"eth0", "aa:bb:cc", "physical"}, []string{"lo", "aa:bb:dd", "virtual"}}) interfaceAddrsProvider.GetInterfaceAddresses = []boship.InterfaceAddress{ boship.NewSimpleInterfaceAddress("eth0", "2.2.2.2"), } }) It("succeeds", func() { err := boot.Run() Expect(err).NotTo(HaveOccurred()) }) }) }) Context("when two network configurations are provided", func() { BeforeEach(func() { settingsJSON = `{ "networks": { "netA": { "default": ["dns", "gateway"], "ip": "2.2.2.2", "dns": [ "8.8.8.8", "4.4.4.4" ], "netmask": "255.255.255.0", "gateway": "2.2.2.0", "mac": "aa:bb:cc" }, "netB": { "default": ["dns", "gateway"], "ip": "3.3.3.3", "dns": [ "8.8.8.8", "4.4.4.4" ], "netmask": "255.255.255.0", "gateway": "3.3.3.0", "mac": "" } } }` }) Context("and a single physical network interface exists", func() { BeforeEach(func() { stubInterfaces([][]string{[]string{"eth0", "aa:bb:cc", "physical"}}) }) It("raises an error", func() { err := boot.Run() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Number of network settings '2' is greater than the number of network devices '1")) }) }) Context("and two physical network interfaces with matching MAC addresses exist", func() { BeforeEach(func() { stubInterfaces([][]string{[]string{"eth0", "aa:bb:cc", "physical"}, []string{"eth1", "aa:bb:dd", "physical"}}) interfaceAddrsProvider.GetInterfaceAddresses = []boship.InterfaceAddress{ boship.NewSimpleInterfaceAddress("eth0", "2.2.2.2"), boship.NewSimpleInterfaceAddress("eth1", "3.3.3.3"), } }) It("succeeds", func() { err := boot.Run() Expect(err).ToNot(HaveOccurred()) }) }) }) }) }) }
func describeDummyPlatform() { var ( platform Platform collector boshstats.Collector fs *fakesys.FakeFileSystem cmdRunner boshsys.CmdRunner dirProvider boshdirs.Provider devicePathResolver boshdpresolv.DevicePathResolver logger boshlog.Logger ) BeforeEach(func() { collector = &fakestats.FakeCollector{} fs = fakesys.NewFakeFileSystem() cmdRunner = fakesys.NewFakeCmdRunner() dirProvider = boshdirs.NewProvider("/fake-dir") devicePathResolver = fakedpresolv.NewFakeDevicePathResolver() logger = boshlog.NewLogger(boshlog.LevelNone) }) JustBeforeEach(func() { platform = NewDummyPlatform( collector, fs, cmdRunner, dirProvider, devicePathResolver, logger, ) }) Describe("GetDefaultNetwork", func() { It("returns the contents of dummy-defaults-network-settings.json since that's what the dummy cpi writes", func() { settingsFilePath := "/fake-dir/bosh/dummy-default-network-settings.json" fs.WriteFileString(settingsFilePath, `{"IP": "1.2.3.4"}`) network, err := platform.GetDefaultNetwork() Expect(err).NotTo(HaveOccurred()) Expect(network.IP).To(Equal("1.2.3.4")) }) }) Describe("GetCertManager", func() { It("returs a dummy cert manager", func() { certManager := platform.GetCertManager() Expect(certManager.UpdateCertificates("")).Should(BeNil()) }) }) Describe("UnmountPersistentDisk", func() { Context("when there are two mounted persistent disks in the mounts json", func() { BeforeEach(func() { var mounts []mount mounts = append(mounts, mount{MountDir: "dir1", DiskCid: "cid1"}) mounts = append(mounts, mount{MountDir: "dir2", DiskCid: "cid2"}) mountsJSON, _ := json.Marshal(mounts) mountsPath := path.Join(dirProvider.BoshDir(), "mounts.json") fs.WriteFile(mountsPath, mountsJSON) }) It("removes one of the disks from the mounts json", func() { unmounted, err := platform.UnmountPersistentDisk(settings.DiskSettings{ID: "cid1"}) Expect(err).NotTo(HaveOccurred()) Expect(unmounted).To(Equal(true)) _, isMountPoint, err := platform.IsMountPoint("dir1") Expect(isMountPoint).To(Equal(false)) _, isMountPoint, err = platform.IsMountPoint("dir2") Expect(isMountPoint).To(Equal(true)) }) }) }) Describe("SetUserPassword", func() { It("writes the password to a file", func() { err := platform.SetUserPassword("user-name", "fake-password") Expect(err).NotTo(HaveOccurred()) userPasswordsPath := path.Join(dirProvider.BoshDir(), "user-name", CredentialFileName) password, err := fs.ReadFileString(userPasswordsPath) Expect(err).NotTo(HaveOccurred()) Expect(password).To(Equal("fake-password")) }) It("writes the passwords to different files for each user", func() { err := platform.SetUserPassword("user-name1", "fake-password1") Expect(err).NotTo(HaveOccurred()) err = platform.SetUserPassword("user-name2", "fake-password2") Expect(err).NotTo(HaveOccurred()) userPasswordsPath := path.Join(dirProvider.BoshDir(), "user-name1", CredentialFileName) password, err := fs.ReadFileString(userPasswordsPath) Expect(err).NotTo(HaveOccurred()) Expect(password).To(Equal("fake-password1")) userPasswordsPath = path.Join(dirProvider.BoshDir(), "user-name2", CredentialFileName) password, err = fs.ReadFileString(userPasswordsPath) Expect(err).NotTo(HaveOccurred()) Expect(password).To(Equal("fake-password2")) }) }) Describe("SetupDataDir", func() { It("creates a link from BASEDIR/sys to BASEDIR/data/sys", func() { err := platform.SetupDataDir() Expect(err).NotTo(HaveOccurred()) stat := fs.GetFileTestStat("/fake-dir/sys") Expect(stat).ToNot(BeNil()) Expect(stat.SymlinkTarget).To(Equal("/fake-dir/data/sys")) }) }) }
fakecmd "github.com/cloudfoundry/bosh-utils/fileutil/fakes" ) var _ = Describe("FetchLogsAction", func() { var ( compressor *fakecmd.FakeCompressor copier *fakecmd.FakeCopier blobstore *fakeblobstore.FakeBlobstore dirProvider boshdirs.Provider action FetchLogsAction ) BeforeEach(func() { compressor = fakecmd.NewFakeCompressor() blobstore = &fakeblobstore.FakeBlobstore{} dirProvider = boshdirs.NewProvider("/fake/dir") copier = fakecmd.NewFakeCopier() action = NewFetchLogs(compressor, copier, blobstore, dirProvider) }) It("logs should be asynchronous", func() { Expect(action.IsAsynchronous()).To(BeTrue()) }) It("is not persistent", func() { Expect(action.IsPersistent()).To(BeFalse()) }) Describe("Run", func() { testLogs := func(logType string, filters []string, expectedFilters []string) { copier.FilteredCopyToTempTempDir = "/fake-temp-dir"
func describeLinuxPlatform() { var ( collector *fakestats.FakeCollector fs *fakesys.FakeFileSystem cmdRunner *fakesys.FakeCmdRunner diskManager *fakedisk.FakeDiskManager dirProvider boshdirs.Provider devicePathResolver *fakedpresolv.FakeDevicePathResolver platform Platform cdutil *fakedevutil.FakeDeviceUtil compressor boshcmd.Compressor copier boshcmd.Copier vitalsService boshvitals.Service netManager *fakenet.FakeManager certManager *fakecert.FakeManager monitRetryStrategy *fakeretry.FakeRetryStrategy fakeDefaultNetworkResolver *fakenet.FakeDefaultNetworkResolver options LinuxOptions logger boshlog.Logger ) BeforeEach(func() { logger = boshlog.NewLogger(boshlog.LevelNone) collector = &fakestats.FakeCollector{} fs = fakesys.NewFakeFileSystem() cmdRunner = fakesys.NewFakeCmdRunner() diskManager = fakedisk.NewFakeDiskManager() dirProvider = boshdirs.NewProvider("/fake-dir") cdutil = fakedevutil.NewFakeDeviceUtil() compressor = boshcmd.NewTarballCompressor(cmdRunner, fs) copier = boshcmd.NewCpCopier(cmdRunner, fs, logger) vitalsService = boshvitals.NewService(collector, dirProvider) netManager = &fakenet.FakeManager{} certManager = new(fakecert.FakeManager) monitRetryStrategy = fakeretry.NewFakeRetryStrategy() devicePathResolver = fakedpresolv.NewFakeDevicePathResolver() fakeDefaultNetworkResolver = &fakenet.FakeDefaultNetworkResolver{} options = LinuxOptions{} fs.SetGlob("/sys/bus/scsi/devices/*:0:0:0/block/*", []string{ "/sys/bus/scsi/devices/0:0:0:0/block/sr0", "/sys/bus/scsi/devices/6:0:0:0/block/sdd", "/sys/bus/scsi/devices/fake-host-id:0:0:0/block/sda", }) fs.SetGlob("/sys/bus/scsi/devices/fake-host-id:0:fake-disk-id:0/block/*", []string{ "/sys/bus/scsi/devices/fake-host-id:0:fake-disk-id:0/block/sdf", }) }) JustBeforeEach(func() { platform = NewLinuxPlatform( fs, cmdRunner, collector, compressor, copier, dirProvider, vitalsService, cdutil, diskManager, netManager, certManager, monitRetryStrategy, devicePathResolver, 5*time.Millisecond, options, logger, fakeDefaultNetworkResolver, ) }) Describe("SetupRuntimeConfiguration", func() { It("setups runtime configuration", func() { err := platform.SetupRuntimeConfiguration() Expect(err).NotTo(HaveOccurred()) Expect(len(cmdRunner.RunCommands)).To(Equal(1)) Expect(cmdRunner.RunCommands[0]).To(Equal([]string{"bosh-agent-rc"})) }) }) Describe("CreateUser", func() { It("creates user", func() { expectedUseradd := []string{ "useradd", "-m", "-b", "/some/path/to/home", "-s", "/bin/bash", "-p", "bar-pwd", "foo-user", } err := platform.CreateUser("foo-user", "bar-pwd", "/some/path/to/home") Expect(err).NotTo(HaveOccurred()) basePathStat := fs.GetFileTestStat("/some/path/to/home") Expect(basePathStat.FileType).To(Equal(fakesys.FakeFileTypeDir)) Expect(basePathStat.FileMode).To(Equal(os.FileMode(0755))) Expect(cmdRunner.RunCommands).To(Equal([][]string{expectedUseradd})) }) It("creates user with an empty password", func() { expectedUseradd := []string{ "useradd", "-m", "-b", "/some/path/to/home", "-s", "/bin/bash", "foo-user", } err := platform.CreateUser("foo-user", "", "/some/path/to/home") Expect(err).NotTo(HaveOccurred()) basePathStat := fs.GetFileTestStat("/some/path/to/home") Expect(basePathStat.FileType).To(Equal(fakesys.FakeFileTypeDir)) Expect(basePathStat.FileMode).To(Equal(os.FileMode(0755))) Expect(cmdRunner.RunCommands).To(Equal([][]string{expectedUseradd})) }) }) Describe("AddUserToGroups", func() { It("adds user to groups", func() { err := platform.AddUserToGroups("foo-user", []string{"group1", "group2", "group3"}) Expect(err).NotTo(HaveOccurred()) Expect(len(cmdRunner.RunCommands)).To(Equal(1)) usermod := []string{"usermod", "-G", "group1,group2,group3", "foo-user"} Expect(cmdRunner.RunCommands[0]).To(Equal(usermod)) }) }) Describe("DeleteEphemeralUsersMatching", func() { It("deletes users with prefix and regex", func() { passwdFile := `bosh_foo:... bosh_bar:... foo:... bar:... foobar:... bosh_foobar:...` fs.WriteFileString("/etc/passwd", passwdFile) err := platform.DeleteEphemeralUsersMatching("bar$") Expect(err).NotTo(HaveOccurred()) Expect(len(cmdRunner.RunCommands)).To(Equal(2)) Expect(cmdRunner.RunCommands[0]).To(Equal([]string{"userdel", "-r", "bosh_bar"})) Expect(cmdRunner.RunCommands[1]).To(Equal([]string{"userdel", "-r", "bosh_foobar"})) }) }) Describe("SetupSSH", func() { It("setup ssh", func() { fs.HomeDirHomePath = "/some/home/dir" platform.SetupSSH("some public key", "vcap") sshDirPath := "/some/home/dir/.ssh" sshDirStat := fs.GetFileTestStat(sshDirPath) Expect("vcap").To(Equal(fs.HomeDirUsername)) Expect(sshDirStat).NotTo(BeNil()) Expect(sshDirStat.FileType).To(Equal(fakesys.FakeFileTypeDir)) Expect(os.FileMode(0700)).To(Equal(sshDirStat.FileMode)) Expect("vcap").To(Equal(sshDirStat.Username)) authKeysStat := fs.GetFileTestStat(filepath.Join(sshDirPath, "authorized_keys")) Expect(authKeysStat).NotTo(BeNil()) Expect(fakesys.FakeFileTypeFile).To(Equal(authKeysStat.FileType)) Expect(os.FileMode(0600)).To(Equal(authKeysStat.FileMode)) Expect("vcap").To(Equal(authKeysStat.Username)) Expect("some public key").To(Equal(authKeysStat.StringContents())) }) }) Describe("SetUserPassword", func() { It("set user password", func() { platform.SetUserPassword("my-user", "my-encrypted-password") Expect(len(cmdRunner.RunCommands)).To(Equal(1)) Expect(cmdRunner.RunCommands[0]).To(Equal([]string{"usermod", "-p", "my-encrypted-password", "my-user"})) }) }) Describe("SetupHostname", func() { const expectedEtcHosts = `127.0.0.1 localhost foobar.local # The following lines are desirable for IPv6 capable hosts ::1 localhost ip6-localhost ip6-loopback foobar.local fe00::0 ip6-localnet ff00::0 ip6-mcastprefix ff02::1 ip6-allnodes ff02::2 ip6-allrouters ff02::3 ip6-allhosts ` It("sets up hostname", func() { platform.SetupHostname("foobar.local") Expect(len(cmdRunner.RunCommands)).To(Equal(1)) Expect(cmdRunner.RunCommands[0]).To(Equal([]string{"hostname", "foobar.local"})) hostnameFileContent, err := fs.ReadFileString("/etc/hostname") Expect(err).NotTo(HaveOccurred()) Expect(hostnameFileContent).To(Equal("foobar.local")) hostsFileContent, err := fs.ReadFileString("/etc/hosts") Expect(err).NotTo(HaveOccurred()) Expect(hostsFileContent).To(Equal(expectedEtcHosts)) }) }) Describe("SetupLogrotate", func() { const expectedEtcLogrotate = `# Generated by bosh-agent fake-base-path/data/sys/log/*.log fake-base-path/data/sys/log/*/*.log fake-base-path/data/sys/log/*/*/*.log { missingok rotate 7 compress delaycompress copytruncate size=fake-size } ` It("sets up logrotate", func() { platform.SetupLogrotate("fake-group-name", "fake-base-path", "fake-size") logrotateFileContent, err := fs.ReadFileString("/etc/logrotate.d/fake-group-name") Expect(err).NotTo(HaveOccurred()) Expect(logrotateFileContent).To(Equal(expectedEtcLogrotate)) }) }) Describe("SetTimeWithNtpServers", func() { It("sets time with ntp servers", func() { platform.SetTimeWithNtpServers([]string{"0.north-america.pool.ntp.org", "1.north-america.pool.ntp.org"}) ntpConfig := fs.GetFileTestStat("/fake-dir/bosh/etc/ntpserver") Expect(ntpConfig.StringContents()).To(Equal("0.north-america.pool.ntp.org 1.north-america.pool.ntp.org")) Expect(ntpConfig.FileType).To(Equal(fakesys.FakeFileTypeFile)) Expect(len(cmdRunner.RunCommands)).To(Equal(1)) Expect(cmdRunner.RunCommands[0]).To(Equal([]string{"ntpdate"})) }) It("sets time with ntp servers is noop when no ntp server provided", func() { platform.SetTimeWithNtpServers([]string{}) Expect(len(cmdRunner.RunCommands)).To(Equal(0)) ntpConfig := fs.GetFileTestStat("/fake-dir/bosh/etc/ntpserver") Expect(ntpConfig).To(BeNil()) }) }) Describe("SetupEphemeralDiskWithPath", func() { var ( partitioner *fakedisk.FakePartitioner formatter *fakedisk.FakeFormatter mounter *fakedisk.FakeMounter ) BeforeEach(func() { partitioner = diskManager.FakePartitioner formatter = diskManager.FakeFormatter mounter = diskManager.FakeMounter }) itSetsUpEphemeralDisk := func(act func() error) { It("sets up ephemeral disk with path", func() { err := act() Expect(err).NotTo(HaveOccurred()) dataDir := fs.GetFileTestStat("/fake-dir/data") Expect(dataDir.FileType).To(Equal(fakesys.FakeFileTypeDir)) Expect(dataDir.FileMode).To(Equal(os.FileMode(0750))) }) It("creates new partition even if the data directory is not empty", func() { fs.SetGlob(path.Join("/fake-dir", "data", "*"), []string{"something"}) err := act() Expect(err).ToNot(HaveOccurred()) Expect(partitioner.PartitionCalled).To(BeTrue()) Expect(formatter.FormatCalled).To(BeTrue()) Expect(mounter.MountCalled).To(BeTrue()) }) } Context("when ephemeral disk path is provided", func() { act := func() error { return platform.SetupEphemeralDiskWithPath("/dev/xvda") } itSetsUpEphemeralDisk(act) It("returns error if creating data dir fails", func() { fs.MkdirAllError = errors.New("fake-mkdir-all-err") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-mkdir-all-err")) Expect(partitioner.PartitionCalled).To(BeFalse()) Expect(formatter.FormatCalled).To(BeFalse()) Expect(mounter.MountCalled).To(BeFalse()) }) It("returns err when the data directory cannot be globbed", func() { fs.GlobErr = errors.New("fake-glob-err") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Globbing ephemeral disk mount point `/fake-dir/data/*'")) Expect(err.Error()).To(ContainSubstring("fake-glob-err")) Expect(partitioner.PartitionCalled).To(BeFalse()) Expect(formatter.FormatCalled).To(BeFalse()) Expect(mounter.MountCalled).To(BeFalse()) }) It("returns err when mem stats are unavailable", func() { collector.MemStatsErr = errors.New("fake-memstats-error") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Calculating partition sizes")) Expect(err.Error()).To(ContainSubstring("fake-memstats-error")) Expect(partitioner.PartitionCalled).To(BeFalse()) Expect(formatter.FormatCalled).To(BeFalse()) Expect(mounter.MountCalled).To(BeFalse()) }) It("returns an error when partitioning fails", func() { partitioner.PartitionErr = errors.New("fake-partition-error") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Partitioning ephemeral disk `/dev/xvda'")) Expect(err.Error()).To(ContainSubstring("fake-partition-error")) Expect(formatter.FormatCalled).To(BeFalse()) Expect(mounter.MountCalled).To(BeFalse()) }) It("formats swap and data partitions", func() { err := act() Expect(err).NotTo(HaveOccurred()) Expect(len(formatter.FormatPartitionPaths)).To(Equal(2)) Expect(formatter.FormatPartitionPaths[0]).To(Equal("/dev/xvda1")) Expect(formatter.FormatPartitionPaths[1]).To(Equal("/dev/xvda2")) Expect(len(formatter.FormatFsTypes)).To(Equal(2)) Expect(formatter.FormatFsTypes[0]).To(Equal(boshdisk.FileSystemSwap)) Expect(formatter.FormatFsTypes[1]).To(Equal(boshdisk.FileSystemExt4)) }) It("mounts swap and data partitions", func() { err := act() Expect(err).NotTo(HaveOccurred()) Expect(len(mounter.MountMountPoints)).To(Equal(1)) Expect(mounter.MountMountPoints[0]).To(Equal("/fake-dir/data")) Expect(len(mounter.MountPartitionPaths)).To(Equal(1)) Expect(mounter.MountPartitionPaths[0]).To(Equal("/dev/xvda2")) Expect(len(mounter.SwapOnPartitionPaths)).To(Equal(1)) Expect(mounter.SwapOnPartitionPaths[0]).To(Equal("/dev/xvda1")) }) It("creates swap the size of the memory and the rest for data when disk is bigger than twice the memory", func() { memSizeInBytes := uint64(1024 * 1024 * 1024) diskSizeInBytes := 2*memSizeInBytes + 64 fakePartitioner := partitioner fakePartitioner.GetDeviceSizeInBytesSizes["/dev/xvda"] = diskSizeInBytes collector.MemStats.Total = memSizeInBytes err := act() Expect(err).NotTo(HaveOccurred()) Expect(fakePartitioner.PartitionPartitions).To(Equal([]boshdisk.Partition{ {SizeInBytes: memSizeInBytes, Type: boshdisk.PartitionTypeSwap}, {SizeInBytes: diskSizeInBytes - memSizeInBytes, Type: boshdisk.PartitionTypeLinux}, })) }) It("creates equal swap and data partitions when disk is twice the memory or smaller", func() { memSizeInBytes := uint64(1024 * 1024 * 1024) diskSizeInBytes := 2*memSizeInBytes - 64 fakePartitioner := partitioner fakePartitioner.GetDeviceSizeInBytesSizes["/dev/xvda"] = diskSizeInBytes collector.MemStats.Total = memSizeInBytes err := act() Expect(err).NotTo(HaveOccurred()) Expect(fakePartitioner.PartitionPartitions).To(Equal([]boshdisk.Partition{ {SizeInBytes: diskSizeInBytes / 2, Type: boshdisk.PartitionTypeSwap}, {SizeInBytes: diskSizeInBytes / 2, Type: boshdisk.PartitionTypeLinux}, })) }) }) Context("when ephemeral disk path is not provided", func() { act := func() error { return platform.SetupEphemeralDiskWithPath("") } Context("when agent should partition ephemeral disk on root disk", func() { BeforeEach(func() { partitioner = diskManager.FakeRootDevicePartitioner options.CreatePartitionIfNoEphemeralDisk = true }) Context("when root device fails to be determined", func() { BeforeEach(func() { diskManager.FakeMountsSearcher.SearchMountsErr = errors.New("fake-mounts-searcher-error") }) It("returns an error", func() { err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Finding root partition device")) Expect(partitioner.PartitionCalled).To(BeFalse()) Expect(formatter.FormatCalled).To(BeFalse()) Expect(mounter.MountCalled).To(BeFalse()) }) }) Context("when root partition is not the first partition", func() { BeforeEach(func() { diskManager.FakeMountsSearcher.SearchMountsMounts = []boshdisk.Mount{ {MountPoint: "/", PartitionPath: "/dev/vda2"}, } }) It("returns an error", func() { err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Root partition is not the first partition")) Expect(partitioner.PartitionCalled).To(BeFalse()) Expect(formatter.FormatCalled).To(BeFalse()) Expect(mounter.MountCalled).To(BeFalse()) }) }) Context("when root device is determined", func() { BeforeEach(func() { diskManager.FakeMountsSearcher.SearchMountsMounts = []boshdisk.Mount{ {MountPoint: "/", PartitionPath: "rootfs"}, {MountPoint: "/", PartitionPath: "/dev/vda1"}, } }) Context("when getting absolute path fails", func() { BeforeEach(func() { cmdRunner.AddCmdResult( "readlink -f /dev/vda1", fakesys.FakeCmdResult{Error: errors.New("fake-readlink-error")}, ) }) It("returns an error", func() { err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-readlink-error")) Expect(partitioner.PartitionCalled).To(BeFalse()) Expect(formatter.FormatCalled).To(BeFalse()) Expect(mounter.MountCalled).To(BeFalse()) }) }) Context("when getting absolute path suceeds", func() { BeforeEach(func() { cmdRunner.AddCmdResult( "readlink -f /dev/vda1", fakesys.FakeCmdResult{Stdout: "/dev/vda1"}, ) }) Context("when root device has insufficient space for ephemeral partitions", func() { BeforeEach(func() { partitioner.GetDeviceSizeInBytesSizes["/dev/vda"] = 1024*1024*1024 - 1 collector.MemStats.Total = 8 }) It("returns an error", func() { err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Insufficient remaining disk")) Expect(partitioner.PartitionCalled).To(BeFalse()) Expect(formatter.FormatCalled).To(BeFalse()) Expect(mounter.MountCalled).To(BeFalse()) }) }) Context("when root device has sufficient space for ephemeral partitions", func() { BeforeEach(func() { partitioner.GetDeviceSizeInBytesSizes["/dev/vda"] = 1024 * 1024 * 1024 collector.MemStats.Total = 256 * 1024 * 1024 }) itSetsUpEphemeralDisk(act) It("returns err when mem stats are unavailable", func() { collector.MemStatsErr = errors.New("fake-memstats-error") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Calculating partition sizes")) Expect(err.Error()).To(ContainSubstring("fake-memstats-error")) Expect(partitioner.PartitionCalled).To(BeFalse()) Expect(formatter.FormatCalled).To(BeFalse()) Expect(mounter.MountCalled).To(BeFalse()) }) It("returns an error when partitioning fails", func() { partitioner.PartitionErr = errors.New("fake-partition-error") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Partitioning root device `/dev/vda'")) Expect(err.Error()).To(ContainSubstring("fake-partition-error")) Expect(formatter.FormatCalled).To(BeFalse()) Expect(mounter.MountCalled).To(BeFalse()) }) It("formats swap and data partitions", func() { err := act() Expect(err).NotTo(HaveOccurred()) Expect(len(formatter.FormatPartitionPaths)).To(Equal(2)) Expect(formatter.FormatPartitionPaths[0]).To(Equal("/dev/vda2")) Expect(formatter.FormatPartitionPaths[1]).To(Equal("/dev/vda3")) Expect(len(formatter.FormatFsTypes)).To(Equal(2)) Expect(formatter.FormatFsTypes[0]).To(Equal(boshdisk.FileSystemSwap)) Expect(formatter.FormatFsTypes[1]).To(Equal(boshdisk.FileSystemExt4)) }) It("mounts swap and data partitions", func() { err := act() Expect(err).NotTo(HaveOccurred()) Expect(len(mounter.MountMountPoints)).To(Equal(1)) Expect(mounter.MountMountPoints[0]).To(Equal("/fake-dir/data")) Expect(len(mounter.MountPartitionPaths)).To(Equal(1)) Expect(mounter.MountPartitionPaths[0]).To(Equal("/dev/vda3")) Expect(len(mounter.SwapOnPartitionPaths)).To(Equal(1)) Expect(mounter.SwapOnPartitionPaths[0]).To(Equal("/dev/vda2")) }) It("creates swap the size of the memory and the rest for data when disk is bigger than twice the memory", func() { memSizeInBytes := uint64(1024 * 1024 * 1024) diskSizeInBytes := 2*memSizeInBytes + 64 partitioner.GetDeviceSizeInBytesSizes["/dev/vda"] = diskSizeInBytes collector.MemStats.Total = memSizeInBytes err := act() Expect(err).ToNot(HaveOccurred()) Expect(partitioner.PartitionDevicePath).To(Equal("/dev/vda")) Expect(partitioner.PartitionPartitions).To(ContainElement( boshdisk.Partition{ SizeInBytes: memSizeInBytes, Type: boshdisk.PartitionTypeSwap, }), ) Expect(partitioner.PartitionPartitions).To(ContainElement( boshdisk.Partition{ SizeInBytes: diskSizeInBytes - memSizeInBytes, Type: boshdisk.PartitionTypeLinux, }), ) }) It("creates equal swap and data partitions when disk is twice the memory or smaller", func() { memSizeInBytes := uint64(1024 * 1024 * 1024) diskSizeInBytes := 2*memSizeInBytes - 64 partitioner.GetDeviceSizeInBytesSizes["/dev/vda"] = diskSizeInBytes collector.MemStats.Total = memSizeInBytes err := act() Expect(err).ToNot(HaveOccurred()) Expect(partitioner.PartitionDevicePath).To(Equal("/dev/vda")) Expect(partitioner.PartitionPartitions).To(ContainElement( boshdisk.Partition{ SizeInBytes: diskSizeInBytes / 2, Type: boshdisk.PartitionTypeSwap, }), ) Expect(partitioner.PartitionPartitions).To(ContainElement( boshdisk.Partition{ SizeInBytes: diskSizeInBytes / 2, Type: boshdisk.PartitionTypeLinux, }), ) }) }) Context("when getting root device remaining size fails", func() { BeforeEach(func() { partitioner.GetDeviceSizeInBytesErr = errors.New("fake-get-remaining-size-error") }) It("returns an error", func() { err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Getting root device remaining size")) Expect(err.Error()).To(ContainSubstring("fake-get-remaining-size-error")) Expect(partitioner.PartitionCalled).To(BeFalse()) Expect(formatter.FormatCalled).To(BeFalse()) Expect(mounter.MountCalled).To(BeFalse()) }) }) }) }) It("returns error if creating data dir fails", func() { fs.MkdirAllError = errors.New("fake-mkdir-all-err") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-mkdir-all-err")) Expect(partitioner.PartitionCalled).To(BeFalse()) Expect(formatter.FormatCalled).To(BeFalse()) Expect(mounter.MountCalled).To(BeFalse()) }) It("returns err when the data directory cannot be globbed", func() { fs.GlobErr = errors.New("fake-glob-err") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Globbing ephemeral disk mount point `/fake-dir/data/*'")) Expect(err.Error()).To(ContainSubstring("fake-glob-err")) Expect(partitioner.PartitionCalled).To(BeFalse()) Expect(formatter.FormatCalled).To(BeFalse()) Expect(mounter.MountCalled).To(BeFalse()) }) }) Context("when agent should not partition ephemeral disk on root disk", func() { BeforeEach(func() { options.CreatePartitionIfNoEphemeralDisk = false }) It("returns an error", func() { err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("cannot use root partition as ephemeral disk")) }) It("does not try to partition anything", func() { err := act() Expect(err).To(HaveOccurred()) Expect(partitioner.PartitionCalled).To(BeFalse()) }) It("does not try to format anything", func() { err := act() Expect(err).To(HaveOccurred()) Expect(formatter.FormatCalled).To(BeFalse()) }) It("does not try to mount anything", func() { err := act() Expect(err).To(HaveOccurred()) Expect(mounter.MountCalled).To(BeFalse()) }) }) }) }) Describe("SetupDataDir", func() { var mounter *fakedisk.FakeMounter BeforeEach(func() { mounter = diskManager.FakeMounter }) Context("when sys/run is already mounted", func() { BeforeEach(func() { mounter.IsMountPointResult = true }) It("creates sys/log directory in data directory", func() { err := platform.SetupDataDir() Expect(err).NotTo(HaveOccurred()) sysLogStats := fs.GetFileTestStat("/fake-dir/data/sys/log") Expect(sysLogStats).ToNot(BeNil()) Expect(sysLogStats.FileType).To(Equal(fakesys.FakeFileTypeDir)) Expect(sysLogStats.FileMode).To(Equal(os.FileMode(0750))) Expect(cmdRunner.RunCommands[0]).To(Equal([]string{"chown", "root:vcap", "/fake-dir/data/sys"})) Expect(cmdRunner.RunCommands[1]).To(Equal([]string{"chown", "root:vcap", "/fake-dir/data/sys/log"})) }) It("creates symlink from sys to data/sys", func() { err := platform.SetupDataDir() Expect(err).NotTo(HaveOccurred()) sysStats := fs.GetFileTestStat("/fake-dir/sys") Expect(sysStats).ToNot(BeNil()) Expect(sysStats.FileType).To(Equal(fakesys.FakeFileTypeSymlink)) Expect(sysStats.SymlinkTarget).To(Equal("/fake-dir/data/sys")) }) It("does not create new sys/run dir", func() { err := platform.SetupDataDir() Expect(err).NotTo(HaveOccurred()) sysRunStats := fs.GetFileTestStat("/fake-dir/data/sys/run") Expect(sysRunStats).To(BeNil()) }) It("does not mount tmpfs again", func() { err := platform.SetupDataDir() Expect(err).NotTo(HaveOccurred()) Expect(len(mounter.MountPartitionPaths)).To(Equal(0)) }) }) Context("when sys/run is not yet mounted", func() { BeforeEach(func() { mounter.IsMountPointResult = false }) It("creates sys/log directory in data directory", func() { err := platform.SetupDataDir() Expect(err).NotTo(HaveOccurred()) sysLogStats := fs.GetFileTestStat("/fake-dir/data/sys/log") Expect(sysLogStats).ToNot(BeNil()) Expect(sysLogStats.FileType).To(Equal(fakesys.FakeFileTypeDir)) Expect(sysLogStats.FileMode).To(Equal(os.FileMode(0750))) Expect(cmdRunner.RunCommands[0]).To(Equal([]string{"chown", "root:vcap", "/fake-dir/data/sys"})) Expect(cmdRunner.RunCommands[1]).To(Equal([]string{"chown", "root:vcap", "/fake-dir/data/sys/log"})) }) It("creates symlink from sys to data/sys", func() { err := platform.SetupDataDir() Expect(err).NotTo(HaveOccurred()) sysStats := fs.GetFileTestStat("/fake-dir/sys") Expect(sysStats).ToNot(BeNil()) Expect(sysStats.FileType).To(Equal(fakesys.FakeFileTypeSymlink)) Expect(sysStats.SymlinkTarget).To(Equal("/fake-dir/data/sys")) }) It("creates new sys/run dir", func() { err := platform.SetupDataDir() Expect(err).NotTo(HaveOccurred()) sysRunStats := fs.GetFileTestStat("/fake-dir/data/sys/run") Expect(sysRunStats).ToNot(BeNil()) Expect(sysRunStats.FileType).To(Equal(fakesys.FakeFileTypeDir)) Expect(sysRunStats.FileMode).To(Equal(os.FileMode(0750))) Expect(cmdRunner.RunCommands[2]).To(Equal([]string{"chown", "root:vcap", "/fake-dir/data/sys/run"})) }) It("mounts tmpfs to sys/run", func() { err := platform.SetupDataDir() Expect(err).NotTo(HaveOccurred()) Expect(len(mounter.MountPartitionPaths)).To(Equal(1)) Expect(mounter.MountPartitionPaths[0]).To(Equal("tmpfs")) Expect(mounter.MountMountPoints[0]).To(Equal("/fake-dir/data/sys/run")) Expect(mounter.MountMountOptions[0]).To(Equal([]string{"-t", "tmpfs", "-o", "size=1m"})) }) It("returns an error if creation of mount point fails", func() { fs.MkdirAllError = errors.New("fake-mkdir-error") err := platform.SetupDataDir() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-mkdir-error")) }) It("returns an error if mounting tmpfs fails", func() { mounter.MountErr = errors.New("fake-mount-error") err := platform.SetupDataDir() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-mount-error")) }) }) }) Describe("SetupTmpDir", func() { act := func() error { return platform.SetupTmpDir() } var mounter *fakedisk.FakeMounter BeforeEach(func() { mounter = diskManager.FakeMounter }) It("changes permissions on /tmp", func() { err := act() Expect(err).NotTo(HaveOccurred()) Expect(cmdRunner.RunCommands[0]).To(Equal([]string{"chown", "root:vcap", "/tmp"})) Expect(cmdRunner.RunCommands[1]).To(Equal([]string{"chmod", "0770", "/tmp"})) Expect(cmdRunner.RunCommands[2]).To(Equal([]string{"chmod", "0700", "/var/tmp"})) }) It("creates new temp dir", func() { err := act() Expect(err).NotTo(HaveOccurred()) fileStats := fs.GetFileTestStat("/fake-dir/data/tmp") Expect(fileStats).NotTo(BeNil()) Expect(fileStats.FileType).To(Equal(fakesys.FakeFileType(fakesys.FakeFileTypeDir))) Expect(fileStats.FileMode).To(Equal(os.FileMode(0755))) }) It("returns error if creating new temp dir errs", func() { fs.MkdirAllError = errors.New("fake-mkdir-error") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-mkdir-error")) }) It("sets TMPDIR environment variable so that children of this process will use new temp dir", func() { err := act() Expect(err).NotTo(HaveOccurred()) Expect(os.Getenv("TMPDIR")).To(Equal("/fake-dir/data/tmp")) }) It("returns error if setting TMPDIR errs", func() { // uses os package; no way to trigger err }) ItDoesNotTryToUseLoopDevice := func() { It("does not create new tmp filesystem", func() { act() for _, cmd := range cmdRunner.RunCommands { Expect(cmd[0]).ToNot(Equal("truncate")) Expect(cmd[0]).ToNot(Equal("mke2fs")) } }) It("does not try to mount anything /tmp", func() { act() Expect(len(mounter.MountPartitionPaths)).To(Equal(0)) }) } Context("when UseDefaultTmpDir option is set to false", func() { BeforeEach(func() { options.UseDefaultTmpDir = false }) Context("when /tmp is not a mount point", func() { BeforeEach(func() { mounter.IsMountPointResult = false }) It("creates new tmp filesystem of 128MB placed in data dir", func() { err := act() Expect(err).NotTo(HaveOccurred()) Expect(cmdRunner.RunCommands[3]).To(Equal([]string{"truncate", "-s", "128M", "/fake-dir/data/root_tmp"})) Expect(cmdRunner.RunCommands[4]).To(Equal([]string{"chmod", "0700", "/fake-dir/data/root_tmp"})) Expect(cmdRunner.RunCommands[5]).To(Equal([]string{"mke2fs", "-t", "ext4", "-m", "1", "-F", "/fake-dir/data/root_tmp"})) }) It("mounts the new tmp filesystem over /tmp", func() { err := act() Expect(err).NotTo(HaveOccurred()) Expect(len(mounter.MountPartitionPaths)).To(Equal(1)) Expect(mounter.MountPartitionPaths[0]).To(Equal("/fake-dir/data/root_tmp")) Expect(mounter.MountMountPoints[0]).To(Equal("/tmp")) Expect(mounter.MountMountOptions[0]).To(Equal([]string{"-t", "ext4", "-o", "loop"})) }) It("returns error if mounting the new tmp filesystem fails", func() { mounter.MountErr = errors.New("fake-mount-error") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-mount-error")) }) It("changes permissions on /tmp again because it is a new mount", func() { err := act() Expect(err).NotTo(HaveOccurred()) Expect(cmdRunner.RunCommands[6]).To(Equal([]string{"chown", "root:vcap", "/tmp"})) Expect(cmdRunner.RunCommands[7]).To(Equal([]string{"chmod", "0770", "/tmp"})) }) }) Context("when /tmp is a mount point", func() { BeforeEach(func() { mounter.IsMountPointResult = true }) It("returns without an error", func() { err := act() Expect(err).ToNot(HaveOccurred()) }) ItDoesNotTryToUseLoopDevice() }) Context("when /tmp cannot be determined if it is a mount point", func() { BeforeEach(func() { mounter.IsMountPointErr = errors.New("fake-is-mount-point-error") }) It("returns error", func() { err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-is-mount-point-error")) }) ItDoesNotTryToUseLoopDevice() }) }) Context("when UseDefaultTmpDir option is set to true", func() { BeforeEach(func() { options.UseDefaultTmpDir = true }) It("returns without an error", func() { err := act() Expect(err).ToNot(HaveOccurred()) }) ItDoesNotTryToUseLoopDevice() }) }) Describe("MountPersistentDisk", func() { act := func() error { return platform.MountPersistentDisk( boshsettings.DiskSettings{Path: "fake-volume-id"}, "/mnt/point", ) } var ( partitioner *fakedisk.FakePartitioner formatter *fakedisk.FakeFormatter mounter *fakedisk.FakeMounter ) BeforeEach(func() { partitioner = diskManager.FakePartitioner formatter = diskManager.FakeFormatter mounter = diskManager.FakeMounter }) Context("when device path is successfully resolved", func() { BeforeEach(func() { devicePathResolver.RealDevicePath = "fake-real-device-path" }) Context("when UsePreformattedPersistentDisk set to false", func() { It("creates the mount directory with the correct permissions", func() { err := act() Expect(err).ToNot(HaveOccurred()) mountPoint := fs.GetFileTestStat("/mnt/point") Expect(mountPoint.FileType).To(Equal(fakesys.FakeFileTypeDir)) Expect(mountPoint.FileMode).To(Equal(os.FileMode(0700))) }) It("returns error when creating mount directory fails", func() { fs.MkdirAllError = errors.New("fake-mkdir-all-err") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-mkdir-all-err")) }) It("partitions the disk", func() { err := act() Expect(err).ToNot(HaveOccurred()) partitions := []boshdisk.Partition{{Type: boshdisk.PartitionTypeLinux}} Expect(partitioner.PartitionDevicePath).To(Equal("fake-real-device-path")) Expect(partitioner.PartitionPartitions).To(Equal(partitions)) }) It("formats the disk", func() { err := act() Expect(err).ToNot(HaveOccurred()) Expect(formatter.FormatPartitionPaths).To(Equal([]string{"fake-real-device-path1"})) Expect(formatter.FormatFsTypes).To(Equal([]boshdisk.FileSystemType{boshdisk.FileSystemExt4})) }) It("mounts the disk", func() { err := act() Expect(err).ToNot(HaveOccurred()) Expect(mounter.MountPartitionPaths).To(Equal([]string{"fake-real-device-path1"})) Expect(mounter.MountMountPoints).To(Equal([]string{"/mnt/point"})) Expect(mounter.MountMountOptions).To(Equal([][]string{nil})) }) }) Context("when UsePreformattedPersistentDisk set to true", func() { BeforeEach(func() { options.UsePreformattedPersistentDisk = true }) It("creates the mount directory with the correct permissions", func() { err := act() Expect(err).ToNot(HaveOccurred()) mountPoint := fs.GetFileTestStat("/mnt/point") Expect(mountPoint.FileType).To(Equal(fakesys.FakeFileTypeDir)) Expect(mountPoint.FileMode).To(Equal(os.FileMode(0700))) }) It("returns error when creating mount directory fails", func() { fs.MkdirAllError = errors.New("fake-mkdir-all-err") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-mkdir-all-err")) }) It("mounts volume at mount point", func() { err := act() Expect(err).ToNot(HaveOccurred()) Expect(len(mounter.MountPartitionPaths)).To(Equal(1)) Expect(mounter.MountPartitionPaths).To(Equal([]string{"fake-real-device-path"})) // no '1' because no partition Expect(mounter.MountMountPoints).To(Equal([]string{"/mnt/point"})) Expect(mounter.MountMountOptions).To(Equal([][]string{nil})) }) It("returns error when mounting fails", func() { mounter.MountErr = errors.New("fake-mount-err") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-mount-err")) }) It("does not partition the disk", func() { err := act() Expect(err).ToNot(HaveOccurred()) Expect(partitioner.PartitionCalled).To(BeFalse()) }) It("does not format the disk", func() { err := act() Expect(err).ToNot(HaveOccurred()) Expect(formatter.FormatCalled).To(BeFalse()) }) }) }) Context("when device path is not successfully resolved", func() { It("return an error", func() { devicePathResolver.GetRealDevicePathErr = errors.New("fake-get-real-device-path-err") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-get-real-device-path-err")) }) }) }) Describe("UnmountPersistentDisk", func() { act := func() (bool, error) { return platform.UnmountPersistentDisk(boshsettings.DiskSettings{Path: "fake-device-path"}) } var mounter *fakedisk.FakeMounter BeforeEach(func() { mounter = diskManager.FakeMounter }) Context("when device path can be resolved", func() { BeforeEach(func() { devicePathResolver.RealDevicePath = "fake-real-device-path" }) ItUnmountsPersistentDisk := func(expectedUnmountMountPoint string) { It("returs true without an error if unmounting succeeded", func() { mounter.UnmountDidUnmount = true didUnmount, err := act() Expect(err).NotTo(HaveOccurred()) Expect(didUnmount).To(BeTrue()) Expect(mounter.UnmountPartitionPathOrMountPoint).To(Equal(expectedUnmountMountPoint)) }) It("returs false without an error if was already unmounted", func() { mounter.UnmountDidUnmount = false didUnmount, err := act() Expect(err).NotTo(HaveOccurred()) Expect(didUnmount).To(BeFalse()) Expect(mounter.UnmountPartitionPathOrMountPoint).To(Equal(expectedUnmountMountPoint)) }) It("returns error if unmounting fails", func() { mounter.UnmountDidUnmount = false mounter.UnmountErr = errors.New("fake-unmount-err") didUnmount, err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-unmount-err")) Expect(didUnmount).To(BeFalse()) Expect(mounter.UnmountPartitionPathOrMountPoint).To(Equal(expectedUnmountMountPoint)) }) } Context("UsePreformattedPersistentDisk is set to false", func() { ItUnmountsPersistentDisk("fake-real-device-path1") // note partition '1' }) Context("UsePreformattedPersistentDisk is set to true", func() { BeforeEach(func() { options.UsePreformattedPersistentDisk = true }) ItUnmountsPersistentDisk("fake-real-device-path") // note no '1'; no partitions }) }) Context("when device path cannot be resolved", func() { BeforeEach(func() { devicePathResolver.GetRealDevicePathErr = errors.New("fake-get-real-device-path-err") devicePathResolver.GetRealDevicePathTimedOut = false }) It("returns error", func() { isMounted, err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-get-real-device-path-err")) Expect(isMounted).To(BeFalse()) }) }) Context("when device path cannot be resolved due to timeout", func() { BeforeEach(func() { devicePathResolver.GetRealDevicePathErr = errors.New("fake-get-real-device-path-err") devicePathResolver.GetRealDevicePathTimedOut = true }) It("does not return error", func() { isMounted, err := act() Expect(err).NotTo(HaveOccurred()) Expect(isMounted).To(BeFalse()) }) }) }) Describe("GetFileContentsFromCDROM", func() { It("delegates to cdutil", func() { cdutil.GetFilesContentsContents = [][]byte{[]byte("fake-contents")} filename := "fake-env" contents, err := platform.GetFileContentsFromCDROM(filename) Expect(err).NotTo(HaveOccurred()) Expect(cdutil.GetFilesContentsFileNames[0]).To(Equal(filename)) Expect(contents).To(Equal([]byte("fake-contents"))) }) }) Describe("GetFilesContentsFromDisk", func() { It("delegates to diskutil", func() { diskManager.FakeDiskUtil.GetFilesContentsContents = [][]byte{ []byte("fake-contents-1"), []byte("fake-contents-2"), } contents, err := platform.GetFilesContentsFromDisk( "fake-disk-path", []string{"fake-file-path-1", "fake-file-path-2"}, ) Expect(err).NotTo(HaveOccurred()) Expect(diskManager.DiskUtilDiskPath).To(Equal("fake-disk-path")) Expect(diskManager.FakeDiskUtil.GetFilesContentsFileNames).To(Equal( []string{"fake-file-path-1", "fake-file-path-2"}, )) Expect(contents).To(Equal([][]byte{ []byte("fake-contents-1"), []byte("fake-contents-2"), })) }) }) Describe("GetEphemeralDiskPath", func() { Context("when device path is an empty string", func() { It("returns an empty string", func() { devicePathResolver.RealDevicePath = "non-desired-device-path" diskSettings := boshsettings.DiskSettings{ ID: "fake-id", VolumeID: "fake-volume-id", Path: "", } Expect(platform.GetEphemeralDiskPath(diskSettings)).To(BeEmpty()) }) }) Context("when real device path was resolved without an error", func() { It("returns real device path and true", func() { devicePathResolver.RealDevicePath = "fake-real-device-path" realPath := platform.GetEphemeralDiskPath(boshsettings.DiskSettings{Path: "fake-device-path"}) Expect(realPath).To(Equal("fake-real-device-path")) }) }) Context("when real device path was not resolved without an error", func() { It("returns real device path and true", func() { devicePathResolver.GetRealDevicePathErr = errors.New("fake-get-real-device-path-err") realPath := platform.GetEphemeralDiskPath(boshsettings.DiskSettings{Path: "fake-device-path"}) Expect(realPath).To(Equal("")) }) }) }) Describe("MigratePersistentDisk", func() { var mounter *fakedisk.FakeMounter BeforeEach(func() { mounter = diskManager.FakeMounter }) It("migrate persistent disk", func() { err := platform.MigratePersistentDisk("/from/path", "/to/path") Expect(err).ToNot(HaveOccurred()) Expect(mounter.RemountAsReadonlyPath).To(Equal("/from/path")) Expect(len(cmdRunner.RunCommands)).To(Equal(1)) Expect(cmdRunner.RunCommands[0]).To(Equal([]string{"sh", "-c", "(tar -C /from/path -cf - .) | (tar -C /to/path -xpf -)"})) Expect(mounter.UnmountPartitionPathOrMountPoint).To(Equal("/from/path")) Expect(mounter.RemountFromMountPoint).To(Equal("/to/path")) Expect(mounter.RemountToMountPoint).To(Equal("/from/path")) }) }) Describe("IsPersistentDiskMounted", func() { act := func() (bool, error) { return platform.IsPersistentDiskMounted(boshsettings.DiskSettings{Path: "fake-device-path"}) } var mounter *fakedisk.FakeMounter BeforeEach(func() { mounter = diskManager.FakeMounter }) Context("when device path can be resolved", func() { BeforeEach(func() { devicePathResolver.RealDevicePath = "fake-real-device-path" }) ItChecksPersistentDiskMountPoint := func(expectedCheckedMountPoint string) { Context("when checking persistent disk mount point succeeds", func() { It("returns true if mount point exists", func() { mounter.IsMountedResult = true isMounted, err := act() Expect(err).NotTo(HaveOccurred()) Expect(isMounted).To(BeTrue()) Expect(mounter.IsMountedDevicePathOrMountPoint).To(Equal(expectedCheckedMountPoint)) }) It("returns false if mount point does not exist", func() { mounter.IsMountedResult = false isMounted, err := act() Expect(err).NotTo(HaveOccurred()) Expect(isMounted).To(BeFalse()) Expect(mounter.IsMountedDevicePathOrMountPoint).To(Equal(expectedCheckedMountPoint)) }) }) Context("checking persistent disk mount points fails", func() { It("returns error", func() { mounter.IsMountedResult = false mounter.IsMountedErr = errors.New("fake-is-mounted-err") isMounted, err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-is-mounted-err")) Expect(isMounted).To(BeFalse()) Expect(mounter.IsMountedDevicePathOrMountPoint).To(Equal(expectedCheckedMountPoint)) }) }) } Context("UsePreformattedPersistentDisk is set to false", func() { ItChecksPersistentDiskMountPoint("fake-real-device-path1") // note partition '1' }) Context("UsePreformattedPersistentDisk is set to true", func() { BeforeEach(func() { options.UsePreformattedPersistentDisk = true }) ItChecksPersistentDiskMountPoint("fake-real-device-path") // note no '1'; no partitions }) }) Context("when device path cannot be resolved", func() { BeforeEach(func() { devicePathResolver.GetRealDevicePathErr = errors.New("fake-get-real-device-path-err") devicePathResolver.GetRealDevicePathTimedOut = false }) It("returns error", func() { isMounted, err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-get-real-device-path-err")) Expect(isMounted).To(BeFalse()) }) }) Context("when device path cannot be resolved due to timeout", func() { BeforeEach(func() { devicePathResolver.GetRealDevicePathErr = errors.New("fake-get-real-device-path-err") devicePathResolver.GetRealDevicePathTimedOut = true }) It("does not return error", func() { isMounted, err := act() Expect(err).NotTo(HaveOccurred()) Expect(isMounted).To(BeFalse()) }) }) }) Describe("StartMonit", func() { It("creates a symlink between /etc/service/monit and /etc/sv/monit", func() { err := platform.StartMonit() Expect(err).NotTo(HaveOccurred()) target, _ := fs.ReadLink(filepath.Join("/etc", "service", "monit")) Expect(target).To(Equal(filepath.Join("/etc", "sv", "monit"))) }) It("retries to start monit", func() { err := platform.StartMonit() Expect(err).NotTo(HaveOccurred()) Expect(monitRetryStrategy.TryCalled).To(BeTrue()) }) It("returns error if retrying to start monit fails", func() { monitRetryStrategy.TryErr = errors.New("fake-retry-monit-error") err := platform.StartMonit() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-retry-monit-error")) }) }) Describe("SetupMonitUser", func() { It("setup monit user if file does not exist", func() { err := platform.SetupMonitUser() Expect(err).NotTo(HaveOccurred()) monitUserFileStats := fs.GetFileTestStat("/fake-dir/monit/monit.user") Expect(monitUserFileStats).ToNot(BeNil()) Expect(monitUserFileStats.StringContents()).To(Equal("vcap:random-password")) }) It("setup monit user if file does exist", func() { fs.WriteFileString("/fake-dir/monit/monit.user", "vcap:other-random-password") err := platform.SetupMonitUser() Expect(err).NotTo(HaveOccurred()) monitUserFileStats := fs.GetFileTestStat("/fake-dir/monit/monit.user") Expect(monitUserFileStats).ToNot(BeNil()) Expect(monitUserFileStats.StringContents()).To(Equal("vcap:other-random-password")) }) }) Describe("GetMonitCredentials", func() { It("get monit credentials reads monit file from disk", func() { fs.WriteFileString("/fake-dir/monit/monit.user", "fake-user:fake-random-password") username, password, err := platform.GetMonitCredentials() Expect(err).NotTo(HaveOccurred()) Expect(username).To(Equal("fake-user")) Expect(password).To(Equal("fake-random-password")) }) It("get monit credentials errs when invalid file format", func() { fs.WriteFileString("/fake-dir/monit/monit.user", "fake-user") _, _, err := platform.GetMonitCredentials() Expect(err).To(HaveOccurred()) }) It("get monit credentials leaves colons in password intact", func() { fs.WriteFileString("/fake-dir/monit/monit.user", "fake-user:fake:random:password") username, password, err := platform.GetMonitCredentials() Expect(err).NotTo(HaveOccurred()) Expect(username).To(Equal("fake-user")) Expect(password).To(Equal("fake:random:password")) }) }) Describe("PrepareForNetworkingChange", func() { It("removes the network persistent rules file", func() { fs.WriteFile("/etc/udev/rules.d/70-persistent-net.rules", []byte{}) err := platform.PrepareForNetworkingChange() Expect(err).NotTo(HaveOccurred()) Expect(fs.FileExists("/etc/udev/rules.d/70-persistent-net.rules")).To(BeFalse()) }) It("returns error if removing persistent rules file fails", func() { fs.RemoveAllError = errors.New("fake-remove-all-error") err := platform.PrepareForNetworkingChange() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-remove-all-error")) }) }) Describe("SetupNetworking", func() { It("delegates to the NetManager", func() { networks := boshsettings.Networks{} err := platform.SetupNetworking(networks) Expect(err).ToNot(HaveOccurred()) Expect(netManager.SetupNetworkingNetworks).To(Equal(networks)) }) }) Describe("GetConfiguredNetworkInterfaces", func() { It("delegates to the NetManager", func() { netmanagerInterfaces := []string{"fake-eth0", "fake-eth1"} netManager.GetConfiguredNetworkInterfacesInterfaces = netmanagerInterfaces interfaces, err := platform.GetConfiguredNetworkInterfaces() Expect(err).ToNot(HaveOccurred()) Expect(interfaces).To(Equal(netmanagerInterfaces)) }) }) Describe("GetDefaultNetwork", func() { It("delegates to the defaultNetworkResolver", func() { defaultNetwork := boshsettings.Network{IP: "1.2.3.4"} fakeDefaultNetworkResolver.GetDefaultNetworkNetwork = defaultNetwork network, err := platform.GetDefaultNetwork() Expect(err).ToNot(HaveOccurred()) Expect(network).To(Equal(defaultNetwork)) }) }) }
func (app *app) Setup(args []string) error { opts, err := ParseOptions(args) if err != nil { return bosherr.WrapError(err, "Parsing options") } config, err := app.loadConfig(opts.ConfigPath) if err != nil { return bosherr.WrapError(err, "Loading config") } dirProvider := boshdirs.NewProvider(opts.BaseDirectory) // Pulled outside of the platform provider so bosh-init will not pull in // sigar when cross compiling linux -> darwin sigarCollector := boshsigar.NewSigarStatsCollector(&sigar.ConcreteSigar{}) platformProvider := boshplatform.NewProvider(app.logger, dirProvider, sigarCollector, config.Platform) app.platform, err = platformProvider.Get(opts.PlatformName) if err != nil { return bosherr.WrapError(err, "Getting platform") } settingsSourceFactory := boshinf.NewSettingsSourceFactory(config.Infrastructure.Settings, app.platform, app.logger) settingsSource, err := settingsSourceFactory.New() if err != nil { return bosherr.WrapError(err, "Getting Settings Source") } settingsService := boshsettings.NewService( app.platform.GetFs(), filepath.Join(dirProvider.BoshDir(), "settings.json"), settingsSource, app.platform, app.logger, ) boot := boshagent.NewBootstrap( app.platform, dirProvider, settingsService, app.logger, ) if err = boot.Run(); err != nil { return bosherr.WrapError(err, "Running bootstrap") } mbusHandlerProvider := boshmbus.NewHandlerProvider(settingsService, app.logger) mbusHandler, err := mbusHandlerProvider.Get(app.platform, dirProvider) if err != nil { return bosherr.WrapError(err, "Getting mbus handler") } blobstoreProvider := boshblob.NewProvider(app.platform.GetFs(), app.platform.GetRunner(), dirProvider.EtcDir(), app.logger) blobsettings := settingsService.GetSettings().Blobstore blobstore, err := blobstoreProvider.Get(blobsettings.Type, blobsettings.Options) if err != nil { return bosherr.WrapError(err, "Getting blobstore") } monitClientProvider := boshmonit.NewProvider(app.platform, app.logger) monitClient, err := monitClientProvider.Get() if err != nil { return bosherr.WrapError(err, "Getting monit client") } jobSupervisorProvider := boshjobsuper.NewProvider( app.platform, monitClient, app.logger, dirProvider, mbusHandler, ) jobSupervisor, err := jobSupervisorProvider.Get(opts.JobSupervisor) if err != nil { return bosherr.WrapError(err, "Getting job supervisor") } notifier := boshnotif.NewNotifier(mbusHandler) applier, compiler := app.buildApplierAndCompiler(dirProvider, blobstore, jobSupervisor) uuidGen := boshuuid.NewGenerator() taskService := boshtask.NewAsyncTaskService(uuidGen, app.logger) taskManager := boshtask.NewManagerProvider().NewManager( app.logger, app.platform.GetFs(), dirProvider.BoshDir(), ) specFilePath := filepath.Join(dirProvider.BoshDir(), "spec.json") specService := boshas.NewConcreteV1Service( app.platform.GetFs(), specFilePath, ) drainScriptProvider := boshdrain.NewConcreteScriptProvider( app.platform.GetRunner(), app.platform.GetFs(), dirProvider, ) actionFactory := boshaction.NewFactory( settingsService, app.platform, blobstore, taskService, notifier, applier, compiler, jobSupervisor, specService, drainScriptProvider, app.logger, ) actionRunner := boshaction.NewRunner() actionDispatcher := boshagent.NewActionDispatcher( app.logger, taskService, taskManager, actionFactory, actionRunner, ) syslogServer := boshsyslog.NewServer(33331, app.logger) timeService := clock.NewClock() app.agent = boshagent.New( app.logger, mbusHandler, app.platform, actionDispatcher, jobSupervisor, specService, syslogServer, time.Minute, settingsService, uuidGen, timeService, ) return nil }
func (app *app) Setup(args []string) error { opts, err := ParseOptions(args) if err != nil { return bosherr.WrapError(err, "Parsing options") } config, err := app.loadConfig(opts.ConfigPath) if err != nil { return bosherr.WrapError(err, "Loading config") } app.digestProvider = boshcrypto.NewDigestProvider(app.fs) app.dirProvider = boshdirs.NewProvider(opts.BaseDirectory) app.logStemcellInfo() statsCollector := boshsigar.NewSigarStatsCollector(&sigar.ConcreteSigar{}) state, err := boshplatform.NewBootstrapState(app.fs, filepath.Join(app.dirProvider.BoshDir(), "agent_state.json")) if err != nil { return bosherr.WrapError(err, "Loading state") } timeService := clock.NewClock() platformProvider := boshplatform.NewProvider(app.logger, app.dirProvider, statsCollector, app.fs, config.Platform, state, timeService) app.platform, err = platformProvider.Get(opts.PlatformName) if err != nil { return bosherr.WrapError(err, "Getting platform") } settingsSourceFactory := boshinf.NewSettingsSourceFactory(config.Infrastructure.Settings, app.platform, app.logger) settingsSource, err := settingsSourceFactory.New() if err != nil { return bosherr.WrapError(err, "Getting Settings Source") } settingsService := boshsettings.NewService( app.platform.GetFs(), filepath.Join(app.dirProvider.BoshDir(), "settings.json"), settingsSource, app.platform, app.logger, ) boot := boshagent.NewBootstrap( app.platform, app.dirProvider, settingsService, app.logger, ) if err = boot.Run(); err != nil { return bosherr.WrapError(err, "Running bootstrap") } mbusHandlerProvider := boshmbus.NewHandlerProvider(settingsService, app.logger) mbusHandler, err := mbusHandlerProvider.Get(app.platform, app.dirProvider) if err != nil { return bosherr.WrapError(err, "Getting mbus handler") } blobManager := boshblob.NewBlobManager(app.platform.GetFs(), app.dirProvider.BlobsDir()) blobstore, err := app.setupBlobstore(settingsService.GetSettings().Blobstore, blobManager) if err != nil { return bosherr.WrapError(err, "Getting blobstore") } monitClientProvider := boshmonit.NewProvider(app.platform, app.logger) monitClient, err := monitClientProvider.Get() if err != nil { return bosherr.WrapError(err, "Getting monit client") } jobSupervisorProvider := boshjobsuper.NewProvider( app.platform, monitClient, app.logger, app.dirProvider, mbusHandler, ) jobSupervisor, err := jobSupervisorProvider.Get(opts.JobSupervisor) if err != nil { return bosherr.WrapError(err, "Getting job supervisor") } notifier := boshnotif.NewNotifier(mbusHandler) applier, compiler := app.buildApplierAndCompiler(app.dirProvider, blobstore, jobSupervisor) uuidGen := boshuuid.NewGenerator() taskService := boshtask.NewAsyncTaskService(uuidGen, app.logger) taskManager := boshtask.NewManagerProvider().NewManager( app.logger, app.platform.GetFs(), app.dirProvider.BoshDir(), ) specFilePath := filepath.Join(app.dirProvider.BoshDir(), "spec.json") specService := boshas.NewConcreteV1Service( app.platform.GetFs(), specFilePath, ) jobScriptProvider := boshscript.NewConcreteJobScriptProvider( app.platform.GetRunner(), app.platform.GetFs(), app.platform.GetDirProvider(), timeService, app.logger, ) actionFactory := boshaction.NewFactory( settingsService, app.platform, blobstore, blobManager, taskService, notifier, applier, compiler, jobSupervisor, specService, jobScriptProvider, app.logger, ) actionRunner := boshaction.NewRunner() actionDispatcher := boshagent.NewActionDispatcher( app.logger, taskService, taskManager, actionFactory, actionRunner, ) syslogServer := boshsyslog.NewServer(33331, net.Listen, app.logger) app.agent = boshagent.New( app.logger, mbusHandler, app.platform, actionDispatcher, jobSupervisor, specService, syslogServer, time.Second*30, settingsService, uuidGen, timeService, ) return nil }