}) Context("when everything is correct", func() { It("does not error", func() { Expect(err).NotTo(HaveOccurred()) }) It("builds a valid DesiredLRP", func() { Expect(desiredLRP.ProcessGuid).To(Equal("the-app-guid-the-app-version")) Expect(desiredLRP.Instances).To(BeEquivalentTo(23)) Expect(*desiredLRP.Routes).To(Equal(cfroutes.CFRoutes{ {Hostnames: []string{"route1", "route2"}, Port: 8080}, }.RoutingInfo())) Expect(desiredLRP.Annotation).To(Equal("etag-updated-at")) Expect(desiredLRP.RootFs).To(Equal(models.PreloadedRootFS("some-stack"))) Expect(desiredLRP.MemoryMb).To(BeEquivalentTo(128)) Expect(desiredLRP.DiskMb).To(BeEquivalentTo(512)) Expect(desiredLRP.Ports).To(Equal([]uint32{8080})) Expect(desiredLRP.Privileged).To(BeTrue()) Expect(desiredLRP.StartTimeout).To(BeEquivalentTo(123456)) Expect(desiredLRP.LogGuid).To(Equal("the-log-id")) Expect(desiredLRP.LogSource).To(Equal("CELL")) Expect(desiredLRP.EnvironmentVariables).To(ConsistOf(&models.EnvironmentVariable{"LANG", recipebuilder.DefaultLANG})) Expect(desiredLRP.MetricsGuid).To(Equal("the-log-id")) expectedSetup := models.Serial( &models.DownloadAction{
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 }
handler := handlers.NewDesireAppHandler(logger, fakeBBS, map[string]recipebuilder.RecipeBuilder{ "buildpack": buildpackBuilder, "docker": dockerBuilder, }) handler.DesireApp(responseRecorder, request) }) Context("when the desired LRP does not exist", func() { var newlyDesiredLRP *models.DesiredLRP BeforeEach(func() { newlyDesiredLRP = &models.DesiredLRP{ ProcessGuid: "new-process-guid", Instances: 1, RootFs: models.PreloadedRootFS("stack-2"), Action: models.WrapAction(&models.RunAction{ User: "******", Path: "ls", }), Annotation: "last-modified-etag", } fakeBBS.DesiredLRPByProcessGuidReturns(&models.DesiredLRP{}, models.ErrResourceNotFound) buildpackBuilder.BuildReturns(newlyDesiredLRP, nil) }) It("logs the incoming and outgoing request", func() { Eventually(logger.TestSink.Buffer).Should(gbytes.Say("request-from-cc")) Eventually(logger.TestSink.Buffer).Should(gbytes.Say("creating-desired-lrp")) })
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 }
"fmt" "sync" "time" "github.com/cloudfoundry-incubator/auction/simulation/util" "github.com/cloudfoundry-incubator/auction/simulation/visualization" "github.com/cloudfoundry-incubator/auctioneer" "github.com/cloudfoundry-incubator/bbs/models" "github.com/cloudfoundry-incubator/rep" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) var _ = Describe("Auction", func() { var initialDistributions map[int][]rep.LRP var linuxRootFSURL = models.PreloadedRootFS(linuxStack) newLRP := func(processGuid string, index int, memoryMB int) rep.LRP { lrpKey := models.NewActualLRPKey(processGuid, int32(index), "domain") return rep.NewLRP(lrpKey, rep.NewResource(int32(memoryMB), 1, linuxRootFSURL)) } generateUniqueLRPs := func(numInstances int, index int, memoryMB int) []rep.LRP { instances := []rep.LRP{} for i := 0; i < numInstances; i++ { instances = append(instances, newLRP(util.NewGrayscaleGuid("AAA"), index, memoryMB)) } return instances } newLRPStartAuction := func(processGuid string, index int, memoryMB int32) auctioneer.LRPStartRequest {
auctions := make([]auctiontypes.LRPAuction, 0, len(start.Indices)) for _, index := range start.Indices { lrpKey := models.NewActualLRPKey(start.ProcessGuid, int32(index), start.Domain) auctions = append(auctions, auctiontypes.NewLRPAuction(rep.NewLRP(lrpKey, start.Resource), queueTime)) } return auctions } func BuildTaskAuction(task *rep.Task, queueTime time.Time) auctiontypes.TaskAuction { return auctiontypes.NewTaskAuction(*task, queueTime) } const linuxStack = "linux" var linuxRootFSURL = models.PreloadedRootFS(linuxStack) var linuxOnlyRootFSProviders = rep.RootFSProviders{models.PreloadedRootFSScheme: rep.NewFixedSetRootFSProvider(linuxStack)} const windowsStack = "windows" var windowsRootFSURL = models.PreloadedRootFS(windowsStack) var windowsOnlyRootFSProviders = rep.RootFSProviders{models.PreloadedRootFSScheme: rep.NewFixedSetRootFSProvider(windowsStack)} func BuildCellState( zone string, memoryMB int32, diskMB int32, containers int, evacuating bool,
lrps, err := bbsClient.DesiredLRPs(models.DesiredLRPFilter{}) Expect(err).NotTo(HaveOccurred()) result := []*models.DesiredLRP{} for _, lrp := range lrps { lrp.ModificationTag = nil result = append(result, lrp) } return result } Eventually(desiredLRPsWithoutModificationTag).Should(ContainElement(&models.DesiredLRP{ ProcessGuid: "process-guid-1", Domain: "cf-apps", Instances: 42, RootFs: models.PreloadedRootFS("some-stack"), Setup: models.WrapAction(expectedSetupActions1), StartTimeout: 123456, EnvironmentVariables: []*models.EnvironmentVariable{ {Name: "LANG", Value: recipebuilder.DefaultLANG}, }, Action: models.WrapAction(models.Codependent(&models.RunAction{ User: "******", Path: "/tmp/lifecycle/launcher", Args: []string{"app", "start-command-1", "execution-metadata-1"}, Env: []*models.EnvironmentVariable{ {Name: "env-key-1", Value: "env-value-1"}, {Name: "env-key-2", Value: "env-value-2"}, {Name: "PORT", Value: "8080"}, }, ResourceLimits: &models.ResourceLimits{Nofile: &nofile},
actions := actionsFromTaskDef(taskDef) Expect(actions).To(HaveLen(2)) Expect(actions[0].GetEmitProgressAction()).To(Equal(downloadBuilderAction)) Expect(actions[1].GetEmitProgressAction()).To(Equal(runAction)) Expect(taskDef.MemoryMb).To(Equal(memoryMb)) Expect(taskDef.DiskMb).To(Equal(diskMb)) Expect(taskDef.EgressRules).To(ConsistOf(egressRules)) }) It("uses the configured docker staging stack", func() { taskDef, _, _, err := docker.BuildRecipe(stagingGuid, stagingRequest) Expect(err).NotTo(HaveOccurred()) Expect(taskDef.RootFs).To(Equal(models.PreloadedRootFS("penguin"))) }) It("gives the task a callback URL to call it back", func() { taskDef, _, _, err := docker.BuildRecipe(stagingGuid, stagingRequest) Expect(err).NotTo(HaveOccurred()) Expect(taskDef.CompletionCallbackUrl).To(Equal(fmt.Sprintf("%s/v1/staging/%s/completed", config.StagerURL, stagingGuid))) }) Describe("staging action timeout", func() { Context("when a positive timeout is specified in the staging request from CC", func() { BeforeEach(func() { timeout = 5 })
func (backend *traditionalBackend) 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") if request.LifecycleData == nil { return &models.TaskDefinition{}, "", "", ErrMissingLifecycleData } var lifecycleData cc_messages.BuildpackStagingData 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(request, lifecycleData) if err != nil { return &models.TaskDefinition{}, "", "", err } buildpacksOrder := []string{} for _, buildpack := range lifecycleData.Buildpacks { buildpacksOrder = append(buildpacksOrder, buildpack.Key) } skipDetect := len(lifecycleData.Buildpacks) == 1 && lifecycleData.Buildpacks[0].SkipDetect builderConfig := buildpack_app_lifecycle.NewLifecycleBuilderConfig(buildpacksOrder, skipDetect, backend.config.SkipCertVerify) timeout := traditionalTimeout(request, backend.logger) actions := []models.ActionInterface{} //Download app package appDownloadAction := &models.DownloadAction{ Artifact: "app package", From: lifecycleData.AppBitsDownloadUri, To: builderConfig.BuildDir(), User: "******", } actions = append(actions, appDownloadAction) downloadActions := []models.ActionInterface{} downloadNames := []string{} //Download builder downloadActions = append( downloadActions, models.EmitProgressFor( &models.DownloadAction{ From: compilerURL.String(), To: path.Dir(builderConfig.ExecutablePath), CacheKey: fmt.Sprintf("buildpack-%s-lifecycle", lifecycleData.Stack), User: "******", }, "", "", "Failed to set up staging environment", ), ) //Download buildpacks buildpackNames := []string{} downloadMsgPrefix := "" if !skipDetect { downloadMsgPrefix = "No buildpack specified; fetching standard buildpacks to detect and build your application.\n" } for _, buildpack := range lifecycleData.Buildpacks { if buildpack.Name == cc_messages.CUSTOM_BUILDPACK { buildpackNames = append(buildpackNames, buildpack.Url) } else { buildpackNames = append(buildpackNames, buildpack.Name) downloadActions = append( downloadActions, &models.DownloadAction{ Artifact: buildpack.Name, From: buildpack.Url, To: builderConfig.BuildpackPath(buildpack.Key), CacheKey: buildpack.Key, User: "******", }, ) } } downloadNames = append(downloadNames, fmt.Sprintf("buildpacks (%s)", strings.Join(buildpackNames, ", "))) //Download buildpack artifacts cache downloadURL, err := backend.buildArtifactsDownloadURL(lifecycleData) if err != nil { return &models.TaskDefinition{}, "", "", err } if downloadURL != nil { downloadActions = append( downloadActions, models.Try( &models.DownloadAction{ Artifact: "build artifacts cache", From: downloadURL.String(), To: builderConfig.BuildArtifactsCacheDir(), User: "******", }, ), ) downloadNames = append(downloadNames, "build artifacts cache") } downloadMsg := downloadMsgPrefix + fmt.Sprintf("Downloading %s...", strings.Join(downloadNames, ", ")) actions = append(actions, models.EmitProgressFor(models.Parallel(downloadActions...), downloadMsg, "Downloaded buildpacks", "Downloading buildpacks failed")) fileDescriptorLimit := uint64(request.FileDescriptors) //Run Builder runEnv := append(request.Environment, &models.EnvironmentVariable{"CF_STACK", lifecycleData.Stack}) actions = append( actions, models.EmitProgressFor( &models.RunAction{ User: "******", Path: builderConfig.Path(), Args: builderConfig.Args(), Env: runEnv, ResourceLimits: &models.ResourceLimits{ Nofile: &fileDescriptorLimit, }, }, "Staging...", "Staging complete", "Staging failed", ), ) //Upload Droplet uploadActions := []models.ActionInterface{} uploadNames := []string{} uploadURL, err := backend.dropletUploadURL(request, lifecycleData) if err != nil { return &models.TaskDefinition{}, "", "", err } uploadActions = append( uploadActions, &models.UploadAction{ Artifact: "droplet", From: builderConfig.OutputDroplet(), // get the droplet To: addTimeoutParamToURL(*uploadURL, timeout).String(), User: "******", }, ) uploadNames = append(uploadNames, "droplet") //Upload Buildpack Artifacts Cache uploadURL, err = backend.buildArtifactsUploadURL(request, lifecycleData) if err != nil { return &models.TaskDefinition{}, "", "", err } uploadActions = append(uploadActions, models.Try( &models.UploadAction{ Artifact: "build artifacts cache", From: builderConfig.OutputBuildArtifactsCache(), // get the compressed build artifacts cache To: addTimeoutParamToURL(*uploadURL, timeout).String(), User: "******", }, ), ) uploadNames = append(uploadNames, "build artifacts cache") uploadMsg := fmt.Sprintf("Uploading %s...", strings.Join(uploadNames, ", ")) actions = append(actions, models.EmitProgressFor(models.Parallel(uploadActions...), uploadMsg, "Uploading complete", "Uploading failed")) annotationJson, _ := json.Marshal(cc_messages.StagingTaskAnnotation{ Lifecycle: TraditionalLifecycleName, CompletionCallback: request.CompletionCallback, }) taskDefinition := &models.TaskDefinition{ RootFs: models.PreloadedRootFS(lifecycleData.Stack), ResultFile: builderConfig.OutputMetadata(), MemoryMb: int32(request.MemoryMB), DiskMb: int32(request.DiskMB), CpuWeight: uint32(StagingTaskCpuWeight), Action: models.WrapAction(models.Timeout(models.Serial(actions...), timeout)), LogGuid: request.LogGuid, LogSource: TaskLogSource, CompletionCallbackUrl: backend.config.CallbackURL(stagingGuid), EgressRules: request.EgressRules, Annotation: string(annotationJson), Privileged: true, EnvironmentVariables: []*models.EnvironmentVariable{{"LANG", DefaultLANG}}, } logger.Debug("staging-task-request") return taskDefinition, stagingGuid, backend.config.TaskDomain, nil }
func (b *BuildpackRecipeBuilder) Build(desiredApp *cc_messages.DesireAppRequestFromCC) (*models.DesiredLRP, error) { lrpGuid := desiredApp.ProcessGuid buildLogger := b.logger.Session("message-builder") if desiredApp.DropletUri == "" { buildLogger.Error("desired-app-invalid", ErrDropletSourceMissing, lager.Data{"desired-app": desiredApp}) return nil, ErrDropletSourceMissing } if desiredApp.DropletUri != "" && desiredApp.DockerImageUrl != "" { buildLogger.Error("desired-app-invalid", ErrMultipleAppSources, lager.Data{"desired-app": desiredApp}) return nil, ErrMultipleAppSources } var lifecycle = "buildpack/" + desiredApp.Stack lifecyclePath, ok := b.config.Lifecycles[lifecycle] if !ok { buildLogger.Error("unknown-lifecycle", ErrNoLifecycleDefined, lager.Data{ "lifecycle": lifecycle, }) return nil, ErrNoLifecycleDefined } lifecycleURL := lifecycleDownloadURL(lifecyclePath, b.config.FileServerURL) rootFSPath := models.PreloadedRootFS(desiredApp.Stack) var containerEnvVars []*models.EnvironmentVariable containerEnvVars = append(containerEnvVars, &models.EnvironmentVariable{"LANG", DefaultLANG}) numFiles := DefaultFileDescriptorLimit if desiredApp.FileDescriptors != 0 { numFiles = desiredApp.FileDescriptors } var setup []models.ActionInterface var actions []models.ActionInterface var monitor models.ActionInterface cachedDependencies := []*models.CachedDependency{} cachedDependencies = append(cachedDependencies, &models.CachedDependency{ From: lifecycleURL, To: "/tmp/lifecycle", CacheKey: fmt.Sprintf("%s-lifecycle", strings.Replace(lifecycle, "/", "-", 1)), }) desiredAppPorts, err := b.ExtractExposedPorts(desiredApp) if err != nil { return nil, err } switch desiredApp.HealthCheckType { case cc_messages.PortHealthCheckType, cc_messages.UnspecifiedHealthCheckType: monitor = models.Timeout(getParallelAction(desiredAppPorts, "vcap"), 30*time.Second) } setup = append(setup, &models.DownloadAction{ From: desiredApp.DropletUri, To: ".", CacheKey: fmt.Sprintf("droplets-%s", lrpGuid), User: "******", }) actions = append(actions, &models.RunAction{ User: "******", Path: "/tmp/lifecycle/launcher", Args: append( []string{"app"}, desiredApp.StartCommand, desiredApp.ExecutionMetadata, ), Env: createLrpEnv(desiredApp.Environment, desiredAppPorts[0]), LogSource: AppLogSource, ResourceLimits: &models.ResourceLimits{ Nofile: &numFiles, }, }) desiredAppRoutingInfo, err := helpers.CCRouteInfoToRoutes(desiredApp.RoutingInfo, desiredAppPorts) if err != nil { buildLogger.Error("marshaling-cc-route-info-failed", err) return nil, err } if desiredApp.AllowSSH { hostKeyPair, err := b.config.KeyFactory.NewKeyPair(1024) if err != nil { buildLogger.Error("new-host-key-pair-failed", err) return nil, err } userKeyPair, err := b.config.KeyFactory.NewKeyPair(1024) if err != nil { buildLogger.Error("new-user-key-pair-failed", err) return nil, err } actions = append(actions, &models.RunAction{ User: "******", Path: "/tmp/lifecycle/diego-sshd", Args: []string{ "-address=" + fmt.Sprintf("0.0.0.0:%d", DefaultSSHPort), "-hostKey=" + hostKeyPair.PEMEncodedPrivateKey(), "-authorizedKey=" + userKeyPair.AuthorizedKey(), "-inheritDaemonEnv", "-logLevel=fatal", }, Env: createLrpEnv(desiredApp.Environment, desiredAppPorts[0]), ResourceLimits: &models.ResourceLimits{ Nofile: &numFiles, }, }) sshRoutePayload, err := json.Marshal(ssh_routes.SSHRoute{ ContainerPort: 2222, PrivateKey: userKeyPair.PEMEncodedPrivateKey(), HostFingerprint: hostKeyPair.Fingerprint(), }) if err != nil { buildLogger.Error("marshaling-ssh-route-failed", err) return nil, err } sshRouteMessage := json.RawMessage(sshRoutePayload) desiredAppRoutingInfo[ssh_routes.DIEGO_SSH] = &sshRouteMessage desiredAppPorts = append(desiredAppPorts, DefaultSSHPort) } setupAction := models.Serial(setup...) actionAction := models.Codependent(actions...) return &models.DesiredLRP{ Privileged: true, Domain: cc_messages.AppLRPDomain, ProcessGuid: lrpGuid, Instances: int32(desiredApp.NumInstances), Routes: &desiredAppRoutingInfo, Annotation: desiredApp.ETag, CpuWeight: cpuWeight(desiredApp.MemoryMB), MemoryMb: int32(desiredApp.MemoryMB), DiskMb: int32(desiredApp.DiskMB), Ports: desiredAppPorts, RootFs: rootFSPath, LogGuid: desiredApp.LogGuid, LogSource: LRPLogSource, MetricsGuid: desiredApp.LogGuid, EnvironmentVariables: containerEnvVars, CachedDependencies: cachedDependencies, Setup: models.WrapAction(setupAction), Action: models.WrapAction(actionAction), Monitor: models.WrapAction(monitor), StartTimeout: uint32(desiredApp.HealthCheckTimeoutInSeconds), EgressRules: desiredApp.EgressRules, LegacyDownloadUser: "******", }, nil }
func (b *BuildpackRecipeBuilder) BuildTask(task *cc_messages.TaskRequestFromCC) (*models.TaskDefinition, error) { logger := b.logger.Session("build-task", lager.Data{"request": task}) if task.DropletUri == "" { logger.Error("missing-droplet-source", ErrDropletSourceMissing) return nil, ErrDropletSourceMissing } if task.DockerPath != "" { logger.Error("invalid-docker-path", ErrMultipleAppSources) return nil, ErrMultipleAppSources } downloadAction := &models.DownloadAction{ From: task.DropletUri, To: ".", CacheKey: "", User: "******", } runAction := &models.RunAction{ User: "******", Path: "/tmp/lifecycle/launcher", Args: []string{"app", task.Command, ""}, Env: task.EnvironmentVariables, LogSource: "TASK", ResourceLimits: &models.ResourceLimits{}, } var lifecycle = "buildpack/" + task.RootFs lifecyclePath, ok := b.config.Lifecycles[lifecycle] if !ok { logger.Error("unknown-lifecycle", ErrNoLifecycleDefined, lager.Data{ "lifecycle": lifecycle, }) return nil, ErrNoLifecycleDefined } lifecycleURL := lifecycleDownloadURL(lifecyclePath, b.config.FileServerURL) cachedDependencies := []*models.CachedDependency{ &models.CachedDependency{ From: lifecycleURL, To: "/tmp/lifecycle", CacheKey: fmt.Sprintf("%s-lifecycle", strings.Replace(lifecycle, "/", "-", 1)), }, } rootFSPath := models.PreloadedRootFS(task.RootFs) taskDefinition := &models.TaskDefinition{ Privileged: true, LogGuid: task.LogGuid, MemoryMb: int32(task.MemoryMb), DiskMb: int32(task.DiskMb), CpuWeight: cpuWeight(task.MemoryMb), EnvironmentVariables: task.EnvironmentVariables, RootFs: rootFSPath, CompletionCallbackUrl: task.CompletionCallbackUrl, Action: models.WrapAction(models.Serial( downloadAction, runAction, )), CachedDependencies: cachedDependencies, EgressRules: task.EgressRules, LegacyDownloadUser: "******", } return taskDefinition, nil }
}) It("returns an error", func() { _, _, _, err := traditional.BuildRecipe(stagingGuid, stagingRequest) Expect(err).To(Equal(backend.ErrMissingLifecycleData)) }) }) }) It("creates a cf-app-staging Task with staging instructions", func() { taskDef, guid, domain, err := traditional.BuildRecipe(stagingGuid, stagingRequest) Expect(err).NotTo(HaveOccurred()) Expect(domain).To(Equal("config-task-domain")) Expect(guid).To(Equal(stagingGuid)) Expect(taskDef.RootFs).To(Equal(models.PreloadedRootFS("rabbit_hole"))) Expect(taskDef.LogGuid).To(Equal("bunny")) Expect(taskDef.MetricsGuid).To(BeEmpty()) // do not emit metrics for staging! Expect(taskDef.LogSource).To(Equal(backend.TaskLogSource)) Expect(taskDef.ResultFile).To(Equal("/tmp/result.json")) Expect(taskDef.Privileged).To(BeTrue()) var annotation cc_messages.StagingTaskAnnotation err = json.Unmarshal([]byte(taskDef.Annotation), &annotation) Expect(err).NotTo(HaveOccurred()) Expect(annotation).To(Equal(cc_messages.StagingTaskAnnotation{ Lifecycle: "buildpack", CompletionCallback: "https://api.cc.com/v1/staging/some-staging-guid/droplet_completed", }))