func init() { const expectedUbuntuDHCPConfig = `# Generated by bosh-agent option rfc3442-classless-static-routes code 121 = array of unsigned integer 8; send host-name "<hostname>"; request subnet-mask, broadcast-address, time-offset, routers, domain-name, domain-name-servers, domain-search, host-name, netbios-name-servers, netbios-scope, interface-mtu, rfc3442-classless-static-routes, ntp-servers; prepend domain-name-servers zz.zz.zz.zz; prepend domain-name-servers yy.yy.yy.yy; prepend domain-name-servers xx.xx.xx.xx; ` Describe("ubuntu", func() { var ( collector *fakestats.FakeStatsCollector fs *fakesys.FakeFileSystem cmdRunner *fakesys.FakeCmdRunner diskManager *fakedisk.FakeDiskManager dirProvider boshdirs.DirectoriesProvider platform Platform cdutil *fakecd.FakeCdUtil compressor boshcmd.Compressor copier boshcmd.Copier vitalsService boshvitals.Service logger boshlog.Logger ) BeforeEach(func() { collector = &fakestats.FakeStatsCollector{} fs = fakesys.NewFakeFileSystem() cmdRunner = fakesys.NewFakeCmdRunner() diskManager = fakedisk.NewFakeDiskManager() dirProvider = boshdirs.NewDirectoriesProvider("/fake-dir") cdutil = fakecd.NewFakeCdUtil() compressor = boshcmd.NewTarballCompressor(cmdRunner, fs) copier = boshcmd.NewCpCopier(cmdRunner, fs) vitalsService = boshvitals.NewService(collector, dirProvider) logger = boshlog.NewLogger(boshlog.LevelNone) }) JustBeforeEach(func() { netManager := boshnet.NewUbuntuNetManager(fs, cmdRunner, 1*time.Millisecond) platform = NewLinuxPlatform( fs, cmdRunner, collector, compressor, copier, dirProvider, vitalsService, cdutil, diskManager, netManager, 1*time.Millisecond, logger, ) }) Describe("SetupDhcp", func() { networks := boshsettings.Networks{ "bosh": boshsettings.Network{ Default: []string{"dns"}, DNS: []string{"xx.xx.xx.xx", "yy.yy.yy.yy", "zz.zz.zz.zz"}, }, "vip": boshsettings.Network{ Default: []string{}, DNS: []string{"aa.aa.aa.aa"}, }, } Context("when dhcp was not previously configured", func() { It("updates dhclient.conf", func() { err := platform.SetupDhcp(networks) Expect(err).ToNot(HaveOccurred()) dhcpConfig := fs.GetFileTestStat("/etc/dhcp3/dhclient.conf") Expect(dhcpConfig).ToNot(BeNil()) Expect(dhcpConfig.StringContents()).To(Equal(expectedUbuntuDHCPConfig)) }) It("restarts dhclient", func() { err := platform.SetupDhcp(networks) Expect(err).ToNot(HaveOccurred()) Expect(len(cmdRunner.RunCommands)).To(Equal(2)) Expect(cmdRunner.RunCommands[0]).To(Equal([]string{"pkill", "dhclient3"})) Expect(cmdRunner.RunCommands[1]).To(Equal([]string{"/etc/init.d/networking", "restart"})) }) }) Context("when dhcp was previously configured with different configuration", func() { BeforeEach(func() { fs.WriteFileString("/etc/dhcp3/dhclient.conf", "fake-other-configuration") }) It("sets up dhcp and restarts dhclient", func() { err := platform.SetupDhcp(networks) Expect(err).ToNot(HaveOccurred()) dhcpConfig := fs.GetFileTestStat("/etc/dhcp3/dhclient.conf") Expect(dhcpConfig).ToNot(BeNil()) Expect(dhcpConfig.StringContents()).To(Equal(expectedUbuntuDHCPConfig)) }) It("sets up dhcp and restarts dhclient", func() { err := platform.SetupDhcp(networks) Expect(err).ToNot(HaveOccurred()) Expect(len(cmdRunner.RunCommands)).To(Equal(2)) Expect(cmdRunner.RunCommands[0]).To(Equal([]string{"pkill", "dhclient3"})) Expect(cmdRunner.RunCommands[1]).To(Equal([]string{"/etc/init.d/networking", "restart"})) }) }) Context("when dhcp was previously configured with the same configuration", func() { BeforeEach(func() { fs.WriteFileString("/etc/dhcp3/dhclient.conf", expectedUbuntuDHCPConfig) }) It("does not restart dhclient", func() { err := platform.SetupDhcp(networks) Expect(err).ToNot(HaveOccurred()) dhcpConfig := fs.GetFileTestStat("/etc/dhcp3/dhclient.conf") Expect(dhcpConfig).ToNot(BeNil()) Expect(dhcpConfig.StringContents()).To(Equal(expectedUbuntuDHCPConfig)) }) It("does not restart dhclient", func() { err := platform.SetupDhcp(networks) Expect(err).ToNot(HaveOccurred()) Expect(len(cmdRunner.RunCommands)).To(Equal(0)) }) }) }) Describe("SetupManualNetworking", func() { BeforeEach(func() { // For mac addr to interface resolution fs.WriteFile("/sys/class/net/eth0", []byte{}) fs.WriteFileString("/sys/class/net/eth0/address", "22:00:0a:1f:ac:2a\n") fs.SetGlob("/sys/class/net/*", []string{"/sys/class/net/eth0"}) }) networks := boshsettings.Networks{ "bosh": boshsettings.Network{ Default: []string{"dns", "gateway"}, IP: "192.168.195.6", Netmask: "255.255.255.0", Gateway: "192.168.195.1", Mac: "22:00:0a:1f:ac:2a", DNS: []string{"10.80.130.2", "10.80.130.1"}, }, } Context("when manual networking was not previously configured", func() { It("writes /etc/network/interfaces", func() { err := platform.SetupManualNetworking(networks) Expect(err).ToNot(HaveOccurred()) networkConfig := fs.GetFileTestStat("/etc/network/interfaces") Expect(networkConfig).ToNot(BeNil()) Expect(networkConfig.StringContents()).To(Equal(expectedUbuntuNetworkInterfaces)) }) It("restarts networking", func() { err := platform.SetupManualNetworking(networks) Expect(err).ToNot(HaveOccurred()) Expect(len(cmdRunner.RunCommands) >= 2).To(BeTrue()) Expect(cmdRunner.RunCommands[0]).To(Equal([]string{"service", "network-interface", "stop", "INTERFACE=eth0"})) Expect(cmdRunner.RunCommands[1]).To(Equal([]string{"service", "network-interface", "start", "INTERFACE=eth0"})) }) It("updates dns", func() { err := platform.SetupManualNetworking(networks) Expect(err).ToNot(HaveOccurred()) resolvConf := fs.GetFileTestStat("/etc/resolv.conf") Expect(resolvConf).ToNot(BeNil()) Expect(resolvConf.StringContents()).To(Equal(expectedUbuntuResolvConf)) }) It("starts sending arping", func() { err := platform.SetupManualNetworking(networks) Expect(err).ToNot(HaveOccurred()) time.Sleep(100 * time.Millisecond) Expect(cmdRunner.RunCommands[2]).To(Equal([]string{"arping", "-c", "1", "-U", "-I", "eth0", "192.168.195.6"})) Expect(cmdRunner.RunCommands[7]).To(Equal([]string{"arping", "-c", "1", "-U", "-I", "eth0", "192.168.195.6"})) }) }) Context("when manual networking was previously configured with different configuration", func() { BeforeEach(func() { fs.WriteFileString("/etc/network/interfaces", "fake-manual-config") }) It("updates /etc/network/interfaces", func() { err := platform.SetupManualNetworking(networks) Expect(err).ToNot(HaveOccurred()) networkConfig := fs.GetFileTestStat("/etc/network/interfaces") Expect(networkConfig).ToNot(BeNil()) Expect(networkConfig.StringContents()).To(Equal(expectedUbuntuNetworkInterfaces)) }) It("restarts networking", func() { err := platform.SetupManualNetworking(networks) Expect(err).ToNot(HaveOccurred()) Expect(len(cmdRunner.RunCommands) >= 2).To(BeTrue()) Expect(cmdRunner.RunCommands[0]).To(Equal([]string{"service", "network-interface", "stop", "INTERFACE=eth0"})) Expect(cmdRunner.RunCommands[1]).To(Equal([]string{"service", "network-interface", "start", "INTERFACE=eth0"})) }) It("updates dns", func() { err := platform.SetupManualNetworking(networks) Expect(err).ToNot(HaveOccurred()) resolvConf := fs.GetFileTestStat("/etc/resolv.conf") Expect(resolvConf).ToNot(BeNil()) Expect(resolvConf.StringContents()).To(Equal(expectedUbuntuResolvConf)) }) It("starts sending arping", func() { err := platform.SetupManualNetworking(networks) Expect(err).ToNot(HaveOccurred()) time.Sleep(100 * time.Millisecond) Expect(cmdRunner.RunCommands[2]).To(Equal([]string{"arping", "-c", "1", "-U", "-I", "eth0", "192.168.195.6"})) Expect(cmdRunner.RunCommands[7]).To(Equal([]string{"arping", "-c", "1", "-U", "-I", "eth0", "192.168.195.6"})) }) }) Context("when manual networking was previously configured with same configuration", func() { BeforeEach(func() { fs.WriteFileString("/etc/network/interfaces", expectedUbuntuNetworkInterfaces) }) It("keeps same /etc/network/interfaces", func() { err := platform.SetupManualNetworking(networks) Expect(err).ToNot(HaveOccurred()) networkConfig := fs.GetFileTestStat("/etc/network/interfaces") Expect(networkConfig).ToNot(BeNil()) Expect(networkConfig.StringContents()).To(Equal(expectedUbuntuNetworkInterfaces)) }) It("does not restart networking because configuration did not change", func() { err := platform.SetupManualNetworking(networks) Expect(err).ToNot(HaveOccurred()) for _, cmd := range cmdRunner.RunCommands { Expect(cmd[0]).ToNot(Equal("service")) } }) It("updates /etc/resolv.conf for DNS", func() { err := platform.SetupManualNetworking(networks) Expect(err).ToNot(HaveOccurred()) resolvConf := fs.GetFileTestStat("/etc/resolv.conf") Expect(resolvConf).ToNot(BeNil()) Expect(resolvConf.StringContents()).To(Equal(expectedUbuntuResolvConf)) }) It("starts sending 6 arp ping", func() { err := platform.SetupManualNetworking(networks) Expect(err).ToNot(HaveOccurred()) time.Sleep(100 * time.Millisecond) Expect(len(cmdRunner.RunCommands)).To(Equal(6)) Expect(cmdRunner.RunCommands[0]).To(Equal([]string{"arping", "-c", "1", "-U", "-I", "eth0", "192.168.195.6"})) Expect(cmdRunner.RunCommands[5]).To(Equal([]string{"arping", "-c", "1", "-U", "-I", "eth0", "192.168.195.6"})) }) }) }) }) }
func init() { Describe("renderedJobApplier", func() { var ( jobsBc *fakebc.FakeBundleCollection jobSupervisor *fakejobsuper.FakeJobSupervisor packageApplierProvider *fakepa.FakePackageApplierProvider blobstore *fakeblob.FakeBlobstore compressor *fakecmd.FakeCompressor fs *fakesys.FakeFileSystem applier JobApplier ) BeforeEach(func() { jobsBc = fakebc.NewFakeBundleCollection() jobSupervisor = fakejobsuper.NewFakeJobSupervisor() packageApplierProvider = fakepa.NewFakePackageApplierProvider() blobstore = fakeblob.NewFakeBlobstore() fs = fakesys.NewFakeFileSystem() compressor = fakecmd.NewFakeCompressor() logger := boshlog.NewLogger(boshlog.LevelNone) applier = NewRenderedJobApplier( jobsBc, jobSupervisor, packageApplierProvider, blobstore, compressor, fs, logger, ) }) Describe("Prepare & Apply", func() { var ( job models.Job bundle *fakebc.FakeBundle ) BeforeEach(func() { job, bundle = buildJob(jobsBc) }) ItInstallsJob := func(act func() error) { It("returns error when installing job fails", func() { bundle.InstallError = errors.New("fake-install-error") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-install-error")) }) It("downloads and later cleans up downloaded job template blob", func() { blobstore.GetFileName = "/fake-blobstore-file-name" err := act() Expect(err).ToNot(HaveOccurred()) Expect(blobstore.GetBlobIDs[0]).To(Equal("fake-blobstore-id")) Expect(blobstore.GetFingerprints[0]).To(Equal("fake-blob-sha1")) // downloaded file is cleaned up Expect(blobstore.CleanUpFileName).To(Equal("/fake-blobstore-file-name")) }) It("returns error when downloading job template blob fails", func() { blobstore.GetError = errors.New("fake-get-error") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-get-error")) }) It("decompresses job template blob to tmp path and later cleans it up", func() { fs.TempDirDir = "/fake-tmp-dir" blobstore.GetFileName = "/fake-blobstore-file-name" var tmpDirExistsBeforeInstall bool bundle.InstallCallBack = func() { tmpDirExistsBeforeInstall = true } err := act() Expect(err).ToNot(HaveOccurred()) Expect(compressor.DecompressFileToDirTarballPaths[0]).To(Equal("/fake-blobstore-file-name")) Expect(compressor.DecompressFileToDirDirs[0]).To(Equal("/fake-tmp-dir")) // tmp dir exists before bundle install Expect(tmpDirExistsBeforeInstall).To(BeTrue()) // tmp dir is cleaned up after install Expect(fs.FileExists(fs.TempDirDir)).To(BeFalse()) }) It("returns error when temporary directory creation fails", func() { fs.TempDirError = errors.New("fake-filesystem-tempdir-error") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-filesystem-tempdir-error")) }) It("returns error when decompressing job template fails", func() { compressor.DecompressFileToDirErr = errors.New("fake-decompress-error") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-decompress-error")) }) It("returns error when getting the list of bin files fails", func() { fs.GlobErr = errors.New("fake-glob-error") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-glob-error")) }) It("returns error when changing permissions on bin files fails", func() { fs.TempDirDir = "/fake-tmp-dir" fs.SetGlob("/fake-tmp-dir/fake-path-in-archive/bin/*", []string{ "/fake-tmp-dir/fake-path-in-archive/bin/test", }) fs.ChmodErr = errors.New("fake-chmod-error") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-chmod-error")) }) It("installs bundle from decompressed tmp path of a job template", func() { fs.TempDirDir = "/fake-tmp-dir" var installedBeforeDecompression bool compressor.DecompressFileToDirCallBack = func() { installedBeforeDecompression = bundle.Installed } err := act() Expect(err).ToNot(HaveOccurred()) // bundle installation did not happen before decompression Expect(installedBeforeDecompression).To(BeFalse()) // make sure that bundle install happened after decompression Expect(bundle.InstallSourcePath).To(Equal("/fake-tmp-dir/fake-path-in-archive")) }) It("sets executable bit for files in bin", func() { fs.TempDirDir = "/fake-tmp-dir" compressor.DecompressFileToDirCallBack = func() { fs.WriteFile("/fake-tmp-dir/fake-path-in-archive/bin/test1", []byte{}) fs.WriteFile("/fake-tmp-dir/fake-path-in-archive/bin/test2", []byte{}) fs.WriteFile("/fake-tmp-dir/fake-path-in-archive/config/test", []byte{}) } fs.SetGlob("/fake-tmp-dir/fake-path-in-archive/bin/*", []string{ "/fake-tmp-dir/fake-path-in-archive/bin/test1", "/fake-tmp-dir/fake-path-in-archive/bin/test2", }) var binTest1Stats, binTest2Stats, configTestStats *fakesys.FakeFileStats bundle.InstallCallBack = func() { binTest1Stats = fs.GetFileTestStat("/fake-tmp-dir/fake-path-in-archive/bin/test1") binTest2Stats = fs.GetFileTestStat("/fake-tmp-dir/fake-path-in-archive/bin/test2") configTestStats = fs.GetFileTestStat("/fake-tmp-dir/fake-path-in-archive/config/test") } err := act() Expect(err).ToNot(HaveOccurred()) // bin files are executable Expect(int(binTest1Stats.FileMode)).To(Equal(0755)) Expect(int(binTest2Stats.FileMode)).To(Equal(0755)) // non-bin files are not made executable Expect(int(configTestStats.FileMode)).ToNot(Equal(0755)) }) } ItUpdatesPackages := func(act func() error) { var packageApplier *fakepa.FakePackageApplier BeforeEach(func() { packageApplier = fakepa.NewFakePackageApplier() packageApplierProvider.JobSpecificPackageAppliers[job.Name] = packageApplier }) It("applies each package that job depends on and then cleans up packages", func() { err := act() Expect(err).ToNot(HaveOccurred()) Expect(packageApplier.ActionsCalled).To(Equal([]string{"Apply", "Apply", "KeepOnly"})) Expect(len(packageApplier.AppliedPackages)).To(Equal(2)) // present Expect(packageApplier.AppliedPackages).To(Equal(job.Packages)) }) It("returns error when applying package that job depends on fails", func() { packageApplier.ApplyError = errors.New("fake-apply-err") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-apply-err")) }) It("keeps only currently required packages but does not completely uninstall them", func() { err := act() Expect(err).ToNot(HaveOccurred()) Expect(len(packageApplier.KeptOnlyPackages)).To(Equal(2)) // present Expect(packageApplier.KeptOnlyPackages).To(Equal(job.Packages)) }) It("returns error when keeping only currently required packages fails", func() { packageApplier.KeepOnlyErr = errors.New("fake-keep-only-err") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-keep-only-err")) }) } Describe("Prepare", func() { act := func() error { return applier.Prepare(job) } It("return an error if getting file bundle fails", func() { jobsBc.GetErr = errors.New("fake-get-bundle-error") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-get-bundle-error")) }) It("returns an error if checking for installed path fails", func() { bundle.IsInstalledErr = errors.New("fake-is-installed-error") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-is-installed-error")) }) Context("when job is already installed", func() { BeforeEach(func() { bundle.Installed = true }) It("does not install", func() { err := act() Expect(err).ToNot(HaveOccurred()) Expect(bundle.ActionsCalled).To(Equal([]string{})) // no Install }) It("does not download the job template", func() { err := act() Expect(err).ToNot(HaveOccurred()) Expect(blobstore.GetBlobIDs).To(BeNil()) }) }) Context("when job is not installed", func() { BeforeEach(func() { bundle.Installed = false }) It("installs job (but does not enable)", func() { err := act() Expect(err).ToNot(HaveOccurred()) Expect(bundle.ActionsCalled).To(Equal([]string{"Install"})) }) ItInstallsJob(act) }) }) Describe("Apply", func() { act := func() error { return applier.Apply(job) } It("return an error if getting file bundle fails", func() { jobsBc.GetErr = errors.New("fake-get-bundle-error") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-get-bundle-error")) }) It("returns an error if checking for installed path fails", func() { bundle.IsInstalledErr = errors.New("fake-is-installed-error") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-is-installed-error")) }) Context("when job is already installed", func() { BeforeEach(func() { bundle.Installed = true }) It("does not install but only enables job", func() { err := act() Expect(err).ToNot(HaveOccurred()) Expect(bundle.ActionsCalled).To(Equal([]string{"Enable"})) // no Install }) It("returns error when job enable fails", func() { bundle.EnableError = errors.New("fake-enable-error") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-enable-error")) }) It("does not download the job template", func() { err := act() Expect(err).ToNot(HaveOccurred()) Expect(blobstore.GetBlobIDs).To(BeNil()) }) ItUpdatesPackages(act) }) Context("when job is not installed", func() { BeforeEach(func() { bundle.Installed = false }) It("installs and enables job", func() { err := act() Expect(err).ToNot(HaveOccurred()) Expect(bundle.ActionsCalled).To(Equal([]string{"Install", "Enable"})) }) It("returns error when job enable fails", func() { bundle.EnableError = errors.New("fake-enable-error") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-enable-error")) }) ItInstallsJob(act) ItUpdatesPackages(act) }) }) }) Describe("Configure", func() { It("adds job to the job supervisor", func() { job, bundle := buildJob(jobsBc) fs := fakesys.NewFakeFileSystem() fs.WriteFileString("/path/to/job/monit", "some conf") fs.SetGlob("/path/to/job/*.monit", []string{"/path/to/job/subjob.monit"}) bundle.GetDirPath = "/path/to/job" bundle.GetDirFs = fs err := applier.Configure(job, 0) Expect(err).ToNot(HaveOccurred()) Expect(2).To(Equal(len(jobSupervisor.AddJobArgs))) firstArgs := fakejobsuper.AddJobArgs{ Name: job.Name, Index: 0, ConfigPath: "/path/to/job/monit", } secondArgs := fakejobsuper.AddJobArgs{ Name: job.Name + "_subjob", Index: 0, ConfigPath: "/path/to/job/subjob.monit", } Expect(firstArgs).To(Equal(jobSupervisor.AddJobArgs[0])) Expect(secondArgs).To(Equal(jobSupervisor.AddJobArgs[1])) }) }) Describe("KeepOnly", func() { It("first disables and then uninstalls jobs that are not in keeponly list", func() { _, bundle1 := buildJob(jobsBc) job2, bundle2 := buildJob(jobsBc) _, bundle3 := buildJob(jobsBc) job4, bundle4 := buildJob(jobsBc) jobsBc.ListBundles = []boshbc.Bundle{bundle1, bundle2, bundle3, bundle4} err := applier.KeepOnly([]models.Job{job4, job2}) Expect(err).ToNot(HaveOccurred()) Expect(bundle1.ActionsCalled).To(Equal([]string{"Disable", "Uninstall"})) Expect(bundle2.ActionsCalled).To(Equal([]string{})) Expect(bundle3.ActionsCalled).To(Equal([]string{"Disable", "Uninstall"})) Expect(bundle4.ActionsCalled).To(Equal([]string{})) }) It("returns error when bundle collection fails to return list of installed bundles", func() { jobsBc.ListErr = errors.New("fake-bc-list-error") err := applier.KeepOnly([]models.Job{}) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-bc-list-error")) }) It("returns error when bundle collection cannot retrieve bundle for keep-only job", func() { job1, bundle1 := buildJob(jobsBc) jobsBc.ListBundles = []boshbc.Bundle{bundle1} jobsBc.GetErr = errors.New("fake-bc-get-error") err := applier.KeepOnly([]models.Job{job1}) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-bc-get-error")) }) It("returns error when at least one bundle cannot be disabled", func() { _, bundle1 := buildJob(jobsBc) jobsBc.ListBundles = []boshbc.Bundle{bundle1} bundle1.DisableErr = errors.New("fake-bc-disable-error") err := applier.KeepOnly([]models.Job{}) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-bc-disable-error")) }) It("returns error when at least one bundle cannot be uninstalled", func() { _, bundle1 := buildJob(jobsBc) jobsBc.ListBundles = []boshbc.Bundle{bundle1} bundle1.UninstallErr = errors.New("fake-bc-uninstall-error") err := applier.KeepOnly([]models.Job{}) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-bc-uninstall-error")) }) }) }) }
func init() { const expectedUbuntuDHCPConfig = `# Generated by bosh-agent option rfc3442-classless-static-routes code 121 = array of unsigned integer 8; send host-name "<hostname>"; request subnet-mask, broadcast-address, time-offset, routers, domain-name, domain-name-servers, domain-search, host-name, netbios-name-servers, netbios-scope, interface-mtu, rfc3442-classless-static-routes, ntp-servers; prepend domain-name-servers zz.zz.zz.zz, yy.yy.yy.yy, xx.xx.xx.xx; ` Describe("ubuntuNetManager", func() { var ( fs *fakesys.FakeFileSystem cmdRunner *fakesys.FakeCmdRunner defaultNetworkResolver *fakenet.FakeDefaultNetworkResolver netManager NetManager ) BeforeEach(func() { fs = fakesys.NewFakeFileSystem() cmdRunner = fakesys.NewFakeCmdRunner() defaultNetworkResolver = &fakenet.FakeDefaultNetworkResolver{} logger := boshlog.NewLogger(boshlog.LevelNone) netManager = NewUbuntuNetManager(fs, cmdRunner, defaultNetworkResolver, 1*time.Millisecond, logger) }) Describe("SetupDhcp", func() { networks := boshsettings.Networks{ "bosh": boshsettings.Network{ Default: []string{"dns"}, DNS: []string{"xx.xx.xx.xx", "yy.yy.yy.yy", "zz.zz.zz.zz"}, }, "vip": boshsettings.Network{ Default: []string{}, DNS: []string{"aa.aa.aa.aa"}, }, } ItRestartsDhcp := func() { Context("when ifconfig version is 0.7", func() { BeforeEach(func() { cmdRunner.AddCmdResult("ifup --version", fakesys.FakeCmdResult{ Stdout: "ifup version 0.7.47", }) }) It("restarts dhclient", func() { err := netManager.SetupDhcp(networks) Expect(err).ToNot(HaveOccurred()) Expect(len(cmdRunner.RunCommands)).To(Equal(3)) Expect(cmdRunner.RunCommands[1]).To(Equal([]string{"ifdown", "-a", "--no-loopback"})) Expect(cmdRunner.RunCommands[2]).To(Equal([]string{"ifup", "-a", "--no-loopback"})) }) }) Context("when ifconfig version is 0.6", func() { BeforeEach(func() { cmdRunner.AddCmdResult("ifup --version", fakesys.FakeCmdResult{ Stdout: "ifup version 0.6.0", }) }) It("restarts dhclient", func() { err := netManager.SetupDhcp(networks) Expect(err).ToNot(HaveOccurred()) Expect(len(cmdRunner.RunCommands)).To(Equal(3)) Expect(cmdRunner.RunCommands[1]).To(Equal([]string{"ifdown", "-a", "--exclude=lo"})) Expect(cmdRunner.RunCommands[2]).To(Equal([]string{"ifup", "-a", "--exclude=lo"})) }) }) } ItUpdatesDhcp3Config := func() { It("updates /etc/dhcp3/dhclient.conf", func() { err := netManager.SetupDhcp(networks) Expect(err).ToNot(HaveOccurred()) dhcpConfig := fs.GetFileTestStat("/etc/dhcp3/dhclient.conf") Expect(dhcpConfig).ToNot(BeNil()) Expect(dhcpConfig.StringContents()).To(Equal(expectedUbuntuDHCPConfig)) }) } ItUpdatesDhcpConfig := func() { It("updates /etc/dhcp/dhclient.conf", func() { err := netManager.SetupDhcp(networks) Expect(err).ToNot(HaveOccurred()) dhcpConfig := fs.GetFileTestStat("/etc/dhcp/dhclient.conf") Expect(dhcpConfig).ToNot(BeNil()) Expect(dhcpConfig.StringContents()).To(Equal(expectedUbuntuDHCPConfig)) }) } ItDoesNotRestartDhcp := func() { It("does not restart dhclient", func() { err := netManager.SetupDhcp(networks) Expect(err).ToNot(HaveOccurred()) Expect(len(cmdRunner.RunCommands)).To(Equal(0)) }) } Context("when dhclient3 is installed on the system", func() { BeforeEach(func() { cmdRunner.CommandExistsValue = true }) Context("when dhcp was not previously configured", func() { ItUpdatesDhcp3Config() ItRestartsDhcp() }) Context("when dhcp was previously configured with different configuration", func() { BeforeEach(func() { fs.WriteFileString("/etc/dhcp3/dhclient.conf", "fake-other-configuration") }) ItUpdatesDhcp3Config() ItRestartsDhcp() }) Context("when dhcp was previously configured with the same configuration", func() { BeforeEach(func() { fs.WriteFileString("/etc/dhcp3/dhclient.conf", expectedUbuntuDHCPConfig) }) ItUpdatesDhcp3Config() ItDoesNotRestartDhcp() }) }) Context("when dhclient3 is not installed on the system", func() { BeforeEach(func() { cmdRunner.CommandExistsValue = false }) Context("when dhcp was not previously configured", func() { ItUpdatesDhcpConfig() ItRestartsDhcp() }) Context("when dhcp was previously configured with different configuration", func() { BeforeEach(func() { fs.WriteFileString("/etc/dhcp/dhclient.conf", "fake-other-configuration") }) ItUpdatesDhcpConfig() ItRestartsDhcp() }) Context("when dhcp was previously configured with the same configuration", func() { BeforeEach(func() { fs.WriteFileString("/etc/dhcp/dhclient.conf", expectedUbuntuDHCPConfig) }) ItUpdatesDhcpConfig() ItDoesNotRestartDhcp() }) }) }) Describe("SetupManualNetworking", func() { var errCh chan error BeforeEach(func() { errCh = make(chan error) }) BeforeEach(func() { // For mac addr to interface resolution fs.WriteFile("/sys/class/net/eth0", []byte{}) fs.WriteFileString("/sys/class/net/eth0/address", "22:00:0a:1f:ac:2a\n") fs.SetGlob("/sys/class/net/*", []string{"/sys/class/net/eth0"}) }) networks := boshsettings.Networks{ "bosh": boshsettings.Network{ Default: []string{"dns", "gateway"}, IP: "192.168.195.6", Netmask: "255.255.255.0", Gateway: "192.168.195.1", Mac: "22:00:0a:1f:ac:2a", DNS: []string{"10.80.130.2", "10.80.130.1"}, }, } Context("when manual networking was not previously configured", func() { It("writes /etc/network/interfaces", func() { err := netManager.SetupManualNetworking(networks, nil) Expect(err).ToNot(HaveOccurred()) networkConfig := fs.GetFileTestStat("/etc/network/interfaces") Expect(networkConfig).ToNot(BeNil()) Expect(networkConfig.StringContents()).To(Equal(expectedUbuntuNetworkInterfaces)) }) It("restarts networking", func() { err := netManager.SetupManualNetworking(networks, errCh) Expect(err).ToNot(HaveOccurred()) <-errCh // wait for all arpings Expect(len(cmdRunner.RunCommands) >= 2).To(BeTrue()) Expect(cmdRunner.RunCommands[0]).To(Equal([]string{"service", "network-interface", "stop", "INTERFACE=eth0"})) Expect(cmdRunner.RunCommands[1]).To(Equal([]string{"service", "network-interface", "start", "INTERFACE=eth0"})) }) It("updates dns", func() { err := netManager.SetupManualNetworking(networks, nil) Expect(err).ToNot(HaveOccurred()) resolvConf := fs.GetFileTestStat("/etc/resolv.conf") Expect(resolvConf).ToNot(BeNil()) Expect(resolvConf.StringContents()).To(Equal(expectedUbuntuResolvConf)) }) It("starts sending arping", func() { err := netManager.SetupManualNetworking(networks, errCh) Expect(err).ToNot(HaveOccurred()) <-errCh // wait for all arpings Expect(cmdRunner.RunCommands[2]).To(Equal([]string{"arping", "-c", "1", "-U", "-I", "eth0", "192.168.195.6"})) Expect(cmdRunner.RunCommands[7]).To(Equal([]string{"arping", "-c", "1", "-U", "-I", "eth0", "192.168.195.6"})) }) }) Context("when manual networking was previously configured with different configuration", func() { BeforeEach(func() { fs.WriteFileString("/etc/network/interfaces", "fake-manual-config") }) It("updates /etc/network/interfaces", func() { err := netManager.SetupManualNetworking(networks, nil) Expect(err).ToNot(HaveOccurred()) networkConfig := fs.GetFileTestStat("/etc/network/interfaces") Expect(networkConfig).ToNot(BeNil()) Expect(networkConfig.StringContents()).To(Equal(expectedUbuntuNetworkInterfaces)) }) It("restarts networking", func() { err := netManager.SetupManualNetworking(networks, errCh) Expect(err).ToNot(HaveOccurred()) <-errCh // wait for all arpings Expect(len(cmdRunner.RunCommands) >= 2).To(BeTrue()) Expect(cmdRunner.RunCommands[0]).To(Equal([]string{"service", "network-interface", "stop", "INTERFACE=eth0"})) Expect(cmdRunner.RunCommands[1]).To(Equal([]string{"service", "network-interface", "start", "INTERFACE=eth0"})) }) It("updates dns", func() { err := netManager.SetupManualNetworking(networks, nil) Expect(err).ToNot(HaveOccurred()) resolvConf := fs.GetFileTestStat("/etc/resolv.conf") Expect(resolvConf).ToNot(BeNil()) Expect(resolvConf.StringContents()).To(Equal(expectedUbuntuResolvConf)) }) It("starts sending 6 arp pings", func() { err := netManager.SetupManualNetworking(networks, errCh) Expect(err).ToNot(HaveOccurred()) <-errCh // wait for all arpings Expect(cmdRunner.RunCommands[2]).To(Equal([]string{"arping", "-c", "1", "-U", "-I", "eth0", "192.168.195.6"})) Expect(cmdRunner.RunCommands[7]).To(Equal([]string{"arping", "-c", "1", "-U", "-I", "eth0", "192.168.195.6"})) }) }) Context("when manual networking was previously configured with same configuration", func() { BeforeEach(func() { fs.WriteFileString("/etc/network/interfaces", expectedUbuntuNetworkInterfaces) }) It("keeps same /etc/network/interfaces", func() { err := netManager.SetupManualNetworking(networks, nil) Expect(err).ToNot(HaveOccurred()) networkConfig := fs.GetFileTestStat("/etc/network/interfaces") Expect(networkConfig).ToNot(BeNil()) Expect(networkConfig.StringContents()).To(Equal(expectedUbuntuNetworkInterfaces)) }) It("does not restart networking because configuration did not change", func() { err := netManager.SetupManualNetworking(networks, errCh) Expect(err).ToNot(HaveOccurred()) <-errCh // wait for all arpings for _, cmd := range cmdRunner.RunCommands { Expect(cmd[0]).ToNot(Equal("service")) } }) It("updates /etc/resolv.conf for DNS", func() { err := netManager.SetupManualNetworking(networks, nil) Expect(err).ToNot(HaveOccurred()) resolvConf := fs.GetFileTestStat("/etc/resolv.conf") Expect(resolvConf).ToNot(BeNil()) Expect(resolvConf.StringContents()).To(Equal(expectedUbuntuResolvConf)) }) It("starts sending 6 arp ping", func() { err := netManager.SetupManualNetworking(networks, errCh) Expect(err).ToNot(HaveOccurred()) <-errCh // wait for all arpings Expect(len(cmdRunner.RunCommands)).To(Equal(6)) Expect(cmdRunner.RunCommands[0]).To(Equal([]string{"arping", "-c", "1", "-U", "-I", "eth0", "192.168.195.6"})) Expect(cmdRunner.RunCommands[5]).To(Equal([]string{"arping", "-c", "1", "-U", "-I", "eth0", "192.168.195.6"})) }) }) }) }) }
var ( fs *fakesys.FakeFileSystem cmdRunner *fakesys.FakeCmdRunner arping AddressBroadcaster ) BeforeEach(func() { fs = fakesys.NewFakeFileSystem() cmdRunner = fakesys.NewFakeCmdRunner() logger := boshlog.NewLogger(boshlog.LevelNone) arping = NewArping(cmdRunner, fs, logger, arpingIterations, 0, 0) }) Describe("BroadcastMACAddresses", func() { BeforeEach(func() { fs.WriteFile("/sys/class/net/eth0", []byte{}) fs.WriteFile("/sys/class/net/eth1", []byte{}) }) It("runs arping commands for each interface", func() { addresses := []boship.InterfaceAddress{ boship.NewSimpleInterfaceAddress("eth0", "192.168.195.6"), boship.NewSimpleInterfaceAddress("eth1", "127.0.0.1"), } arping.BroadcastMACAddresses(addresses) countA := 0 countB := 0 a := []string{"arping", "-c", "1", "-U", "-I", "eth0", "192.168.195.6"}
func init() { const expectedCentosDHCPConfig = `# Generated by bosh-agent option rfc3442-classless-static-routes code 121 = array of unsigned integer 8; send host-name "<hostname>"; request subnet-mask, broadcast-address, time-offset, routers, domain-name, domain-name-servers, domain-search, host-name, netbios-name-servers, netbios-scope, interface-mtu, rfc3442-classless-static-routes, ntp-servers; prepend domain-name-servers zz.zz.zz.zz; prepend domain-name-servers yy.yy.yy.yy; prepend domain-name-servers xx.xx.xx.xx; ` const expectedCentosIfcfg = `DEVICE=eth0 BOOTPROTO=static IPADDR=192.168.195.6 NETMASK=255.255.255.0 BROADCAST=192.168.195.255 GATEWAY=192.168.195.1 ONBOOT=yes` Describe("centos", func() { var ( collector *fakestats.FakeStatsCollector fs *fakesys.FakeFileSystem cmdRunner *fakesys.FakeCmdRunner diskManager *fakedisk.FakeDiskManager dirProvider boshdirs.DirectoriesProvider platform Platform cdutil *fakecd.FakeCdUtil compressor boshcmd.Compressor copier boshcmd.Copier vitalsService boshvitals.Service logger boshlog.Logger ) BeforeEach(func() { collector = &fakestats.FakeStatsCollector{} fs = fakesys.NewFakeFileSystem() cmdRunner = fakesys.NewFakeCmdRunner() diskManager = fakedisk.NewFakeDiskManager() dirProvider = boshdirs.NewDirectoriesProvider("/fake-dir") cdutil = fakecd.NewFakeCdUtil() compressor = boshcmd.NewTarballCompressor(cmdRunner, fs) copier = boshcmd.NewCpCopier(cmdRunner, fs) vitalsService = boshvitals.NewService(collector, dirProvider) logger = boshlog.NewLogger(boshlog.LevelNone) }) JustBeforeEach(func() { netManager := boshnet.NewCentosNetManager(fs, cmdRunner, 1*time.Millisecond) platform = NewLinuxPlatform( fs, cmdRunner, collector, compressor, copier, dirProvider, vitalsService, cdutil, diskManager, netManager, 1*time.Millisecond, logger, ) }) Describe("SetupDhcp", func() { networks := boshsettings.Networks{ "bosh": boshsettings.Network{ Default: []string{"dns"}, DNS: []string{"xx.xx.xx.xx", "yy.yy.yy.yy", "zz.zz.zz.zz"}, }, "vip": boshsettings.Network{ Default: []string{}, DNS: []string{"aa.aa.aa.aa"}, }, } Context("when dhcp was not previously configured", func() { It("writes dhcp configuration", func() { err := platform.SetupDhcp(networks) Expect(err).ToNot(HaveOccurred()) dhcpConfig := fs.GetFileTestStat("/etc/dhcp/dhclient.conf") Expect(dhcpConfig).ToNot(BeNil()) Expect(dhcpConfig.StringContents()).To(Equal(expectedCentosDHCPConfig)) }) It("restarts network", func() { err := platform.SetupDhcp(networks) Expect(err).ToNot(HaveOccurred()) Expect(len(cmdRunner.RunCommands)).To(Equal(1)) Expect(cmdRunner.RunCommands[0]).To(Equal([]string{"service", "network", "restart"})) }) }) Context("when dhcp was previously configured with different configuration", func() { BeforeEach(func() { fs.WriteFileString("/etc/dhcp/dhclient.conf", "fake-other-configuration") }) It("updates dhcp configuration", func() { err := platform.SetupDhcp(networks) Expect(err).ToNot(HaveOccurred()) dhcpConfig := fs.GetFileTestStat("/etc/dhcp/dhclient.conf") Expect(dhcpConfig).ToNot(BeNil()) Expect(dhcpConfig.StringContents()).To(Equal(expectedCentosDHCPConfig)) }) It("restarts network", func() { err := platform.SetupDhcp(networks) Expect(err).ToNot(HaveOccurred()) Expect(len(cmdRunner.RunCommands)).To(Equal(1)) Expect(cmdRunner.RunCommands[0]).To(Equal([]string{"service", "network", "restart"})) }) }) Context("when dhcp was previously configured with same configuration", func() { BeforeEach(func() { fs.WriteFileString("/etc/dhcp/dhclient.conf", expectedCentosDHCPConfig) }) It("keeps dhcp configuration", func() { err := platform.SetupDhcp(networks) Expect(err).ToNot(HaveOccurred()) dhcpConfig := fs.GetFileTestStat("/etc/dhcp/dhclient.conf") Expect(dhcpConfig).ToNot(BeNil()) Expect(dhcpConfig.StringContents()).To(Equal(expectedCentosDHCPConfig)) }) It("does not restart network", func() { err := platform.SetupDhcp(networks) Expect(err).ToNot(HaveOccurred()) Expect(len(cmdRunner.RunCommands)).To(Equal(0)) }) }) }) Describe("SetupManualNetworking", func() { networks := boshsettings.Networks{ "bosh": boshsettings.Network{ Default: []string{"dns", "gateway"}, IP: "192.168.195.6", Netmask: "255.255.255.0", Gateway: "192.168.195.1", Mac: "22:00:0a:1f:ac:2a", DNS: []string{"10.80.130.2", "10.80.130.1"}, }, } BeforeEach(func() { fs.WriteFile("/sys/class/net/eth0", []byte{}) fs.WriteFileString("/sys/class/net/eth0/address", "22:00:0a:1f:ac:2a\n") fs.SetGlob("/sys/class/net/*", []string{"/sys/class/net/eth0"}) }) It("sets up centos expected ifconfig", func() { err := platform.SetupManualNetworking(networks) Expect(err).ToNot(HaveOccurred()) networkConfig := fs.GetFileTestStat("/etc/sysconfig/network-scripts/ifcfg-eth0") Expect(networkConfig).ToNot(BeNil()) Expect(networkConfig.StringContents()).To(Equal(expectedCentosIfcfg)) }) It("sets up centos /etc/resolv.conf", func() { err := platform.SetupManualNetworking(networks) Expect(err).ToNot(HaveOccurred()) resolvConf := fs.GetFileTestStat("/etc/resolv.conf") Expect(resolvConf).ToNot(BeNil()) Expect(resolvConf.StringContents()).To(Equal(expectedCentosResolvConf)) }) It("restarts networking", func() { err := platform.SetupManualNetworking(networks) Expect(err).ToNot(HaveOccurred()) fs.GetFileTestStat("/etc/sysconfig/network-scripts/ifcfg-eth0") fs.GetFileTestStat("/etc/resolv.conf") time.Sleep(100 * time.Millisecond) Expect(len(cmdRunner.RunCommands)).To(Equal(7)) Expect(cmdRunner.RunCommands[0]).To(Equal([]string{"service", "network", "restart"})) }) It("runs arping commands", func() { err := platform.SetupManualNetworking(networks) Expect(err).ToNot(HaveOccurred()) fs.GetFileTestStat("/etc/sysconfig/network-scripts/ifcfg-eth0") fs.GetFileTestStat("/etc/resolv.conf") time.Sleep(100 * time.Millisecond) Expect(cmdRunner.RunCommands[1]).To(Equal([]string{"arping", "-c", "1", "-U", "-I", "eth0", "192.168.195.6"})) Expect(cmdRunner.RunCommands[6]).To(Equal([]string{"arping", "-c", "1", "-U", "-I", "eth0", "192.168.195.6"})) }) }) }) }
func init() { Describe("prepareNetworkChange", func() { var ( action PrepareNetworkChangeAction fs *fakesys.FakeFileSystem settingsService *fakesettings.FakeSettingsService ) BeforeEach(func() { fs = fakesys.NewFakeFileSystem() settingsService = &fakesettings.FakeSettingsService{} action = NewPrepareNetworkChange(fs, settingsService) }) It("is synchronous", func() { Expect(action.IsAsynchronous()).To(BeFalse()) }) It("is not persistent", func() { Expect(action.IsPersistent()).To(BeFalse()) }) It("invalidates settings so that load settings cannot fall back on old settings", func() { resp, err := action.Run() Expect(err).NotTo(HaveOccurred()) Expect(resp).To(Equal("ok")) Expect(settingsService.SettingsWereInvalidated).To(BeTrue()) }) Context("when settings invalidation succeeds", func() { Context("when the network rules file can be removed", func() { It("removes the network rules file", func() { fs.WriteFile("/etc/udev/rules.d/70-persistent-net.rules", []byte{}) resp, err := action.Run() Expect(err).NotTo(HaveOccurred()) Expect(resp).To(Equal("ok")) Expect(fs.FileExists("/etc/udev/rules.d/70-persistent-net.rules")).To(BeFalse()) }) }) Context("when the network rules file cannot be removed", func() { BeforeEach(func() { fs.RemoveAllError = errors.New("fake-remove-all-error") }) It("returns error from removing the network rules file", func() { resp, err := action.Run() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-remove-all-error")) Expect(resp).To(BeNil()) }) }) }) Context("when settings invalidation fails", func() { BeforeEach(func() { settingsService.InvalidateSettingsError = errors.New("fake-invalidate-error") }) It("returns error early if settings err invalidating", func() { resp, err := action.Run() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-invalidate-error")) Expect(resp).To(BeNil()) }) It("does not remove the network rules file", func() { fs.WriteFile("/etc/udev/rules.d/70-persistent-net.rules", []byte{}) action.Run() Expect(fs.FileExists("/etc/udev/rules.d/70-persistent-net.rules")).To(BeTrue()) }) }) }) }
}) 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")) }) })
Expect(len(cmdRunner.RunCommands)).To(Equal(0)) ntpConfig := fs.GetFileTestStat("/fake-dir/bosh/etc/ntpserver") Expect(ntpConfig).To(BeNil()) }) }) Describe("SetupEphemeralDiskWithPath", func() { It("sets up ephemeral disk with path", func() { fakeFormatter := diskManager.FakeFormatter fakePartitioner := diskManager.FakePartitioner fakeMounter := diskManager.FakeMounter fakePartitioner.GetDeviceSizeInMbSizes = map[string]uint64{"/dev/xvda": uint64(1024 * 1024 * 1024)} fs.WriteFile("/dev/xvda", []byte{}) err := platform.SetupEphemeralDiskWithPath("/dev/xvda") 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))) Expect(fakePartitioner.PartitionDevicePath).To(Equal("/dev/xvda")) Expect(len(fakePartitioner.PartitionPartitions)).To(Equal(2)) swapPartition := fakePartitioner.PartitionPartitions[0] ext4Partition := fakePartitioner.PartitionPartitions[1] Expect(swapPartition.Type).To(Equal(boshdisk.PartitionTypeSwap))
runner = NewFileLoggingCmdRunner(fs, cmdRunner, "/fake-base-dir", 15) cmd = boshsys.Command{ Name: "fake-cmd", Args: []string{"fake-args"}, Env: map[string]string{"fake-env-key": "fake-env-var"}, WorkingDir: "/fake-working-dir", } }) Describe("RunCommand", func() { It("cleans logs directory", func() { err := fs.MkdirAll("/fake-base-dir/fake-log-dir-name/", os.FileMode(0750)) Expect(err).ToNot(HaveOccurred()) err = fs.WriteFile("/fake-base-dir/fake-log-dir-name/old-file", []byte("test-data")) Expect(err).ToNot(HaveOccurred()) _, err = runner.RunCommand("fake-log-dir-name", "fake-log-file-name", cmd) Expect(err).ToNot(HaveOccurred()) Expect(fs.FileExists("/fake-base-dir/fake-log-dir-name/old-file")).To(BeFalse()) }) It("returns an error if it fails to remove previous logs directory", func() { fs.RemoveAllError = errors.New("fake-remove-all-error") _, err := runner.RunCommand("fake-log-dir-name", "fake-log-file-name", cmd) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-remove-all-error")) })
func init() { Describe("concreteServiceProvider", func() { var ( platform *fakeplatform.FakePlatform ) Describe("NewService", func() { It("returns service with settings.json as its settings path", func() { // Cannot compare fetcher functions since function comparison is problematic fs := fakesys.NewFakeFileSystem() logger := boshlog.NewLogger(boshlog.LevelNone) service := NewServiceProvider().NewService(fs, "/setting/path", nil, platform, logger) Expect(service).To(Equal(NewService(fs, "/setting/path/settings.json", nil, platform, logger))) }) }) }) Describe("concreteService", func() { var ( fs *fakesys.FakeFileSystem platform *fakeplatform.FakePlatform ) BeforeEach(func() { fs = fakesys.NewFakeFileSystem() platform = fakeplatform.NewFakePlatform() }) buildService := func(fetcher SettingsFetcher) (Service, *fakesys.FakeFileSystem) { logger := boshlog.NewLogger(boshlog.LevelNone) service := NewService(fs, "/setting/path", fetcher, platform, logger) return service, fs } Describe("LoadSettings", func() { var ( fetchedSettings Settings fetcherFuncErr error service Service ) BeforeEach(func() { fetchedSettings = Settings{} fetcherFuncErr = nil }) JustBeforeEach(func() { fetcherFunc := func() (Settings, error) { return fetchedSettings, fetcherFuncErr } service, fs = buildService(fetcherFunc) }) Context("when settings fetcher succeeds fetching settings", func() { BeforeEach(func() { fetchedSettings = Settings{AgentID: "some-new-agent-id"} }) Context("when settings contain at most one dynamic network", func() { BeforeEach(func() { fetchedSettings.Networks = Networks{ "fake-net-1": Network{Type: NetworkTypeDynamic}, } }) It("updates the service with settings from the fetcher", func() { err := service.LoadSettings() Expect(err).NotTo(HaveOccurred()) Expect(service.GetSettings().AgentID).To(Equal("some-new-agent-id")) }) It("persists settings to the settings file", func() { err := service.LoadSettings() Expect(err).NotTo(HaveOccurred()) json, err := json.Marshal(fetchedSettings) Expect(err).NotTo(HaveOccurred()) fileContent, err := fs.ReadFile("/setting/path") Expect(err).NotTo(HaveOccurred()) Expect(fileContent).To(Equal(json)) }) It("returns any error from writing to the setting file", func() { fs.WriteToFileError = errors.New("fs-write-file-error") err := service.LoadSettings() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fs-write-file-error")) }) }) Context("when settings contain multiple dynamic networks", func() { BeforeEach(func() { fetchedSettings.Networks = Networks{ "fake-net-1": Network{Type: NetworkTypeDynamic}, "fake-net-2": Network{Type: NetworkTypeDynamic}, } }) It("returns error because multiple dynamic networks are not supported", func() { err := service.LoadSettings() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Multiple dynamic networks are not supported")) }) }) }) Context("when settings fetcher fails fetching settings", func() { BeforeEach(func() { fetcherFuncErr = errors.New("fake-fetch-error") }) Context("when a settings file exists", func() { Context("when settings contain at most one dynamic network", func() { BeforeEach(func() { fs.WriteFile("/setting/path", []byte(`{ "agent_id":"some-agent-id", "networks": {"fake-net-1": {"type": "dynamic"}} }`)) }) It("returns settings from the settings file", func() { err := service.LoadSettings() Expect(err).ToNot(HaveOccurred()) Expect(service.GetSettings()).To(Equal(Settings{ AgentID: "some-agent-id", Networks: Networks{ "fake-net-1": Network{Type: NetworkTypeDynamic}, }, })) }) }) Context("when settings contain multiple dynamic networks", func() { BeforeEach(func() { fs.WriteFile("/setting/path", []byte(`{ "agent_id":"some-agent-id", "networks": { "fake-net-1": {"type": "dynamic"}, "fake-net-2": {"type": "dynamic"} } }`)) }) It("returns error because multiple dynamic networks are not supported", func() { err := service.LoadSettings() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Multiple dynamic networks are not supported")) }) }) }) Context("when non-unmarshallable settings file exists", func() { It("returns any error from the fetcher", func() { fs.WriteFile("/setting/path", []byte(`$%^&*(`)) err := service.LoadSettings() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-fetch-error")) Expect(service.GetSettings()).To(Equal(Settings{})) }) }) Context("when no settings file exists", func() { It("returns any error from the fetcher", func() { err := service.LoadSettings() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-fetch-error")) Expect(service.GetSettings()).To(Equal(Settings{})) }) }) }) }) Describe("InvalidateSettings", func() { It("removes the settings file", func() { service, fs := buildService(nil) fs.WriteFile("/setting/path", []byte(`{}`)) err := service.InvalidateSettings() Expect(err).ToNot(HaveOccurred()) Expect(fs.FileExists("/setting/path")).To(BeFalse()) }) It("returns err if removing settings file errored", func() { service, fs := buildService(nil) fs.RemoveAllError = errors.New("fs-remove-all-error") err := service.InvalidateSettings() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fs-remove-all-error")) }) }) Describe("GetSettings", func() { var ( loadedSettings Settings service Service ) BeforeEach(func() { loadedSettings = Settings{AgentID: "some-agent-id"} }) JustBeforeEach(func() { service, _ = buildService(func() (Settings, error) { return loadedSettings, nil }) err := service.LoadSettings() Expect(err).NotTo(HaveOccurred()) }) Context("when there is are no dynamic networks", func() { It("returns settings without modifying any networks", func() { Expect(service.GetSettings()).To(Equal(loadedSettings)) }) It("does not try to determine default network", func() { _ = service.GetSettings() Expect(platform.GetDefaultNetworkCalled).To(BeFalse()) }) }) Context("when there is one dynamic network", func() { BeforeEach(func() { loadedSettings = Settings{ Networks: map[string]Network{ "fake-net1": Network{ IP: "fake-net1-ip", Netmask: "fake-net1-netmask", Gateway: "fake-net1-gateway", }, "fake-net2": Network{ Type: "dynamic", IP: "fake-net2-ip", Netmask: "fake-net2-netmask", Gateway: "fake-net2-gateway", DNS: []string{"fake-net2-dns"}, }, }, } }) Context("when default network can be retrieved", func() { BeforeEach(func() { platform.GetDefaultNetworkNetwork = Network{ IP: "fake-resolved-ip", Netmask: "fake-resolved-netmask", Gateway: "fake-resolved-gateway", } }) It("returns settings with resolved dynamic network ip, netmask, gateway and keeping everything else the same", func() { settings := service.GetSettings() Expect(settings).To(Equal(Settings{ Networks: map[string]Network{ "fake-net1": Network{ IP: "fake-net1-ip", Netmask: "fake-net1-netmask", Gateway: "fake-net1-gateway", }, "fake-net2": Network{ Type: "dynamic", IP: "fake-resolved-ip", Netmask: "fake-resolved-netmask", Gateway: "fake-resolved-gateway", DNS: []string{"fake-net2-dns"}, }, }, })) }) }) Context("when default network fails to be retrieved", func() { BeforeEach(func() { platform.GetDefaultNetworkErr = errors.New("fake-get-default-network-err") }) It("returns error", func() { settings := service.GetSettings() Expect(settings).To(Equal(loadedSettings)) }) }) }) }) }) }
Context("when infrastructure settings file is found", func() { BeforeEach(func() { settingsPath := filepath.Join(dirProvider.BoshDir(), "dummy-cpi-agent-env.json") expectedSettings := boshsettings.Settings{ AgentID: "123-456-789", Blobstore: boshsettings.Blobstore{ Type: boshsettings.BlobstoreTypeDummy, }, Mbus: "nats://127.0.0.1:4222", } existingSettingsBytes, err := json.Marshal(expectedSettings) Expect(err).ToNot(HaveOccurred()) fs.WriteFile(settingsPath, existingSettingsBytes) }) It("returns settings", func() { settings, err := inf.GetSettings() Expect(err).ToNot(HaveOccurred()) assert.Equal(GinkgoT(), settings, boshsettings.Settings{ AgentID: "123-456-789", Blobstore: boshsettings.Blobstore{Type: boshsettings.BlobstoreTypeDummy}, Mbus: "nats://127.0.0.1:4222", }) }) }) Context("when infrastructure settings file is not found", func() { It("returns error", func() {
expectedNetwork := boshsettings.Network{ Default: []string{"fake-default"}, DNS: []string{"fake-dns-name"}, IP: "fake-ip-address", Netmask: "fake-netmask", Gateway: "fake-gateway", Mac: "fake-mac-address", } BeforeEach(func() { settingsPath := filepath.Join(dirProvider.BoshDir(), "dummy-default-network-settings.json") expectedNetworkBytes, err := json.Marshal(expectedNetwork) Expect(err).ToNot(HaveOccurred()) fs.WriteFile(settingsPath, expectedNetworkBytes) }) It("returns network", func() { network, err := platform.GetDefaultNetwork() Expect(err).ToNot(HaveOccurred()) Expect(network).To(Equal(expectedNetwork)) }) }) Context("when default networks settings file is not found", func() { It("does not return error because dummy configuration allows no dynamic IP", func() { _, err := platform.GetDefaultNetwork() Expect(err).ToNot(HaveOccurred()) }) })
Expect(err).To(HaveOccurred()) Expect(len(runner.RunComplexCommands)).To(Equal(1)) Expect(runner.RunComplexCommands[0].Env).ToNot(HaveKey("BOSH_JOB_NEXT_STATE")) }) It("returns error when cannot get the job next state and does not run drain script", func() { params.jobNextStateErr = errors.New("fake-job-next-state-err") _, err := drainScript.Run(params) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-job-next-state-err")) Expect(len(runner.RunComplexCommands)).To(Equal(0)) }) }) }) Describe("Exists", func() { It("returns bool", func() { commandResult := fakesys.FakeCmdResult{Stdout: "1"} runner.AddCmdResult("/fake/script job_shutdown hash_unchanged foo bar", commandResult) Expect(drainScript.Exists()).To(BeFalse()) fs.WriteFile("/fake/script", []byte{}) Expect(drainScript.Exists()).To(BeTrue()) }) }) })