Example #1
0
func init() {
	Describe("Start", func() {
		var (
			jobSupervisor *fakejobsuper.FakeJobSupervisor
			action        StartAction
		)

		BeforeEach(func() {
			jobSupervisor = fakejobsuper.NewFakeJobSupervisor()
			action = NewStart(jobSupervisor)
		})

		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(jobSupervisor.JobSupervisorStarted).To(BeTrue())
			Expect(jobSupervisor.Started).To(BeTrue())
			Expect(started).To(Equal("started"))
		})

		It("starts monitor services", func() {
			_, err := action.Run()
			Expect(err).ToNot(HaveOccurred())
			Expect(jobSupervisor.Started).To(BeTrue())
		})
	})
}
Example #2
0
func init() {
	Describe("Start", func() {
		var (
			jobSupervisor *fakejobsuper.FakeJobSupervisor
			applier       *fakeappl.FakeApplier
			specService   *fakeas.FakeV1Service
			action        StartAction
		)

		BeforeEach(func() {
			jobSupervisor = fakejobsuper.NewFakeJobSupervisor()
			applier = fakeappl.NewFakeApplier()
			specService = fakeas.NewFakeV1Service()
			action = NewStart(jobSupervisor, applier, specService)
		})

		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"))
		})
	})
}
Example #3
0
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())
		})
	})
}
Example #4
0
func init() {
	Describe("Stop", func() {
		var (
			jobSupervisor *fakejobsuper.FakeJobSupervisor
			action        StopAction
		)

		BeforeEach(func() {
			jobSupervisor = fakejobsuper.NewFakeJobSupervisor()
			action = NewStop(jobSupervisor)
		})

		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(ProtocolVersion(2))
			Expect(err).ToNot(HaveOccurred())
			Expect(stopped).To(Equal("stopped"))
		})

		It("stops job supervisor services", func() {
			_, err := action.Run(ProtocolVersion(2))
			Expect(err).ToNot(HaveOccurred())
			Expect(jobSupervisor.Stopped).To(BeTrue())
		})

		It("stops when protocol version is 2", func() {
			_, err := action.Run(ProtocolVersion(2))
			Expect(err).ToNot(HaveOccurred())
			Expect(jobSupervisor.StoppedAndWaited).ToNot(BeTrue())
		})

		It("stops and waits when protocol version is greater than 2", func() {
			_, err := action.Run(ProtocolVersion(3))
			Expect(err).ToNot(HaveOccurred())
			Expect(jobSupervisor.StoppedAndWaited).To(BeTrue())
		})
	})
}
		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,
			taskService,
			notifier,
			applier,
			compiler,
			jobSupervisor,
			specService,
func init() {
	Describe("concreteApplier", func() {
		var (
			jobApplier        *fakejobs.FakeApplier
			packageApplier    *fakepackages.FakeApplier
			logRotateDelegate *FakeLogRotateDelegate
			jobSupervisor     *fakejobsuper.FakeJobSupervisor
			applier           Applier
		)

		BeforeEach(func() {
			jobApplier = fakejobs.NewFakeApplier()
			packageApplier = fakepackages.NewFakeApplier()
			logRotateDelegate = &FakeLogRotateDelegate{}
			jobSupervisor = fakejobsuper.NewFakeJobSupervisor()
			applier = NewConcreteApplier(
				jobApplier,
				packageApplier,
				logRotateDelegate,
				jobSupervisor,
				boshdirs.NewProvider("/fake-base-dir"),
			)
		})

		Describe("Prepare", func() {
			It("prepares each jobs", func() {
				job := buildJob()

				err := applier.Prepare(
					&fakeas.FakeApplySpec{JobResults: []models.Job{job}},
				)
				Expect(err).ToNot(HaveOccurred())
				Expect(jobApplier.PreparedJobs).To(Equal([]models.Job{job}))
			})

			It("returns error when preparing jobs fails", func() {
				job := buildJob()

				jobApplier.PrepareError = errors.New("fake-prepare-job-error")

				err := applier.Prepare(
					&fakeas.FakeApplySpec{JobResults: []models.Job{job}},
				)
				Expect(err).To(HaveOccurred())
				Expect(err.Error()).To(ContainSubstring("fake-prepare-job-error"))
			})

			It("prepares each packages", func() {
				pkg1 := buildPackage()
				pkg2 := buildPackage()

				err := applier.Prepare(
					&fakeas.FakeApplySpec{PackageResults: []models.Package{pkg1, pkg2}},
				)
				Expect(err).ToNot(HaveOccurred())
				Expect(packageApplier.PreparedPackages).To(Equal([]models.Package{pkg1, pkg2}))
			})

			It("returns error when preparing packages fails", func() {
				pkg := buildPackage()

				packageApplier.PrepareError = errors.New("fake-prepare-package-error")

				err := applier.Prepare(
					&fakeas.FakeApplySpec{PackageResults: []models.Package{pkg}},
				)
				Expect(err).To(HaveOccurred())
				Expect(err.Error()).To(ContainSubstring("fake-prepare-package-error"))
			})
		})

		Describe("Configure jobs", func() {

			It("reloads job supervisor", func() {
				job1 := models.Job{Name: "fake-job-name-1", Version: "fake-version-name-1"}
				job2 := models.Job{Name: "fake-job-name-2", Version: "fake-version-name-2"}
				jobs := []models.Job{job1, job2}

				err := applier.ConfigureJobs(&fakeas.FakeApplySpec{JobResults: jobs})
				Expect(err).ToNot(HaveOccurred())

				Expect(jobSupervisor.Reloaded).To(BeTrue())
			})

			It("configures jobs", func() {
				job1 := models.Job{Name: "fake-job-name-1", Version: "fake-version-name-1"}
				job2 := models.Job{Name: "fake-job-name-2", Version: "fake-version-name-2"}
				jobs := []models.Job{job1, job2}

				err := applier.ConfigureJobs(&fakeas.FakeApplySpec{JobResults: jobs})
				Expect(err).ToNot(HaveOccurred())

				Expect(jobApplier.ConfiguredJobs).To(ConsistOf(job1, job2))
			})
		})

		Describe("Apply", func() {
			It("removes all jobs from job supervisor", func() {
				err := applier.Apply(&fakeas.FakeApplySpec{}, &fakeas.FakeApplySpec{})
				Expect(err).ToNot(HaveOccurred())

				Expect(jobSupervisor.RemovedAllJobs).To(BeTrue())
			})

			It("removes all previous jobs from job supervisor before starting to apply jobs", func() {
				// force remove all error
				jobSupervisor.RemovedAllJobsErr = errors.New("fake-remove-all-jobs-error")

				job := buildJob()
				applier.Apply(
					&fakeas.FakeApplySpec{},
					&fakeas.FakeApplySpec{JobResults: []models.Job{job}},
				)

				// check that jobs were not applied before removing all other jobs
				Expect(jobApplier.AppliedJobs).To(Equal([]models.Job{}))
			})

			It("returns error if removing all jobs from job supervisor fails", func() {
				jobSupervisor.RemovedAllJobsErr = errors.New("fake-remove-all-jobs-error")

				err := applier.Apply(&fakeas.FakeApplySpec{}, &fakeas.FakeApplySpec{})
				Expect(err).To(HaveOccurred())
				Expect(err.Error()).To(ContainSubstring("fake-remove-all-jobs-error"))
			})

			It("apply applies jobs", func() {
				job := buildJob()

				err := applier.Apply(
					&fakeas.FakeApplySpec{},
					&fakeas.FakeApplySpec{JobResults: []models.Job{job}},
				)
				Expect(err).ToNot(HaveOccurred())
				Expect(jobApplier.AppliedJobs).To(Equal([]models.Job{job}))
			})

			It("apply errs when applying jobs errs", func() {
				job := buildJob()

				jobApplier.ApplyError = errors.New("fake-apply-job-error")

				err := applier.Apply(
					&fakeas.FakeApplySpec{},
					&fakeas.FakeApplySpec{JobResults: []models.Job{job}},
				)
				Expect(err).To(HaveOccurred())
				Expect(err.Error()).To(ContainSubstring("fake-apply-job-error"))
			})

			It("asked jobApplier to keep only the jobs in the desired and current specs", func() {
				currentJob := buildJob()
				desiredJob := buildJob()

				err := applier.Apply(
					&fakeas.FakeApplySpec{JobResults: []models.Job{currentJob}},
					&fakeas.FakeApplySpec{JobResults: []models.Job{desiredJob}},
				)
				Expect(err).ToNot(HaveOccurred())

				Expect(jobApplier.KeepOnlyJobs).To(Equal([]models.Job{currentJob, desiredJob}))
			})

			It("returns error when jobApplier fails to keep only the jobs in the desired and current specs", func() {
				jobApplier.KeepOnlyErr = errors.New("fake-keep-only-error")

				currentJob := buildJob()
				desiredJob := buildJob()

				err := applier.Apply(
					&fakeas.FakeApplySpec{JobResults: []models.Job{currentJob}},
					&fakeas.FakeApplySpec{JobResults: []models.Job{desiredJob}},
				)
				Expect(err).To(HaveOccurred())
				Expect(err.Error()).To(ContainSubstring("fake-keep-only-error"))
			})

			It("apply applies packages", func() {
				pkg1 := buildPackage()
				pkg2 := buildPackage()

				err := applier.Apply(
					&fakeas.FakeApplySpec{},
					&fakeas.FakeApplySpec{PackageResults: []models.Package{pkg1, pkg2}},
				)
				Expect(err).ToNot(HaveOccurred())
				Expect(packageApplier.AppliedPackages).To(Equal([]models.Package{pkg1, pkg2}))
			})

			It("apply errs when applying packages errs", func() {
				pkg := buildPackage()

				packageApplier.ApplyError = errors.New("fake-apply-package-error")

				err := applier.Apply(
					&fakeas.FakeApplySpec{},
					&fakeas.FakeApplySpec{PackageResults: []models.Package{pkg}},
				)
				Expect(err).To(HaveOccurred())
				Expect(err.Error()).To(ContainSubstring("fake-apply-package-error"))
			})

			It("asked packageApplier to keep only the packages in the desired and current specs", func() {
				currentPkg := buildPackage()
				desiredPkg := buildPackage()

				err := applier.Apply(
					&fakeas.FakeApplySpec{PackageResults: []models.Package{currentPkg}},
					&fakeas.FakeApplySpec{PackageResults: []models.Package{desiredPkg}},
				)
				Expect(err).ToNot(HaveOccurred())
				Expect(packageApplier.KeptOnlyPackages).To(Equal([]models.Package{currentPkg, desiredPkg}))
			})

			It("returns error when packageApplier fails to keep only the packages in the desired and current specs", func() {
				packageApplier.KeepOnlyErr = errors.New("fake-keep-only-error")

				currentPkg := buildPackage()
				desiredPkg := buildPackage()

				err := applier.Apply(
					&fakeas.FakeApplySpec{PackageResults: []models.Package{currentPkg}},
					&fakeas.FakeApplySpec{PackageResults: []models.Package{desiredPkg}},
				)
				Expect(err).To(HaveOccurred())
				Expect(err.Error()).To(ContainSubstring("fake-keep-only-error"))
			})

			It("apply does not configure jobs", func() {
				job1 := models.Job{Name: "fake-job-name-1", Version: "fake-version-name-1"}
				job2 := models.Job{Name: "fake-job-name-2", Version: "fake-version-name-2"}
				jobs := []models.Job{job1, job2}

				err := applier.Apply(&fakeas.FakeApplySpec{}, &fakeas.FakeApplySpec{JobResults: jobs})
				Expect(err).ToNot(HaveOccurred())
				Expect(jobApplier.ConfiguredJobs).To(BeEmpty())

				Expect(jobSupervisor.Reloaded).To(BeTrue())
			})

			It("apply errs if monitor fails reload", func() {
				jobs := []models.Job{}
				jobSupervisor.ReloadErr = errors.New("error reloading monit")

				err := applier.Apply(&fakeas.FakeApplySpec{}, &fakeas.FakeApplySpec{JobResults: jobs})
				Expect(err).To(HaveOccurred())
				Expect(err.Error()).To(ContainSubstring("error reloading monit"))
			})

			It("apply sets up logrotation", func() {
				err := applier.Apply(
					&fakeas.FakeApplySpec{},
					&fakeas.FakeApplySpec{MaxLogFileSizeResult: "fake-size"},
				)
				Expect(err).ToNot(HaveOccurred())

				assert.Equal(GinkgoT(), logRotateDelegate.SetupLogrotateArgs, SetupLogrotateArgs{
					GroupName: boshsettings.VCAPUsername,
					BasePath:  "/fake-base-dir",
					Size:      "fake-size",
				})
			})

			It("apply errs if setup logrotate fails", func() {
				logRotateDelegate.SetupLogrotateErr = errors.New("fake-set-up-logrotate-error")

				err := applier.Apply(&fakeas.FakeApplySpec{}, &fakeas.FakeApplySpec{})
				Expect(err).To(HaveOccurred())
				Expect(err.Error()).To(ContainSubstring("fake-set-up-logrotate-error"))
			})
		})
	})
}
Example #7
0
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("renderedJobApplier", func() {
		var (
			jobsBc                 *fakebc.FakeBundleCollection
			jobSupervisor          *fakejobsuper.FakeJobSupervisor
			packageApplierProvider *fakepa.FakePackageApplierProvider
			blobstore              *fakeblob.FakeBlobstore
			compressor             *fakecmd.FakeCompressor
			fs                     *fakesys.FakeFileSystem
			applier                JobApplier
		)

		BeforeEach(func() {
			jobsBc = fakebc.NewFakeBundleCollection()
			jobSupervisor = fakejobsuper.NewFakeJobSupervisor()
			packageApplierProvider = fakepa.NewFakePackageApplierProvider()
			blobstore = fakeblob.NewFakeBlobstore()
			fs = fakesys.NewFakeFileSystem()
			compressor = fakecmd.NewFakeCompressor()
			logger := boshlog.NewLogger(boshlog.LevelNone)
			applier = NewRenderedJobApplier(
				jobsBc,
				jobSupervisor,
				packageApplierProvider,
				blobstore,
				compressor,
				fs,
				logger,
			)
		})

		Describe("Prepare & Apply", func() {
			var (
				job    models.Job
				bundle *fakebc.FakeBundle
			)

			BeforeEach(func() {
				job, bundle = buildJob(jobsBc)
			})

			ItInstallsJob := func(act func() error) {
				It("returns error when installing job fails", func() {
					bundle.InstallError = errors.New("fake-install-error")

					err := act()
					Expect(err).To(HaveOccurred())
					Expect(err.Error()).To(ContainSubstring("fake-install-error"))
				})

				It("downloads and later cleans up downloaded job template blob", func() {
					blobstore.GetFileName = "/fake-blobstore-file-name"

					err := act()
					Expect(err).ToNot(HaveOccurred())
					Expect(blobstore.GetBlobIDs[0]).To(Equal("fake-blobstore-id"))
					Expect(blobstore.GetFingerprints[0]).To(Equal("fake-blob-sha1"))

					// downloaded file is cleaned up
					Expect(blobstore.CleanUpFileName).To(Equal("/fake-blobstore-file-name"))
				})

				It("returns error when downloading job template blob fails", func() {
					blobstore.GetError = errors.New("fake-get-error")

					err := act()
					Expect(err).To(HaveOccurred())
					Expect(err.Error()).To(ContainSubstring("fake-get-error"))
				})

				It("decompresses job template blob to tmp path and later cleans it up", func() {
					fs.TempDirDir = "/fake-tmp-dir"
					blobstore.GetFileName = "/fake-blobstore-file-name"

					var tmpDirExistsBeforeInstall bool

					bundle.InstallCallBack = func() {
						tmpDirExistsBeforeInstall = true
					}

					err := act()
					Expect(err).ToNot(HaveOccurred())

					Expect(compressor.DecompressFileToDirTarballPaths[0]).To(Equal("/fake-blobstore-file-name"))
					Expect(compressor.DecompressFileToDirDirs[0]).To(Equal("/fake-tmp-dir"))

					// tmp dir exists before bundle install
					Expect(tmpDirExistsBeforeInstall).To(BeTrue())

					// tmp dir is cleaned up after install
					Expect(fs.FileExists(fs.TempDirDir)).To(BeFalse())
				})

				It("returns error when temporary directory creation fails", func() {
					fs.TempDirError = errors.New("fake-filesystem-tempdir-error")

					err := act()
					Expect(err).To(HaveOccurred())
					Expect(err.Error()).To(ContainSubstring("fake-filesystem-tempdir-error"))
				})

				It("returns error when decompressing job template fails", func() {
					compressor.DecompressFileToDirErr = errors.New("fake-decompress-error")

					err := act()
					Expect(err).To(HaveOccurred())
					Expect(err.Error()).To(ContainSubstring("fake-decompress-error"))
				})

				It("returns error when getting the list of bin files fails", func() {
					fs.GlobErr = errors.New("fake-glob-error")

					err := act()
					Expect(err).To(HaveOccurred())
					Expect(err.Error()).To(ContainSubstring("fake-glob-error"))
				})

				It("returns error when changing permissions on bin files fails", func() {
					fs.TempDirDir = "/fake-tmp-dir"

					fs.SetGlob("/fake-tmp-dir/fake-path-in-archive/bin/*", []string{
						"/fake-tmp-dir/fake-path-in-archive/bin/test",
					})

					fs.ChmodErr = errors.New("fake-chmod-error")

					err := act()
					Expect(err).To(HaveOccurred())
					Expect(err.Error()).To(ContainSubstring("fake-chmod-error"))
				})

				It("installs bundle from decompressed tmp path of a job template", func() {
					fs.TempDirDir = "/fake-tmp-dir"

					var installedBeforeDecompression bool

					compressor.DecompressFileToDirCallBack = func() {
						installedBeforeDecompression = bundle.Installed
					}

					err := act()
					Expect(err).ToNot(HaveOccurred())

					// bundle installation did not happen before decompression
					Expect(installedBeforeDecompression).To(BeFalse())

					// make sure that bundle install happened after decompression
					Expect(bundle.InstallSourcePath).To(Equal("/fake-tmp-dir/fake-path-in-archive"))
				})

				It("sets executable bit for files in bin", func() {
					fs.TempDirDir = "/fake-tmp-dir"

					compressor.DecompressFileToDirCallBack = func() {
						fs.WriteFile("/fake-tmp-dir/fake-path-in-archive/bin/test1", []byte{})
						fs.WriteFile("/fake-tmp-dir/fake-path-in-archive/bin/test2", []byte{})
						fs.WriteFile("/fake-tmp-dir/fake-path-in-archive/config/test", []byte{})
					}

					fs.SetGlob("/fake-tmp-dir/fake-path-in-archive/bin/*", []string{
						"/fake-tmp-dir/fake-path-in-archive/bin/test1",
						"/fake-tmp-dir/fake-path-in-archive/bin/test2",
					})

					var binTest1Stats, binTest2Stats, configTestStats *fakesys.FakeFileStats

					bundle.InstallCallBack = func() {
						binTest1Stats = fs.GetFileTestStat("/fake-tmp-dir/fake-path-in-archive/bin/test1")
						binTest2Stats = fs.GetFileTestStat("/fake-tmp-dir/fake-path-in-archive/bin/test2")
						configTestStats = fs.GetFileTestStat("/fake-tmp-dir/fake-path-in-archive/config/test")
					}

					err := act()
					Expect(err).ToNot(HaveOccurred())

					// bin files are executable
					Expect(int(binTest1Stats.FileMode)).To(Equal(0755))
					Expect(int(binTest2Stats.FileMode)).To(Equal(0755))

					// non-bin files are not made executable
					Expect(int(configTestStats.FileMode)).ToNot(Equal(0755))
				})
			}

			ItUpdatesPackages := func(act func() error) {
				var packageApplier *fakepa.FakePackageApplier

				BeforeEach(func() {
					packageApplier = fakepa.NewFakePackageApplier()
					packageApplierProvider.JobSpecificPackageAppliers[job.Name] = packageApplier
				})

				It("applies each package that job depends on and then cleans up packages", func() {
					err := act()
					Expect(err).ToNot(HaveOccurred())
					Expect(packageApplier.ActionsCalled).To(Equal([]string{"Apply", "Apply", "KeepOnly"}))
					Expect(len(packageApplier.AppliedPackages)).To(Equal(2)) // present
					Expect(packageApplier.AppliedPackages).To(Equal(job.Packages))
				})

				It("returns error when applying package that job depends on fails", func() {
					packageApplier.ApplyError = errors.New("fake-apply-err")

					err := act()
					Expect(err).To(HaveOccurred())
					Expect(err.Error()).To(ContainSubstring("fake-apply-err"))
				})

				It("keeps only currently required packages but does not completely uninstall them", func() {
					err := act()
					Expect(err).ToNot(HaveOccurred())
					Expect(len(packageApplier.KeptOnlyPackages)).To(Equal(2)) // present
					Expect(packageApplier.KeptOnlyPackages).To(Equal(job.Packages))
				})

				It("returns error when keeping only currently required packages fails", func() {
					packageApplier.KeepOnlyErr = errors.New("fake-keep-only-err")

					err := act()
					Expect(err).To(HaveOccurred())
					Expect(err.Error()).To(ContainSubstring("fake-keep-only-err"))
				})
			}

			Describe("Prepare", func() {
				act := func() error { return applier.Prepare(job) }

				It("return an error if getting file bundle fails", func() {
					jobsBc.GetErr = errors.New("fake-get-bundle-error")

					err := act()
					Expect(err).To(HaveOccurred())
					Expect(err.Error()).To(ContainSubstring("fake-get-bundle-error"))
				})

				It("returns an error if checking for installed path fails", func() {
					bundle.IsInstalledErr = errors.New("fake-is-installed-error")

					err := act()
					Expect(err).To(HaveOccurred())
					Expect(err.Error()).To(ContainSubstring("fake-is-installed-error"))
				})

				Context("when job is already installed", func() {
					BeforeEach(func() {
						bundle.Installed = true
					})

					It("does not install", func() {
						err := act()
						Expect(err).ToNot(HaveOccurred())
						Expect(bundle.ActionsCalled).To(Equal([]string{})) // no Install
					})

					It("does not download the job template", func() {
						err := act()
						Expect(err).ToNot(HaveOccurred())
						Expect(blobstore.GetBlobIDs).To(BeNil())
					})
				})

				Context("when job is not installed", func() {
					BeforeEach(func() {
						bundle.Installed = false
					})

					It("installs job (but does not enable)", func() {
						err := act()
						Expect(err).ToNot(HaveOccurred())
						Expect(bundle.ActionsCalled).To(Equal([]string{"Install"}))
					})

					ItInstallsJob(act)
				})
			})

			Describe("Apply", func() {
				act := func() error { return applier.Apply(job) }

				It("return an error if getting file bundle fails", func() {
					jobsBc.GetErr = errors.New("fake-get-bundle-error")

					err := act()
					Expect(err).To(HaveOccurred())
					Expect(err.Error()).To(ContainSubstring("fake-get-bundle-error"))
				})

				It("returns an error if checking for installed path fails", func() {
					bundle.IsInstalledErr = errors.New("fake-is-installed-error")

					err := act()
					Expect(err).To(HaveOccurred())
					Expect(err.Error()).To(ContainSubstring("fake-is-installed-error"))
				})

				Context("when job is already installed", func() {
					BeforeEach(func() {
						bundle.Installed = true
					})

					It("does not install but only enables job", func() {
						err := act()
						Expect(err).ToNot(HaveOccurred())
						Expect(bundle.ActionsCalled).To(Equal([]string{"Enable"})) // no Install
					})

					It("returns error when job enable fails", func() {
						bundle.EnableError = errors.New("fake-enable-error")

						err := act()
						Expect(err).To(HaveOccurred())
						Expect(err.Error()).To(ContainSubstring("fake-enable-error"))
					})

					It("does not download the job template", func() {
						err := act()
						Expect(err).ToNot(HaveOccurred())
						Expect(blobstore.GetBlobIDs).To(BeNil())
					})

					ItUpdatesPackages(act)
				})

				Context("when job is not installed", func() {
					BeforeEach(func() {
						bundle.Installed = false
					})

					It("installs and enables job", func() {
						err := act()
						Expect(err).ToNot(HaveOccurred())
						Expect(bundle.ActionsCalled).To(Equal([]string{"Install", "Enable"}))
					})

					It("returns error when job enable fails", func() {
						bundle.EnableError = errors.New("fake-enable-error")

						err := act()
						Expect(err).To(HaveOccurred())
						Expect(err.Error()).To(ContainSubstring("fake-enable-error"))
					})

					ItInstallsJob(act)

					ItUpdatesPackages(act)
				})
			})
		})

		Describe("Configure", func() {
			It("adds job to the job supervisor", func() {
				job, bundle := buildJob(jobsBc)

				fs := fakesys.NewFakeFileSystem()
				fs.WriteFileString("/path/to/job/monit", "some conf")
				fs.SetGlob("/path/to/job/*.monit", []string{"/path/to/job/subjob.monit"})

				bundle.GetDirPath = "/path/to/job"
				bundle.GetDirFs = fs

				err := applier.Configure(job, 0)
				Expect(err).ToNot(HaveOccurred())

				Expect(len(jobSupervisor.AddJobArgs)).To(Equal(2))

				Expect(jobSupervisor.AddJobArgs[0]).To(Equal(fakejobsuper.AddJobArgs{
					Name:       job.Name,
					Index:      0,
					ConfigPath: "/path/to/job/monit",
				}))

				Expect(jobSupervisor.AddJobArgs[1]).To(Equal(fakejobsuper.AddJobArgs{
					Name:       job.Name + "_subjob",
					Index:      0,
					ConfigPath: "/path/to/job/subjob.monit",
				}))
			})

			It("does not require monit script", func() {
				job, bundle := buildJob(jobsBc)

				fs := fakesys.NewFakeFileSystem()
				bundle.GetDirFs = fs

				err := applier.Configure(job, 0)
				Expect(err).ToNot(HaveOccurred())
				Expect(len(jobSupervisor.AddJobArgs)).To(Equal(0))
			})
		})

		Describe("KeepOnly", func() {
			It("first disables and then uninstalls jobs that are not in keeponly list", func() {
				_, bundle1 := buildJob(jobsBc)
				job2, bundle2 := buildJob(jobsBc)
				_, bundle3 := buildJob(jobsBc)
				job4, bundle4 := buildJob(jobsBc)

				jobsBc.ListBundles = []boshbc.Bundle{bundle1, bundle2, bundle3, bundle4}

				err := applier.KeepOnly([]models.Job{job4, job2})
				Expect(err).ToNot(HaveOccurred())

				Expect(bundle1.ActionsCalled).To(Equal([]string{"Disable", "Uninstall"}))
				Expect(bundle2.ActionsCalled).To(Equal([]string{}))
				Expect(bundle3.ActionsCalled).To(Equal([]string{"Disable", "Uninstall"}))
				Expect(bundle4.ActionsCalled).To(Equal([]string{}))
			})

			It("returns error when bundle collection fails to return list of installed bundles", func() {
				jobsBc.ListErr = errors.New("fake-bc-list-error")

				err := applier.KeepOnly([]models.Job{})
				Expect(err).To(HaveOccurred())
				Expect(err.Error()).To(ContainSubstring("fake-bc-list-error"))
			})

			It("returns error when bundle collection cannot retrieve bundle for keep-only job", func() {
				job1, bundle1 := buildJob(jobsBc)

				jobsBc.ListBundles = []boshbc.Bundle{bundle1}
				jobsBc.GetErr = errors.New("fake-bc-get-error")

				err := applier.KeepOnly([]models.Job{job1})
				Expect(err).To(HaveOccurred())
				Expect(err.Error()).To(ContainSubstring("fake-bc-get-error"))
			})

			It("returns error when at least one bundle cannot be disabled", func() {
				_, bundle1 := buildJob(jobsBc)

				jobsBc.ListBundles = []boshbc.Bundle{bundle1}
				bundle1.DisableErr = errors.New("fake-bc-disable-error")

				err := applier.KeepOnly([]models.Job{})
				Expect(err).To(HaveOccurred())
				Expect(err.Error()).To(ContainSubstring("fake-bc-disable-error"))
			})

			It("returns error when at least one bundle cannot be uninstalled", func() {
				_, bundle1 := buildJob(jobsBc)

				jobsBc.ListBundles = []boshbc.Bundle{bundle1}
				bundle1.UninstallErr = errors.New("fake-bc-uninstall-error")

				err := applier.KeepOnly([]models.Job{})
				Expect(err).To(HaveOccurred())
				Expect(err.Error()).To(ContainSubstring("fake-bc-uninstall-error"))
			})
		})
	})
}
Example #9
0
func init() {
	Describe("DrainAction", func() {
		var (
			notifier            *fakenotif.FakeNotifier
			specService         *fakeas.FakeV1Service
			drainScriptProvider *fakedrain.FakeDrainScriptProvider
			jobSupervisor       *fakejobsuper.FakeJobSupervisor
			action              DrainAction
		)

		BeforeEach(func() {
			notifier = fakenotif.NewFakeNotifier()
			specService = fakeas.NewFakeV1Service()
			drainScriptProvider = fakedrain.NewFakeDrainScriptProvider()
			jobSupervisor = fakejobsuper.NewFakeJobSupervisor()
			action = NewDrain(notifier, specService, drainScriptProvider, jobSupervisor)
		})

		BeforeEach(func() {
			drainScriptProvider.NewDrainScriptDrainScript.ExistsBool = true
		})

		It("is asynchronous", func() {
			Expect(action.IsAsynchronous()).To(BeTrue())
		})

		It("is not persistent", func() {
			Expect(action.IsPersistent()).To(BeFalse())
		})

		Context("when drain update is requested", func() {
			act := func() (int, error) { return action.Run(DrainTypeUpdate, boshas.V1ApplySpec{}) }

			Context("when current agent has a job spec template", func() {
				var currentSpec boshas.V1ApplySpec

				BeforeEach(func() {
					currentSpec = boshas.V1ApplySpec{}
					currentSpec.JobSpec.Template = "foo"
					specService.Spec = currentSpec
				})

				It("unmonitors services so that drain scripts can kill processes on their own", func() {
					value, err := act()
					Expect(err).ToNot(HaveOccurred())
					Expect(value).To(Equal(1))

					Expect(jobSupervisor.Unmonitored).To(BeTrue())
				})

				Context("when unmonitoring services succeeds", func() {
					It("does not notify of job shutdown", func() {
						value, err := act()
						Expect(err).ToNot(HaveOccurred())
						Expect(value).To(Equal(1))

						Expect(notifier.NotifiedShutdown).To(BeFalse())
					})

					Context("when new apply spec is provided", func() {
						newSpec := boshas.V1ApplySpec{
							PackageSpecs: map[string]boshas.PackageSpec{
								"foo": boshas.PackageSpec{
									Name: "foo",
									Sha1: "foo-sha1-new",
								},
							},
						}

						Context("when drain script exists", func() {
							It("runs drain script with job_shutdown param", func() {
								value, err := action.Run(DrainTypeUpdate, newSpec)
								Expect(err).ToNot(HaveOccurred())
								Expect(value).To(Equal(1))

								Expect(drainScriptProvider.NewDrainScriptTemplateName).To(Equal("foo"))
								Expect(drainScriptProvider.NewDrainScriptDrainScript.DidRun).To(BeTrue())

								params := drainScriptProvider.NewDrainScriptDrainScript.RunParams
								Expect(params).To(Equal(boshdrain.NewUpdateDrainParams(currentSpec, newSpec)))
							})

							Context("when drain script runs and errs", func() {
								It("returns error", func() {
									drainScriptProvider.NewDrainScriptDrainScript.RunError = errors.New("fake-drain-run-error")

									value, err := act()
									Expect(err).To(HaveOccurred())
									Expect(err.Error()).To(ContainSubstring("fake-drain-run-error"))
									Expect(value).To(Equal(0))
								})
							})
						})

						Context("when drain script does not exist", func() {
							It("returns 0", func() {
								drainScriptProvider.NewDrainScriptDrainScript.ExistsBool = false

								value, err := act()
								Expect(err).ToNot(HaveOccurred())
								Expect(value).To(Equal(0))

								Expect(drainScriptProvider.NewDrainScriptDrainScript.DidRun).To(BeFalse())
							})
						})
					})

					Context("when apply spec is not provided", func() {
						It("returns error", func() {
							value, err := action.Run(DrainTypeUpdate)
							Expect(err).To(HaveOccurred())
							Expect(err.Error()).To(ContainSubstring("Drain update requires new spec"))
							Expect(value).To(Equal(0))
						})
					})
				})

				Context("when unmonitoring services fails", func() {
					It("returns error", func() {
						jobSupervisor.UnmonitorErr = errors.New("fake-unmonitor-error")

						value, err := act()
						Expect(err).To(HaveOccurred())
						Expect(err.Error()).To(ContainSubstring("fake-unmonitor-error"))
						Expect(value).To(Equal(0))
					})
				})
			})

			Context("when current agent spec does not have a job spec template", func() {
				It("returns 0 and does not run drain script", func() {
					specService.Spec = boshas.V1ApplySpec{}

					value, err := act()
					Expect(err).ToNot(HaveOccurred())
					Expect(value).To(Equal(0))

					Expect(drainScriptProvider.NewDrainScriptDrainScript.DidRun).To(BeFalse())
				})
			})
		})

		Context("when drain shutdown is requested", func() {
			act := func() (int, error) { return action.Run(DrainTypeShutdown) }

			Context("when current agent has a job spec template", func() {
				var currentSpec boshas.V1ApplySpec

				BeforeEach(func() {
					currentSpec = boshas.V1ApplySpec{}
					currentSpec.JobSpec.Template = "foo"
					specService.Spec = currentSpec
				})

				It("unmonitors services so that drain scripts can kill processes on their own", func() {
					value, err := act()
					Expect(err).ToNot(HaveOccurred())
					Expect(value).To(Equal(1))

					Expect(jobSupervisor.Unmonitored).To(BeTrue())
				})

				Context("when unmonitoring services succeeds", func() {
					It("notifies that job is about to shutdown", func() {
						value, err := act()
						Expect(err).ToNot(HaveOccurred())
						Expect(value).To(Equal(1))

						Expect(notifier.NotifiedShutdown).To(BeTrue())
					})

					Context("when job shutdown notification succeeds", func() {
						Context("when drain script exists", func() {
							It("runs drain script with job_shutdown param passing no apply spec", func() {
								value, err := action.Run(DrainTypeShutdown)
								Expect(err).ToNot(HaveOccurred())
								Expect(value).To(Equal(1))

								Expect(drainScriptProvider.NewDrainScriptTemplateName).To(Equal("foo"))
								Expect(drainScriptProvider.NewDrainScriptDrainScript.DidRun).To(BeTrue())

								params := drainScriptProvider.NewDrainScriptDrainScript.RunParams
								Expect(params).To(Equal(boshdrain.NewShutdownDrainParams(currentSpec, nil)))
							})

							It("runs drain script with job_shutdown param passing in first apply spec", func() {
								newSpec := boshas.V1ApplySpec{}
								newSpec.JobSpec.Template = "fake-updated-template"

								value, err := action.Run(DrainTypeShutdown, newSpec)
								Expect(err).ToNot(HaveOccurred())
								Expect(value).To(Equal(1))

								Expect(drainScriptProvider.NewDrainScriptTemplateName).To(Equal("foo"))
								Expect(drainScriptProvider.NewDrainScriptDrainScript.DidRun).To(BeTrue())

								params := drainScriptProvider.NewDrainScriptDrainScript.RunParams
								Expect(params).To(Equal(boshdrain.NewShutdownDrainParams(currentSpec, &newSpec)))
							})

							Context("when drain script runs and errs", func() {
								It("returns error", func() {
									drainScriptProvider.NewDrainScriptDrainScript.RunError = errors.New("fake-drain-run-error")

									value, err := act()
									Expect(err).To(HaveOccurred())
									Expect(err.Error()).To(ContainSubstring("fake-drain-run-error"))
									Expect(value).To(Equal(0))
								})
							})
						})

						Context("when drain script does not exist", func() {
							It("returns 0", func() {
								drainScriptProvider.NewDrainScriptDrainScript.ExistsBool = false

								value, err := act()
								Expect(err).ToNot(HaveOccurred())
								Expect(value).To(Equal(0))

								Expect(drainScriptProvider.NewDrainScriptDrainScript.DidRun).To(BeFalse())
							})
						})
					})

					Context("when job shutdown notification fails", func() {
						It("returns error if job shutdown notifications errs", func() {
							notifier.NotifyShutdownErr = errors.New("fake-shutdown-error")

							value, err := act()
							Expect(err).To(HaveOccurred())
							Expect(err.Error()).To(ContainSubstring("fake-shutdown-error"))
							Expect(value).To(Equal(0))
						})
					})
				})

				Context("when unmonitoring services fails", func() {
					It("returns error", func() {
						jobSupervisor.UnmonitorErr = errors.New("fake-unmonitor-error")

						value, err := act()
						Expect(err).To(HaveOccurred())
						Expect(err.Error()).To(ContainSubstring("fake-unmonitor-error"))
						Expect(value).To(Equal(0))
					})
				})
			})

			Context("when current agent spec does not have a job spec template", func() {
				It("returns 0 and does not run drain script", func() {
					specService.Spec = boshas.V1ApplySpec{}

					value, err := act()
					Expect(err).ToNot(HaveOccurred())
					Expect(value).To(Equal(0))

					Expect(drainScriptProvider.NewDrainScriptDrainScript.DidRun).To(BeFalse())
				})
			})
		})

		Context("when drain status is requested", func() {
			act := func() (int, error) { return action.Run(DrainTypeStatus) }

			Context("when current agent has a job spec template", func() {
				var currentSpec boshas.V1ApplySpec

				BeforeEach(func() {
					currentSpec = boshas.V1ApplySpec{}
					currentSpec.JobSpec.Template = "foo"
					specService.Spec = currentSpec
				})

				It("unmonitors services so that drain scripts can kill processes on their own", func() {
					value, err := act()
					Expect(err).ToNot(HaveOccurred())
					Expect(value).To(Equal(1))

					Expect(jobSupervisor.Unmonitored).To(BeTrue())
				})

				It("does not notify of job shutdown", func() {
					value, err := act()
					Expect(err).ToNot(HaveOccurred())
					Expect(value).To(Equal(1))

					Expect(notifier.NotifiedShutdown).To(BeFalse())
				})

				Context("when unmonitoring services succeeds", func() {
					Context("when drain script exists", func() {
						It("runs drain script with job_check_status param passing no apply spec", func() {
							value, err := action.Run(DrainTypeStatus)
							Expect(err).ToNot(HaveOccurred())
							Expect(value).To(Equal(1))

							Expect(drainScriptProvider.NewDrainScriptTemplateName).To(Equal("foo"))
							Expect(drainScriptProvider.NewDrainScriptDrainScript.DidRun).To(BeTrue())

							params := drainScriptProvider.NewDrainScriptDrainScript.RunParams
							Expect(params).To(Equal(boshdrain.NewStatusDrainParams(currentSpec, nil)))
						})

						It("runs drain script with job_check_status param passing in first apply spec", func() {
							newSpec := boshas.V1ApplySpec{}
							newSpec.JobSpec.Template = "fake-updated-template"

							value, err := action.Run(DrainTypeStatus, newSpec)
							Expect(err).ToNot(HaveOccurred())
							Expect(value).To(Equal(1))

							Expect(drainScriptProvider.NewDrainScriptTemplateName).To(Equal("foo"))
							Expect(drainScriptProvider.NewDrainScriptDrainScript.DidRun).To(BeTrue())

							params := drainScriptProvider.NewDrainScriptDrainScript.RunParams
							Expect(params).To(Equal(boshdrain.NewStatusDrainParams(currentSpec, &newSpec)))
						})

						Context("when drain script runs and errs", func() {
							It("returns error if drain script errs", func() {
								drainScriptProvider.NewDrainScriptDrainScript.RunError = errors.New("fake-drain-run-error")

								value, err := act()
								Expect(err).To(HaveOccurred())
								Expect(err.Error()).To(ContainSubstring("fake-drain-run-error"))
								Expect(value).To(Equal(0))
							})
						})
					})

					Context("when drain script does not exist", func() {
						It("returns error because drain status must be called after starting draining", func() {
							drainScriptProvider.NewDrainScriptDrainScript.ExistsBool = false

							value, err := act()
							Expect(err).To(HaveOccurred())
							Expect(err.Error()).To(ContainSubstring("Check Status on Drain action requires a valid drain script"))
							Expect(value).To(Equal(0))
						})
					})
				})

				Context("when unmonitoring services fails", func() {
					It("returns error if unmonitoring services errs", func() {
						jobSupervisor.UnmonitorErr = errors.New("fake-unmonitor-error")

						value, err := act()
						Expect(err).To(HaveOccurred())
						Expect(err.Error()).To(ContainSubstring("fake-unmonitor-error"))
						Expect(value).To(Equal(0))
					})
				})
			})

			Context("when current agent spec does not have a job spec template", func() {
				It("returns error because drain status should only be called after starting draining", func() {
					specService.Spec = boshas.V1ApplySpec{}

					value, err := action.Run(DrainTypeStatus)
					Expect(err).To(HaveOccurred())
					Expect(err.Error()).To(ContainSubstring("Check Status on Drain action requires job spec"))
					Expect(value).To(Equal(0))
				})
			})
		})
	})
}
Example #10
0
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"))
		})
	})
}