func (t *ETCDHelper) SetRawEvacuatingActualLRP(lrp *models.ActualLRP, ttlInSeconds uint64) { value, err := t.serializer.Marshal(t.logger, t.format, lrp) Expect(err).NotTo(HaveOccurred()) key := etcddb.EvacuatingActualLRPSchemaPath(lrp.GetProcessGuid(), lrp.GetIndex()) _, err = t.client.Set(key, value, ttlInSeconds) Expect(err).NotTo(HaveOccurred()) }
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 *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) 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 lrpForState(state string, timeInState time.Duration) models.ActualLRP { var actualLRPKey = models.NewActualLRPKey("some-process-guid", 1, "tests") var instanceKey = models.NewActualLRPInstanceKey("some-instance-guid", "some-cell") lrp := models.ActualLRP{ ActualLRPKey: actualLRPKey, State: state, Since: clock.Now().Add(-timeInState).UnixNano(), } switch state { case models.ActualLRPStateUnclaimed: case models.ActualLRPStateCrashed: lrp.CrashReason = "crashed" case models.ActualLRPStateClaimed: lrp.ActualLRPInstanceKey = instanceKey case models.ActualLRPStateRunning: lrp.ActualLRPInstanceKey = instanceKey lrp.ActualLRPNetInfo = models.NewActualLRPNetInfo("1.2.3.4", &models.PortMapping{ContainerPort: 1234, HostPort: 5678}) } return lrp }
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 }
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 itValidatesAbsenceOfNetInfo(lrp *models.ActualLRP) { Context("when net info is set", func() { BeforeEach(func() { lrp.ActualLRPNetInfo = models.NewActualLRPNetInfo("1.2.3.4") }) It("validate returns an error", func() { err := lrp.Validate() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("net info")) }) }) Context("when net info is not set", func() { BeforeEach(func() { lrp.ActualLRPNetInfo = models.ActualLRPNetInfo{} }) It("validate does not return an error", func() { Expect(lrp.Validate()).NotTo(HaveOccurred()) }) }) }
func itValidatesAbsenceOfTheInstanceKey(lrp *models.ActualLRP) { Context("when the instance key is set", func() { BeforeEach(func() { lrp.ActualLRPInstanceKey = models.NewActualLRPInstanceKey("some-instance", "some-cell") }) It("validate returns an error", func() { err := lrp.Validate() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("instance key")) }) }) Context("when the instance key is not set", func() { BeforeEach(func() { lrp.ActualLRPInstanceKey = models.ActualLRPInstanceKey{} }) It("validate does not return an error", func() { Expect(lrp.Validate()).NotTo(HaveOccurred()) }) }) }
func itValidatesPresenceOfTheLRPKey(lrp *models.ActualLRP) { Context("when the lrp key is set", func() { BeforeEach(func() { lrp.ActualLRPKey = models.NewActualLRPKey("some-guid", 1, "domain") }) It("validate does not return an error", func() { Expect(lrp.Validate()).NotTo(HaveOccurred()) }) }) Context("when the lrp key is not set", func() { BeforeEach(func() { lrp.ActualLRPKey = models.ActualLRPKey{} }) It("validate returns an error", func() { err := lrp.Validate() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("process_guid")) }) }) }
"code.cloudfoundry.org/bbs/db/dbfakes" "code.cloudfoundry.org/bbs/handlers" "code.cloudfoundry.org/bbs/models" "code.cloudfoundry.org/lager/lagertest" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "github.com/onsi/gomega/gbytes" ) var _ = Describe("ActualLRP Handlers", func() { var ( logger *lagertest.TestLogger fakeActualLRPDB *dbfakes.FakeActualLRPDB responseRecorder *httptest.ResponseRecorder handler *handlers.ActualLRPHandler exitCh chan struct{} actualLRP1 models.ActualLRP actualLRP2 models.ActualLRP evacuatingLRP2 models.ActualLRP ) BeforeEach(func() { fakeActualLRPDB = new(dbfakes.FakeActualLRPDB) logger = lagertest.NewTestLogger("test") responseRecorder = httptest.NewRecorder() exitCh = make(chan struct{}, 1) handler = handlers.NewActualLRPHandler(fakeActualLRPDB, exitCh) }) Describe("ActualLRPGroups", func() {
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 }
var response models.RemoveEvacuatingActualLRPResponse err := response.Unmarshal(responseRecorder.Body.Bytes()) Expect(err).NotTo(HaveOccurred()) Expect(response.Error).NotTo(BeNil()) Expect(response.Error).To(Equal(models.ErrResourceNotFound)) }) }) }) Describe("EvacuateClaimedActualLRP", func() { var ( request *http.Request requestBody *models.EvacuateClaimedActualLRPRequest 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
package main_test import ( "code.cloudfoundry.org/bbs/cmd/bbs/testrunner" "code.cloudfoundry.org/bbs/models" "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() {
netInfo := models.EmptyActualLRPNetInfo() Expect(netInfo.GetAddress()).To(BeEmpty()) Expect(netInfo.GetPorts()).To(BeEmpty()) }) }) }) }) Describe("ActualLRPGroup", func() { Describe("Resolve", func() { var ( instanceLRP *models.ActualLRP evacuatingLRP *models.ActualLRP group models.ActualLRPGroup resolvedLRP *models.ActualLRP evacuating bool ) BeforeEach(func() { lrpKey := models.NewActualLRPKey("process-guid", 1, "domain") instanceLRP = &models.ActualLRP{ ActualLRPKey: lrpKey, Since: 1138, } evacuatingLRP = &models.ActualLRP{ ActualLRPKey: lrpKey, Since: 3417, }
func (db *SQLDB) EvacuateActualLRP( logger lager.Logger, lrpKey *models.ActualLRPKey, instanceKey *models.ActualLRPInstanceKey, netInfo *models.ActualLRPNetInfo, ttl uint64, ) (*models.ActualLRPGroup, error) { logger = logger.Session("evacuate-lrp", lager.Data{"lrp_key": lrpKey, "instance_key": instanceKey, "net_info": netInfo}) logger.Debug("starting") defer logger.Debug("complete") var actualLRP *models.ActualLRP err := db.transact(logger, func(logger lager.Logger, tx *sql.Tx) error { var err error processGuid := lrpKey.ProcessGuid index := lrpKey.Index actualLRP, err = db.fetchActualLRPForUpdate(logger, processGuid, index, true, tx) if err == models.ErrResourceNotFound { logger.Debug("creating-evacuating-lrp") actualLRP, err = db.createEvacuatingActualLRP(logger, lrpKey, instanceKey, netInfo, ttl, tx) return err } if err != nil { logger.Error("failed-locking-lrp", err) return err } if actualLRP.ActualLRPKey.Equal(lrpKey) && actualLRP.ActualLRPInstanceKey.Equal(instanceKey) && reflect.DeepEqual(actualLRP.ActualLRPNetInfo, *netInfo) { logger.Debug("evacuating-lrp-already-exists") return nil } now := db.clock.Now().UnixNano() actualLRP.ModificationTag.Increment() actualLRP.ActualLRPKey = *lrpKey actualLRP.ActualLRPInstanceKey = *instanceKey actualLRP.Since = now actualLRP.ActualLRPNetInfo = *netInfo netInfoData, err := db.serializeModel(logger, netInfo) if err != nil { logger.Error("failed-serializing-net-info", err) return err } _, err = db.update(logger, tx, "actual_lrps", SQLAttributes{ "domain": actualLRP.Domain, "instance_guid": actualLRP.InstanceGuid, "cell_id": actualLRP.CellId, "net_info": netInfoData, "state": actualLRP.State, "since": actualLRP.Since, "modification_tag_index": actualLRP.ModificationTag.Index, }, "process_guid = ? AND instance_index = ? AND evacuating = ?", actualLRP.ProcessGuid, actualLRP.Index, true, ) if err != nil { logger.Error("failed-update-evacuating-lrp", err) return db.convertSQLError(err) } return nil }) return &models.ActualLRPGroup{Evacuating: actualLRP}, err }
package sqldb_test import ( "time" "code.cloudfoundry.org/bbs/models" "code.cloudfoundry.org/bbs/models/test/model_helpers" "code.cloudfoundry.org/bbs/test_helpers" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) var _ = Describe("Evacuation", func() { var ( actualLRP *models.ActualLRP guid string index int32 ) BeforeEach(func() { guid = "some-guid" index = int32(1) actualLRP = model_helpers.NewValidActualLRP(guid, index) actualLRP.CrashCount = 0 actualLRP.CrashReason = "" actualLRP.Since = fakeClock.Now().UnixNano() actualLRP.ModificationTag = models.ModificationTag{} actualLRP.ModificationTag.Increment() actualLRP.ModificationTag.Increment() _, err := sqlDB.CreateUnclaimedActualLRP(logger, &actualLRP.ActualLRPKey)
func (db *ETCDDB) gatherAndOptionallyPruneActualLRPs(logger lager.Logger, guids map[string]struct{}, doPrune bool, lmc *LRPMetricCounter) (map[string]map[int32]*models.ActualLRP, error) { response, modelErr := db.fetchRecursiveRaw(logger, ActualLRPSchemaRoot) if modelErr == models.ErrResourceNotFound { logger.Info("actual-lrp-schema-root-not-found") return map[string]map[int32]*models.ActualLRP{}, nil } if modelErr != nil { return nil, modelErr } actuals := map[string]map[int32]*models.ActualLRP{} var guidKeysToDelete, indexKeysToDelete []string var actualsToDelete []string var guidsLock, actualsLock, guidKeysToDeleteLock, indexKeysToDeleteLock, crashingDesiredsLock, actualsToDeleteLock sync.Mutex logger.Debug("walking-actual-lrp-tree") works := []func(){} crashingDesireds := map[string]struct{}{} for _, guidGroup := range response.Nodes { guidGroup := guidGroup works = append(works, func() { guidGroupWillBeEmpty := true for _, indexGroup := range guidGroup.Nodes { indexGroupWillBeEmpty := true for _, actualNode := range indexGroup.Nodes { actual := new(models.ActualLRP) err := db.deserializeModel(logger, actualNode, actual) if err != nil { actualsToDeleteLock.Lock() actualsToDelete = append(actualsToDelete, actualNode.Key) actualsToDeleteLock.Unlock() continue } err = actual.Validate() if err != nil { actualsToDeleteLock.Lock() actualsToDelete = append(actualsToDelete, actualNode.Key) actualsToDeleteLock.Unlock() continue } indexGroupWillBeEmpty = false guidGroupWillBeEmpty = false switch actual.State { case models.ActualLRPStateUnclaimed: atomic.AddInt32(&lmc.unclaimedLRPs, 1) case models.ActualLRPStateClaimed: atomic.AddInt32(&lmc.claimedLRPs, 1) case models.ActualLRPStateRunning: atomic.AddInt32(&lmc.runningLRPs, 1) case models.ActualLRPStateCrashed: crashingDesiredsLock.Lock() crashingDesireds[actual.ProcessGuid] = struct{}{} crashingDesiredsLock.Unlock() atomic.AddInt32(&lmc.crashedActualLRPs, 1) } guidsLock.Lock() guids[actual.ProcessGuid] = struct{}{} guidsLock.Unlock() if path.Base(actualNode.Key) == ActualLRPInstanceKey { actualsLock.Lock() if actuals[actual.ProcessGuid] == nil { actuals[actual.ProcessGuid] = map[int32]*models.ActualLRP{} } actuals[actual.ProcessGuid][actual.Index] = actual actualsLock.Unlock() } } if indexGroupWillBeEmpty { indexKeysToDeleteLock.Lock() indexKeysToDelete = append(indexKeysToDelete, indexGroup.Key) indexKeysToDeleteLock.Unlock() } } if guidGroupWillBeEmpty { guidKeysToDeleteLock.Lock() guidKeysToDelete = append(guidKeysToDelete, guidGroup.Key) guidKeysToDeleteLock.Unlock() } }) } logger.Debug("done-walking-actual-lrp-tree") throttler, err := workpool.NewThrottler(db.convergenceWorkersSize, works) if err != nil { logger.Error("failed-to-create-throttler", err) } throttler.Work() if doPrune { logger.Info("deleting-invalid-actual-lrps", lager.Data{"num_lrps": len(actualsToDelete)}) db.batchDeleteNodes(actualsToDelete, logger) actualLRPsDeleted.Add(uint64(len(actualsToDelete))) logger.Info("deleting-empty-actual-indices", lager.Data{"num_indices": len(indexKeysToDelete)}) err = db.deleteLeaves(logger, indexKeysToDelete) if err != nil { logger.Error("failed-deleting-empty-actual-indices", err, lager.Data{"num_indices": len(indexKeysToDelete)}) } else { logger.Info("succeeded-deleting-empty-actual-indices", lager.Data{"num_indices": len(indexKeysToDelete)}) } logger.Info("deleting-empty-actual-guids", lager.Data{"num_guids": len(guidKeysToDelete)}) err = db.deleteLeaves(logger, guidKeysToDelete) if err != nil { logger.Error("failed-deleting-empty-actual-guids", err, lager.Data{"num_guids": len(guidKeysToDelete)}) } else { logger.Info("succeeded-deleting-empty-actual-guids", lager.Data{"num_guids": len(guidKeysToDelete)}) } } lmc.crashingDesiredLRPs = int32(len(crashingDesireds)) return actuals, nil }
"code.cloudfoundry.org/rep/repfakes" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "github.com/onsi/gomega/gbytes" ) var _ = Describe("ActualLRP Lifecycle Handlers", func() { var ( logger *lagertest.TestLogger fakeActualLRPDB *dbfakes.FakeActualLRPDB fakeDesiredLRPDB *dbfakes.FakeDesiredLRPDB fakeAuctioneerClient *auctioneerfakes.FakeClient actualHub *eventfakes.FakeHub responseRecorder *httptest.ResponseRecorder handler *handlers.ActualLRPLifecycleHandler exitCh chan struct{} actualLRP models.ActualLRP afterActualLRP models.ActualLRP fakeServiceClient *fake_bbs.FakeServiceClient fakeRepClientFactory *repfakes.FakeClientFactory fakeRepClient *repfakes.FakeClient ) BeforeEach(func() { fakeActualLRPDB = new(dbfakes.FakeActualLRPDB) fakeAuctioneerClient = new(auctioneerfakes.FakeClient) fakeDesiredLRPDB = new(dbfakes.FakeDesiredLRPDB) logger = lagertest.NewTestLogger("test") responseRecorder = httptest.NewRecorder()
Context("when we fail to create the node", func() { BeforeEach(func() { fakeStoreClient.GetReturns(nil, etcderrors.EtcdError{ErrorCode: ETCDErrKeyNotFound}) fakeStoreClient.CreateReturns(nil, errors.New("oh no!")) }) It("errors", func() { _, _, err := etcdDBWithFakeStore.UnclaimActualLRP(logger, lrpKey) Expect(err).To(HaveOccurred()) }) }) }) Context("when the actual LRP exists", func() { var actualLRP *models.ActualLRP BeforeEach(func() { actualLRP = model_helpers.NewValidActualLRP(lrpKey.ProcessGuid, lrpKey.Index) etcdHelper.SetRawActualLRP(actualLRP) }) It("transitions the actual lrp into the unclaimed state", func() { _, _, err := etcdDB.UnclaimActualLRP(logger, lrpKey) Expect(err).NotTo(HaveOccurred()) group, err := etcdDB.ActualLRPGroupByProcessGuidAndIndex(logger, guid, index) Expect(err).NotTo(HaveOccurred()) actualLRP, evacuating := group.Resolve() Expect(evacuating).To(BeFalse())
"github.com/onsi/gomega/gbytes" ) var _ = Describe("LRP Convergence Controllers", func() { var ( err error logger *lagertest.TestLogger fakeLRPDB *dbfakes.FakeLRPDB actualHub *eventfakes.FakeHub fakeAuctioneerClient *auctioneerfakes.FakeClient keysToAuction []*auctioneer.LRPStartRequest keysToRetire []*models.ActualLRPKey keysWithMissingCells []*models.ActualLRPKeyWithSchedulingInfo retiringActualLRP1 *models.ActualLRP retiringActualLRP2 *models.ActualLRP desiredLRP1, desiredLRP2 models.DesiredLRPSchedulingInfo unclaimingActualLRP1 *models.ActualLRP unclaimingActualLRP2 *models.ActualLRP cellID string cellSet models.CellSet controller *controllers.LRPConvergenceController ) BeforeEach(func() { fakeLRPDB = new(dbfakes.FakeLRPDB) fakeAuctioneerClient = new(auctioneerfakes.FakeClient)
import ( "errors" "code.cloudfoundry.org/bbs/db/etcd" "code.cloudfoundry.org/bbs/models" "code.cloudfoundry.org/bbs/models/test/model_helpers" etcderrors "github.com/coreos/go-etcd/etcd" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) var _ = Describe("Evacuation", func() { Describe("EvacuateActualLRP", func() { var ( actualLRP *models.ActualLRP index int32 guid string ttl uint64 ) BeforeEach(func() { guid = "the-guid" index = 1 ttl = 60 actualLRP = model_helpers.NewValidActualLRP(guid, index) etcdHelper.SetRawEvacuatingActualLRP(actualLRP, ttl) node, err := storeClient.Get(etcd.EvacuatingActualLRPSchemaPath(guid, index), false, false) fakeStoreClient.GetReturns(node, err) })