func (dr *dropletRunner) BuildDroplet(taskName, dropletName, buildpackUrl string, environment map[string]string, memoryMB, cpuWeight, diskMB int) error { builderConfig := buildpack_app_lifecycle.NewLifecycleBuilderConfig([]string{buildpackUrl}, true, false) action := models.WrapAction(&models.SerialAction{ Actions: []*models.Action{ models.WrapAction(&models.DownloadAction{ From: "http://file-server.service.cf.internal:8080/v1/static/cell-helpers/cell-helpers.tgz", To: "/tmp", User: "******", }), models.WrapAction(&models.DownloadAction{ From: "http://file-server.service.cf.internal:8080/v1/static/buildpack_app_lifecycle/buildpack_app_lifecycle.tgz", To: "/tmp", User: "******", }), dr.blobStore.DownloadAppBitsAction(dropletName), dr.blobStore.DeleteAppBitsAction(dropletName), models.WrapAction(&models.RunAction{ Path: "/bin/chmod", Dir: "/tmp/app", Args: []string{"-R", "a+X", "."}, User: "******", }), models.WrapAction(&models.RunAction{ Path: "/tmp/builder", Dir: "/", Args: builderConfig.Args(), User: "******", }), dr.blobStore.UploadDropletAction(dropletName), dr.blobStore.UploadDropletMetadataAction(dropletName), }, }) environment["CF_STACK"] = DropletStack environment["MEMORY_LIMIT"] = fmt.Sprintf("%dM", memoryMB) proxyConf, err := dr.proxyConfReader.ProxyConf() if err != nil { return err } environment["http_proxy"] = proxyConf.HTTPProxy environment["https_proxy"] = proxyConf.HTTPSProxy environment["no_proxy"] = proxyConf.NoProxy createTaskParams := task_runner.NewCreateTaskParams( action, taskName, DropletRootFS, "lattice", "BUILD", environment, []*models.SecurityGroupRule{}, memoryMB, cpuWeight, diskMB, ) return dr.taskRunner.CreateTask(createTaskParams) }
func (b *BlobStore) DownloadAppBitsAction(dropletName string) *models.Action { return models.WrapAction(&models.SerialAction{ Actions: []*models.Action{ models.WrapAction(&models.RunAction{ Path: "/tmp/s3tool", Dir: "/", Args: []string{ "get", b.blobTarget.AccessKey, b.blobTarget.SecretKey, b.Bucket, b.blobTarget.Region, "/" + dropletName + "/bits.zip", "/tmp/bits.zip", }, User: "******", }), models.WrapAction(&models.RunAction{ Path: "/bin/mkdir", Args: []string{"/tmp/app"}, User: "******", }), models.WrapAction(&models.RunAction{ Path: "/usr/bin/unzip", Dir: "/tmp/app", Args: []string{"-q", "/tmp/bits.zip"}, User: "******", }), }, }) }
func NewValidDesiredLRP(guid string) *models.DesiredLRP { myRouterJSON := json.RawMessage(`{"foo":"bar"}`) modTag := models.NewModificationTag("epoch", 0) desiredLRP := &models.DesiredLRP{ ProcessGuid: guid, Domain: "some-domain", RootFs: "some:rootfs", Instances: 1, EnvironmentVariables: []*models.EnvironmentVariable{{Name: "FOO", Value: "bar"}}, CachedDependencies: []*models.CachedDependency{ {Name: "app bits", From: "blobstore.com/bits/app-bits", To: "/usr/local/app", CacheKey: "cache-key", LogSource: "log-source"}, {Name: "app bits with checksum", From: "blobstore.com/bits/app-bits-checksum", To: "/usr/local/app-checksum", CacheKey: "cache-key", LogSource: "log-source", ChecksumAlgorithm: "md5", ChecksumValue: "checksum-value"}, }, Setup: models.WrapAction(&models.RunAction{Path: "ls", User: "******"}), Action: models.WrapAction(&models.RunAction{Path: "ls", User: "******"}), StartTimeoutMs: 15000, Monitor: models.WrapAction(models.EmitProgressFor( models.Timeout(models.Try(models.Parallel(models.Serial(&models.RunAction{Path: "ls", User: "******"}))), 10*time.Second, ), "start-message", "success-message", "failure-message", )), DiskMb: 512, MemoryMb: 1024, CpuWeight: 42, Routes: &models.Routes{"my-router": &myRouterJSON}, LogSource: "some-log-source", LogGuid: "some-log-guid", MetricsGuid: "some-metrics-guid", Annotation: "some-annotation", Network: &models.Network{ Properties: map[string]string{ "some-key": "some-value", "some-other-key": "some-other-value", }, }, EgressRules: []*models.SecurityGroupRule{{ Protocol: models.TCPProtocol, Destinations: []string{"1.1.1.1/32", "2.2.2.2/32"}, PortRange: &models.PortRange{Start: 10, End: 16000}, }}, ModificationTag: &modTag, LegacyDownloadUser: "******", TrustedSystemCertificatesPath: "/etc/somepath", VolumeMounts: []*models.VolumeMount{ { Driver: "my-driver", VolumeId: "my-volume", ContainerPath: "/mnt/mypath", Mode: models.BindMountMode_RO, }, }, } err := desiredLRP.Validate() Expect(err).NotTo(HaveOccurred()) return desiredLRP }
func (b *BlobStore) DownloadDropletAction(dropletName string) *models.Action { return models.WrapAction(&models.SerialAction{ Actions: []*models.Action{ models.WrapAction(&models.RunAction{ Path: "/tmp/s3tool", Dir: "/", Args: []string{ "get", b.blobTarget.AccessKey, b.blobTarget.SecretKey, b.Bucket, b.blobTarget.Region, "/" + dropletName + "/droplet.tgz", "/tmp/droplet.tgz", }, User: "******", }), models.WrapAction(&models.RunAction{ Path: "/bin/tar", Args: []string{"zxf", "/tmp/droplet.tgz"}, Dir: "/home/vcap", User: "******", }), }, }) }
func (dr *dropletRunner) LaunchDroplet(appName, dropletName string, startCommand string, startArgs []string, appEnvironmentParams app_runner.AppEnvironmentParams) error { executionMetadata, err := dr.getExecutionMetadata(path.Join(dropletName, "result.json")) if err != nil { return err } dropletAnnotation := annotation{} dropletAnnotation.DropletSource.DropletName = dropletName annotationBytes, err := json.Marshal(dropletAnnotation) if err != nil { return err } if appEnvironmentParams.EnvironmentVariables == nil { appEnvironmentParams.EnvironmentVariables = map[string]string{} } appEnvironmentParams.EnvironmentVariables["PWD"] = "/home/vcap" appEnvironmentParams.EnvironmentVariables["TMPDIR"] = "/home/vcap/tmp" appEnvironmentParams.WorkingDir = "/home/vcap" proxyConf, err := dr.proxyConfReader.ProxyConf() if err != nil { return err } appEnvironmentParams.EnvironmentVariables["http_proxy"] = proxyConf.HTTPProxy appEnvironmentParams.EnvironmentVariables["https_proxy"] = proxyConf.HTTPSProxy appEnvironmentParams.EnvironmentVariables["no_proxy"] = proxyConf.NoProxy appParams := app_runner.CreateAppParams{ AppEnvironmentParams: appEnvironmentParams, Name: appName, RootFS: DropletRootFS, StartCommand: "/tmp/launcher", AppArgs: []string{ "/home/vcap/app", strings.Join(append([]string{startCommand}, startArgs...), " "), executionMetadata, }, Annotation: string(annotationBytes), Setup: models.WrapAction(&models.SerialAction{ LogSource: appName, Actions: []*models.Action{ models.WrapAction(&models.DownloadAction{ From: "http://file-server.service.cf.internal:8080/v1/static/cell-helpers/cell-helpers.tgz", To: "/tmp", User: "******", }), dr.blobStore.DownloadDropletAction(dropletName), }, }), } return dr.appRunner.CreateApp(appParams) }
func createTestTask(taskGuid string) *models.Task { task := model_helpers.NewValidTask(taskGuid) task.Domain = "test-domain" task.TaskDefinition.RootFs = "some:rootfs" task.TaskDefinition.Action = models.WrapAction(&models.RunAction{User: "******", Path: "/bin/true"}) return task }
func (b *BlobStore) DownloadDropletAction(dropletName string) *models.Action { return models.WrapAction(&models.DownloadAction{ From: b.URL.String() + "/blobs/" + dropletName + "/droplet.tgz", To: "/home/vcap", User: "******", }) }
func (b *BlobStore) DownloadAppBitsAction(dropletName string) *models.Action { return models.WrapAction(&models.DownloadAction{ From: b.URL.String() + "/blobs/" + dropletName + "/bits.zip", To: "/tmp/app", User: "******", }) }
func (b *BlobStore) DeleteAppBitsAction(dropletName string) *models.Action { return models.WrapAction(&models.RunAction{ Path: "/tmp/davtool", Dir: "/", Args: []string{"delete", b.URL.String() + "/blobs/" + dropletName + "/bits.zip"}, User: "******", }) }
func (b *BlobStore) UploadDropletMetadataAction(dropletName string) *models.Action { return models.WrapAction(&models.RunAction{ Path: "/tmp/davtool", Dir: "/", Args: []string{"put", b.URL.String() + "/blobs/" + dropletName + "/result.json", "/tmp/result.json"}, User: "******", }) }
func (b *BlobStore) UploadDropletAction(dropletName string) *models.Action { return models.WrapAction(&models.RunAction{ Path: "/tmp/davtool", Dir: "/", Args: []string{"put", b.URL.String() + "/blobs/" + dropletName + "-droplet.tgz", "/tmp/droplet"}, User: "******", LogSource: "DROPLET", }) }
func taskCreateRequest(taskGuid, rootFS string, action models.ActionInterface, memoryMB, diskMB int) receptor.TaskCreateRequest { return receptor.TaskCreateRequest{ TaskGuid: taskGuid, Domain: defaultDomain, RootFS: rootFS, MemoryMB: memoryMB, DiskMB: diskMB, Action: models.WrapAction(action), } }
func NewValidDesiredLRP(guid string) *models.DesiredLRP { myRouterJSON := json.RawMessage(`{"foo":"bar"}`) modTag := models.NewModificationTag("epoch", 0) desiredLRP := &models.DesiredLRP{ ProcessGuid: guid, Domain: "some-domain", RootFs: "some:rootfs", Instances: 1, EnvironmentVariables: []*models.EnvironmentVariable{{Name: "FOO", Value: "bar"}}, Setup: models.WrapAction(&models.RunAction{Path: "ls", User: "******"}), Action: models.WrapAction(&models.RunAction{Path: "ls", User: "******"}), StartTimeout: 15, Monitor: models.WrapAction(models.EmitProgressFor( models.Timeout(models.Try(models.Parallel(models.Serial(&models.RunAction{Path: "ls", User: "******"}))), 10*time.Second, ), "start-message", "success-message", "failure-message", )), DiskMb: 512, MemoryMb: 1024, CpuWeight: 42, Routes: &models.Routes{"my-router": &myRouterJSON}, LogSource: "some-log-source", LogGuid: "some-log-guid", MetricsGuid: "some-metrics-guid", Annotation: "some-annotation", EgressRules: []*models.SecurityGroupRule{{ Protocol: models.TCPProtocol, Destinations: []string{"1.1.1.1/32", "2.2.2.2/32"}, PortRange: &models.PortRange{Start: 10, End: 16000}, }}, ModificationTag: &modTag, } err := desiredLRP.Validate() Expect(err).NotTo(HaveOccurred()) return desiredLRP }
func (b *BlobStore) DeleteAppBitsAction(dropletName string) *models.Action { return models.WrapAction(&models.RunAction{ Path: "/tmp/s3tool", Dir: "/", Args: []string{ "delete", b.blobTarget.AccessKey, b.blobTarget.SecretKey, b.Bucket, b.blobTarget.Region, "/" + dropletName + "/bits.zip", }, User: "******", }) }
func (b *BlobStore) UploadDropletMetadataAction(dropletName string) *models.Action { return models.WrapAction(&models.RunAction{ Path: "/tmp/s3tool", Dir: "/", Args: []string{ "put", b.blobTarget.AccessKey, b.blobTarget.SecretKey, b.Bucket, b.blobTarget.Region, "/" + dropletName + "/result.json", "/tmp/result.json", }, User: "******", }) }
func (b *BlobStore) UploadDropletAction(dropletName string) *models.Action { return models.WrapAction(&models.RunAction{ Path: "/tmp/s3tool", Dir: "/", Args: []string{ "put", b.blobTarget.AccessKey, b.blobTarget.SecretKey, b.Bucket, b.blobTarget.Region, "/" + dropletName + "-droplet.tgz", "/tmp/droplet", }, User: "******", LogSource: "DROPLET", }) }
func NewValidTaskDefinition() *models.TaskDefinition { return &models.TaskDefinition{ RootFs: "docker:///docker.com/docker", EnvironmentVariables: []*models.EnvironmentVariable{ { Name: "FOO", Value: "BAR", }, }, Action: models.WrapAction(&models.RunAction{ User: "******", Path: "echo", Args: []string{"hello world"}, ResourceLimits: &models.ResourceLimits{}, }), MemoryMb: 256, DiskMb: 1024, CpuWeight: 42, Privileged: true, LogGuid: "123", LogSource: "APP", MetricsGuid: "456", ResultFile: "some-file.txt", EgressRules: []*models.SecurityGroupRule{ { Protocol: "tcp", Destinations: []string{"0.0.0.0/0"}, PortRange: &models.PortRange{ Start: 1, End: 1024, }, Log: true, }, { Protocol: "udp", Destinations: []string{"8.8.0.0/16"}, Ports: []uint32{53}, }, }, Annotation: `[{"anything": "you want!"}]... dude`, } }
func newLRPContainer(lrpKey models.ActualLRPKey, instanceKey models.ActualLRPInstanceKey, netInfo models.ActualLRPNetInfo) executor.Container { ports := []executor.PortMapping{} for _, portMap := range netInfo.Ports { ports = append(ports, executor.PortMapping{ ContainerPort: uint16(portMap.ContainerPort), HostPort: uint16(portMap.HostPort), }) } return executor.Container{ Guid: rep.LRPContainerGuid(lrpKey.ProcessGuid, instanceKey.InstanceGuid), RunInfo: executor.RunInfo{ Action: models.WrapAction(&models.RunAction{Path: "true"}), Ports: ports, }, ExternalIP: netInfo.Address, Tags: executor.Tags{ rep.ProcessGuidTag: lrpKey.ProcessGuid, rep.InstanceGuidTag: instanceKey.InstanceGuid, rep.ProcessIndexTag: strconv.Itoa(int(lrpKey.Index)), rep.DomainTag: lrpKey.Domain, }, } }
Expect(err).To(MatchError(ContainSubstring("connection refused"))) }) }) Context("Droplet Actions", func() { var dropletURL string BeforeEach(func() { dropletURL = fmt.Sprintf("http://%s:%s@%s:%s/blobs/droplet-name", blobTargetInfo.Username, blobTargetInfo.Password, blobTargetInfo.Host, blobTargetInfo.Port) }) Describe("#DownloadAppBitsAction", func() { It("constructs the correct Action to download app bits", func() { Expect(blobStore.DownloadAppBitsAction("droplet-name")).To(Equal(models.WrapAction(&models.DownloadAction{ From: dropletURL + "/bits.zip", To: "/tmp/app", User: "******", }))) }) }) Describe("#DeleteAppBitsAction", func() { It("constructs the correct Action to delete app bits", func() { Expect(blobStore.DeleteAppBitsAction("droplet-name")).To(Equal(models.WrapAction(&models.RunAction{ Path: "/tmp/davtool", Dir: "/", Args: []string{"delete", dropletURL + "/bits.zip"}, User: "******", }))) }) })
&models.CachedDependency{ From: "http://file-server.com/v1/static/the/docker/lifecycle/path.tgz", To: "/tmp/lifecycle", CacheKey: "docker-lifecycle", }, } Expect(taskDefinition.LegacyDownloadUser).To(Equal("vcap")) Expect(taskDefinition.CachedDependencies).To(BeEquivalentTo(expectedCacheDependencies)) expectedAction := models.WrapAction(&models.RunAction{ User: "******", Path: "/tmp/lifecycle/launcher", Args: append( []string{"app"}, "docker run fast", "{}", ), Env: taskRequest.EnvironmentVariables, ResourceLimits: &models.ResourceLimits{}, LogSource: "TASK", }) Expect(taskDefinition.Action).To(BeEquivalentTo(expectedAction)) }) Context("when the docker path is not specified", func() { BeforeEach(func() { taskRequest.DockerPath = "" }) It("returns an error", func() {
func (backend *dockerBackend) BuildRecipe(stagingGuid string, request cc_messages.StagingRequestFromCC) (*models.TaskDefinition, string, string, error) { logger := backend.logger.Session("build-recipe", lager.Data{"app-id": request.AppId, "staging-guid": stagingGuid}) logger.Info("staging-request") var lifecycleData cc_messages.DockerStagingData err := json.Unmarshal(*request.LifecycleData, &lifecycleData) if err != nil { return &models.TaskDefinition{}, "", "", err } err = backend.validateRequest(request, lifecycleData) if err != nil { return &models.TaskDefinition{}, "", "", err } compilerURL, err := backend.compilerDownloadURL() if err != nil { return &models.TaskDefinition{}, "", "", err } cacheDockerImage := false for _, envVar := range request.Environment { if envVar.Name == "DIEGO_DOCKER_CACHE" && envVar.Value == "true" { cacheDockerImage = true break } } actions := []models.ActionInterface{} //Download builder actions = append( actions, models.EmitProgressFor( &models.DownloadAction{ From: compilerURL.String(), To: path.Dir(DockerBuilderExecutablePath), CacheKey: "docker-lifecycle", User: "******", }, "", "", "Failed to set up docker environment", ), ) runActionArguments := []string{"-outputMetadataJSONFilename", DockerBuilderOutputPath, "-dockerRef", lifecycleData.DockerImageUrl} runAs := "vcap" if cacheDockerImage { runAs = "root" host, port, err := net.SplitHostPort(backend.config.DockerRegistryAddress) if err != nil { logger.Debug("invalid docker registry address", lager.Data{"address": backend.config.DockerRegistryAddress, "error": err.Error()}) return &models.TaskDefinition{}, "", "", ErrInvalidDockerRegistryAddress } registryServices, err := getDockerRegistryServices(backend.config.ConsulCluster, backend.logger) if err != nil { return &models.TaskDefinition{}, "", "", err } registryRules := addDockerRegistryRules(request.EgressRules, registryServices) request.EgressRules = append(request.EgressRules, registryRules...) registryIPs := strings.Join(buildDockerRegistryAddresses(registryServices), ",") runActionArguments, err = addDockerCachingArguments(runActionArguments, registryIPs, backend.config.InsecureDockerRegistry, host, port, lifecycleData) if err != nil { return &models.TaskDefinition{}, "", "", err } } fileDescriptorLimit := uint64(request.FileDescriptors) // Run builder actions = append( actions, models.EmitProgressFor( &models.RunAction{ Path: DockerBuilderExecutablePath, Args: runActionArguments, Env: request.Environment, ResourceLimits: &models.ResourceLimits{ Nofile: &fileDescriptorLimit, }, User: runAs, }, "Staging...", "Staging Complete", "Staging Failed", ), ) annotationJson, _ := json.Marshal(cc_messages.StagingTaskAnnotation{ Lifecycle: DockerLifecycleName, }) taskDefinition := &models.TaskDefinition{ RootFs: models.PreloadedRootFS(backend.config.DockerStagingStack), ResultFile: DockerBuilderOutputPath, Privileged: true, MemoryMb: int32(request.MemoryMB), LogSource: TaskLogSource, LogGuid: request.LogGuid, EgressRules: request.EgressRules, DiskMb: int32(request.DiskMB), CompletionCallbackUrl: backend.config.CallbackURL(stagingGuid), Annotation: string(annotationJson), Action: models.WrapAction(models.Timeout(models.Serial(actions...), dockerTimeout(request, backend.logger))), } logger.Debug("staging-task-request") return taskDefinition, stagingGuid, backend.config.TaskDomain, nil }
logger.RegisterSink(lager.NewWriterSink(GinkgoWriter, lager.DEBUG)) runner = new(fake_auction_runner.FakeAuctionRunner) responseRecorder = httptest.NewRecorder() handler = New(runner, logger) }) Describe("Task Handler", func() { Context("with a valid task", func() { BeforeEach(func() { tasks := []models.Task{{ TaskGuid: "the-task-guid", Domain: "some-domain", RootFs: "some:rootfs", Action: models.WrapAction(&models.RunAction{ User: "******", Path: "ls", }), }} reqGen := rata.NewRequestGenerator("http://localhost", Routes) payload, err := json.Marshal(tasks) Expect(err).NotTo(HaveOccurred()) req, err := reqGen.CreateRequest(CreateTaskAuctionsRoute, rata.Params{}, bytes.NewBuffer(payload)) Expect(err).NotTo(HaveOccurred()) handler.ServeHTTP(responseRecorder, req) }) It("responds with 202", func() {
fakeRawEventSource = new(fake_receptor.FakeRawEventSource) eventSource = receptor.NewEventSource(fakeRawEventSource) }) Describe("Next", func() { Describe("Desired LRP events", func() { var desiredLRPResponse receptor.DesiredLRPResponse BeforeEach(func() { desiredLRPResponse = serialization.DesiredLRPProtoToResponse( &models.DesiredLRP{ ProcessGuid: "some-guid", Domain: "some-domain", RootFs: "some-rootfs", Action: models.WrapAction(&models.RunAction{ Path: "true", User: "******", }), }, ) }) Context("when receiving a DesiredLRPCreatedEvent", func() { var expectedEvent receptor.DesiredLRPCreatedEvent BeforeEach(func() { expectedEvent = receptor.NewDesiredLRPCreatedEvent(desiredLRPResponse) payload, err := json.Marshal(expectedEvent) Expect(err).NotTo(HaveOccurred()) fakeRawEventSource.NextReturns( sse.Event{
Expect(completedTasks[0].TaskGuid).To(Equal(task.TaskGuid)) Expect(completedTasks[0].Failed).To(BeTrue()) }) }) Describe("polling the BBS for actual LRPs to reap", func() { JustBeforeEach(func() { desiredLRP := &models.DesiredLRP{ ProcessGuid: "process-guid", RootFs: "some:rootfs", Domain: "some-domain", Instances: 1, Action: models.WrapAction(&models.RunAction{ User: "******", Path: "the-path", Args: []string{}, }), } index := 0 err := bbsClient.DesireLRP(desiredLRP) Expect(err).NotTo(HaveOccurred()) instanceKey := models.NewActualLRPInstanceKey("some-instance-guid", cellID) err = bbsClient.ClaimActualLRP(desiredLRP.ProcessGuid, index, &instanceKey) Expect(err).NotTo(HaveOccurred()) }) It("eventually reaps actual LRPs with no corresponding container", func() { Eventually(getActualLRPGroups, 5*pollingInterval).Should(BeEmpty())
DiskMB: 1024, ExposedPorts: []uint16{2000, 4000}, WorkingDir: "/user/web/myappdir", Privileged: true, User: "******", }, Name: "americano-app", StartCommand: "/app-run-statement", RootFS: "/runtest/runner", AppArgs: []string{"app", "arg1", "--app", "arg 2"}, Annotation: "some annotation", Setup: models.WrapAction(&models.DownloadAction{ From: "some-cell-helper-url", To: "/tmp", User: "******", }), } }) It("Upserts lattice domain so that it is always fresh, then starts the Docker App", func() { err := appRunner.CreateApp(createAppParams) Expect(err).ToNot(HaveOccurred()) Expect(fakeReceptorClient.UpsertDomainCallCount()).To(Equal(1)) domain, ttl := fakeReceptorClient.UpsertDomainArgsForCall(0) Expect(domain).To(Equal("lattice")) Expect(ttl).To(Equal(time.Duration(0))) Expect(fakeReceptorClient.CreateDesiredLRPCallCount()).To(Equal(1))
return } eventChannel <- event } }() rawMessage := json.RawMessage([]byte(`{"port":8080,"hosts":["primer-route"]}`)) primerLRP := &models.DesiredLRP{ ProcessGuid: "primer-guid", Domain: "primer-domain", RootFs: "primer:rootfs", Routes: &models.Routes{ "router": &rawMessage, }, Action: models.WrapAction(&models.RunAction{ User: "******", Path: "true", }), } etcdHelper.SetRawDesiredLRP(primerLRP) PRIMING: for { select { case <-eventChannel: break PRIMING case <-time.After(50 * time.Millisecond): etcdHelper.SetRawDesiredLRP(primerLRP) Expect(err).NotTo(HaveOccurred()) } }
func (t crashTest) Test() { Context(t.Name, func() { var ( crashErr error actualLRPKey *models.ActualLRPKey instanceKey *models.ActualLRPInstanceKey initialTimestamp int64 initialModificationIndex uint32 ) BeforeEach(func() { actualLRP := t.LRP() actualLRPKey = &actualLRP.ActualLRPKey instanceKey = &actualLRP.ActualLRPInstanceKey initialTimestamp = actualLRP.Since initialModificationIndex = actualLRP.ModificationTag.Index desiredLRP := models.DesiredLRP{ ProcessGuid: actualLRPKey.ProcessGuid, Domain: actualLRPKey.Domain, Instances: actualLRPKey.Index + 1, RootFs: "foo:bar", Action: models.WrapAction(&models.RunAction{Path: "true", User: "******"}), } etcdHelper.SetRawDesiredLRP(&desiredLRP) etcdHelper.SetRawActualLRP(&actualLRP) }) JustBeforeEach(func() { clock.Increment(600) crashErr = etcdDB.CrashActualLRP(logger, actualLRPKey, instanceKey, "crashed") }) if t.Result.ReturnedErr == nil { It("does not return an error", func() { Expect(crashErr).NotTo(HaveOccurred()) }) } else { It(fmt.Sprintf("returned error should be '%s'", t.Result.ReturnedErr.Error()), func() { Expect(crashErr).To(Equal(t.Result.ReturnedErr)) }) } It(fmt.Sprintf("has crash count %d", t.Result.CrashCount), func() { actualLRP, err := etcdHelper.GetInstanceActualLRP(actualLRPKey) Expect(err).NotTo(HaveOccurred()) Expect(actualLRP.CrashCount).To(Equal(t.Result.CrashCount)) }) It(fmt.Sprintf("has crash reason %s", t.Result.CrashReason), func() { actualLRP, err := etcdHelper.GetInstanceActualLRP(actualLRPKey) Expect(err).NotTo(HaveOccurred()) Expect(actualLRP.CrashReason).To(Equal(t.Result.CrashReason)) }) if t.Result.ShouldUpdate { It("updates the Since", func() { actualLRP, err := etcdHelper.GetInstanceActualLRP(actualLRPKey) Expect(err).NotTo(HaveOccurred()) Expect(actualLRP.Since).To(Equal(clock.Now().UnixNano())) }) It("updates the ModificationIndex", func() { actualLRP, err := etcdHelper.GetInstanceActualLRP(actualLRPKey) Expect(err).NotTo(HaveOccurred()) Expect(actualLRP.ModificationTag.Index).To(Equal(initialModificationIndex + 1)) }) } else { It("does not update the Since", func() { actualLRP, err := etcdHelper.GetInstanceActualLRP(actualLRPKey) Expect(err).NotTo(HaveOccurred()) Expect(actualLRP.Since).To(Equal(initialTimestamp)) }) It("does not update the ModificationIndex", func() { actualLRP, err := etcdHelper.GetInstanceActualLRP(actualLRPKey) Expect(err).NotTo(HaveOccurred()) Expect(actualLRP.ModificationTag.Index).To(Equal(initialModificationIndex)) }) } It(fmt.Sprintf("CAS to %s", t.Result.State), func() { actualLRP, err := etcdHelper.GetInstanceActualLRP(actualLRPKey) Expect(err).NotTo(HaveOccurred()) Expect(actualLRP.State).To(Equal(t.Result.State)) }) if t.Result.Auction { It("starts an auction", func() { Expect(fakeAuctioneerClient.RequestLRPAuctionsCallCount()).To(Equal(1)) requestedAuctions := fakeAuctioneerClient.RequestLRPAuctionsArgsForCall(0) Expect(requestedAuctions).To(HaveLen(1)) desiredLRP, err := etcdDB.DesiredLRPByProcessGuid(logger, actualLRPKey.ProcessGuid) Expect(err).NotTo(HaveOccurred()) expectedStartRequest := auctioneer.NewLRPStartRequestFromModel(desiredLRP, int(actualLRPKey.Index)) Expect(*requestedAuctions[0]).To(Equal(expectedStartRequest)) }) Context("when the desired LRP no longer exists", func() { BeforeEach(func() { etcdHelper.DeleteDesiredLRP(actualLRPKey.ProcessGuid) }) It("the actual LRP is also deleted", func() { Expect(crashErr).NotTo(HaveOccurred()) _, err := etcdDB.ActualLRPGroupByProcessGuidAndIndex(logger, actualLRPKey.ProcessGuid, actualLRPKey.Index) Expect(err).To(Equal(models.ErrResourceNotFound)) }) }) } else { It("does not start an auction", func() { Expect(fakeAuctioneerClient.RequestLRPAuctionsCallCount()).To(Equal(0)) }) } Context("when crashing a different instance key", func() { var beforeActualGroup *models.ActualLRPGroup BeforeEach(func() { var err error beforeActualGroup, err = etcdDB.ActualLRPGroupByProcessGuidAndIndex(logger, actualLRPKey.ProcessGuid, actualLRPKey.Index) Expect(err).NotTo(HaveOccurred()) instanceKey.InstanceGuid = "another-guid" }) It("does not crash", func() { Expect(crashErr).To(Equal(models.ErrActualLRPCannotBeCrashed)) afterActualGroup, err := etcdDB.ActualLRPGroupByProcessGuidAndIndex(logger, actualLRPKey.ProcessGuid, actualLRPKey.Index) Expect(err).NotTo(HaveOccurred()) Expect(afterActualGroup).To(Equal(beforeActualGroup)) }) }) }) }
func (backend *dockerBackend) BuildRecipe(stagingGuid string, request cc_messages.StagingRequestFromCC) (*models.TaskDefinition, string, string, error) { logger := backend.logger.Session("build-recipe", lager.Data{"app-id": request.AppId, "staging-guid": stagingGuid}) logger.Info("staging-request") var lifecycleData cc_messages.DockerStagingData err := json.Unmarshal(*request.LifecycleData, &lifecycleData) if err != nil { return &models.TaskDefinition{}, "", "", err } err = backend.validateRequest(request, lifecycleData) if err != nil { return &models.TaskDefinition{}, "", "", err } compilerURL, err := backend.compilerDownloadURL() if err != nil { return &models.TaskDefinition{}, "", "", err } cachedDependencies := []*models.CachedDependency{ &models.CachedDependency{ From: compilerURL.String(), To: path.Dir(DockerBuilderExecutablePath), CacheKey: "docker-lifecycle", }, } runActionArguments := []string{ "-outputMetadataJSONFilename", DockerBuilderOutputPath, "-dockerRef", lifecycleData.DockerImageUrl, } if len(backend.config.InsecureDockerRegistries) > 0 { insecureDockerRegistries := strings.Join(backend.config.InsecureDockerRegistries, ",") runActionArguments = append(runActionArguments, "-insecureDockerRegistries", insecureDockerRegistries) } fileDescriptorLimit := uint64(request.FileDescriptors) runAs := "vcap" actions := []models.ActionInterface{} if cacheDockerImage(request.Environment) { runAs = "root" additionalEgressRules, additionalArgs, err := cachingEgressRulesAndArgs( logger, backend.config.DockerRegistryAddress, backend.config.ConsulCluster, lifecycleData, ) if err != nil { return &models.TaskDefinition{}, "", "", err } runActionArguments = append(runActionArguments, additionalArgs...) request.EgressRules = append(request.EgressRules, additionalEgressRules...) actions = append( actions, models.EmitProgressFor( &models.RunAction{ Path: MountCgroupsPath, ResourceLimits: &models.ResourceLimits{ Nofile: &fileDescriptorLimit, }, User: runAs, }, "Preparing docker daemon...", "", "Failed to set up docker environment", ), ) } actions = append( actions, models.EmitProgressFor( &models.RunAction{ Path: DockerBuilderExecutablePath, Args: runActionArguments, Env: request.Environment, ResourceLimits: &models.ResourceLimits{ Nofile: &fileDescriptorLimit, }, User: runAs, }, "Staging...", "Staging Complete", "Staging Failed", ), ) annotationJson, _ := json.Marshal(cc_messages.StagingTaskAnnotation{ Lifecycle: DockerLifecycleName, CompletionCallback: request.CompletionCallback, }) taskDefinition := &models.TaskDefinition{ RootFs: models.PreloadedRootFS(backend.config.DockerStagingStack), ResultFile: DockerBuilderOutputPath, Privileged: true, MemoryMb: int32(request.MemoryMB), LogSource: TaskLogSource, LogGuid: request.LogGuid, EgressRules: request.EgressRules, DiskMb: int32(request.DiskMB), CompletionCallbackUrl: backend.config.CallbackURL(stagingGuid), Annotation: string(annotationJson), Action: models.WrapAction(models.Timeout(models.Serial(actions...), dockerTimeout(request, backend.logger))), CachedDependencies: cachedDependencies, LegacyDownloadUser: "******", TrustedSystemCertificatesPath: TrustedSystemCertificatesPath, } logger.Debug("staging-task-request") return taskDefinition, stagingGuid, backend.config.TaskDomain, nil }
responseRecorder = httptest.NewRecorder() handler = auctionhandlers.NewTaskAuctionHandler(runner) }) Describe("Create", func() { Context("when the request body is a task", func() { var tasks []*models.Task BeforeEach(func() { tasks = []*models.Task{{ TaskGuid: "the-task-guid", Domain: "some-domain", RootFs: "some:rootfs", Action: models.WrapAction(&models.RunAction{ User: "******", Path: "ls", ResourceLimits: &models.ResourceLimits{}, }), }} handler.Create(responseRecorder, newTestRequest(tasks), logger) }) It("responds with 202", func() { Expect(responseRecorder.Code).To(Equal(http.StatusAccepted)) }) It("responds with an empty JSON body", func() { Expect(responseRecorder.Body.String()).To(Equal("{}")) })
BeforeEach(func() { fakeRawEventSource = new(eventfakes.FakeRawEventSource) eventSource = events.NewEventSource(fakeRawEventSource) }) Describe("Next", func() { Describe("Desired LRP events", func() { var desiredLRP *models.DesiredLRP BeforeEach(func() { desiredLRP = &models.DesiredLRP{ ProcessGuid: "some-guid", Domain: "some-domain", RootFs: "some-rootfs", Action: models.WrapAction(&models.RunAction{ Path: "true", User: "******", }), } }) Context("when receiving a DesiredLRPCreatedEvent", func() { var expectedEvent *models.DesiredLRPCreatedEvent BeforeEach(func() { expectedEvent = models.NewDesiredLRPCreatedEvent(desiredLRP) payload, err := proto.Marshal(expectedEvent) Expect(err).NotTo(HaveOccurred()) payload = []byte(base64.StdEncoding.EncodeToString(payload)) fakeRawEventSource.NextReturns( sse.Event{