Beispiel #1
0
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"}
Beispiel #5
0
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"))
		})
	})
Beispiel #8
0
			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())
		})
	})
})