func (h *DesireAppHandler) updateDesiredApp( logger lager.Logger, existingLRP *models.DesiredLRP, desireAppMessage cc_messages.DesireAppRequestFromCC, ) error { var builder recipebuilder.RecipeBuilder = h.recipeBuilders["buildpack"] if desireAppMessage.DockerImageUrl != "" { builder = h.recipeBuilders["docker"] } ports, err := builder.ExtractExposedPorts(&desireAppMessage) if err != nil { logger.Error("failed to-get-exposed-port", err) return err } updateRoutes, err := helpers.CCRouteInfoToRoutes(desireAppMessage.RoutingInfo, ports) if err != nil { logger.Error("failed-to-marshal-routes", err) return err } routes := existingLRP.Routes if routes == nil { routes = &models.Routes{} } if value, ok := updateRoutes[cfroutes.CF_ROUTER]; ok { (*routes)[cfroutes.CF_ROUTER] = value } if value, ok := updateRoutes[tcp_routes.TCP_ROUTER]; ok { (*routes)[tcp_routes.TCP_ROUTER] = value } instances := int32(desireAppMessage.NumInstances) updateRequest := &models.DesiredLRPUpdate{ Annotation: &desireAppMessage.ETag, Instances: &instances, Routes: routes, } logger.Debug("updating-desired-lrp", lager.Data{"routes": sanitizeRoutes(existingLRP.Routes)}) err = h.bbsClient.UpdateDesiredLRP(desireAppMessage.ProcessGuid, updateRequest) if err != nil { logger.Error("failed-to-update-lrp", err) return err } logger.Debug("updated-desired-lrp") return nil }
. "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) var _ = Describe("Routing Helpers", func() { Describe("CCRouteInfo To Routes", func() { Context("when there are only http routes", func() { It("can convert itself into a Routes structure", func() { routeInfo, err := cc_messages.CCHTTPRoutes{ {Hostname: "route1"}, {Hostname: "route2", RouteServiceUrl: "https://rs.example.com"}, {Hostname: "route3", Port: 8080}, }.CCRouteInfo() Expect(err).NotTo(HaveOccurred()) routes, err := helpers.CCRouteInfoToRoutes(routeInfo, []uint32{8080}) Expect(err).NotTo(HaveOccurred()) expectedCfRoutes := cfroutes.CFRoutes{ {Hostnames: []string{"route1", "route3"}, Port: 8080}, {Hostnames: []string{"route2"}, Port: 8080, RouteServiceUrl: "https://rs.example.com"}, } test_helpers.VerifyHttpRoutes(routes, expectedCfRoutes) Expect(routes).To(HaveLen(1)) }) }) Context("when there are only tcp routes", func() { It("can convert itself into a Routes structure", func() { routeInfo, err := cc_messages.CCTCPRoutes{
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 (p *Processor) updateStaleDesiredLRPs( logger lager.Logger, cancel <-chan struct{}, stale <-chan []cc_messages.DesireAppRequestFromCC, existingSchedulingInfoMap map[string]*models.DesiredLRPSchedulingInfo, invalidCount *int32, ) <-chan error { logger = logger.Session("update-stale-desired-lrps") errc := make(chan error, 1) go func() { defer close(errc) for { var staleAppRequests []cc_messages.DesireAppRequestFromCC select { case <-cancel: return case selected, open := <-stale: if !open { return } staleAppRequests = selected } works := make([]func(), len(staleAppRequests)) for i, desireAppRequest := range staleAppRequests { desireAppRequest := desireAppRequest var builder recipebuilder.RecipeBuilder = p.builders["buildpack"] if desireAppRequest.DockerImageUrl != "" { builder = p.builders["docker"] } works[i] = func() { processGuid := desireAppRequest.ProcessGuid existingSchedulingInfo := existingSchedulingInfoMap[desireAppRequest.ProcessGuid] updateReq := &models.DesiredLRPUpdate{} instances := int32(desireAppRequest.NumInstances) updateReq.Instances = &instances updateReq.Annotation = &desireAppRequest.ETag exposedPorts, err := builder.ExtractExposedPorts(&desireAppRequest) if err != nil { logger.Error("failed-updating-stale-lrp", err, lager.Data{ "process-guid": processGuid, "execution-metadata": desireAppRequest.ExecutionMetadata, }) errc <- err return } routes, err := helpers.CCRouteInfoToRoutes(desireAppRequest.RoutingInfo, exposedPorts) if err != nil { logger.Error("failed-to-marshal-routes", err) errc <- err return } updateReq.Routes = &routes for k, v := range existingSchedulingInfo.Routes { if k != cfroutes.CF_ROUTER { (*updateReq.Routes)[k] = v } } logger.Debug("updating-stale-lrp", updateDesiredRequestDebugData(processGuid, updateReq)) err = p.bbsClient.UpdateDesiredLRP(processGuid, updateReq) if err != nil { logger.Error("failed-updating-stale-lrp", err, lager.Data{ "process-guid": processGuid, }) if models.ConvertError(err).Type == models.Error_InvalidRequest { atomic.AddInt32(invalidCount, int32(1)) } else { errc <- err } return } logger.Debug("succeeded-updating-stale-lrp", updateDesiredRequestDebugData(processGuid, updateReq)) } } throttler, err := workpool.NewThrottler(p.updateLRPWorkPoolSize, works) if err != nil { errc <- err return } logger.Info("processing-batch", lager.Data{"size": len(staleAppRequests)}) throttler.Work() logger.Info("done-processing-batch", lager.Data{"size": len(staleAppRequests)}) } }() return errc }