It("returns an error if creation of parent directory fails", func() { fs.MkdirAllError = errors.New("fake-mkdir-error") _, _, err := fileBundle.Install(sourcePath) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-mkdir-error")) }) It("sets correct permissions on install path", func() { fs.Chmod(sourcePath, os.FileMode(0700)) _, _, err := fileBundle.Install(sourcePath) Expect(err).NotTo(HaveOccurred()) fileStats := fs.GetFileTestStat(installPath) Expect(fileStats).ToNot(BeNil()) Expect(fileStats.FileType).To(Equal(fakesys.FakeFileType(fakesys.FakeFileTypeDir))) Expect(fileStats.FileMode).To(Equal(os.FileMode(0755))) }) It("is idempotent", func() { actualFs, path, err := fileBundle.Install(sourcePath) Expect(err).NotTo(HaveOccurred()) Expect(actualFs).To(Equal(fs)) Expect(path).To(Equal(installPath)) otherSourcePath := createSourcePath() actualFs, path, err = fileBundle.Install(otherSourcePath) Expect(err).NotTo(HaveOccurred())
}) }) }) }) Describe("ChmodExecutables", func() { var ( binGlob string filePath string ) BeforeEach(func() { binGlob = "fake-glob/*" filePath = "fake-glob/file" fs.SetGlob("fake-glob/*", []string{filePath}) fs.WriteFileString(filePath, "content") }) It("fetches the files", func() { fileMode := fs.GetFileTestStat(filePath).FileMode Expect(fileMode).To(Equal(os.FileMode(0))) err := extractor.ChmodExecutables(binGlob) Expect(err).ToNot(HaveOccurred()) fileMode = fs.GetFileTestStat(filePath).FileMode Expect(fileMode).To(Equal(os.FileMode(0755))) }) }) })
func describeCentosNetManager() { var ( fs *fakesys.FakeFileSystem cmdRunner *fakesys.FakeCmdRunner ipResolver *fakeip.FakeResolver interfaceAddrsProvider *fakeip.FakeInterfaceAddressesProvider addressBroadcaster *fakearp.FakeAddressBroadcaster netManager Manager interfaceConfigurationCreator InterfaceConfigurationCreator ) BeforeEach(func() { fs = fakesys.NewFakeFileSystem() cmdRunner = fakesys.NewFakeCmdRunner() ipResolver = &fakeip.FakeResolver{} logger := boshlog.NewLogger(boshlog.LevelNone) interfaceConfigurationCreator = NewInterfaceConfigurationCreator(logger) interfaceAddrsProvider = &fakeip.FakeInterfaceAddressesProvider{} interfaceAddrsValidator := boship.NewInterfaceAddressesValidator(interfaceAddrsProvider) dnsValidator := NewDNSValidator(fs) addressBroadcaster = &fakearp.FakeAddressBroadcaster{} netManager = NewCentosNetManager( fs, cmdRunner, ipResolver, interfaceConfigurationCreator, interfaceAddrsValidator, dnsValidator, addressBroadcaster, logger, ) }) writeNetworkDevice := func(iface string, macAddress string, isPhysical bool) string { interfacePath := fmt.Sprintf("/sys/class/net/%s", iface) fs.WriteFile(interfacePath, []byte{}) if isPhysical { fs.WriteFile(fmt.Sprintf("/sys/class/net/%s/device", iface), []byte{}) } fs.WriteFileString(fmt.Sprintf("/sys/class/net/%s/address", iface), fmt.Sprintf("%s\n", macAddress)) return interfacePath } Describe("SetupNetworking", func() { var ( dhcpNetwork boshsettings.Network staticNetwork boshsettings.Network expectedNetworkConfigurationForStatic string expectedNetworkConfigurationForDHCP string expectedDhclientConfiguration string ) BeforeEach(func() { dhcpNetwork = boshsettings.Network{ Type: "dynamic", Default: []string{"dns"}, DNS: []string{"8.8.8.8", "9.9.9.9"}, Mac: "fake-dhcp-mac-address", } staticNetwork = boshsettings.Network{ Type: "manual", IP: "1.2.3.4", Netmask: "255.255.255.0", Gateway: "3.4.5.6", Mac: "fake-static-mac-address", } interfaceAddrsProvider.GetInterfaceAddresses = []boship.InterfaceAddress{ boship.NewSimpleInterfaceAddress("ethstatic", "1.2.3.4"), } fs.WriteFileString("/etc/resolv.conf", ` nameserver 8.8.8.8 nameserver 9.9.9.9 `) expectedNetworkConfigurationForStatic = `DEVICE=ethstatic BOOTPROTO=static IPADDR=1.2.3.4 NETMASK=255.255.255.0 BROADCAST=1.2.3.255 GATEWAY=3.4.5.6 ONBOOT=yes PEERDNS=no DNS1=8.8.8.8 DNS2=9.9.9.9 ` expectedNetworkConfigurationForDHCP = `DEVICE=ethdhcp BOOTPROTO=dhcp ONBOOT=yes PEERDNS=yes ` expectedDhclientConfiguration = `# Generated by bosh-agent option rfc3442-classless-static-routes code 121 = array of unsigned integer 8; send host-name "<hostname>"; request subnet-mask, broadcast-address, time-offset, routers, domain-name, domain-name-servers, domain-search, host-name, netbios-name-servers, netbios-scope, interface-mtu, rfc3442-classless-static-routes, ntp-servers; prepend domain-name-servers 8.8.8.8, 9.9.9.9; ` }) stubInterfacesWithVirtual := func(physicalInterfaces map[string]boshsettings.Network, virtualInterfaces []string) { interfacePaths := []string{} for iface, networkSettings := range physicalInterfaces { interfacePaths = append(interfacePaths, writeNetworkDevice(iface, networkSettings.Mac, true)) } for _, iface := range virtualInterfaces { interfacePaths = append(interfacePaths, writeNetworkDevice(iface, "virtual", false)) } fs.SetGlob("/sys/class/net/*", interfacePaths) } stubInterfaces := func(physicalInterfaces map[string]boshsettings.Network) { stubInterfacesWithVirtual(physicalInterfaces, nil) } It("writes a network script for static and dynamic interfaces", func() { stubInterfaces(map[string]boshsettings.Network{ "ethdhcp": dhcpNetwork, "ethstatic": staticNetwork, }) err := netManager.SetupNetworking(boshsettings.Networks{"dhcp-network": dhcpNetwork, "static-network": staticNetwork}, nil) Expect(err).ToNot(HaveOccurred()) staticConfig := fs.GetFileTestStat("/etc/sysconfig/network-scripts/ifcfg-ethstatic") Expect(staticConfig).ToNot(BeNil()) Expect(staticConfig.StringContents()).To(Equal(expectedNetworkConfigurationForStatic)) dhcpConfig := fs.GetFileTestStat("/etc/sysconfig/network-scripts/ifcfg-ethdhcp") Expect(dhcpConfig).ToNot(BeNil()) Expect(dhcpConfig.StringContents()).To(Equal(expectedNetworkConfigurationForDHCP)) }) It("returns errors from glob /sys/class/net/", func() { fs.GlobErr = errors.New("fs-glob-error") err := netManager.SetupNetworking(boshsettings.Networks{"dhcp-network": dhcpNetwork, "static-network": staticNetwork}, nil) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fs-glob-error")) }) It("returns errors from writing the network configuration", func() { stubInterfaces(map[string]boshsettings.Network{ "dhcp": dhcpNetwork, "static": staticNetwork, }) fs.WriteFileError = errors.New("fs-write-file-error") err := netManager.SetupNetworking(boshsettings.Networks{"dhcp-network": dhcpNetwork, "static-network": staticNetwork}, nil) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fs-write-file-error")) }) It("returns errors when it can't create network interface configurations", func() { stubInterfaces(map[string]boshsettings.Network{ "ethstatic": staticNetwork, }) staticNetwork.Netmask = "not an ip" //will cause InterfaceConfigurationCreator to fail err := netManager.SetupNetworking(boshsettings.Networks{"static-network": staticNetwork}, nil) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Creating interface configurations")) }) It("wrtites a dhcp configuration if there are dhcp networks", func() { stubInterfaces(map[string]boshsettings.Network{ "ethdhcp": dhcpNetwork, "ethstatic": staticNetwork, }) err := netManager.SetupNetworking(boshsettings.Networks{"dhcp-network": dhcpNetwork, "static-network": staticNetwork}, nil) Expect(err).ToNot(HaveOccurred()) dhcpConfig := fs.GetFileTestStat("/etc/dhcp/dhclient.conf") Expect(dhcpConfig).ToNot(BeNil()) Expect(dhcpConfig.StringContents()).To(Equal(expectedDhclientConfiguration)) dhcpConfigSymlink := fs.GetFileTestStat("/etc/dhcp/dhclient-ethdhcp.conf") Expect(dhcpConfigSymlink).ToNot(BeNil()) Expect(dhcpConfigSymlink.SymlinkTarget).To(Equal("/etc/dhcp/dhclient.conf")) }) It("writes a dhcp configuration without prepended dns servers if there are no dns servers specified", func() { dhcpNetworkWithoutDNS := boshsettings.Network{ Type: "dynamic", Mac: "fake-dhcp-mac-address", } stubInterfaces(map[string]boshsettings.Network{ "ethdhcp": dhcpNetwork, }) err := netManager.SetupNetworking(boshsettings.Networks{"dhcp-network": dhcpNetworkWithoutDNS}, nil) Expect(err).ToNot(HaveOccurred()) dhcpConfig := fs.GetFileTestStat("/etc/dhcp/dhclient.conf") Expect(dhcpConfig).ToNot(BeNil()) Expect(dhcpConfig.StringContents()).To(Equal(`# Generated by bosh-agent option rfc3442-classless-static-routes code 121 = array of unsigned integer 8; send host-name "<hostname>"; request subnet-mask, broadcast-address, time-offset, routers, domain-name, domain-name-servers, domain-search, host-name, netbios-name-servers, netbios-scope, interface-mtu, rfc3442-classless-static-routes, ntp-servers; `)) dhcpConfigSymlink := fs.GetFileTestStat("/etc/dhcp/dhclient-ethdhcp.conf") Expect(dhcpConfigSymlink).ToNot(BeNil()) Expect(dhcpConfigSymlink.SymlinkTarget).To(Equal("/etc/dhcp/dhclient.conf")) }) It("returns an error if it can't write a dhcp configuration", func() { stubInterfaces(map[string]boshsettings.Network{ "ethdhcp": dhcpNetwork, "ethstatic": staticNetwork, }) fs.WriteFileErrors["/etc/dhcp/dhclient.conf"] = errors.New("dhclient.conf-write-error") err := netManager.SetupNetworking(boshsettings.Networks{"dhcp-network": dhcpNetwork, "static-network": staticNetwork}, nil) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("dhclient.conf-write-error")) }) It("returns an error if it can't symlink a dhcp configuration", func() { stubInterfaces(map[string]boshsettings.Network{ "ethdhcp": dhcpNetwork, "ethstatic": staticNetwork, }) fs.SymlinkError = errors.New("dhclient-ethdhcp.conf-symlink-error") err := netManager.SetupNetworking(boshsettings.Networks{"dhcp-network": dhcpNetwork, "static-network": staticNetwork}, nil) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("dhclient-ethdhcp.conf-symlink-error")) }) It("doesn't write a dhcp configuration if there are no dhcp networks", func() { stubInterfaces(map[string]boshsettings.Network{ "ethstatic": staticNetwork, }) err := netManager.SetupNetworking(boshsettings.Networks{"static-network": staticNetwork}, nil) Expect(err).ToNot(HaveOccurred()) dhcpConfig := fs.GetFileTestStat("/etc/dhcp/dhclient-ethdhcp.conf") Expect(dhcpConfig).To(BeNil()) }) It("restarts the networks if any ifconfig file changes", func() { changingStaticNetwork := boshsettings.Network{ Type: "manual", IP: "1.2.3.5", Netmask: "255.255.255.0", Gateway: "3.4.5.6", Mac: "ethstatict-that-changes", } stubInterfaces(map[string]boshsettings.Network{ "ethdhcp": dhcpNetwork, "ethstatic-that-changes": changingStaticNetwork, "ethstatic": staticNetwork, }) interfaceAddrsProvider.GetInterfaceAddresses = []boship.InterfaceAddress{ boship.NewSimpleInterfaceAddress("ethstatic", "1.2.3.4"), boship.NewSimpleInterfaceAddress("ethstatic-that-changes", "1.2.3.5"), } fs.WriteFileString("/etc/sysconfig/network-scripts/ifcfg-ethstatic", expectedNetworkConfigurationForStatic) fs.WriteFileString("/etc/dhcp/dhclient.conf", expectedDhclientConfiguration) err := netManager.SetupNetworking(boshsettings.Networks{ "dhcp-network": dhcpNetwork, "changing-static-network": changingStaticNetwork, "static-network": staticNetwork, }, nil) Expect(err).ToNot(HaveOccurred()) Expect(len(cmdRunner.RunCommands)).To(Equal(1)) Expect(cmdRunner.RunCommands[0]).To(Equal([]string{"service", "network", "restart"})) }) It("doesn't restart the networks if ifcfg and /etc/dhcp/dhclient.conf don't change", func() { stubInterfaces(map[string]boshsettings.Network{ "ethdhcp": dhcpNetwork, "ethstatic": staticNetwork, }) fs.WriteFileString("/etc/sysconfig/network-scripts/ifcfg-ethstatic", expectedNetworkConfigurationForStatic) fs.WriteFileString("/etc/sysconfig/network-scripts/ifcfg-ethdhcp", expectedNetworkConfigurationForDHCP) fs.WriteFileString("/etc/dhcp/dhclient.conf", expectedDhclientConfiguration) err := netManager.SetupNetworking(boshsettings.Networks{"dhcp-network": dhcpNetwork, "static-network": staticNetwork}, nil) Expect(err).ToNot(HaveOccurred()) networkConfig := fs.GetFileTestStat("/etc/sysconfig/network-scripts/ifcfg-ethstatic") Expect(networkConfig).ToNot(BeNil()) Expect(networkConfig.StringContents()).To(Equal(expectedNetworkConfigurationForStatic)) dhcpConfig := fs.GetFileTestStat("/etc/dhcp/dhclient.conf") Expect(dhcpConfig.StringContents()).To(Equal(expectedDhclientConfiguration)) Expect(len(cmdRunner.RunCommands)).To(Equal(0)) }) It("restarts the networks if /etc/dhcp/dhclient.conf changes", func() { stubInterfaces(map[string]boshsettings.Network{ "ethdhcp": dhcpNetwork, "ethstatic": staticNetwork, }) fs.WriteFileString("/etc/sysconfig/network-scripts/ifcfg-ethstatic", expectedNetworkConfigurationForStatic) err := netManager.SetupNetworking(boshsettings.Networks{"dhcp-network": dhcpNetwork, "static-network": staticNetwork}, nil) Expect(err).ToNot(HaveOccurred()) networkConfig := fs.GetFileTestStat("/etc/sysconfig/network-scripts/ifcfg-ethstatic") Expect(networkConfig).ToNot(BeNil()) Expect(networkConfig.StringContents()).To(Equal(expectedNetworkConfigurationForStatic)) Expect(len(cmdRunner.RunCommands)).To(Equal(1)) Expect(cmdRunner.RunCommands[0]).To(Equal([]string{"service", "network", "restart"})) }) Context("when manual networks were not configured with proper IP addresses", func() { BeforeEach(func() { interfaceAddrsProvider.GetInterfaceAddresses = []boship.InterfaceAddress{ boship.NewSimpleInterfaceAddress("ethstatic", "1.2.3.5"), } }) It("fails", func() { stubInterfaces(map[string]boshsettings.Network{ "ethstatic": staticNetwork, }) errCh := make(chan error) err := netManager.SetupNetworking(boshsettings.Networks{"static-network": staticNetwork}, errCh) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Validating static network configuration")) }) }) Context("when dns is not properly configured", func() { BeforeEach(func() { fs.WriteFileString("/etc/resolv.conf", "") }) It("fails", func() { staticNetwork = boshsettings.Network{ Type: "manual", IP: "1.2.3.4", Default: []string{"dns"}, DNS: []string{"8.8.8.8"}, Netmask: "255.255.255.0", Gateway: "3.4.5.6", Mac: "fake-static-mac-address", } stubInterfaces(map[string]boshsettings.Network{ "ethstatic": staticNetwork, }) errCh := make(chan error) err := netManager.SetupNetworking(boshsettings.Networks{"static-network": staticNetwork}, errCh) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Validating dns configuration")) }) }) It("broadcasts MAC addresses for all interfaces", func() { stubInterfaces(map[string]boshsettings.Network{ "ethdhcp": dhcpNetwork, "ethstatic": staticNetwork, }) errCh := make(chan error) err := netManager.SetupNetworking(boshsettings.Networks{"dhcp-network": dhcpNetwork, "static-network": staticNetwork}, errCh) Expect(err).ToNot(HaveOccurred()) broadcastErr := <-errCh // wait for all arpings Expect(broadcastErr).ToNot(HaveOccurred()) Expect(addressBroadcaster.BroadcastMACAddressesAddresses).To(Equal([]boship.InterfaceAddress{ boship.NewSimpleInterfaceAddress("ethstatic", "1.2.3.4"), boship.NewResolvingInterfaceAddress("ethdhcp", ipResolver), })) }) It("skips vip networks", func() { stubInterfaces(map[string]boshsettings.Network{ "ethdhcp": dhcpNetwork, "ethstatic": staticNetwork, }) vipNetwork := boshsettings.Network{ Type: "vip", Default: []string{"dns"}, DNS: []string{"4.4.4.4", "5.5.5.5"}, Mac: "fake-vip-mac-address", IP: "9.8.7.6", } err := netManager.SetupNetworking(boshsettings.Networks{ "dhcp-network": dhcpNetwork, "static-network": staticNetwork, "vip-network": vipNetwork, }, nil) Expect(err).ToNot(HaveOccurred()) networkConfig := fs.GetFileTestStat("/etc/sysconfig/network-scripts/ifcfg-ethstatic") Expect(networkConfig).ToNot(BeNil()) Expect(networkConfig.StringContents()).To(Equal(expectedNetworkConfigurationForStatic)) }) It("doesn't use vip networks dns", func() { stubInterfaces(map[string]boshsettings.Network{ "ethstatic": staticNetwork, }) vipNetwork := boshsettings.Network{ Type: "vip", Default: []string{"dns"}, DNS: []string{"4.4.4.4", "5.5.5.5"}, Mac: "fake-vip-mac-address", IP: "9.8.7.6", } err := netManager.SetupNetworking(boshsettings.Networks{ "vip-network": vipNetwork, "static-network": staticNetwork, }, nil) Expect(err).ToNot(HaveOccurred()) networkConfig := fs.GetFileTestStat("/etc/sysconfig/network-scripts/ifcfg-ethstatic") Expect(networkConfig).ToNot(BeNil()) Expect(networkConfig.StringContents()).ToNot(ContainSubstring("4.4.4.4")) Expect(networkConfig.StringContents()).ToNot(ContainSubstring("5.5.5.5")) }) Context("when no MAC address is provided in the settings", func() { var staticNetworkWithoutMAC boshsettings.Network BeforeEach(func() { staticNetworkWithoutMAC = boshsettings.Network{ Type: "manual", IP: "1.2.3.4", Netmask: "255.255.255.0", Gateway: "3.4.5.6", DNS: []string{"8.8.8.8", "9.9.9.9"}, Default: []string{"dns"}, } }) It("configures network for single device", func() { stubInterfaces( map[string]boshsettings.Network{ "ethstatic": staticNetwork, }, ) err := netManager.SetupNetworking(boshsettings.Networks{ "static-network": staticNetworkWithoutMAC, }, nil) Expect(err).ToNot(HaveOccurred()) networkConfig := fs.GetFileTestStat("/etc/sysconfig/network-scripts/ifcfg-ethstatic") Expect(networkConfig).ToNot(BeNil()) Expect(networkConfig.StringContents()).To(Equal(expectedNetworkConfigurationForStatic)) }) It("configures network for single device, when a virtual device is also present", func() { stubInterfacesWithVirtual( map[string]boshsettings.Network{ "ethstatic": staticNetwork, }, []string{"virtual"}, ) err := netManager.SetupNetworking(boshsettings.Networks{ "static-network": staticNetworkWithoutMAC, }, nil) Expect(err).ToNot(HaveOccurred()) physicalNetworkConfig := fs.GetFileTestStat("/etc/sysconfig/network-scripts/ifcfg-ethstatic") Expect(physicalNetworkConfig).ToNot(BeNil()) Expect(physicalNetworkConfig.StringContents()).To(Equal(expectedNetworkConfigurationForStatic)) virtualNetworkConfig := fs.GetFileTestStat("/etc/sysconfig/network-scripts/ifcfg-virtual") Expect(virtualNetworkConfig).To(BeNil()) }) }) }) Describe("GetConfiguredNetworkInterfaces", func() { Context("when there are network devices", func() { BeforeEach(func() { interfacePaths := []string{} interfacePaths = append(interfacePaths, writeNetworkDevice("fake-eth0", "aa:bb", true)) interfacePaths = append(interfacePaths, writeNetworkDevice("fake-eth1", "cc:dd", true)) interfacePaths = append(interfacePaths, writeNetworkDevice("fake-eth2", "ee:ff", true)) fs.SetGlob("/sys/class/net/*", interfacePaths) }) writeIfcgfFile := func(iface string) { fs.WriteFileString(fmt.Sprintf("/etc/sysconfig/network-scripts/ifcfg-%s", iface), "fake-config") } It("returns networks that have ifcfg config present", func() { writeIfcgfFile("fake-eth0") writeIfcgfFile("fake-eth2") interfaces, err := netManager.GetConfiguredNetworkInterfaces() Expect(err).ToNot(HaveOccurred()) Expect(interfaces).To(ConsistOf("fake-eth0", "fake-eth2")) }) }) Context("when there are no network devices", func() { It("returns empty list", func() { interfaces, err := netManager.GetConfiguredNetworkInterfaces() Expect(err).ToNot(HaveOccurred()) Expect(interfaces).To(Equal([]string{})) }) }) }) }
}) Describe("Get", func() { It("fetches the local blob contents", func() { fs.WriteFileString(fakeBlobstorePath+"/fake-blob-id", "fake contents") tempFile, err := fs.TempFile("bosh-blobstore-local-TestLocalGet") Expect(err).ToNot(HaveOccurred()) fs.ReturnTempFile = tempFile defer fs.RemoveAll(tempFile.Name()) _, err = blobstore.Get("fake-blob-id", "") Expect(err).ToNot(HaveOccurred()) fileStats := fs.GetFileTestStat(tempFile.Name()) Expect(fileStats).ToNot(BeNil()) Expect("fake contents").To(Equal(fileStats.StringContents())) }) It("errs when temp file create errs", func() { fs.TempFileError = errors.New("fake-error") fileName, err := blobstore.Get("fake-blob-id", "") Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-error")) Expect(fileName).To(BeEmpty()) }) It("errs when copy file errs", func() {
func describeDummyPlatform() { var ( platform Platform collector boshstats.Collector fs *fakesys.FakeFileSystem cmdRunner boshsys.CmdRunner dirProvider boshdirs.Provider devicePathResolver boshdpresolv.DevicePathResolver logger boshlog.Logger ) BeforeEach(func() { collector = &fakestats.FakeCollector{} fs = fakesys.NewFakeFileSystem() cmdRunner = fakesys.NewFakeCmdRunner() dirProvider = boshdirs.NewProvider("/fake-dir") devicePathResolver = fakedpresolv.NewFakeDevicePathResolver() logger = boshlog.NewLogger(boshlog.LevelNone) }) JustBeforeEach(func() { platform = NewDummyPlatform( collector, fs, cmdRunner, dirProvider, devicePathResolver, logger, ) }) Describe("GetDefaultNetwork", func() { It("returns the contents of dummy-defaults-network-settings.json since that's what the dummy cpi writes", func() { settingsFilePath := "/fake-dir/bosh/dummy-default-network-settings.json" fs.WriteFileString(settingsFilePath, `{"IP": "1.2.3.4"}`) network, err := platform.GetDefaultNetwork() Expect(err).NotTo(HaveOccurred()) Expect(network.IP).To(Equal("1.2.3.4")) }) }) Describe("GetCertManager", func() { It("returs a dummy cert manager", func() { certManager := platform.GetCertManager() Expect(certManager.UpdateCertificates("")).Should(BeNil()) }) }) Describe("UnmountPersistentDisk", func() { Context("when there are two mounted persistent disks in the mounts json", func() { BeforeEach(func() { var mounts []mount mounts = append(mounts, mount{MountDir: "dir1", DiskCid: "cid1"}) mounts = append(mounts, mount{MountDir: "dir2", DiskCid: "cid2"}) mountsJSON, _ := json.Marshal(mounts) mountsPath := path.Join(dirProvider.BoshDir(), "mounts.json") fs.WriteFile(mountsPath, mountsJSON) }) It("removes one of the disks from the mounts json", func() { unmounted, err := platform.UnmountPersistentDisk(settings.DiskSettings{ID: "cid1"}) Expect(err).NotTo(HaveOccurred()) Expect(unmounted).To(Equal(true)) _, isMountPoint, err := platform.IsMountPoint("dir1") Expect(isMountPoint).To(Equal(false)) _, isMountPoint, err = platform.IsMountPoint("dir2") Expect(isMountPoint).To(Equal(true)) }) }) }) Describe("SetUserPassword", func() { It("writes the password to a file", func() { err := platform.SetUserPassword("user-name", "fake-password") Expect(err).NotTo(HaveOccurred()) userPasswordsPath := path.Join(dirProvider.BoshDir(), "user-name", CredentialFileName) password, err := fs.ReadFileString(userPasswordsPath) Expect(err).NotTo(HaveOccurred()) Expect(password).To(Equal("fake-password")) }) It("writes the passwords to different files for each user", func() { err := platform.SetUserPassword("user-name1", "fake-password1") Expect(err).NotTo(HaveOccurred()) err = platform.SetUserPassword("user-name2", "fake-password2") Expect(err).NotTo(HaveOccurred()) userPasswordsPath := path.Join(dirProvider.BoshDir(), "user-name1", CredentialFileName) password, err := fs.ReadFileString(userPasswordsPath) Expect(err).NotTo(HaveOccurred()) Expect(password).To(Equal("fake-password1")) userPasswordsPath = path.Join(dirProvider.BoshDir(), "user-name2", CredentialFileName) password, err = fs.ReadFileString(userPasswordsPath) Expect(err).NotTo(HaveOccurred()) Expect(password).To(Equal("fake-password2")) }) }) Describe("SetupDataDir", func() { It("creates a link from BASEDIR/sys to BASEDIR/data/sys", func() { err := platform.SetupDataDir() Expect(err).NotTo(HaveOccurred()) stat := fs.GetFileTestStat("/fake-dir/sys") Expect(stat).ToNot(BeNil()) Expect(stat.SymlinkTarget).To(Equal("/fake-dir/data/sys")) }) }) }
func describeUbuntuNetManager() { var ( fs *fakesys.FakeFileSystem cmdRunner *fakesys.FakeCmdRunner ipResolver *fakeip.FakeResolver addressBroadcaster *fakearp.FakeAddressBroadcaster interfaceAddrsProvider *fakeip.FakeInterfaceAddressesProvider 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{} interfaceAddrsProvider = &fakeip.FakeInterfaceAddressesProvider{} interfaceAddrsValidator := boship.NewInterfaceAddressesValidator(interfaceAddrsProvider) dnsValidator := NewDNSValidator(fs) netManager = NewUbuntuNetManager( fs, cmdRunner, ipResolver, interfaceConfigurationCreator, interfaceAddrsValidator, dnsValidator, 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", IsDefaultForGateway: true, 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", Default: []string{"gateway"}, Netmask: "255.255.255.0", Gateway: "3.4.5.6", Mac: "fake-static-mac-address", } interfaceAddrsProvider.GetInterfaceAddresses = []boship.InterfaceAddress{ boship.NewSimpleInterfaceAddress("ethstatic", "1.2.3.4"), } fs.WriteFileString("/etc/resolv.conf", ` nameserver 8.8.8.8 nameserver 9.9.9.9 `) 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("configures gateway, broadcast and dns for default network only", func() { 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", } secondStaticNetwork := boshsettings.Network{ Type: "manual", IP: "5.6.7.8", Netmask: "255.255.255.0", Gateway: "6.7.8.9", Mac: "second-fake-static-mac-address", DNS: []string{"8.8.8.8"}, Default: []string{"gateway", "dns"}, } stubInterfaces(map[string]boshsettings.Network{ "eth0": staticNetwork, "eth1": secondStaticNetwork, }) interfaceAddrsProvider.GetInterfaceAddresses = []boship.InterfaceAddress{ boship.NewSimpleInterfaceAddress("eth0", "1.2.3.4"), boship.NewSimpleInterfaceAddress("eth1", "5.6.7.8"), } err := netManager.SetupNetworking(boshsettings.Networks{ "static-1": staticNetwork, "static-2": secondStaticNetwork, }, 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 eth0 iface eth0 inet static address 1.2.3.4 network 1.2.3.0 netmask 255.255.255.0 auto eth1 iface eth1 inet static address 5.6.7.8 network 5.6.7.0 netmask 255.255.255.0 broadcast 5.6.7.255 gateway 6.7.8.9 dns-nameservers 8.8.8.8`)) }) 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", Default: []string{"gateway"}, 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", "--force", "ethdhcp", "ethstatic"})) Expect(cmdRunner.RunCommands[4]).To(Equal([]string{"ifup", "--force", "ethdhcp", "ethstatic"})) }) 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", "--force", "ethdhcp", "ethstatic"})) Expect(cmdRunner.RunCommands[4]).To(Equal([]string{"ifup", "--force", "ethdhcp", "ethstatic"})) }) 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 manual networks were not configured with proper IP addresses", func() { BeforeEach(func() { interfaceAddrsProvider.GetInterfaceAddresses = []boship.InterfaceAddress{ boship.NewSimpleInterfaceAddress("ethstatic", "1.2.3.5"), } }) It("fails", func() { stubInterfaces(map[string]boshsettings.Network{ "ethstatic": staticNetwork, }) errCh := make(chan error) err := netManager.SetupNetworking(boshsettings.Networks{"static-network": staticNetwork}, errCh) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Validating static network configuration")) }) }) Context("when dns is not properly configured", func() { BeforeEach(func() { fs.WriteFileString("/etc/resolv.conf", "") }) It("fails", func() { staticNetwork = boshsettings.Network{ Type: "manual", IP: "1.2.3.4", Default: []string{"dns"}, DNS: []string{"8.8.8.8"}, Netmask: "255.255.255.0", Gateway: "3.4.5.6", Mac: "fake-static-mac-address", } stubInterfaces(map[string]boshsettings.Network{ "ethstatic": staticNetwork, }) errCh := make(chan error) err := netManager.SetupNetworking(boshsettings.Networks{"static-network": staticNetwork}, errCh) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Validating dns configuration")) }) }) 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", Default: []string{"gateway"}, Netmask: "255.255.255.0", Gateway: "3.4.5.6", } stubInterfaces( map[string]boshsettings.Network{ "ethstatic": staticNetwork, }, ) interfaceAddrsProvider.GetInterfaceAddresses = []boship.InterfaceAddress{ boship.NewSimpleInterfaceAddress("ethstatic", "2.2.2.2"), } 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", Default: []string{"gateway"}, Netmask: "255.255.255.0", Gateway: "3.4.5.6", } stubInterfacesWithVirtual( map[string]boshsettings.Network{ "ethstatic": staticNetwork, }, []string{"virtual"}, ) interfaceAddrsProvider.GetInterfaceAddresses = []boship.InterfaceAddress{ boship.NewSimpleInterfaceAddress("ethstatic", "2.2.2.2"), } 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{})) }) }) }) }
func init() { Describe("renderedJobApplier", func() { var ( jobsBc *fakebc.FakeBundleCollection jobSupervisor *fakejobsuper.FakeJobSupervisor packageApplierProvider *fakepackages.FakeApplierProvider blobstore *fakeblob.FakeBlobstore compressor *fakecmd.FakeCompressor fs *fakesys.FakeFileSystem applier Applier ) BeforeEach(func() { jobsBc = fakebc.NewFakeBundleCollection() jobSupervisor = fakejobsuper.NewFakeJobSupervisor() packageApplierProvider = fakepackages.NewFakeApplierProvider() blobstore = fakeblob.NewFakeBlobstore() fs = fakesys.NewFakeFileSystem() compressor = fakecmd.NewFakeCompressor() logger := boshlog.NewLogger(boshlog.LevelNone) applier = NewRenderedJobApplier( jobsBc, jobSupervisor, packageApplierProvider, blobstore, compressor, fs, logger, ) }) Describe("Prepare & Apply", func() { var ( job models.Job bundle *fakebc.FakeBundle ) BeforeEach(func() { job, bundle = buildJob(jobsBc) }) ItInstallsJob := func(act func() error) { BeforeEach(func() { fs.TempDirDir = "/fake-tmp-dir" }) It("returns error when installing job fails", func() { bundle.InstallError = errors.New("fake-install-error") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-install-error")) }) It("downloads and later cleans up downloaded job template blob", func() { blobstore.GetFileName = "/fake-blobstore-file-name" err := act() Expect(err).ToNot(HaveOccurred()) Expect(blobstore.GetBlobIDs[0]).To(Equal("fake-blobstore-id")) Expect(blobstore.GetFingerprints[0]).To(Equal(boshcrypto.NewDigest("sha1", "fake-blob-sha1"))) // downloaded file is cleaned up Expect(blobstore.CleanUpFileName).To(Equal("/fake-blobstore-file-name")) }) It("returns error when downloading job template blob fails", func() { blobstore.GetError = errors.New("fake-get-error") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-get-error")) }) It("decompresses job template blob to tmp path and later cleans it up", func() { blobstore.GetFileName = "/fake-blobstore-file-name" var tmpDirExistsBeforeInstall bool bundle.InstallCallBack = func() { tmpDirExistsBeforeInstall = true } err := act() Expect(err).ToNot(HaveOccurred()) Expect(compressor.DecompressFileToDirTarballPaths[0]).To(Equal("/fake-blobstore-file-name")) Expect(compressor.DecompressFileToDirDirs[0]).To(Equal("/fake-tmp-dir")) // tmp dir exists before bundle install Expect(tmpDirExistsBeforeInstall).To(BeTrue()) // tmp dir is cleaned up after install Expect(fs.FileExists(fs.TempDirDir)).To(BeFalse()) }) It("returns error when temporary directory creation fails", func() { fs.TempDirError = errors.New("fake-filesystem-tempdir-error") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-filesystem-tempdir-error")) }) It("can process sha1 checksums in the new format", func() { blobstore.GetFileName = "/fake-blobstore-file-name" job.Source.Sha1 = "sha1:fake-blob-sha1" err := act() Expect(err).ToNot(HaveOccurred()) Expect(blobstore.GetBlobIDs[0]).To(Equal("fake-blobstore-id")) Expect(blobstore.GetFingerprints[0]).To(Equal(boshcrypto.NewDigest("sha1", "fake-blob-sha1"))) }) It("can process sha2 checksums", func() { blobstore.GetFileName = "/fake-blobstore-file-name" job.Source.Sha1 = "sha256:fake-blob-sha256" err := act() Expect(err).ToNot(HaveOccurred()) Expect(blobstore.GetBlobIDs[0]).To(Equal("fake-blobstore-id")) Expect(blobstore.GetFingerprints[0]).To(Equal(boshcrypto.NewDigest("sha256", "fake-blob-sha256"))) }) It("returns error when given and unsupported fingerprint", func() { blobstore.GetFileName = "/fake-blobstore-file-name" job.Source.Sha1 = "unsupported:checksum" err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Parsing job blob digest")) }) It("returns error when decompressing job template fails", func() { compressor.DecompressFileToDirErr = errors.New("fake-decompress-error") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-decompress-error")) }) It("returns error when walking the tree of files fails", func() { fs.WalkErr = errors.New("fake-walk-error") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-walk-error")) }) It("installs bundle from decompressed tmp path of a job template", func() { var installedBeforeDecompression bool compressor.DecompressFileToDirCallBack = func() { installedBeforeDecompression = bundle.Installed } err := act() Expect(err).ToNot(HaveOccurred()) // bundle installation did not happen before decompression Expect(installedBeforeDecompression).To(BeFalse()) // make sure that bundle install happened after decompression Expect(bundle.InstallSourcePath).To(Equal("/fake-tmp-dir/fake-path-in-archive")) }) It("sets executable bit for the bin and config directories", func() { var binDirStats, configDirStats *fakesys.FakeFileStats compressor.DecompressFileToDirCallBack = func() { fs.WriteFile("/fake-tmp-dir/fake-path-in-archive/bin/blarg", []byte{}) fs.WriteFile("/fake-tmp-dir/fake-path-in-archive/config/blarg.yml", []byte{}) } bundle.InstallCallBack = func() { binDirStats = fs.GetFileTestStat("/fake-tmp-dir/fake-path-in-archive/bin") configDirStats = fs.GetFileTestStat("/fake-tmp-dir/fake-path-in-archive/config") } err := act() Expect(err).ToNot(HaveOccurred()) Expect(int(binDirStats.FileMode)).To(Equal(0755)) Expect(int(configDirStats.FileMode)).To(Equal(0755)) }) It("sets executable bit for files in bin", func() { compressor.DecompressFileToDirCallBack = func() { fs.WriteFile("/fake-tmp-dir/fake-path-in-archive/bin/test1", []byte{}) fs.WriteFile("/fake-tmp-dir/fake-path-in-archive/bin/test2", []byte{}) fs.WriteFile("/fake-tmp-dir/fake-path-in-archive/config/test", []byte{}) } fs.SetGlob("/fake-tmp-dir/fake-path-in-archive/bin/*", []string{ "/fake-tmp-dir/fake-path-in-archive/bin/test1", "/fake-tmp-dir/fake-path-in-archive/bin/test2", }) var binTest1Stats, binTest2Stats, configTestStats *fakesys.FakeFileStats bundle.InstallCallBack = func() { binTest1Stats = fs.GetFileTestStat("/fake-tmp-dir/fake-path-in-archive/bin/test1") binTest2Stats = fs.GetFileTestStat("/fake-tmp-dir/fake-path-in-archive/bin/test2") configTestStats = fs.GetFileTestStat("/fake-tmp-dir/fake-path-in-archive/config/test") } err := act() Expect(err).ToNot(HaveOccurred()) // bin files are executable Expect(int(binTest1Stats.FileMode)).To(Equal(0755)) Expect(int(binTest2Stats.FileMode)).To(Equal(0755)) // non-bin files are not made executable Expect(int(configTestStats.FileMode)).ToNot(Equal(0755)) }) It("sets 644 permissions for files in config", func() { compressor.DecompressFileToDirCallBack = func() { fs.WriteFile("/fake-tmp-dir/fake-path-in-archive/config/config1", []byte{}) fs.WriteFile("/fake-tmp-dir/fake-path-in-archive/config/config2", []byte{}) } fs.SetGlob("/fake-tmp-dir/fake-path-in-archive/config/*", []string{ "/fake-tmp-dir/fake-path-in-archive/config/config1", "/fake-tmp-dir/fake-path-in-archive/config/config2", }) var config1Stats, config2Stats *fakesys.FakeFileStats bundle.InstallCallBack = func() { config1Stats = fs.GetFileTestStat("/fake-tmp-dir/fake-path-in-archive/config/config1") config2Stats = fs.GetFileTestStat("/fake-tmp-dir/fake-path-in-archive/config/config2") } err := act() Expect(err).ToNot(HaveOccurred()) // permission for config files should be readable by all Expect(int(config1Stats.FileMode)).To(Equal(0644)) Expect(int(config2Stats.FileMode)).To(Equal(0644)) }) } ItUpdatesPackages := func(act func() error) { var packageApplier *fakepackages.FakeApplier BeforeEach(func() { packageApplier = fakepackages.NewFakeApplier() packageApplierProvider.JobSpecificAppliers[job.Name] = packageApplier }) It("applies each package that job depends on and then cleans up packages", func() { err := act() Expect(err).ToNot(HaveOccurred()) Expect(packageApplier.ActionsCalled).To(Equal([]string{"Apply", "Apply", "KeepOnly"})) Expect(len(packageApplier.AppliedPackages)).To(Equal(2)) // present Expect(packageApplier.AppliedPackages).To(Equal(job.Packages)) }) It("returns error when applying package that job depends on fails", func() { packageApplier.ApplyError = errors.New("fake-apply-err") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-apply-err")) }) It("keeps only currently required packages but does not completely uninstall them", func() { err := act() Expect(err).ToNot(HaveOccurred()) Expect(len(packageApplier.KeptOnlyPackages)).To(Equal(2)) // present Expect(packageApplier.KeptOnlyPackages).To(Equal(job.Packages)) }) It("returns error when keeping only currently required packages fails", func() { packageApplier.KeepOnlyErr = errors.New("fake-keep-only-err") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-keep-only-err")) }) } Describe("Prepare", func() { act := func() error { return applier.Prepare(job) } It("return an error if getting file bundle fails", func() { jobsBc.GetErr = errors.New("fake-get-bundle-error") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-get-bundle-error")) }) It("returns an error if checking for installed path fails", func() { bundle.IsInstalledErr = errors.New("fake-is-installed-error") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-is-installed-error")) }) Context("when job is already installed", func() { BeforeEach(func() { bundle.Installed = true }) It("does not install", func() { err := act() Expect(err).ToNot(HaveOccurred()) Expect(bundle.ActionsCalled).To(Equal([]string{})) // no Install }) It("does not download the job template", func() { err := act() Expect(err).ToNot(HaveOccurred()) Expect(blobstore.GetBlobIDs).To(BeNil()) }) }) Context("when job is not installed", func() { BeforeEach(func() { bundle.Installed = false }) It("installs job (but does not enable)", func() { err := act() Expect(err).ToNot(HaveOccurred()) Expect(bundle.ActionsCalled).To(Equal([]string{"Install"})) }) ItInstallsJob(act) }) }) Describe("Apply", func() { act := func() error { return applier.Apply(job) } It("return an error if getting file bundle fails", func() { jobsBc.GetErr = errors.New("fake-get-bundle-error") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-get-bundle-error")) }) It("returns an error if checking for installed path fails", func() { bundle.IsInstalledErr = errors.New("fake-is-installed-error") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-is-installed-error")) }) Context("when job is already installed", func() { BeforeEach(func() { bundle.Installed = true }) It("does not install but only enables job", func() { err := act() Expect(err).ToNot(HaveOccurred()) Expect(bundle.ActionsCalled).To(Equal([]string{"Enable"})) // no Install }) It("returns error when job enable fails", func() { bundle.EnableError = errors.New("fake-enable-error") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-enable-error")) }) It("does not download the job template", func() { err := act() Expect(err).ToNot(HaveOccurred()) Expect(blobstore.GetBlobIDs).To(BeNil()) }) ItUpdatesPackages(act) }) Context("when job is not installed", func() { BeforeEach(func() { bundle.Installed = false }) It("installs and enables job", func() { err := act() Expect(err).ToNot(HaveOccurred()) Expect(bundle.ActionsCalled).To(Equal([]string{"Install", "Enable"})) }) It("returns error when job enable fails", func() { bundle.EnableError = errors.New("fake-enable-error") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-enable-error")) }) ItInstallsJob(act) ItUpdatesPackages(act) }) }) }) Describe("Configure", func() { It("adds job to the job supervisor", func() { job, bundle := buildJob(jobsBc) fs := fakesys.NewFakeFileSystem() fs.WriteFileString("/path/to/job/monit", "some conf") fs.SetGlob("/path/to/job/*.monit", []string{"/path/to/job/subjob.monit"}) bundle.GetDirPath = "/path/to/job" bundle.GetDirFs = fs err := applier.Configure(job, 0) Expect(err).ToNot(HaveOccurred()) Expect(len(jobSupervisor.AddJobArgs)).To(Equal(2)) Expect(jobSupervisor.AddJobArgs[0]).To(Equal(fakejobsuper.AddJobArgs{ Name: job.Name, Index: 0, ConfigPath: "/path/to/job/monit", })) Expect(jobSupervisor.AddJobArgs[1]).To(Equal(fakejobsuper.AddJobArgs{ Name: job.Name + "_subjob", Index: 0, ConfigPath: "/path/to/job/subjob.monit", })) }) It("does not require monit script", func() { job, bundle := buildJob(jobsBc) fs := fakesys.NewFakeFileSystem() bundle.GetDirFs = fs err := applier.Configure(job, 0) Expect(err).ToNot(HaveOccurred()) Expect(len(jobSupervisor.AddJobArgs)).To(Equal(0)) }) }) Describe("KeepOnly", func() { It("first disables and then uninstalls jobs that are not in keeponly list", func() { _, bundle1 := buildJob(jobsBc) job2, bundle2 := buildJob(jobsBc) _, bundle3 := buildJob(jobsBc) job4, bundle4 := buildJob(jobsBc) jobsBc.ListBundles = []boshbc.Bundle{bundle1, bundle2, bundle3, bundle4} err := applier.KeepOnly([]models.Job{job4, job2}) Expect(err).ToNot(HaveOccurred()) Expect(bundle1.ActionsCalled).To(Equal([]string{"Disable", "Uninstall"})) Expect(bundle2.ActionsCalled).To(Equal([]string{})) Expect(bundle3.ActionsCalled).To(Equal([]string{"Disable", "Uninstall"})) Expect(bundle4.ActionsCalled).To(Equal([]string{})) }) It("returns error when bundle collection fails to return list of installed bundles", func() { jobsBc.ListErr = errors.New("fake-bc-list-error") err := applier.KeepOnly([]models.Job{}) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-bc-list-error")) }) It("returns error when bundle collection cannot retrieve bundle for keep-only job", func() { job1, bundle1 := buildJob(jobsBc) jobsBc.ListBundles = []boshbc.Bundle{bundle1} jobsBc.GetErr = errors.New("fake-bc-get-error") err := applier.KeepOnly([]models.Job{job1}) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-bc-get-error")) }) It("returns error when at least one bundle cannot be disabled", func() { _, bundle1 := buildJob(jobsBc) jobsBc.ListBundles = []boshbc.Bundle{bundle1} bundle1.DisableErr = errors.New("fake-bc-disable-error") err := applier.KeepOnly([]models.Job{}) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-bc-disable-error")) }) It("returns error when at least one bundle cannot be uninstalled", func() { _, bundle1 := buildJob(jobsBc) jobsBc.ListBundles = []boshbc.Bundle{bundle1} bundle1.UninstallErr = errors.New("fake-bc-uninstall-error") err := applier.KeepOnly([]models.Job{}) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-bc-uninstall-error")) }) }) }) }
func describeDummyPlatform() { var ( platform Platform collector boshstats.Collector fs *fakesys.FakeFileSystem cmdRunner boshsys.CmdRunner dirProvider boshdirs.Provider devicePathResolver boshdpresolv.DevicePathResolver logger boshlog.Logger ) BeforeEach(func() { collector = &fakestats.FakeCollector{} fs = fakesys.NewFakeFileSystem() cmdRunner = fakesys.NewFakeCmdRunner() dirProvider = boshdirs.NewProvider("/fake-dir") devicePathResolver = fakedpresolv.NewFakeDevicePathResolver() logger = boshlog.NewLogger(boshlog.LevelNone) }) JustBeforeEach(func() { platform = NewDummyPlatform( collector, fs, cmdRunner, dirProvider, devicePathResolver, logger, ) }) Describe("GetDefaultNetwork", func() { It("returns the contents of dummy-defaults-network-settings.json since that's what the dummy cpi writes", func() { settingsFilePath := "/fake-dir/bosh/dummy-default-network-settings.json" fs.WriteFileString(settingsFilePath, `{"IP": "1.2.3.4"}`) network, err := platform.GetDefaultNetwork() Expect(err).NotTo(HaveOccurred()) Expect(network.IP).To(Equal("1.2.3.4")) }) }) Describe("GetCertManager", func() { It("returns a dummy cert manager", func() { certManager := platform.GetCertManager() Expect(certManager.UpdateCertificates("")).Should(BeNil()) }) }) Describe("MountPersistentDisk", func() { var diskSettings boshsettings.DiskSettings var mountsPath, managedSettingsPath, formattedDisksPath string BeforeEach(func() { diskSettings = boshsettings.DiskSettings{ID: "somediskid"} mountsPath = filepath.Join(dirProvider.BoshDir(), "mounts.json") managedSettingsPath = filepath.Join(dirProvider.BoshDir(), "managed_disk_settings.json") formattedDisksPath = filepath.Join(dirProvider.BoshDir(), "formatted_disks.json") }) It("Mounts a persistent disk", func() { mountsContent, _ := fs.ReadFileString(mountsPath) Expect(mountsContent).To(Equal("")) err := platform.MountPersistentDisk(diskSettings, "/dev/potato") Expect(err).NotTo(HaveOccurred()) mountsContent, _ = fs.ReadFileString(mountsPath) Expect(mountsContent).To(Equal(`[{"MountDir":"/dev/potato","DiskCid":"somediskid"}]`)) }) It("Updates the managed disk settings", func() { lastMountedCid, _ := fs.ReadFileString(managedSettingsPath) Expect(lastMountedCid).To(Equal("")) err := platform.MountPersistentDisk(diskSettings, "/dev/potato") Expect(err).NotTo(HaveOccurred()) lastMountedCid, _ = fs.ReadFileString(managedSettingsPath) Expect(lastMountedCid).To(Equal("somediskid")) }) It("Updates the formatted disks", func() { formattedDisks, _ := fs.ReadFileString(formattedDisksPath) Expect(formattedDisks).To(Equal("")) err := platform.MountPersistentDisk(diskSettings, "/dev/potato") Expect(err).NotTo(HaveOccurred()) formattedDisks, _ = fs.ReadFileString(formattedDisksPath) Expect(formattedDisks).To(Equal(`[{"DiskCid":"somediskid"}]`)) }) Context("Device has already been mounted as expected", func() { BeforeEach(func() { fs.WriteFileString(managedSettingsPath, "somediskid") fs.WriteFileString(mountsPath, `[{"MountDir":"/dev/potato","DiskCid":"somediskid"}]`) }) It("Does not mount in new location", func() { err := platform.MountPersistentDisk(diskSettings, "/dev/potato") Expect(err).NotTo(HaveOccurred()) mountsContent, _ := fs.ReadFileString(mountsPath) Expect(mountsContent).To(Equal(`[{"MountDir":"/dev/potato","DiskCid":"somediskid"}]`)) }) }) }) Describe("UnmountPersistentDisk", func() { Context("when there are two mounted persistent disks in the mounts json", func() { BeforeEach(func() { var mounts []mount mounts = append(mounts, mount{MountDir: "dir1", DiskCid: "cid1"}) mounts = append(mounts, mount{MountDir: "dir2", DiskCid: "cid2"}) mountsJSON, err := json.Marshal(mounts) Expect(err).NotTo(HaveOccurred()) mountsPath := filepath.Join(dirProvider.BoshDir(), "mounts.json") fs.WriteFile(mountsPath, mountsJSON) }) It("removes one of the disks from the mounts json", func() { unmounted, err := platform.UnmountPersistentDisk(settings.DiskSettings{ID: "cid1"}) Expect(err).NotTo(HaveOccurred()) Expect(unmounted).To(Equal(true)) _, isMountPoint, err := platform.IsMountPoint("dir1") Expect(err).NotTo(HaveOccurred()) Expect(isMountPoint).To(Equal(false)) _, isMountPoint, err = platform.IsMountPoint("dir2") Expect(err).NotTo(HaveOccurred()) Expect(isMountPoint).To(Equal(true)) }) }) }) Describe("SetDiskAssociations", func() { It("writes the associations to the file", func() { diskName1 := "disk1" diskName2 := "disk2" err := platform.AssociateDisk(diskName1, boshsettings.DiskSettings{}) Expect(err).NotTo(HaveOccurred()) err = platform.AssociateDisk(diskName2, boshsettings.DiskSettings{}) Expect(err).NotTo(HaveOccurred()) diskAssociationsPath := filepath.Join(dirProvider.BoshDir(), "disk_associations.json") actualDiskNames := []string{} fileContent, err := fs.ReadFile(diskAssociationsPath) Expect(err).NotTo(HaveOccurred()) err = json.Unmarshal(fileContent, &actualDiskNames) Expect(err).NotTo(HaveOccurred()) Expect(actualDiskNames).To(ConsistOf([]string{ diskName1, diskName2, })) }) }) Describe("IsPersistentDiskMountable", func() { BeforeEach(func() { formattedDisksPath := filepath.Join(dirProvider.BoshDir(), "formatted_disks.json") fs.WriteFileString(formattedDisksPath, `[{"DiskCid": "my-disk-id"}]`) }) Context("when disk has been formatted", func() { It("returns true with no error", func() { diskSettings := boshsettings.DiskSettings{ID: "my-disk-id"} mountable, err := platform.IsPersistentDiskMountable(diskSettings) Expect(err).ToNot(HaveOccurred()) Expect(mountable).To(Equal(true)) }) }) Context("when disk has NOT been formatted", func() { It("returns false with no error", func() { diskSettings := boshsettings.DiskSettings{ID: "some-other-disk-id"} mountable, err := platform.IsPersistentDiskMountable(diskSettings) Expect(err).ToNot(HaveOccurred()) Expect(mountable).To(Equal(false)) }) }) }) Describe("SetUserPassword", func() { It("writes the password to a file", func() { err := platform.SetUserPassword("user-name", "fake-password") Expect(err).NotTo(HaveOccurred()) userPasswordsPath := filepath.Join(dirProvider.BoshDir(), "user-name", CredentialFileName) password, err := fs.ReadFileString(userPasswordsPath) Expect(err).NotTo(HaveOccurred()) Expect(password).To(Equal("fake-password")) }) It("writes the passwords to different files for each user", func() { err := platform.SetUserPassword("user-name1", "fake-password1") Expect(err).NotTo(HaveOccurred()) err = platform.SetUserPassword("user-name2", "fake-password2") Expect(err).NotTo(HaveOccurred()) userPasswordsPath := filepath.Join(dirProvider.BoshDir(), "user-name1", CredentialFileName) password, err := fs.ReadFileString(userPasswordsPath) Expect(err).NotTo(HaveOccurred()) Expect(password).To(Equal("fake-password1")) userPasswordsPath = filepath.Join(dirProvider.BoshDir(), "user-name2", CredentialFileName) password, err = fs.ReadFileString(userPasswordsPath) Expect(err).NotTo(HaveOccurred()) Expect(password).To(Equal("fake-password2")) }) }) Describe("SetupDataDir", func() { It("creates a link from BASEDIR/sys to BASEDIR/data/sys", func() { err := platform.SetupDataDir() Expect(err).NotTo(HaveOccurred()) stat := fs.GetFileTestStat(filepath.Clean("/fake-dir/sys")) Expect(stat).ToNot(BeNil()) Expect(stat.SymlinkTarget).To(Equal("/fake-dir/data/sys")) }) }) Describe("SetupBlobsDir", func() { It("creates a blobs folder under BASEDIR/DATADIR with correct permissions", func() { err := platform.SetupBlobsDir() Expect(err).NotTo(HaveOccurred()) stat := fs.GetFileTestStat(filepath.Clean("/fake-dir/data/blobs")) Expect(stat.FileType).To(Equal(fakesys.FakeFileTypeDir)) Expect(stat.FileMode).To(Equal(os.FileMode(0700))) }) }) }
func init() { Describe("concreteV1Service", func() { var ( fs *fakesys.FakeFileSystem specPath = "/spec.json" service V1Service ) BeforeEach(func() { fs = fakesys.NewFakeFileSystem() service = NewConcreteV1Service(fs, specPath) }) Describe("Get", func() { Context("when filesystem has a spec file", func() { BeforeEach(func() { fs.WriteFileString(specPath, `{"deployment":"fake-deployment-name"}`) }) It("reads spec from filesystem", func() { spec, err := service.Get() Expect(err).ToNot(HaveOccurred()) Expect(spec).To(Equal(V1ApplySpec{Deployment: "fake-deployment-name"})) }) It("returns error if reading spec from filesystem errs", func() { fs.ReadFileError = errors.New("fake-read-error") spec, err := service.Get() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-read-error")) Expect(spec).To(Equal(V1ApplySpec{})) }) }) Context("when filesystem does not have a spec file", func() { It("reads spec from filesystem", func() { spec, err := service.Get() Expect(err).ToNot(HaveOccurred()) Expect(spec).To(Equal(V1ApplySpec{})) }) }) }) Describe("Set", func() { newSpec := V1ApplySpec{Deployment: "fake-deployment-name"} It("writes spec to filesystem", func() { err := service.Set(newSpec) Expect(err).ToNot(HaveOccurred()) specPathStats := fs.GetFileTestStat(specPath) Expect(specPathStats).ToNot(BeNil()) boshassert.MatchesJSONBytes(GinkgoT(), newSpec, specPathStats.Content) }) It("returns error if writing spec to filesystem errs", func() { fs.WriteFileError = errors.New("fake-write-error") err := service.Set(newSpec) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-write-error")) }) }) Describe("PopulateDHCPNetworks", func() { var settings boshsettings.Settings var unresolvedSpec V1ApplySpec var staticSpec NetworkSpec var dhcpSpec NetworkSpec var manualSetting boshsettings.Network var dynamicSetting boshsettings.Network BeforeEach(func() { settings = boshsettings.Settings{ Networks: boshsettings.Networks{}, } manualSetting = boshsettings.Network{ Type: "manual", IP: "fake-manual-ip", Netmask: "fake-manual-netmask", Gateway: "fake-manual-gateway", Mac: "fake-manual-mac", } dynamicSetting = boshsettings.Network{ Type: "dynamic", IP: "fake-dynamic-ip", Netmask: "fake-dynamic-netmask", Gateway: "fake-dynamic-gateway", } unresolvedSpec = V1ApplySpec{ Deployment: "fake-deployment", NetworkSpecs: map[string]NetworkSpec{}, } staticSpec = NetworkSpec{ Fields: map[string]interface{}{ "ip": "fake-net1-ip", "netmask": "fake-net1-netmask", "gateway": "fake-net1-gateway", "mac": "fake-net1-mac", }, } dhcpSpec = NetworkSpec{ Fields: map[string]interface{}{ "type": NetworkSpecTypeDynamic, "ip": "fake-net2-ip", "netmask": "fake-net2-netmask", "gateway": "fake-net2-gateway", }, } }) Context("when associated network is in settings", func() { Context("when there are no networks configured with DHCP", func() { BeforeEach(func() { settings.Networks["fake-net"] = manualSetting unresolvedSpec.NetworkSpecs["fake-net"] = staticSpec }) It("returns spec without modifying any networks", func() { spec, err := service.PopulateDHCPNetworks(unresolvedSpec, settings) Expect(err).ToNot(HaveOccurred()) Expect(spec).To(Equal(unresolvedSpec)) }) }) Context("when there is network with name 'local' and ip 127.0.0.1", func() { BeforeEach(func() { unresolvedSpec.NetworkSpecs["local"] = NetworkSpec{ Fields: map[string]interface{}{"ip": "127.0.0.1"}, } }) It("returns spec without modifying any networks", func() { spec, err := service.PopulateDHCPNetworks(unresolvedSpec, settings) Expect(err).ToNot(HaveOccurred()) Expect(spec).To(Equal(unresolvedSpec)) }) }) Context("when there are networks configured with DHCP", func() { BeforeEach(func() { settings.Networks["static-net1"] = manualSetting settings.Networks["dhcp-net2"] = dynamicSetting unresolvedSpec.NetworkSpecs["static-net1"] = staticSpec unresolvedSpec.NetworkSpecs["dhcp-net2"] = dhcpSpec }) It("returns spec with networks modified via DHCP and keeps everything else the same", func() { spec, err := service.PopulateDHCPNetworks(unresolvedSpec, settings) Expect(err).ToNot(HaveOccurred()) Expect(spec).To(Equal(V1ApplySpec{ Deployment: "fake-deployment", NetworkSpecs: map[string]NetworkSpec{ "static-net1": staticSpec, "dhcp-net2": NetworkSpec{ Fields: map[string]interface{}{ "type": NetworkSpecTypeDynamic, "ip": dynamicSetting.IP, "netmask": dynamicSetting.Netmask, "gateway": dynamicSetting.Gateway, }, }, }, })) }) }) }) Context("when associated network cannot be found in settings", func() { BeforeEach(func() { settings.Networks["net-present-in-settings"] = manualSetting unresolvedSpec.NetworkSpecs["net-present-in-settings"] = staticSpec unresolvedSpec.NetworkSpecs["net-not-present-in-settings"] = dhcpSpec }) It("returns error", func() { spec, err := service.PopulateDHCPNetworks(unresolvedSpec, settings) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Network 'net-not-present-in-settings' is not found in settings")) Expect(spec).To(Equal(V1ApplySpec{})) }) }) }) }) }