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 }
func (db *ETCDDB) EvacuateActualLRP( logger lager.Logger, lrpKey *models.ActualLRPKey, instanceKey *models.ActualLRPInstanceKey, netInfo *models.ActualLRPNetInfo, ttl uint64, ) (*models.ActualLRPGroup, error) { logger = logger.Session("evacuate-actual-lrp", lager.Data{"process_guid": lrpKey.ProcessGuid, "index": lrpKey.Index}) logger.Debug("starting") defer logger.Debug("complete") node, err := db.fetchRaw(logger, EvacuatingActualLRPSchemaPath(lrpKey.ProcessGuid, lrpKey.Index)) bbsErr := models.ConvertError(err) if bbsErr != nil { if bbsErr.Type == models.Error_ResourceNotFound { return db.createEvacuatingActualLRP(logger, lrpKey, instanceKey, netInfo, ttl) } return nil, bbsErr } lrp := models.ActualLRP{} err = db.deserializeModel(logger, node, &lrp) if err != nil { return nil, err } if lrp.ActualLRPKey.Equal(lrpKey) && lrp.ActualLRPInstanceKey.Equal(instanceKey) && reflect.DeepEqual(lrp.ActualLRPNetInfo, *netInfo) { return &models.ActualLRPGroup{Evacuating: &lrp}, nil } lrp.ActualLRPNetInfo = *netInfo lrp.ActualLRPKey = *lrpKey lrp.ActualLRPInstanceKey = *instanceKey lrp.Since = db.clock.Now().UnixNano() lrp.ModificationTag.Increment() data, err := db.serializeModel(logger, &lrp) if err != nil { logger.Error("failed-serializing", err) return nil, err } _, err = db.client.CompareAndSwap(EvacuatingActualLRPSchemaPath(lrp.ProcessGuid, lrp.Index), data, ttl, node.ModifiedIndex) if err != nil { return nil, ErrorFromEtcdError(logger, err) } return &models.ActualLRPGroup{Evacuating: &lrp}, nil }
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 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()) }) }) }
State: models.ActualLRPStateUnclaimed, Since: 1138, } }) JustBeforeEach(func() { request := newTestRequest(requestBody) handler.RemoveActualLRP(responseRecorder, request) }) Context("when removing the actual lrp in the DB succeeds", func() { var removedActualLRP models.ActualLRP BeforeEach(func() { removedActualLRP = actualLRP removedActualLRP.ActualLRPInstanceKey = instanceKey fakeActualLRPDB.RemoveActualLRPReturns(nil) }) It("removes the actual lrp by process guid and index", func() { Expect(responseRecorder.Code).To(Equal(http.StatusOK)) Expect(fakeActualLRPDB.RemoveActualLRPCallCount()).To(Equal(1)) _, actualProcessGuid, idx := fakeActualLRPDB.RemoveActualLRPArgsForCall(0) Expect(actualProcessGuid).To(Equal(processGuid)) Expect(idx).To(BeEquivalentTo(index)) }) It("response with no error", func() { Expect(responseRecorder.Code).To(Equal(http.StatusOK)) response := &models.ActualLRPLifecycleResponse{} err := response.Unmarshal(responseRecorder.Body.Bytes())
{models.ActualLRPStateClaimed, models.ActualLRPStateRunning, claimedKey, differentInstanceGuidKey, true}, {models.ActualLRPStateClaimed, models.ActualLRPStateRunning, claimedKey, differentCellIDKey, true}, {models.ActualLRPStateRunning, models.ActualLRPStateUnclaimed, claimedKey, emptyKey, true}, {models.ActualLRPStateRunning, models.ActualLRPStateClaimed, claimedKey, equivalentClaimedKey, true}, {models.ActualLRPStateRunning, models.ActualLRPStateClaimed, claimedKey, differentInstanceGuidKey, false}, {models.ActualLRPStateRunning, models.ActualLRPStateClaimed, claimedKey, differentCellIDKey, false}, {models.ActualLRPStateRunning, models.ActualLRPStateRunning, claimedKey, equivalentClaimedKey, true}, {models.ActualLRPStateRunning, models.ActualLRPStateClaimed, claimedKey, differentInstanceGuidKey, false}, {models.ActualLRPStateRunning, models.ActualLRPStateClaimed, claimedKey, differentCellIDKey, false}, } for _, entry := range stateTable { entry := entry It(EntryToString(entry), func() { before.State = entry.BeforeState before.ActualLRPInstanceKey = entry.BeforeInstanceKey Expect(before.AllowsTransitionTo(before.ActualLRPKey, entry.AfterInstanceKey, entry.AfterState)).To(Equal(entry.Allowed)) }) } }) }) Describe("Validate", func() { Context("when state is unclaimed", func() { BeforeEach(func() { lrp = models.ActualLRP{ ActualLRPKey: lrpKey, State: models.ActualLRPStateUnclaimed, Since: 1138, } })
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-sqldb", 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 }
Expect(err).NotTo(HaveOccurred()) Expect(lrpGroupInBBS.Instance.InstanceGuid).To(Equal(instanceGuid)) }) }) }) Context("when the existing ActualLRP is Running", func() { var instanceGuid string BeforeEach(func() { instanceGuid = "some-instance-guid" instanceKey = models.NewActualLRPInstanceKey(instanceGuid, cellID) actualLRP.State = models.ActualLRPStateRunning actualLRP.ActualLRPInstanceKey = instanceKey actualLRP.ActualLRPNetInfo = models.ActualLRPNetInfo{Address: "1"} Expect(actualLRP.Validate()).NotTo(HaveOccurred()) etcdHelper.SetRawActualLRP(actualLRP) }) Context("with the same cell and instance guid", func() { BeforeEach(func() { instanceKey = models.NewActualLRPInstanceKey(instanceGuid, cellID) }) It("does not return an error", func() { Expect(claimErr).NotTo(HaveOccurred()) })