func (db *ETCDDB) UpdateDesiredLRP(logger lager.Logger, processGuid string, update *models.DesiredLRPUpdate) (*models.DesiredLRP, error) { logger.Info("starting") defer logger.Info("complete") var schedulingInfo *models.DesiredLRPSchedulingInfo var err error var beforeDesiredLRP *models.DesiredLRP for i := 0; i < 2; i++ { var index uint64 beforeDesiredLRP, index, err = db.rawDesiredLRPByProcessGuid(logger, processGuid) if err != nil { logger.Error("failed-to-fetch-desired-lrp", err) break } schedulingInfoValue := beforeDesiredLRP.DesiredLRPSchedulingInfo() schedulingInfo = &schedulingInfoValue schedulingInfo.ApplyUpdate(update) err = db.updateDesiredLRPSchedulingInfo(logger, schedulingInfo, index) if err != nil { logger.Error("update-scheduling-info-failed", err) modelErr := models.ConvertError(err) if modelErr != models.ErrResourceConflict { break } // Retry on CAS fail continue } break } if err != nil { return nil, err } return beforeDesiredLRP, nil }
func (h *DesiredLRPHandler) DesiredLRPByProcessGuid_r1(logger lager.Logger, w http.ResponseWriter, req *http.Request) { var err error logger = logger.Session("desired-lrp-by-process-guid", lager.Data{"revision": 1}) request := &models.DesiredLRPByProcessGuidRequest{} response := &models.DesiredLRPResponse{} err = parseRequest(logger, req, request) if err == nil { var lrp *models.DesiredLRP lrp, err = h.desiredLRPDB.DesiredLRPByProcessGuid(logger, request.ProcessGuid) if err == nil { transformedLRP := lrp.VersionDownTo(format.V1) response.DesiredLrp = transformedLRP } } response.Error = models.ConvertError(err) writeResponse(w, response) exitIfUnrecoverable(logger, h.exitChan, response.Error) }
func (m *SplitDesiredLRP) WriteRunInfo(logger lager.Logger, desiredLRP models.DesiredLRP) { environmentVariables := make([]models.EnvironmentVariable, len(desiredLRP.EnvironmentVariables)) for i := range desiredLRP.EnvironmentVariables { environmentVariables[i] = *desiredLRP.EnvironmentVariables[i] } egressRules := make([]models.SecurityGroupRule, len(desiredLRP.EgressRules)) for i := range desiredLRP.EgressRules { egressRules[i] = *desiredLRP.EgressRules[i] } runInfo := models.DesiredLRPRunInfo{ DesiredLRPKey: desiredLRP.DesiredLRPKey(), EnvironmentVariables: environmentVariables, Setup: desiredLRP.Setup, Action: desiredLRP.Action, Monitor: desiredLRP.Monitor, StartTimeoutMs: desiredLRP.StartTimeoutMs, Privileged: desiredLRP.Privileged, CpuWeight: desiredLRP.CpuWeight, Ports: desiredLRP.Ports, EgressRules: egressRules, LogSource: desiredLRP.LogSource, MetricsGuid: desiredLRP.MetricsGuid, } runInfoPayload, marshalErr := m.serializer.Marshal(logger, format.ENCRYPTED_PROTO, &runInfo) if marshalErr != nil { logger.Error("failed-marshaling-run-info", marshalErr, lager.Data{"process_guid": runInfo.ProcessGuid}) } _, setErr := m.storeClient.Set(etcd.DesiredLRPRunInfoSchemaPath(runInfo.ProcessGuid), runInfoPayload, etcd.NO_TTL) if setErr != nil { logger.Error("failed-set-of-run-info", marshalErr, lager.Data{"process_guid": runInfo.ProcessGuid}) } }
func (m *SplitDesiredLRP) WriteSchedulingInfo(logger lager.Logger, desiredLRP models.DesiredLRP) { schedulingInfo := models.DesiredLRPSchedulingInfo{ DesiredLRPKey: desiredLRP.DesiredLRPKey(), Annotation: desiredLRP.Annotation, Instances: desiredLRP.Instances, DesiredLRPResource: desiredLRP.DesiredLRPResource(), } if desiredLRP.Routes != nil { schedulingInfo.Routes = *desiredLRP.Routes } if desiredLRP.ModificationTag != nil { schedulingInfo.ModificationTag = *desiredLRP.ModificationTag } schedulingInfoPayload, marshalErr := m.serializer.Marshal(logger, format.ENCRYPTED_PROTO, &schedulingInfo) if marshalErr != nil { logger.Error("failed-marshaling-scheduling-info", marshalErr, lager.Data{"process_guid": schedulingInfo.ProcessGuid}) } _, setErr := m.storeClient.Set(etcd.DesiredLRPSchedulingInfoSchemaPath(desiredLRP.ProcessGuid), schedulingInfoPayload, etcd.NO_TTL) if setErr != nil { logger.Error("failed-set-of-scheduling-info", marshalErr, lager.Data{"process_guid": schedulingInfo.ProcessGuid}) } }
// DesireLRP creates a DesiredLRPSchedulingInfo and a DesiredLRPRunInfo. In order // to ensure that the complete model is available and there are no races in // Desired Watches, DesiredLRPRunInfo is created before DesiredLRPSchedulingInfo. func (db *ETCDDB) DesireLRP(logger lager.Logger, desiredLRP *models.DesiredLRP) error { logger = logger.WithData(lager.Data{"process_guid": desiredLRP.ProcessGuid}) logger.Info("starting") defer logger.Info("complete") schedulingInfo, runInfo := desiredLRP.CreateComponents(db.clock.Now()) err := db.createDesiredLRPRunInfo(logger, &runInfo) if err != nil { return err } schedulingErr := db.createDesiredLRPSchedulingInfo(logger, &schedulingInfo) if schedulingErr != nil { logger.Info("deleting-orphaned-run-info") _, err = db.client.Delete(DesiredLRPRunInfoSchemaPath(desiredLRP.ProcessGuid), true) if err != nil { logger.Error("failed-deleting-orphaned-run-info", err) } return schedulingErr } return nil }
func (db *SQLDB) DesireLRP(logger lager.Logger, desiredLRP *models.DesiredLRP) error { logger = logger.WithData(lager.Data{"process_guid": desiredLRP.ProcessGuid}) logger.Info("starting") defer logger.Info("complete") return db.transact(logger, func(logger lager.Logger, tx *sql.Tx) error { routesData, err := db.encodeRouteData(logger, desiredLRP.Routes) if err != nil { logger.Error("failed-encoding-route-data", err) return err } runInfo := desiredLRP.DesiredLRPRunInfo(db.clock.Now()) runInfoData, err := db.serializeModel(logger, &runInfo) if err != nil { logger.Error("failed-to-serialize-model", err) return err } volumePlacement := &models.VolumePlacement{} volumePlacement.DriverNames = []string{} for _, mount := range desiredLRP.VolumeMounts { volumePlacement.DriverNames = append(volumePlacement.DriverNames, mount.Driver) } volumePlacementData, err := db.serializeModel(logger, volumePlacement) if err != nil { logger.Error("failed-to-serialize-model", err) return err } guid, err := db.guidProvider.NextGUID() if err != nil { logger.Error("failed-to-generate-guid", err) return models.ErrGUIDGeneration } placementTagData, err := json.Marshal(desiredLRP.PlacementTags) if err != nil { logger.Error("failed-to-serialize-model", err) return err } desiredLRP.ModificationTag = &models.ModificationTag{Epoch: guid, Index: 0} _, err = db.insert(logger, tx, desiredLRPsTable, SQLAttributes{ "process_guid": desiredLRP.ProcessGuid, "domain": desiredLRP.Domain, "log_guid": desiredLRP.LogGuid, "annotation": desiredLRP.Annotation, "instances": desiredLRP.Instances, "memory_mb": desiredLRP.MemoryMb, "disk_mb": desiredLRP.DiskMb, "rootfs": desiredLRP.RootFs, "volume_placement": volumePlacementData, "modification_tag_epoch": desiredLRP.ModificationTag.Epoch, "modification_tag_index": desiredLRP.ModificationTag.Index, "routes": routesData, "run_info": runInfoData, "placement_tags": placementTagData, }, ) if err != nil { logger.Error("failed-inserting-desired", err) return db.convertSQLError(err) } return nil }) }
It("provides relevant error information", func() { Expect(responseRecorder.Code).To(Equal(http.StatusOK)) response := models.DesiredLRPSchedulingInfosResponse{} err := response.Unmarshal(responseRecorder.Body.Bytes()) Expect(err).NotTo(HaveOccurred()) Expect(response.Error).To(Equal(models.ErrUnknownError)) }) }) }) Describe("DesireDesiredLRP", func() { var ( desiredLRP *models.DesiredLRP requestBody interface{} ) BeforeEach(func() { desiredLRP = model_helpers.NewValidDesiredLRP("some-guid") desiredLRP.Instances = 5 requestBody = &models.DesireLRPRequest{ DesiredLrp: desiredLRP, } }) JustBeforeEach(func() { request := newTestRequest(requestBody) handler.DesireDesiredLRP(logger, responseRecorder, request) })
etcdRunner.Stop() }) AfterEach(func() { etcdRunner.Start() }) It("errors", func() { _, err := etcdDB.DesiredLRPSchedulingInfos(logger, filter) Expect(err).To(HaveOccurred()) }) }) }) Describe("DesireLRP", func() { var lrp *models.DesiredLRP BeforeEach(func() { lrp = model_helpers.NewValidDesiredLRP("some-process-guid") lrp.Instances = 5 }) Context("when the desired LRP does not yet exist", func() { It("persists the scheduling info and run info", func() { err := etcdDB.DesireLRP(logger, lrp) Expect(err).NotTo(HaveOccurred()) persisted, err := etcdDB.DesiredLRPByProcessGuid(logger, "some-process-guid") Expect(err).NotTo(HaveOccurred()) Expect(persisted.DesiredLRPKey()).To(Equal(lrp.DesiredLRPKey()))
Context("when there are no actions", func() { BeforeEach(func() { task.Action = nil }) It("does nothing", func() { Expect(migrationErr).NotTo(HaveOccurred()) _, err := db.TaskByGuid(logger, task.TaskGuid) Expect(err).NotTo(HaveOccurred()) }) }) }) Describe("DesiredLRP Migration", func() { var ( processGuid string desiredLRP *models.DesiredLRP ) BeforeEach(func() { processGuid = "process-guid-1" desiredLRP = model_helpers.NewValidDesiredLRP(processGuid) desiredLRP.DeprecatedStartTimeoutS = 15 desiredLRP.Action = models.WrapAction(&models.TimeoutAction{Action: models.WrapAction(&models.RunAction{Path: "ls", User: "******"}), DeprecatedTimeoutNs: 4 * int64(time.Second), }) desiredLRP.Setup = models.WrapAction(&models.TimeoutAction{Action: models.WrapAction(&models.RunAction{Path: "ls", User: "******"}), DeprecatedTimeoutNs: 7 * int64(time.Second), }) desiredLRP.Monitor = models.WrapAction(models.EmitProgressFor( &models.TimeoutAction{
"domain-0", ), State: models.ActualLRPStateUnclaimed, Since: 1138, CrashCount: 1, CrashReason: errorMessage, } }) JustBeforeEach(func() { request := newTestRequest(requestBody) handler.CrashActualLRP(logger, responseRecorder, request) }) Context("when crashing the actual lrp in the DB succeeds", func() { var desiredLRP *models.DesiredLRP BeforeEach(func() { desiredLRP = &models.DesiredLRP{ ProcessGuid: "process-guid", Domain: "some-domain", RootFs: "some-stack", MemoryMb: 128, DiskMb: 512, } fakeDesiredLRPDB.DesiredLRPByProcessGuidReturns(desiredLRP, nil) fakeActualLRPDB.CrashActualLRPReturns(&models.ActualLRPGroup{Instance: &actualLRP}, &models.ActualLRPGroup{Instance: &afterActualLRP}, true, nil) }) It("response with no error", func() {
"code.cloudfoundry.org/lager" "code.cloudfoundry.org/lager/lagertest" "code.cloudfoundry.org/rep" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "github.com/onsi/gomega/gbytes" ) var _ = Describe("DesiredLRP Handlers", func() { var ( logger *lagertest.TestLogger fakeDesiredLRPDB *dbfakes.FakeDesiredLRPDB fakeActualLRPDB *dbfakes.FakeActualLRPDB fakeAuctioneerClient *auctioneerfakes.FakeClient desiredHub *eventfakes.FakeHub actualHub *eventfakes.FakeHub responseRecorder *httptest.ResponseRecorder handler *handlers.DesiredLRPHandler exitCh chan struct{} desiredLRP1 models.DesiredLRP desiredLRP2 models.DesiredLRP ) BeforeEach(func() { fakeDesiredLRPDB = new(dbfakes.FakeDesiredLRPDB) fakeActualLRPDB = new(dbfakes.FakeActualLRPDB) fakeAuctioneerClient = new(auctioneerfakes.FakeClient) logger = lagertest.NewTestLogger("test") responseRecorder = httptest.NewRecorder() desiredHub = new(eventfakes.FakeHub) actualHub = new(eventfakes.FakeHub)
func (t *ETCDHelper) SetRawDesiredLRP(lrp *models.DesiredLRP) { schedulingInfo, runInfo := lrp.CreateComponents(t.clock.Now()) t.SetRawDesiredLRPSchedulingInfo(&schedulingInfo) t.SetRawDesiredLRPRunInfo(&runInfo) }
Expect(err).NotTo(HaveOccurred()) rowsAffected, err := result.RowsAffected() Expect(err).NotTo(HaveOccurred()) Expect(rowsAffected).To(BeEquivalentTo(1)) }) It("excludes the invalid desired LRP from the response", func() { desiredLRPSchedulingInfos, err := sqlDB.DesiredLRPSchedulingInfos(logger, models.DesiredLRPFilter{}) Expect(err).NotTo(HaveOccurred()) Expect(desiredLRPSchedulingInfos).To(HaveLen(1)) }) }) }) Describe("UpdateDesiredLRP", func() { var expectedDesiredLRP *models.DesiredLRP var update *models.DesiredLRPUpdate BeforeEach(func() { desiredLRPGuid := "desired-lrp-guid" expectedDesiredLRP = model_helpers.NewValidDesiredLRP(desiredLRPGuid) Expect(sqlDB.DesireLRP(logger, expectedDesiredLRP)).To(Succeed()) instances := int32(1) update = &models.DesiredLRPUpdate{ Instances: &instances, } }) It("updates the lrp", func() { instances := int32(123) routeContent := []byte("{}")
}) }) Describe("Desired LRPs", func() { var ( existingDesiredLRPs []migrations.ETCDToSQLDesiredLRP desiredLRPsToCreate int ) BeforeEach(func() { encoder := format.NewEncoder(cryptor) desiredLRPsToCreate = 3 for i := 0; i < desiredLRPsToCreate; i++ { processGuid := fmt.Sprintf("process-guid-%d", i) var desiredLRP *models.DesiredLRP desiredLRP = model_helpers.NewValidDesiredLRP(processGuid) schedulingInfo, runInfo := desiredLRP.CreateComponents(fakeClock.Now()) var ( encryptedVolumePlacement []byte err error ) if i == 0 { // test for nil and full VolumePlacements schedulingInfo.VolumePlacement = nil encryptedVolumePlacement, err = serializer.Marshal(logger, format.ENCRYPTED_PROTO, &models.VolumePlacement{}) } else { encryptedVolumePlacement, err = serializer.Marshal(logger, format.ENCRYPTED_PROTO, schedulingInfo.VolumePlacement) } Expect(err).NotTo(HaveOccurred())
It("has the correct number of responses", func() { Expect(actualDesiredLRPs).To(HaveLen(2)) }) It("returns only the desired lrps in the requested domain", func() { for _, lrp := range desiredLRPs[domain] { expectedDesiredLRPs = append(expectedDesiredLRPs, lrp) } Expect(actualDesiredLRPs).To(ConsistOf(expectedDesiredLRPs)) }) }) }) Describe("DesiredLRPByProcessGuid", func() { var ( desiredLRP *models.DesiredLRP expectedDesiredLRP *models.DesiredLRP ) JustBeforeEach(func() { expectedDesiredLRP = desiredLRPs["domain-1"][0] desiredLRP, getErr = client.DesiredLRPByProcessGuid(logger, expectedDesiredLRP.GetProcessGuid()) desiredLRP.ModificationTag.Epoch = "epoch" }) It("responds without error", func() { Expect(getErr).NotTo(HaveOccurred()) }) It("returns all desired lrps from the bbs", func() { Expect(desiredLRP).To(Equal(expectedDesiredLRP)) })
"encoding/json" "fmt" "time" "code.cloudfoundry.org/bbs/format" "code.cloudfoundry.org/bbs/models" "code.cloudfoundry.org/bbs/models/test/model_helpers" "github.com/gogo/protobuf/proto" . "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo/extensions/table" . "github.com/onsi/gomega" ) var _ = Describe("DesiredLRP", func() { var desiredLRP models.DesiredLRP jsonDesiredLRP := `{ "setup": { "serial": { "actions": [ { "download": { "from": "http://file-server.service.cf.internal:8080/v1/static/buildpack_app_lifecycle/buildpack_app_lifecycle.tgz", "to": "/tmp/lifecycle", "cache_key": "buildpack-cflinuxfs2-lifecycle", "user": "******", "checksum_algorithm": "md5", "checksum_value": "some random value" } },