BeforeEach(func() { compressor = fakecmd.NewFakeCompressor() fs = fakesys.NewFakeFileSystem() stemcellReader = NewReader(compressor, fs) manifestContents := ` --- name: fake-stemcell-name version: '2690' cloud_properties: infrastructure: aws ami: us-east-1: fake-ami-version ` fs.WriteFileString("fake-extracted-path/stemcell.MF", manifestContents) }) It("extracts the stemcells from a stemcell path", func() { _, err := stemcellReader.Read("fake-stemcell-path", "fake-extracted-path") Expect(err).ToNot(HaveOccurred()) Expect(compressor.DecompressFileToDirTarballPaths).To(ContainElement("fake-stemcell-path")) Expect(compressor.DecompressFileToDirDirs).To(ContainElement("fake-extracted-path")) }) It("generates correct stemcell", func() { stemcell, err := stemcellReader.Read("fake-stemcell-path", "fake-extracted-path") Expect(err).ToNot(HaveOccurred()) expectedStemcell := NewExtractedStemcell( Manifest{ Name: "fake-stemcell-name",
result := cert.SplitCerts("abcdefghij") Expect(len(result)).To(Equal(0)) }) }) Describe("DeleteFile()", func() { var ( fakeFs *fakesys.FakeFileSystem ) BeforeEach(func() { fakeFs = fakesys.NewFakeFileSystem() }) It("only deletes the files with the given prefix", func() { fakeFs.WriteFileString("/path/to/delete/stuff/in/delete_me_1.foo", "goodbye") fakeFs.WriteFileString("/path/to/delete/stuff/in/delete_me_2.foo", "goodbye") fakeFs.WriteFileString("/path/to/delete/stuff/in/different_file_1.bar", "goodbye") fakeFs.SetGlob("/path/to/delete/stuff/in/delete_me_*", []string{ "/path/to/delete/stuff/in/delete_me_1.foo", "/path/to/delete/stuff/in/delete_me_2.foo", }) count, err := cert.DeleteFiles(fakeFs, "/path/to/delete/stuff/in/", "delete_me_") Expect(err).ToNot(HaveOccurred()) Expect(count).To(Equal(2)) Expect(countFiles(fakeFs, "/path/to/delete/stuff/in/")).To(Equal(1)) }) It("only deletes the files in the given path", func() { fakeFs.WriteFileString("/path/to/delete/stuff/in/delete_me_1.foo", "goodbye") fakeFs.WriteFileString("/path/to/delete/stuff/in/delete_me_2.foo", "goodbye")
fs = fakesys.NewFakeFileSystem() logger := boshlog.NewLogger(boshlog.LevelNone) metadataService = NewFileMetadataService( "fake-metadata-file-path", "fake-userdata-file-path", "fake-settings-file-path", fs, logger, ) }) Describe("GetInstanceID", func() { Context("when metadata service file exists", func() { BeforeEach(func() { metadataContents := `{"instance-id":"fake-instance-id"}` fs.WriteFileString("fake-metadata-file-path", metadataContents) }) It("returns instance id", func() { instanceID, err := metadataService.GetInstanceID() Expect(err).NotTo(HaveOccurred()) Expect(instanceID).To(Equal("fake-instance-id")) }) }) Context("when metadata service file does not exist", func() { It("returns an error", func() { _, err := metadataService.GetInstanceID() Expect(err).To(HaveOccurred()) }) })
fs.WriteFileString("/fake-config.conf", `{ "Platform": { "Linux": { "UseDefaultTmpDir": true, "UsePreformattedPersistentDisk": true, "BindMountPersistentDisk": true, "DevicePathResolutionType": "virtio" } }, "Infrastructure": { "Settings": { "Sources": [ { "Type": "HTTP", "URI": "http://fake-uri" }, { "Type": "ConfigDrive", "DiskPaths": ["/fake-disk-path1", "/fake-disk-path2"], "MetaDataPath": "/fake-metadata-path", "UserDataPath": "/fake-userdata-path", "SettingsPath": "/fake-settings-path" }, { "Type": "File", "MetaDataPath": "/fake-metadata-path", "UserDataPath": "/fake-userdata-path", "SettingsPath": "/fake-settings-path" }, { "Type": "CDROM", "FileName": "/fake-file-name" } ], "UseServerName": true, "UseRegistry": true } } }`)
Expect(disks).To(HaveLen(1)) Expect(disks[0].CID()).To(Equal("fake-existing-disk-cid")) }) }) Context("when disk does not exists in disk repo", func() { It("returns an empty array", func() { disks, err := manager.FindCurrent() Expect(err).ToNot(HaveOccurred()) Expect(disks).To(BeEmpty()) }) }) Context("when reading disk repo fails", func() { BeforeEach(func() { fakeFs.WriteFileString("/fake/path", "{}") fakeFs.ReadFileError = errors.New("fake-read-error") }) It("returns an error", func() { _, err := manager.FindCurrent() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-read-error")) }) }) }) Describe("FindUnused", func() { var ( firstDisk bidisk.Disk thirdDisk bidisk.Disk
Describe("Start", func() { It("start starts each monit service in group vcap", func() { client.ServicesInGroupServices = []string{"fake-service"} err := monit.Start() Expect(err).ToNot(HaveOccurred()) Expect(client.ServicesInGroupName).To(Equal("vcap")) Expect(len(client.StartServiceNames)).To(Equal(1)) Expect(client.StartServiceNames[0]).To(Equal("fake-service")) }) It("deletes stopped file", func() { fs.MkdirAll("/var/vcap/monit/stopped", os.FileMode(0755)) fs.WriteFileString("/var/vcap/monit/stopped", "") err := monit.Start() Expect(err).ToNot(HaveOccurred()) Expect(fs.FileExists("/var/vcap/monit/stopped")).ToNot(BeTrue()) }) It("does not fail if stopped file is not present", func() { err := monit.Start() Expect(err).ToNot(HaveOccurred()) }) }) Describe("Stop", func() { It("stop stops each monit service in group vcap", func() { client.ServicesInGroupServices = []string{"fake-service"}
}) }) }) }) 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))) }) }) })
BeforeEach(func() { compressor = fakecmd.NewFakeCompressor() fakeFs = fakesys.NewFakeFileSystem() reader = NewReader("/some/job/archive", "/extracted/job", compressor, fakeFs) }) Context("when the job archive is a valid tar", func() { Context("when the job manifest is valid", func() { BeforeEach(func() { fakeFs.WriteFileString( "/extracted/job/job.MF", `--- name: fake-job templates: some_template: some_file packages: - fake-package properties: fake-property: description: "Fake description" default: "fake-default" `, ) }) It("returns a job with the details from the manifest", func() { job, err := reader.Read() Expect(err).NotTo(HaveOccurred()) Expect(job).To(Equal( Job{ Name: "fake-job", Templates: map[string]string{"some_template": "some_file"},
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")) }) }) }
Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Not supported")) }) Context("when sync_dns is recieved", func() { Context("when blobstore contains DNS records", func() { BeforeEach(func() { fakeDNSRecordsString := ` { "records": [ ["fake-ip0", "fake-name0"], ["fake-ip1", "fake-name1"] ] }` err := fakeFileSystem.WriteFileString("fake-blobstore-file-path", fakeDNSRecordsString) Expect(err).ToNot(HaveOccurred()) fakeBlobstore.GetFileName = "fake-blobstore-file-path" }) It("accesses the blobstore and fetches DNS records", func() { response, err := syncDNS.Run("fake-blobstore-id", "fake-fingerprint") Expect(err).ToNot(HaveOccurred()) Expect(response).To(Equal("synced")) Expect(fakeBlobstore.GetBlobIDs).To(ContainElement("fake-blobstore-id")) Expect(fakeBlobstore.GetFingerprints).To(ContainElement("fake-fingerprint")) Expect(fakeBlobstore.GetError).ToNot(HaveOccurred()) Expect(fakeBlobstore.GetFileName).ToNot(Equal(""))
cache Cache fs *fakesys.FakeFileSystem ) BeforeEach(func() { logger := boshlog.NewLogger(boshlog.LevelNone) fs = fakesys.NewFakeFileSystem() cache = NewCache( "/fake-base-path", fs, logger, ) }) It("is a cache hit when the tarball with that url and sha1 has been downloaded", func() { fs.WriteFileString("source-path", "") err := cache.Save("source-path", &fakeSource{ sha1: "fake-sha1", url: "http://foo.bar.com", description: "some tarball", }) Expect(err).ToNot(HaveOccurred()) path, found := cache.Get(&fakeSource{ sha1: "fake-sha1", url: "http://foo.bar.com", description: "some tarball", }) Expect(found).To(BeTrue()) Expect(fs.FileExists(path)).To(BeTrue())
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{})) }) }) }) }
fakeFs = fakesys.NewFakeFileSystem() logger := boshlog.NewLogger(boshlog.LevelNone) fakeValidator = fakes.NewFakeValidator() fakeValidator.SetValidateBehavior([]fakes.ValidateOutput{ {Err: nil}, }) parser = manifest.NewParser(fakeFs, logger, fakeValidator) fakeFs.WriteFileString(comboManifestPath, ` --- releases: - name: fake-release-name-1 url: file://~/absolute-path/fake-release-1.tgz sha1: fake-sha1 - name: fake-release-name-2 url: file:///absolute-path/fake-release-2.tgz sha1: fake-sha2 - name: fake-release-name-3 url: file://relative-path/fake-release-3.tgz sha1: fake-sha3 - name: fake-release-name-4 url: http://fake-url/fake-release-4.tgz sha1: fake-sha4 name: unknown-keys-are-ignored `) }) Context("when combo manifest path does not exist", func() { BeforeEach(func() { err := fakeFs.RemoveAll(comboManifestPath) Expect(err).ToNot(HaveOccurred()) })
failureHandler := func(alert boshalert.MonitAlert) (err error) { didHandleAlert = true return } go monit.MonitorJobFailures(failureHandler) err := doJobFailureEmail(`fake-other-email`, jobFailuresServerPort) Expect(err).ToNot(HaveOccurred()) Expect(didHandleAlert).To(BeFalse()) }) }) Describe("AddJob", func() { BeforeEach(func() { fs.WriteFileString("/some/config/path", "fake-config") }) Context("when reading configuration from config path succeeds", func() { Context("when writing job configuration succeeds", func() { It("returns no error because monit can track added job in jobs directory", func() { err := monit.AddJob("router", 0, "/some/config/path") Expect(err).ToNot(HaveOccurred()) writtenConfig, err := fs.ReadFileString( dirProvider.MonitJobsDir() + "/0000_router.monitrc") Expect(err).ToNot(HaveOccurred()) Expect(writtenConfig).To(Equal("fake-config")) }) })
Expect(err.Error()).To(ContainSubstring("missing blobstore_path")) }) It("returns error when blobstore path is not a string", func() { options := map[string]interface{}{"blobstore_path": 443} blobstore = NewLocalBlobstore(fs, uuidGen, options) err := blobstore.Validate() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("blobstore_path must be a 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())) })
fs = fakesys.NewFakeFileSystem() sha1Calculator = NewSha1Calculator(fs) }) Describe("Calculate", func() { Context("when path is directory", func() { BeforeEach(func() { fs.RegisterOpenFile("/fake-templates-dir", &fakesys.FakeFile{ Stats: &fakesys.FakeFileStats{FileType: fakesys.FakeFileTypeDir}, }) fs.RegisterOpenFile("/fake-templates-dir/file-1", &fakesys.FakeFile{ Contents: []byte("fake-file-1-contents"), }) fs.WriteFileString("/fake-templates-dir/file-1", "fake-file-1-contents") fs.RegisterOpenFile("/fake-templates-dir/config/file-2", &fakesys.FakeFile{ Contents: []byte("fake-file-2-contents"), }) fs.MkdirAll("/fake-templates-dir/config", os.ModePerm) fs.WriteFileString("/fake-templates-dir/config/file-2", "fake-file-2-contents") }) It("returns sha1 of the all files in the directory", func() { sha1, err := sha1Calculator.Calculate("/fake-templates-dir") Expect(err).ToNot(HaveOccurred()) Expect(sha1).To(Equal("bc0646cd41b98cd6c878db7a0573eca345f78200")) }) })
networks: - name: vip static_ips: [1.2.3.4] - name: fake-network-name default: [dns] persistent_disk: 1024 persistent_disk_pool: fake-disk-pool-name resource_pool: fake-resource-pool properties: fake-prop-key: nested-prop-key: fake-prop-value properties: foo: bar: baz ` fakeFs.WriteFileString(comboManifestPath, contents) }) It("parses deployment manifest from combo manifest file", func() { deploymentManifest, err := parser.Parse(comboManifestPath) Expect(err).ToNot(HaveOccurred()) Expect(deploymentManifest).To(Equal(Manifest{ Name: "fake-deployment-name", Update: Update{ UpdateWatchTime: WatchTime{ Start: 2000, End: 7000, }, }, Networks: []Network{
. "github.com/onsi/gomega" bireljob "github.com/cloudfoundry/bosh-init/release/job" birelpkg "github.com/cloudfoundry/bosh-init/release/pkg" fakesys "github.com/cloudfoundry/bosh-utils/system/fakes" ) var _ = Describe("Validator", func() { var fakeFs *fakesys.FakeFileSystem BeforeEach(func() { fakeFs = fakesys.NewFakeFileSystem() }) It("validates a valid release without error", func() { fakeFs.WriteFileString("/some/job/path/monit", "") fakeFs.WriteFileString("/some/job/path/templates/fake-job-1-template", "") release := NewRelease( "fake-release-name", "fake-release-version", []bireljob.Job{ { Name: "fake-job-1-name", Fingerprint: "fake-job-1-fingerprint", SHA1: "fake-job-1-sha", Templates: map[string]string{"fake-job-1-template": "fake-job-1-file"}, ExtractedPath: "/some/job/path", }, }, []*birelpkg.Package{ {
Expect(s.Linux.HostsConfigured).To(BeFalse()) }) }) Context("When the path to the agent's state is ''", func() { It("returns an error and a state object with false properties", func() { s, err = platform.NewBootstrapState(fs, "") Expect(s.Linux.HostsConfigured).To(BeFalse()) }) }) Context("When the agent cannot read the state file due to a failed disk", func() { It("returns an error and a state object with false properties", func() { fs.WriteFileString(path, `{ "hosts_configured": true, "hostname_configured": true }`) fs.RegisterReadFileError(path, errors.New("ENXIO: disk failed")) _, readerr := platform.NewBootstrapState(fs, path) Expect(readerr.Error()).To(ContainSubstring("disk failed")) }) }) Context("When the agent cannot parse the state file due to malformed JSON", func() { It("returns an error and a state object with false properties", func() { fs.WriteFileString(path, "malformed-JSON") _, readerr := platform.NewBootstrapState(fs, path)
platform = NewWindowsPlatform( collector, fs, cmdRunner, dirProvider, netManager, certManager, devicePathResolver, logger, fakeDefaultNetworkResolver, ) }) Describe("GetFileContentsFromCDROM", func() { It("reads file from D drive", func() { fs.WriteFileString("D:/env", "fake-contents") contents, err := platform.GetFileContentsFromCDROM("env") Expect(err).NotTo(HaveOccurred()) Expect(contents).To(Equal([]byte("fake-contents"))) }) }) Describe("SetupNetworking", func() { It("delegates to the NetManager", func() { networks := boshsettings.Networks{} err := platform.SetupNetworking(networks) Expect(err).ToNot(HaveOccurred()) Expect(netManager.SetupNetworkingNetworks).To(Equal(networks)) })
BeforeEach(func() { fs = fakesys.NewFakeFileSystem() logger := boshlog.NewLogger(boshlog.LevelNone) cache = NewCache("/fake-base-path", fs, logger) sha1Calculator = fakebicrypto.NewFakeSha1Calculator() httpClient = fakebihttpclient.NewFakeHTTPClient() provider = NewProvider(cache, fs, httpClient, sha1Calculator, 3, 0, logger) fakeStage = fakebiui.NewFakeStage() }) Describe("Get", func() { Context("when URL starts with file://", func() { BeforeEach(func() { source = newFakeSource("file://fake-file", "fake-sha1", "fake-description") fs.WriteFileString("expanded-file-path", "") fs.ExpandPathExpanded = "expanded-file-path" }) It("returns expanded path to file", func() { path, err := provider.Get(source, fakeStage) Expect(err).ToNot(HaveOccurred()) Expect(path).To(Equal("expanded-file-path")) }) }) Context("when URL starts with http(s)://", func() { BeforeEach(func() { source = newFakeSource("http://fake-url", "fake-sha1", "fake-description") })
BeforeEach(func() { fakeFS = fakesys.NewFakeFileSystem() fakeUUIDGenerator = fakeuuid.NewFakeGenerator() logger = boshlog.NewLogger(boshlog.LevelNone) deploymentStateService = biconfig.NewFileSystemDeploymentStateService( fakeFS, fakeUUIDGenerator, logger, configPath, ) targetProvider = NewTargetProvider(deploymentStateService, fakeUUIDGenerator, installationsRootPath) }) Context("when the installation_id exists in the deployment state", func() { BeforeEach(func() { err := fakeFS.WriteFileString(configPath, `{"installation_id":"12345"}`) Expect(err).ToNot(HaveOccurred()) }) It("uses the existing installation_id & returns a target based on it", func() { target, err := targetProvider.NewTarget() Expect(err).ToNot(HaveOccurred()) Expect(target.Path()).To(Equal("/.bosh_init/installations/12345")) }) It("does not change the saved installation_id", func() { _, err := targetProvider.NewTarget() Expect(err).ToNot(HaveOccurred()) deploymentState, err := deploymentStateService.Load() Expect(err).ToNot(HaveOccurred())
func init() { Describe("bootstrap", func() { Describe("Run", func() { var ( platform *fakeplatform.FakePlatform dirProvider boshdir.Provider settingsSource *fakeinf.FakeSettingsSource settingsService *fakesettings.FakeSettingsService ) BeforeEach(func() { platform = fakeplatform.NewFakePlatform() dirProvider = boshdir.NewProvider("/var/vcap") settingsSource = &fakeinf.FakeSettingsSource{} settingsService = &fakesettings.FakeSettingsService{} }) bootstrap := func() error { logger := boshlog.NewLogger(boshlog.LevelNone) return NewBootstrap(platform, dirProvider, settingsService, logger).Run() } It("sets up runtime configuration", func() { err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(platform.SetupRuntimeConfigurationWasInvoked).To(BeTrue()) }) Describe("SSH tunnel setup for registry", func() { It("returns error without configuring ssh on the platform if getting public key fails", func() { settingsService.PublicKeyErr = errors.New("fake-get-public-key-err") err := bootstrap() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-get-public-key-err")) Expect(platform.SetupSSHCalled).To(BeFalse()) }) Context("when public key is not empty", func() { BeforeEach(func() { settingsService.PublicKey = "fake-public-key" }) It("gets the public key and sets up ssh via the platform", func() { err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(platform.SetupSSHPublicKey).To(Equal("fake-public-key")) Expect(platform.SetupSSHUsername).To(Equal("vcap")) }) It("returns error if configuring ssh on the platform fails", func() { platform.SetupSSHErr = errors.New("fake-setup-ssh-err") err := bootstrap() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-setup-ssh-err")) }) }) Context("when public key key is empty", func() { BeforeEach(func() { settingsSource.PublicKey = "" }) It("gets the public key and does not setup SSH", func() { err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(platform.SetupSSHCalled).To(BeFalse()) }) }) }) It("sets up hostname", func() { settingsService.Settings.AgentID = "foo-bar-baz-123" err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(platform.SetupHostnameHostname).To(Equal("foo-bar-baz-123")) }) It("fetches initial settings", func() { err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(settingsService.SettingsWereLoaded).To(BeTrue()) }) It("returns error from loading initial settings", func() { settingsService.LoadSettingsError = errors.New("fake-load-error") err := bootstrap() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-load-error")) }) It("sets up networking", func() { networks := boshsettings.Networks{ "bosh": boshsettings.Network{}, } settingsService.Settings.Networks = networks err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(platform.SetupNetworkingNetworks).To(Equal(networks)) }) It("sets up ephemeral disk", func() { settingsService.Settings.Disks = boshsettings.Disks{ Ephemeral: "fake-ephemeral-disk-setting", } platform.GetEphemeralDiskPathRealPath = "/dev/sda" err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(platform.SetupEphemeralDiskWithPathDevicePath).To(Equal("/dev/sda")) Expect(platform.GetEphemeralDiskPathSettings).To(Equal(boshsettings.DiskSettings{ VolumeID: "fake-ephemeral-disk-setting", Path: "fake-ephemeral-disk-setting", })) }) It("returns error if setting ephemeral disk fails", func() { platform.SetupEphemeralDiskWithPathErr = errors.New("fake-setup-ephemeral-disk-err") err := bootstrap() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-setup-ephemeral-disk-err")) }) It("sets up 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("returns error if set up of tmp dir fails", func() { platform.SetupTmpDirErr = errors.New("fake-setup-tmp-dir-err") err := bootstrap() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-setup-tmp-dir-err")) }) It("mounts persistent disk", func() { settingsService.Settings.Disks = boshsettings.Disks{ Persistent: map[string]interface{}{ "vol-123": map[string]interface{}{ "volume_id": "2", "path": "/dev/sdb", }, }, } err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(platform.MountPersistentDiskSettings).To(Equal(boshsettings.DiskSettings{ ID: "vol-123", VolumeID: "2", Path: "/dev/sdb", })) Expect(platform.MountPersistentDiskMountPoint).To(Equal(dirProvider.StoreDir())) }) It("errors if there is more than one persistent disk", func() { settingsService.Settings.Disks = boshsettings.Disks{ Persistent: map[string]interface{}{ "vol-123": "/dev/sdb", "vol-456": "/dev/sdc", }, } err := bootstrap() Expect(err).To(HaveOccurred()) }) It("does not try to mount when no persistent disk", func() { settingsService.Settings.Disks = boshsettings.Disks{ Persistent: map[string]interface{}{}, } err := bootstrap() Expect(err).NotTo(HaveOccurred()) Expect(platform.MountPersistentDiskSettings).To(Equal(boshsettings.DiskSettings{})) Expect(platform.MountPersistentDiskMountPoint).To(Equal("")) }) It("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("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.NewCpCopier(runner, fs, logger) sigarCollector := boshsigar.NewSigarStatsCollector(&sigar.ConcreteSigar{}) vitalsService := boshvitals.NewService(sigarCollector, dirProvider) ipResolver := boship.NewResolver(boship.NetworkInterfaceToAddrsFunc) arping := bosharp.NewArping(runner, fs, logger, boshplatform.ArpIterations, boshplatform.ArpIterationDelay, boshplatform.ArpInterfaceCheckDelay) interfaceConfigurationCreator := boshnet.NewInterfaceConfigurationCreator(logger) 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() routesSearcher := boshnet.NewCmdRoutesSearcher(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, 500*time.Millisecond, state, linuxOptions, logger, defaultNetworkResolver, ) }) JustBeforeEach(func() { settingsPath := filepath.Join("bosh", "settings.json") var settings boshsettings.Settings json.Unmarshal([]byte(settingsJSON), &settings) settingsSource := fakeinf.FakeSettingsSource{ PublicKey: "123", SettingsValue: settings, } settingsService := boshsettings.NewService( platform.GetFs(), settingsPath, settingsSource, platform, logger, ) boot = NewBootstrap( platform, dirProvider, settingsService, logger, ) }) Context("when a single network configuration is provided, with a MAC address", func() { BeforeEach(func() { settingsJSON = `{ "networks": { "netA": { "default": ["dns", "gateway"], "ip": "2.2.2.2", "dns": [ "8.8.8.8", "4.4.4.4" ], "netmask": "255.255.255.0", "gateway": "2.2.2.0", "mac": "aa:bb:cc" } } }` }) Context("and no physical network interfaces exist", func() { Context("and a single virtual network interface exists", func() { BeforeEach(func() { stubInterfaces([][]string{[]string{"lo", "aa:bb:cc", "virtual"}}) }) It("raises an error", func() { err := boot.Run() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Number of network settings '1' is greater than the number of network devices '0")) }) }) }) Context("and a single physical network interface exists", func() { BeforeEach(func() { stubInterfaces([][]string{[]string{"eth0", "aa:bb:cc", "physical"}}) 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()) }) }) }) }) }) }
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{})) }) }) }) }
expectFind = mockCompiledPackageRepo.EXPECT().Find(*pkg).Return(bistatepkg.CompiledPackageRecord{}, false, nil).AnyTimes() dep1 = bistatepkg.CompiledPackageRecord{ BlobID: "fake-dependency-blobstore-id-1", BlobSHA1: "fake-dependency-sha1-1", } mockCompiledPackageRepo.EXPECT().Find(*dependency1).Return(dep1, true, nil).AnyTimes() dep2 = bistatepkg.CompiledPackageRecord{ BlobID: "fake-dependency-blobstore-id-2", BlobSHA1: "fake-dependency-sha1-2", } mockCompiledPackageRepo.EXPECT().Find(*dependency2).Return(dep2, true, nil).AnyTimes() // packaging file created when source is extracted fs.WriteFileString(path.Join(pkg.ExtractedPath, "packaging"), "") compressor.CompressFilesInDirTarballPath = compiledPackageTarballPath record := bistatepkg.CompiledPackageRecord{ BlobID: "fake-blob-id", BlobSHA1: "fake-fingerprint", } expectSave = mockCompiledPackageRepo.EXPECT().Save(*pkg, record).AnyTimes() }) Context("when the compiled package repo already has the package", func() { JustBeforeEach(func() { compiledPkgRecord := bistatepkg.CompiledPackageRecord{ BlobSHA1: "fake-fingerprint", }
BeforeEach(func() { fakeFS = fakesys.NewFakeFileSystem() compressor = fakecmd.NewFakeCompressor() fakeReleaseValidator = fakebirel.NewFakeValidator() logger := boshlog.NewLogger(boshlog.LevelNone) releaseExtractor = NewExtractor(fakeFS, compressor, fakeReleaseValidator, logger) }) Describe("Extract", func() { var ( releaseTarballPath string ) BeforeEach(func() { releaseTarballPath = "/fake/release.tgz" fakeFS.WriteFileString(releaseTarballPath, "fake-tgz-contents") }) Context("when an extracted release directory can be created", func() { BeforeEach(func() { fakeFS.TempDirDirs = []string{"/extracted-release-path"} releaseContents := `--- name: fake-release-name version: fake-release-version packages: - name: fake-release-package-name version: fake-release-package-version fingerprint: fake-release-package-fingerprint sha1: fake-release-package-sha1 dependencies: []
func init() { Describe("concreteCompiler", func() { var ( compiler Compiler compressor *fakecmd.FakeCompressor blobstore *fakeblobstore.FakeBlobstore fs *fakesys.FakeFileSystem runner *fakecmdrunner.FakeFileLoggingCmdRunner packageApplier *fakepackages.FakeApplier packagesBc *fakebc.FakeBundleCollection ) BeforeEach(func() { compressor = fakecmd.NewFakeCompressor() blobstore = &fakeblobstore.FakeBlobstore{} fs = fakesys.NewFakeFileSystem() runner = fakecmdrunner.NewFakeFileLoggingCmdRunner() packageApplier = fakepackages.NewFakeApplier() packagesBc = fakebc.NewFakeBundleCollection() compiler = NewConcreteCompiler( compressor, blobstore, fs, runner, FakeCompileDirProvider{Dir: "/fake-compile-dir"}, packageApplier, packagesBc, ) }) BeforeEach(func() { fs.MkdirAll("/fake-compile-dir", os.ModePerm) }) Describe("Compile", func() { var ( bundle *fakebc.FakeBundle pkg Package pkgDeps []boshmodels.Package ) BeforeEach(func() { bundle = packagesBc.FakeGet(boshmodels.Package{ Name: "pkg_name", Version: "pkg_version", }) bundle.InstallPath = "/fake-dir/data/packages/pkg_name/pkg_version" bundle.EnablePath = "/fake-dir/packages/pkg_name" compressor.CompressFilesInDirTarballPath = "/tmp/compressed-compiled-package" pkg, pkgDeps = getCompileArgs() }) It("returns blob id and sha1 of created compiled package", func() { blobstore.CreateBlobID = "fake-blob-id" blobstore.CreateFingerprint = "fake-blob-sha1" blobID, sha1, err := compiler.Compile(pkg, pkgDeps) Expect(err).ToNot(HaveOccurred()) Expect(blobID).To(Equal("fake-blob-id")) Expect(sha1).To(Equal("fake-blob-sha1")) }) It("cleans up all packages before and after applying dependent packages", func() { _, _, err := compiler.Compile(pkg, pkgDeps) Expect(err).ToNot(HaveOccurred()) Expect(packageApplier.ActionsCalled).To(Equal([]string{"KeepOnly", "Apply", "Apply", "KeepOnly"})) Expect(packageApplier.KeptOnlyPackages).To(BeEmpty()) }) It("returns an error if cleaning up packages fails", func() { packageApplier.KeepOnlyErr = errors.New("fake-keep-only-error") _, _, err := compiler.Compile(pkg, pkgDeps) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-keep-only-error")) }) It("fetches source package from blobstore without checking SHA1 by default because of Director bug", func() { _, _, err := compiler.Compile(pkg, pkgDeps) Expect(err).ToNot(HaveOccurred()) Expect(blobstore.GetBlobIDs[0]).To(Equal("blobstore_id")) Expect(blobstore.GetFingerprints[0]).To(Equal("")) }) PIt("(Pending Tracker Story: <https://www.pivotaltracker.com/story/show/94524232>) fetches source package from blobstore and checks SHA1 by default in future", func() { _, _, err := compiler.Compile(pkg, pkgDeps) Expect(err).ToNot(HaveOccurred()) Expect(blobstore.GetBlobIDs[0]).To(Equal("blobstore_id")) Expect(blobstore.GetFingerprints[0]).To(Equal("sha1")) }) It("returns an error if removing compile target directory during uncompression fails", func() { fs.RemoveAllStub = func(path string) error { if path == "/fake-compile-dir/pkg_name" { return errors.New("fake-remove-error") } return nil } _, _, err := compiler.Compile(pkg, pkgDeps) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-remove-error")) }) It("returns an error if creating compile target directory during uncompression fails", func() { fs.RemoveAllStub = func(path string) error { if path == "/fake-compile-dir/pkg_name" { return errors.New("fake-mkdir-error") } return nil } _, _, err := compiler.Compile(pkg, pkgDeps) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-mkdir-error")) }) It("returns an error if removing temporary compile target directory during uncompression fails", func() { fs.RemoveAllStub = func(path string) error { if path == "/fake-compile-dir/pkg_name-bosh-agent-unpack" { return errors.New("fake-remove-error") } return nil } _, _, err := compiler.Compile(pkg, pkgDeps) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-remove-error")) }) It("returns an error if creating temporary compile target directory during uncompression fails", func() { fs.RegisterMkdirAllError("/fake-compile-dir/pkg_name-bosh-agent-unpack", errors.New("fake-mkdir-error")) _, _, err := compiler.Compile(pkg, pkgDeps) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-mkdir-error")) }) It("returns an error if target directory is empty during uncompression", func() { pkg.BlobstoreID = "" _, _, err := compiler.Compile(pkg, pkgDeps) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Blobstore ID for package '%s' is empty", pkg.Name)) }) It("installs dependent packages", func() { _, _, err := compiler.Compile(pkg, pkgDeps) Expect(err).ToNot(HaveOccurred()) Expect(packageApplier.AppliedPackages).To(Equal(pkgDeps)) }) It("cleans up the compile directory", func() { _, _, err := compiler.Compile(pkg, pkgDeps) Expect(err).ToNot(HaveOccurred()) Expect(fs.FileExists("/fake-compile-dir/pkg_name")).To(BeFalse()) }) It("installs, enables and later cleans up bundle", func() { _, _, err := compiler.Compile(pkg, pkgDeps) Expect(err).ToNot(HaveOccurred()) Expect(bundle.ActionsCalled).To(Equal([]string{ "InstallWithoutContents", "Enable", "Disable", "Uninstall", })) }) It("returns an error if removing the compile directory fails", func() { callCount := 0 fs.RemoveAllStub = func(path string) error { if path == "/fake-compile-dir/pkg_name" { callCount++ if callCount > 1 { return errors.New("fake-remove-error") } } return nil } _, _, err := compiler.Compile(pkg, pkgDeps) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-remove-error")) }) Context("when packaging script exists", func() { const packagingScriptContents = "hi" BeforeEach(func() { compressor.DecompressFileToDirCallBack = func() { filename := "/fake-compile-dir/pkg_name/" + PackagingScriptName fs.WriteFileString(filename, packagingScriptContents) } }) It("runs packaging script ", func() { _, _, err := compiler.Compile(pkg, pkgDeps) Expect(err).ToNot(HaveOccurred()) expectedCmd := boshsys.Command{ Env: map[string]string{ "BOSH_COMPILE_TARGET": "/fake-compile-dir/pkg_name", "BOSH_INSTALL_TARGET": "/fake-dir/packages/pkg_name", "BOSH_PACKAGE_NAME": "pkg_name", "BOSH_PACKAGE_VERSION": "pkg_version", }, WorkingDir: "/fake-compile-dir/pkg_name", } cmd := runner.RunCommands[0] if runtime.GOOS == "windows" { expectedCmd.Name = "powershell" expectedCmd.Args = []string{"-command", fmt.Sprintf(`"iex (get-content -raw %s)"`, PackagingScriptName)} } else { expectedCmd.Name = "bash" expectedCmd.Args = []string{"-x", PackagingScriptName} } Expect(cmd).To(Equal(expectedCmd)) Expect(len(runner.RunCommands)).To(Equal(1)) Expect(runner.RunCommandJobName).To(Equal("compilation")) Expect(runner.RunCommandTaskName).To(Equal(PackagingScriptName)) }) It("propagates the error from packaging script", func() { runner.RunCommandErr = errors.New("fake-packaging-error") _, _, err := compiler.Compile(pkg, pkgDeps) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-packaging-error")) }) }) It("does not run packaging script when script does not exist", func() { _, _, err := compiler.Compile(pkg, pkgDeps) Expect(err).ToNot(HaveOccurred()) Expect(runner.RunCommands).To(BeEmpty()) }) It("compresses compiled package", func() { _, _, err := compiler.Compile(pkg, pkgDeps) Expect(err).ToNot(HaveOccurred()) // archive was downloaded from the blobstore and decompress to this temp dir Expect(compressor.DecompressFileToDirDirs[0]).To(Equal("/fake-compile-dir/pkg_name-bosh-agent-unpack")) Expect(compressor.DecompressFileToDirTarballPaths[0]).To(Equal(blobstore.GetFileName)) // contents were moved from the temp dir to the install/enable dir Expect(fs.RenameOldPaths[0]).To(Equal("/fake-compile-dir/pkg_name-bosh-agent-unpack")) Expect(fs.RenameNewPaths[0]).To(Equal("/fake-compile-dir/pkg_name")) // install path, presumably with your packaged code, was compressed installPath := "/fake-dir/data/packages/pkg_name/pkg_version" Expect(compressor.CompressFilesInDirDir).To(Equal(installPath)) }) It("uploads compressed package to blobstore", func() { compressor.CompressFilesInDirTarballPath = "/tmp/compressed-compiled-package" _, _, err := compiler.Compile(pkg, pkgDeps) Expect(err).ToNot(HaveOccurred()) Expect(blobstore.CreateFileNames[0]).To(Equal("/tmp/compressed-compiled-package")) }) It("returs error if uploading compressed package fails", func() { blobstore.CreateErr = errors.New("fake-create-err") _, _, err := compiler.Compile(pkg, pkgDeps) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-create-err")) }) It("cleans up compressed package after uploading it to blobstore", func() { var beforeCleanUpTarballPath, afterCleanUpTarballPath string blobstore.CreateCallBack = func() { beforeCleanUpTarballPath = compressor.CleanUpTarballPath } _, _, err := compiler.Compile(pkg, pkgDeps) Expect(err).ToNot(HaveOccurred()) // Compressed package is not cleaned up before blobstore upload Expect(beforeCleanUpTarballPath).To(Equal("")) // Deleted after it was uploaded afterCleanUpTarballPath = compressor.CleanUpTarballPath Expect(afterCleanUpTarballPath).To(Equal("/tmp/compressed-compiled-package")) }) }) }) }
func rootDesc() { var mockCtrl *gomock.Controller BeforeEach(func() { mockCtrl = gomock.NewController(GinkgoT()) }) AfterEach(func() { mockCtrl.Finish() }) Describe("Run", func() { var ( command bicmd.Cmd fakeFs *fakesys.FakeFileSystem stdOut *gbytes.Buffer stdErr *gbytes.Buffer userInterface biui.UI sha1Calculator crypto.SHA1Calculator manifestSHA1 string mockDeployer *mock_deployment.MockDeployer mockInstaller *mock_install.MockInstaller mockInstallerFactory *mock_install.MockInstallerFactory mockReleaseExtractor *mock_release.MockExtractor releaseManager birel.Manager mockRegistryServerManager *mock_registry.MockServerManager mockRegistryServer *mock_registry.MockServer mockAgentClient *mock_agentclient.MockAgentClient mockAgentClientFactory *mock_httpagent.MockAgentClientFactory mockCloudFactory *mock_cloud.MockFactory fakeCPIRelease *fakebirel.FakeRelease logger boshlog.Logger mockBlobstoreFactory *mock_blobstore.MockFactory mockBlobstore *mock_blobstore.MockBlobstore mockVMManagerFactory *mock_vm.MockManagerFactory fakeVMManager *fakebivm.FakeManager fakeStemcellExtractor *fakebistemcell.FakeExtractor mockStemcellManager *mock_stemcell.MockManager fakeStemcellManagerFactory *fakebistemcell.FakeManagerFactory fakeReleaseSetParser *fakebirelsetmanifest.FakeParser fakeInstallationParser *fakebiinstallmanifest.FakeParser fakeDeploymentParser *fakebideplmanifest.FakeParser mockLegacyDeploymentStateMigrator *mock_config.MockLegacyDeploymentStateMigrator setupDeploymentStateService biconfig.DeploymentStateService fakeDeploymentValidator *fakebideplval.FakeValidator directorID = "generated-director-uuid" fakeUUIDGenerator *fakeuuid.FakeGenerator configUUIDGenerator *fakeuuid.FakeGenerator fakeStage *fakebiui.FakeStage deploymentManifestPath string deploymentStatePath string cpiReleaseTarballPath string stemcellTarballPath string extractedStemcell bistemcell.ExtractedStemcell expectDeploy *gomock.Call mbusURL = "http://*****:*****@fake-mbus-endpoint" releaseSetManifest birelsetmanifest.Manifest boshDeploymentManifest bideplmanifest.Manifest installationManifest biinstallmanifest.Manifest cloud bicloud.Cloud cloudStemcell bistemcell.CloudStemcell expectLegacyMigrate *gomock.Call expectStemcellUpload *gomock.Call expectStemcellDeleteUnused *gomock.Call expectCPIReleaseExtract *gomock.Call expectInstall *gomock.Call expectNewCloud *gomock.Call ) BeforeEach(func() { logger = boshlog.NewLogger(boshlog.LevelNone) stdOut = gbytes.NewBuffer() stdErr = gbytes.NewBuffer() userInterface = biui.NewWriterUI(stdOut, stdErr, logger) fakeFs = fakesys.NewFakeFileSystem() fakeFs.EnableStrictTempRootBehavior() deploymentManifestPath = "/path/to/manifest.yml" deploymentStatePath = "/path/to/manifest-state.json" fakeFs.RegisterOpenFile(deploymentManifestPath, &fakesys.FakeFile{ Stats: &fakesys.FakeFileStats{FileType: fakesys.FakeFileTypeFile}, }) fakeFs.WriteFileString(deploymentManifestPath, "") mockDeployer = mock_deployment.NewMockDeployer(mockCtrl) mockInstaller = mock_install.NewMockInstaller(mockCtrl) mockInstallerFactory = mock_install.NewMockInstallerFactory(mockCtrl) mockReleaseExtractor = mock_release.NewMockExtractor(mockCtrl) releaseManager = birel.NewManager(logger) mockRegistryServerManager = mock_registry.NewMockServerManager(mockCtrl) mockRegistryServer = mock_registry.NewMockServer(mockCtrl) mockAgentClientFactory = mock_httpagent.NewMockAgentClientFactory(mockCtrl) mockAgentClient = mock_agentclient.NewMockAgentClient(mockCtrl) mockAgentClientFactory.EXPECT().NewAgentClient(gomock.Any(), gomock.Any()).Return(mockAgentClient).AnyTimes() mockCloudFactory = mock_cloud.NewMockFactory(mockCtrl) mockBlobstoreFactory = mock_blobstore.NewMockFactory(mockCtrl) mockBlobstore = mock_blobstore.NewMockBlobstore(mockCtrl) mockBlobstoreFactory.EXPECT().Create(mbusURL, gomock.Any()).Return(mockBlobstore, nil).AnyTimes() mockVMManagerFactory = mock_vm.NewMockManagerFactory(mockCtrl) fakeVMManager = fakebivm.NewFakeManager() mockVMManagerFactory.EXPECT().NewManager(gomock.Any(), mockAgentClient).Return(fakeVMManager).AnyTimes() fakeStemcellExtractor = fakebistemcell.NewFakeExtractor() mockStemcellManager = mock_stemcell.NewMockManager(mockCtrl) fakeStemcellManagerFactory = fakebistemcell.NewFakeManagerFactory() fakeReleaseSetParser = fakebirelsetmanifest.NewFakeParser() fakeInstallationParser = fakebiinstallmanifest.NewFakeParser() fakeDeploymentParser = fakebideplmanifest.NewFakeParser() mockLegacyDeploymentStateMigrator = mock_config.NewMockLegacyDeploymentStateMigrator(mockCtrl) configUUIDGenerator = &fakeuuid.FakeGenerator{} configUUIDGenerator.GeneratedUUID = directorID setupDeploymentStateService = biconfig.NewFileSystemDeploymentStateService(fakeFs, configUUIDGenerator, logger, biconfig.DeploymentStatePath(deploymentManifestPath)) fakeDeploymentValidator = fakebideplval.NewFakeValidator() fakeStage = fakebiui.NewFakeStage() sha1Calculator = crypto.NewSha1Calculator(fakeFs) fakeUUIDGenerator = &fakeuuid.FakeGenerator{} var err error manifestSHA1, err = sha1Calculator.Calculate(deploymentManifestPath) Expect(err).ToNot(HaveOccurred()) cpiReleaseTarballPath = "/release/tarball/path" stemcellTarballPath = "/stemcell/tarball/path" extractedStemcell = bistemcell.NewExtractedStemcell( bistemcell.Manifest{ ImagePath: "/stemcell/image/path", Name: "fake-stemcell-name", Version: "fake-stemcell-version", SHA1: "fake-stemcell-sha1", CloudProperties: biproperty.Map{}, OS: "ubuntu-trusty", }, "fake-extracted-path", fakeFs, ) // create input files fakeFs.WriteFileString(cpiReleaseTarballPath, "") fakeFs.WriteFileString(stemcellTarballPath, "") // deployment exists fakeFs.WriteFileString(deploymentManifestPath, "") // deployment is valid fakeDeploymentValidator.SetValidateBehavior([]fakebideplval.ValidateOutput{ {Err: nil}, }) fakeDeploymentValidator.SetValidateReleaseJobsBehavior([]fakebideplval.ValidateReleaseJobsOutput{ {Err: nil}, }) // stemcell exists fakeFs.WriteFile(stemcellTarballPath, []byte{}) releaseSetManifest = birelsetmanifest.Manifest{ Releases: []birelmanifest.ReleaseRef{ { Name: "fake-cpi-release-name", URL: "file://" + cpiReleaseTarballPath, }, }, } // parsed CPI deployment manifest installationManifest = biinstallmanifest.Manifest{ Template: biinstallmanifest.ReleaseJobRef{ Name: "fake-cpi-release-job-name", Release: "fake-cpi-release-name", }, Mbus: mbusURL, } // parsed BOSH deployment manifest boshDeploymentManifest = bideplmanifest.Manifest{ Name: "fake-deployment-name", Jobs: []bideplmanifest.Job{ { Name: "fake-job-name", }, }, ResourcePools: []bideplmanifest.ResourcePool{ { Stemcell: bideplmanifest.StemcellRef{ URL: "file://" + stemcellTarballPath, }, }, }, } fakeDeploymentParser.ParseManifest = boshDeploymentManifest // parsed/extracted CPI release fakeCPIRelease = fakebirel.NewFakeRelease() fakeCPIRelease.ReleaseName = "fake-cpi-release-name" fakeCPIRelease.ReleaseVersion = "1.0" fakeCPIRelease.ReleaseIsCompiled = false fakeCPIRelease.ReleaseJobs = []bireljob.Job{ { Name: "fake-cpi-release-job-name", Templates: map[string]string{ "templates/cpi.erb": "bin/cpi", }, }, } cloud = bicloud.NewCloud(fakebicloud.NewFakeCPICmdRunner(), "fake-director-id", logger) cloudStemcell = fakebistemcell.NewFakeCloudStemcell("fake-stemcell-cid", "fake-stemcell-name", "fake-stemcell-version") }) JustBeforeEach(func() { doGet := func(deploymentManifestPath string) (bicmd.DeploymentPreparer, error) { deploymentStateService := biconfig.NewFileSystemDeploymentStateService(fakeFs, configUUIDGenerator, logger, biconfig.DeploymentStatePath(deploymentManifestPath)) deploymentRepo := biconfig.NewDeploymentRepo(deploymentStateService) releaseRepo := biconfig.NewReleaseRepo(deploymentStateService, fakeUUIDGenerator) stemcellRepo := biconfig.NewStemcellRepo(deploymentStateService, fakeUUIDGenerator) deploymentRecord := deployment.NewRecord(deploymentRepo, releaseRepo, stemcellRepo, sha1Calculator) fakeHTTPClient := fakebihttpclient.NewFakeHTTPClient() tarballCache := bitarball.NewCache("fake-base-path", fakeFs, logger) tarballProvider := bitarball.NewProvider(tarballCache, fakeFs, fakeHTTPClient, sha1Calculator, 1, 0, logger) cpiInstaller := bicpirel.CpiInstaller{ ReleaseManager: releaseManager, InstallerFactory: mockInstallerFactory, Validator: bicpirel.NewValidator(), } releaseFetcher := birel.NewFetcher(tarballProvider, mockReleaseExtractor, releaseManager) stemcellFetcher := bistemcell.Fetcher{ TarballProvider: tarballProvider, StemcellExtractor: fakeStemcellExtractor, } releaseSetAndInstallationManifestParser := bicmd.ReleaseSetAndInstallationManifestParser{ ReleaseSetParser: fakeReleaseSetParser, InstallationParser: fakeInstallationParser, } deploymentManifestParser := bicmd.DeploymentManifestParser{ DeploymentParser: fakeDeploymentParser, DeploymentValidator: fakeDeploymentValidator, ReleaseManager: releaseManager, } fakeInstallationUUIDGenerator := &fakeuuid.FakeGenerator{} fakeInstallationUUIDGenerator.GeneratedUUID = "fake-installation-id" targetProvider := biinstall.NewTargetProvider( deploymentStateService, fakeInstallationUUIDGenerator, filepath.Join("fake-install-dir"), ) tempRootConfigurator := bicmd.NewTempRootConfigurator(fakeFs) return bicmd.NewDeploymentPreparer( userInterface, logger, "deployCmd", deploymentStateService, mockLegacyDeploymentStateMigrator, releaseManager, deploymentRecord, mockCloudFactory, fakeStemcellManagerFactory, mockAgentClientFactory, mockVMManagerFactory, mockBlobstoreFactory, mockDeployer, deploymentManifestPath, cpiInstaller, releaseFetcher, stemcellFetcher, releaseSetAndInstallationManifestParser, deploymentManifestParser, tempRootConfigurator, targetProvider, ), nil } command = bicmd.NewDeployCmd(userInterface, fakeFs, logger, doGet) expectLegacyMigrate = mockLegacyDeploymentStateMigrator.EXPECT().MigrateIfExists("/path/to/bosh-deployments.yml").AnyTimes() fakeStemcellExtractor.SetExtractBehavior(stemcellTarballPath, extractedStemcell, nil) fakeStemcellManagerFactory.SetNewManagerBehavior(cloud, mockStemcellManager) expectStemcellUpload = mockStemcellManager.EXPECT().Upload(extractedStemcell, fakeStage).Return(cloudStemcell, nil).AnyTimes() expectStemcellDeleteUnused = mockStemcellManager.EXPECT().DeleteUnused(fakeStage).AnyTimes() fakeReleaseSetParser.ParseManifest = releaseSetManifest fakeDeploymentParser.ParseManifest = boshDeploymentManifest fakeInstallationParser.ParseManifest = installationManifest installationPath := filepath.Join("fake-install-dir", "fake-installation-id") target := biinstall.NewTarget(installationPath) installedJob := biinstall.NewInstalledJob( biinstall.RenderedJobRef{ Name: "fake-cpi-release-job-name", }, filepath.Join(target.JobsPath(), "fake-cpi-release-job-name"), ) mockInstallerFactory.EXPECT().NewInstaller(target).Return(mockInstaller).AnyTimes() installation := biinstall.NewInstallation(target, installedJob, installationManifest, mockRegistryServerManager) expectInstall = mockInstaller.EXPECT().Install(installationManifest, gomock.Any()).Do(func(_ interface{}, stage biui.Stage) { Expect(fakeStage.SubStages).To(ContainElement(stage)) }).Return(installation, nil).AnyTimes() mockInstaller.EXPECT().Cleanup(installation).AnyTimes() mockDeployment := mock_deployment.NewMockDeployment(mockCtrl) expectDeploy = mockDeployer.EXPECT().Deploy( cloud, boshDeploymentManifest, cloudStemcell, installationManifest.Registry, fakeVMManager, mockBlobstore, gomock.Any(), ).Do(func(_, _, _, _, _, _ interface{}, stage biui.Stage) { Expect(fakeStage.SubStages).To(ContainElement(stage)) }).Return(mockDeployment, nil).AnyTimes() expectCPIReleaseExtract = mockReleaseExtractor.EXPECT().Extract(cpiReleaseTarballPath).Return(fakeCPIRelease, nil).AnyTimes() expectNewCloud = mockCloudFactory.EXPECT().NewCloud(installation, directorID).Return(cloud, nil).AnyTimes() }) It("prints the deployment manifest and state file", func() { err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).NotTo(HaveOccurred()) Expect(stdOut).To(gbytes.Say("Deployment manifest: '/path/to/manifest.yml'")) Expect(stdOut).To(gbytes.Say("Deployment state: '/path/to/manifest-state.json'")) }) It("does not migrate the legacy bosh-deployments.yml if manifest-state.json exists", func() { err := fakeFs.WriteFileString(deploymentStatePath, "{}") Expect(err).ToNot(HaveOccurred()) expectLegacyMigrate.Times(0) err = command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).NotTo(HaveOccurred()) Expect(fakeInstallationParser.ParsePath).To(Equal(deploymentManifestPath)) }) It("migrates the legacy bosh-deployments.yml if manifest-state.json does not exist", func() { err := fakeFs.RemoveAll(deploymentStatePath) Expect(err).ToNot(HaveOccurred()) expectLegacyMigrate.Return(true, nil).Times(1) err = command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).NotTo(HaveOccurred()) Expect(fakeInstallationParser.ParsePath).To(Equal(deploymentManifestPath)) Expect(stdOut).To(gbytes.Say("Deployment manifest: '/path/to/manifest.yml'")) Expect(stdOut).To(gbytes.Say("Deployment state: '/path/to/manifest-state.json'")) Expect(stdOut).To(gbytes.Say("Migrated legacy deployments file: '/path/to/bosh-deployments.yml'")) }) It("sets the temp root", func() { err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).NotTo(HaveOccurred()) Expect(fakeFs.TempRootPath).To(Equal("fake-install-dir/fake-installation-id/tmp")) }) Context("when setting the temp root fails", func() { It("returns an error", func() { fakeFs.ChangeTempRootErr = errors.New("fake ChangeTempRootErr") err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(Equal("Setting temp root: fake ChangeTempRootErr")) }) }) It("parses the installation manifest", func() { err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).NotTo(HaveOccurred()) Expect(fakeInstallationParser.ParsePath).To(Equal(deploymentManifestPath)) }) It("parses the deployment manifest", func() { err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).NotTo(HaveOccurred()) Expect(fakeDeploymentParser.ParsePath).To(Equal(deploymentManifestPath)) }) It("validates bosh deployment manifest", func() { err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).NotTo(HaveOccurred()) Expect(fakeDeploymentValidator.ValidateInputs).To(Equal([]fakebideplval.ValidateInput{ {Manifest: boshDeploymentManifest, ReleaseSetManifest: releaseSetManifest}, })) }) It("validates jobs in manifest refer to job in releases", func() { err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).NotTo(HaveOccurred()) Expect(fakeDeploymentValidator.ValidateReleaseJobsInputs).To(Equal([]fakebideplval.ValidateReleaseJobsInput{ {Manifest: boshDeploymentManifest, ReleaseManager: releaseManager}, })) }) It("logs validating stages", func() { err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).NotTo(HaveOccurred()) Expect(fakeStage.PerformCalls[0]).To(Equal(&fakebiui.PerformCall{ Name: "validating", Stage: &fakebiui.FakeStage{ PerformCalls: []*fakebiui.PerformCall{ {Name: "Validating release 'fake-cpi-release-name'"}, {Name: "Validating cpi release"}, {Name: "Validating deployment manifest"}, {Name: "Validating stemcell"}, }, }, })) }) It("extracts CPI release tarball", func() { expectCPIReleaseExtract.Times(1) err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).NotTo(HaveOccurred()) }) It("installs the CPI locally", func() { expectInstall.Times(1) expectNewCloud.Times(1) err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).NotTo(HaveOccurred()) }) It("adds a new 'installing CPI' event logger stage", func() { err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).NotTo(HaveOccurred()) Expect(fakeStage.PerformCalls[1]).To(Equal(&fakebiui.PerformCall{ Name: "installing CPI", Stage: &fakebiui.FakeStage{}, // mock installer doesn't add sub-stages })) }) It("adds a new 'Starting registry' event logger stage", func() { err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).NotTo(HaveOccurred()) Expect(fakeStage.PerformCalls[2]).To(Equal(&fakebiui.PerformCall{ Name: "Starting registry", })) }) Context("when the registry is configured", func() { BeforeEach(func() { installationManifest.Registry = biinstallmanifest.Registry{ Username: "******", Password: "******", Host: "fake-host", Port: 123, } }) It("starts & stops the registry", func() { mockRegistryServerManager.EXPECT().Start("fake-username", "fake-password", "fake-host", 123).Return(mockRegistryServer, nil) mockRegistryServer.EXPECT().Stop() err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).NotTo(HaveOccurred()) }) }) It("deletes the extracted CPI release", func() { err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).NotTo(HaveOccurred()) Expect(fakeCPIRelease.DeleteCalled).To(BeTrue()) }) It("extracts the stemcell", func() { err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).NotTo(HaveOccurred()) Expect(fakeStemcellExtractor.ExtractInputs).To(Equal([]fakebistemcell.ExtractInput{ {TarballPath: stemcellTarballPath}, })) }) It("uploads the stemcell", func() { expectStemcellUpload.Times(1) err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).ToNot(HaveOccurred()) }) It("adds a new 'deploying' event logger stage", func() { err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).NotTo(HaveOccurred()) Expect(fakeStage.PerformCalls[3]).To(Equal(&fakebiui.PerformCall{ Name: "deploying", Stage: &fakebiui.FakeStage{}, // mock deployer doesn't add sub-stages })) }) It("deploys", func() { expectDeploy.Times(1) err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).NotTo(HaveOccurred()) }) It("updates the deployment record", func() { err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).NotTo(HaveOccurred()) deploymentState, err := setupDeploymentStateService.Load() Expect(err).ToNot(HaveOccurred()) Expect(deploymentState.CurrentManifestSHA1).To(Equal(manifestSHA1)) Expect(deploymentState.Releases).To(Equal([]biconfig.ReleaseRecord{ { ID: "fake-uuid-0", Name: fakeCPIRelease.Name(), Version: fakeCPIRelease.Version(), }, })) }) It("deletes unused stemcells", func() { expectStemcellDeleteUnused.Times(1) err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).NotTo(HaveOccurred()) }) Context("when deployment has not changed", func() { JustBeforeEach(func() { previousDeploymentState := biconfig.DeploymentState{ DirectorID: directorID, CurrentReleaseIDs: []string{"my-release-id-1"}, Releases: []biconfig.ReleaseRecord{{ ID: "my-release-id-1", Name: fakeCPIRelease.Name(), Version: fakeCPIRelease.Version(), }}, CurrentStemcellID: "my-stemcellRecordID", Stemcells: []biconfig.StemcellRecord{{ ID: "my-stemcellRecordID", Name: cloudStemcell.Name(), Version: cloudStemcell.Version(), }}, CurrentManifestSHA1: manifestSHA1, } err := setupDeploymentStateService.Save(previousDeploymentState) Expect(err).ToNot(HaveOccurred()) }) It("skips deploy", func() { expectDeploy.Times(0) err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).NotTo(HaveOccurred()) Expect(stdOut).To(gbytes.Say("No deployment, stemcell or release changes. Skipping deploy.")) }) }) Context("when parsing the cpi deployment manifest fails", func() { BeforeEach(func() { fakeDeploymentParser.ParseErr = bosherr.Error("fake-parse-error") }) It("returns error", func() { err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Parsing deployment manifest")) Expect(err.Error()).To(ContainSubstring("fake-parse-error")) Expect(fakeDeploymentParser.ParsePath).To(Equal(deploymentManifestPath)) }) }) Context("when the cpi release does not contain a 'cpi' job", func() { BeforeEach(func() { fakeCPIRelease.ReleaseJobs = []bireljob.Job{ { Name: "not-cpi", }, } }) It("returns error", func() { err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(Equal("Invalid CPI release 'fake-cpi-release-name': CPI release must contain specified job 'fake-cpi-release-job-name'")) }) }) Context("when multiple releases are given", func() { var ( otherReleaseTarballPath string fakeOtherRelease *fakebirel.FakeRelease expectOtherReleaseExtract *gomock.Call ) BeforeEach(func() { otherReleaseTarballPath = "/path/to/other-release.tgz" fakeFs.WriteFileString(otherReleaseTarballPath, "") fakeOtherRelease = fakebirel.New("other-release", "1234") fakeOtherRelease.ReleaseJobs = []bireljob.Job{{Name: "not-cpi"}} expectOtherReleaseExtract = mockReleaseExtractor.EXPECT().Extract( otherReleaseTarballPath, ).Return(fakeOtherRelease, nil).AnyTimes() releaseSetManifest = birelsetmanifest.Manifest{ Releases: []birelmanifest.ReleaseRef{ { Name: "fake-cpi-release-name", URL: "file://" + cpiReleaseTarballPath, }, { Name: "other-release", URL: "file://" + otherReleaseTarballPath, }, }, } }) It("extracts all the release tarballs", func() { expectCPIReleaseExtract.Times(1) expectOtherReleaseExtract.Times(1) err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).NotTo(HaveOccurred()) }) It("installs the CPI release locally", func() { expectInstall.Times(1) expectNewCloud.Times(1) err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).NotTo(HaveOccurred()) }) It("updates the deployment record", func() { err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).NotTo(HaveOccurred()) deploymentState, err := setupDeploymentStateService.Load() Expect(err).ToNot(HaveOccurred()) Expect(deploymentState.CurrentManifestSHA1).To(Equal(manifestSHA1)) Expect(deploymentState.Releases).To(Equal([]biconfig.ReleaseRecord{ { ID: "fake-uuid-0", Name: fakeCPIRelease.Name(), Version: fakeCPIRelease.Version(), }, { ID: "fake-uuid-1", Name: fakeOtherRelease.Name(), Version: fakeOtherRelease.Version(), }, })) }) Context("when one of the releases in the deployment has changed", func() { JustBeforeEach(func() { olderReleaseVersion := "1233" Expect(fakeOtherRelease.Version()).ToNot(Equal(olderReleaseVersion)) previousDeploymentState := biconfig.DeploymentState{ DirectorID: directorID, CurrentReleaseIDs: []string{"existing-release-id-1", "existing-release-id-2"}, Releases: []biconfig.ReleaseRecord{ { ID: "existing-release-id-1", Name: fakeCPIRelease.Name(), Version: fakeCPIRelease.Version(), }, { ID: "existing-release-id-2", Name: fakeOtherRelease.Name(), Version: olderReleaseVersion, }, }, CurrentStemcellID: "my-stemcellRecordID", Stemcells: []biconfig.StemcellRecord{{ ID: "my-stemcellRecordID", Name: cloudStemcell.Name(), Version: cloudStemcell.Version(), }}, CurrentManifestSHA1: manifestSHA1, } err := setupDeploymentStateService.Save(previousDeploymentState) Expect(err).ToNot(HaveOccurred()) }) It("updates the deployment record, clearing out unused releases", func() { err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).NotTo(HaveOccurred()) deploymentState, err := setupDeploymentStateService.Load() Expect(err).ToNot(HaveOccurred()) Expect(deploymentState.CurrentManifestSHA1).To(Equal(manifestSHA1)) keys := []string{} ids := []string{} for _, releaseRecord := range deploymentState.Releases { keys = append(keys, fmt.Sprintf("%s-%s", releaseRecord.Name, releaseRecord.Version)) ids = append(ids, releaseRecord.ID) } Expect(deploymentState.CurrentReleaseIDs).To(ConsistOf(ids)) Expect(keys).To(ConsistOf([]string{ fmt.Sprintf("%s-%s", fakeCPIRelease.Name(), fakeCPIRelease.Version()), fmt.Sprintf("%s-%s", fakeOtherRelease.Name(), fakeOtherRelease.Version()), })) }) }) Context("when the deployment has not changed", func() { JustBeforeEach(func() { previousDeploymentState := biconfig.DeploymentState{ DirectorID: directorID, CurrentReleaseIDs: []string{"my-release-id-1", "my-release-id-2"}, Releases: []biconfig.ReleaseRecord{ { ID: "my-release-id-1", Name: fakeCPIRelease.Name(), Version: fakeCPIRelease.Version(), }, { ID: "my-release-id-2", Name: fakeOtherRelease.Name(), Version: fakeOtherRelease.Version(), }, }, CurrentStemcellID: "my-stemcellRecordID", Stemcells: []biconfig.StemcellRecord{{ ID: "my-stemcellRecordID", Name: cloudStemcell.Name(), Version: cloudStemcell.Version(), }}, CurrentManifestSHA1: manifestSHA1, } err := setupDeploymentStateService.Save(previousDeploymentState) Expect(err).ToNot(HaveOccurred()) }) It("skips deploy", func() { expectDeploy.Times(0) err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).NotTo(HaveOccurred()) Expect(stdOut).To(gbytes.Say("No deployment, stemcell or release changes. Skipping deploy.")) }) }) }) Context("when release name does not match the name in release tarball", func() { BeforeEach(func() { releaseSetManifest.Releases = []birelmanifest.ReleaseRef{ { Name: "fake-other-cpi-release-name", URL: "file://" + cpiReleaseTarballPath, }, } }) It("returns an error", func() { err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Release name 'fake-other-cpi-release-name' does not match the name in release tarball 'fake-cpi-release-name'")) }) }) Context("When the stemcell tarball does not exist", func() { JustBeforeEach(func() { fakeStemcellExtractor.SetExtractBehavior(stemcellTarballPath, extractedStemcell, errors.New("no-stemcell-there")) }) It("returns error", func() { err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("no-stemcell-there")) performCall := fakeStage.PerformCalls[0].Stage.PerformCalls[3] Expect(performCall.Name).To(Equal("Validating stemcell")) Expect(performCall.Error.Error()).To(ContainSubstring("no-stemcell-there")) }) }) Context("when release file does not exist", func() { BeforeEach(func() { mockReleaseExtractor.EXPECT().Extract(cpiReleaseTarballPath).Return(nil, errors.New("not there")) }) It("returns error", func() { err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("not there")) performCall := fakeStage.PerformCalls[0].Stage.PerformCalls[0] Expect(performCall.Name).To(Equal("Validating release 'fake-cpi-release-name'")) Expect(performCall.Error.Error()).To(ContainSubstring("not there")) }) }) Context("when the deployment state file does not exist", func() { BeforeEach(func() { fakeFs.RemoveAll(deploymentStatePath) }) It("creates a deployment state", func() { err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).ToNot(HaveOccurred()) deploymentState, err := setupDeploymentStateService.Load() Expect(err).ToNot(HaveOccurred()) Expect(deploymentState.DirectorID).To(Equal(directorID)) }) }) It("returns err when the deployment manifest does not exist", func() { fakeFs.RemoveAll(deploymentManifestPath) err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Deployment manifest does not exist at '/path/to/manifest.yml'")) Expect(stdErr).To(gbytes.Say("Deployment '/path/to/manifest.yml' does not exist")) }) Context("when the deployment manifest is invalid", func() { BeforeEach(func() { fakeDeploymentValidator.SetValidateBehavior([]fakebideplval.ValidateOutput{ {Err: bosherr.Error("fake-deployment-validation-error")}, }) }) It("returns err", func() { err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-deployment-validation-error")) }) It("logs the failed event log", func() { err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).To(HaveOccurred()) performCall := fakeStage.PerformCalls[0].Stage.PerformCalls[2] Expect(performCall.Name).To(Equal("Validating deployment manifest")) Expect(performCall.Error.Error()).To(Equal("Validating deployment manifest: fake-deployment-validation-error")) }) }) Context("when validating jobs fails", func() { BeforeEach(func() { fakeDeploymentValidator.SetValidateReleaseJobsBehavior([]fakebideplval.ValidateReleaseJobsOutput{ {Err: bosherr.Error("fake-jobs-validation-error")}, }) }) It("returns err", func() { err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-jobs-validation-error")) }) It("logs the failed event log", func() { err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).To(HaveOccurred()) performCall := fakeStage.PerformCalls[0].Stage.PerformCalls[2] Expect(performCall.Name).To(Equal("Validating deployment manifest")) Expect(performCall.Error.Error()).To(Equal("Validating deployment jobs refer to jobs in release: fake-jobs-validation-error")) }) }) It("returns err when number of arguments is not equal 1", func() { err := command.Run(fakeStage, []string{}) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Invalid usage")) err = command.Run(fakeStage, []string{"1", "2"}) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Invalid usage")) }) Context("when uploading stemcell fails", func() { JustBeforeEach(func() { expectStemcellUpload.Return(nil, bosherr.Error("fake-upload-error")) }) It("returns an error", func() { err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-upload-error")) }) }) Context("when deploy fails", func() { BeforeEach(func() { mockDeployer.EXPECT().Deploy( cloud, boshDeploymentManifest, cloudStemcell, installationManifest.Registry, fakeVMManager, mockBlobstore, gomock.Any(), ).Return(nil, errors.New("fake-deploy-error")).AnyTimes() previousDeploymentState := biconfig.DeploymentState{ CurrentReleaseIDs: []string{"my-release-id-1"}, Releases: []biconfig.ReleaseRecord{{ ID: "my-release-id-1", Name: fakeCPIRelease.Name(), Version: fakeCPIRelease.Version(), }}, CurrentManifestSHA1: "fake-manifest-sha", } setupDeploymentStateService.Save(previousDeploymentState) }) It("clears the deployment record", func() { err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-deploy-error")) deploymentState, err := setupDeploymentStateService.Load() Expect(err).ToNot(HaveOccurred()) Expect(deploymentState.CurrentManifestSHA1).To(Equal("")) Expect(deploymentState.Releases).To(Equal([]biconfig.ReleaseRecord{})) Expect(deploymentState.CurrentReleaseIDs).To(Equal([]string{})) }) }) Context("when compiled releases are being used", func() { var ( otherReleaseTarballPath string fakeOtherRelease *fakebirel.FakeRelease expectOtherReleaseExtract *gomock.Call ) BeforeEach(func() { otherReleaseTarballPath = "/path/to/other-release.tgz" fakeFs.WriteFileString(otherReleaseTarballPath, "") fakeOtherRelease = fakebirel.New("other-release", "1234") fakeOtherRelease.ReleaseIsCompiled = true fakeOtherRelease.ReleaseJobs = []bireljob.Job{{Name: "not-cpi"}} fakeOtherRelease.ReleasePackages = []*bipkg.Package{ { Stemcell: "ubuntu-trusty/fake-stemcell-version", }, } expectOtherReleaseExtract = mockReleaseExtractor.EXPECT().Extract( otherReleaseTarballPath, ).Return(fakeOtherRelease, nil).AnyTimes() releaseSetManifest = birelsetmanifest.Manifest{ Releases: []birelmanifest.ReleaseRef{ { Name: "fake-cpi-release-name", URL: "file://" + cpiReleaseTarballPath, }, { Name: "other-release", URL: "file://" + otherReleaseTarballPath, }, }, } boshDeploymentManifest = bideplmanifest.Manifest{ Name: "fake-deployment-name", Jobs: []bideplmanifest.Job{ { Name: "fake-job-name", Templates: []bideplmanifest.ReleaseJobRef{ { Release: "other-release", }, }, }, }, ResourcePools: []bideplmanifest.ResourcePool{ { Stemcell: bideplmanifest.StemcellRef{ URL: "file://" + stemcellTarballPath, }, }, }, } }) It("extracts the compiled release tarball", func() { expectOtherReleaseExtract.Times(1) err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).NotTo(HaveOccurred()) }) It("parse compiled releases correctly", func() { err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).ToNot(HaveOccurred()) }) It("returns error if compiled package stemcell does not match the deployment stemcell", func() { fakeOtherRelease.ReleasePackages = []*bipkg.Package{ { Stemcell: "ubuntu-trusty/wrong-version", }, } err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("OS/Version mismatch between deployment stemcell and compiled package stemcell for release 'other-release'")) }) It("returns error if CPI release is compiled", func() { fakeCPIRelease.ReleaseIsCompiled = true err := command.Run(fakeStage, []string{deploymentManifestPath}) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("CPI is not allowed to be a compiled release. The provided CPI release 'fake-cpi-release-name' is compiled")) }) }) }) }
var validConfig = Config{ SoftLayer: validSoftLayerConfig, Actions: validActionsOptions, } var _ = Describe("NewConfigFromPath", func() { var ( fs *fakesys.FakeFileSystem ) BeforeEach(func() { fs = fakesys.NewFakeFileSystem() }) It("returns error if config is not valid", func() { err := fs.WriteFileString("/config.json", "{}") Expect(err).ToNot(HaveOccurred()) _, err = NewConfigFromPath("/config.json", fs) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Validating config")) }) It("returns error if file contains invalid json", func() { err := fs.WriteFileString("/config.json", "-") Expect(err).ToNot(HaveOccurred()) _, err = NewConfigFromPath("/config.json", fs) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Unmarshalling config")) })
Expect(readErr).ToNot(HaveOccurred()) Expect(httpBody).To(Equal([]byte(`{"value":"expected value"}`))) }) Context("when incorrect http method is used", func() { It("returns a 404", func() { httpResponse, err := httpClient.Get(serverURL + "/agent") Expect(err).ToNot(HaveOccurred()) Expect(httpResponse.StatusCode).To(Equal(404)) }) }) }) Describe("GET /blobs", func() { It("returns data from file system", func() { fs.WriteFileString("/var/vcap/micro_bosh/data/cache/123-456-789", "Some data") httpResponse, err := httpClient.Get(serverURL + "/blobs/a5/123-456-789") for err != nil { httpResponse, err = httpClient.Get(serverURL + "/blobs/a5/123-456-789") } defer httpResponse.Body.Close() httpBody, readErr := ioutil.ReadAll(httpResponse.Body) Expect(readErr).ToNot(HaveOccurred()) Expect(httpResponse.StatusCode).To(Equal(200)) Expect(httpBody).To(Equal([]byte("Some data"))) }) It("closes the underlying file", func() {