/dev/sda3 : start= xxxx, size= xxxx, Id=83 /dev/sda4 : start= 0, size= 0, Id= 0 ` const devSdaSfdiskDumpOnePartition = `# partition table of /dev/sda unit: sectors /dev/sda1 : start= 1, size= xxxx, Id=83 /dev/sda2 : start= xxxx, size= xxxx, Id=83 /dev/sda3 : start= 0, size= 0, Id= 0 /dev/sda4 : start= 0, size= 0, Id= 0 ` var _ = Describe("sfdiskPartitioner", func() { var ( runner *fakesys.FakeCmdRunner partitioner Partitioner ) BeforeEach(func() { runner = fakesys.NewFakeCmdRunner() logger := boshlog.NewLogger(boshlog.LevelNone) partitioner = NewSfdiskPartitioner(logger, runner) }) It("sfdisk partition", func() { runner.AddCmdResult("sfdisk -d /dev/sda", fakesys.FakeCmdResult{Stdout: devSdaSfdiskEmptyDump}) partitions := []Partition{ {Type: PartitionTypeSwap, SizeInBytes: 512 * 1024 * 1024}, {Type: PartitionTypeLinux, SizeInBytes: 1024 * 1024 * 1024},
import ( "errors" . "github.com/cloudfoundry/bosh-agent/internal/github.com/onsi/ginkgo" . "github.com/cloudfoundry/bosh-agent/internal/github.com/onsi/gomega" boshretry "github.com/cloudfoundry/bosh-agent/internal/github.com/cloudfoundry/bosh-utils/retrystrategy" fakesys "github.com/cloudfoundry/bosh-agent/internal/github.com/cloudfoundry/bosh-utils/system/fakes" . "github.com/cloudfoundry/bosh-agent/platform" ) var _ = Describe("MonitRetryable", func() { var ( cmdRunner *fakesys.FakeCmdRunner monitRetryable boshretry.Retryable ) BeforeEach(func() { cmdRunner = fakesys.NewFakeCmdRunner() monitRetryable = NewMonitRetryable(cmdRunner) }) Describe("Attempt", func() { Context("when starting monit fails", func() { BeforeEach(func() { cmdRunner.AddCmdResult("sv start monit", fakesys.FakeCmdResult{ ExitStatus: 255, Error: errors.New("fake-start-monit-error"), }) })
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" ) var _ = Describe("DigDNSResolver", func() { var ( resolver DigDNSResolver runner *fakesys.FakeCmdRunner ) BeforeEach(func() { logger := boshlog.NewLogger(boshlog.LevelNone) runner = fakesys.NewFakeCmdRunner() resolver = NewDigDNSResolver(runner, logger) }) Describe("LookupHost", func() { Context("when host is an ip", func() { It("lookup host with an ip", func() { ip, err := resolver.LookupHost([]string{"8.8.8.8"}, "74.125.239.101") Expect(err).ToNot(HaveOccurred()) Expect(runner.RunCommands).To(BeEmpty()) Expect(ip).To(Equal("74.125.239.101")) })
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 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("cmdMountsSeacher", func() { var ( runner *fakesys.FakeCmdRunner searcher MountsSearcher ) BeforeEach(func() { runner = fakesys.NewFakeCmdRunner() searcher = NewCmdMountsSearcher(runner) }) Describe("SearchMounts", func() { Context("when running command succeeds", func() { It("returns parsed mount information", func() { runner.AddCmdResult("mount", fakesys.FakeCmdResult{ Stdout: `devpts on /dev/pts type devpts (rw,noexec,nosuid,gid=5,mode=0620) tmpfs on /run type tmpfs (rw,noexec,nosuid,size=10%,mode=0755) /dev/sda1 on /boot type ext2 (rw) none on /tmp/warden/cgroup type tmpfs (rw)`,
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)) }) }) }
package net_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/net" ) var _ = Describe("cmdRoutesSeacher", func() { var ( runner *fakesys.FakeCmdRunner searcher RoutesSearcher ) BeforeEach(func() { runner = fakesys.NewFakeCmdRunner() searcher = NewCmdRoutesSearcher(runner) }) Describe("SearchRoutes", func() { Context("when running command succeeds", func() { It("returns parsed routes information", func() { runner.AddCmdResult("route -n", fakesys.FakeCmdResult{ Stdout: `Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface 172.16.79.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0 169.254.0.0 0.0.0.0 255.255.0.0 U 1002 0 0 eth0
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,
package blobstore_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/internal/github.com/cloudfoundry/bosh-utils/blobstore" 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" boshuuid "github.com/cloudfoundry/bosh-agent/internal/github.com/cloudfoundry/bosh-utils/uuid" ) var _ = Describe("Provider", func() { var ( fs *fakesys.FakeFileSystem runner *fakesys.FakeCmdRunner logger boshlog.Logger provider Provider ) BeforeEach(func() { fs = fakesys.NewFakeFileSystem() runner = fakesys.NewFakeCmdRunner() logger = boshlog.NewLogger(boshlog.LevelNone) provider = NewProvider(fs, runner, "/var/vcap/config", logger) }) Describe("Get", func() { It("get dummy", func() { blobstore, err := provider.Get(BlobstoreTypeDummy, map[string]interface{}{}) Expect(err).ToNot(HaveOccurred()) Expect(blobstore).ToNot(BeNil())
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{})) }) }) }) }
"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"}
package cdrom_test import ( "errors" fakesys "github.com/cloudfoundry/bosh-agent/internal/github.com/cloudfoundry/bosh-utils/system/fakes" . "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/platform/cdrom" fakeudev "github.com/cloudfoundry/bosh-agent/platform/udevdevice/fakes" ) var _ = Describe("LinuxCdrom", func() { var ( udev *fakeudev.FakeUdevDevice runner *fakesys.FakeCmdRunner cd Cdrom ) BeforeEach(func() { udev = fakeudev.NewFakeUdevDevice() runner = fakesys.NewFakeCmdRunner() }) JustBeforeEach(func() { cd = NewLinuxCdrom("/dev/sr0", udev, runner) }) Describe("WaitForMedia", func() { It("polls the cdrom to force udev to notice it", func() { err := cd.WaitForMedia()
. "github.com/cloudfoundry/bosh-agent/internal/github.com/onsi/ginkgo" . "github.com/cloudfoundry/bosh-agent/internal/github.com/onsi/gomega" fakeaction "github.com/cloudfoundry/bosh-agent/agent/action/fakes" "github.com/cloudfoundry/bosh-agent/agent/applier/applyspec" . "github.com/cloudfoundry/bosh-agent/agent/script/drain" "github.com/cloudfoundry/bosh-agent/agent/script/drain/fakes" 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("ConcreteScript", func() { var ( fs *fakesys.FakeFileSystem runner *fakesys.FakeCmdRunner params ScriptParams fakeClock *fakeaction.FakeClock script ConcreteScript exampleSpec func() applyspec.V1ApplySpec ) BeforeEach(func() { fs = fakesys.NewFakeFileSystem() runner = fakesys.NewFakeCmdRunner() params = &fakes.FakeScriptParams{} fakeClock = &fakeaction.FakeClock{} }) JustBeforeEach(func() { script = NewConcreteScript(fs, runner, "my-tag", "/fake/script", params, fakeClock) })
fakeFs.WriteFileString("/path/to/delete/stuff/in/delete_me_1.foo", "goodbye") fakeFs.WriteFileString("/path/to/delete/stuff/in/delete_me_2.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.bar", }) count, err := cert.DeleteFiles(fakeFs, "/path/to/delete/stuff/in/", "delete_me_") Expect(err).To(HaveOccurred()) Expect(count).To(Equal(0)) }) }) Describe("cert.Manager implementations", func() { var ( fakeFs *fakesys.FakeFileSystem fakeCmd *fakesys.FakeCmdRunner certManager cert.Manager ) SharedLinuxCertManagerExamples := func(certBasePath, certUpdateProgram string) { It("writes 1 cert to a file", func() { err := certManager.UpdateCertificates(cert1) Expect(err).NotTo(HaveOccurred()) Expect(fakeFs.FileExists(fmt.Sprintf("%s/bosh-trusted-cert-1.crt", certBasePath))).To(BeTrue()) }) It("writes each cert to its own file", func() { certs := fmt.Sprintf("%s\n%s\n", cert1, cert1) err := certManager.UpdateCertificates(certs) Expect(err).NotTo(HaveOccurred())
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", } })