func (db *ETCDDB) unclaimActualLRPWithIndex( logger lager.Logger, lrp *models.ActualLRP, storeIndex uint64, actualLRPKey *models.ActualLRPKey, actualLRPInstanceKey *models.ActualLRPInstanceKey, ) (change stateChange, err error) { logger = logger.Session("unclaim-actual-lrp-with-index") defer func() { logger.Debug("complete", lager.Data{"stateChange": change, "error": err}) }() if !lrp.ActualLRPKey.Equal(actualLRPKey) { logger.Error("failed-actual-lrp-key-differs", models.ErrActualLRPCannotBeUnclaimed) return stateDidNotChange, models.ErrActualLRPCannotBeUnclaimed } if lrp.State == models.ActualLRPStateUnclaimed { logger.Info("already-unclaimed") return stateDidNotChange, nil } if !lrp.ActualLRPInstanceKey.Equal(actualLRPInstanceKey) { logger.Error("failed-actual-lrp-instance-key-differs", models.ErrActualLRPCannotBeUnclaimed) return stateDidNotChange, models.ErrActualLRPCannotBeUnclaimed } lrp.Since = db.clock.Now().UnixNano() lrp.State = models.ActualLRPStateUnclaimed lrp.ActualLRPInstanceKey = models.ActualLRPInstanceKey{} lrp.ActualLRPNetInfo = models.EmptyActualLRPNetInfo() lrp.ModificationTag.Increment() err = lrp.Validate() if err != nil { logger.Error("failed-to-validate-unclaimed-lrp", err) return stateDidNotChange, models.NewError(models.Error_InvalidRecord, err.Error()) } lrpData, serialErr := db.serializeModel(logger, lrp) if serialErr != nil { logger.Error("failed-to-marshal-unclaimed-lrp", serialErr) return stateDidNotChange, serialErr } _, err = db.client.CompareAndSwap(ActualLRPSchemaPath(actualLRPKey.ProcessGuid, actualLRPKey.Index), lrpData, 0, storeIndex) if err != nil { logger.Error("failed-to-compare-and-swap", err) return stateDidNotChange, models.ErrActualLRPCannotBeUnclaimed } logger.Debug("changed-to-unclaimed") return stateDidChange, nil }
actualLRP2 = models.ActualLRP{ ActualLRPKey: models.NewActualLRPKey( "process-guid-1", 2, "domain-1", ), ActualLRPInstanceKey: models.NewActualLRPInstanceKey( "instance-guid-1", "cell-id-1", ), State: models.ActualLRPStateClaimed, Since: 4444, } evacuatingLRP2 = actualLRP2 evacuatingLRP2.State = models.ActualLRPStateRunning evacuatingLRP2.Since = 3417 }) JustBeforeEach(func() { handler.ActualLRPGroups(responseRecorder, request) }) Context("when reading actual lrps from DB succeeds", func() { var actualLRPGroups *models.ActualLRPGroups BeforeEach(func() { actualLRPGroups = &models.ActualLRPGroups{ []*models.ActualLRPGroup{ {Instance: &actualLRP1}, {Instance: &actualLRP2, Evacuating: &evacuatingLRP2},
actualLRP2 = models.ActualLRP{ ActualLRPKey: models.NewActualLRPKey( "process-guid-1", 2, "domain-1", ), ActualLRPInstanceKey: models.NewActualLRPInstanceKey( "instance-guid-1", "cell-id-1", ), State: proto.String(models.ActualLRPStateClaimed), Since: proto.Int64(4444), } evacuatingLRP2 = actualLRP2 evacuatingLRP2.State = proto.String(models.ActualLRPStateRunning) evacuatingLRP2.Since = proto.Int64(3417) }) // old before each BeforeEach(func() { oldActualLRP1 = oldmodels.ActualLRP{ ActualLRPKey: oldmodels.NewActualLRPKey( "process-guid-0", 1, "domain-0", ), ActualLRPInstanceKey: oldmodels.NewActualLRPInstanceKey( "instance-guid-0", "cell-id-0", ),
Expect(resolvedLRP).To(Equal(evacuatingLRP)) Expect(evacuating).To(BeTrue()) }) }) Context("When both the Instance and the Evacuating LRP are set", func() { BeforeEach(func() { group = models.ActualLRPGroup{ Evacuating: evacuatingLRP, Instance: instanceLRP, } }) Context("When the Instance is UNCLAIMED", func() { BeforeEach(func() { instanceLRP.State = models.ActualLRPStateUnclaimed }) It("returns the Evacuating LRP", func() { Expect(resolvedLRP).To(Equal(evacuatingLRP)) Expect(evacuating).To(BeTrue()) }) }) Context("When the Instance is CLAIMED", func() { BeforeEach(func() { instanceLRP.State = models.ActualLRPStateClaimed }) It("returns the Evacuating LRP", func() { Expect(resolvedLRP).To(Equal(evacuatingLRP))
. "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) var _ = Describe("Evacuation API", func() { BeforeEach(func() { bbsRunner = testrunner.New(bbsBinPath, bbsArgs) bbsProcess = ginkgomon.Invoke(bbsRunner) }) var actual *models.ActualLRP BeforeEach(func() { actual = model_helpers.NewValidActualLRP("some-process-guid", 1) actual.State = models.ActualLRPStateRunning desiredLRP := model_helpers.NewValidDesiredLRP(actual.ProcessGuid) desiredLRP.Instances = 2 err := client.DesireLRP(logger, desiredLRP) Expect(err).NotTo(HaveOccurred()) err = client.ClaimActualLRP(logger, actual.ProcessGuid, 1, &actual.ActualLRPInstanceKey) Expect(err).NotTo(HaveOccurred()) }) Describe("RemoveEvacuatingActualLRP", func() { It("removes the evacuating actual_lrp", func() { _, err := client.EvacuateClaimedActualLRP(logger, &actual.ActualLRPKey, &actual.ActualLRPInstanceKey) Expect(err).NotTo(HaveOccurred()) err = client.RemoveEvacuatingActualLRP(logger, &actual.ActualLRPKey, &actual.ActualLRPInstanceKey) Expect(err).NotTo(HaveOccurred())
} actualResponse := serialization.ActualLRPProtoToResponse(actualLRP, true) Expect(actualResponse).To(Equal(expectedResponse)) }) It("maps model states to receptor states", func() { expectedStateMap := map[string]receptor.ActualLRPState{ models.ActualLRPStateUnclaimed: receptor.ActualLRPStateUnclaimed, models.ActualLRPStateClaimed: receptor.ActualLRPStateClaimed, models.ActualLRPStateRunning: receptor.ActualLRPStateRunning, models.ActualLRPStateCrashed: receptor.ActualLRPStateCrashed, } for modelState, jsonState := range expectedStateMap { actualLRP.State = modelState Expect(serialization.ActualLRPProtoToResponse(actualLRP, false).State).To(Equal(jsonState)) } actualLRP.State = "" Expect(serialization.ActualLRPProtoToResponse(actualLRP, false).State).To(Equal(receptor.ActualLRPStateInvalid)) }) Context("when there is placement error", func() { BeforeEach(func() { actualLRP.State = models.ActualLRPStateUnclaimed actualLRP.PlacementError = "some-error" }) It("includes the placement error", func() { actualResponse := serialization.ActualLRPProtoToResponse(actualLRP, false)
actual *models.ActualLRP afterActual *models.ActualLRP desiredLRP *models.DesiredLRP ) BeforeEach(func() { desiredLRP = model_helpers.NewValidDesiredLRP("the-guid") fakeDesiredLRPDB.DesiredLRPByProcessGuidReturns(desiredLRP, nil) actual = model_helpers.NewValidActualLRP("process-guid", 1) requestBody = &models.EvacuateClaimedActualLRPRequest{ ActualLrpKey: &actual.ActualLRPKey, ActualLrpInstanceKey: &actual.ActualLRPInstanceKey, } afterActual = model_helpers.NewValidActualLRP("process-guid", 1) afterActual.State = models.ActualLRPStateUnclaimed fakeActualLRPDB.ActualLRPGroupByProcessGuidAndIndexReturns(&models.ActualLRPGroup{Evacuating: actual}, nil) fakeActualLRPDB.UnclaimActualLRPReturns(&models.ActualLRPGroup{Instance: actual}, &models.ActualLRPGroup{Instance: afterActual}, nil) request = newTestRequest(requestBody) }) JustBeforeEach(func() { handler.EvacuateClaimedActualLRP(responseRecorder, request) Expect(responseRecorder.Code).To(Equal(http.StatusOK)) }) It("removes the evacuating actual lrp", func() { response := models.EvacuationResponse{} err := response.Unmarshal(responseRecorder.Body.Bytes()) Expect(err).NotTo(HaveOccurred())