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 itValidatesPresenceOfPlacementError(lrp *models.ActualLRP) { Context("when placement error is set", func() { BeforeEach(func() { lrp.PlacementError = "insufficient capacity" }) It("validate does not return an error", func() { Expect(lrp.Validate()).NotTo(HaveOccurred()) }) }) Context("when placement error is not set", func() { BeforeEach(func() { lrp.PlacementError = "" }) It("validate does not return an error", func() { Expect(lrp.Validate()).NotTo(HaveOccurred()) }) }) }
func itValidatesAbsenceOfPlacementError(lrp *models.ActualLRP) { Context("when placement error is set", func() { BeforeEach(func() { lrp.PlacementError = "insufficient capacity" }) It("validate returns an error", func() { err := lrp.Validate() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("placement error")) }) }) Context("when placement error is not set", func() { BeforeEach(func() { lrp.PlacementError = "" }) It("validate does not return an error", func() { Expect(lrp.Validate()).NotTo(HaveOccurred()) }) }) }
func (db *SQLDB) FailActualLRP(logger lager.Logger, key *models.ActualLRPKey, placementError string) (*models.ActualLRPGroup, *models.ActualLRPGroup, error) { logger = logger.WithData(lager.Data{"actual_lrp_key": key, "placement_error": placementError}) 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, key.ProcessGuid, key.Index, false, tx) if err != nil { logger.Error("failed-to-get-actual-lrp", err) return err } beforeActualLRP = *actualLRP if actualLRP.State != models.ActualLRPStateUnclaimed { logger.Error("cannot-fail-actual-lrp", nil, lager.Data{"from_state": actualLRP.State}) return models.ErrActualLRPCannotBeFailed } now := db.clock.Now().UnixNano() actualLRP.ModificationTag.Increment() actualLRP.PlacementError = placementError actualLRP.Since = now evacuating := false _, err = db.update(logger, tx, actualLRPsTable, SQLAttributes{ "modification_tag_index": actualLRP.ModificationTag.Index, "placement_error": truncateString(actualLRP.PlacementError, 1024), "since": actualLRP.Since, }, "process_guid = ? AND instance_index = ? AND evacuating = ?", key.ProcessGuid, key.Index, evacuating, ) if err != nil { logger.Error("failed-failing-actual-lrp", err) return db.convertSQLError(err) } return nil }) return &models.ActualLRPGroup{Instance: &beforeActualLRP}, &models.ActualLRPGroup{Instance: actualLRP}, 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 }
Expect(claimErr).To(Equal(models.ErrActualLRPCannotBeClaimed)) }) It("does not alter the existing actual", func() { lrpGroupInBBS, err := etcdDB.ActualLRPGroupByProcessGuidAndIndex(logger, processGuid, index) Expect(err).NotTo(HaveOccurred()) Expect(lrpGroupInBBS.Instance.InstanceGuid).To(Equal(instanceGuid)) }) }) }) Context("when there is a placement error", func() { BeforeEach(func() { instanceKey = models.NewActualLRPInstanceKey("some-instance-guid", cellID) actualLRP.PlacementError = "insufficient resources" etcdHelper.SetRawActualLRP(actualLRP) }) It("should clear placement error", func() { Expect(claimErr).NotTo(HaveOccurred()) lrp, err := etcdDB.ActualLRPGroupByProcessGuidAndIndex(logger, processGuid, index) Expect(err).NotTo(HaveOccurred()) Expect(lrp.Instance.PlacementError).To(BeEmpty()) }) It("returns the existing actual lrp group", func() { Expect(beforeActualGroup).To(Equal(&models.ActualLRPGroup{Instance: actualLRP})) }) }) })
}) It("does not emit any events", func() { Consistently(actualHub.EmitCallCount).Should(Equal(0)) }) }) }) Context("when the instance is unclaimed", func() { BeforeEach(func() { actual.State = models.ActualLRPStateUnclaimed }) Context("without a placement error", func() { BeforeEach(func() { actual.PlacementError = "" group := &models.ActualLRPGroup{Evacuating: afterActual} fakeEvacuationDB.EvacuateActualLRPReturns(group, nil) }) It("evacuates the LRP", func() { response := models.EvacuationResponse{} err := response.Unmarshal(responseRecorder.Body.Bytes()) Expect(err).NotTo(HaveOccurred()) Expect(response.KeepContainer).To(BeTrue()) Expect(response.Error).To(BeNil()) Expect(fakeEvacuationDB.EvacuateActualLRPCallCount()).To(Equal(1)) _, actualLRPKey, actualLRPInstanceKey, actualLrpNetInfo, ttl := fakeEvacuationDB.EvacuateActualLRPArgsForCall(0) Expect(*actualLRPKey).To(Equal(actual.ActualLRPKey)) Expect(*actualLRPInstanceKey).To(Equal(actual.ActualLRPInstanceKey))