func (db *SQLDB) ClaimActualLRP(logger lager.Logger, processGuid string, index int32, instanceKey *models.ActualLRPInstanceKey) (*models.ActualLRPGroup, *models.ActualLRPGroup, error) { logger = logger.WithData(lager.Data{"process_guid": processGuid, "index": index, "instance_key": instanceKey}) logger.Info("starting") defer logger.Info("complete") var beforeActualLRP models.ActualLRP var actualLRP *models.ActualLRP err := db.transact(logger, func(logger lager.Logger, tx *sql.Tx) error { var err error actualLRP, err = db.fetchActualLRPForUpdate(logger, processGuid, index, false, tx) if err != nil { logger.Error("failed-fetching-actual-lrp-for-share", err) return err } beforeActualLRP = *actualLRP if !actualLRP.AllowsTransitionTo(&actualLRP.ActualLRPKey, instanceKey, models.ActualLRPStateClaimed) { logger.Error("cannot-transition-to-claimed", nil, lager.Data{"from_state": actualLRP.State, "same_instance_key": actualLRP.ActualLRPInstanceKey.Equal(instanceKey)}) return models.ErrActualLRPCannotBeClaimed } if actualLRP.State == models.ActualLRPStateClaimed && actualLRP.ActualLRPInstanceKey.Equal(instanceKey) { return nil } actualLRP.ModificationTag.Increment() actualLRP.State = models.ActualLRPStateClaimed actualLRP.ActualLRPInstanceKey = *instanceKey actualLRP.PlacementError = "" actualLRP.ActualLRPNetInfo = models.ActualLRPNetInfo{} actualLRP.Since = db.clock.Now().UnixNano() _, err = db.update(logger, tx, actualLRPsTable, SQLAttributes{ "state": actualLRP.State, "cell_id": actualLRP.CellId, "instance_guid": actualLRP.InstanceGuid, "modification_tag_index": actualLRP.ModificationTag.Index, "placement_error": actualLRP.PlacementError, "since": actualLRP.Since, "net_info": []byte{}, }, "process_guid = ? AND instance_index = ? AND evacuating = ?", processGuid, index, false, ) if err != nil { logger.Error("failed-claiming-actual-lrp", err) return db.convertSQLError(err) } return nil }) return &models.ActualLRPGroup{Instance: &beforeActualLRP}, &models.ActualLRPGroup{Instance: actualLRP}, err }
func (db *SQLDB) UnclaimActualLRP(logger lager.Logger, key *models.ActualLRPKey) (*models.ActualLRPGroup, *models.ActualLRPGroup, error) { logger = logger.WithData(lager.Data{"key": key}) var beforeActualLRP models.ActualLRP var actualLRP *models.ActualLRP processGuid := key.ProcessGuid index := key.Index err := db.transact(logger, func(logger lager.Logger, tx *sql.Tx) error { var err error actualLRP, err = db.fetchActualLRPForUpdate(logger, processGuid, index, false, tx) if err != nil { logger.Error("failed-fetching-actual-lrp-for-share", err) return err } beforeActualLRP = *actualLRP if actualLRP.State == models.ActualLRPStateUnclaimed { logger.Debug("already-unclaimed") return models.ErrActualLRPCannotBeUnclaimed } logger.Info("starting") defer logger.Info("complete") now := db.clock.Now().UnixNano() actualLRP.ModificationTag.Increment() actualLRP.State = models.ActualLRPStateUnclaimed actualLRP.ActualLRPInstanceKey.CellId = "" actualLRP.ActualLRPInstanceKey.InstanceGuid = "" actualLRP.Since = now actualLRP.ActualLRPNetInfo = models.ActualLRPNetInfo{} _, err = db.update(logger, tx, actualLRPsTable, SQLAttributes{ "state": actualLRP.State, "cell_id": actualLRP.CellId, "instance_guid": actualLRP.InstanceGuid, "modification_tag_index": actualLRP.ModificationTag.Index, "since": actualLRP.Since, "net_info": []byte{}, }, "process_guid = ? AND instance_index = ? AND evacuating = ?", processGuid, index, false, ) if err != nil { logger.Error("failed-to-unclaim-actual-lrp", err) return db.convertSQLError(err) } return nil }) return &models.ActualLRPGroup{Instance: &beforeActualLRP}, &models.ActualLRPGroup{Instance: actualLRP}, err }
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 logger.Debug("complete", lager.Data{"state_change": 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 }
unclaimingActualLRP1 = model_helpers.NewValidActualLRP("to-unclaim-1", 0) desiredLRP2 = model_helpers.NewValidDesiredLRP("to-unclaim-2").DesiredLRPSchedulingInfo() unclaimingActualLRP2 = model_helpers.NewValidActualLRP("to-unclaim-2", 1) keysWithMissingCells = []*models.ActualLRPKeyWithSchedulingInfo{ {Key: &unclaimingActualLRP1.ActualLRPKey, SchedulingInfo: &desiredLRP1}, {Key: &unclaimingActualLRP2.ActualLRPKey, SchedulingInfo: &desiredLRP2}, } keysToAuction = []*auctioneer.LRPStartRequest{&request1, &request2} cellID = "cell-id" instanceKey := models.NewActualLRPInstanceKey("instance-guid", cellID) retiringActualLRP1.CellId = cellID retiringActualLRP1.ActualLRPInstanceKey = instanceKey retiringActualLRP1.State = models.ActualLRPStateClaimed group1 := &models.ActualLRPGroup{Instance: retiringActualLRP1} retiringActualLRP2.CellId = cellID retiringActualLRP2.ActualLRPInstanceKey = instanceKey retiringActualLRP2.State = models.ActualLRPStateClaimed group2 := &models.ActualLRPGroup{Instance: retiringActualLRP2} fakeLRPDB.ActualLRPGroupByProcessGuidAndIndexStub = func(_ lager.Logger, processGuid string, _ int32) (*models.ActualLRPGroup, error) { if processGuid == retiringActualLRP1.ProcessGuid { return group1, nil } if processGuid == retiringActualLRP2.ProcessGuid { return group2, nil }
func (db *SQLDB) CrashActualLRP(logger lager.Logger, key *models.ActualLRPKey, instanceKey *models.ActualLRPInstanceKey, crashReason string) (*models.ActualLRPGroup, *models.ActualLRPGroup, bool, error) { logger = logger.WithData(lager.Data{"key": key, "instance_key": instanceKey, "crash_reason": crashReason}) logger.Info("starting") defer logger.Info("complete") var immediateRestart = false var beforeActualLRP models.ActualLRP var actualLRP *models.ActualLRP err := db.transact(logger, func(logger lager.Logger, tx *sql.Tx) error { var err error actualLRP, err = db.fetchActualLRPForUpdate(logger, key.ProcessGuid, key.Index, false, tx) if err != nil { logger.Error("failed-to-get-actual-lrp", err) return err } beforeActualLRP = *actualLRP latestChangeTime := time.Duration(db.clock.Now().UnixNano() - actualLRP.Since) var newCrashCount int32 if latestChangeTime > models.CrashResetTimeout && actualLRP.State == models.ActualLRPStateRunning { newCrashCount = 1 } else { newCrashCount = actualLRP.CrashCount + 1 } if !actualLRP.AllowsTransitionTo(&actualLRP.ActualLRPKey, instanceKey, models.ActualLRPStateCrashed) { logger.Error("failed-to-transition-to-crashed", nil, lager.Data{"from_state": actualLRP.State, "same_instance_key": actualLRP.ActualLRPInstanceKey.Equal(instanceKey)}) return models.ErrActualLRPCannotBeCrashed } actualLRP.ModificationTag.Increment() actualLRP.State = models.ActualLRPStateCrashed actualLRP.ActualLRPInstanceKey.InstanceGuid = "" actualLRP.ActualLRPInstanceKey.CellId = "" actualLRP.ActualLRPNetInfo = models.ActualLRPNetInfo{} actualLRP.CrashCount = newCrashCount actualLRP.CrashReason = crashReason evacuating := false if actualLRP.ShouldRestartImmediately(models.NewDefaultRestartCalculator()) { actualLRP.State = models.ActualLRPStateUnclaimed immediateRestart = true } now := db.clock.Now().UnixNano() actualLRP.Since = now _, err = db.update(logger, tx, actualLRPsTable, SQLAttributes{ "state": actualLRP.State, "cell_id": actualLRP.CellId, "instance_guid": actualLRP.InstanceGuid, "modification_tag_index": actualLRP.ModificationTag.Index, "crash_count": actualLRP.CrashCount, "crash_reason": truncateString(actualLRP.CrashReason, 1024), "since": actualLRP.Since, "net_info": []byte{}, }, "process_guid = ? AND instance_index = ? AND evacuating = ?", key.ProcessGuid, key.Index, evacuating, ) if err != nil { logger.Error("failed-to-crash-actual-lrp", err) return db.convertSQLError(err) } return nil }) return &models.ActualLRPGroup{Instance: &beforeActualLRP}, &models.ActualLRPGroup{Instance: actualLRP}, immediateRestart, err }
func (db *SQLDB) StartActualLRP(logger lager.Logger, key *models.ActualLRPKey, instanceKey *models.ActualLRPInstanceKey, netInfo *models.ActualLRPNetInfo) (*models.ActualLRPGroup, *models.ActualLRPGroup, error) { logger = logger.WithData(lager.Data{"actual_lrp_key": key, "actual_lrp_instance_key": instanceKey, "net_info": netInfo}) var beforeActualLRP models.ActualLRP var actualLRP *models.ActualLRP err := db.transact(logger, func(logger lager.Logger, tx *sql.Tx) error { var err error actualLRP, err = db.fetchActualLRPForUpdate(logger, key.ProcessGuid, key.Index, false, tx) if err == models.ErrResourceNotFound { actualLRP, err = db.createRunningActualLRP(logger, key, instanceKey, netInfo, tx) return err } if err != nil { logger.Error("failed-to-get-actual-lrp", err) return err } beforeActualLRP = *actualLRP if actualLRP.ActualLRPKey.Equal(key) && actualLRP.ActualLRPInstanceKey.Equal(instanceKey) && actualLRP.ActualLRPNetInfo.Equal(netInfo) && actualLRP.State == models.ActualLRPStateRunning { logger.Debug("nothing-to-change") return nil } if !actualLRP.AllowsTransitionTo(key, instanceKey, models.ActualLRPStateRunning) { logger.Error("failed-to-transition-actual-lrp-to-started", nil) return models.ErrActualLRPCannotBeStarted } logger.Info("starting") defer logger.Info("completed") now := db.clock.Now().UnixNano() evacuating := false actualLRP.ActualLRPInstanceKey = *instanceKey actualLRP.ActualLRPNetInfo = *netInfo actualLRP.State = models.ActualLRPStateRunning actualLRP.Since = now actualLRP.ModificationTag.Increment() actualLRP.PlacementError = "" netInfoData, err := db.serializeModel(logger, &actualLRP.ActualLRPNetInfo) if err != nil { logger.Error("failed-to-serialize-net-info", err) return err } _, err = db.update(logger, tx, actualLRPsTable, SQLAttributes{ "state": actualLRP.State, "cell_id": actualLRP.CellId, "instance_guid": actualLRP.InstanceGuid, "modification_tag_index": actualLRP.ModificationTag.Index, "placement_error": actualLRP.PlacementError, "since": actualLRP.Since, "net_info": netInfoData, }, "process_guid = ? AND instance_index = ? AND evacuating = ?", key.ProcessGuid, key.Index, evacuating, ) if err != nil { logger.Error("failed-starting-actual-lrp", err) return db.convertSQLError(err) } return nil }) return &models.ActualLRPGroup{Instance: &beforeActualLRP}, &models.ActualLRPGroup{Instance: actualLRP}, err }
})) }) It("returns the previous and the next actual lrp group", func() { before, after, err := etcdDB.UnclaimActualLRP(logger, lrpKey) Expect(err).NotTo(HaveOccurred()) Expect(before).To(Equal(&models.ActualLRPGroup{Instance: actualLRP})) group, err := etcdDB.ActualLRPGroupByProcessGuidAndIndex(logger, guid, index) Expect(err).NotTo(HaveOccurred()) Expect(after).To(Equal(group)) }) Context("when the actual lrp is already unclaimed", func() { BeforeEach(func() { actualLRP.State = models.ActualLRPStateUnclaimed actualLRP.ActualLRPNetInfo = models.EmptyActualLRPNetInfo() actualLRP.ActualLRPInstanceKey = models.ActualLRPInstanceKey{} etcdHelper.SetRawActualLRP(actualLRP) }) It("returns an error", func() { _, _, err := etcdDB.UnclaimActualLRP(logger, lrpKey) Expect(err).To(HaveOccurred()) }) }) Context("when compare and swap fails", func() { BeforeEach(func() { fakeStoreClient.CompareAndSwapReturns(nil, errors.New("OOOOOH NOSE!"))
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() { request := newTestRequest(requestBody) handler.ActualLRPGroups(logger, responseRecorder, request) }) Context("when reading actual lrps from DB succeeds", func() { var actualLRPGroups []*models.ActualLRPGroup BeforeEach(func() { actualLRPGroups = []*models.ActualLRPGroup{ {Instance: &actualLRP1},
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))
"code.cloudfoundry.org/bbs/models/test/model_helpers" "github.com/tedsuo/ifrit/ginkgomon" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) var _ = Describe("Evacuation API", func() { var actual *models.ActualLRP BeforeEach(func() { bbsRunner = testrunner.New(bbsBinPath, bbsArgs) bbsProcess = ginkgomon.Invoke(bbsRunner) actual = model_helpers.NewValidActualLRP("some-process-guid", 1) actual.State = models.ActualLRPStateRunning desiredLRP := model_helpers.NewValidDesiredLRP(actual.ProcessGuid) desiredLRP.Instances = 2 Expect(client.DesireLRP(logger, desiredLRP)).To(Succeed()) Expect(client.ClaimActualLRP(logger, actual.ProcessGuid, 1, &actual.ActualLRPInstanceKey)).To(Succeed()) _, err := client.ActualLRPGroupByProcessGuidAndIndex(logger, actual.ProcessGuid, int(actual.Index)) 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)
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(logger, 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())