func (factory *gardenContainerSpecFactory) BuildTaskContainerSpec(
	spec TaskContainerSpec,
	gardenSpec garden.ContainerSpec,
	cancel <-chan os.Signal,
	delegate ImageFetchingDelegate,
	id Identifier,
	metadata Metadata,
	workerClient Client,
) (garden.ContainerSpec, error) {
	if spec.ImageResourcePointer == nil {
		gardenSpec.RootFSPath = spec.Image
	}

	gardenSpec.Privileged = spec.Privileged

	var err error
	gardenSpec, err = factory.createVolumes(gardenSpec, spec.Inputs)
	if err != nil {
		return gardenSpec, err
	}

	for _, mount := range spec.Outputs {
		volume := mount.Volume
		gardenSpec.BindMounts = append(gardenSpec.BindMounts, garden.BindMount{
			SrcPath: volume.Path(),
			DstPath: mount.MountPath,
			Mode:    garden.BindMountModeRW,
		})

		factory.volumeHandles = append(factory.volumeHandles, volume.Handle())
		factory.volumeMounts[volume.Handle()] = mount.MountPath
	}

	return gardenSpec, nil
}
Beispiel #2
0
func (s *GardenServer) handleCreate(w http.ResponseWriter, r *http.Request) {
	var spec garden.ContainerSpec
	if !s.readRequest(&spec, w, r) {
		return
	}

	hLog := s.logger.Session("create", lager.Data{
		"request": spec,
	})

	if spec.GraceTime == 0 {
		spec.GraceTime = s.containerGraceTime
	}

	hLog.Debug("creating")

	container, err := s.backend.Create(spec)
	if err != nil {
		s.writeError(w, err, hLog)
		return
	}

	hLog.Info("created")

	s.bomberman.Strap(container)

	s.writeResponse(w, &struct{ Handle string }{
		Handle: container.Handle(),
	})
}
func (p *LinuxResourcePool) Acquire(spec garden.ContainerSpec) (linux_backend.LinuxContainerSpec, error) {
	id := <-p.containerIDs
	containerPath := path.Join(p.depotPath, id)
	pLog := p.logger.Session(id)

	pLog.Info("creating")

	resources, err := p.acquirePoolResources(spec, id)
	if err != nil {
		return linux_backend.LinuxContainerSpec{}, err
	}
	defer cleanup(&err, func() {
		p.releasePoolResources(resources)
	})

	pLog.Info("acquired-pool-resources")

	handle := getHandle(spec.Handle, id)

	var quota int64 = int64(spec.Limits.Disk.ByteHard)
	if quota == 0 {
		quota = math.MaxInt64
	}

	containerRootFSPath, rootFSEnv, err := p.acquireSystemResources(id, handle, containerPath, spec.RootFSPath, resources, spec.BindMounts, quota, pLog)
	if err != nil {
		return linux_backend.LinuxContainerSpec{}, err
	}

	pLog.Info("created")

	specEnv, err := process.NewEnv(spec.Env)
	if err != nil {
		p.tryReleaseSystemResources(p.logger, id)
		return linux_backend.LinuxContainerSpec{}, err
	}

	pLog.Debug("calculate-environment", lager.Data{
		"rootfs-env": rootFSEnv,
	})

	spec.Env = rootFSEnv.Merge(specEnv).Array()
	spec.Handle = handle

	return linux_backend.LinuxContainerSpec{
		ID:                  id,
		ContainerPath:       containerPath,
		ContainerRootFSPath: containerRootFSPath,
		Resources:           resources,
		Events:              []string{},
		Version:             p.currentContainerVersion,
		State:               linux_backend.StateBorn,

		ContainerSpec: spec,
	}, nil
}
func (factory *gardenContainerSpecFactory) BuildResourceContainerSpec(
	spec ResourceTypeContainerSpec,
	gardenSpec garden.ContainerSpec,
	resourceTypes []atc.WorkerResourceType,
) (garden.ContainerSpec, error) {
	if len(spec.Mounts) > 0 && spec.Cache.Volume != nil {
		return gardenSpec, errors.New("a container may not have mounts and a cache")
	}

	gardenSpec.Privileged = true
	gardenSpec.Env = append(gardenSpec.Env, spec.Env...)

	if spec.Ephemeral {
		gardenSpec.Properties[ephemeralPropertyName] = "true"
	}

	if spec.Cache.Volume != nil && spec.Cache.MountPath != "" {
		gardenSpec.BindMounts = []garden.BindMount{
			{
				SrcPath: spec.Cache.Volume.Path(),
				DstPath: spec.Cache.MountPath,
				Mode:    garden.BindMountModeRW,
			},
		}

		factory.volumeHandles = append(factory.volumeHandles, spec.Cache.Volume.Handle())
		factory.volumeMounts[spec.Cache.Volume.Handle()] = spec.Cache.MountPath
	}

	var err error
	gardenSpec, err = factory.createVolumes(gardenSpec, spec.Mounts)
	if err != nil {
		return gardenSpec, err
	}

	if spec.ImageResourcePointer == nil {
		for _, t := range resourceTypes {
			if t.Type == spec.Type {
				gardenSpec.RootFSPath = t.Image
				return gardenSpec, nil
			}
		}

		return gardenSpec, ErrUnsupportedResourceType
	}

	return gardenSpec, nil
}
func (factory *gardenContainerSpecFactory) createVolumes(containerSpec garden.ContainerSpec, mounts []VolumeMount) (garden.ContainerSpec, error) {
	for _, mount := range mounts {
		cowVolume, err := factory.baggageclaimClient.CreateVolume(factory.logger, baggageclaim.VolumeSpec{
			Strategy: baggageclaim.COWStrategy{
				Parent: mount.Volume,
			},
			Privileged: containerSpec.Privileged,
			TTL:        VolumeTTL,
		})
		if err != nil {
			return containerSpec, err
		}

		factory.releaseAfterCreate = append(factory.releaseAfterCreate, cowVolume)

		containerSpec.BindMounts = append(containerSpec.BindMounts, garden.BindMount{
			SrcPath: cowVolume.Path(),
			DstPath: mount.MountPath,
			Mode:    garden.BindMountModeRW,
		})

		factory.volumeHandles = append(factory.volumeHandles, cowVolume.Handle())
		factory.volumeMounts[cowVolume.Handle()] = mount.MountPath
	}

	return containerSpec, nil
}
Beispiel #6
0
func createContainer(containerSpec garden.ContainerSpec) garden.Container {
	handle, err := uuid.NewV4()
	Expect(err).ShouldNot(HaveOccurred())
	containerSpec.Handle = handle.String()
	container, err := client.Create(containerSpec)
	Expect(err).ShouldNot(HaveOccurred())
	err = StreamIn(container)
	Expect(err).ShouldNot(HaveOccurred())
	return container
}
func (s *GardenServer) handleCreate(w http.ResponseWriter, r *http.Request) {
	var spec garden.ContainerSpec
	if !s.readRequest(&spec, w, r) {
		return
	}

	hLog := s.logger.Session("create", lager.Data{
		"request": containerDebugInfo{
			Handle:     spec.Handle,
			GraceTime:  spec.GraceTime,
			RootFSPath: spec.RootFSPath,
			BindMounts: spec.BindMounts,
			Network:    spec.Network,
			Privileged: spec.Privileged,
			Limits:     spec.Limits,
		},
	})

	if spec.GraceTime == 0 {
		spec.GraceTime = s.containerGraceTime
	}

	hLog.Debug("creating")

	container, err := s.backend.Create(spec)
	if err != nil {
		s.writeError(w, err, hLog)
		return
	}

	hLog.Info("created")

	s.bomberman.Strap(container)

	s.writeResponse(w, &struct{ Handle string }{
		Handle: container.Handle(),
	})
}
Beispiel #8
0
func (worker *gardenWorker) CreateContainer(id Identifier, spec ContainerSpec) (Container, error) {
	gardenSpec := garden.ContainerSpec{
		Properties: id.gardenProperties(),
	}

dance:
	switch s := spec.(type) {
	case ResourceTypeContainerSpec:
		gardenSpec.Privileged = true

		if s.Ephemeral {
			gardenSpec.Properties[ephemeralPropertyName] = "true"
		}

		for _, t := range worker.resourceTypes {
			if t.Type == s.Type {
				gardenSpec.RootFSPath = t.Image
				break dance
			}
		}

		return nil, ErrUnsupportedResourceType

	case TaskContainerSpec:
		gardenSpec.RootFSPath = s.Image
		gardenSpec.Privileged = s.Privileged

	default:
		return nil, fmt.Errorf("unknown container spec type: %T (%#v)", s, s)
	}

	gardenContainer, err := worker.gardenClient.Create(gardenSpec)
	if err != nil {
		return nil, err
	}

	return newGardenWorkerContainer(gardenContainer, worker.gardenClient, worker.clock), nil
}
Beispiel #9
0
func (g *Gardener) Create(spec garden.ContainerSpec) (garden.Container, error) {
	log := g.Logger.Session("create")

	if spec.Handle == "" {
		spec.Handle = g.UidGenerator.Generate()
	}

	networkPath, err := g.Networker.Network(log, spec.Handle, spec.Network)
	if err != nil {
		return nil, err
	}

	rootFSURL, err := url.Parse(spec.RootFSPath)
	if err != nil {
		g.Networker.Destroy(g.Logger, spec.Handle)
		return nil, err
	}

	rootFSPath, _, err := g.VolumeCreator.Create(spec.Handle, rootfs_provider.Spec{RootFS: rootFSURL})
	if err != nil {
		g.Networker.Destroy(g.Logger, spec.Handle)
		return nil, err
	}

	if err := g.Containerizer.Create(log, DesiredContainerSpec{
		Handle:      spec.Handle,
		RootFSPath:  rootFSPath,
		NetworkPath: networkPath,
	}); err != nil {
		g.Networker.Destroy(g.Logger, spec.Handle)
		return nil, err
	}

	container, err := g.Lookup(spec.Handle)
	if err != nil {
		return nil, err
	}

	for name, value := range spec.Properties {
		err := container.SetProperty(name, value)
		if err != nil {
			return nil, err
		}
	}

	return container, nil
}
Beispiel #10
0
func (g *Gardener) Create(spec garden.ContainerSpec) (garden.Container, error) {
	if spec.Handle == "" {
		spec.Handle = g.UidGenerator.Generate()
	}

	networkPath, err := g.Networker.Network(spec.Network)
	if err != nil {
		return nil, err
	}

	if err := g.Containerizer.Create(DesiredContainerSpec{
		Handle:      spec.Handle,
		NetworkPath: networkPath,
	}); err != nil {
		return nil, err
	}

	return g.Lookup(spec.Handle)
}
Beispiel #11
0
func (backend *Backend) Create(spec garden.ContainerSpec) (garden.Container, error) {
	backend.containersL.Lock()
	defer backend.containersL.Unlock()

	capacity, err := backend.Capacity()
	if err != nil {
		return nil, err
	}

	activeContainers := 0
	for _, container := range backend.containers {
		if _, ok := container.currentProperties()["concourse:exit-status"]; !ok {
			activeContainers++
		}
	}

	if activeContainers >= int(capacity.MaxContainers) {
		return nil, atc.WorkerNotCreatedError{errors.New("worker already has the maximum number of active containers")}
	}

	id := backend.generateContainerID()

	if spec.Handle == "" {
		spec.Handle = id
	}

	dir := filepath.Join(backend.containersDir, id)

	err = os.MkdirAll(dir, 0755)
	if err != nil {
		return nil, err
	}

	container := newContainer(spec, dir)
	backend.containers[spec.Handle] = container

	return container, nil
}
Beispiel #12
0
func (p *LinuxResourcePool) Acquire(spec garden.ContainerSpec) (linux_backend.LinuxContainerSpec, error) {
	id := <-p.containerIDs
	containerPath := path.Join(p.depotPath, id)
	handle := getHandle(spec.Handle, id)
	pLog := p.logger.Session("acquire", lager.Data{"handle": handle})

	iptablesCh := make(chan error, 1)

	go func(iptablesCh chan error) {
		pLog.Debug("setup-iptables-starting")
		if err := p.filterProvider.ProvideFilter(id).Setup(handle); err != nil {
			pLog.Error("setup-iptables-failed", err)
			iptablesCh <- fmt.Errorf("resource_pool: set up filter: %v", err)
		} else {
			pLog.Debug("setup-iptables-ended")
			iptablesCh <- nil
		}
	}(iptablesCh)

	pLog.Info("creating")

	resources, err := p.acquirePoolResources(spec, id, pLog)
	if err != nil {
		return linux_backend.LinuxContainerSpec{}, err
	}
	defer cleanup(&err, func() {
		p.releasePoolResources(resources, pLog)
	})

	pLog.Info("acquired-pool-resources")

	pLog.Info("running-graph-cleanup")
	if err := p.rootFSProvider.GC(pLog); err != nil {
		pLog.Error("graph-cleanup-failed", err)
	}

	containerRootFSPath, rootFSEnv, err := p.acquireSystemResources(
		spec, id, resources, pLog,
	)
	if err != nil {
		return linux_backend.LinuxContainerSpec{}, err
	}

	err = <-iptablesCh
	if err != nil {
		p.tryReleaseSystemResources(p.logger, id)
		return linux_backend.LinuxContainerSpec{}, err
	}

	pLog.Info("created")

	specEnv, err := process.NewEnv(spec.Env)
	if err != nil {
		p.tryReleaseSystemResources(p.logger, id)
		return linux_backend.LinuxContainerSpec{}, err
	}

	spec.Env = rootFSEnv.Merge(specEnv).Array()
	spec.Handle = handle

	return linux_backend.LinuxContainerSpec{
		ID:                  id,
		ContainerPath:       containerPath,
		ContainerRootFSPath: containerRootFSPath,
		Resources:           resources,
		Events:              []string{},
		Version:             p.currentContainerVersion,
		State:               linux_backend.StateBorn,

		ContainerSpec: spec,
	}, nil
}
Beispiel #13
0
func (c *RuncContainerCreator) Create(spec garden.ContainerSpec) (*Container, error) {
	dir, err := c.Depot.Create()
	if err != nil {
		return nil, fmt.Errorf("create depot dir: %s", err)
	}

	if len(spec.RootFSPath) == 0 {
		spec.RootFSPath = c.DefaultRootfs
	}

	rootfs, err := url.Parse(spec.RootFSPath)
	if err != nil {
		return nil, fmt.Errorf("create: not a valid rootfs path: %s", err)
	}

	if _, err := exec.Command("cp", "-r", rootfs.Path, path.Join(dir, "rootfs")).CombinedOutput(); err != nil {
		return nil, fmt.Errorf("create: copy rootfs: %s", err)
	}

	runcSpec := runc.PortableSpec{
		Version: "0.1",
		OS:      runtime.GOOS,
		Arch:    runtime.GOARCH,
		Cpus:    1.1,
		Memory:  1024,
		Root: runc.Root{
			Path:     "rootfs",
			Readonly: false,
		},
		Namespaces: []runc.Namespace{
			{
				Type: "process",
			},
			{
				Type: "network",
			},
			{
				Type: "mount",
			},
			{
				Type: "ipc",
			},
			{
				Type: "uts",
			},
		},
		Devices: []string{
			"null",
			"random",
			"full",
			"tty",
			"zero",
			"urandom",
		},
		Mounts: []runc.Mount{
			{
				Type:        "proc",
				Source:      "proc",
				Destination: "/proc",
				Options:     "",
			},
			{
				Type:        "tmpfs",
				Source:      "tmpfs",
				Destination: "/dev",
				Options:     "nosuid,strictatime,mode=755,size=65536k",
			},
			{
				Type:        "devpts",
				Source:      "devpts",
				Destination: "/dev/pts",
				Options:     "nosuid,noexec,newinstance,ptmxmode=0666,mode=0620,gid=5",
			},
			{
				Type:        "tmpfs",
				Source:      "shm",
				Destination: "/dev/shm",
				Options:     "nosuid,noexec,nodev,mode=1777,size=65536k",
			},
			{
				Type:        "mqueue",
				Source:      "mqueue",
				Destination: "/dev/mqueue",
				Options:     "nosuid,noexec,nodev",
			},
			{
				Type:        "sysfs",
				Source:      "sysfs",
				Destination: "/sys",
				Options:     "nosuid,noexec,nodev",
			},
			{
				Type:        "bind",
				Source:      c.InitdPath,
				Destination: "/garden-bin/initd",
				Options:     "bind",
			}, {
				Type:        "bind",
				Source:      path.Join(dir, "run"),
				Destination: "/run/garden",
				Options:     "bind",
			}},
		Processes: []*runc.Process{{
			// User: "******",
			// Args: []string{
			// 	"/bin/ls", "-lR", "/garden-bin",
			// },
			// }},
			User: "******",
			Args: []string{
				"/garden-bin/initd",
				"-socket", "/run/garden/initd.sock",
				"-unmountAfterListening", "/run/garden",
			},
		}},
	}

	data, err := json.MarshalIndent(&runcSpec, "", "\t")
	if err != nil {
		return nil, fmt.Errorf("create: marshal runc spec: %s", err)
	}

	err = ioutil.WriteFile(path.Join(dir, "container.json"), data, 0700)
	if err != nil {
		return nil, fmt.Errorf("create: write runc spec: %s", err)
	}

	os.Setenv("CGO_ENABLED", "1")
	runcBin, err := gexec.Build("github.com/opencontainers/runc")
	if err != nil {
		return nil, fmt.Errorf("create: build runc: %s", err)
	}

	runcCommand := exec.Command(runcBin)
	runcCommand.Dir = dir
	if err := c.CommandRunner.Start(runcCommand); err != nil {
		return nil, fmt.Errorf("create: start runc container: %s", err)
	}

	time.Sleep(2 * time.Second)

	return &Container{
		LimitsHandler: &LimitsHandler{},
		StreamHandler: &StreamHandler{},
		InfoHandler: &InfoHandler{
			Spec:          spec,
			ContainerPath: dir,
			PropsHandler:  &PropsHandler{},
		},
		NetHandler: &NetHandler{
			Chain:    c.Chain,
			PortPool: c.PortPool,
		},
		RunHandler: &RunHandler{
			ProcessTracker: process_tracker.New(dir, c.CommandRunner),
			ContainerCmd: &doshcmd{
				Path:      filepath.Join(dir, "bin", "dosh"),
				InitdSock: filepath.Join(dir, "run", "initd.sock"),
			},
		},
	}, nil
}
Beispiel #14
0
			volumizer.VolumizeReturns("the-volumized-rootfs-path", nil)

			containerizer.CreateStub = func(spec gardener.DesiredContainerSpec) error {
				return nil
			}

			gdnr = &gardener.Gardener{
				Networker:     networker,
				Volumizer:     volumizer,
				Containerizer: containerizer,
			}
		})

		Describe("creating a container", func() {
			var (
				createdContainer garden.Container
				spec             garden.ContainerSpec
			)

			BeforeEach(func() {
				spec = garden.ContainerSpec{}
			})

			JustBeforeEach(func() {
				var err error
				createdContainer, err = gdnr.Create(spec)

				Expect(err).NotTo(HaveOccurred())
			})

			It("passes the rootfs provided by the volumizer to the containerizer", func() {
				Expect(containerizer.CreateArgsForCall(0).RootFSPath).To(Equal("the-volumized-rootfs-path"))
Beispiel #15
0
package lifecycle_test

import (
	"github.com/cloudfoundry-incubator/garden"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gbytes"
)

var _ = Describe("Logging", func() {
	var container garden.Container
	var containerSpec garden.ContainerSpec

	BeforeEach(func() {
		containerSpec = garden.ContainerSpec{}
	})

	JustBeforeEach(func() {
		var err error
		client = startGarden()
		container, err = client.Create(containerSpec)
		Expect(err).ToNot(HaveOccurred())
	})

	Context("when container is created", func() {
		BeforeEach(func() {
			containerSpec = garden.ContainerSpec{
				Handle: "kumquat",
				Env:    []string{"PASSWORD=MY_SECRET"},
				Properties: garden.Properties{
Beispiel #16
0
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
}