func init() { Describe("compiledPackageApplier", func() { var ( packagesBc *fakebc.FakeBundleCollection blobstore *fakeblob.FakeBlobstore compressor *fakecmd.FakeCompressor fs *fakesys.FakeFileSystem logger boshlog.Logger applier Applier ) BeforeEach(func() { packagesBc = fakebc.NewFakeBundleCollection() blobstore = fakeblob.NewFakeBlobstore() compressor = fakecmd.NewFakeCompressor() fs = fakesys.NewFakeFileSystem() logger = boshlog.NewLogger(boshlog.LevelNone) applier = NewCompiledPackageApplier(packagesBc, true, blobstore, compressor, fs, logger) }) Describe("Prepare & Apply", func() { var ( pkg models.Package bundle *fakebc.FakeBundle ) BeforeEach(func() { pkg, bundle = buildPkg(packagesBc) }) ItInstallsPkg := func(act func() error) { It("returns error when installing package 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 package 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 package 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 package 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 package blob fails", func() { compressor.DecompressFileToDirErr = errors.New("fake-decompress-error") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-decompress-error")) }) It("installs bundle from decompressed tmp path of a package blob", 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")) }) } Describe("Prepare", func() { act := func() error { return applier.Prepare(pkg) } It("return an error if getting file bundle fails", func() { packagesBc.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 package installation 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 package 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 package", func() { err := act() Expect(err).ToNot(HaveOccurred()) Expect(blobstore.GetBlobIDs).To(BeNil()) }) }) Context("when package is not installed", func() { BeforeEach(func() { bundle.Installed = false }) It("installs package (but does not enable it)", func() { err := act() Expect(err).ToNot(HaveOccurred()) Expect(bundle.ActionsCalled).To(Equal([]string{"Install"})) }) ItInstallsPkg(act) }) }) Describe("Apply", func() { act := func() error { return applier.Apply(pkg) } It("return an error if getting file bundle fails", func() { packagesBc.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 package installation 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 package is already installed", func() { BeforeEach(func() { bundle.Installed = true }) It("does not install but only enables package", func() { err := act() Expect(err).ToNot(HaveOccurred()) Expect(bundle.ActionsCalled).To(Equal([]string{"Enable"})) // no Install }) It("returns error when package 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 package", func() { err := act() Expect(err).ToNot(HaveOccurred()) Expect(blobstore.GetBlobIDs).To(BeNil()) }) }) Context("when package is not installed", func() { BeforeEach(func() { bundle.Installed = false }) It("installs and enables package", func() { err := act() Expect(err).ToNot(HaveOccurred()) Expect(bundle.ActionsCalled).To(Equal([]string{"Install", "Enable"})) }) It("returns error when package enable fails", func() { bundle.EnableError = errors.New("fake-enable-error") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-enable-error")) }) ItInstallsPkg(act) }) }) }) Describe("KeepOnly", func() { ItReturnsErrors := func() { It("returns error when bundle collection fails to return list of installed bundles", func() { packagesBc.ListErr = errors.New("fake-bc-list-error") err := applier.KeepOnly([]models.Package{}) 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 package", func() { pkg1, bundle1 := buildPkg(packagesBc) packagesBc.ListBundles = []boshbc.Bundle{bundle1} packagesBc.GetErr = errors.New("fake-bc-get-error") err := applier.KeepOnly([]models.Package{pkg1}) 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 := buildPkg(packagesBc) packagesBc.ListBundles = []boshbc.Bundle{bundle1} bundle1.DisableErr = errors.New("fake-bc-disable-error") err := applier.KeepOnly([]models.Package{}) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-bc-disable-error")) }) } Context("when operating on packages as a package owner", func() { BeforeEach(func() { applier = NewCompiledPackageApplier(packagesBc, true, blobstore, compressor, fs, logger) }) It("first disables and then uninstalls packages that are not in keeponly list", func() { _, bundle1 := buildPkg(packagesBc) pkg2, bundle2 := buildPkg(packagesBc) _, bundle3 := buildPkg(packagesBc) pkg4, bundle4 := buildPkg(packagesBc) packagesBc.ListBundles = []boshbc.Bundle{bundle1, bundle2, bundle3, bundle4} err := applier.KeepOnly([]models.Package{pkg4, pkg2}) 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{})) }) ItReturnsErrors() It("returns error when at least one bundle cannot be uninstalled", func() { _, bundle1 := buildPkg(packagesBc) packagesBc.ListBundles = []boshbc.Bundle{bundle1} bundle1.UninstallErr = errors.New("fake-bc-uninstall-error") err := applier.KeepOnly([]models.Package{}) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-bc-uninstall-error")) }) }) Context("when operating on packages not as a package owner", func() { BeforeEach(func() { applier = NewCompiledPackageApplier(packagesBc, false, blobstore, compressor, fs, logger) }) It("disables and but does not uninstall packages that are not in keeponly list", func() { _, bundle1 := buildPkg(packagesBc) pkg2, bundle2 := buildPkg(packagesBc) _, bundle3 := buildPkg(packagesBc) pkg4, bundle4 := buildPkg(packagesBc) packagesBc.ListBundles = []boshbc.Bundle{bundle1, bundle2, bundle3, bundle4} err := applier.KeepOnly([]models.Package{pkg4, pkg2}) Expect(err).ToNot(HaveOccurred()) Expect(bundle1.ActionsCalled).To(Equal([]string{"Disable"})) // no Uninstall Expect(bundle2.ActionsCalled).To(Equal([]string{})) Expect(bundle3.ActionsCalled).To(Equal([]string{"Disable"})) // no Uninstall Expect(bundle4.ActionsCalled).To(Equal([]string{})) }) ItReturnsErrors() }) }) }) }
import ( "encoding/json" . "github.com/cloudfoundry/bosh-agent/internal/github.com/onsi/ginkgo" . "github.com/cloudfoundry/bosh-agent/internal/github.com/onsi/gomega" fakesys "github.com/cloudfoundry/bosh-agent/internal/github.com/cloudfoundry/bosh-utils/system/fakes" boshsettings "github.com/cloudfoundry/bosh-agent/settings" . "github.com/cloudfoundry/bosh-agent/infrastructure" ) var _ = Describe("FileRegistry", func() { var ( fs *fakesys.FakeFileSystem fileRegistry Registry ) BeforeEach(func() { fs = fakesys.NewFakeFileSystem() fileRegistry = NewFileRegistry("/fake-registry-file-path", fs) }) Describe("GetSettings", func() { Context("when the registry file exists", func() { var ( expectedSettings boshsettings.Settings ) BeforeEach(func() { expectedSettings = boshsettings.Settings{
jobNextState string jobNextStateErr error } func (p fakeParams) JobChange() (change string) { return p.jobChange } func (p fakeParams) HashChange() (change string) { return p.hashChange } func (p fakeParams) UpdatedPackages() (pkgs []string) { return p.updatedPackages } func (p fakeParams) JobState() (string, error) { return p.jobState, p.jobStateErr } func (p fakeParams) JobNextState() (string, error) { return p.jobNextState, p.jobNextStateErr } var _ = Describe("ConcreteScript", func() { var ( runner *fakesys.FakeCmdRunner fs *fakesys.FakeFileSystem script ConcreteScript ) BeforeEach(func() { fs = fakesys.NewFakeFileSystem() runner = fakesys.NewFakeCmdRunner() script = NewConcreteScript(fs, runner, "/fake/script") }) Describe("Run", func() { var ( params fakeParams ) BeforeEach(func() {
package infrastructure_test import ( . "github.com/cloudfoundry/bosh-agent/internal/github.com/onsi/ginkgo" . "github.com/cloudfoundry/bosh-agent/internal/github.com/onsi/gomega" . "github.com/cloudfoundry/bosh-agent/infrastructure" boshlog "github.com/cloudfoundry/bosh-agent/internal/github.com/cloudfoundry/bosh-utils/logger" fakesys "github.com/cloudfoundry/bosh-agent/internal/github.com/cloudfoundry/bosh-utils/system/fakes" boshsettings "github.com/cloudfoundry/bosh-agent/settings" ) var _ = Describe("FileMetadataService", func() { var ( fs *fakesys.FakeFileSystem metadataService MetadataService ) BeforeEach(func() { fs = fakesys.NewFakeFileSystem() logger := boshlog.NewLogger(boshlog.LevelNone) metadataService = NewFileMetadataService( "fake-metadata-file-path", "fake-userdata-file-path", "fake-settings-file-path", fs, logger, ) }) Describe("GetInstanceID", func() {
func describeLinuxPlatform() { var ( collector *fakestats.FakeCollector fs *fakesys.FakeFileSystem cmdRunner *fakesys.FakeCmdRunner diskManager *fakedisk.FakeDiskManager dirProvider boshdirs.Provider devicePathResolver *fakedpresolv.FakeDevicePathResolver platform Platform cdutil *fakedevutil.FakeDeviceUtil compressor boshcmd.Compressor copier boshcmd.Copier vitalsService boshvitals.Service netManager *fakenet.FakeManager certManager *fakecert.FakeManager monitRetryStrategy *fakeretry.FakeRetryStrategy fakeDefaultNetworkResolver *fakenet.FakeDefaultNetworkResolver options LinuxOptions logger boshlog.Logger ) BeforeEach(func() { logger = boshlog.NewLogger(boshlog.LevelNone) collector = &fakestats.FakeCollector{} fs = fakesys.NewFakeFileSystem() cmdRunner = fakesys.NewFakeCmdRunner() diskManager = fakedisk.NewFakeDiskManager() dirProvider = boshdirs.NewProvider("/fake-dir") cdutil = fakedevutil.NewFakeDeviceUtil() compressor = boshcmd.NewTarballCompressor(cmdRunner, fs) copier = boshcmd.NewCpCopier(cmdRunner, fs, logger) vitalsService = boshvitals.NewService(collector, dirProvider) netManager = &fakenet.FakeManager{} certManager = new(fakecert.FakeManager) monitRetryStrategy = fakeretry.NewFakeRetryStrategy() devicePathResolver = fakedpresolv.NewFakeDevicePathResolver() fakeDefaultNetworkResolver = &fakenet.FakeDefaultNetworkResolver{} options = LinuxOptions{} fs.SetGlob("/sys/bus/scsi/devices/*:0:0:0/block/*", []string{ "/sys/bus/scsi/devices/0:0:0:0/block/sr0", "/sys/bus/scsi/devices/6:0:0:0/block/sdd", "/sys/bus/scsi/devices/fake-host-id:0:0:0/block/sda", }) fs.SetGlob("/sys/bus/scsi/devices/fake-host-id:0:fake-disk-id:0/block/*", []string{ "/sys/bus/scsi/devices/fake-host-id:0:fake-disk-id:0/block/sdf", }) }) JustBeforeEach(func() { platform = NewLinuxPlatform( fs, cmdRunner, collector, compressor, copier, dirProvider, vitalsService, cdutil, diskManager, netManager, certManager, monitRetryStrategy, devicePathResolver, 5*time.Millisecond, options, logger, fakeDefaultNetworkResolver, ) }) Describe("SetupRuntimeConfiguration", func() { It("setups runtime configuration", func() { err := platform.SetupRuntimeConfiguration() Expect(err).NotTo(HaveOccurred()) Expect(len(cmdRunner.RunCommands)).To(Equal(1)) Expect(cmdRunner.RunCommands[0]).To(Equal([]string{"bosh-agent-rc"})) }) }) Describe("CreateUser", func() { It("creates user", func() { expectedUseradd := []string{ "useradd", "-m", "-b", "/some/path/to/home", "-s", "/bin/bash", "-p", "bar-pwd", "foo-user", } err := platform.CreateUser("foo-user", "bar-pwd", "/some/path/to/home") Expect(err).NotTo(HaveOccurred()) basePathStat := fs.GetFileTestStat("/some/path/to/home") Expect(basePathStat.FileType).To(Equal(fakesys.FakeFileTypeDir)) Expect(basePathStat.FileMode).To(Equal(os.FileMode(0755))) Expect(cmdRunner.RunCommands).To(Equal([][]string{expectedUseradd})) }) It("creates user with an empty password", func() { expectedUseradd := []string{ "useradd", "-m", "-b", "/some/path/to/home", "-s", "/bin/bash", "foo-user", } err := platform.CreateUser("foo-user", "", "/some/path/to/home") Expect(err).NotTo(HaveOccurred()) basePathStat := fs.GetFileTestStat("/some/path/to/home") Expect(basePathStat.FileType).To(Equal(fakesys.FakeFileTypeDir)) Expect(basePathStat.FileMode).To(Equal(os.FileMode(0755))) Expect(cmdRunner.RunCommands).To(Equal([][]string{expectedUseradd})) }) }) Describe("AddUserToGroups", func() { It("adds user to groups", func() { err := platform.AddUserToGroups("foo-user", []string{"group1", "group2", "group3"}) Expect(err).NotTo(HaveOccurred()) Expect(len(cmdRunner.RunCommands)).To(Equal(1)) usermod := []string{"usermod", "-G", "group1,group2,group3", "foo-user"} Expect(cmdRunner.RunCommands[0]).To(Equal(usermod)) }) }) Describe("DeleteEphemeralUsersMatching", func() { It("deletes users with prefix and regex", func() { passwdFile := `bosh_foo:... bosh_bar:... foo:... bar:... foobar:... bosh_foobar:...` fs.WriteFileString("/etc/passwd", passwdFile) err := platform.DeleteEphemeralUsersMatching("bar$") Expect(err).NotTo(HaveOccurred()) Expect(len(cmdRunner.RunCommands)).To(Equal(2)) Expect(cmdRunner.RunCommands[0]).To(Equal([]string{"userdel", "-r", "bosh_bar"})) Expect(cmdRunner.RunCommands[1]).To(Equal([]string{"userdel", "-r", "bosh_foobar"})) }) }) Describe("SetupSSH", func() { It("setup ssh", func() { fs.HomeDirHomePath = "/some/home/dir" platform.SetupSSH("some public key", "vcap") sshDirPath := "/some/home/dir/.ssh" sshDirStat := fs.GetFileTestStat(sshDirPath) Expect("vcap").To(Equal(fs.HomeDirUsername)) Expect(sshDirStat).NotTo(BeNil()) Expect(sshDirStat.FileType).To(Equal(fakesys.FakeFileTypeDir)) Expect(os.FileMode(0700)).To(Equal(sshDirStat.FileMode)) Expect("vcap").To(Equal(sshDirStat.Username)) authKeysStat := fs.GetFileTestStat(filepath.Join(sshDirPath, "authorized_keys")) Expect(authKeysStat).NotTo(BeNil()) Expect(fakesys.FakeFileTypeFile).To(Equal(authKeysStat.FileType)) Expect(os.FileMode(0600)).To(Equal(authKeysStat.FileMode)) Expect("vcap").To(Equal(authKeysStat.Username)) Expect("some public key").To(Equal(authKeysStat.StringContents())) }) }) Describe("SetUserPassword", func() { It("set user password", func() { platform.SetUserPassword("my-user", "my-encrypted-password") Expect(len(cmdRunner.RunCommands)).To(Equal(1)) Expect(cmdRunner.RunCommands[0]).To(Equal([]string{"usermod", "-p", "my-encrypted-password", "my-user"})) }) }) Describe("SetupHostname", func() { const expectedEtcHosts = `127.0.0.1 localhost foobar.local # The following lines are desirable for IPv6 capable hosts ::1 localhost ip6-localhost ip6-loopback foobar.local fe00::0 ip6-localnet ff00::0 ip6-mcastprefix ff02::1 ip6-allnodes ff02::2 ip6-allrouters ff02::3 ip6-allhosts ` It("sets up hostname", func() { platform.SetupHostname("foobar.local") Expect(len(cmdRunner.RunCommands)).To(Equal(1)) Expect(cmdRunner.RunCommands[0]).To(Equal([]string{"hostname", "foobar.local"})) hostnameFileContent, err := fs.ReadFileString("/etc/hostname") Expect(err).NotTo(HaveOccurred()) Expect(hostnameFileContent).To(Equal("foobar.local")) hostsFileContent, err := fs.ReadFileString("/etc/hosts") Expect(err).NotTo(HaveOccurred()) Expect(hostsFileContent).To(Equal(expectedEtcHosts)) }) }) Describe("SetupLogrotate", func() { const expectedEtcLogrotate = `# Generated by bosh-agent fake-base-path/data/sys/log/*.log fake-base-path/data/sys/log/*/*.log fake-base-path/data/sys/log/*/*/*.log { missingok rotate 7 compress delaycompress copytruncate size=fake-size } ` It("sets up logrotate", func() { platform.SetupLogrotate("fake-group-name", "fake-base-path", "fake-size") logrotateFileContent, err := fs.ReadFileString("/etc/logrotate.d/fake-group-name") Expect(err).NotTo(HaveOccurred()) Expect(logrotateFileContent).To(Equal(expectedEtcLogrotate)) }) }) Describe("SetTimeWithNtpServers", func() { It("sets time with ntp servers", func() { platform.SetTimeWithNtpServers([]string{"0.north-america.pool.ntp.org", "1.north-america.pool.ntp.org"}) ntpConfig := fs.GetFileTestStat("/fake-dir/bosh/etc/ntpserver") Expect(ntpConfig.StringContents()).To(Equal("0.north-america.pool.ntp.org 1.north-america.pool.ntp.org")) Expect(ntpConfig.FileType).To(Equal(fakesys.FakeFileTypeFile)) Expect(len(cmdRunner.RunCommands)).To(Equal(1)) Expect(cmdRunner.RunCommands[0]).To(Equal([]string{"ntpdate"})) }) It("sets time with ntp servers is noop when no ntp server provided", func() { platform.SetTimeWithNtpServers([]string{}) Expect(len(cmdRunner.RunCommands)).To(Equal(0)) ntpConfig := fs.GetFileTestStat("/fake-dir/bosh/etc/ntpserver") Expect(ntpConfig).To(BeNil()) }) }) Describe("SetupEphemeralDiskWithPath", func() { var ( partitioner *fakedisk.FakePartitioner formatter *fakedisk.FakeFormatter mounter *fakedisk.FakeMounter ) BeforeEach(func() { partitioner = diskManager.FakePartitioner formatter = diskManager.FakeFormatter mounter = diskManager.FakeMounter }) itSetsUpEphemeralDisk := func(act func() error) { It("sets up ephemeral disk with path", func() { err := act() Expect(err).NotTo(HaveOccurred()) dataDir := fs.GetFileTestStat("/fake-dir/data") Expect(dataDir.FileType).To(Equal(fakesys.FakeFileTypeDir)) Expect(dataDir.FileMode).To(Equal(os.FileMode(0750))) }) It("creates new partition even if the data directory is not empty", func() { fs.SetGlob(path.Join("/fake-dir", "data", "*"), []string{"something"}) err := act() Expect(err).ToNot(HaveOccurred()) Expect(partitioner.PartitionCalled).To(BeTrue()) Expect(formatter.FormatCalled).To(BeTrue()) Expect(mounter.MountCalled).To(BeTrue()) }) } Context("when ephemeral disk path is provided", func() { act := func() error { return platform.SetupEphemeralDiskWithPath("/dev/xvda") } itSetsUpEphemeralDisk(act) It("returns error if creating data dir fails", func() { fs.MkdirAllError = errors.New("fake-mkdir-all-err") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-mkdir-all-err")) Expect(partitioner.PartitionCalled).To(BeFalse()) Expect(formatter.FormatCalled).To(BeFalse()) Expect(mounter.MountCalled).To(BeFalse()) }) It("returns err when the data directory cannot be globbed", func() { fs.GlobErr = errors.New("fake-glob-err") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Globbing ephemeral disk mount point `/fake-dir/data/*'")) Expect(err.Error()).To(ContainSubstring("fake-glob-err")) Expect(partitioner.PartitionCalled).To(BeFalse()) Expect(formatter.FormatCalled).To(BeFalse()) Expect(mounter.MountCalled).To(BeFalse()) }) It("returns err when mem stats are unavailable", func() { collector.MemStatsErr = errors.New("fake-memstats-error") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Calculating partition sizes")) Expect(err.Error()).To(ContainSubstring("fake-memstats-error")) Expect(partitioner.PartitionCalled).To(BeFalse()) Expect(formatter.FormatCalled).To(BeFalse()) Expect(mounter.MountCalled).To(BeFalse()) }) It("returns an error when partitioning fails", func() { partitioner.PartitionErr = errors.New("fake-partition-error") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Partitioning ephemeral disk `/dev/xvda'")) Expect(err.Error()).To(ContainSubstring("fake-partition-error")) Expect(formatter.FormatCalled).To(BeFalse()) Expect(mounter.MountCalled).To(BeFalse()) }) It("formats swap and data partitions", func() { err := act() Expect(err).NotTo(HaveOccurred()) Expect(len(formatter.FormatPartitionPaths)).To(Equal(2)) Expect(formatter.FormatPartitionPaths[0]).To(Equal("/dev/xvda1")) Expect(formatter.FormatPartitionPaths[1]).To(Equal("/dev/xvda2")) Expect(len(formatter.FormatFsTypes)).To(Equal(2)) Expect(formatter.FormatFsTypes[0]).To(Equal(boshdisk.FileSystemSwap)) Expect(formatter.FormatFsTypes[1]).To(Equal(boshdisk.FileSystemExt4)) }) It("mounts swap and data partitions", func() { err := act() Expect(err).NotTo(HaveOccurred()) Expect(len(mounter.MountMountPoints)).To(Equal(1)) Expect(mounter.MountMountPoints[0]).To(Equal("/fake-dir/data")) Expect(len(mounter.MountPartitionPaths)).To(Equal(1)) Expect(mounter.MountPartitionPaths[0]).To(Equal("/dev/xvda2")) Expect(len(mounter.SwapOnPartitionPaths)).To(Equal(1)) Expect(mounter.SwapOnPartitionPaths[0]).To(Equal("/dev/xvda1")) }) It("creates swap the size of the memory and the rest for data when disk is bigger than twice the memory", func() { memSizeInBytes := uint64(1024 * 1024 * 1024) diskSizeInBytes := 2*memSizeInBytes + 64 fakePartitioner := partitioner fakePartitioner.GetDeviceSizeInBytesSizes["/dev/xvda"] = diskSizeInBytes collector.MemStats.Total = memSizeInBytes err := act() Expect(err).NotTo(HaveOccurred()) Expect(fakePartitioner.PartitionPartitions).To(Equal([]boshdisk.Partition{ {SizeInBytes: memSizeInBytes, Type: boshdisk.PartitionTypeSwap}, {SizeInBytes: diskSizeInBytes - memSizeInBytes, Type: boshdisk.PartitionTypeLinux}, })) }) It("creates equal swap and data partitions when disk is twice the memory or smaller", func() { memSizeInBytes := uint64(1024 * 1024 * 1024) diskSizeInBytes := 2*memSizeInBytes - 64 fakePartitioner := partitioner fakePartitioner.GetDeviceSizeInBytesSizes["/dev/xvda"] = diskSizeInBytes collector.MemStats.Total = memSizeInBytes err := act() Expect(err).NotTo(HaveOccurred()) Expect(fakePartitioner.PartitionPartitions).To(Equal([]boshdisk.Partition{ {SizeInBytes: diskSizeInBytes / 2, Type: boshdisk.PartitionTypeSwap}, {SizeInBytes: diskSizeInBytes / 2, Type: boshdisk.PartitionTypeLinux}, })) }) }) Context("when ephemeral disk path is not provided", func() { act := func() error { return platform.SetupEphemeralDiskWithPath("") } Context("when agent should partition ephemeral disk on root disk", func() { BeforeEach(func() { partitioner = diskManager.FakeRootDevicePartitioner options.CreatePartitionIfNoEphemeralDisk = true }) Context("when root device fails to be determined", func() { BeforeEach(func() { diskManager.FakeMountsSearcher.SearchMountsErr = errors.New("fake-mounts-searcher-error") }) It("returns an error", func() { err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Finding root partition device")) Expect(partitioner.PartitionCalled).To(BeFalse()) Expect(formatter.FormatCalled).To(BeFalse()) Expect(mounter.MountCalled).To(BeFalse()) }) }) Context("when root partition is not the first partition", func() { BeforeEach(func() { diskManager.FakeMountsSearcher.SearchMountsMounts = []boshdisk.Mount{ {MountPoint: "/", PartitionPath: "/dev/vda2"}, } }) It("returns an error", func() { err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Root partition is not the first partition")) Expect(partitioner.PartitionCalled).To(BeFalse()) Expect(formatter.FormatCalled).To(BeFalse()) Expect(mounter.MountCalled).To(BeFalse()) }) }) Context("when root device is determined", func() { BeforeEach(func() { diskManager.FakeMountsSearcher.SearchMountsMounts = []boshdisk.Mount{ {MountPoint: "/", PartitionPath: "rootfs"}, {MountPoint: "/", PartitionPath: "/dev/vda1"}, } }) Context("when getting absolute path fails", func() { BeforeEach(func() { cmdRunner.AddCmdResult( "readlink -f /dev/vda1", fakesys.FakeCmdResult{Error: errors.New("fake-readlink-error")}, ) }) It("returns an error", func() { err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-readlink-error")) Expect(partitioner.PartitionCalled).To(BeFalse()) Expect(formatter.FormatCalled).To(BeFalse()) Expect(mounter.MountCalled).To(BeFalse()) }) }) Context("when getting absolute path suceeds", func() { BeforeEach(func() { cmdRunner.AddCmdResult( "readlink -f /dev/vda1", fakesys.FakeCmdResult{Stdout: "/dev/vda1"}, ) }) Context("when root device has insufficient space for ephemeral partitions", func() { BeforeEach(func() { partitioner.GetDeviceSizeInBytesSizes["/dev/vda"] = 1024*1024*1024 - 1 collector.MemStats.Total = 8 }) It("returns an error", func() { err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Insufficient remaining disk")) Expect(partitioner.PartitionCalled).To(BeFalse()) Expect(formatter.FormatCalled).To(BeFalse()) Expect(mounter.MountCalled).To(BeFalse()) }) }) Context("when root device has sufficient space for ephemeral partitions", func() { BeforeEach(func() { partitioner.GetDeviceSizeInBytesSizes["/dev/vda"] = 1024 * 1024 * 1024 collector.MemStats.Total = 256 * 1024 * 1024 }) itSetsUpEphemeralDisk(act) It("returns err when mem stats are unavailable", func() { collector.MemStatsErr = errors.New("fake-memstats-error") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Calculating partition sizes")) Expect(err.Error()).To(ContainSubstring("fake-memstats-error")) Expect(partitioner.PartitionCalled).To(BeFalse()) Expect(formatter.FormatCalled).To(BeFalse()) Expect(mounter.MountCalled).To(BeFalse()) }) It("returns an error when partitioning fails", func() { partitioner.PartitionErr = errors.New("fake-partition-error") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Partitioning root device `/dev/vda'")) Expect(err.Error()).To(ContainSubstring("fake-partition-error")) Expect(formatter.FormatCalled).To(BeFalse()) Expect(mounter.MountCalled).To(BeFalse()) }) It("formats swap and data partitions", func() { err := act() Expect(err).NotTo(HaveOccurred()) Expect(len(formatter.FormatPartitionPaths)).To(Equal(2)) Expect(formatter.FormatPartitionPaths[0]).To(Equal("/dev/vda2")) Expect(formatter.FormatPartitionPaths[1]).To(Equal("/dev/vda3")) Expect(len(formatter.FormatFsTypes)).To(Equal(2)) Expect(formatter.FormatFsTypes[0]).To(Equal(boshdisk.FileSystemSwap)) Expect(formatter.FormatFsTypes[1]).To(Equal(boshdisk.FileSystemExt4)) }) It("mounts swap and data partitions", func() { err := act() Expect(err).NotTo(HaveOccurred()) Expect(len(mounter.MountMountPoints)).To(Equal(1)) Expect(mounter.MountMountPoints[0]).To(Equal("/fake-dir/data")) Expect(len(mounter.MountPartitionPaths)).To(Equal(1)) Expect(mounter.MountPartitionPaths[0]).To(Equal("/dev/vda3")) Expect(len(mounter.SwapOnPartitionPaths)).To(Equal(1)) Expect(mounter.SwapOnPartitionPaths[0]).To(Equal("/dev/vda2")) }) It("creates swap the size of the memory and the rest for data when disk is bigger than twice the memory", func() { memSizeInBytes := uint64(1024 * 1024 * 1024) diskSizeInBytes := 2*memSizeInBytes + 64 partitioner.GetDeviceSizeInBytesSizes["/dev/vda"] = diskSizeInBytes collector.MemStats.Total = memSizeInBytes err := act() Expect(err).ToNot(HaveOccurred()) Expect(partitioner.PartitionDevicePath).To(Equal("/dev/vda")) Expect(partitioner.PartitionPartitions).To(ContainElement( boshdisk.Partition{ SizeInBytes: memSizeInBytes, Type: boshdisk.PartitionTypeSwap, }), ) Expect(partitioner.PartitionPartitions).To(ContainElement( boshdisk.Partition{ SizeInBytes: diskSizeInBytes - memSizeInBytes, Type: boshdisk.PartitionTypeLinux, }), ) }) It("creates equal swap and data partitions when disk is twice the memory or smaller", func() { memSizeInBytes := uint64(1024 * 1024 * 1024) diskSizeInBytes := 2*memSizeInBytes - 64 partitioner.GetDeviceSizeInBytesSizes["/dev/vda"] = diskSizeInBytes collector.MemStats.Total = memSizeInBytes err := act() Expect(err).ToNot(HaveOccurred()) Expect(partitioner.PartitionDevicePath).To(Equal("/dev/vda")) Expect(partitioner.PartitionPartitions).To(ContainElement( boshdisk.Partition{ SizeInBytes: diskSizeInBytes / 2, Type: boshdisk.PartitionTypeSwap, }), ) Expect(partitioner.PartitionPartitions).To(ContainElement( boshdisk.Partition{ SizeInBytes: diskSizeInBytes / 2, Type: boshdisk.PartitionTypeLinux, }), ) }) }) Context("when getting root device remaining size fails", func() { BeforeEach(func() { partitioner.GetDeviceSizeInBytesErr = errors.New("fake-get-remaining-size-error") }) It("returns an error", func() { err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Getting root device remaining size")) Expect(err.Error()).To(ContainSubstring("fake-get-remaining-size-error")) Expect(partitioner.PartitionCalled).To(BeFalse()) Expect(formatter.FormatCalled).To(BeFalse()) Expect(mounter.MountCalled).To(BeFalse()) }) }) }) }) It("returns error if creating data dir fails", func() { fs.MkdirAllError = errors.New("fake-mkdir-all-err") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-mkdir-all-err")) Expect(partitioner.PartitionCalled).To(BeFalse()) Expect(formatter.FormatCalled).To(BeFalse()) Expect(mounter.MountCalled).To(BeFalse()) }) It("returns err when the data directory cannot be globbed", func() { fs.GlobErr = errors.New("fake-glob-err") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Globbing ephemeral disk mount point `/fake-dir/data/*'")) Expect(err.Error()).To(ContainSubstring("fake-glob-err")) Expect(partitioner.PartitionCalled).To(BeFalse()) Expect(formatter.FormatCalled).To(BeFalse()) Expect(mounter.MountCalled).To(BeFalse()) }) }) Context("when agent should not partition ephemeral disk on root disk", func() { BeforeEach(func() { options.CreatePartitionIfNoEphemeralDisk = false }) It("returns an error", func() { err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("cannot use root partition as ephemeral disk")) }) It("does not try to partition anything", func() { err := act() Expect(err).To(HaveOccurred()) Expect(partitioner.PartitionCalled).To(BeFalse()) }) It("does not try to format anything", func() { err := act() Expect(err).To(HaveOccurred()) Expect(formatter.FormatCalled).To(BeFalse()) }) It("does not try to mount anything", func() { err := act() Expect(err).To(HaveOccurred()) Expect(mounter.MountCalled).To(BeFalse()) }) }) }) }) Describe("SetupDataDir", func() { var mounter *fakedisk.FakeMounter BeforeEach(func() { mounter = diskManager.FakeMounter }) Context("when sys/run is already mounted", func() { BeforeEach(func() { mounter.IsMountPointResult = true }) It("creates sys/log directory in data directory", func() { err := platform.SetupDataDir() Expect(err).NotTo(HaveOccurred()) sysLogStats := fs.GetFileTestStat("/fake-dir/data/sys/log") Expect(sysLogStats).ToNot(BeNil()) Expect(sysLogStats.FileType).To(Equal(fakesys.FakeFileTypeDir)) Expect(sysLogStats.FileMode).To(Equal(os.FileMode(0750))) Expect(cmdRunner.RunCommands[0]).To(Equal([]string{"chown", "root:vcap", "/fake-dir/data/sys"})) Expect(cmdRunner.RunCommands[1]).To(Equal([]string{"chown", "root:vcap", "/fake-dir/data/sys/log"})) }) It("creates symlink from sys to data/sys", func() { err := platform.SetupDataDir() Expect(err).NotTo(HaveOccurred()) sysStats := fs.GetFileTestStat("/fake-dir/sys") Expect(sysStats).ToNot(BeNil()) Expect(sysStats.FileType).To(Equal(fakesys.FakeFileTypeSymlink)) Expect(sysStats.SymlinkTarget).To(Equal("/fake-dir/data/sys")) }) It("does not create new sys/run dir", func() { err := platform.SetupDataDir() Expect(err).NotTo(HaveOccurred()) sysRunStats := fs.GetFileTestStat("/fake-dir/data/sys/run") Expect(sysRunStats).To(BeNil()) }) It("does not mount tmpfs again", func() { err := platform.SetupDataDir() Expect(err).NotTo(HaveOccurred()) Expect(len(mounter.MountPartitionPaths)).To(Equal(0)) }) }) Context("when sys/run is not yet mounted", func() { BeforeEach(func() { mounter.IsMountPointResult = false }) It("creates sys/log directory in data directory", func() { err := platform.SetupDataDir() Expect(err).NotTo(HaveOccurred()) sysLogStats := fs.GetFileTestStat("/fake-dir/data/sys/log") Expect(sysLogStats).ToNot(BeNil()) Expect(sysLogStats.FileType).To(Equal(fakesys.FakeFileTypeDir)) Expect(sysLogStats.FileMode).To(Equal(os.FileMode(0750))) Expect(cmdRunner.RunCommands[0]).To(Equal([]string{"chown", "root:vcap", "/fake-dir/data/sys"})) Expect(cmdRunner.RunCommands[1]).To(Equal([]string{"chown", "root:vcap", "/fake-dir/data/sys/log"})) }) It("creates symlink from sys to data/sys", func() { err := platform.SetupDataDir() Expect(err).NotTo(HaveOccurred()) sysStats := fs.GetFileTestStat("/fake-dir/sys") Expect(sysStats).ToNot(BeNil()) Expect(sysStats.FileType).To(Equal(fakesys.FakeFileTypeSymlink)) Expect(sysStats.SymlinkTarget).To(Equal("/fake-dir/data/sys")) }) It("creates new sys/run dir", func() { err := platform.SetupDataDir() Expect(err).NotTo(HaveOccurred()) sysRunStats := fs.GetFileTestStat("/fake-dir/data/sys/run") Expect(sysRunStats).ToNot(BeNil()) Expect(sysRunStats.FileType).To(Equal(fakesys.FakeFileTypeDir)) Expect(sysRunStats.FileMode).To(Equal(os.FileMode(0750))) Expect(cmdRunner.RunCommands[2]).To(Equal([]string{"chown", "root:vcap", "/fake-dir/data/sys/run"})) }) It("mounts tmpfs to sys/run", func() { err := platform.SetupDataDir() Expect(err).NotTo(HaveOccurred()) Expect(len(mounter.MountPartitionPaths)).To(Equal(1)) Expect(mounter.MountPartitionPaths[0]).To(Equal("tmpfs")) Expect(mounter.MountMountPoints[0]).To(Equal("/fake-dir/data/sys/run")) Expect(mounter.MountMountOptions[0]).To(Equal([]string{"-t", "tmpfs", "-o", "size=1m"})) }) It("returns an error if creation of mount point fails", func() { fs.MkdirAllError = errors.New("fake-mkdir-error") err := platform.SetupDataDir() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-mkdir-error")) }) It("returns an error if mounting tmpfs fails", func() { mounter.MountErr = errors.New("fake-mount-error") err := platform.SetupDataDir() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-mount-error")) }) }) }) Describe("SetupTmpDir", func() { act := func() error { return platform.SetupTmpDir() } var mounter *fakedisk.FakeMounter BeforeEach(func() { mounter = diskManager.FakeMounter }) It("changes permissions on /tmp", func() { err := act() Expect(err).NotTo(HaveOccurred()) Expect(cmdRunner.RunCommands[0]).To(Equal([]string{"chown", "root:vcap", "/tmp"})) Expect(cmdRunner.RunCommands[1]).To(Equal([]string{"chmod", "0770", "/tmp"})) Expect(cmdRunner.RunCommands[2]).To(Equal([]string{"chmod", "0700", "/var/tmp"})) }) It("creates new temp dir", func() { err := act() Expect(err).NotTo(HaveOccurred()) fileStats := fs.GetFileTestStat("/fake-dir/data/tmp") Expect(fileStats).NotTo(BeNil()) Expect(fileStats.FileType).To(Equal(fakesys.FakeFileType(fakesys.FakeFileTypeDir))) Expect(fileStats.FileMode).To(Equal(os.FileMode(0755))) }) It("returns error if creating new temp dir errs", func() { fs.MkdirAllError = errors.New("fake-mkdir-error") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-mkdir-error")) }) It("sets TMPDIR environment variable so that children of this process will use new temp dir", func() { err := act() Expect(err).NotTo(HaveOccurred()) Expect(os.Getenv("TMPDIR")).To(Equal("/fake-dir/data/tmp")) }) It("returns error if setting TMPDIR errs", func() { // uses os package; no way to trigger err }) ItDoesNotTryToUseLoopDevice := func() { It("does not create new tmp filesystem", func() { act() for _, cmd := range cmdRunner.RunCommands { Expect(cmd[0]).ToNot(Equal("truncate")) Expect(cmd[0]).ToNot(Equal("mke2fs")) } }) It("does not try to mount anything /tmp", func() { act() Expect(len(mounter.MountPartitionPaths)).To(Equal(0)) }) } Context("when UseDefaultTmpDir option is set to false", func() { BeforeEach(func() { options.UseDefaultTmpDir = false }) Context("when /tmp is not a mount point", func() { BeforeEach(func() { mounter.IsMountPointResult = false }) It("creates new tmp filesystem of 128MB placed in data dir", func() { err := act() Expect(err).NotTo(HaveOccurred()) Expect(cmdRunner.RunCommands[3]).To(Equal([]string{"truncate", "-s", "128M", "/fake-dir/data/root_tmp"})) Expect(cmdRunner.RunCommands[4]).To(Equal([]string{"chmod", "0700", "/fake-dir/data/root_tmp"})) Expect(cmdRunner.RunCommands[5]).To(Equal([]string{"mke2fs", "-t", "ext4", "-m", "1", "-F", "/fake-dir/data/root_tmp"})) }) It("mounts the new tmp filesystem over /tmp", func() { err := act() Expect(err).NotTo(HaveOccurred()) Expect(len(mounter.MountPartitionPaths)).To(Equal(1)) Expect(mounter.MountPartitionPaths[0]).To(Equal("/fake-dir/data/root_tmp")) Expect(mounter.MountMountPoints[0]).To(Equal("/tmp")) Expect(mounter.MountMountOptions[0]).To(Equal([]string{"-t", "ext4", "-o", "loop"})) }) It("returns error if mounting the new tmp filesystem fails", func() { mounter.MountErr = errors.New("fake-mount-error") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-mount-error")) }) It("changes permissions on /tmp again because it is a new mount", func() { err := act() Expect(err).NotTo(HaveOccurred()) Expect(cmdRunner.RunCommands[6]).To(Equal([]string{"chown", "root:vcap", "/tmp"})) Expect(cmdRunner.RunCommands[7]).To(Equal([]string{"chmod", "0770", "/tmp"})) }) }) Context("when /tmp is a mount point", func() { BeforeEach(func() { mounter.IsMountPointResult = true }) It("returns without an error", func() { err := act() Expect(err).ToNot(HaveOccurred()) }) ItDoesNotTryToUseLoopDevice() }) Context("when /tmp cannot be determined if it is a mount point", func() { BeforeEach(func() { mounter.IsMountPointErr = errors.New("fake-is-mount-point-error") }) It("returns error", func() { err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-is-mount-point-error")) }) ItDoesNotTryToUseLoopDevice() }) }) Context("when UseDefaultTmpDir option is set to true", func() { BeforeEach(func() { options.UseDefaultTmpDir = true }) It("returns without an error", func() { err := act() Expect(err).ToNot(HaveOccurred()) }) ItDoesNotTryToUseLoopDevice() }) }) Describe("MountPersistentDisk", func() { act := func() error { return platform.MountPersistentDisk( boshsettings.DiskSettings{Path: "fake-volume-id"}, "/mnt/point", ) } var ( partitioner *fakedisk.FakePartitioner formatter *fakedisk.FakeFormatter mounter *fakedisk.FakeMounter ) BeforeEach(func() { partitioner = diskManager.FakePartitioner formatter = diskManager.FakeFormatter mounter = diskManager.FakeMounter }) Context("when device path is successfully resolved", func() { BeforeEach(func() { devicePathResolver.RealDevicePath = "fake-real-device-path" }) Context("when UsePreformattedPersistentDisk set to false", func() { It("creates the mount directory with the correct permissions", func() { err := act() Expect(err).ToNot(HaveOccurred()) mountPoint := fs.GetFileTestStat("/mnt/point") Expect(mountPoint.FileType).To(Equal(fakesys.FakeFileTypeDir)) Expect(mountPoint.FileMode).To(Equal(os.FileMode(0700))) }) It("returns error when creating mount directory fails", func() { fs.MkdirAllError = errors.New("fake-mkdir-all-err") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-mkdir-all-err")) }) It("partitions the disk", func() { err := act() Expect(err).ToNot(HaveOccurred()) partitions := []boshdisk.Partition{{Type: boshdisk.PartitionTypeLinux}} Expect(partitioner.PartitionDevicePath).To(Equal("fake-real-device-path")) Expect(partitioner.PartitionPartitions).To(Equal(partitions)) }) It("formats the disk", func() { err := act() Expect(err).ToNot(HaveOccurred()) Expect(formatter.FormatPartitionPaths).To(Equal([]string{"fake-real-device-path1"})) Expect(formatter.FormatFsTypes).To(Equal([]boshdisk.FileSystemType{boshdisk.FileSystemExt4})) }) It("mounts the disk", func() { err := act() Expect(err).ToNot(HaveOccurred()) Expect(mounter.MountPartitionPaths).To(Equal([]string{"fake-real-device-path1"})) Expect(mounter.MountMountPoints).To(Equal([]string{"/mnt/point"})) Expect(mounter.MountMountOptions).To(Equal([][]string{nil})) }) }) Context("when UsePreformattedPersistentDisk set to true", func() { BeforeEach(func() { options.UsePreformattedPersistentDisk = true }) It("creates the mount directory with the correct permissions", func() { err := act() Expect(err).ToNot(HaveOccurred()) mountPoint := fs.GetFileTestStat("/mnt/point") Expect(mountPoint.FileType).To(Equal(fakesys.FakeFileTypeDir)) Expect(mountPoint.FileMode).To(Equal(os.FileMode(0700))) }) It("returns error when creating mount directory fails", func() { fs.MkdirAllError = errors.New("fake-mkdir-all-err") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-mkdir-all-err")) }) It("mounts volume at mount point", func() { err := act() Expect(err).ToNot(HaveOccurred()) Expect(len(mounter.MountPartitionPaths)).To(Equal(1)) Expect(mounter.MountPartitionPaths).To(Equal([]string{"fake-real-device-path"})) // no '1' because no partition Expect(mounter.MountMountPoints).To(Equal([]string{"/mnt/point"})) Expect(mounter.MountMountOptions).To(Equal([][]string{nil})) }) It("returns error when mounting fails", func() { mounter.MountErr = errors.New("fake-mount-err") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-mount-err")) }) It("does not partition the disk", func() { err := act() Expect(err).ToNot(HaveOccurred()) Expect(partitioner.PartitionCalled).To(BeFalse()) }) It("does not format the disk", func() { err := act() Expect(err).ToNot(HaveOccurred()) Expect(formatter.FormatCalled).To(BeFalse()) }) }) }) Context("when device path is not successfully resolved", func() { It("return an error", func() { devicePathResolver.GetRealDevicePathErr = errors.New("fake-get-real-device-path-err") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-get-real-device-path-err")) }) }) }) Describe("UnmountPersistentDisk", func() { act := func() (bool, error) { return platform.UnmountPersistentDisk(boshsettings.DiskSettings{Path: "fake-device-path"}) } var mounter *fakedisk.FakeMounter BeforeEach(func() { mounter = diskManager.FakeMounter }) Context("when device path can be resolved", func() { BeforeEach(func() { devicePathResolver.RealDevicePath = "fake-real-device-path" }) ItUnmountsPersistentDisk := func(expectedUnmountMountPoint string) { It("returs true without an error if unmounting succeeded", func() { mounter.UnmountDidUnmount = true didUnmount, err := act() Expect(err).NotTo(HaveOccurred()) Expect(didUnmount).To(BeTrue()) Expect(mounter.UnmountPartitionPathOrMountPoint).To(Equal(expectedUnmountMountPoint)) }) It("returs false without an error if was already unmounted", func() { mounter.UnmountDidUnmount = false didUnmount, err := act() Expect(err).NotTo(HaveOccurred()) Expect(didUnmount).To(BeFalse()) Expect(mounter.UnmountPartitionPathOrMountPoint).To(Equal(expectedUnmountMountPoint)) }) It("returns error if unmounting fails", func() { mounter.UnmountDidUnmount = false mounter.UnmountErr = errors.New("fake-unmount-err") didUnmount, err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-unmount-err")) Expect(didUnmount).To(BeFalse()) Expect(mounter.UnmountPartitionPathOrMountPoint).To(Equal(expectedUnmountMountPoint)) }) } Context("UsePreformattedPersistentDisk is set to false", func() { ItUnmountsPersistentDisk("fake-real-device-path1") // note partition '1' }) Context("UsePreformattedPersistentDisk is set to true", func() { BeforeEach(func() { options.UsePreformattedPersistentDisk = true }) ItUnmountsPersistentDisk("fake-real-device-path") // note no '1'; no partitions }) }) Context("when device path cannot be resolved", func() { BeforeEach(func() { devicePathResolver.GetRealDevicePathErr = errors.New("fake-get-real-device-path-err") devicePathResolver.GetRealDevicePathTimedOut = false }) It("returns error", func() { isMounted, err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-get-real-device-path-err")) Expect(isMounted).To(BeFalse()) }) }) Context("when device path cannot be resolved due to timeout", func() { BeforeEach(func() { devicePathResolver.GetRealDevicePathErr = errors.New("fake-get-real-device-path-err") devicePathResolver.GetRealDevicePathTimedOut = true }) It("does not return error", func() { isMounted, err := act() Expect(err).NotTo(HaveOccurred()) Expect(isMounted).To(BeFalse()) }) }) }) Describe("GetFileContentsFromCDROM", func() { It("delegates to cdutil", func() { cdutil.GetFilesContentsContents = [][]byte{[]byte("fake-contents")} filename := "fake-env" contents, err := platform.GetFileContentsFromCDROM(filename) Expect(err).NotTo(HaveOccurred()) Expect(cdutil.GetFilesContentsFileNames[0]).To(Equal(filename)) Expect(contents).To(Equal([]byte("fake-contents"))) }) }) Describe("GetFilesContentsFromDisk", func() { It("delegates to diskutil", func() { diskManager.FakeDiskUtil.GetFilesContentsContents = [][]byte{ []byte("fake-contents-1"), []byte("fake-contents-2"), } contents, err := platform.GetFilesContentsFromDisk( "fake-disk-path", []string{"fake-file-path-1", "fake-file-path-2"}, ) Expect(err).NotTo(HaveOccurred()) Expect(diskManager.DiskUtilDiskPath).To(Equal("fake-disk-path")) Expect(diskManager.FakeDiskUtil.GetFilesContentsFileNames).To(Equal( []string{"fake-file-path-1", "fake-file-path-2"}, )) Expect(contents).To(Equal([][]byte{ []byte("fake-contents-1"), []byte("fake-contents-2"), })) }) }) Describe("GetEphemeralDiskPath", func() { Context("when device path is an empty string", func() { It("returns an empty string", func() { devicePathResolver.RealDevicePath = "non-desired-device-path" diskSettings := boshsettings.DiskSettings{ ID: "fake-id", VolumeID: "fake-volume-id", Path: "", } Expect(platform.GetEphemeralDiskPath(diskSettings)).To(BeEmpty()) }) }) Context("when real device path was resolved without an error", func() { It("returns real device path and true", func() { devicePathResolver.RealDevicePath = "fake-real-device-path" realPath := platform.GetEphemeralDiskPath(boshsettings.DiskSettings{Path: "fake-device-path"}) Expect(realPath).To(Equal("fake-real-device-path")) }) }) Context("when real device path was not resolved without an error", func() { It("returns real device path and true", func() { devicePathResolver.GetRealDevicePathErr = errors.New("fake-get-real-device-path-err") realPath := platform.GetEphemeralDiskPath(boshsettings.DiskSettings{Path: "fake-device-path"}) Expect(realPath).To(Equal("")) }) }) }) Describe("MigratePersistentDisk", func() { var mounter *fakedisk.FakeMounter BeforeEach(func() { mounter = diskManager.FakeMounter }) It("migrate persistent disk", func() { err := platform.MigratePersistentDisk("/from/path", "/to/path") Expect(err).ToNot(HaveOccurred()) Expect(mounter.RemountAsReadonlyPath).To(Equal("/from/path")) Expect(len(cmdRunner.RunCommands)).To(Equal(1)) Expect(cmdRunner.RunCommands[0]).To(Equal([]string{"sh", "-c", "(tar -C /from/path -cf - .) | (tar -C /to/path -xpf -)"})) Expect(mounter.UnmountPartitionPathOrMountPoint).To(Equal("/from/path")) Expect(mounter.RemountFromMountPoint).To(Equal("/to/path")) Expect(mounter.RemountToMountPoint).To(Equal("/from/path")) }) }) Describe("IsPersistentDiskMounted", func() { act := func() (bool, error) { return platform.IsPersistentDiskMounted(boshsettings.DiskSettings{Path: "fake-device-path"}) } var mounter *fakedisk.FakeMounter BeforeEach(func() { mounter = diskManager.FakeMounter }) Context("when device path can be resolved", func() { BeforeEach(func() { devicePathResolver.RealDevicePath = "fake-real-device-path" }) ItChecksPersistentDiskMountPoint := func(expectedCheckedMountPoint string) { Context("when checking persistent disk mount point succeeds", func() { It("returns true if mount point exists", func() { mounter.IsMountedResult = true isMounted, err := act() Expect(err).NotTo(HaveOccurred()) Expect(isMounted).To(BeTrue()) Expect(mounter.IsMountedDevicePathOrMountPoint).To(Equal(expectedCheckedMountPoint)) }) It("returns false if mount point does not exist", func() { mounter.IsMountedResult = false isMounted, err := act() Expect(err).NotTo(HaveOccurred()) Expect(isMounted).To(BeFalse()) Expect(mounter.IsMountedDevicePathOrMountPoint).To(Equal(expectedCheckedMountPoint)) }) }) Context("checking persistent disk mount points fails", func() { It("returns error", func() { mounter.IsMountedResult = false mounter.IsMountedErr = errors.New("fake-is-mounted-err") isMounted, err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-is-mounted-err")) Expect(isMounted).To(BeFalse()) Expect(mounter.IsMountedDevicePathOrMountPoint).To(Equal(expectedCheckedMountPoint)) }) }) } Context("UsePreformattedPersistentDisk is set to false", func() { ItChecksPersistentDiskMountPoint("fake-real-device-path1") // note partition '1' }) Context("UsePreformattedPersistentDisk is set to true", func() { BeforeEach(func() { options.UsePreformattedPersistentDisk = true }) ItChecksPersistentDiskMountPoint("fake-real-device-path") // note no '1'; no partitions }) }) Context("when device path cannot be resolved", func() { BeforeEach(func() { devicePathResolver.GetRealDevicePathErr = errors.New("fake-get-real-device-path-err") devicePathResolver.GetRealDevicePathTimedOut = false }) It("returns error", func() { isMounted, err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-get-real-device-path-err")) Expect(isMounted).To(BeFalse()) }) }) Context("when device path cannot be resolved due to timeout", func() { BeforeEach(func() { devicePathResolver.GetRealDevicePathErr = errors.New("fake-get-real-device-path-err") devicePathResolver.GetRealDevicePathTimedOut = true }) It("does not return error", func() { isMounted, err := act() Expect(err).NotTo(HaveOccurred()) Expect(isMounted).To(BeFalse()) }) }) }) Describe("StartMonit", func() { It("creates a symlink between /etc/service/monit and /etc/sv/monit", func() { err := platform.StartMonit() Expect(err).NotTo(HaveOccurred()) target, _ := fs.ReadLink(filepath.Join("/etc", "service", "monit")) Expect(target).To(Equal(filepath.Join("/etc", "sv", "monit"))) }) It("retries to start monit", func() { err := platform.StartMonit() Expect(err).NotTo(HaveOccurred()) Expect(monitRetryStrategy.TryCalled).To(BeTrue()) }) It("returns error if retrying to start monit fails", func() { monitRetryStrategy.TryErr = errors.New("fake-retry-monit-error") err := platform.StartMonit() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-retry-monit-error")) }) }) Describe("SetupMonitUser", func() { It("setup monit user if file does not exist", func() { err := platform.SetupMonitUser() Expect(err).NotTo(HaveOccurred()) monitUserFileStats := fs.GetFileTestStat("/fake-dir/monit/monit.user") Expect(monitUserFileStats).ToNot(BeNil()) Expect(monitUserFileStats.StringContents()).To(Equal("vcap:random-password")) }) It("setup monit user if file does exist", func() { fs.WriteFileString("/fake-dir/monit/monit.user", "vcap:other-random-password") err := platform.SetupMonitUser() Expect(err).NotTo(HaveOccurred()) monitUserFileStats := fs.GetFileTestStat("/fake-dir/monit/monit.user") Expect(monitUserFileStats).ToNot(BeNil()) Expect(monitUserFileStats.StringContents()).To(Equal("vcap:other-random-password")) }) }) Describe("GetMonitCredentials", func() { It("get monit credentials reads monit file from disk", func() { fs.WriteFileString("/fake-dir/monit/monit.user", "fake-user:fake-random-password") username, password, err := platform.GetMonitCredentials() Expect(err).NotTo(HaveOccurred()) Expect(username).To(Equal("fake-user")) Expect(password).To(Equal("fake-random-password")) }) It("get monit credentials errs when invalid file format", func() { fs.WriteFileString("/fake-dir/monit/monit.user", "fake-user") _, _, err := platform.GetMonitCredentials() Expect(err).To(HaveOccurred()) }) It("get monit credentials leaves colons in password intact", func() { fs.WriteFileString("/fake-dir/monit/monit.user", "fake-user:fake:random:password") username, password, err := platform.GetMonitCredentials() Expect(err).NotTo(HaveOccurred()) Expect(username).To(Equal("fake-user")) Expect(password).To(Equal("fake:random:password")) }) }) Describe("PrepareForNetworkingChange", func() { It("removes the network persistent rules file", func() { fs.WriteFile("/etc/udev/rules.d/70-persistent-net.rules", []byte{}) err := platform.PrepareForNetworkingChange() Expect(err).NotTo(HaveOccurred()) Expect(fs.FileExists("/etc/udev/rules.d/70-persistent-net.rules")).To(BeFalse()) }) It("returns error if removing persistent rules file fails", func() { fs.RemoveAllError = errors.New("fake-remove-all-error") err := platform.PrepareForNetworkingChange() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-remove-all-error")) }) }) Describe("SetupNetworking", func() { It("delegates to the NetManager", func() { networks := boshsettings.Networks{} err := platform.SetupNetworking(networks) Expect(err).ToNot(HaveOccurred()) Expect(netManager.SetupNetworkingNetworks).To(Equal(networks)) }) }) Describe("GetConfiguredNetworkInterfaces", func() { It("delegates to the NetManager", func() { netmanagerInterfaces := []string{"fake-eth0", "fake-eth1"} netManager.GetConfiguredNetworkInterfacesInterfaces = netmanagerInterfaces interfaces, err := platform.GetConfiguredNetworkInterfaces() Expect(err).ToNot(HaveOccurred()) Expect(interfaces).To(Equal(netmanagerInterfaces)) }) }) Describe("GetDefaultNetwork", func() { It("delegates to the defaultNetworkResolver", func() { defaultNetwork := boshsettings.Network{IP: "1.2.3.4"} fakeDefaultNetworkResolver.GetDefaultNetworkNetwork = defaultNetwork network, err := platform.GetDefaultNetwork() Expect(err).ToNot(HaveOccurred()) Expect(network).To(Equal(defaultNetwork)) }) }) }
boshalert "github.com/cloudfoundry/bosh-agent/agent/alert" boshlog "github.com/cloudfoundry/bosh-agent/internal/github.com/cloudfoundry/bosh-utils/logger" fakesys "github.com/cloudfoundry/bosh-agent/internal/github.com/cloudfoundry/bosh-utils/system/fakes" . "github.com/cloudfoundry/bosh-agent/jobsupervisor" boshmonit "github.com/cloudfoundry/bosh-agent/jobsupervisor/monit" fakemonit "github.com/cloudfoundry/bosh-agent/jobsupervisor/monit/fakes" boshdir "github.com/cloudfoundry/bosh-agent/settings/directories" ) var _ = Describe("monitJobSupervisor", func() { var ( fs *fakesys.FakeFileSystem runner *fakesys.FakeCmdRunner client *fakemonit.FakeMonitClient logger boshlog.Logger dirProvider boshdir.Provider jobFailuresServerPort int monit JobSupervisor ) var jobFailureServerPort = 5000 getJobFailureServerPort := func() int { jobFailureServerPort++ return jobFailureServerPort } BeforeEach(func() { fs = fakesys.NewFakeFileSystem() runner = fakesys.NewFakeCmdRunner()
boshlog "github.com/cloudfoundry/bosh-agent/internal/github.com/cloudfoundry/bosh-utils/logger" fakesys "github.com/cloudfoundry/bosh-agent/internal/github.com/cloudfoundry/bosh-utils/system/fakes" ) type testBundle struct { Name string Version string } func (s testBundle) BundleName() string { return s.Name } func (s testBundle) BundleVersion() string { return s.Version } var _ = Describe("FileBundleCollection", func() { var ( fs *fakesys.FakeFileSystem logger boshlog.Logger fileBundleCollection FileBundleCollection ) BeforeEach(func() { fs = fakesys.NewFakeFileSystem() logger = boshlog.NewLogger(boshlog.LevelNone) fileBundleCollection = NewFileBundleCollection( "/fake-collection-path/data", "/fake-collection-path", "fake-collection-name", fs, logger, ) })
import ( "time" . "github.com/cloudfoundry/bosh-agent/internal/github.com/onsi/ginkgo" . "github.com/cloudfoundry/bosh-agent/internal/github.com/onsi/gomega" fakesys "github.com/cloudfoundry/bosh-agent/internal/github.com/cloudfoundry/bosh-utils/system/fakes" boshsettings "github.com/cloudfoundry/bosh-agent/settings" . "github.com/cloudfoundry/bosh-agent/infrastructure/devicepathresolver" ) var _ = Describe("VSphere Path Resolver", func() { var ( fs *fakesys.FakeFileSystem resolver DevicePathResolver diskSettings boshsettings.DiskSettings ) const sleepInterval = time.Millisecond * 1 BeforeEach(func() { fs = fakesys.NewFakeFileSystem() resolver = NewScsiDevicePathResolver(sleepInterval, fs) fs.SetGlob("/sys/bus/scsi/devices/*:0:0:0/block/*", []string{ "/sys/bus/scsi/devices/0:0:0:0/block/sr0", "/sys/bus/scsi/devices/6:0:0:0/block/sdd", "/sys/bus/scsi/devices/fake-host-id:0:0:0/block/sda", })
func init() { Describe("renderedJobApplier", func() { var ( jobsBc *fakebc.FakeBundleCollection jobSupervisor *fakejobsuper.FakeJobSupervisor packageApplierProvider *fakepackages.FakeApplierProvider blobstore *fakeblob.FakeBlobstore compressor *fakecmd.FakeCompressor fs *fakesys.FakeFileSystem applier Applier ) BeforeEach(func() { jobsBc = fakebc.NewFakeBundleCollection() jobSupervisor = fakejobsuper.NewFakeJobSupervisor() packageApplierProvider = fakepackages.NewFakeApplierProvider() 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) { BeforeEach(func() { fs.TempDirDir = "/fake-tmp-dir" }) 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() { 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 walking the tree of files fails", func() { fs.WalkErr = errors.New("fake-walk-error") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-walk-error")) }) It("installs bundle from decompressed tmp path of a job template", func() { 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 the bin and config directories", func() { var binDirStats, configDirStats *fakesys.FakeFileStats compressor.DecompressFileToDirCallBack = func() { fs.WriteFile("/fake-tmp-dir/fake-path-in-archive/bin/blarg", []byte{}) fs.WriteFile("/fake-tmp-dir/fake-path-in-archive/config/blarg.yml", []byte{}) } bundle.InstallCallBack = func() { binDirStats = fs.GetFileTestStat("/fake-tmp-dir/fake-path-in-archive/bin") configDirStats = fs.GetFileTestStat("/fake-tmp-dir/fake-path-in-archive/config") } err := act() Expect(err).ToNot(HaveOccurred()) Expect(int(binDirStats.FileMode)).To(Equal(0755)) Expect(int(configDirStats.FileMode)).To(Equal(0755)) }) It("sets executable bit for files in bin", func() { 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)) }) It("sets 644 permissions for files in config", func() { compressor.DecompressFileToDirCallBack = func() { fs.WriteFile("/fake-tmp-dir/fake-path-in-archive/config/config1", []byte{}) fs.WriteFile("/fake-tmp-dir/fake-path-in-archive/config/config2", []byte{}) } fs.SetGlob("/fake-tmp-dir/fake-path-in-archive/config/*", []string{ "/fake-tmp-dir/fake-path-in-archive/config/config1", "/fake-tmp-dir/fake-path-in-archive/config/config2", }) var config1Stats, config2Stats *fakesys.FakeFileStats bundle.InstallCallBack = func() { config1Stats = fs.GetFileTestStat("/fake-tmp-dir/fake-path-in-archive/config/config1") config2Stats = fs.GetFileTestStat("/fake-tmp-dir/fake-path-in-archive/config/config2") } err := act() Expect(err).ToNot(HaveOccurred()) // permission for config files should be readable by all Expect(int(config1Stats.FileMode)).To(Equal(0644)) Expect(int(config2Stats.FileMode)).To(Equal(0644)) }) } ItUpdatesPackages := func(act func() error) { var packageApplier *fakepackages.FakeApplier BeforeEach(func() { packageApplier = fakepackages.NewFakeApplier() packageApplierProvider.JobSpecificAppliers[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(len(jobSupervisor.AddJobArgs)).To(Equal(2)) Expect(jobSupervisor.AddJobArgs[0]).To(Equal(fakejobsuper.AddJobArgs{ Name: job.Name, Index: 0, ConfigPath: "/path/to/job/monit", })) Expect(jobSupervisor.AddJobArgs[1]).To(Equal(fakejobsuper.AddJobArgs{ Name: job.Name + "_subjob", Index: 0, ConfigPath: "/path/to/job/subjob.monit", })) }) It("does not require monit script", func() { job, bundle := buildJob(jobsBc) fs := fakesys.NewFakeFileSystem() bundle.GetDirFs = fs err := applier.Configure(job, 0) Expect(err).ToNot(HaveOccurred()) Expect(len(jobSupervisor.AddJobArgs)).To(Equal(0)) }) }) 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")) }) }) }) }
) type failingInterfaceAddress struct{} func (ia failingInterfaceAddress) GetInterfaceName() string { return "eth0" } func (ia failingInterfaceAddress) GetIP() (string, error) { return "", errors.New("fake-get-ip-err") } var _ = Describe("arping", func() { const arpingIterations = 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("returns an empty slice for an empty string", func() { result := cert.SplitCerts("") Expect(len(result)).To(Equal(0)) }) It("returns an empty slice for an non-empty string that does not contain any certificates", func() { result := cert.SplitCerts("abcdefghij") Expect(len(result)).To(Equal(0)) }) }) Describe("DeleteFile()", func() { var ( fakeFs *fakesys.FakeFileSystem ) BeforeEach(func() { fakeFs = fakesys.NewFakeFileSystem() }) It("only deletes the files with the given prefix", func() { fakeFs.WriteFileString("/path/to/delete/stuff/in/delete_me_1.foo", "goodbye") fakeFs.WriteFileString("/path/to/delete/stuff/in/delete_me_2.foo", "goodbye") fakeFs.WriteFileString("/path/to/delete/stuff/in/different_file_1.bar", "goodbye") fakeFs.SetGlob("/path/to/delete/stuff/in/delete_me_*", []string{ "/path/to/delete/stuff/in/delete_me_1.foo", "/path/to/delete/stuff/in/delete_me_2.foo", }) count, err := cert.DeleteFiles(fakeFs, "/path/to/delete/stuff/in/", "delete_me_")
import ( "errors" "os" . "github.com/cloudfoundry/bosh-agent/internal/github.com/onsi/ginkgo" . "github.com/cloudfoundry/bosh-agent/internal/github.com/onsi/gomega" . "github.com/cloudfoundry/bosh-agent/agent/cmdrunner" boshsys "github.com/cloudfoundry/bosh-agent/internal/github.com/cloudfoundry/bosh-utils/system" fakesys "github.com/cloudfoundry/bosh-agent/internal/github.com/cloudfoundry/bosh-utils/system/fakes" ) var _ = Describe("FileLoggingCmdRunner", func() { var ( fs *fakesys.FakeFileSystem cmdRunner *fakesys.FakeCmdRunner cmd boshsys.Command runner CmdRunner ) BeforeEach(func() { fs = fakesys.NewFakeFileSystem() cmdRunner = fakesys.NewFakeCmdRunner() 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", } })
package disk_test import ( "errors" . "github.com/cloudfoundry/bosh-agent/internal/github.com/onsi/ginkgo" . "github.com/cloudfoundry/bosh-agent/internal/github.com/onsi/gomega" fakesys "github.com/cloudfoundry/bosh-agent/internal/github.com/cloudfoundry/bosh-utils/system/fakes" . "github.com/cloudfoundry/bosh-agent/platform/disk" ) var _ = Describe("procMountsSearcher", func() { var ( fs *fakesys.FakeFileSystem searcher MountsSearcher ) BeforeEach(func() { fs = fakesys.NewFakeFileSystem() searcher = NewProcMountsSearcher(fs) }) Describe("SearchMounts", func() { Context("when reading /proc/mounts succeeds", func() { It("returns parsed mount information", func() { fs.WriteFileString( "/proc/mounts", `none /run/lock tmpfs rw,nosuid,nodev,noexec,relatime,size=5120k 0 0 none /run/shm tmpfs rw,nosuid,nodev,relatime 0 0 /dev/sda1 /boot ext2 rw,relatime,errors=continue 0 0
package app import ( . "github.com/cloudfoundry/bosh-agent/internal/github.com/onsi/ginkgo" . "github.com/cloudfoundry/bosh-agent/internal/github.com/onsi/gomega" boshinf "github.com/cloudfoundry/bosh-agent/infrastructure" fakesys "github.com/cloudfoundry/bosh-agent/internal/github.com/cloudfoundry/bosh-utils/system/fakes" boshplatform "github.com/cloudfoundry/bosh-agent/platform" ) var _ = Describe("LoadConfigFromPath", func() { var ( fs *fakesys.FakeFileSystem ) BeforeEach(func() { fs = fakesys.NewFakeFileSystem() }) It("returns populates config", func() { fs.WriteFileString("/fake-config.conf", `{ "Platform": { "Linux": { "UseDefaultTmpDir": true, "UsePreformattedPersistentDisk": true, "BindMountPersistentDisk": true, "DevicePathResolutionType": "virtio" } }, "Infrastructure": {
import ( "errors" "os" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" . "github.com/cloudfoundry/bosh-agent/internal/github.com/cloudfoundry/bosh-utils/blobstore" fakesys "github.com/cloudfoundry/bosh-agent/internal/github.com/cloudfoundry/bosh-utils/system/fakes" fakeuuid "github.com/cloudfoundry/bosh-agent/internal/github.com/cloudfoundry/bosh-utils/uuid/fakes" ) var _ = Describe("localBlobstore", func() { var ( fs *fakesys.FakeFileSystem uuidGen *fakeuuid.FakeGenerator fakeBlobstorePath = "/some/local/path" blobstore Blobstore ) BeforeEach(func() { fs = fakesys.NewFakeFileSystem() uuidGen = &fakeuuid.FakeGenerator{} options := map[string]interface{}{"blobstore_path": fakeBlobstorePath} blobstore = NewLocalBlobstore(fs, uuidGen, options) }) Describe("Validate", func() { It("returns no error when blobstore_path is present", func() { err := blobstore.Validate() Expect(err).ToNot(HaveOccurred()) })
func init() { Describe("settingsService", func() { var ( fs *fakesys.FakeFileSystem fakeDefaultNetworkResolver *fakenet.FakeDefaultNetworkResolver fakeSettingsSource *fakes.FakeSettingsSource ) BeforeEach(func() { fs = fakesys.NewFakeFileSystem() fakeDefaultNetworkResolver = &fakenet.FakeDefaultNetworkResolver{} fakeSettingsSource = &fakes.FakeSettingsSource{} }) buildService := func() (Service, *fakesys.FakeFileSystem) { logger := boshlog.NewLogger(boshlog.LevelNone) service := NewService(fs, "/setting/path.json", fakeSettingsSource, fakeDefaultNetworkResolver, logger) return service, fs } Describe("LoadSettings", func() { var ( fetchedSettings Settings fetcherFuncErr error service Service ) BeforeEach(func() { fetchedSettings = Settings{} fetcherFuncErr = nil }) JustBeforeEach(func() { fakeSettingsSource.SettingsValue = fetchedSettings fakeSettingsSource.SettingsErr = fetcherFuncErr service, fs = buildService() }) 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.json") Expect(err).NotTo(HaveOccurred()) Expect(fileContent).To(Equal(json)) }) It("returns any error from writing to the setting file", func() { fs.WriteFileError = 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 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.json", []byte(`{ "agent_id":"some-agent-id", "networks": {"fake-net-1": {"type": "dynamic"}} }`)) fakeDefaultNetworkResolver.GetDefaultNetworkNetwork = Network{ IP: "fake-resolved-ip", Netmask: "fake-resolved-netmask", Gateway: "fake-resolved-gateway", } }) It("returns settings from the settings file with resolved network", 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, IP: "fake-resolved-ip", Netmask: "fake-resolved-netmask", Gateway: "fake-resolved-gateway", Resolved: true, }, }, })) }) }) }) Context("when non-unmarshallable settings file exists", func() { It("returns any error from the fetcher", func() { fs.WriteFile("/setting/path.json", []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() { fakeSettingsSource.SettingsValue = Settings{} fakeSettingsSource.SettingsErr = nil service, fs := buildService() fs.WriteFile("/setting/path.json", []byte(`{}`)) err := service.InvalidateSettings() Expect(err).ToNot(HaveOccurred()) Expect(fs.FileExists("/setting/path.json")).To(BeFalse()) }) It("returns err if removing settings file errored", func() { fakeSettingsSource.SettingsValue = Settings{} fakeSettingsSource.SettingsErr = nil service, fs := buildService() 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() { fakeSettingsSource.SettingsValue = loadedSettings fakeSettingsSource.SettingsErr = nil service, _ = buildService() 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(fakeDefaultNetworkResolver.GetDefaultNetworkCalled).To(BeFalse()) }) }) Context("when there is network that needs to be resolved (ip, netmask, or mac are not set)", func() { BeforeEach(func() { loadedSettings = Settings{ Networks: map[string]Network{ "fake-net1": Network{ IP: "fake-net1-ip", Netmask: "fake-net1-netmask", Mac: "fake-net1-mac", Gateway: "fake-net1-gateway", }, "fake-net2": Network{ Gateway: "fake-net2-gateway", DNS: []string{"fake-net2-dns"}, }, }, } }) Context("when default network can be retrieved", func() { BeforeEach(func() { fakeDefaultNetworkResolver.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", Mac: "fake-net1-mac", Gateway: "fake-net1-gateway", }, "fake-net2": Network{ IP: "fake-resolved-ip", Netmask: "fake-resolved-netmask", Gateway: "fake-resolved-gateway", DNS: []string{"fake-net2-dns"}, Resolved: true, }, }, })) }) }) Context("when default network fails to be retrieved", func() { BeforeEach(func() { fakeDefaultNetworkResolver.GetDefaultNetworkErr = errors.New("fake-get-default-network-err") }) It("returns error", func() { settings := service.GetSettings() Expect(settings).To(Equal(loadedSettings)) }) }) }) }) }) }
func describeUbuntuNetManager() { var ( fs *fakesys.FakeFileSystem cmdRunner *fakesys.FakeCmdRunner ipResolver *fakeip.FakeResolver addressBroadcaster *fakearp.FakeAddressBroadcaster netManager UbuntuNetManager interfaceConfigurationCreator InterfaceConfigurationCreator ) writeNetworkDevice := func(iface string, macAddress string, isPhysical bool) string { interfacePath := fmt.Sprintf("/sys/class/net/%s", iface) fs.WriteFile(interfacePath, []byte{}) if isPhysical { fs.WriteFile(fmt.Sprintf("/sys/class/net/%s/device", iface), []byte{}) } fs.WriteFileString(fmt.Sprintf("/sys/class/net/%s/address", iface), fmt.Sprintf("%s\n", macAddress)) return interfacePath } stubInterfacesWithVirtual := func(physicalInterfaces map[string]boshsettings.Network, virtualInterfaces []string) { interfacePaths := []string{} for iface, networkSettings := range physicalInterfaces { interfacePaths = append(interfacePaths, writeNetworkDevice(iface, networkSettings.Mac, true)) } for _, iface := range virtualInterfaces { interfacePaths = append(interfacePaths, writeNetworkDevice(iface, "virtual", false)) } fs.SetGlob("/sys/class/net/*", interfacePaths) } stubInterfaces := func(physicalInterfaces map[string]boshsettings.Network) { stubInterfacesWithVirtual(physicalInterfaces, nil) } BeforeEach(func() { fs = fakesys.NewFakeFileSystem() cmdRunner = fakesys.NewFakeCmdRunner() ipResolver = &fakeip.FakeResolver{} logger := boshlog.NewLogger(boshlog.LevelNone) interfaceConfigurationCreator = NewInterfaceConfigurationCreator(logger) addressBroadcaster = &fakearp.FakeAddressBroadcaster{} netManager = NewUbuntuNetManager( fs, cmdRunner, ipResolver, interfaceConfigurationCreator, addressBroadcaster, logger, ).(UbuntuNetManager) }) Describe("ComputeNetworkConfig", func() { Context("when there is one manual network and neither is marked as default for DNS", func() { It("should use the manual network for DNS", func() { networks := boshsettings.Networks{ "manual": factory.Network{DNS: &[]string{"8.8.8.8"}}.Build(), } stubInterfaces(networks) _, _, dnsServers, err := netManager.ComputeNetworkConfig(networks) Expect(err).ToNot(HaveOccurred()) Expect(dnsServers).To(Equal([]string{"8.8.8.8"})) }) }) Context("when there is a vip network and a manual network and neither is marked as default for DNS", func() { It("should use the manual network for DNS", func() { networks := boshsettings.Networks{ "vip": boshsettings.Network{Type: "vip"}, "manual": factory.Network{Type: "manual", DNS: &[]string{"8.8.8.8"}}.Build(), } stubInterfaces(networks) _, _, dnsServers, err := netManager.ComputeNetworkConfig(networks) Expect(err).ToNot(HaveOccurred()) Expect(dnsServers).To(Equal([]string{"8.8.8.8"})) }) }) Context("when there is a vip network and a manual network and the manual network is marked as default for DNS", func() { It("should use the manual network for DNS", func() { networks := boshsettings.Networks{ "vip": boshsettings.Network{Type: "vip"}, "manual": factory.Network{Type: "manual", DNS: &[]string{"8.8.8.8"}, Default: []string{"dns"}}.Build(), } stubInterfaces(networks) _, _, dnsServers, err := netManager.ComputeNetworkConfig(networks) Expect(err).ToNot(HaveOccurred()) Expect(dnsServers).To(Equal([]string{"8.8.8.8"})) }) }) Context("when specified more than one DNS", func() { It("extracts all DNS servers from the network configured as default DNS", func() { networks := boshsettings.Networks{ "default": factory.Network{ IP: "10.10.0.32", Netmask: "255.255.255.0", Mac: "aa::bb::cc", Default: []string{"dns", "gateway"}, DNS: &[]string{"54.209.78.6", "127.0.0.5"}, Gateway: "10.10.0.1", }.Build(), } stubInterfaces(networks) staticInterfaceConfigurations, dhcpInterfaceConfigurations, dnsServers, err := netManager.ComputeNetworkConfig(networks) Expect(err).ToNot(HaveOccurred()) Expect(staticInterfaceConfigurations).To(Equal([]StaticInterfaceConfiguration{ { Name: "default", Address: "10.10.0.32", Netmask: "255.255.255.0", Network: "10.10.0.0", Broadcast: "10.10.0.255", Mac: "aa::bb::cc", Gateway: "10.10.0.1", }, })) Expect(dhcpInterfaceConfigurations).To(BeEmpty()) Expect(dnsServers).To(Equal([]string{"54.209.78.6", "127.0.0.5"})) }) }) }) Describe("SetupNetworking", func() { var ( dhcpNetwork boshsettings.Network staticNetwork boshsettings.Network expectedNetworkConfigurationForStaticAndDhcp string ) BeforeEach(func() { dhcpNetwork = boshsettings.Network{ Type: "dynamic", Default: []string{"dns"}, DNS: []string{"8.8.8.8", "9.9.9.9"}, Mac: "fake-dhcp-mac-address", } staticNetwork = boshsettings.Network{ Type: "manual", IP: "1.2.3.4", Netmask: "255.255.255.0", Gateway: "3.4.5.6", Mac: "fake-static-mac-address", } expectedNetworkConfigurationForStaticAndDhcp = `# Generated by bosh-agent auto lo iface lo inet loopback auto ethdhcp iface ethdhcp inet dhcp auto ethstatic iface ethstatic inet static address 1.2.3.4 network 1.2.3.0 netmask 255.255.255.0 broadcast 1.2.3.255 gateway 3.4.5.6 dns-nameservers 8.8.8.8 9.9.9.9` }) It("writes interfaces in /etc/network/interfaces in alphabetic order", func() { anotherDHCPNetwork := boshsettings.Network{ Type: "dynamic", Default: []string{"dns"}, DNS: []string{"8.8.8.8", "9.9.9.9"}, Mac: "fake-another-mac-address", } stubInterfaces(map[string]boshsettings.Network{ "ethstatic": staticNetwork, "ethdhcp1": dhcpNetwork, "ethdhcp0": anotherDHCPNetwork, }) err := netManager.SetupNetworking(boshsettings.Networks{ "dhcp-network-1": dhcpNetwork, "dhcp-network-2": anotherDHCPNetwork, "static-network": staticNetwork, }, nil) Expect(err).ToNot(HaveOccurred()) networkConfig := fs.GetFileTestStat("/etc/network/interfaces") Expect(networkConfig).ToNot(BeNil()) expectedNetworkConfigurationForStaticAndDhcp = `# Generated by bosh-agent auto lo iface lo inet loopback auto ethdhcp0 iface ethdhcp0 inet dhcp auto ethdhcp1 iface ethdhcp1 inet dhcp auto ethstatic iface ethstatic inet static address 1.2.3.4 network 1.2.3.0 netmask 255.255.255.0 broadcast 1.2.3.255 gateway 3.4.5.6 dns-nameservers 8.8.8.8 9.9.9.9` Expect(networkConfig.StringContents()).To(Equal(expectedNetworkConfigurationForStaticAndDhcp)) }) It("writes /etc/network/interfaces without dns-namservers if there are no dns servers", func() { staticNetworkWithoutDNS := boshsettings.Network{ Type: "manual", IP: "1.2.3.4", Netmask: "255.255.255.0", Gateway: "3.4.5.6", Mac: "fake-static-mac-address", } stubInterfaces(map[string]boshsettings.Network{ "ethstatic": staticNetworkWithoutDNS, }) err := netManager.SetupNetworking(boshsettings.Networks{"static-network": staticNetworkWithoutDNS}, nil) Expect(err).ToNot(HaveOccurred()) networkConfig := fs.GetFileTestStat("/etc/network/interfaces") Expect(networkConfig).ToNot(BeNil()) Expect(networkConfig.StringContents()).To(Equal(`# Generated by bosh-agent auto lo iface lo inet loopback auto ethstatic iface ethstatic inet static address 1.2.3.4 network 1.2.3.0 netmask 255.255.255.0 broadcast 1.2.3.255 gateway 3.4.5.6 `)) }) It("returns errors from glob /sys/class/net/", func() { fs.GlobErr = errors.New("fs-glob-error") err := netManager.SetupNetworking(boshsettings.Networks{"dhcp-network": dhcpNetwork, "static-network": staticNetwork}, nil) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fs-glob-error")) }) It("returns errors from writing the network configuration", func() { stubInterfaces(map[string]boshsettings.Network{ "dhcp": dhcpNetwork, "static": staticNetwork, }) fs.WriteFileError = errors.New("fs-write-file-error") err := netManager.SetupNetworking(boshsettings.Networks{"dhcp-network": dhcpNetwork, "static-network": staticNetwork}, nil) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fs-write-file-error")) }) It("returns errors when it can't creating network interface configurations", func() { stubInterfaces(map[string]boshsettings.Network{ "ethdhcp": dhcpNetwork, "ethstatic": staticNetwork, }) staticNetwork.Netmask = "not an ip" //will cause InterfaceConfigurationCreator to fail err := netManager.SetupNetworking(boshsettings.Networks{"static-network": staticNetwork}, nil) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Creating interface configurations")) }) It("writes a dhcp configuration if there are dhcp networks", func() { stubInterfaces(map[string]boshsettings.Network{ "ethdhcp": dhcpNetwork, "ethstatic": staticNetwork, }) err := netManager.SetupNetworking(boshsettings.Networks{"dhcp-network": dhcpNetwork, "static-network": staticNetwork}, nil) Expect(err).ToNot(HaveOccurred()) dhcpConfig := fs.GetFileTestStat("/etc/dhcp/dhclient.conf") Expect(dhcpConfig).ToNot(BeNil()) Expect(dhcpConfig.StringContents()).To(Equal(`# 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 8.8.8.8, 9.9.9.9; `)) }) It("writes a dhcp configuration without prepended dns servers if there are no dns servers specified", func() { dhcpNetworkWithoutDNS := boshsettings.Network{ Type: "dynamic", Mac: "fake-dhcp-mac-address", } stubInterfaces(map[string]boshsettings.Network{ "ethdhcp": dhcpNetwork, }) err := netManager.SetupNetworking(boshsettings.Networks{"dhcp-network": dhcpNetworkWithoutDNS}, nil) Expect(err).ToNot(HaveOccurred()) dhcpConfig := fs.GetFileTestStat("/etc/dhcp/dhclient.conf") Expect(dhcpConfig).ToNot(BeNil()) Expect(dhcpConfig.StringContents()).To(Equal(`# 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; `)) }) It("returns an error if it can't write a dhcp configuration", func() { stubInterfaces(map[string]boshsettings.Network{ "ethdhcp": dhcpNetwork, "ethstatic": staticNetwork, }) fs.WriteFileErrors["/etc/dhcp/dhclient.conf"] = errors.New("dhclient.conf-write-error") err := netManager.SetupNetworking(boshsettings.Networks{"dhcp-network": dhcpNetwork, "static-network": staticNetwork}, nil) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("dhclient.conf-write-error")) }) It("doesn't write a dhcp configuration if there are no dhcp networks", func() { stubInterfaces(map[string]boshsettings.Network{ "ethstatic": staticNetwork, }) err := netManager.SetupNetworking(boshsettings.Networks{"static-network": staticNetwork}, nil) Expect(err).ToNot(HaveOccurred()) dhcpConfig := fs.GetFileTestStat("/etc/dhcp/dhclient.conf") Expect(dhcpConfig).To(BeNil()) }) It("restarts the networks if /etc/network/interfaces changes", func() { initialDhcpConfig := `# 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 8.8.8.8, 9.9.9.9; ` stubInterfaces(map[string]boshsettings.Network{ "ethdhcp": dhcpNetwork, "ethstatic": staticNetwork, }) fs.WriteFileString("/etc/dhcp/dhclient.conf", initialDhcpConfig) err := netManager.SetupNetworking(boshsettings.Networks{"dhcp-network": dhcpNetwork, "static-network": staticNetwork}, nil) Expect(err).ToNot(HaveOccurred()) Expect(len(cmdRunner.RunCommands)).To(Equal(5)) Expect(cmdRunner.RunCommands[0]).To(Equal([]string{"pkill", "dhclient"})) Expect(cmdRunner.RunCommands[1:3]).To(ContainElement([]string{"resolvconf", "-d", "ethdhcp.dhclient"})) Expect(cmdRunner.RunCommands[1:3]).To(ContainElement([]string{"resolvconf", "-d", "ethstatic.dhclient"})) Expect(cmdRunner.RunCommands[3]).To(Equal([]string{"ifdown", "-a", "--no-loopback"})) Expect(cmdRunner.RunCommands[4]).To(Equal([]string{"ifup", "-a", "--no-loopback"})) }) It("doesn't restart the networks if /etc/network/interfaces and /etc/dhcp/dhclient.conf don't change", func() { initialDhcpConfig := `# 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 8.8.8.8, 9.9.9.9; ` stubInterfaces(map[string]boshsettings.Network{ "ethdhcp": dhcpNetwork, "ethstatic": staticNetwork, }) fs.WriteFileString("/etc/network/interfaces", expectedNetworkConfigurationForStaticAndDhcp) fs.WriteFileString("/etc/dhcp/dhclient.conf", initialDhcpConfig) err := netManager.SetupNetworking(boshsettings.Networks{"dhcp-network": dhcpNetwork, "static-network": staticNetwork}, nil) Expect(err).ToNot(HaveOccurred()) networkConfig := fs.GetFileTestStat("/etc/network/interfaces") Expect(networkConfig.StringContents()).To(Equal(expectedNetworkConfigurationForStaticAndDhcp)) dhcpConfig := fs.GetFileTestStat("/etc/dhcp/dhclient.conf") Expect(dhcpConfig.StringContents()).To(Equal(initialDhcpConfig)) Expect(len(cmdRunner.RunCommands)).To(Equal(0)) }) It("restarts the networks if /etc/dhcp/dhclient.conf changes", func() { stubInterfaces(map[string]boshsettings.Network{ "ethdhcp": dhcpNetwork, "ethstatic": staticNetwork, }) fs.WriteFileString("/etc/network/interfaces", expectedNetworkConfigurationForStaticAndDhcp) err := netManager.SetupNetworking(boshsettings.Networks{"dhcp-network": dhcpNetwork, "static-network": staticNetwork}, nil) Expect(err).ToNot(HaveOccurred()) networkConfig := fs.GetFileTestStat("/etc/network/interfaces") Expect(networkConfig.StringContents()).To(Equal(expectedNetworkConfigurationForStaticAndDhcp)) Expect(len(cmdRunner.RunCommands)).To(Equal(5)) Expect(cmdRunner.RunCommands[0]).To(Equal([]string{"pkill", "dhclient"})) Expect(cmdRunner.RunCommands[1:3]).To(ContainElement([]string{"resolvconf", "-d", "ethdhcp.dhclient"})) Expect(cmdRunner.RunCommands[1:3]).To(ContainElement([]string{"resolvconf", "-d", "ethstatic.dhclient"})) Expect(cmdRunner.RunCommands[3]).To(Equal([]string{"ifdown", "-a", "--no-loopback"})) Expect(cmdRunner.RunCommands[4]).To(Equal([]string{"ifup", "-a", "--no-loopback"})) }) It("broadcasts MAC addresses for all interfaces", func() { stubInterfaces(map[string]boshsettings.Network{ "ethdhcp": dhcpNetwork, "ethstatic": staticNetwork, }) errCh := make(chan error) err := netManager.SetupNetworking(boshsettings.Networks{"dhcp-network": dhcpNetwork, "static-network": staticNetwork}, errCh) Expect(err).ToNot(HaveOccurred()) broadcastErr := <-errCh // wait for all arpings Expect(broadcastErr).ToNot(HaveOccurred()) Expect(addressBroadcaster.BroadcastMACAddressesAddresses).To(Equal([]boship.InterfaceAddress{ boship.NewSimpleInterfaceAddress("ethstatic", "1.2.3.4"), boship.NewResolvingInterfaceAddress("ethdhcp", ipResolver), })) }) It("skips vip networks", func() { stubInterfaces(map[string]boshsettings.Network{ "ethdhcp": dhcpNetwork, "ethstatic": staticNetwork, }) vipNetwork := boshsettings.Network{ Type: "vip", Default: []string{"dns"}, DNS: []string{"8.8.8.8", "9.9.9.9"}, Mac: "fake-vip-mac-address", IP: "9.8.7.6", } err := netManager.SetupNetworking(boshsettings.Networks{ "dhcp-network": dhcpNetwork, "static-network": staticNetwork, "vip-network": vipNetwork, }, nil) Expect(err).ToNot(HaveOccurred()) networkConfig := fs.GetFileTestStat("/etc/network/interfaces") Expect(networkConfig).ToNot(BeNil()) Expect(networkConfig.StringContents()).To(Equal(expectedNetworkConfigurationForStaticAndDhcp)) }) Context("when no MAC address is provided in the settings", func() { It("configures network for single device", func() { staticNetworkWithoutMAC := boshsettings.Network{ Type: "manual", IP: "2.2.2.2", Netmask: "255.255.255.0", Gateway: "3.4.5.6", } stubInterfaces( map[string]boshsettings.Network{ "ethstatic": staticNetwork, }, ) err := netManager.SetupNetworking(boshsettings.Networks{ "static-network": staticNetworkWithoutMAC, }, nil) Expect(err).ToNot(HaveOccurred()) networkConfig := fs.GetFileTestStat("/etc/network/interfaces") Expect(networkConfig).ToNot(BeNil()) expectedNetworkConfiguration := `# Generated by bosh-agent auto lo iface lo inet loopback auto ethstatic iface ethstatic inet static address 2.2.2.2 network 2.2.2.0 netmask 255.255.255.0 broadcast 2.2.2.255 gateway 3.4.5.6 ` Expect(networkConfig.StringContents()).To(Equal(expectedNetworkConfiguration)) }) It("configures network for a single physical device, when a virtual device is also present", func() { staticNetworkWithoutMAC := boshsettings.Network{ Type: "manual", IP: "2.2.2.2", Netmask: "255.255.255.0", Gateway: "3.4.5.6", } stubInterfacesWithVirtual( map[string]boshsettings.Network{ "ethstatic": staticNetwork, }, []string{"virtual"}, ) err := netManager.SetupNetworking(boshsettings.Networks{ "static-network": staticNetworkWithoutMAC, }, nil) Expect(err).ToNot(HaveOccurred()) networkConfig := fs.GetFileTestStat("/etc/network/interfaces") Expect(networkConfig).ToNot(BeNil()) expectedNetworkConfiguration := `# Generated by bosh-agent auto lo iface lo inet loopback auto ethstatic iface ethstatic inet static address 2.2.2.2 network 2.2.2.0 netmask 255.255.255.0 broadcast 2.2.2.255 gateway 3.4.5.6 ` Expect(networkConfig.StringContents()).To(Equal(expectedNetworkConfiguration)) }) }) }) Describe("GetConfiguredNetworkInterfaces", func() { Context("when there are network devices", func() { BeforeEach(func() { interfacePaths := []string{} interfacePaths = append(interfacePaths, writeNetworkDevice("fake-eth0", "aa:bb", true)) interfacePaths = append(interfacePaths, writeNetworkDevice("fake-eth1", "cc:dd", true)) interfacePaths = append(interfacePaths, writeNetworkDevice("fake-eth2", "ee:ff", true)) fs.SetGlob("/sys/class/net/*", interfacePaths) }) It("returns networks that are defined in /etc/network/interfaces", func() { cmdRunner.AddCmdResult("ifup --no-act fake-eth0", fakesys.FakeCmdResult{ Stdout: "", Stderr: "ifup: interface fake-eth0 already configured", ExitStatus: 0, }) cmdRunner.AddCmdResult("ifup --no-act fake-eth1", fakesys.FakeCmdResult{ Stdout: "", Stderr: "Ignoring unknown interface fake-eth1=fake-eth1.", ExitStatus: 0, }) cmdRunner.AddCmdResult("ifup --no-act fake-eth2", fakesys.FakeCmdResult{ Stdout: "", Stderr: "ifup: interface fake-eth2 already configured", ExitStatus: 0, }) interfaces, err := netManager.GetConfiguredNetworkInterfaces() Expect(err).ToNot(HaveOccurred()) Expect(interfaces).To(ConsistOf("fake-eth0", "fake-eth2")) }) }) Context("when there are no network devices", func() { It("returns empty list", func() { interfaces, err := netManager.GetConfiguredNetworkInterfaces() Expect(err).ToNot(HaveOccurred()) Expect(interfaces).To(Equal([]string{})) }) }) }) }
import ( . "github.com/cloudfoundry/bosh-agent/internal/github.com/onsi/ginkgo" . "github.com/cloudfoundry/bosh-agent/internal/github.com/onsi/gomega" boshlog "github.com/cloudfoundry/bosh-agent/internal/github.com/cloudfoundry/bosh-utils/logger" fakesys "github.com/cloudfoundry/bosh-agent/internal/github.com/cloudfoundry/bosh-utils/system/fakes" boshcdrom "github.com/cloudfoundry/bosh-agent/platform/cdrom" fakecdrom "github.com/cloudfoundry/bosh-agent/platform/cdrom/fakes" boshdevutil "github.com/cloudfoundry/bosh-agent/platform/deviceutil" ) var _ = Describe("Cdutil", func() { var ( fs *fakesys.FakeFileSystem cdrom *fakecdrom.FakeCdrom cdutil boshdevutil.DeviceUtil logger boshlog.Logger ) BeforeEach(func() { fs = fakesys.NewFakeFileSystem() cdrom = fakecdrom.NewFakeCdrom(fs, "env", "fake env contents") logger = boshlog.NewLogger(boshlog.LevelNone) }) JustBeforeEach(func() { cdutil = boshcdrom.NewCdUtil("/fake/settings/dir", fs, cdrom, logger) }) It("gets file contents from CDROM", func() { contents, err := cdutil.GetFilesContents([]string{"env"})
func init() { Describe("concreteCompiler", func() { var ( compiler Compiler compressor *fakecmd.FakeCompressor blobstore *fakeblobstore.FakeBlobstore fs *fakesys.FakeFileSystem runner *fakecmdrunner.FakeFileLoggingCmdRunner packageApplier *fakepackages.FakeApplier packagesBc *fakebc.FakeBundleCollection ) BeforeEach(func() { compressor = fakecmd.NewFakeCompressor() blobstore = &fakeblobstore.FakeBlobstore{} fs = fakesys.NewFakeFileSystem() runner = fakecmdrunner.NewFakeFileLoggingCmdRunner() packageApplier = fakepackages.NewFakeApplier() packagesBc = fakebc.NewFakeBundleCollection() compiler = NewConcreteCompiler( compressor, blobstore, fs, runner, FakeCompileDirProvider{Dir: "/fake-compile-dir"}, packageApplier, packagesBc, ) }) BeforeEach(func() { fs.MkdirAll("/fake-compile-dir", os.ModePerm) }) Describe("Compile", func() { var ( bundle *fakebc.FakeBundle pkg Package pkgDeps []boshmodels.Package ) BeforeEach(func() { bundle = packagesBc.FakeGet(boshmodels.Package{ Name: "pkg_name", Version: "pkg_version", }) bundle.InstallPath = "/fake-dir/data/packages/pkg_name/pkg_version" bundle.EnablePath = "/fake-dir/packages/pkg_name" compressor.CompressFilesInDirTarballPath = "/tmp/compressed-compiled-package" pkg, pkgDeps = getCompileArgs() }) It("returns blob id and sha1 of created compiled package", func() { blobstore.CreateBlobID = "fake-blob-id" blobstore.CreateFingerprint = "fake-blob-sha1" blobID, sha1, err := compiler.Compile(pkg, pkgDeps) Expect(err).ToNot(HaveOccurred()) Expect(blobID).To(Equal("fake-blob-id")) Expect(sha1).To(Equal("fake-blob-sha1")) }) It("cleans up all packages before and after applying dependent packages", func() { _, _, err := compiler.Compile(pkg, pkgDeps) Expect(err).ToNot(HaveOccurred()) Expect(packageApplier.ActionsCalled).To(Equal([]string{"KeepOnly", "Apply", "Apply", "KeepOnly"})) Expect(packageApplier.KeptOnlyPackages).To(BeEmpty()) }) It("returns an error if cleaning up packages fails", func() { packageApplier.KeepOnlyErr = errors.New("fake-keep-only-error") _, _, err := compiler.Compile(pkg, pkgDeps) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-keep-only-error")) }) It("fetches source package from blobstore without checking SHA1 by default because of Director bug", func() { _, _, err := compiler.Compile(pkg, pkgDeps) Expect(err).ToNot(HaveOccurred()) Expect(blobstore.GetBlobIDs[0]).To(Equal("blobstore_id")) Expect(blobstore.GetFingerprints[0]).To(Equal("")) }) PIt("(Pending Tracker Story: <https://www.pivotaltracker.com/story/show/94524232>) fetches source package from blobstore and checks SHA1 by default in future", func() { _, _, err := compiler.Compile(pkg, pkgDeps) Expect(err).ToNot(HaveOccurred()) Expect(blobstore.GetBlobIDs[0]).To(Equal("blobstore_id")) Expect(blobstore.GetFingerprints[0]).To(Equal("sha1")) }) It("returns an error if removing compile target directory during uncompression fails", func() { fs.RegisterRemoveAllError("/fake-compile-dir/pkg_name", errors.New("fake-remove-error")) _, _, err := compiler.Compile(pkg, pkgDeps) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-remove-error")) }) It("returns an error if creating compile target directory during uncompression fails", func() { fs.RegisterMkdirAllError("/fake-compile-dir/pkg_name", errors.New("fake-mkdir-error")) _, _, err := compiler.Compile(pkg, pkgDeps) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-mkdir-error")) }) It("returns an error if removing temporary compile target directory during uncompression fails", func() { fs.RegisterRemoveAllError("/fake-compile-dir/pkg_name-bosh-agent-unpack", errors.New("fake-remove-error")) _, _, err := compiler.Compile(pkg, pkgDeps) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-remove-error")) }) It("returns an error if creating temporary compile target directory during uncompression fails", func() { fs.RegisterMkdirAllError("/fake-compile-dir/pkg_name-bosh-agent-unpack", errors.New("fake-mkdir-error")) _, _, err := compiler.Compile(pkg, pkgDeps) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-mkdir-error")) }) It("returns an error if target directory is empty during uncompression", func() { pkg.BlobstoreID = "" _, _, err := compiler.Compile(pkg, pkgDeps) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Blobstore ID for package '%s' is empty", pkg.Name)) }) It("installs dependent packages", func() { _, _, err := compiler.Compile(pkg, pkgDeps) Expect(err).ToNot(HaveOccurred()) Expect(packageApplier.AppliedPackages).To(Equal(pkgDeps)) }) It("cleans up the compile directory", func() { _, _, err := compiler.Compile(pkg, pkgDeps) Expect(err).ToNot(HaveOccurred()) Expect(fs.FileExists("/fake-compile-dir/pkg_name")).To(BeFalse()) }) It("installs, enables and later cleans up bundle", func() { _, _, err := compiler.Compile(pkg, pkgDeps) Expect(err).ToNot(HaveOccurred()) Expect(bundle.ActionsCalled).To(Equal([]string{ "InstallWithoutContents", "Enable", "Disable", "Uninstall", })) }) Context("when packaging script exists", func() { BeforeEach(func() { compressor.DecompressFileToDirCallBack = func() { fs.WriteFileString("/fake-compile-dir/pkg_name/packaging", "hi") } }) It("runs packaging script ", func() { _, _, err := compiler.Compile(pkg, pkgDeps) Expect(err).ToNot(HaveOccurred()) expectedCmd := boshsys.Command{ Name: "bash", Args: []string{"-x", "packaging"}, Env: map[string]string{ "BOSH_COMPILE_TARGET": "/fake-compile-dir/pkg_name", "BOSH_INSTALL_TARGET": "/fake-dir/packages/pkg_name", "BOSH_PACKAGE_NAME": "pkg_name", "BOSH_PACKAGE_VERSION": "pkg_version", }, WorkingDir: "/fake-compile-dir/pkg_name", } Expect(len(runner.RunCommands)).To(Equal(1)) Expect(runner.RunCommands[0]).To(Equal(expectedCmd)) Expect(runner.RunCommandJobName).To(Equal("compilation")) Expect(runner.RunCommandTaskName).To(Equal("packaging")) }) It("propagates the error from packaging script", func() { runner.RunCommandErr = errors.New("fake-packaging-error") _, _, err := compiler.Compile(pkg, pkgDeps) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-packaging-error")) }) }) It("does not run packaging script when script does not exist", func() { _, _, err := compiler.Compile(pkg, pkgDeps) Expect(err).ToNot(HaveOccurred()) Expect(runner.RunCommands).To(BeEmpty()) }) It("compresses compiled package", func() { _, _, err := compiler.Compile(pkg, pkgDeps) Expect(err).ToNot(HaveOccurred()) // archive was downloaded from the blobstore and decompress to this temp dir Expect(compressor.DecompressFileToDirDirs[0]).To(Equal("/fake-compile-dir/pkg_name-bosh-agent-unpack")) Expect(compressor.DecompressFileToDirTarballPaths[0]).To(Equal(blobstore.GetFileName)) // contents were moved from the temp dir to the install/enable dir Expect(fs.RenameOldPaths[0]).To(Equal("/fake-compile-dir/pkg_name-bosh-agent-unpack")) Expect(fs.RenameNewPaths[0]).To(Equal("/fake-compile-dir/pkg_name")) // install path, presumably with your packaged code, was compressed installPath := "/fake-dir/data/packages/pkg_name/pkg_version" Expect(compressor.CompressFilesInDirDir).To(Equal(installPath)) }) It("uploads compressed package to blobstore", func() { compressor.CompressFilesInDirTarballPath = "/tmp/compressed-compiled-package" _, _, err := compiler.Compile(pkg, pkgDeps) Expect(err).ToNot(HaveOccurred()) Expect(blobstore.CreateFileNames[0]).To(Equal("/tmp/compressed-compiled-package")) }) It("returs error if uploading compressed package fails", func() { blobstore.CreateErr = errors.New("fake-create-err") _, _, err := compiler.Compile(pkg, pkgDeps) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-create-err")) }) It("cleans up compressed package after uploading it to blobstore", func() { var beforeCleanUpTarballPath, afterCleanUpTarballPath string blobstore.CreateCallBack = func() { beforeCleanUpTarballPath = compressor.CleanUpTarballPath } _, _, err := compiler.Compile(pkg, pkgDeps) Expect(err).ToNot(HaveOccurred()) // Compressed package is not cleaned up before blobstore upload Expect(beforeCleanUpTarballPath).To(Equal("")) // Deleted after it was uploaded afterCleanUpTarballPath = compressor.CleanUpTarballPath Expect(afterCleanUpTarballPath).To(Equal("/tmp/compressed-compiled-package")) }) }) }) }
func describeCentosNetManager() { var ( fs *fakesys.FakeFileSystem cmdRunner *fakesys.FakeCmdRunner ipResolver *fakeip.FakeResolver addressBroadcaster *fakearp.FakeAddressBroadcaster netManager Manager interfaceConfigurationCreator InterfaceConfigurationCreator ) BeforeEach(func() { fs = fakesys.NewFakeFileSystem() cmdRunner = fakesys.NewFakeCmdRunner() ipResolver = &fakeip.FakeResolver{} logger := boshlog.NewLogger(boshlog.LevelNone) interfaceConfigurationCreator = NewInterfaceConfigurationCreator(logger) addressBroadcaster = &fakearp.FakeAddressBroadcaster{} netManager = NewCentosNetManager( fs, cmdRunner, ipResolver, interfaceConfigurationCreator, addressBroadcaster, logger, ) }) writeNetworkDevice := func(iface string, macAddress string, isPhysical bool) string { interfacePath := fmt.Sprintf("/sys/class/net/%s", iface) fs.WriteFile(interfacePath, []byte{}) if isPhysical { fs.WriteFile(fmt.Sprintf("/sys/class/net/%s/device", iface), []byte{}) } fs.WriteFileString(fmt.Sprintf("/sys/class/net/%s/address", iface), fmt.Sprintf("%s\n", macAddress)) return interfacePath } Describe("SetupNetworking", func() { var ( dhcpNetwork boshsettings.Network staticNetwork boshsettings.Network expectedNetworkConfigurationForStatic string expectedNetworkConfigurationForDHCP string expectedDhclientConfiguration string ) BeforeEach(func() { dhcpNetwork = boshsettings.Network{ Type: "dynamic", Default: []string{"dns"}, DNS: []string{"8.8.8.8", "9.9.9.9"}, Mac: "fake-dhcp-mac-address", } staticNetwork = boshsettings.Network{ Type: "manual", IP: "1.2.3.4", Netmask: "255.255.255.0", Gateway: "3.4.5.6", Mac: "fake-static-mac-address", } expectedNetworkConfigurationForStatic = `DEVICE=ethstatic BOOTPROTO=static IPADDR=1.2.3.4 NETMASK=255.255.255.0 BROADCAST=1.2.3.255 GATEWAY=3.4.5.6 ONBOOT=yes PEERDNS=no DNS1=8.8.8.8 DNS2=9.9.9.9 ` expectedNetworkConfigurationForDHCP = `DEVICE=ethdhcp BOOTPROTO=dhcp ONBOOT=yes PEERDNS=yes ` expectedDhclientConfiguration = `# 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 8.8.8.8, 9.9.9.9; ` }) stubInterfacesWithVirtual := func(physicalInterfaces map[string]boshsettings.Network, virtualInterfaces []string) { interfacePaths := []string{} for iface, networkSettings := range physicalInterfaces { interfacePaths = append(interfacePaths, writeNetworkDevice(iface, networkSettings.Mac, true)) } for _, iface := range virtualInterfaces { interfacePaths = append(interfacePaths, writeNetworkDevice(iface, "virtual", false)) } fs.SetGlob("/sys/class/net/*", interfacePaths) } stubInterfaces := func(physicalInterfaces map[string]boshsettings.Network) { stubInterfacesWithVirtual(physicalInterfaces, nil) } It("writes a network script for static and dynamic interfaces", func() { stubInterfaces(map[string]boshsettings.Network{ "ethdhcp": dhcpNetwork, "ethstatic": staticNetwork, }) err := netManager.SetupNetworking(boshsettings.Networks{"dhcp-network": dhcpNetwork, "static-network": staticNetwork}, nil) Expect(err).ToNot(HaveOccurred()) staticConfig := fs.GetFileTestStat("/etc/sysconfig/network-scripts/ifcfg-ethstatic") Expect(staticConfig).ToNot(BeNil()) Expect(staticConfig.StringContents()).To(Equal(expectedNetworkConfigurationForStatic)) dhcpConfig := fs.GetFileTestStat("/etc/sysconfig/network-scripts/ifcfg-ethdhcp") Expect(dhcpConfig).ToNot(BeNil()) Expect(dhcpConfig.StringContents()).To(Equal(expectedNetworkConfigurationForDHCP)) }) It("returns errors from glob /sys/class/net/", func() { fs.GlobErr = errors.New("fs-glob-error") err := netManager.SetupNetworking(boshsettings.Networks{"dhcp-network": dhcpNetwork, "static-network": staticNetwork}, nil) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fs-glob-error")) }) It("returns errors from writing the network configuration", func() { stubInterfaces(map[string]boshsettings.Network{ "dhcp": dhcpNetwork, "static": staticNetwork, }) fs.WriteFileError = errors.New("fs-write-file-error") err := netManager.SetupNetworking(boshsettings.Networks{"dhcp-network": dhcpNetwork, "static-network": staticNetwork}, nil) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fs-write-file-error")) }) It("returns errors when it can't create network interface configurations", func() { stubInterfaces(map[string]boshsettings.Network{ "ethstatic": staticNetwork, }) staticNetwork.Netmask = "not an ip" //will cause InterfaceConfigurationCreator to fail err := netManager.SetupNetworking(boshsettings.Networks{"static-network": staticNetwork}, nil) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Creating interface configurations")) }) It("wrtites a dhcp configuration if there are dhcp networks", func() { stubInterfaces(map[string]boshsettings.Network{ "ethdhcp": dhcpNetwork, "ethstatic": staticNetwork, }) err := netManager.SetupNetworking(boshsettings.Networks{"dhcp-network": dhcpNetwork, "static-network": staticNetwork}, nil) Expect(err).ToNot(HaveOccurred()) dhcpConfig := fs.GetFileTestStat("/etc/dhcp/dhclient.conf") Expect(dhcpConfig).ToNot(BeNil()) Expect(dhcpConfig.StringContents()).To(Equal(expectedDhclientConfiguration)) dhcpConfigSymlink := fs.GetFileTestStat("/etc/dhcp/dhclient-ethdhcp.conf") Expect(dhcpConfigSymlink).ToNot(BeNil()) Expect(dhcpConfigSymlink.SymlinkTarget).To(Equal("/etc/dhcp/dhclient.conf")) }) It("writes a dhcp configuration without prepended dns servers if there are no dns servers specified", func() { dhcpNetworkWithoutDNS := boshsettings.Network{ Type: "dynamic", Mac: "fake-dhcp-mac-address", } stubInterfaces(map[string]boshsettings.Network{ "ethdhcp": dhcpNetwork, }) err := netManager.SetupNetworking(boshsettings.Networks{"dhcp-network": dhcpNetworkWithoutDNS}, nil) Expect(err).ToNot(HaveOccurred()) dhcpConfig := fs.GetFileTestStat("/etc/dhcp/dhclient.conf") Expect(dhcpConfig).ToNot(BeNil()) Expect(dhcpConfig.StringContents()).To(Equal(`# 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; `)) dhcpConfigSymlink := fs.GetFileTestStat("/etc/dhcp/dhclient-ethdhcp.conf") Expect(dhcpConfigSymlink).ToNot(BeNil()) Expect(dhcpConfigSymlink.SymlinkTarget).To(Equal("/etc/dhcp/dhclient.conf")) }) It("returns an error if it can't write a dhcp configuration", func() { stubInterfaces(map[string]boshsettings.Network{ "ethdhcp": dhcpNetwork, "ethstatic": staticNetwork, }) fs.WriteFileErrors["/etc/dhcp/dhclient.conf"] = errors.New("dhclient.conf-write-error") err := netManager.SetupNetworking(boshsettings.Networks{"dhcp-network": dhcpNetwork, "static-network": staticNetwork}, nil) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("dhclient.conf-write-error")) }) It("returns an error if it can't symlink a dhcp configuration", func() { stubInterfaces(map[string]boshsettings.Network{ "ethdhcp": dhcpNetwork, "ethstatic": staticNetwork, }) fs.SymlinkError = errors.New("dhclient-ethdhcp.conf-symlink-error") err := netManager.SetupNetworking(boshsettings.Networks{"dhcp-network": dhcpNetwork, "static-network": staticNetwork}, nil) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("dhclient-ethdhcp.conf-symlink-error")) }) It("doesn't write a dhcp configuration if there are no dhcp networks", func() { stubInterfaces(map[string]boshsettings.Network{ "ethstatic": staticNetwork, }) err := netManager.SetupNetworking(boshsettings.Networks{"static-network": staticNetwork}, nil) Expect(err).ToNot(HaveOccurred()) dhcpConfig := fs.GetFileTestStat("/etc/dhcp/dhclient-ethdhcp.conf") Expect(dhcpConfig).To(BeNil()) }) It("restarts the networks if any ifconfig file changes", func() { changingStaticNetwork := boshsettings.Network{ Type: "manual", IP: "1.2.3.5", Netmask: "255.255.255.0", Gateway: "3.4.5.6", Mac: "ethstatict-that-changes", } stubInterfaces(map[string]boshsettings.Network{ "ethdhcp": dhcpNetwork, "ethstatic-that-changes": changingStaticNetwork, "ethstatic": staticNetwork, }) fs.WriteFileString("/etc/sysconfig/network-scripts/ifcfg-ethstatic", expectedNetworkConfigurationForStatic) fs.WriteFileString("/etc/dhcp/dhclient.conf", expectedDhclientConfiguration) err := netManager.SetupNetworking(boshsettings.Networks{ "dhcp-network": dhcpNetwork, "changing-static-network": changingStaticNetwork, "static-network": staticNetwork, }, nil) Expect(err).ToNot(HaveOccurred()) Expect(len(cmdRunner.RunCommands)).To(Equal(1)) Expect(cmdRunner.RunCommands[0]).To(Equal([]string{"service", "network", "restart"})) }) It("doesn't restart the networks if ifcfg and /etc/dhcp/dhclient.conf don't change", func() { stubInterfaces(map[string]boshsettings.Network{ "ethdhcp": dhcpNetwork, "ethstatic": staticNetwork, }) fs.WriteFileString("/etc/sysconfig/network-scripts/ifcfg-ethstatic", expectedNetworkConfigurationForStatic) fs.WriteFileString("/etc/sysconfig/network-scripts/ifcfg-ethdhcp", expectedNetworkConfigurationForDHCP) fs.WriteFileString("/etc/dhcp/dhclient.conf", expectedDhclientConfiguration) err := netManager.SetupNetworking(boshsettings.Networks{"dhcp-network": dhcpNetwork, "static-network": staticNetwork}, nil) Expect(err).ToNot(HaveOccurred()) networkConfig := fs.GetFileTestStat("/etc/sysconfig/network-scripts/ifcfg-ethstatic") Expect(networkConfig).ToNot(BeNil()) Expect(networkConfig.StringContents()).To(Equal(expectedNetworkConfigurationForStatic)) dhcpConfig := fs.GetFileTestStat("/etc/dhcp/dhclient.conf") Expect(dhcpConfig.StringContents()).To(Equal(expectedDhclientConfiguration)) Expect(len(cmdRunner.RunCommands)).To(Equal(0)) }) It("restarts the networks if /etc/dhcp/dhclient.conf changes", func() { stubInterfaces(map[string]boshsettings.Network{ "ethdhcp": dhcpNetwork, "ethstatic": staticNetwork, }) fs.WriteFileString("/etc/sysconfig/network-scripts/ifcfg-ethstatic", expectedNetworkConfigurationForStatic) err := netManager.SetupNetworking(boshsettings.Networks{"dhcp-network": dhcpNetwork, "static-network": staticNetwork}, nil) Expect(err).ToNot(HaveOccurred()) networkConfig := fs.GetFileTestStat("/etc/sysconfig/network-scripts/ifcfg-ethstatic") Expect(networkConfig).ToNot(BeNil()) Expect(networkConfig.StringContents()).To(Equal(expectedNetworkConfigurationForStatic)) Expect(len(cmdRunner.RunCommands)).To(Equal(1)) Expect(cmdRunner.RunCommands[0]).To(Equal([]string{"service", "network", "restart"})) }) It("broadcasts MAC addresses for all interfaces", func() { stubInterfaces(map[string]boshsettings.Network{ "ethdhcp": dhcpNetwork, "ethstatic": staticNetwork, }) errCh := make(chan error) err := netManager.SetupNetworking(boshsettings.Networks{"dhcp-network": dhcpNetwork, "static-network": staticNetwork}, errCh) Expect(err).ToNot(HaveOccurred()) broadcastErr := <-errCh // wait for all arpings Expect(broadcastErr).ToNot(HaveOccurred()) Expect(addressBroadcaster.BroadcastMACAddressesAddresses).To(Equal([]boship.InterfaceAddress{ boship.NewSimpleInterfaceAddress("ethstatic", "1.2.3.4"), boship.NewResolvingInterfaceAddress("ethdhcp", ipResolver), })) }) It("skips vip networks", func() { stubInterfaces(map[string]boshsettings.Network{ "ethdhcp": dhcpNetwork, "ethstatic": staticNetwork, }) vipNetwork := boshsettings.Network{ Type: "vip", Default: []string{"dns"}, DNS: []string{"4.4.4.4", "5.5.5.5"}, Mac: "fake-vip-mac-address", IP: "9.8.7.6", } err := netManager.SetupNetworking(boshsettings.Networks{ "dhcp-network": dhcpNetwork, "static-network": staticNetwork, "vip-network": vipNetwork, }, nil) Expect(err).ToNot(HaveOccurred()) networkConfig := fs.GetFileTestStat("/etc/sysconfig/network-scripts/ifcfg-ethstatic") Expect(networkConfig).ToNot(BeNil()) Expect(networkConfig.StringContents()).To(Equal(expectedNetworkConfigurationForStatic)) }) It("doesn't use vip networks dns", func() { stubInterfaces(map[string]boshsettings.Network{ "ethstatic": staticNetwork, }) vipNetwork := boshsettings.Network{ Type: "vip", Default: []string{"dns"}, DNS: []string{"4.4.4.4", "5.5.5.5"}, Mac: "fake-vip-mac-address", IP: "9.8.7.6", } err := netManager.SetupNetworking(boshsettings.Networks{ "vip-network": vipNetwork, "static-network": staticNetwork, }, nil) Expect(err).ToNot(HaveOccurred()) networkConfig := fs.GetFileTestStat("/etc/sysconfig/network-scripts/ifcfg-ethstatic") Expect(networkConfig).ToNot(BeNil()) Expect(networkConfig.StringContents()).ToNot(ContainSubstring("4.4.4.4")) Expect(networkConfig.StringContents()).ToNot(ContainSubstring("5.5.5.5")) }) Context("when no MAC address is provided in the settings", func() { var staticNetworkWithoutMAC boshsettings.Network BeforeEach(func() { staticNetworkWithoutMAC = boshsettings.Network{ Type: "manual", IP: "1.2.3.4", Netmask: "255.255.255.0", Gateway: "3.4.5.6", DNS: []string{"8.8.8.8", "9.9.9.9"}, Default: []string{"dns"}, } }) It("configures network for single device", func() { stubInterfaces( map[string]boshsettings.Network{ "ethstatic": staticNetwork, }, ) err := netManager.SetupNetworking(boshsettings.Networks{ "static-network": staticNetworkWithoutMAC, }, nil) Expect(err).ToNot(HaveOccurred()) networkConfig := fs.GetFileTestStat("/etc/sysconfig/network-scripts/ifcfg-ethstatic") Expect(networkConfig).ToNot(BeNil()) Expect(networkConfig.StringContents()).To(Equal(expectedNetworkConfigurationForStatic)) }) It("configures network for single device, when a virtual device is also present", func() { stubInterfacesWithVirtual( map[string]boshsettings.Network{ "ethstatic": staticNetwork, }, []string{"virtual"}, ) err := netManager.SetupNetworking(boshsettings.Networks{ "static-network": staticNetworkWithoutMAC, }, nil) Expect(err).ToNot(HaveOccurred()) physicalNetworkConfig := fs.GetFileTestStat("/etc/sysconfig/network-scripts/ifcfg-ethstatic") Expect(physicalNetworkConfig).ToNot(BeNil()) Expect(physicalNetworkConfig.StringContents()).To(Equal(expectedNetworkConfigurationForStatic)) virtualNetworkConfig := fs.GetFileTestStat("/etc/sysconfig/network-scripts/ifcfg-virtual") Expect(virtualNetworkConfig).To(BeNil()) }) }) }) Describe("GetConfiguredNetworkInterfaces", func() { Context("when there are network devices", func() { BeforeEach(func() { interfacePaths := []string{} interfacePaths = append(interfacePaths, writeNetworkDevice("fake-eth0", "aa:bb", true)) interfacePaths = append(interfacePaths, writeNetworkDevice("fake-eth1", "cc:dd", true)) interfacePaths = append(interfacePaths, writeNetworkDevice("fake-eth2", "ee:ff", true)) fs.SetGlob("/sys/class/net/*", interfacePaths) }) writeIfcgfFile := func(iface string) { fs.WriteFileString(fmt.Sprintf("/etc/sysconfig/network-scripts/ifcfg-%s", iface), "fake-config") } It("returns networks that have ifcfg config present", func() { writeIfcgfFile("fake-eth0") writeIfcgfFile("fake-eth2") interfaces, err := netManager.GetConfiguredNetworkInterfaces() Expect(err).ToNot(HaveOccurred()) Expect(interfaces).To(ConsistOf("fake-eth0", "fake-eth2")) }) }) Context("when there are no network devices", func() { It("returns empty list", func() { interfaces, err := netManager.GetConfiguredNetworkInterfaces() Expect(err).ToNot(HaveOccurred()) Expect(interfaces).To(Equal([]string{})) }) }) }) }
import ( "errors" . "github.com/cloudfoundry/bosh-agent/internal/github.com/onsi/ginkgo" . "github.com/cloudfoundry/bosh-agent/internal/github.com/onsi/gomega" "github.com/cloudfoundry/bosh-agent/agent/scriptrunner" fakesys "github.com/cloudfoundry/bosh-agent/internal/github.com/cloudfoundry/bosh-utils/system/fakes" "path/filepath" ) var _ = Describe("GenericScript", func() { var ( fs *fakesys.FakeFileSystem cmdRunner *fakesys.FakeCmdRunner genericScript scriptrunner.GenericScript stdoutLogPath string stderrLogPath string ) BeforeEach(func() { fs = fakesys.NewFakeFileSystem() cmdRunner = fakesys.NewFakeCmdRunner() stdoutLogPath = filepath.Join("base", "stdout", "logdir", "stdout.log") stderrLogPath = filepath.Join("base", "stderr", "logdir", "stderr.log") genericScript = scriptrunner.NewScript( "my-tag", fs, cmdRunner, "/path-to-script", stdoutLogPath,
"strings" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" boshassert "github.com/cloudfoundry/bosh-agent/internal/github.com/cloudfoundry/bosh-utils/assert" . "github.com/cloudfoundry/bosh-agent/internal/github.com/cloudfoundry/bosh-utils/blobstore" fakesys "github.com/cloudfoundry/bosh-agent/internal/github.com/cloudfoundry/bosh-utils/system/fakes" fakeuuid "github.com/cloudfoundry/bosh-agent/internal/github.com/cloudfoundry/bosh-utils/uuid/fakes" ) var _ = Describe("externalBlobstore", func() { var ( fs *fakesys.FakeFileSystem runner *fakesys.FakeCmdRunner uuidGen *fakeuuid.FakeGenerator configPath string blobstore Blobstore ) BeforeEach(func() { fs = fakesys.NewFakeFileSystem() runner = fakesys.NewFakeCmdRunner() uuidGen = &fakeuuid.FakeGenerator{} configPath = filepath.Join("/etc/", "blobstore-fake-provider.json") blobstore = NewExternalBlobstore("fake-provider", map[string]interface{}{}, fs, runner, uuidGen, configPath) }) Describe("Validate", func() { It("external validate writes config file", func() { options := map[string]interface{}{"fake-key": "fake-value"}
"errors" "os" . "github.com/cloudfoundry/bosh-agent/internal/github.com/onsi/ginkgo" . "github.com/cloudfoundry/bosh-agent/internal/github.com/onsi/gomega" . "github.com/cloudfoundry/bosh-agent/agent/applier/bundlecollection" boshlog "github.com/cloudfoundry/bosh-agent/internal/github.com/cloudfoundry/bosh-utils/logger" fakesys "github.com/cloudfoundry/bosh-agent/internal/github.com/cloudfoundry/bosh-utils/system/fakes" ) var _ = Describe("FileBundle", func() { var ( fs *fakesys.FakeFileSystem logger boshlog.Logger sourcePath string installPath string enablePath string fileBundle FileBundle ) BeforeEach(func() { fs = fakesys.NewFakeFileSystem() installPath = "/install-path" enablePath = "/enable-path" logger = boshlog.NewLogger(boshlog.LevelNone) fileBundle = NewFileBundle(installPath, enablePath, fs, logger) }) createSourcePath := func() string { path := "/source-path" err := fs.MkdirAll(path, os.ModePerm)
. "github.com/cloudfoundry/bosh-agent/internal/github.com/onsi/ginkgo" . "github.com/cloudfoundry/bosh-agent/internal/github.com/onsi/gomega" . "github.com/cloudfoundry/bosh-agent/micro" boshhandler "github.com/cloudfoundry/bosh-agent/handler" boshlog "github.com/cloudfoundry/bosh-agent/internal/github.com/cloudfoundry/bosh-utils/logger" fakesys "github.com/cloudfoundry/bosh-agent/internal/github.com/cloudfoundry/bosh-utils/system/fakes" boshdir "github.com/cloudfoundry/bosh-agent/settings/directories" ) var _ = Describe("HTTPSHandler", func() { var ( serverURL string handler HTTPSHandler fs *fakesys.FakeFileSystem receivedRequest boshhandler.Request httpClient http.Client ) BeforeEach(func() { serverURL = "https://*****:*****@127.0.0.1:6900" mbusURL, _ := url.Parse(serverURL) logger := boshlog.NewLogger(boshlog.LevelNone) fs = fakesys.NewFakeFileSystem() dirProvider := boshdir.NewProvider("/var/vcap") handler = NewHTTPSHandler(mbusURL, logger, fs, dirProvider) go handler.Start(func(req boshhandler.Request) (resp boshhandler.Response) { receivedRequest = req return boshhandler.NewValueResponse("expected value")
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, fakeactions.NewFakeAgentKiller()) }) 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()) }) }) }) }
func init() { Describe("concreteV1Service", func() { var ( fs *fakesys.FakeFileSystem specPath = "/spec.json" service V1Service ) BeforeEach(func() { fs = fakesys.NewFakeFileSystem() service = NewConcreteV1Service(fs, specPath) }) Describe("Get", func() { Context("when filesystem has a spec file", func() { BeforeEach(func() { fs.WriteFileString(specPath, `{"deployment":"fake-deployment-name"}`) }) It("reads spec from filesystem", func() { spec, err := service.Get() Expect(err).ToNot(HaveOccurred()) Expect(spec).To(Equal(V1ApplySpec{Deployment: "fake-deployment-name"})) }) It("returns error if reading spec from filesystem errs", func() { fs.ReadFileError = errors.New("fake-read-error") spec, err := service.Get() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-read-error")) Expect(spec).To(Equal(V1ApplySpec{})) }) }) Context("when filesystem does not have a spec file", func() { It("reads spec from filesystem", func() { spec, err := service.Get() Expect(err).ToNot(HaveOccurred()) Expect(spec).To(Equal(V1ApplySpec{})) }) }) }) Describe("Set", func() { newSpec := V1ApplySpec{Deployment: "fake-deployment-name"} It("writes spec to filesystem", func() { err := service.Set(newSpec) Expect(err).ToNot(HaveOccurred()) specPathStats := fs.GetFileTestStat(specPath) Expect(specPathStats).ToNot(BeNil()) boshassert.MatchesJSONBytes(GinkgoT(), newSpec, specPathStats.Content) }) It("returns error if writing spec to filesystem errs", func() { fs.WriteFileError = errors.New("fake-write-error") err := service.Set(newSpec) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-write-error")) }) }) Describe("PopulateDHCPNetworks", func() { var settings boshsettings.Settings var unresolvedSpec V1ApplySpec var staticSpec NetworkSpec var dhcpSpec NetworkSpec var manualSetting boshsettings.Network var dynamicSetting boshsettings.Network BeforeEach(func() { settings = boshsettings.Settings{ Networks: boshsettings.Networks{}, } manualSetting = boshsettings.Network{ Type: "manual", IP: "fake-manual-ip", Netmask: "fake-manual-netmask", Gateway: "fake-manual-gateway", Mac: "fake-manual-mac", } dynamicSetting = boshsettings.Network{ Type: "dynamic", IP: "fake-dynamic-ip", Netmask: "fake-dynamic-netmask", Gateway: "fake-dynamic-gateway", } unresolvedSpec = V1ApplySpec{ Deployment: "fake-deployment", NetworkSpecs: map[string]NetworkSpec{}, } staticSpec = NetworkSpec{ Fields: map[string]interface{}{ "ip": "fake-net1-ip", "netmask": "fake-net1-netmask", "gateway": "fake-net1-gateway", "mac": "fake-net1-mac", }, } dhcpSpec = NetworkSpec{ Fields: map[string]interface{}{ "type": NetworkSpecTypeDynamic, "ip": "fake-net2-ip", "netmask": "fake-net2-netmask", "gateway": "fake-net2-gateway", }, } }) Context("when associated network is in settings", func() { Context("when there are no networks configured with DHCP", func() { BeforeEach(func() { settings.Networks["fake-net"] = manualSetting unresolvedSpec.NetworkSpecs["fake-net"] = staticSpec }) It("returns spec without modifying any networks", func() { spec, err := service.PopulateDHCPNetworks(unresolvedSpec, settings) Expect(err).ToNot(HaveOccurred()) Expect(spec).To(Equal(unresolvedSpec)) }) }) Context("when there is network with name 'local' and ip 127.0.0.1", func() { BeforeEach(func() { unresolvedSpec.NetworkSpecs["local"] = NetworkSpec{ Fields: map[string]interface{}{"ip": "127.0.0.1"}, } }) It("returns spec without modifying any networks", func() { spec, err := service.PopulateDHCPNetworks(unresolvedSpec, settings) Expect(err).ToNot(HaveOccurred()) Expect(spec).To(Equal(unresolvedSpec)) }) }) Context("when there are networks configured with DHCP", func() { BeforeEach(func() { settings.Networks["static-net1"] = manualSetting settings.Networks["dhcp-net2"] = dynamicSetting unresolvedSpec.NetworkSpecs["static-net1"] = staticSpec unresolvedSpec.NetworkSpecs["dhcp-net2"] = dhcpSpec }) It("returns spec with networks modified via DHCP and keeps everything else the same", func() { spec, err := service.PopulateDHCPNetworks(unresolvedSpec, settings) Expect(err).ToNot(HaveOccurred()) Expect(spec).To(Equal(V1ApplySpec{ Deployment: "fake-deployment", NetworkSpecs: map[string]NetworkSpec{ "static-net1": staticSpec, "dhcp-net2": NetworkSpec{ Fields: map[string]interface{}{ "type": NetworkSpecTypeDynamic, "ip": dynamicSetting.IP, "netmask": dynamicSetting.Netmask, "gateway": dynamicSetting.Gateway, }, }, }, })) }) }) }) Context("when associated network cannot be found in settings", func() { BeforeEach(func() { settings.Networks["net-present-in-settings"] = manualSetting unresolvedSpec.NetworkSpecs["net-present-in-settings"] = staticSpec unresolvedSpec.NetworkSpecs["net-not-present-in-settings"] = dhcpSpec }) It("returns error", func() { spec, err := service.PopulateDHCPNetworks(unresolvedSpec, settings) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Network 'net-not-present-in-settings' is not found in settings")) Expect(spec).To(Equal(V1ApplySpec{})) }) }) }) }) }
. "github.com/cloudfoundry/bosh-agent/internal/github.com/onsi/ginkgo" . "github.com/cloudfoundry/bosh-agent/internal/github.com/onsi/gomega" boshlog "github.com/cloudfoundry/bosh-agent/internal/github.com/cloudfoundry/bosh-utils/logger" fakesys "github.com/cloudfoundry/bosh-agent/internal/github.com/cloudfoundry/bosh-utils/system/fakes" boshdevutil "github.com/cloudfoundry/bosh-agent/platform/deviceutil" fakedisk "github.com/cloudfoundry/bosh-agent/platform/disk/fakes" . "github.com/cloudfoundry/bosh-agent/platform/disk" ) var _ = Describe("Diskutil", func() { var ( diskUtil boshdevutil.DeviceUtil mounter *fakedisk.FakeMounter fs *fakesys.FakeFileSystem ) BeforeEach(func() { mounter = &fakedisk.FakeMounter{} fs = fakesys.NewFakeFileSystem() logger := boshlog.NewLogger(boshlog.LevelNone) diskUtil = NewDiskUtil("fake-disk-path", mounter, fs, logger) }) Describe("GetFileContents", func() { Context("when disk path does not exist", func() { It("returns an error if diskpath does not exist", func() { _, err := diskUtil.GetFilesContents([]string{"fake-file-path-1"}) Expect(err).To(HaveOccurred())
func init() { Describe("bootstrap", func() { Describe("Run", func() { var ( platform *fakeplatform.FakePlatform dirProvider boshdir.Provider settingsSource *fakeinf.FakeSettingsSource settingsService *fakesettings.FakeSettingsService ) BeforeEach(func() { platform = fakeplatform.NewFakePlatform() dirProvider = boshdir.NewProvider("/var/vcap") settingsSource = &fakeinf.FakeSettingsSource{} settingsService = &fakesettings.FakeSettingsService{} }) bootstrap := func() error { logger := boshlog.NewLogger(boshlog.LevelNone) return NewBootstrap(platform, dirProvider, settingsService, logger).Run() } It("sets up runtime configuration", func() { err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(platform.SetupRuntimeConfigurationWasInvoked).To(BeTrue()) }) Describe("SSH tunnel setup for registry", func() { It("returns error without configuring ssh on the platform if getting public key fails", func() { settingsService.PublicKeyErr = errors.New("fake-get-public-key-err") err := bootstrap() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-get-public-key-err")) Expect(platform.SetupSSHCalled).To(BeFalse()) }) Context("when public key is not empty", func() { BeforeEach(func() { settingsService.PublicKey = "fake-public-key" }) It("gets the public key and sets up ssh via the platform", func() { err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(platform.SetupSSHPublicKey).To(Equal("fake-public-key")) Expect(platform.SetupSSHUsername).To(Equal("vcap")) }) It("returns error if configuring ssh on the platform fails", func() { platform.SetupSSHErr = errors.New("fake-setup-ssh-err") err := bootstrap() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-setup-ssh-err")) }) }) Context("when public key key is empty", func() { BeforeEach(func() { settingsSource.PublicKey = "" }) It("gets the public key and does not setup SSH", func() { err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(platform.SetupSSHCalled).To(BeFalse()) }) }) }) It("sets up hostname", func() { settingsService.Settings.AgentID = "foo-bar-baz-123" err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(platform.SetupHostnameHostname).To(Equal("foo-bar-baz-123")) }) It("fetches initial settings", func() { err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(settingsService.SettingsWereLoaded).To(BeTrue()) }) It("returns error from loading initial settings", func() { settingsService.LoadSettingsError = errors.New("fake-load-error") err := bootstrap() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-load-error")) }) It("sets up networking", func() { networks := boshsettings.Networks{ "bosh": boshsettings.Network{}, } settingsService.Settings.Networks = networks err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(platform.SetupNetworkingNetworks).To(Equal(networks)) }) It("sets up ephemeral disk", func() { settingsService.Settings.Disks = boshsettings.Disks{ Ephemeral: "fake-ephemeral-disk-setting", } platform.GetEphemeralDiskPathRealPath = "/dev/sda" err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(platform.SetupEphemeralDiskWithPathDevicePath).To(Equal("/dev/sda")) Expect(platform.GetEphemeralDiskPathSettings).To(Equal(boshsettings.DiskSettings{ VolumeID: "fake-ephemeral-disk-setting", Path: "fake-ephemeral-disk-setting", })) }) It("returns error if setting ephemeral disk fails", func() { platform.SetupEphemeralDiskWithPathErr = errors.New("fake-setup-ephemeral-disk-err") err := bootstrap() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-setup-ephemeral-disk-err")) }) It("sets up data dir", func() { err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(platform.SetupDataDirCalled).To(BeTrue()) }) It("returns error if set up of data dir fails", func() { platform.SetupDataDirErr = errors.New("fake-setup-data-dir-err") err := bootstrap() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-setup-data-dir-err")) }) It("sets up tmp dir", func() { err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(platform.SetupTmpDirCalled).To(BeTrue()) }) It("returns error if set up of tmp dir fails", func() { platform.SetupTmpDirErr = errors.New("fake-setup-tmp-dir-err") err := bootstrap() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-setup-tmp-dir-err")) }) It("mounts persistent disk", func() { settingsService.Settings.Disks = boshsettings.Disks{ Persistent: map[string]interface{}{ "vol-123": map[string]interface{}{ "volume_id": "2", "path": "/dev/sdb", }, }, } err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(platform.MountPersistentDiskSettings).To(Equal(boshsettings.DiskSettings{ ID: "vol-123", VolumeID: "2", Path: "/dev/sdb", })) Expect(platform.MountPersistentDiskMountPoint).To(Equal(dirProvider.StoreDir())) }) It("errors if there is more than one persistent disk", func() { settingsService.Settings.Disks = boshsettings.Disks{ Persistent: map[string]interface{}{ "vol-123": "/dev/sdb", "vol-456": "/dev/sdc", }, } err := bootstrap() Expect(err).To(HaveOccurred()) }) It("does not try to mount when no persistent disk", func() { settingsService.Settings.Disks = boshsettings.Disks{ Persistent: map[string]interface{}{}, } err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(platform.MountPersistentDiskSettings).To(Equal(boshsettings.DiskSettings{})) Expect(platform.MountPersistentDiskMountPoint).To(Equal("")) }) It("sets root and vcap passwords", func() { settingsService.Settings.Env.Bosh.Password = "******" err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(2).To(Equal(len(platform.UserPasswords))) Expect("some-encrypted-password").To(Equal(platform.UserPasswords["root"])) Expect("some-encrypted-password").To(Equal(platform.UserPasswords["vcap"])) }) It("does not set password if not provided", func() { err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(0).To(Equal(len(platform.UserPasswords))) }) It("sets ntp", func() { settingsService.Settings.Ntp = []string{ "0.north-america.pool.ntp.org", "1.north-america.pool.ntp.org", } err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(2).To(Equal(len(platform.SetTimeWithNtpServersServers))) Expect("0.north-america.pool.ntp.org").To(Equal(platform.SetTimeWithNtpServersServers[0])) Expect("1.north-america.pool.ntp.org").To(Equal(platform.SetTimeWithNtpServersServers[1])) }) It("setups up monit user", func() { err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(platform.SetupMonitUserSetup).To(BeTrue()) }) It("starts monit", func() { err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(platform.StartMonitStarted).To(BeTrue()) }) }) Describe("Network setup exercised by Run", func() { var ( settingsJSON string fs *fakesys.FakeFileSystem platform boshplatform.Platform boot Bootstrap defaultNetworkResolver boshsettings.DefaultNetworkResolver logger boshlog.Logger dirProvider boshdirs.Provider ) writeNetworkDevice := func(iface string, macAddress string, isPhysical bool) string { interfacePath := fmt.Sprintf("/sys/class/net/%s", iface) fs.WriteFile(interfacePath, []byte{}) if isPhysical { fs.WriteFile(fmt.Sprintf("/sys/class/net/%s/device", iface), []byte{}) } fs.WriteFileString(fmt.Sprintf("/sys/class/net/%s/address", iface), fmt.Sprintf("%s\n", macAddress)) return interfacePath } stubInterfaces := func(interfaces [][]string) { var interfacePaths []string for _, iface := range interfaces { interfaceName := iface[0] interfaceMAC := iface[1] interfaceType := iface[2] isPhysical := interfaceType == "physical" interfacePaths = append(interfacePaths, writeNetworkDevice(interfaceName, interfaceMAC, isPhysical)) } fs.SetGlob("/sys/class/net/*", interfacePaths) } BeforeEach(func() { fs = fakesys.NewFakeFileSystem() runner := fakesys.NewFakeCmdRunner() dirProvider = boshdirs.NewProvider("/var/vcap/bosh") linuxOptions := boshplatform.LinuxOptions{ CreatePartitionIfNoEphemeralDisk: true, } logger = boshlog.NewLogger(boshlog.LevelNone) diskManager := fakedisk.NewFakeDiskManager() diskManager.FakeMountsSearcher.SearchMountsMounts = []boshdisk.Mount{ {MountPoint: "/", PartitionPath: "rootfs"}, {MountPoint: "/", PartitionPath: "/dev/vda1"}, } runner.AddCmdResult( "readlink -f /dev/vda1", fakesys.FakeCmdResult{Stdout: "/dev/vda1"}, ) diskManager.FakeRootDevicePartitioner.GetDeviceSizeInBytesSizes["/dev/vda"] = 1024 * 1024 * 1024 udev := boshudev.NewConcreteUdevDevice(runner, logger) linuxCdrom := boshcdrom.NewLinuxCdrom("/dev/sr0", udev, runner) linuxCdutil := boshcdrom.NewCdUtil(dirProvider.SettingsDir(), fs, linuxCdrom, logger) compressor := boshcmd.NewTarballCompressor(runner, fs) copier := boshcmd.NewCpCopier(runner, fs, logger) sigarCollector := boshsigar.NewSigarStatsCollector(&sigar.ConcreteSigar{}) vitalsService := boshvitals.NewService(sigarCollector, dirProvider) ipResolver := boship.NewResolver(boship.NetworkInterfaceToAddrsFunc) arping := bosharp.NewArping(runner, fs, logger, boshplatform.ArpIterations, boshplatform.ArpIterationDelay, boshplatform.ArpInterfaceCheckDelay) interfaceConfigurationCreator := boshnet.NewInterfaceConfigurationCreator(logger) ubuntuNetManager := boshnet.NewUbuntuNetManager(fs, runner, ipResolver, interfaceConfigurationCreator, arping, logger) ubuntuCertManager := boshcert.NewUbuntuCertManager(fs, runner, logger) monitRetryable := boshplatform.NewMonitRetryable(runner) monitRetryStrategy := boshretry.NewAttemptRetryStrategy(10, 1*time.Second, monitRetryable, logger) devicePathResolver := devicepathresolver.NewIdentityDevicePathResolver() routesSearcher := boshnet.NewCmdRoutesSearcher(runner) defaultNetworkResolver = boshnet.NewDefaultNetworkResolver(routesSearcher, ipResolver) platform = boshplatform.NewLinuxPlatform( fs, runner, sigarCollector, compressor, copier, dirProvider, vitalsService, linuxCdutil, diskManager, ubuntuNetManager, ubuntuCertManager, monitRetryStrategy, devicePathResolver, 500*time.Millisecond, linuxOptions, logger, defaultNetworkResolver, ) }) JustBeforeEach(func() { settingsPath := filepath.Join("bosh", "settings.json") var settings boshsettings.Settings json.Unmarshal([]byte(settingsJSON), &settings) settingsSource := fakeinf.FakeSettingsSource{ PublicKey: "123", SettingsValue: settings, } settingsService := boshsettings.NewService( platform.GetFs(), settingsPath, settingsSource, platform, logger, ) boot = NewBootstrap( platform, dirProvider, settingsService, logger, ) }) Context("when a single network configuration is provided, with a MAC address", func() { BeforeEach(func() { settingsJSON = `{ "networks": { "netA": { "default": ["dns", "gateway"], "ip": "2.2.2.2", "dns": [ "8.8.8.8", "4.4.4.4" ], "netmask": "255.255.255.0", "gateway": "2.2.2.0", "mac": "aa:bb:cc" } } }` }) Context("and no physical network interfaces exist", func() { Context("and a single virtual network interface exists", func() { BeforeEach(func() { stubInterfaces([][]string{[]string{"lo", "aa:bb:cc", "virtual"}}) }) It("raises an error", func() { err := boot.Run() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Number of network settings '1' is greater than the number of network devices '0")) }) }) }) Context("and a single physical network interface exists", func() { BeforeEach(func() { stubInterfaces([][]string{[]string{"eth0", "aa:bb:cc", "physical"}}) }) It("succeeds", func() { err := boot.Run() Expect(err).NotTo(HaveOccurred()) }) }) Context("and extra physical network interfaces exist", func() { BeforeEach(func() { stubInterfaces([][]string{[]string{"eth0", "aa:bb:cc", "physical"}, []string{"eth1", "aa:bb:dd", "physical"}}) }) It("succeeds", func() { err := boot.Run() Expect(err).NotTo(HaveOccurred()) }) }) Context("and extra virtual network interfaces exist", func() { BeforeEach(func() { stubInterfaces([][]string{[]string{"eth0", "aa:bb:cc", "physical"}, []string{"lo", "aa:bb:ee", "virtual"}}) }) It("succeeds", func() { err := boot.Run() Expect(err).ToNot(HaveOccurred()) }) }) }) Context("when a single network configuration is provided, without a MAC address", func() { BeforeEach(func() { settingsJSON = `{ "networks": { "netA": { "default": ["dns", "gateway"], "ip": "2.2.2.2", "dns": [ "8.8.8.8", "4.4.4.4" ], "netmask": "255.255.255.0", "gateway": "2.2.2.0" } } }` }) Context("and no physical network interfaces exist", func() { Context("and a single virtual network interface exists", func() { BeforeEach(func() { stubInterfaces([][]string{[]string{"lo", "aa:bb:cc", "virtual"}}) }) It("raises an error", func() { err := boot.Run() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Number of network settings '1' is greater than the number of network devices '0")) }) }) }) Context("and a single physical network interface exists", func() { BeforeEach(func() { stubInterfaces([][]string{[]string{"eth0", "aa:bb:cc", "physical"}}) }) It("succeeds", func() { err := boot.Run() Expect(err).NotTo(HaveOccurred()) }) }) Context("and extra physical network interfaces exist", func() { BeforeEach(func() { stubInterfaces([][]string{[]string{"eth0", "aa:bb:cc", "physical"}, []string{"eth1", "aa:bb:dd", "physical"}}) }) It("succeeds", func() { err := boot.Run() Expect(err).NotTo(HaveOccurred()) }) }) Context("and an extra virtual network interface exists", func() { BeforeEach(func() { stubInterfaces([][]string{[]string{"eth0", "aa:bb:cc", "physical"}, []string{"lo", "aa:bb:dd", "virtual"}}) }) It("succeeds", func() { err := boot.Run() Expect(err).NotTo(HaveOccurred()) }) }) }) Context("when two network configurations are provided", func() { BeforeEach(func() { settingsJSON = `{ "networks": { "netA": { "default": ["dns", "gateway"], "ip": "2.2.2.2", "dns": [ "8.8.8.8", "4.4.4.4" ], "netmask": "255.255.255.0", "gateway": "2.2.2.0", "mac": "aa:bb:cc" }, "netB": { "default": ["dns", "gateway"], "ip": "3.3.3.3", "dns": [ "8.8.8.8", "4.4.4.4" ], "netmask": "255.255.255.0", "gateway": "3.3.3.0", "mac": "" } } }` }) Context("and a single physical network interface exists", func() { BeforeEach(func() { stubInterfaces([][]string{[]string{"eth0", "aa:bb:cc", "physical"}}) }) It("raises an error", func() { err := boot.Run() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Number of network settings '2' is greater than the number of network devices '1")) }) }) Context("and two physical network interfaces with matching MAC addresses exist", func() { BeforeEach(func() { stubInterfaces([][]string{[]string{"eth0", "aa:bb:cc", "physical"}, []string{"eth1", "aa:bb:dd", "physical"}}) }) It("succeeds", func() { err := boot.Run() Expect(err).ToNot(HaveOccurred()) }) }) }) }) }) }
. "github.com/cloudfoundry/bosh-agent/internal/github.com/cloudfoundry/bosh-utils/logger/file" boshlog "github.com/cloudfoundry/bosh-agent/internal/github.com/cloudfoundry/bosh-utils/logger" boshsys "github.com/cloudfoundry/bosh-agent/internal/github.com/cloudfoundry/bosh-utils/system" fakeboshsys "github.com/cloudfoundry/bosh-agent/internal/github.com/cloudfoundry/bosh-utils/system/fakes" ) func expectedLogFormat(tag, msg string) string { return fmt.Sprintf("\\[%s\\] [0-9]{4}/[0-9]{2}/[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2} %s\n", tag, msg) } var _ = Describe("NewFileLogger", func() { var ( fs *fakeboshsys.FakeFileSystem logFile boshsys.File ) BeforeEach(func() { fs = fakeboshsys.NewFakeFileSystem() var err error logFile, err = fs.TempFile("file-logger-test") Expect(err).ToNot(HaveOccurred()) err = logFile.Close() Expect(err).ToNot(HaveOccurred()) }) AfterEach(func() { logFile.Close() fs.RemoveAll(logFile.Name()) })