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 }
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}, },
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", ), State: oldmodels.ActualLRPStateRunning,
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 }
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) }) Context("when the something about the actual LRP has changed", func() { BeforeEach(func() { clock.IncrementBySeconds(5) actualLRP.Since = clock.Now().UnixNano() }) Context("when the lrp key changes", func() { BeforeEach(func() { actualLRP.Domain = "some-other-domain" }) It("persists the evacuating lrp in etcd", func() { group, err := etcdDB.EvacuateActualLRP(logger, &actualLRP.ActualLRPKey, &actualLRP.ActualLRPInstanceKey, &actualLRP.ActualLRPNetInfo, ttl) Expect(err).NotTo(HaveOccurred()) actualLRP.ModificationTag.Increment() actualLRPGroup, err := etcdDB.ActualLRPGroupByProcessGuidAndIndex(logger, guid, index) Expect(err).NotTo(HaveOccurred()) Expect(actualLRPGroup.Evacuating).To(BeEquivalentTo(actualLRP))
CellId: "my-cell-id", InstanceGuid: "my-instance-guid", } actualLRP, startErr = client.StartActualLRP(&unclaimedLRPKey, &instanceKey, &netInfo) }) It("starts the actual_lrp", func() { Expect(startErr).NotTo(HaveOccurred()) expectedActualLRP := *unclaimedLRP expectedActualLRP.State = models.ActualLRPStateRunning expectedActualLRP.ActualLRPInstanceKey = instanceKey expectedActualLRP.ActualLRPNetInfo = netInfo expectedActualLRP.ModificationTag.Increment() expectedActualLRP.Since = 0 actualLRP.Since = 0 Expect(*actualLRP).To(Equal(expectedActualLRP)) fetchedActualLRPGroup, err := client.ActualLRPGroupByProcessGuidAndIndex(unclaimedProcessGuid, unclaimedIndex) Expect(err).NotTo(HaveOccurred()) fetchedActualLRP, evacuating := fetchedActualLRPGroup.Resolve() Expect(evacuating).To(BeFalse()) fetchedActualLRP.Since = 0 Expect(*fetchedActualLRP).To(Equal(expectedActualLRP)) }) }) Describe("POST /v1/actual_lrps/fail", func() { var (