}) }) Context("when there are no exposed ports", func() { BeforeEach(func() { container.Ports = nil }) It("does not return an error", func() { Expect(netInfoConversionErr).NotTo(HaveOccurred()) }) }) Context("when the executor host is invalid", func() { BeforeEach(func() { container.ExternalIP = "" }) It("returns an invalid host error", func() { Expect(netInfoConversionErr.Error()).To(ContainSubstring("address")) }) }) }) Describe("StackPathMap", func() { It("deserializes a valid input", func() { stackMapPayload := []byte(`{ "pancakes": "/path/to/lingonberries", "waffles": "/where/is/the/syrup" }`)
It("deletes the container", func() { Expect(fakeContainerDelegate.DeleteContainerCallCount()).To(Equal(1)) _, actualContainerGuid := fakeContainerDelegate.DeleteContainerArgsForCall(0) Expect(actualContainerGuid).To(Equal(container.Guid)) }) }) }) Context("when the container is Running", func() { var lrpNetInfo models.ActualLRPNetInfo BeforeEach(func() { container.State = executor.StateRunning externalIP := "executor-ip" container.ExternalIP = externalIP container.Ports = []executor.PortMapping{{ContainerPort: 1357, HostPort: 8642}} lrpNetInfo = models.NewActualLRPNetInfo(externalIP, models.NewPortMapping(8642, 1357)) }) It("evacuates the lrp", func() { Expect(fakeBBS.EvacuateRunningActualLRPCallCount()).To(Equal(1)) actualLRPKey, actualLRPContainerKey, actualLRPNetInfo, actualTTL := fakeBBS.EvacuateRunningActualLRPArgsForCall(0) Expect(*actualLRPKey).To(Equal(lrpKey)) Expect(*actualLRPContainerKey).To(Equal(lrpInstanceKey)) Expect(*actualLRPNetInfo).To(Equal(lrpNetInfo)) Expect(actualTTL).To(Equal(uint64(evacuationTTL))) }) Context("when the evacuation returns successfully", func() { BeforeEach(func() {
itClaimsTheLRPOrDeletesTheContainer(sessionPrefix + "process-initializing-container") }) Context("and the container is CREATED", func() { BeforeEach(func() { container.State = executor.StateCreated }) itClaimsTheLRPOrDeletesTheContainer(sessionPrefix + "process-created-container") }) Context("and the container is RUNNING", func() { BeforeEach(func() { expectedSessionName = sessionPrefix + "process-running-container" container.State = executor.StateRunning container.ExternalIP = "1.2.3.4" container.Ports = []executor.PortMapping{{ContainerPort: 8080, HostPort: 61999}} }) It("starts the lrp", func() { Expect(bbsClient.StartActualLRPCallCount()).To(Equal(1)) lrpKey, instanceKey, netInfo := bbsClient.StartActualLRPArgsForCall(0) Expect(*lrpKey).To(Equal(expectedLrpKey)) Expect(*instanceKey).To(Equal(expectedInstanceKey)) Expect(*netInfo).To(Equal(expectedNetInfo)) }) Context("when starting fails because ErrActualLRPCannotBeStarted", func() { BeforeEach(func() { bbsClient.StartActualLRPReturns(models.ErrActualLRPCannotBeStarted) })
func (exchanger exchanger) CreateInGarden(logger lager.Logger, gardenClient GardenClient, executorContainer executor.Container) (executor.Container, error) { logger = logger.Session("create-in-garden", lager.Data{"container-guid": executorContainer.Guid}) containerSpec := garden.ContainerSpec{ Handle: executorContainer.Guid, Privileged: executorContainer.Privileged, RootFSPath: executorContainer.RootFSPath, } if executorContainer.MemoryMB != 0 { logger.Debug("setting-up-memory-limits") containerSpec.Limits.Memory.LimitInBytes = uint64(executorContainer.MemoryMB * 1024 * 1024) } logger.Debug("setting-up-disk-limits") gardenScope := garden.DiskLimitScopeExclusive if executorContainer.DiskScope == executor.TotalDiskLimit { gardenScope = garden.DiskLimitScopeTotal } containerSpec.Limits.Disk = garden.DiskLimits{ ByteHard: uint64(executorContainer.DiskMB * 1024 * 1024), InodeHard: exchanger.containerInodeLimit, Scope: gardenScope, } logger.Debug("setting-up-cpu-limits") containerSpec.Limits.CPU.LimitInShares = uint64(float64(exchanger.containerMaxCPUShares) * float64(executorContainer.CPUWeight) / 100.0) logJson, err := json.Marshal(executorContainer.LogConfig) if err != nil { logger.Error("failed-marshal-log", err) return executor.Container{}, err } metricsConfigJson, err := json.Marshal(executorContainer.MetricsConfig) if err != nil { logger.Error("failed-marshal-metrics-config", err) return executor.Container{}, err } resultJson, err := json.Marshal(executorContainer.RunResult) if err != nil { logger.Error("failed-marshal-run-result", err) return executor.Container{}, err } containerSpec.Properties = garden.Properties{ ContainerOwnerProperty: exchanger.containerOwnerName, ContainerStateProperty: string(executorContainer.State), ContainerAllocatedAtProperty: fmt.Sprintf("%d", executorContainer.AllocatedAt), ContainerStartTimeoutProperty: fmt.Sprintf("%d", executorContainer.StartTimeout), ContainerRootfsProperty: executorContainer.RootFSPath, ContainerLogProperty: string(logJson), ContainerMetricsConfigProperty: string(metricsConfigJson), ContainerResultProperty: string(resultJson), ContainerMemoryMBProperty: fmt.Sprintf("%d", executorContainer.MemoryMB), ContainerDiskMBProperty: fmt.Sprintf("%d", executorContainer.DiskMB), ContainerCPUWeightProperty: fmt.Sprintf("%d", executorContainer.CPUWeight), } for name, value := range executorContainer.Tags { containerSpec.Properties[TagPropertyPrefix+name] = value } for _, env := range executorContainer.Env { containerSpec.Env = append(containerSpec.Env, env.Name+"="+env.Value) } for _, securityRule := range executorContainer.EgressRules { if err := securityRule.Validate(); err != nil { logger.Error("invalid-security-rule", err, lager.Data{"security_group_rule": securityRule}) return executor.Container{}, executor.ErrInvalidSecurityGroup } } logger.Debug("creating-garden-container") gardenContainer, err := gardenClient.Create(containerSpec) if err != nil { logger.Error("failed-creating-garden-container", err) return executor.Container{}, err } logger.Debug("succeeded-creating-garden-container") if executorContainer.Ports != nil { actualPortMappings := make([]executor.PortMapping, len(executorContainer.Ports)) logger.Debug("setting-up-ports") for i, ports := range executorContainer.Ports { actualHostPort, actualContainerPort, err := gardenContainer.NetIn(uint32(ports.HostPort), uint32(ports.ContainerPort)) if err != nil { logger.Error("failed-setting-up-ports", err) exchanger.destroyContainer(logger, gardenClient, gardenContainer) return executor.Container{}, err } actualPortMappings[i].ContainerPort = uint16(actualContainerPort) actualPortMappings[i].HostPort = uint16(actualHostPort) } logger.Debug("succeeded-setting-up-ports") executorContainer.Ports = actualPortMappings } for _, securityRule := range executorContainer.EgressRules { netOutRule, err := securityGroupRuleToNetOutRule(securityRule) if err != nil { logger.Error("failed-to-build-net-out-rule", err, lager.Data{"security_group_rule": securityRule}) return executor.Container{}, err } logger.Debug("setting-up-net-out") err = gardenContainer.NetOut(netOutRule) if err != nil { logger.Error("failed-setting-up-net-out", err, lager.Data{"net-out-rule": netOutRule}) exchanger.destroyContainer(logger, gardenClient, gardenContainer) return executor.Container{}, err } logger.Debug("succeeded-setting-up-net-out") } logger.Debug("getting-garden-container-info") info, err := gardenContainer.Info() if err != nil { logger.Error("failed-getting-garden-container-info", err) gardenErr := gardenClient.Destroy(gardenContainer.Handle()) if gardenErr != nil { logger.Error("failed-destroy-garden-container", gardenErr) } return executor.Container{}, err } logger.Debug("succeeded-getting-garden-container-info") executorContainer.ExternalIP = info.ExternalIP return executorContainer, nil }