func NewWindowsPlatform( collector boshstats.Collector, fs boshsys.FileSystem, cmdRunner boshsys.CmdRunner, dirProvider boshdirs.Provider, netManager boshnet.Manager, certManager boshcert.Manager, devicePathResolver boshdpresolv.DevicePathResolver, logger boshlog.Logger, defaultNetworkResolver boshsettings.DefaultNetworkResolver, ) Platform { return &WindowsPlatform{ fs: fs, cmdRunner: cmdRunner, collector: collector, compressor: boshcmd.NewTarballCompressor(cmdRunner, fs), copier: boshcmd.NewGenericCpCopier(fs, logger), dirProvider: dirProvider, netManager: netManager, devicePathResolver: devicePathResolver, vitalsService: boshvitals.NewService(collector, dirProvider), certManager: certManager, defaultNetworkResolver: defaultNetworkResolver, } }
func NewDummyPlatform( collector boshstats.Collector, fs boshsys.FileSystem, cmdRunner boshsys.CmdRunner, dirProvider boshdirs.Provider, devicePathResolver boshdpresolv.DevicePathResolver, logger boshlog.Logger, ) Platform { return &dummyPlatform{ fs: fs, cmdRunner: cmdRunner, collector: collector, compressor: boshcmd.NewTarballCompressor(cmdRunner, fs), copier: boshcmd.NewGenericCpCopier(fs, logger), dirProvider: dirProvider, devicePathResolver: devicePathResolver, vitalsService: boshvitals.NewService(collector, dirProvider), certManager: boshcert.NewDummyCertManager(fs, cmdRunner, 0, logger), logger: logger, } }
func NewProvider(logger boshlog.Logger, dirProvider boshdirs.Provider, statsCollector boshstats.Collector, fs boshsys.FileSystem, options Options, bootstrapState *BootstrapState, clock clock.Clock) Provider { runner := boshsys.NewExecCmdRunner(logger) linuxDiskManager := boshdisk.NewLinuxDiskManager(logger, runner, fs, options.Linux.BindMountPersistentDisk) 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.NewGenericCpCopier(fs, logger) // Kick of stats collection as soon as possible statsCollector.StartCollecting(SigarStatsCollectionInterval, nil) vitalsService := boshvitals.NewService(statsCollector, dirProvider) ipResolver := boship.NewResolver(boship.NetworkInterfaceToAddrsFunc) arping := bosharp.NewArping(runner, fs, logger, ArpIterations, ArpIterationDelay, ArpInterfaceCheckDelay) interfaceConfigurationCreator := boshnet.NewInterfaceConfigurationCreator(logger) interfaceAddressesProvider := boship.NewSystemInterfaceAddressesProvider() interfaceAddressesValidator := boship.NewInterfaceAddressesValidator(interfaceAddressesProvider) dnsValidator := boshnet.NewDNSValidator(fs) centosNetManager := boshnet.NewCentosNetManager(fs, runner, ipResolver, interfaceConfigurationCreator, interfaceAddressesValidator, dnsValidator, arping, logger) ubuntuNetManager := boshnet.NewUbuntuNetManager(fs, runner, ipResolver, interfaceConfigurationCreator, interfaceAddressesValidator, dnsValidator, arping, logger) windowsNetManager := boshnet.NewWindowsNetManager(runner, interfaceConfigurationCreator, boshnet.NewMACAddressDetector(), logger, clock) centosCertManager := boshcert.NewCentOSCertManager(fs, runner, 0, logger) ubuntuCertManager := boshcert.NewUbuntuCertManager(fs, runner, 60, logger) windowsCertManager := boshcert.NewWindowsCertManager(fs, runner, dirProvider, logger) routesSearcher := boshnet.NewRoutesSearcher(runner) defaultNetworkResolver := boshnet.NewDefaultNetworkResolver(routesSearcher, ipResolver) monitRetryable := NewMonitRetryable(runner) monitRetryStrategy := boshretry.NewAttemptRetryStrategy(10, 1*time.Second, monitRetryable, logger) var devicePathResolver devicepathresolver.DevicePathResolver switch options.Linux.DevicePathResolutionType { case "virtio": udev := boshudev.NewConcreteUdevDevice(runner, logger) idDevicePathResolver := devicepathresolver.NewIDDevicePathResolver(500*time.Millisecond, udev, fs) mappedDevicePathResolver := devicepathresolver.NewMappedDevicePathResolver(30000*time.Millisecond, fs) devicePathResolver = devicepathresolver.NewVirtioDevicePathResolver(idDevicePathResolver, mappedDevicePathResolver, logger) case "scsi": scsiIDPathResolver := devicepathresolver.NewSCSIIDDevicePathResolver(50000*time.Millisecond, fs, logger) scsiVolumeIDPathResolver := devicepathresolver.NewSCSIVolumeIDDevicePathResolver(500*time.Millisecond, fs) scsiLunPathResolver := devicepathresolver.NewSCSILunDevicePathResolver(50000*time.Millisecond, fs, logger) devicePathResolver = devicepathresolver.NewScsiDevicePathResolver(scsiVolumeIDPathResolver, scsiIDPathResolver, scsiLunPathResolver) default: devicePathResolver = devicepathresolver.NewIdentityDevicePathResolver() } uuidGenerator := boshuuid.NewGenerator() centos := NewLinuxPlatform( fs, runner, statsCollector, compressor, copier, dirProvider, vitalsService, linuxCdutil, linuxDiskManager, centosNetManager, centosCertManager, monitRetryStrategy, devicePathResolver, bootstrapState, options.Linux, logger, defaultNetworkResolver, uuidGenerator, ) ubuntu := NewLinuxPlatform( fs, runner, statsCollector, compressor, copier, dirProvider, vitalsService, linuxCdutil, linuxDiskManager, ubuntuNetManager, ubuntuCertManager, monitRetryStrategy, devicePathResolver, bootstrapState, options.Linux, logger, defaultNetworkResolver, uuidGenerator, ) windows := NewWindowsPlatform( statsCollector, fs, runner, dirProvider, windowsNetManager, windowsCertManager, devicePathResolver, logger, defaultNetworkResolver, ) return provider{ platforms: map[string]Platform{ "ubuntu": ubuntu, "centos": centos, "dummy": NewDummyPlatform(statsCollector, fs, runner, dirProvider, devicePathResolver, logger), "windows": windows, }, } }
func init() { Describe("bootstrap", func() { Describe("Run", func() { var ( platform *fakeplatform.FakePlatform dirProvider boshdir.Provider settingsSource *fakeinf.FakeSettingsSource settingsService *fakesettings.FakeSettingsService updateSettings *boshsettings.UpdateSettings ) BeforeEach(func() { platform = fakeplatform.NewFakePlatform() dirProvider = boshdir.NewProvider("/var/vcap") settingsSource = &fakeinf.FakeSettingsSource{} settingsService = &fakesettings.FakeSettingsService{} updateSettings = &boshsettings.UpdateSettings{} }) 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(ConsistOf("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() { settingsService.PublicKey = "" }) It("gets the public key and does not setup SSH", func() { err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(platform.SetupSSHCalled).To(BeFalse()) }) }) Context("when the environment has authorized keys", func() { BeforeEach(func() { settingsService.Settings.Env.Bosh.AuthorizedKeys = []string{"fake-public-key", "another-fake-public-key"} settingsService.PublicKey = "" }) It("gets the public key and sets up SSH", func() { err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(platform.SetupSSHCalled).To(BeTrue()) Expect(platform.SetupSSHPublicKey).To(ConsistOf("fake-public-key", "another-fake-public-key")) Expect(platform.SetupSSHUsername).To(Equal("vcap")) }) }) Context("when both have authorized keys", func() { BeforeEach(func() { settingsService.Settings.Env.Bosh.AuthorizedKeys = []string{"another-fake-public-key"} settingsService.PublicKey = "fake-public-key" }) It("gets the public key and sets up SSH", func() { err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(platform.SetupSSHCalled).To(BeTrue()) Expect(platform.SetupSSHPublicKey).To(ConsistOf("fake-public-key", "another-fake-public-key")) Expect(platform.SetupSSHUsername).To(Equal("vcap")) }) }) }) 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")) }) Context("load settings errors", func() { BeforeEach(func() { settingsService.LoadSettingsError = errors.New("fake-load-error") settingsService.PublicKey = "fake-public-key" }) It("sets a ssh key despite settings error", func() { err := bootstrap() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-load-error")) Expect(platform.SetupSSHCalled).To(BeTrue()) }) }) It("sets up networking", func() { networks := boshsettings.Networks{ "bosh": boshsettings.Network{}, } settingsService.Settings.Networks = networks err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(platform.SetupNetworkingNetworks).To(Equal(networks)) }) It("sets up ephemeral disk", func() { settingsService.Settings.Disks = boshsettings.Disks{ Ephemeral: "fake-ephemeral-disk-setting", } platform.GetEphemeralDiskPathRealPath = "/dev/sda" err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(platform.SetupEphemeralDiskWithPathDevicePath).To(Equal("/dev/sda")) Expect(platform.GetEphemeralDiskPathSettings).To(Equal(boshsettings.DiskSettings{ VolumeID: "fake-ephemeral-disk-setting", Path: "fake-ephemeral-disk-setting", })) }) It("returns error if setting ephemeral disk fails", func() { platform.SetupEphemeralDiskWithPathErr = errors.New("fake-setup-ephemeral-disk-err") err := bootstrap() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-setup-ephemeral-disk-err")) }) It("sets up raw ephemeral disks if paths exist", func() { settingsService.Settings.Disks = boshsettings.Disks{ RawEphemeral: []boshsettings.DiskSettings{{Path: "/dev/xvdb"}, {Path: "/dev/xvdc"}}, } err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(platform.SetupRawEphemeralDisksCallCount).To(Equal(1)) Expect(len(platform.SetupRawEphemeralDisksDevices)).To(Equal(2)) Expect(platform.SetupRawEphemeralDisksDevices[0].Path).To(Equal("/dev/xvdb")) Expect(platform.SetupRawEphemeralDisksDevices[1].Path).To(Equal("/dev/xvdc")) }) It("returns error if setting raw ephemeral disks fails", func() { platform.SetupRawEphemeralDisksErr = errors.New("fake-setup-raw-ephemeral-disks-err") err := bootstrap() Expect(platform.SetupRawEphemeralDisksCallCount).To(Equal(1)) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-setup-raw-ephemeral-disks-err")) }) It("sets up data dir", func() { err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(platform.SetupDataDirCalled).To(BeTrue()) }) It("returns error if set up of data dir fails", func() { platform.SetupDataDirErr = errors.New("fake-setup-data-dir-err") err := bootstrap() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-setup-data-dir-err")) }) It("sets up tmp dir", func() { err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(platform.SetupTmpDirCalled).To(BeTrue()) }) It("sets up /home dir", func() { err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(platform.SetupHomeDirCalled).To(BeTrue()) }) It("sets up log dir", func() { err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(platform.SetupLogDirCalled).To(BeTrue()) }) It("sets up logging and auditing services", func() { err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(platform.SetupLoggingAndAuditingCalled).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("grows the root filesystem", func() { err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(platform.SetupRootDiskCalledTimes).To(Equal(1)) }) It("returns an error if growing the root filesystem fails", func() { platform.SetupRootDiskError = errors.New("growfs failed") err := bootstrap() Expect(err).To(HaveOccurred()) Expect(platform.SetupRootDiskCalledTimes).To(Equal(1)) Expect(err.Error()).To(ContainSubstring("growfs failed")) }) It("sets root and vcap passwords", func() { settingsService.Settings.Env.Bosh.Password = "******" settingsService.Settings.Env.Bosh.KeepRootPassword = false err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(2).To(Equal(len(platform.UserPasswords))) Expect("some-encrypted-password").To(Equal(platform.UserPasswords["root"])) Expect("some-encrypted-password").To(Equal(platform.UserPasswords["vcap"])) }) It("does not change root password if keep_root_password is set to true", func() { settingsService.Settings.Env.Bosh.Password = "******" settingsService.Settings.Env.Bosh.KeepRootPassword = true err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(1).To(Equal(len(platform.UserPasswords))) Expect("some-encrypted-password").ToNot(Equal(platform.UserPasswords["root"])) Expect("some-encrypted-password").To(Equal(platform.UserPasswords["vcap"])) }) It("does not set password if not provided", func() { settingsService.Settings.Env.Bosh.KeepRootPassword = false err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(0).To(Equal(len(platform.UserPasswords))) }) It("sets ntp", func() { settingsService.Settings.Ntp = []string{ "0.north-america.pool.ntp.org", "1.north-america.pool.ntp.org", } err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(2).To(Equal(len(platform.SetTimeWithNtpServersServers))) Expect("0.north-america.pool.ntp.org").To(Equal(platform.SetTimeWithNtpServersServers[0])) Expect("1.north-america.pool.ntp.org").To(Equal(platform.SetTimeWithNtpServersServers[1])) }) It("setups up monit user", func() { err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(platform.SetupMonitUserSetup).To(BeTrue()) }) It("starts monit", func() { err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(platform.StartMonitStarted).To(BeTrue()) }) Describe("RemoveDevTools", func() { It("removes development tools if settings.env.bosh.remove_dev_tools is true", func() { settingsService.Settings.Env.Bosh.RemoveDevTools = true platform.GetFs().WriteFileString(path.Join(dirProvider.EtcDir(), "dev_tools_file_list"), "/usr/bin/gfortran") err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(platform.IsRemoveDevToolsCalled).To(BeTrue()) Expect(platform.PackageFileListPath).To(Equal(path.Join(dirProvider.EtcDir(), "dev_tools_file_list"))) }) It("does NOTHING if settings.env.bosh.remove_dev_tools is NOT set", func() { err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(platform.IsRemoveDevToolsCalled).To(BeFalse()) }) It("does NOTHING if if settings.env.bosh.remove_dev_tools is true AND dev_tools_file_list does NOT exist", func() { settingsService.Settings.Env.Bosh.RemoveDevTools = true err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(platform.IsRemoveDevToolsCalled).To(BeFalse()) }) }) Describe("checking persistent disks", func() { Context("managed persistent disk", func() { BeforeEach(func() { updateSettings := boshsettings.UpdateSettings{} updateSettingsBytes, err := json.Marshal(updateSettings) Expect(err).ToNot(HaveOccurred()) updateSettingsPath := filepath.Join(platform.GetDirProvider().BoshDir(), "update_settings.json") platform.Fs.WriteFile(updateSettingsPath, updateSettingsBytes) }) It("succesfully bootstraps", func() { err := bootstrap() Expect(err).ToNot(HaveOccurred()) }) Context("there is a single managed persistent disk attached", func() { BeforeEach(func() { settingsService.Settings.Disks = boshsettings.Disks{ Persistent: map[string]interface{}{ "vol-123": "/dev/sdb", }, } }) It("succesfully bootstraps", func() { err := bootstrap() Expect(err).ToNot(HaveOccurred()) }) }) Context("there are multiple managed persistent disk attached", func() { BeforeEach(func() { settingsService.Settings.Disks = boshsettings.Disks{ Persistent: map[string]interface{}{ "vol-123": "/dev/sdb", "vol-456": "/dev/sdc", }, } }) It("returns an error", func() { err := bootstrap() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Unexpected disk attached")) }) }) Context("last mount information is present", func() { var managedDiskSettingsPath string BeforeEach(func() { diskCid := "i-am-a-disk-cid" managedDiskSettingsPath = filepath.Join(platform.GetDirProvider().BoshDir(), "managed_disk_settings.json") platform.Fs.WriteFile(managedDiskSettingsPath, []byte(diskCid)) settingsService.Settings.Disks = boshsettings.Disks{ Persistent: map[string]interface{}{ "i-am-a-disk-cid": "/dev/sdb", }, } }) It("successfully bootstraps", func() { err := bootstrap() Expect(err).ToNot(HaveOccurred()) }) Context("when the last mount information cannot be read", func() { It("returns an error", func() { platform.Fs.RegisterReadFileError(managedDiskSettingsPath, errors.New("Oh noes!")) err := bootstrap() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Reading managed_disk_settings.json")) }) }) Context("attached disk's CID differs from last mounted CID", func() { BeforeEach(func() { diskCid := "i-am-a-different-cid" platform.Fs.WriteFile(managedDiskSettingsPath, []byte(diskCid)) }) It("returns an error", func() { err := bootstrap() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Attached disk disagrees with previous mount")) }) }) Context("when there are no attached disks", func() { BeforeEach(func() { settingsService.Settings.Disks = boshsettings.Disks{} }) It("successfully bootstraps", func() { err := bootstrap() Expect(err).ToNot(HaveOccurred()) }) }) }) }) Context("unmanaged persistent disk", func() { BeforeEach(func() { updateSettings := boshsettings.UpdateSettings{ DiskAssociations: []boshsettings.DiskAssociation{ boshsettings.DiskAssociation{ Name: "test-disk", DiskCID: "vol-123", }, boshsettings.DiskAssociation{ Name: "test-disk-2", DiskCID: "vol-456", }, }, } updateSettingsBytes, err := json.Marshal(updateSettings) Expect(err).ToNot(HaveOccurred()) updateSettingsPath := filepath.Join(platform.GetDirProvider().BoshDir(), "update_settings.json") platform.Fs.WriteFile(updateSettingsPath, updateSettingsBytes) settingsService.Settings.Disks = boshsettings.Disks{ Persistent: map[string]interface{}{ "vol-123": "/dev/sdb", "vol-456": "/dev/sdc", }, } }) It("succesfully bootstraps", func() { err := bootstrap() Expect(err).ToNot(HaveOccurred()) }) Context("a disk is not attached that should be", func() { BeforeEach(func() { settingsService.Settings.Disks = boshsettings.Disks{} }) It("returns an error", func() { err := bootstrap() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Disk vol-123 is not attached")) }) }) Context("A disk is attached that shouldn't be", func() { BeforeEach(func() { settingsService.Settings.Disks = boshsettings.Disks{ Persistent: map[string]interface{}{ "vol-123": "/dev/sdb", "vol-456": "/dev/sdc", "vol-789": "/dev/sdd", }, } }) It("returns an error", func() { err := bootstrap() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Unexpected disk attached")) }) }) }) Context("update_settings.json does not exist", func() { Context("there are multiple disks in the registry for this instance", func() { BeforeEach(func() { settingsService.Settings.Disks = boshsettings.Disks{ Persistent: map[string]interface{}{ "vol-123": "/dev/sdb", "vol-456": "/dev/sdc", }, } }) It("returns error", func() { err := bootstrap() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Unexpected disk attached")) }) }) Context("there are no disks in the registry for this instance", func() { It("succesfully bootstraps", func() { err := bootstrap() Expect(err).ToNot(HaveOccurred()) }) }) }) Context("when update_settings.json exists but cannot be read", func() { BeforeEach(func() { updateSettingsPath := filepath.Join(platform.GetDirProvider().BoshDir(), "update_settings.json") platform.Fs.WriteFile(updateSettingsPath, []byte(`{"persistent_disks":{"invalid":true`)) }) It("returns error", func() { platform.Fs.ReadFileError = errors.New("Oh noes!") err := bootstrap() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Reading update_settings.json")) }) }) Context("when unmarshalling update_settings fails", func() { BeforeEach(func() { updateSettingsPath := filepath.Join(platform.GetDirProvider().BoshDir(), "update_settings.json") platform.Fs.WriteFile(updateSettingsPath, []byte(`{"persistent_disks":{"invalid":true`)) }) It("returns wrapped error", func() { err := bootstrap() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Unmarshalling update_settings.json")) }) }) }) Describe("Mount persistent disk", func() { Context("when there is no persistent disk", func() { It("does not try to mount ", 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("")) }) }) Context("when there is no drive specified by settings", func() { It("returns error", func() { settingsService.Settings.Disks = boshsettings.Disks{ Persistent: map[string]interface{}{ "vol-123": "/dev/not-exists", }, } platform.SetIsPersistentDiskMountable(false, errors.New("Drive not exist!")) err := bootstrap() Expect(err).To(HaveOccurred()) Expect(platform.MountPersistentDiskSettings).To(Equal(boshsettings.DiskSettings{})) Expect(platform.MountPersistentDiskMountPoint).To(Equal("")) }) }) Context("when there is no partition on drive specified by settings", func() { BeforeEach(func() { updateSettings := boshsettings.UpdateSettings{} updateSettingsBytes, err := json.Marshal(updateSettings) Expect(err).ToNot(HaveOccurred()) updateSettingsPath := filepath.Join(platform.GetDirProvider().BoshDir(), "update_settings.json") platform.Fs.WriteFile(updateSettingsPath, updateSettingsBytes) }) It("does not try to mount ", func() { settingsService.Settings.Disks = boshsettings.Disks{ Persistent: map[string]interface{}{ "vol-123": "/dev/valid", }, } platform.SetIsPersistentDiskMountable(false, nil) err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(platform.MountPersistentDiskSettings).To(Equal(boshsettings.DiskSettings{})) Expect(platform.MountPersistentDiskMountPoint).To(Equal("")) }) }) Context("when specified disk has partition", func() { BeforeEach(func() { updateSettings := boshsettings.UpdateSettings{} updateSettingsBytes, err := json.Marshal(updateSettings) Expect(err).ToNot(HaveOccurred()) updateSettingsPath := filepath.Join(platform.GetDirProvider().BoshDir(), "update_settings.json") platform.Fs.WriteFile(updateSettingsPath, updateSettingsBytes) settingsService.Settings.Disks = boshsettings.Disks{ Persistent: map[string]interface{}{ "vol-123": map[string]interface{}{ "volume_id": "2", "path": "/dev/sdb", }, }, } }) It("does not mount the disk", func() { platform.SetIsPersistentDiskMountable(true, nil) err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(platform.MountPersistentDiskSettings).To(Equal(boshsettings.DiskSettings{})) Expect(platform.MountPersistentDiskMountPoint).To(Equal("")) }) Context("when last mounted cid information is present", func() { BeforeEach(func() { diskCid := "vol-123" managedDiskSettingsPath := filepath.Join(platform.GetDirProvider().BoshDir(), "managed_disk_settings.json") platform.Fs.WriteFile(managedDiskSettingsPath, []byte(diskCid)) }) It("mounts persistent disk", func() { platform.SetIsPersistentDiskMountable(true, nil) 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())) }) }) }) }) }) Describe("Network setup exercised by Run", func() { var ( settingsJSON string fs *fakesys.FakeFileSystem platform boshplatform.Platform boot Bootstrap defaultNetworkResolver boshsettings.DefaultNetworkResolver logger boshlog.Logger dirProvider boshdirs.Provider interfaceAddrsProvider *fakeip.FakeInterfaceAddressesProvider ) writeNetworkDevice := func(iface string, macAddress string, isPhysical bool) string { interfacePath := fmt.Sprintf("/sys/class/net/%s", iface) fs.WriteFile(interfacePath, []byte{}) if isPhysical { fs.WriteFile(fmt.Sprintf("/sys/class/net/%s/device", iface), []byte{}) } fs.WriteFileString(fmt.Sprintf("/sys/class/net/%s/address", iface), fmt.Sprintf("%s\n", macAddress)) return interfacePath } stubInterfaces := func(interfaces [][]string) { var interfacePaths []string for _, iface := range interfaces { interfaceName := iface[0] interfaceMAC := iface[1] interfaceType := iface[2] isPhysical := interfaceType == "physical" interfacePaths = append(interfacePaths, writeNetworkDevice(interfaceName, interfaceMAC, isPhysical)) } fs.SetGlob("/sys/class/net/*", interfacePaths) } BeforeEach(func() { fs = fakesys.NewFakeFileSystem() runner := fakesys.NewFakeCmdRunner() dirProvider = boshdirs.NewProvider("/var/vcap/bosh") linuxOptions := boshplatform.LinuxOptions{ CreatePartitionIfNoEphemeralDisk: true, } logger = boshlog.NewLogger(boshlog.LevelNone) diskManager := fakedisk.NewFakeDiskManager() diskManager.FakeMountsSearcher.SearchMountsMounts = []boshdisk.Mount{ {MountPoint: "/", PartitionPath: "rootfs"}, {MountPoint: "/", PartitionPath: "/dev/vda1"}, } // for the GrowRootFS call to findRootDevicePath runner.AddCmdResult( "readlink -f /dev/vda1", fakesys.FakeCmdResult{Stdout: "/dev/vda1"}, ) // for the createEphemeralPartitionsOnRootDevice call to findRootDevicePath runner.AddCmdResult( "readlink -f /dev/vda1", fakesys.FakeCmdResult{Stdout: "/dev/vda1"}, ) diskManager.FakeRootDevicePartitioner.GetDeviceSizeInBytesSizes["/dev/vda"] = 1024 * 1024 * 1024 udev := boshudev.NewConcreteUdevDevice(runner, logger) linuxCdrom := boshcdrom.NewLinuxCdrom("/dev/sr0", udev, runner) linuxCdutil := boshcdrom.NewCdUtil(dirProvider.SettingsDir(), fs, linuxCdrom, logger) compressor := boshcmd.NewTarballCompressor(runner, fs) copier := boshcmd.NewGenericCpCopier(fs, logger) sigarCollector := boshsigar.NewSigarStatsCollector(&sigar.ConcreteSigar{}) vitalsService := boshvitals.NewService(sigarCollector, dirProvider) ipResolver := boship.NewResolver(boship.NetworkInterfaceToAddrsFunc) arping := bosharp.NewArping(runner, fs, logger, boshplatform.ArpIterations, boshplatform.ArpIterationDelay, boshplatform.ArpInterfaceCheckDelay) interfaceConfigurationCreator := boshnet.NewInterfaceConfigurationCreator(logger) interfaceAddrsProvider = &fakeip.FakeInterfaceAddressesProvider{} interfaceAddressesValidator := boship.NewInterfaceAddressesValidator(interfaceAddrsProvider) dnsValidator := boshnet.NewDNSValidator(fs) fs.WriteFileString("/etc/resolv.conf", "8.8.8.8 4.4.4.4") ubuntuNetManager := boshnet.NewUbuntuNetManager(fs, runner, ipResolver, interfaceConfigurationCreator, interfaceAddressesValidator, dnsValidator, arping, logger) ubuntuCertManager := boshcert.NewUbuntuCertManager(fs, runner, 1, logger) monitRetryable := boshplatform.NewMonitRetryable(runner) monitRetryStrategy := boshretry.NewAttemptRetryStrategy(10, 1*time.Second, monitRetryable, logger) devicePathResolver := devicepathresolver.NewIdentityDevicePathResolver() fakeUUIDGenerator := boshuuid.NewGenerator() routesSearcher := boshnet.NewRoutesSearcher(runner) defaultNetworkResolver = boshnet.NewDefaultNetworkResolver(routesSearcher, ipResolver) state, err := boshplatform.NewBootstrapState(fs, "/tmp/agent_state.json") Expect(err).NotTo(HaveOccurred()) platform = boshplatform.NewLinuxPlatform( fs, runner, sigarCollector, compressor, copier, dirProvider, vitalsService, linuxCdutil, diskManager, ubuntuNetManager, ubuntuCertManager, monitRetryStrategy, devicePathResolver, state, linuxOptions, logger, defaultNetworkResolver, fakeUUIDGenerator, ) }) JustBeforeEach(func() { settingsPath := filepath.Join("bosh", "settings.json") var settings boshsettings.Settings json.Unmarshal([]byte(settingsJSON), &settings) settingsSource := fakeinf.FakeSettingsSource{ PublicKey: "123", SettingsValue: settings, } settingsService := boshsettings.NewService( platform.GetFs(), settingsPath, settingsSource, platform, logger, ) boot = NewBootstrap( platform, dirProvider, settingsService, logger, ) }) Context("when a single network configuration is provided, with a MAC address", func() { BeforeEach(func() { settingsJSON = `{ "networks": { "netA": { "default": ["dns", "gateway"], "ip": "2.2.2.2", "dns": [ "8.8.8.8", "4.4.4.4" ], "netmask": "255.255.255.0", "gateway": "2.2.2.0", "mac": "aa:bb:cc" } } }` }) Context("and no physical network interfaces exist", func() { Context("and a single virtual network interface exists", func() { BeforeEach(func() { stubInterfaces([][]string{[]string{"lo", "aa:bb:cc", "virtual"}}) }) It("raises an error", func() { err := boot.Run() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Number of network settings '1' is greater than the number of network devices '0")) }) }) }) Context("and a single physical network interface exists", func() { BeforeEach(func() { stubInterfaces([][]string{[]string{"eth0", "aa:bb:cc", "physical"}}) interfaceAddrsProvider.GetInterfaceAddresses = []boship.InterfaceAddress{ boship.NewSimpleInterfaceAddress("eth0", "2.2.2.2"), } }) It("succeeds", func() { err := boot.Run() Expect(err).NotTo(HaveOccurred()) }) }) Context("and extra physical network interfaces exist", func() { BeforeEach(func() { stubInterfaces([][]string{[]string{"eth0", "aa:bb:cc", "physical"}, []string{"eth1", "aa:bb:dd", "physical"}}) interfaceAddrsProvider.GetInterfaceAddresses = []boship.InterfaceAddress{ boship.NewSimpleInterfaceAddress("eth0", "2.2.2.2"), } }) It("succeeds", func() { err := boot.Run() Expect(err).NotTo(HaveOccurred()) }) }) Context("and extra virtual network interfaces exist", func() { BeforeEach(func() { stubInterfaces([][]string{[]string{"eth0", "aa:bb:cc", "physical"}, []string{"lo", "aa:bb:ee", "virtual"}}) interfaceAddrsProvider.GetInterfaceAddresses = []boship.InterfaceAddress{ boship.NewSimpleInterfaceAddress("eth0", "2.2.2.2"), } }) It("succeeds", func() { err := boot.Run() Expect(err).ToNot(HaveOccurred()) }) }) }) Context("when a single network configuration is provided, without a MAC address", func() { BeforeEach(func() { settingsJSON = `{ "networks": { "netA": { "default": ["dns", "gateway"], "ip": "2.2.2.2", "dns": [ "8.8.8.8", "4.4.4.4" ], "netmask": "255.255.255.0", "gateway": "2.2.2.0" } } }` }) Context("and no physical network interfaces exist", func() { Context("and a single virtual network interface exists", func() { BeforeEach(func() { stubInterfaces([][]string{[]string{"lo", "aa:bb:cc", "virtual"}}) }) It("raises an error", func() { err := boot.Run() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Number of network settings '1' is greater than the number of network devices '0")) }) }) }) Context("and a single physical network interface exists", func() { BeforeEach(func() { stubInterfaces([][]string{[]string{"eth0", "aa:bb:cc", "physical"}}) interfaceAddrsProvider.GetInterfaceAddresses = []boship.InterfaceAddress{ boship.NewSimpleInterfaceAddress("eth0", "2.2.2.2"), } }) It("succeeds", func() { err := boot.Run() Expect(err).NotTo(HaveOccurred()) }) }) Context("and extra physical network interfaces exist", func() { BeforeEach(func() { stubInterfaces([][]string{[]string{"eth0", "aa:bb:cc", "physical"}, []string{"eth1", "aa:bb:dd", "physical"}}) interfaceAddrsProvider.GetInterfaceAddresses = []boship.InterfaceAddress{ boship.NewSimpleInterfaceAddress("eth0", "2.2.2.2"), } }) It("succeeds", func() { err := boot.Run() Expect(err).NotTo(HaveOccurred()) }) }) Context("and an extra virtual network interface exists", func() { BeforeEach(func() { stubInterfaces([][]string{[]string{"eth0", "aa:bb:cc", "physical"}, []string{"lo", "aa:bb:dd", "virtual"}}) interfaceAddrsProvider.GetInterfaceAddresses = []boship.InterfaceAddress{ boship.NewSimpleInterfaceAddress("eth0", "2.2.2.2"), } }) It("succeeds", func() { err := boot.Run() Expect(err).NotTo(HaveOccurred()) }) }) }) Context("when two network configurations are provided", func() { BeforeEach(func() { settingsJSON = `{ "networks": { "netA": { "default": ["dns", "gateway"], "ip": "2.2.2.2", "dns": [ "8.8.8.8", "4.4.4.4" ], "netmask": "255.255.255.0", "gateway": "2.2.2.0", "mac": "aa:bb:cc" }, "netB": { "default": ["dns", "gateway"], "ip": "3.3.3.3", "dns": [ "8.8.8.8", "4.4.4.4" ], "netmask": "255.255.255.0", "gateway": "3.3.3.0", "mac": "" } } }` }) Context("and a single physical network interface exists", func() { BeforeEach(func() { stubInterfaces([][]string{[]string{"eth0", "aa:bb:cc", "physical"}}) }) It("raises an error", func() { err := boot.Run() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Number of network settings '2' is greater than the number of network devices '1")) }) }) Context("and two physical network interfaces with matching MAC addresses exist", func() { BeforeEach(func() { stubInterfaces([][]string{[]string{"eth0", "aa:bb:cc", "physical"}, []string{"eth1", "aa:bb:dd", "physical"}}) interfaceAddrsProvider.GetInterfaceAddresses = []boship.InterfaceAddress{ boship.NewSimpleInterfaceAddress("eth0", "2.2.2.2"), boship.NewSimpleInterfaceAddress("eth1", "3.3.3.3"), } }) It("succeeds", func() { err := boot.Run() Expect(err).ToNot(HaveOccurred()) }) }) }) }) }) }