func init() { Describe("ReleaseApplySpec", func() { var ( platform *fakeplatform.FakePlatform action ReleaseApplySpecAction ) BeforeEach(func() { platform = fakeplatform.NewFakePlatform() action = NewReleaseApplySpec(platform) }) It("is synchronous", func() { Expect(action.IsAsynchronous()).To(BeFalse()) }) It("is not persistent", func() { Expect(action.IsPersistent()).To(BeFalse()) }) It("run", func() { err := platform.GetFs().WriteFileString("/var/vcap/micro/apply_spec.json", `{"json":["objects"]}`) Expect(err).ToNot(HaveOccurred()) value, err := action.Run() Expect(err).ToNot(HaveOccurred()) Expect(value).To(Equal(map[string]interface{}{"json": []interface{}{"objects"}})) }) }) }
func buildSSHAction(settingsService boshsettings.Service) (*fakeplatform.FakePlatform, SSHAction) { platform := fakeplatform.NewFakePlatform() dirProvider := boshdirs.NewProvider("/foo") logger := boshlog.NewLogger(boshlog.LevelNone) action := NewSSH(settingsService, platform, dirProvider, logger) return platform, action }
func init() { Describe("Stop", func() { var ( jobSupervisor *fakejobsuper.FakeJobSupervisor platform *fakeplatform.FakePlatform settingsService *fakesettings.FakeSettingsService logger boshlog.Logger specService *fakeas.FakeV1Service dualDCSupport *nimbus.DualDCSupport action StopAction ) BeforeEach(func() { jobSupervisor = fakejobsuper.NewFakeJobSupervisor() platform = fakeplatform.NewFakePlatform() logger = boshlog.NewLogger(boshlog.LevelNone) specService = fakeas.NewFakeV1Service() settingsService = &fakesettings.FakeSettingsService{} dualDCSupport = nimbus.NewDualDCSupport( platform.GetRunner(), platform.GetFs(), platform.GetDirProvider(), specService, settingsService, logger, ) action = NewStop(jobSupervisor, dualDCSupport, platform) }) It("is asynchronous", func() { Expect(action.IsAsynchronous()).To(BeTrue()) }) It("is not persistent", func() { Expect(action.IsPersistent()).To(BeFalse()) }) It("returns stopped", func() { stopped, err := action.Run() Expect(err).ToNot(HaveOccurred()) Expect(stopped).To(Equal("stopped")) }) It("stops job supervisor services", func() { _, err := action.Run() Expect(err).ToNot(HaveOccurred()) Expect(jobSupervisor.Stopped).To(BeTrue()) }) }) }
func init() { Describe("ListDisk", func() { var ( settingsService *fakesettings.FakeSettingsService platform *fakeplatform.FakePlatform logger boshlog.Logger action ListDiskAction ) BeforeEach(func() { settingsService = &fakesettings.FakeSettingsService{} platform = fakeplatform.NewFakePlatform() logger = boshlog.NewLogger(boshlog.LevelNone) action = NewListDisk(settingsService, platform, logger) }) It("list disk should be synchronous", func() { Expect(action.IsAsynchronous()).To(BeFalse()) }) It("is not persistent", func() { Expect(action.IsPersistent()).To(BeFalse()) }) It("list disk run", func() { platform.MountedDevicePaths = []string{"/dev/sdb", "/dev/sdc"} settingsService.Settings.Disks = boshsettings.Disks{ Persistent: map[string]interface{}{ "volume-1": "/dev/sda", "volume-2": "/dev/sdb", "volume-3": "/dev/sdc", }, } value, err := action.Run() Expect(err).ToNot(HaveOccurred()) values, ok := value.([]string) Expect(ok).To(BeTrue()) Expect(values).To(ContainElement("volume-2")) Expect(values).To(ContainElement("volume-3")) Expect(len(values)).To(Equal(2)) }) }) }
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 buildMigrateDiskAction() (platform *fakeplatform.FakePlatform, action MigrateDiskAction) { platform = fakeplatform.NewFakePlatform() dirProvider := boshdirs.NewProvider("/foo") action = NewMigrateDisk(platform, dirProvider) return }
func init() { Describe("Agent", func() { var ( logger boshlog.Logger handler *fakembus.FakeHandler platform *fakeplatform.FakePlatform actionDispatcher *fakeagent.FakeActionDispatcher jobSupervisor *fakejobsuper.FakeJobSupervisor specService *fakeas.FakeV1Service syslogServer *fakesyslog.FakeServer settingsService *fakesettings.FakeSettingsService uuidGenerator *fakeuuid.FakeGenerator timeService *fakeclock.FakeClock agent Agent ) BeforeEach(func() { logger = boshlog.NewLogger(boshlog.LevelNone) handler = &fakembus.FakeHandler{} platform = fakeplatform.NewFakePlatform() actionDispatcher = &fakeagent.FakeActionDispatcher{} jobSupervisor = fakejobsuper.NewFakeJobSupervisor() specService = fakeas.NewFakeV1Service() syslogServer = &fakesyslog.FakeServer{} settingsService = &fakesettings.FakeSettingsService{} uuidGenerator = &fakeuuid.FakeGenerator{} timeService = fakeclock.NewFakeClock(time.Now()) agent = New( logger, handler, platform, actionDispatcher, jobSupervisor, specService, syslogServer, 5*time.Millisecond, settingsService, uuidGenerator, timeService, ) }) Describe("Run", func() { It("lets dispatcher handle requests arriving via handler", func() { err := agent.Run() Expect(err).ToNot(HaveOccurred()) expectedResp := boshhandler.NewValueResponse("pong") actionDispatcher.DispatchResp = expectedResp req := boshhandler.NewRequest("fake-reply", "fake-action", []byte("fake-payload")) resp := handler.RunFunc(req) Expect(actionDispatcher.DispatchReq).To(Equal(req)) Expect(resp).To(Equal(expectedResp)) }) It("resumes persistent actions *before* dispatching new requests", func() { resumedBeforeStartingToDispatch := false handler.RunCallBack = func() { resumedBeforeStartingToDispatch = actionDispatcher.ResumedPreviouslyDispatchedTasks } err := agent.Run() Expect(err).ToNot(HaveOccurred()) Expect(resumedBeforeStartingToDispatch).To(BeTrue()) }) Context("when heartbeats can be sent", func() { BeforeEach(func() { handler.KeepOnRunning() }) BeforeEach(func() { jobName := "fake-job" nodeID := "node-id" jobIndex := 1 specService.Spec = boshas.V1ApplySpec{ JobSpec: boshas.JobSpec{Name: &jobName}, Index: &jobIndex, NodeID: nodeID, } jobSupervisor.StatusStatus = "fake-state" platform.FakeVitalsService.GetVitals = boshvitals.Vitals{ Load: []string{"a", "b", "c"}, } }) expectedJobName := "fake-job" expectedJobIndex := 1 expectedNodeID := "node-id" expectedHb := Heartbeat{ Job: &expectedJobName, Index: &expectedJobIndex, JobState: "fake-state", NodeID: expectedNodeID, Vitals: boshvitals.Vitals{Load: []string{"a", "b", "c"}}, } It("sends initial heartbeat", func() { // Configure periodic heartbeat every 5 hours // so that we are sure that we will not receive it agent = New( logger, handler, platform, actionDispatcher, jobSupervisor, specService, syslogServer, 5*time.Hour, settingsService, uuidGenerator, timeService, ) // Immediately exit after sending initial heartbeat handler.SendErr = errors.New("stop") err := agent.Run() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("stop")) Expect(handler.SendInputs()).To(Equal([]fakembus.SendInput{ { Target: boshhandler.HealthMonitor, Topic: boshhandler.Heartbeat, Message: expectedHb, }, })) }) It("sends periodic heartbeats", func() { sentRequests := 0 handler.SendCallback = func(_ fakembus.SendInput) { sentRequests++ if sentRequests == 3 { handler.SendErr = errors.New("stop") } } err := agent.Run() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("stop")) Expect(handler.SendInputs()).To(Equal([]fakembus.SendInput{ { Target: boshhandler.HealthMonitor, Topic: boshhandler.Heartbeat, Message: expectedHb, }, { Target: boshhandler.HealthMonitor, Topic: boshhandler.Heartbeat, Message: expectedHb, }, { Target: boshhandler.HealthMonitor, Topic: boshhandler.Heartbeat, Message: expectedHb, }, })) }) }) Context("when the agent fails to get job spec for a heartbeat", func() { BeforeEach(func() { specService.GetErr = errors.New("fake-spec-service-error") handler.KeepOnRunning() }) It("returns the error", func() { err := agent.Run() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-spec-service-error")) }) }) Context("when the agent fails to get vitals for a heartbeat", func() { BeforeEach(func() { platform.FakeVitalsService.GetErr = errors.New("fake-vitals-service-error") handler.KeepOnRunning() }) It("returns the error", func() { err := agent.Run() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-vitals-service-error")) }) }) It("sends job monitoring alerts to health manager", func() { handler.KeepOnRunning() monitAlert := boshalert.MonitAlert{ ID: "fake-monit-alert", Service: "fake-service", Event: "fake-event", Action: "fake-action", Date: "Sun, 22 May 2011 20:07:41 +0500", Description: "fake-description", } jobSupervisor.JobFailureAlert = &monitAlert // Fail the first time handler.Send is called for an alert (ignore heartbeats) handler.SendCallback = func(input fakembus.SendInput) { if input.Topic == boshhandler.Alert { handler.SendErr = errors.New("stop") } } err := agent.Run() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("stop")) expectedAlert := boshalert.Alert{ ID: "fake-monit-alert", Severity: boshalert.SeverityDefault, Title: "fake-service - fake-event - fake-action", Summary: "fake-description", CreatedAt: int64(1306076861), } Expect(handler.SendInputs()).To(ContainElement(fakembus.SendInput{ Target: boshhandler.HealthMonitor, Topic: boshhandler.Alert, Message: expectedAlert, })) }) It("sends ssh alerts to health manager", func() { handler.KeepOnRunning() syslogMsg := boshsyslog.Msg{Content: "disconnected by user"} syslogServer.StartFirstSyslogMsg = &syslogMsg uuidGenerator.GeneratedUUID = "fake-uuid" // Fail the first time handler.Send is called for an alert (ignore heartbeats) handler.SendCallback = func(input fakembus.SendInput) { if input.Topic == boshhandler.Alert { handler.SendErr = errors.New("stop") } } err := agent.Run() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("stop")) expectedAlert := boshalert.Alert{ ID: "fake-uuid", Severity: boshalert.SeverityWarning, Title: "SSH Logout", Summary: "disconnected by user", CreatedAt: timeService.Now().Unix(), } Expect(handler.SendInputs()).To(ContainElement(fakembus.SendInput{ Target: boshhandler.HealthMonitor, Topic: boshhandler.Alert, Message: expectedAlert, })) }) }) }) }
func init() { Describe("ApplyAction", func() { var ( applier *fakeappl.FakeApplier specService *fakeas.FakeV1Service settingsService *fakesettings.FakeSettingsService platform *fakeplatform.FakePlatform dualDCSupport *nimbus.DualDCSupport logger boshlog.Logger action ApplyAction ) BeforeEach(func() { applier = fakeappl.NewFakeApplier() specService = fakeas.NewFakeV1Service() settingsService = &fakesettings.FakeSettingsService{} platform = fakeplatform.NewFakePlatform() logger = boshlog.NewLogger(boshlog.LevelNone) dualDCSupport = nimbus.NewDualDCSupport( platform.GetRunner(), platform.GetFs(), platform.GetDirProvider(), specService, settingsService, logger, ) action = NewApply(applier, specService, settingsService, dualDCSupport, platform) }) It("apply should be asynchronous", func() { Expect(action.IsAsynchronous()).To(BeTrue()) }) It("is not persistent", func() { Expect(action.IsPersistent()).To(BeFalse()) }) Describe("Run", func() { settings := boshsettings.Settings{AgentID: "fake-agent-id"} BeforeEach(func() { settingsService.Settings = settings }) Context("when desired spec has configuration hash", func() { currentApplySpec := boshas.V1ApplySpec{ConfigurationHash: "fake-current-config-hash"} desiredApplySpec := boshas.V1ApplySpec{ConfigurationHash: "fake-desired-config-hash"} populatedDesiredApplySpec := boshas.V1ApplySpec{ ConfigurationHash: "fake-populated-desired-config-hash", } Context("when current spec can be retrieved", func() { BeforeEach(func() { specService.Spec = currentApplySpec }) It("populates dynamic networks in desired spec", func() { _, err := action.Run(desiredApplySpec) Expect(err).ToNot(HaveOccurred()) Expect(specService.PopulateDHCPNetworksSpec).To(Equal(desiredApplySpec)) Expect(specService.PopulateDHCPNetworksSettings).To(Equal(settings)) }) Context("when resolving dynamic networks succeeds", func() { BeforeEach(func() { specService.PopulateDHCPNetworksResultSpec = populatedDesiredApplySpec }) It("runs applier with populated desired spec", func() { _, err := action.Run(desiredApplySpec) Expect(err).ToNot(HaveOccurred()) Expect(applier.Applied).To(BeTrue()) Expect(applier.ApplyCurrentApplySpec).To(Equal(currentApplySpec)) Expect(applier.ApplyDesiredApplySpec).To(Equal(populatedDesiredApplySpec)) }) Context("when applier succeeds applying desired spec", func() { Context("when saving desires spec as current spec succeeds", func() { It("returns 'applied' after setting populated desired spec as current spec", func() { value, err := action.Run(desiredApplySpec) Expect(err).ToNot(HaveOccurred()) Expect(value).To(Equal("applied")) Expect(specService.Spec).To(Equal(populatedDesiredApplySpec)) }) }) Context("when saving populated desires spec as current spec fails", func() { It("returns error because agent was not able to remember that is converged to desired spec", func() { specService.SetErr = errors.New("fake-set-error") _, err := action.Run(desiredApplySpec) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-set-error")) }) }) }) Context("when applier fails applying desired spec", func() { BeforeEach(func() { applier.ApplyError = errors.New("fake-apply-error") }) It("returns error", func() { _, err := action.Run(desiredApplySpec) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-apply-error")) }) It("does not save desired spec as current spec", func() { _, err := action.Run(desiredApplySpec) Expect(err).To(HaveOccurred()) Expect(specService.Spec).To(Equal(currentApplySpec)) }) }) }) Context("when resolving dynamic networks fails", func() { BeforeEach(func() { specService.PopulateDHCPNetworksErr = errors.New("fake-populate-dynamic-networks-err") }) It("returns error", func() { _, err := action.Run(desiredApplySpec) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-populate-dynamic-networks-err")) }) It("does not apply desired spec as current spec", func() { _, err := action.Run(desiredApplySpec) Expect(err).To(HaveOccurred()) Expect(applier.Applied).To(BeFalse()) }) It("does not save desired spec as current spec", func() { _, err := action.Run(desiredApplySpec) Expect(err).To(HaveOccurred()) Expect(specService.Spec).To(Equal(currentApplySpec)) }) }) }) Context("when current spec cannot be retrieved", func() { BeforeEach(func() { specService.Spec = currentApplySpec specService.GetErr = errors.New("fake-get-error") }) It("returns error and does not apply desired spec", func() { _, err := action.Run(desiredApplySpec) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-get-error")) }) It("does not run applier with desired spec", func() { _, err := action.Run(desiredApplySpec) Expect(err).To(HaveOccurred()) Expect(applier.Applied).To(BeFalse()) }) It("does not save desired spec as current spec", func() { _, err := action.Run(desiredApplySpec) Expect(err).To(HaveOccurred()) Expect(specService.Spec).To(Equal(currentApplySpec)) }) }) }) Context("when desired spec does not have a configuration hash", func() { desiredApplySpec := boshas.V1ApplySpec{ JobSpec: boshas.JobSpec{ Template: "fake-job-template", }, } populatedDesiredApplySpec := boshas.V1ApplySpec{ JobSpec: boshas.JobSpec{ Template: "fake-populated-job-template", }, } It("populates dynamic networks in desired spec", func() { _, err := action.Run(desiredApplySpec) Expect(err).ToNot(HaveOccurred()) Expect(specService.PopulateDHCPNetworksSpec).To(Equal(desiredApplySpec)) Expect(specService.PopulateDHCPNetworksSettings).To(Equal(settings)) }) Context("when resolving dynamic networks succeeds", func() { BeforeEach(func() { specService.PopulateDHCPNetworksResultSpec = populatedDesiredApplySpec }) Context("when saving desires spec as current spec succeeds", func() { It("returns 'applied' after setting desired spec as current spec", func() { value, err := action.Run(desiredApplySpec) Expect(err).ToNot(HaveOccurred()) Expect(value).To(Equal("applied")) Expect(specService.Spec).To(Equal(populatedDesiredApplySpec)) }) It("does not try to apply desired spec since it does not have jobs and packages", func() { _, err := action.Run(desiredApplySpec) Expect(err).ToNot(HaveOccurred()) Expect(applier.Applied).To(BeFalse()) }) }) Context("when saving desires spec as current spec fails", func() { BeforeEach(func() { specService.SetErr = errors.New("fake-set-error") }) It("returns error because agent was not able to remember that is converged to desired spec", func() { _, err := action.Run(desiredApplySpec) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-set-error")) }) It("does not try to apply desired spec since it does not have jobs and packages", func() { _, err := action.Run(desiredApplySpec) Expect(err).To(HaveOccurred()) Expect(applier.Applied).To(BeFalse()) }) }) }) Context("when resolving dynamic networks fails", func() { BeforeEach(func() { specService.PopulateDHCPNetworksErr = errors.New("fake-populate-dynamic-networks-err") }) It("returns error", func() { _, err := action.Run(desiredApplySpec) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-populate-dynamic-networks-err")) }) It("does not apply desired spec as current spec", func() { _, err := action.Run(desiredApplySpec) Expect(err).To(HaveOccurred()) Expect(applier.Applied).To(BeFalse()) }) It("does not save desired spec as current spec", func() { _, err := action.Run(desiredApplySpec) Expect(err).To(HaveOccurred()) Expect(specService.Spec).ToNot(Equal(desiredApplySpec)) }) }) }) }) }) }
func describeConfigDriveMetadataService() { var ( metadataService MetadataService resolver *fakeinf.FakeDNSResolver platform *fakeplatform.FakePlatform logger boshlog.Logger ) updateMetadata := func(metadataContents MetadataContentsType) { metadataJSON, err := json.Marshal(metadataContents) Expect(err).ToNot(HaveOccurred()) platform.SetGetFilesContentsFromDisk("/fake-disk-path-1/fake-metadata-path", metadataJSON, nil) Expect(metadataService.IsAvailable()).To(BeTrue()) } updateUserdata := func(userdataContents string) { platform.SetGetFilesContentsFromDisk("/fake-disk-path-1/fake-userdata-path", []byte(userdataContents), nil) Expect(metadataService.IsAvailable()).To(BeTrue()) } BeforeEach(func() { resolver = &fakeinf.FakeDNSResolver{} platform = fakeplatform.NewFakePlatform() logger = boshlog.NewLogger(boshlog.LevelNone) diskPaths := []string{ "/fake-disk-path-1", "/fake-disk-path-2", } metadataService = NewConfigDriveMetadataService( resolver, platform, diskPaths, "fake-metadata-path", "fake-userdata-path", logger, ) userdataContents := fmt.Sprintf(`{"server":{"name":"fake-server-name"},"registry":{"endpoint":"fake-registry-endpoint"}}`) platform.SetGetFilesContentsFromDisk("/fake-disk-path-1/fake-userdata-path", []byte(userdataContents), nil) metadata := MetadataContentsType{ PublicKeys: map[string]PublicKeyType{ "0": PublicKeyType{ "openssh-key": "fake-openssh-key", }, }, InstanceID: "fake-instance-id", } updateMetadata(metadata) }) Describe("GetNetworks", func() { It("returns the network settings", func() { userdataContents := ` { "networks": { "network_1": {"type": "manual", "ip": "1.2.3.4", "netmask": "2.3.4.5", "gateway": "3.4.5.6", "default": ["dns"], "dns": ["8.8.8.8"], "mac": "fake-mac-address-1"}, "network_2": {"type": "dynamic", "default": ["dns"], "dns": ["8.8.8.8"], "mac": "fake-mac-address-2"} } }` updateUserdata(userdataContents) networks, err := metadataService.GetNetworks() Expect(err).ToNot(HaveOccurred()) Expect(networks).To(Equal(boshsettings.Networks{ "network_1": boshsettings.Network{ Type: "manual", IP: "1.2.3.4", Netmask: "2.3.4.5", Gateway: "3.4.5.6", Default: []string{"dns"}, DNS: []string{"8.8.8.8"}, Mac: "fake-mac-address-1", }, "network_2": boshsettings.Network{ Type: "dynamic", Default: []string{"dns"}, DNS: []string{"8.8.8.8"}, Mac: "fake-mac-address-2", }, })) }) It("returns a nil Networks if the settings are missing (from an old CPI version)", func() { userdataContents := `{}` updateUserdata(userdataContents) networks, err := metadataService.GetNetworks() Expect(err).ToNot(HaveOccurred()) Expect(networks).To(BeNil()) }) }) Describe("IsAvailable", func() { It("return true when it can load successfully", func() { Expect(metadataService.IsAvailable()).To(BeTrue()) }) It("returns an error if it fails to read meta-data.json from disk", func() { platform.SetGetFilesContentsFromDisk("/fake-disk-path-1/fake-metadata-path", []byte{}, errors.New("fake-read-disk-error")) Expect(metadataService.IsAvailable()).To(BeFalse()) }) It("tries to load meta-data.json from potential disk locations", func() { platform.SetGetFilesContentsFromDisk("/fake-disk-path-1/fake-metadata-path", []byte{}, errors.New("fake-read-disk-error")) Expect(metadataService.IsAvailable()).To(BeFalse()) Expect(platform.GetFileContentsFromDiskDiskPaths).To(ContainElement("/fake-disk-path-1")) Expect(platform.GetFileContentsFromDiskDiskPaths).To(ContainElement("/fake-disk-path-2")) }) It("returns an error if it fails to parse meta-data.json contents", func() { platform.SetGetFilesContentsFromDisk("/fake-disk-path-1/fake-metadata-path", []byte("broken"), nil) Expect(metadataService.IsAvailable()).To(BeFalse()) }) It("returns an error if it fails to read user_data from disk", func() { platform.SetGetFilesContentsFromDisk("/fake-disk-path-1/fake-userdata-path", []byte{}, errors.New("fake-read-disk-error")) Expect(metadataService.IsAvailable()).To(BeFalse()) }) It("returns an error if it fails to parse user_data contents", func() { platform.SetGetFilesContentsFromDisk("/fake-disk-path-1/fake-userdata-path", []byte("broken"), nil) Expect(metadataService.IsAvailable()).To(BeFalse()) }) Context("when disk paths are not given", func() { It("returns false", func() { metadataService = NewConfigDriveMetadataService( resolver, platform, []string{}, "fake-metadata-path", "fake-userdata-path", logger, ) Expect(metadataService.IsAvailable()).To(BeFalse()) }) }) }) Describe("GetPublicKey", func() { It("returns public key", func() { value, err := metadataService.GetPublicKey() Expect(err).ToNot(HaveOccurred()) Expect(value).To(Equal("fake-openssh-key")) }) It("returns an error if it fails to get ssh key", func() { updateMetadata(MetadataContentsType{}) value, err := metadataService.GetPublicKey() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Failed to load openssh-key from config drive metadata service")) Expect(value).To(Equal("")) }) }) Describe("GetInstanceID", func() { It("returns instance id", func() { value, err := metadataService.GetInstanceID() Expect(err).ToNot(HaveOccurred()) Expect(value).To(Equal("fake-instance-id")) }) It("returns an error if it fails to get instance id", func() { updateMetadata(MetadataContentsType{}) value, err := metadataService.GetInstanceID() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Failed to load instance-id from config drive metadata service")) Expect(value).To(Equal("")) }) }) Describe("GetServerName", func() { It("returns server name", func() { value, err := metadataService.GetServerName() Expect(err).ToNot(HaveOccurred()) Expect(value).To(Equal("fake-server-name")) }) It("returns an error if it fails to get server name", func() { updateUserdata("{}") value, err := metadataService.GetServerName() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Failed to load server name from config drive metadata service")) Expect(value).To(Equal("")) }) }) Describe("GetRegistryEndpoint", func() { It("returns an error if it fails to get registry endpoint", func() { updateUserdata("{}") value, err := metadataService.GetRegistryEndpoint() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Failed to load registry endpoint from config drive metadata service")) Expect(value).To(Equal("")) }) Context("when user_data does not contain a dns server", func() { It("returns registry endpoint", func() { value, err := metadataService.GetRegistryEndpoint() Expect(err).ToNot(HaveOccurred()) Expect(value).To(Equal("fake-registry-endpoint")) }) }) Context("when user_data contains a dns server", func() { BeforeEach(func() { userdataContents := fmt.Sprintf( `{"server":{"name":"%s"},"registry":{"endpoint":"%s"},"dns":{"nameserver":["%s"]}}`, "fake-server-name", "http://fake-registry.com", "fake-dns-server-ip", ) updateUserdata(userdataContents) }) Context("when registry endpoint is successfully resolved", func() { BeforeEach(func() { resolver.RegisterRecord(fakeinf.FakeDNSRecord{ DNSServers: []string{"fake-dns-server-ip"}, Host: "http://fake-registry.com", IP: "http://fake-registry-ip", }) }) It("returns the successfully resolved registry endpoint", func() { endpoint, err := metadataService.GetRegistryEndpoint() Expect(err).ToNot(HaveOccurred()) Expect(endpoint).To(Equal("http://fake-registry-ip")) }) }) Context("when registry endpoint is not successfully resolved", func() { BeforeEach(func() { resolver.LookupHostErr = errors.New("fake-lookup-host-err") }) It("returns error because it failed to resolve registry endpoint", func() { endpoint, err := metadataService.GetRegistryEndpoint() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-lookup-host-err")) Expect(endpoint).To(BeEmpty()) }) }) }) }) }
func init() { Describe("Start", func() { var ( jobSupervisor *fakejobsuper.FakeJobSupervisor applier *fakeappl.FakeApplier specService *fakeas.FakeV1Service platform *fakeplatform.FakePlatform settingsService *fakesettings.FakeSettingsService logger boshlog.Logger dualDCSupport *nimbus.DualDCSupport action StartAction ) BeforeEach(func() { jobSupervisor = fakejobsuper.NewFakeJobSupervisor() applier = fakeappl.NewFakeApplier() specService = fakeas.NewFakeV1Service() action = NewStart(jobSupervisor, applier, specService, dualDCSupport, platform) platform = fakeplatform.NewFakePlatform() logger = boshlog.NewLogger(boshlog.LevelNone) settingsService = &fakesettings.FakeSettingsService{} dualDCSupport = nimbus.NewDualDCSupport( platform.GetRunner(), platform.GetFs(), platform.GetDirProvider(), specService, settingsService, logger, ) action = NewStart(jobSupervisor, applier, specService, dualDCSupport, platform) }) It("is synchronous", func() { Expect(action.IsAsynchronous()).To(BeFalse()) }) It("is not persistent", func() { Expect(action.IsPersistent()).To(BeFalse()) }) It("returns started", func() { started, err := action.Run() Expect(err).ToNot(HaveOccurred()) Expect(started).To(Equal("started")) }) It("starts monitor services", func() { _, err := action.Run() Expect(err).ToNot(HaveOccurred()) Expect(jobSupervisor.Started).To(BeTrue()) }) It("configures jobs", func() { _, err := action.Run() Expect(err).ToNot(HaveOccurred()) Expect(applier.Configured).To(BeTrue()) }) It("apply errs if a job fails configuring", func() { applier.ConfiguredError = errors.New("fake error") _, err := action.Run() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Configuring jobs")) }) }) }
func buildSSHAction(settingsService boshsettings.Service) (*fakeplatform.FakePlatform, SSHAction) { platform := fakeplatform.NewFakePlatform() dirProvider := boshdirs.NewDirectoriesProvider("/foo") action := NewSSH(settingsService, platform, dirProvider) return platform, action }
func describeHTTPMetadataService() { var ( metadataHeaders map[string]string dnsResolver *fakeinf.FakeDNSResolver platform *fakeplat.FakePlatform logger boshlog.Logger metadataService MetadataService ) BeforeEach(func() { metadataHeaders = make(map[string]string) metadataHeaders["key"] = "value" dnsResolver = &fakeinf.FakeDNSResolver{} platform = fakeplat.NewFakePlatform() logger = boshlog.NewLogger(boshlog.LevelNone) metadataService = NewHTTPMetadataService("fake-metadata-host", metadataHeaders, "/user-data", "/instanceid", "/ssh-keys", dnsResolver, platform, logger) }) ItEnsuresMinimalNetworkSetup := func(subject func() (string, error)) { Context("when no networks are configured", func() { BeforeEach(func() { platform.GetConfiguredNetworkInterfacesInterfaces = []string{} }) It("sets up DHCP network", func() { _, err := subject() Expect(err).ToNot(HaveOccurred()) Expect(platform.SetupNetworkingCalled).To(BeTrue()) Expect(platform.SetupNetworkingNetworks).To(Equal(boshsettings.Networks{ "eth0": boshsettings.Network{ Type: "dynamic", }, })) }) Context("when setting up DHCP fails", func() { BeforeEach(func() { platform.SetupNetworkingErr = errors.New("fake-network-error") }) It("returns an error", func() { _, err := subject() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-network-error")) }) }) }) } Describe("IsAvailable", func() { It("returns true", func() { Expect(metadataService.IsAvailable()).To(BeTrue()) }) }) Describe("GetPublicKey", func() { var ( ts *httptest.Server sshKeysPath string ) BeforeEach(func() { handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { defer GinkgoRecover() Expect(r.Method).To(Equal("GET")) Expect(r.URL.Path).To(Equal("/ssh-keys")) Expect(r.Header.Get("key")).To(Equal("value")) w.Write([]byte("fake-public-key")) }) ts = httptest.NewServer(handler) }) AfterEach(func() { ts.Close() }) Context("when the ssh keys path is present", func() { BeforeEach(func() { sshKeysPath = "/ssh-keys" metadataService = NewHTTPMetadataService(ts.URL, metadataHeaders, "/user-data", "/instanceid", sshKeysPath, dnsResolver, platform, logger) }) It("returns fetched public key", func() { publicKey, err := metadataService.GetPublicKey() Expect(err).NotTo(HaveOccurred()) Expect(publicKey).To(Equal("fake-public-key")) }) ItEnsuresMinimalNetworkSetup(func() (string, error) { return metadataService.GetPublicKey() }) }) Context("when the ssh keys path is not present", func() { BeforeEach(func() { sshKeysPath = "" metadataService = NewHTTPMetadataService(ts.URL, metadataHeaders, "/user-data", "/instanceid", sshKeysPath, dnsResolver, platform, logger) }) It("returns an empty ssh key", func() { publicKey, err := metadataService.GetPublicKey() Expect(err).NotTo(HaveOccurred()) Expect(publicKey).To(BeEmpty()) }) }) }) Describe("GetInstanceID", func() { var ( ts *httptest.Server instanceIDPath string ) BeforeEach(func() { handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { defer GinkgoRecover() Expect(r.Method).To(Equal("GET")) Expect(r.URL.Path).To(Equal("/instanceid")) Expect(r.Header.Get("key")).To(Equal("value")) w.Write([]byte("fake-instance-id")) }) ts = httptest.NewServer(handler) }) AfterEach(func() { ts.Close() }) Context("when the instance ID path is present", func() { BeforeEach(func() { instanceIDPath = "/instanceid" metadataService = NewHTTPMetadataService(ts.URL, metadataHeaders, "/user-data", instanceIDPath, "/ssh-keys", dnsResolver, platform, logger) }) It("returns fetched instance id", func() { instanceID, err := metadataService.GetInstanceID() Expect(err).NotTo(HaveOccurred()) Expect(instanceID).To(Equal("fake-instance-id")) }) ItEnsuresMinimalNetworkSetup(func() (string, error) { return metadataService.GetInstanceID() }) }) Context("when the instance ID path is not present", func() { BeforeEach(func() { instanceIDPath = "" metadataService = NewHTTPMetadataService(ts.URL, metadataHeaders, "/user-data", instanceIDPath, "/ssh-keys", dnsResolver, platform, logger) }) It("returns an empty instance ID", func() { instanceID, err := metadataService.GetInstanceID() Expect(err).NotTo(HaveOccurred()) Expect(instanceID).To(BeEmpty()) }) }) }) Describe("GetServerName", func() { var ( ts *httptest.Server serverName *string ) handlerFunc := func(w http.ResponseWriter, r *http.Request) { defer GinkgoRecover() Expect(r.Method).To(Equal("GET")) Expect(r.URL.Path).To(Equal("/user-data")) Expect(r.Header.Get("key")).To(Equal("value")) var jsonStr string if serverName == nil { jsonStr = `{}` } else { jsonStr = fmt.Sprintf(`{"server":{"name":"%s"}}`, *serverName) } w.Write([]byte(jsonStr)) } BeforeEach(func() { serverName = nil handler := http.HandlerFunc(handlerFunc) ts = httptest.NewServer(handler) metadataService = NewHTTPMetadataService(ts.URL, metadataHeaders, "/user-data", "/instanceid", "/ssh-keys", dnsResolver, platform, logger) }) AfterEach(func() { ts.Close() }) Context("when the server name is present in the JSON", func() { BeforeEach(func() { name := "fake-server-name" serverName = &name }) It("returns the server name", func() { name, err := metadataService.GetServerName() Expect(err).ToNot(HaveOccurred()) Expect(name).To(Equal("fake-server-name")) }) ItEnsuresMinimalNetworkSetup(func() (string, error) { return metadataService.GetServerName() }) }) Context("when the server name is not present in the JSON", func() { BeforeEach(func() { serverName = nil }) It("returns an error", func() { name, err := metadataService.GetServerName() Expect(err).To(HaveOccurred()) Expect(name).To(BeEmpty()) }) }) }) Describe("GetRegistryEndpoint", func() { var ( ts *httptest.Server registryURL *string dnsServer *string ) handlerFunc := func(w http.ResponseWriter, r *http.Request) { defer GinkgoRecover() Expect(r.Method).To(Equal("GET")) Expect(r.URL.Path).To(Equal("/user-data")) Expect(r.Header.Get("key")).To(Equal("value")) var jsonStr string if dnsServer == nil { jsonStr = fmt.Sprintf(`{"registry":{"endpoint":"%s"}}`, *registryURL) } else { jsonStr = fmt.Sprintf(`{ "registry":{"endpoint":"%s"}, "dns":{"nameserver":["%s"]} }`, *registryURL, *dnsServer) } w.Write([]byte(jsonStr)) } BeforeEach(func() { url := "http://fake-registry.com" registryURL = &url dnsServer = nil handler := http.HandlerFunc(handlerFunc) ts = httptest.NewServer(handler) metadataService = NewHTTPMetadataService(ts.URL, metadataHeaders, "/user-data", "/instanceid", "/ssh-keys", dnsResolver, platform, logger) }) AfterEach(func() { ts.Close() }) ItEnsuresMinimalNetworkSetup(func() (string, error) { return metadataService.GetRegistryEndpoint() }) Context("when metadata contains a dns server", func() { BeforeEach(func() { server := "fake-dns-server-ip" dnsServer = &server }) Context("when registry endpoint is successfully resolved", func() { BeforeEach(func() { dnsResolver.RegisterRecord(fakeinf.FakeDNSRecord{ DNSServers: []string{"fake-dns-server-ip"}, Host: "http://fake-registry.com", IP: "http://fake-registry-ip", }) }) It("returns the successfully resolved registry endpoint", func() { endpoint, err := metadataService.GetRegistryEndpoint() Expect(err).ToNot(HaveOccurred()) Expect(endpoint).To(Equal("http://fake-registry-ip")) }) }) Context("when registry endpoint is not successfully resolved", func() { BeforeEach(func() { dnsResolver.LookupHostErr = errors.New("fake-lookup-host-err") }) It("returns error because it failed to resolve registry endpoint", func() { endpoint, err := metadataService.GetRegistryEndpoint() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-lookup-host-err")) Expect(endpoint).To(BeEmpty()) }) }) }) Context("when metadata does not contain dns servers", func() { It("returns fetched registry endpoint", func() { endpoint, err := metadataService.GetRegistryEndpoint() Expect(err).NotTo(HaveOccurred()) Expect(endpoint).To(Equal("http://fake-registry.com")) }) }) }) Describe("GetNetworks", func() { It("returns nil networks, since you don't need them for bootstrapping since your network must be set up before you can get the metadata", func() { Expect(metadataService.GetNetworks()).To(BeNil()) }) }) Describe("Retryable Metadata Service Request", func() { var ( ts *httptest.Server registryURL *string dnsServer *string ) createHandlerFunc := func(count int) func(http.ResponseWriter, *http.Request) { initialCount := 0 return func(w http.ResponseWriter, r *http.Request) { if initialCount < count { initialCount++ http.Error(w, http.StatusText(500), 500) return } var jsonStr string if dnsServer == nil { jsonStr = fmt.Sprintf(`{"registry":{"endpoint":"%s"}}`, *registryURL) } else { jsonStr = fmt.Sprintf(`{ "registry":{"endpoint":"%s"}, "dns":{"nameserver":["%s"]} }`, *registryURL, *dnsServer) } w.Write([]byte(jsonStr)) } } BeforeEach(func() { url := "http://fake-registry.com" registryURL = &url dnsServer = nil }) AfterEach(func() { ts.Close() }) Context("when server returns an HTTP Response with status code ==2xx (as defined by the request retryable) within 10 retries", func() { BeforeEach(func() { dnsResolver.RegisterRecord(fakeinf.FakeDNSRecord{ DNSServers: []string{"fake-dns-server-ip"}, Host: "http://fake-registry.com", IP: "http://fake-registry-ip", }) }) It("returns the successfully resolved registry endpoint", func() { handler := http.HandlerFunc(createHandlerFunc(9)) ts = httptest.NewServer(handler) metadataService = NewHTTPMetadataServiceWithCustomRetryDelay(ts.URL, metadataHeaders, "/user-data", "/instanceid", "/ssh-keys", dnsResolver, platform, logger, 0*time.Second) endpoint, err := metadataService.GetRegistryEndpoint() Expect(err).ToNot(HaveOccurred()) Expect(endpoint).To(Equal("http://fake-registry.com")) }) }) Context("when server returns an HTTP Response with status code !=2xx (as defined by the request retryable) more than 10 times", func() { It("returns an error containing the HTTP Response", func() { handler := http.HandlerFunc(createHandlerFunc(10)) ts = httptest.NewServer(handler) metadataService = NewHTTPMetadataServiceWithCustomRetryDelay(ts.URL, metadataHeaders, "/user-data", "/instanceid", "/ssh-keys", dnsResolver, platform, logger, 0*time.Second) _, err := metadataService.GetRegistryEndpoint() Expect(err).ToNot(BeNil()) Expect(err.Error()).To(Equal(fmt.Sprintf("Getting user data: Getting user data from url %s/user-data: Request failed, response: Response{ StatusCode: 500, Status: '500 Internal Server Error' }", ts.URL))) }) }) }) }
func init() { Describe("natsHandler", func() { var ( settingsService *fakesettings.FakeSettingsService client *fakeyagnats.FakeYagnats logger boshlog.Logger handler boshhandler.Handler platform *fakeplatform.FakePlatform loggerOutBuf *bytes.Buffer loggerErrBuf *bytes.Buffer ) BeforeEach(func() { settingsService = &fakesettings.FakeSettingsService{ Settings: boshsettings.Settings{ AgentID: "my-agent-id", Mbus: "nats://*****:*****@127.0.0.1:1234", }, } loggerOutBuf = bytes.NewBufferString("") loggerErrBuf = bytes.NewBufferString("") logger = boshlog.NewWriterLogger(boshlog.LevelError, loggerOutBuf, loggerErrBuf) client = fakeyagnats.New() platform = fakeplatform.NewFakePlatform() handler = NewNatsHandler(settingsService, client, logger, platform) }) Describe("Start", func() { It("starts", func() { var receivedRequest boshhandler.Request handler.Start(func(req boshhandler.Request) (resp boshhandler.Response) { receivedRequest = req return boshhandler.NewValueResponse("expected value") }) defer handler.Stop() Expect(client.ConnectedConnectionProvider()).ToNot(BeNil()) Expect(client.SubscriptionCount()).To(Equal(1)) subscriptions := client.Subscriptions("agent.my-agent-id") Expect(len(subscriptions)).To(Equal(1)) expectedPayload := []byte(`{"method":"ping","arguments":["foo","bar"], "reply_to": "reply to me!"}`) subscription := subscriptions[0] subscription.Callback(&yagnats.Message{ Subject: "agent.my-agent-id", Payload: expectedPayload, }) Expect(receivedRequest).To(Equal(boshhandler.Request{ ReplyTo: "reply to me!", Method: "ping", Payload: expectedPayload, })) Expect(client.PublishedMessageCount()).To(Equal(1)) messages := client.PublishedMessages("reply to me!") Expect(len(messages)).To(Equal(1)) Expect(messages[0].Payload).To(Equal([]byte(`{"value":"expected value"}`))) }) It("cleans up ip-mac address cache for nats configured with ip address", func() { handler.Start(func(req boshhandler.Request) (resp boshhandler.Response) { return nil }) defer handler.Stop() Expect(platform.CleanedIPMacAddressCache).To(Equal("127.0.0.1")) Expect(client.ConnectedConnectionProvider()).ToNot(BeNil()) }) It("does not try to clean up ip-mac address cache for nats configured with hostname", func() { settingsService.Settings.Mbus = "nats://*****:*****@fake-hostname.com:1234" handler.Start(func(req boshhandler.Request) (resp boshhandler.Response) { return nil }) defer handler.Stop() Expect(platform.CleanedIPMacAddressCache).To(BeEmpty()) Expect(client.ConnectedConnectionProvider()).ToNot(BeNil()) }) It("logs error and proceeds if it fails to clean up ip-mac address cache for nats", func() { platform.CleanIPMacAddressCacheErr = errors.New("failed to run") handler.Start(func(req boshhandler.Request) (resp boshhandler.Response) { return nil }) defer handler.Stop() Expect(platform.CleanedIPMacAddressCache).To(Equal("127.0.0.1")) Expect(loggerErrBuf).To(ContainSubstring("ERROR - Cleaning ip-mac address cache for: 127.0.0.1")) Expect(client.ConnectedConnectionProvider()).ToNot(BeNil()) }) It("does not respond if the response is nil", func() { err := handler.Start(func(req boshhandler.Request) (resp boshhandler.Response) { return nil }) Expect(err).ToNot(HaveOccurred()) defer handler.Stop() subscription := client.Subscriptions("agent.my-agent-id")[0] subscription.Callback(&yagnats.Message{ Subject: "agent.my-agent-id", Payload: []byte(`{"method":"ping","arguments":["foo","bar"], "reply_to": "reply to me!"}`), }) Expect(client.PublishedMessageCount()).To(Equal(0)) }) It("responds with an error if the response is bigger than 1MB", func() { err := handler.Start(func(req boshhandler.Request) (resp boshhandler.Response) { // gets inflated by json.Marshal when enveloping size := 0 switch req.Method { case "small": size = 1024*1024 - 12 case "big": size = 1024 * 1024 default: panic("unknown request size") } chars := make([]byte, size) for i := range chars { chars[i] = 'A' } return boshhandler.NewValueResponse(string(chars)) }) Expect(err).ToNot(HaveOccurred()) defer handler.Stop() subscription := client.Subscriptions("agent.my-agent-id")[0] subscription.Callback(&yagnats.Message{ Subject: "agent.my-agent-id", Payload: []byte(`{"method":"small","arguments":[], "reply_to": "fake-reply-to"}`), }) subscription.Callback(&yagnats.Message{ Subject: "agent.my-agent-id", Payload: []byte(`{"method":"big","arguments":[], "reply_to": "fake-reply-to"}`), }) Expect(client.PublishedMessageCount()).To(Equal(1)) messages := client.PublishedMessages("fake-reply-to") Expect(len(messages)).To(Equal(2)) Expect(messages[0].Payload).To(MatchRegexp("value")) Expect(messages[1].Payload).To(Equal([]byte( `{"exception":{"message":"Response exceeded maximum allowed length"}}`))) }) It("can add additional handler funcs to receive requests", func() { var firstHandlerReq, secondHandlerRequest boshhandler.Request handler.Start(func(req boshhandler.Request) (resp boshhandler.Response) { firstHandlerReq = req return boshhandler.NewValueResponse("first-handler-resp") }) defer handler.Stop() handler.RegisterAdditionalFunc(func(req boshhandler.Request) (resp boshhandler.Response) { secondHandlerRequest = req return boshhandler.NewValueResponse("second-handler-resp") }) expectedPayload := []byte(`{"method":"ping","arguments":["foo","bar"], "reply_to": "fake-reply-to"}`) subscription := client.Subscriptions("agent.my-agent-id")[0] subscription.Callback(&yagnats.Message{ Subject: "agent.my-agent-id", Payload: expectedPayload, }) // Expected requests received by both handlers Expect(firstHandlerReq).To(Equal(boshhandler.Request{ ReplyTo: "fake-reply-to", Method: "ping", Payload: expectedPayload, })) Expect(secondHandlerRequest).To(Equal(boshhandler.Request{ ReplyTo: "fake-reply-to", Method: "ping", Payload: expectedPayload, })) // Bosh handler responses were sent Expect(client.PublishedMessageCount()).To(Equal(1)) messages := client.PublishedMessages("fake-reply-to") Expect(len(messages)).To(Equal(2)) Expect(messages[0].Payload).To(Equal([]byte(`{"value":"first-handler-resp"}`))) Expect(messages[1].Payload).To(Equal([]byte(`{"value":"second-handler-resp"}`))) }) It("has the correct connection info", func() { err := handler.Start(func(req boshhandler.Request) (res boshhandler.Response) { return }) Expect(err).ToNot(HaveOccurred()) defer handler.Stop() Expect(client.ConnectedConnectionProvider()).To(Equal(&yagnats.ConnectionInfo{ Addr: "127.0.0.1:1234", Username: "******", Password: "******", })) }) It("does not err when no username and password", func() { settingsService.Settings.Mbus = "nats://127.0.0.1:1234" handler = NewNatsHandler(settingsService, client, logger, platform) err := handler.Start(func(req boshhandler.Request) (res boshhandler.Response) { return }) Expect(err).ToNot(HaveOccurred()) defer handler.Stop() }) It("errs when has username without password", func() { settingsService.Settings.Mbus = "nats://[email protected]:1234" handler = NewNatsHandler(settingsService, client, logger, platform) err := handler.Start(func(req boshhandler.Request) (res boshhandler.Response) { return }) Expect(err).To(HaveOccurred()) defer handler.Stop() }) }) Describe("Send", func() { It("sends the message over nats to a subject that includes the target and topic", func() { errCh := make(chan error, 1) payload := map[string]string{"key1": "value1", "keyA": "valueA"} go func() { errCh <- handler.Send(boshhandler.HealthMonitor, boshhandler.Heartbeat, payload) }() var err error select { case err = <-errCh: } Expect(err).ToNot(HaveOccurred()) Expect(client.PublishedMessageCount()).To(Equal(1)) messages := client.PublishedMessages("hm.agent.heartbeat.my-agent-id") Expect(messages).To(HaveLen(1)) Expect(messages[0].Payload).To(Equal( []byte("{\"key1\":\"value1\",\"keyA\":\"valueA\"}"), )) }) }) }) }
blobstore *fakeblobstore.FakeBlobstore taskService *faketask.FakeService notifier *fakenotif.FakeNotifier applier *fakeappl.FakeApplier compiler *fakecomp.FakeCompiler jobSupervisor *fakejobsuper.FakeJobSupervisor specService *fakeas.FakeV1Service drainScriptProvider boshdrain.ScriptProvider jobScriptProvider boshscript.JobScriptProvider factory Factory logger boshlog.Logger ) BeforeEach(func() { settingsService = &fakesettings.FakeSettingsService{} platform = fakeplatform.NewFakePlatform() blobstore = &fakeblobstore.FakeBlobstore{} taskService = &faketask.FakeService{} notifier = fakenotif.NewFakeNotifier() applier = fakeappl.NewFakeApplier() compiler = fakecomp.NewFakeCompiler() jobSupervisor = fakejobsuper.NewFakeJobSupervisor() specService = fakeas.NewFakeV1Service() drainScriptProvider = boshdrain.NewConcreteScriptProvider(nil, nil, platform.GetDirProvider()) jobScriptProvider = &fakescript.FakeJobScriptProvider{} logger = boshlog.NewLogger(boshlog.LevelNone) factory = NewFactory( settingsService, platform, blobstore,
func describeHTTPMetadataService() { var ( dnsResolver *fakeinf.FakeDNSResolver platform *fakeplat.FakePlatform logger boshlog.Logger metadataService MetadataService ) BeforeEach(func() { dnsResolver = &fakeinf.FakeDNSResolver{} platform = fakeplat.NewFakePlatform() logger = boshlog.NewLogger(boshlog.LevelNone) metadataService = NewHTTPMetadataService("fake-metadata-host", dnsResolver, platform, logger) }) ItEnsuresMinimalNetworkSetup := func(subject func() (string, error)) { Context("when no networks are configured", func() { BeforeEach(func() { platform.GetConfiguredNetworkInterfacesInterfaces = []string{} }) It("sets up DHCP network", func() { _, err := subject() Expect(err).ToNot(HaveOccurred()) Expect(platform.SetupNetworkingCalled).To(BeTrue()) Expect(platform.SetupNetworkingNetworks).To(Equal(boshsettings.Networks{ "eth0": boshsettings.Network{ Type: "dynamic", }, })) }) Context("when setting up DHCP fails", func() { BeforeEach(func() { platform.SetupNetworkingErr = errors.New("fake-network-error") }) It("returns an error", func() { _, err := subject() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-network-error")) }) }) }) } Describe("IsAvailable", func() { It("returns true", func() { Expect(metadataService.IsAvailable()).To(BeTrue()) }) }) Describe("GetPublicKey", func() { var ( ts *httptest.Server ) BeforeEach(func() { handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { GinkgoRecover() Expect(r.Method).To(Equal("GET")) Expect(r.URL.Path).To(Equal("/latest/meta-data/public-keys/0/openssh-key")) w.Write([]byte("fake-public-key")) }) ts = httptest.NewServer(handler) metadataService = NewHTTPMetadataService(ts.URL, dnsResolver, platform, logger) }) AfterEach(func() { ts.Close() }) ItEnsuresMinimalNetworkSetup(func() (string, error) { return metadataService.GetPublicKey() }) It("returns fetched public key", func() { publicKey, err := metadataService.GetPublicKey() Expect(err).NotTo(HaveOccurred()) Expect(publicKey).To(Equal("fake-public-key")) }) }) Describe("GetInstanceID", func() { var ( ts *httptest.Server ) BeforeEach(func() { handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { GinkgoRecover() Expect(r.Method).To(Equal("GET")) Expect(r.URL.Path).To(Equal("/latest/meta-data/instance-id")) w.Write([]byte("fake-instance-id")) }) ts = httptest.NewServer(handler) metadataService = NewHTTPMetadataService(ts.URL, dnsResolver, platform, logger) }) AfterEach(func() { ts.Close() }) ItEnsuresMinimalNetworkSetup(func() (string, error) { return metadataService.GetInstanceID() }) It("returns fetched instance id", func() { publicKey, err := metadataService.GetInstanceID() Expect(err).NotTo(HaveOccurred()) Expect(publicKey).To(Equal("fake-instance-id")) }) }) Describe("GetServerName", func() { var ( ts *httptest.Server serverName *string ) handlerFunc := func(w http.ResponseWriter, r *http.Request) { GinkgoRecover() Expect(r.Method).To(Equal("GET")) Expect(r.URL.Path).To(Equal("/latest/user-data")) var jsonStr string if serverName == nil { jsonStr = `{}` } else { jsonStr = fmt.Sprintf(`{"server":{"name":"%s"}}`, *serverName) } w.Write([]byte(jsonStr)) } BeforeEach(func() { serverName = nil handler := http.HandlerFunc(handlerFunc) ts = httptest.NewServer(handler) metadataService = NewHTTPMetadataService(ts.URL, dnsResolver, platform, logger) }) AfterEach(func() { ts.Close() }) Context("when the server name is present in the JSON", func() { BeforeEach(func() { name := "fake-server-name" serverName = &name }) It("returns the server name", func() { name, err := metadataService.GetServerName() Expect(err).ToNot(HaveOccurred()) Expect(name).To(Equal("fake-server-name")) }) ItEnsuresMinimalNetworkSetup(func() (string, error) { return metadataService.GetServerName() }) }) Context("when the server name is not present in the JSON", func() { BeforeEach(func() { serverName = nil }) It("returns an error", func() { name, err := metadataService.GetServerName() Expect(err).To(HaveOccurred()) Expect(name).To(BeEmpty()) }) }) }) Describe("GetRegistryEndpoint", func() { var ( ts *httptest.Server registryURL *string dnsServer *string ) handlerFunc := func(w http.ResponseWriter, r *http.Request) { GinkgoRecover() Expect(r.Method).To(Equal("GET")) Expect(r.URL.Path).To(Equal("/latest/user-data")) var jsonStr string if dnsServer == nil { jsonStr = fmt.Sprintf(`{"registry":{"endpoint":"%s"}}`, *registryURL) } else { jsonStr = fmt.Sprintf(`{ "registry":{"endpoint":"%s"}, "dns":{"nameserver":["%s"]} }`, *registryURL, *dnsServer) } w.Write([]byte(jsonStr)) } BeforeEach(func() { url := "http://fake-registry.com" registryURL = &url dnsServer = nil handler := http.HandlerFunc(handlerFunc) ts = httptest.NewServer(handler) metadataService = NewHTTPMetadataService(ts.URL, dnsResolver, platform, logger) }) AfterEach(func() { ts.Close() }) ItEnsuresMinimalNetworkSetup(func() (string, error) { return metadataService.GetRegistryEndpoint() }) Context("when metadata contains a dns server", func() { BeforeEach(func() { server := "fake-dns-server-ip" dnsServer = &server }) Context("when registry endpoint is successfully resolved", func() { BeforeEach(func() { dnsResolver.RegisterRecord(fakeinf.FakeDNSRecord{ DNSServers: []string{"fake-dns-server-ip"}, Host: "http://fake-registry.com", IP: "http://fake-registry-ip", }) }) It("returns the successfully resolved registry endpoint", func() { endpoint, err := metadataService.GetRegistryEndpoint() Expect(err).ToNot(HaveOccurred()) Expect(endpoint).To(Equal("http://fake-registry-ip")) }) }) Context("when registry endpoint is not successfully resolved", func() { BeforeEach(func() { dnsResolver.LookupHostErr = errors.New("fake-lookup-host-err") }) It("returns error because it failed to resolve registry endpoint", func() { endpoint, err := metadataService.GetRegistryEndpoint() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-lookup-host-err")) Expect(endpoint).To(BeEmpty()) }) }) }) Context("when metadata does not contain dns servers", func() { It("returns fetched registry endpoint", func() { endpoint, err := metadataService.GetRegistryEndpoint() Expect(err).NotTo(HaveOccurred()) Expect(endpoint).To(Equal("http://fake-registry.com")) }) }) }) Describe("GetNetworks", func() { It("returns nil networks, since you don't need them for bootstrapping since your network must be set up before you can get the metadata", func() { Expect(metadataService.GetNetworks()).To(BeNil()) }) }) }
func init() { Describe("provider", func() { var ( platform *fakeplatform.FakePlatform client *fakemonit.FakeMonitClient logger boshlog.Logger dirProvider boshdir.Provider jobFailuresServerPort int handler *fakembus.FakeHandler provider Provider timeService clock.Clock ) BeforeEach(func() { platform = fakeplatform.NewFakePlatform() client = fakemonit.NewFakeMonitClient() logger = boshlog.NewLogger(boshlog.LevelNone) dirProvider = boshdir.NewProvider("/fake-base-dir") jobFailuresServerPort = 2825 handler = &fakembus.FakeHandler{} timeService = clock.NewClock() provider = NewProvider( platform, client, logger, dirProvider, handler, ) }) It("provides a monit job supervisor", func() { actualSupervisor, err := provider.Get("monit") Expect(err).ToNot(HaveOccurred()) expectedSupervisor := NewMonitJobSupervisor( platform.Fs, platform.Runner, client, logger, dirProvider, jobFailuresServerPort, MonitReloadOptions{ MaxTries: 3, MaxCheckTries: 6, DelayBetweenCheckTries: 5 * time.Second, }, timeService, ) Expect(actualSupervisor).To(Equal(expectedSupervisor)) }) It("provides a dummy job supervisor", func() { actualSupervisor, err := provider.Get("dummy") Expect(err).ToNot(HaveOccurred()) expectedSupervisor := NewDummyJobSupervisor() Expect(actualSupervisor).To(Equal(expectedSupervisor)) }) It("provides a dummy nats job supervisor", func() { actualSupervisor, err := provider.Get("dummy-nats") Expect(err).NotTo(HaveOccurred()) expectedSupervisor := NewDummyNatsJobSupervisor(handler) Expect(actualSupervisor).To(Equal(expectedSupervisor)) }) It("returns an error when the supervisor is not found", func() { _, err := provider.Get("does-not-exist") Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("does-not-exist could not be found")) }) }) }
func describeInstanceMetadataSettingsSource() { var ( metadataHeaders map[string]string settingsPath string platform *fakeplat.FakePlatform logger boshlog.Logger metadataSource *InstanceMetadataSettingsSource ) BeforeEach(func() { metadataHeaders = make(map[string]string) metadataHeaders["key"] = "value" settingsPath = "/computeMetadata/v1/instance/attributes/bosh_settings" platform = fakeplat.NewFakePlatform() logger = boshlog.NewLogger(boshlog.LevelNone) metadataSource = NewInstanceMetadataSettingsSource("http://fake-metadata-host", metadataHeaders, settingsPath, platform, logger) }) Describe("PublicSSHKeyForUsername", func() { It("returns an empty string", func() { publicKey, err := metadataSource.PublicSSHKeyForUsername("fake-username") Expect(err).ToNot(HaveOccurred()) Expect(publicKey).To(Equal("")) }) }) Describe("Settings", func() { var ( ts *httptest.Server ) handlerFunc := func(w http.ResponseWriter, r *http.Request) { defer GinkgoRecover() Expect(r.Method).To(Equal("GET")) Expect(r.URL.Path).To(Equal(settingsPath)) Expect(r.Header.Get("key")).To(Equal("value")) var jsonStr string jsonStr = `{"agent_id": "123"}` w.Write([]byte(jsonStr)) } BeforeEach(func() { handler := http.HandlerFunc(handlerFunc) ts = httptest.NewServer(handler) metadataSource = NewInstanceMetadataSettingsSource(ts.URL, metadataHeaders, settingsPath, platform, logger) }) AfterEach(func() { ts.Close() }) It("returns settings read from the instance metadata endpoint", func() { settings, err := metadataSource.Settings() Expect(err).NotTo(HaveOccurred()) Expect(settings.AgentID).To(Equal("123")) }) It("returns an error if reading from the instance metadata endpoint fails", func() { metadataSource = NewInstanceMetadataSettingsSource("bad-registry-endpoint", metadataHeaders, settingsPath, platform, logger) _, err := metadataSource.Settings() Expect(err).To(HaveOccurred()) }) }) }