Esempio n. 1
0
import (
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/opencontainers/runtime-spec/specs-go"

	"code.cloudfoundry.org/garden"
	"code.cloudfoundry.org/guardian/gardener"
	"code.cloudfoundry.org/guardian/rundmc/bundlerules"
	"code.cloudfoundry.org/guardian/rundmc/goci"
)

var _ = Describe("BindMountsRule", func() {
	var newBndl goci.Bndl

	BeforeEach(func() {
		newBndl = bundlerules.BindMounts{}.Apply(goci.Bundle(), gardener.DesiredContainerSpec{
			BindMounts: []garden.BindMount{
				{
					SrcPath: "/path/to/ro/src",
					DstPath: "/path/to/ro/dest",
					Mode:    garden.BindMountModeRO,
				},
				{
					SrcPath: "/path/to/rw/src",
					DstPath: "/path/to/rw/dest",
					Mode:    garden.BindMountModeRW,
				},
			},
		})
	})
Esempio n. 2
0
package goci_test

import (
	"code.cloudfoundry.org/guardian/rundmc/goci"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/opencontainers/runtime-spec/specs-go"
)

var _ = Describe("Bundle", func() {
	var initialBundle goci.Bndl
	var returnedBundle goci.Bndl

	BeforeEach(func() {
		initialBundle = goci.Bundle()
	})

	It("specifies the correct version", func() {
		Expect(initialBundle.Spec.Version).To(Equal("0.2.0"))
	})

	Describe("WithHostname", func() {
		It("sets the Hostname in the bundle", func() {
			returnedBundle := initialBundle.WithHostname("hostname")
			Expect(returnedBundle.Hostname()).To(Equal("hostname"))
		})
	})

	Describe("WithCapabilities", func() {
		It("adds capabilities to the bundle", func() {
			returnedBundle := initialBundle.WithCapabilities("growtulips", "waterspuds")
		Context("when removing bundle from depot fails", func() {
			BeforeEach(func() {
				fakeDepot.DestroyReturns(errors.New("destroy failed"))
			})

			It("returns an error", func() {
				Expect(containerizer.RemoveBundle(logger, "some-handle")).To(MatchError(ContainSubstring("destroy failed")))
			})
		})
	})

	Describe("Info", func() {
		BeforeEach(func() {
			fakeBundleLoader.LoadStub = func(bundlePath string) (goci.Bndl, error) {
				if bundlePath != "/path/to/some-handle" {
					return goci.Bundle(), errors.New("cannot find bundle")
				}

				var limit uint64 = 10
				var shares uint64 = 20
				return goci.Bndl{
					Spec: specs.Spec{
						Linux: &specs.Linux{
							Resources: &specs.LinuxResources{
								Memory: &specs.LinuxMemory{
									Limit: &limit,
								},
								CPU: &specs.LinuxCPU{
									Shares: &shares,
								},
							},
Esempio n. 4
0
func (cmd *GuardianCommand) wireContainerizer(log lager.Logger, depotPath, dadooPath, runcPath, nstarPath, tarPath, defaultRootFSPath, appArmorProfile string, properties gardener.PropertyManager) *rundmc.Containerizer {
	depot := depot.New(depotPath)

	commandRunner := linux_command_runner.New()
	chrootMkdir := bundlerules.ChrootMkdir{
		Command:       preparerootfs.Command,
		CommandRunner: commandRunner,
	}

	pidFileReader := &dadoo.PidFileReader{
		Clock:         clock.NewClock(),
		Timeout:       10 * time.Second,
		SleepInterval: time.Millisecond * 100,
	}

	runcrunner := runrunc.New(
		commandRunner,
		runrunc.NewLogRunner(commandRunner, runrunc.LogDir(os.TempDir()).GenerateLogFile),
		goci.RuncBinary(runcPath),
		dadooPath,
		runcPath,
		runrunc.NewExecPreparer(&goci.BndlLoader{}, runrunc.LookupFunc(runrunc.LookupUser), chrootMkdir, NonRootMaxCaps),
		dadoo.NewExecRunner(
			dadooPath,
			runcPath,
			cmd.wireUidGenerator(),
			pidFileReader,
			linux_command_runner.New()),
	)

	mounts := []specs.Mount{
		{Type: "sysfs", Source: "sysfs", Destination: "/sys", Options: []string{"nosuid", "noexec", "nodev", "ro"}},
		{Type: "tmpfs", Source: "tmpfs", Destination: "/dev/shm"},
		{Type: "devpts", Source: "devpts", Destination: "/dev/pts",
			Options: []string{"nosuid", "noexec", "newinstance", "ptmxmode=0666", "mode=0620"}},
		{Type: "bind", Source: cmd.Bin.Init.Path(), Destination: "/tmp/garden-init", Options: []string{"bind"}},
	}

	privilegedMounts := append(mounts,
		specs.Mount{Type: "proc", Source: "proc", Destination: "/proc", Options: []string{"nosuid", "noexec", "nodev"}},
	)

	unprivilegedMounts := append(mounts,
		specs.Mount{Type: "proc", Source: "proc", Destination: "/proc", Options: []string{"nosuid", "noexec", "nodev"}},
	)

	rwm := "rwm"
	character := "c"
	var majorMinor = func(i int64) *int64 {
		return &i
	}

	var worldReadWrite os.FileMode = 0666
	fuseDevice := specs.LinuxDevice{
		Path:     "/dev/fuse",
		Type:     "c",
		Major:    10,
		Minor:    229,
		FileMode: &worldReadWrite,
	}

	denyAll := specs.LinuxDeviceCgroup{Allow: false, Access: &rwm}
	allowedDevices := []specs.LinuxDeviceCgroup{
		{Access: &rwm, Type: &character, Major: majorMinor(1), Minor: majorMinor(3), Allow: true},
		{Access: &rwm, Type: &character, Major: majorMinor(5), Minor: majorMinor(0), Allow: true},
		{Access: &rwm, Type: &character, Major: majorMinor(1), Minor: majorMinor(8), Allow: true},
		{Access: &rwm, Type: &character, Major: majorMinor(1), Minor: majorMinor(9), Allow: true},
		{Access: &rwm, Type: &character, Major: majorMinor(1), Minor: majorMinor(5), Allow: true},
		{Access: &rwm, Type: &character, Major: majorMinor(1), Minor: majorMinor(7), Allow: true},
		{Access: &rwm, Type: &character, Major: majorMinor(1), Minor: majorMinor(7), Allow: true},
		{Access: &rwm, Type: &character, Major: majorMinor(fuseDevice.Major), Minor: majorMinor(fuseDevice.Minor), Allow: true},
	}

	baseProcess := specs.Process{
		Capabilities: UnprivilegedMaxCaps,
		Args:         []string{"/tmp/garden-init"},
		Cwd:          "/",
	}

	baseBundle := goci.Bundle().
		WithNamespaces(PrivilegedContainerNamespaces...).
		WithResources(&specs.LinuxResources{Devices: append([]specs.LinuxDeviceCgroup{denyAll}, allowedDevices...)}).
		WithRootFS(defaultRootFSPath).
		WithDevices(fuseDevice).
		WithProcess(baseProcess)

	unprivilegedBundle := baseBundle.
		WithNamespace(goci.UserNamespace).
		WithUIDMappings(idMappings...).
		WithGIDMappings(idMappings...).
		WithMounts(unprivilegedMounts...).
		WithMaskedPaths(defaultMaskedPaths())

	unprivilegedBundle.Spec.Linux.Seccomp = seccomp
	if appArmorProfile != "" {
		unprivilegedBundle.Spec.Process.ApparmorProfile = appArmorProfile
	}

	privilegedBundle := baseBundle.
		WithMounts(privilegedMounts...).
		WithCapabilities(PrivilegedMaxCaps...)

	template := &rundmc.BundleTemplate{
		Rules: []rundmc.BundlerRule{
			bundlerules.Base{
				PrivilegedBase:   privilegedBundle,
				UnprivilegedBase: unprivilegedBundle,
			},
			bundlerules.RootFS{
				ContainerRootUID: idMappings.Map(0),
				ContainerRootGID: idMappings.Map(0),
				MkdirChown:       chrootMkdir,
			},
			bundlerules.Limits{},
			bundlerules.BindMounts{},
			bundlerules.Env{},
			bundlerules.Hostname{},
		},
	}

	log.Info("base-bundles", lager.Data{
		"privileged":   privilegedBundle,
		"unprivileged": unprivilegedBundle,
	})

	eventStore := rundmc.NewEventStore(properties)
	stateStore := rundmc.NewStateStore(properties)

	nstar := rundmc.NewNstarRunner(nstarPath, tarPath, linux_command_runner.New())
	stopper := stopper.New(stopper.NewRuncStateCgroupPathResolver("/run/runc"), nil, retrier.New(retrier.ConstantBackoff(10, 1*time.Second), nil))
	return rundmc.New(depot, template, runcrunner, &goci.BndlLoader{}, nstar, stopper, eventStore, stateStore)
}
Esempio n. 5
0
				Command: func(rootfsPath string, uid, gid int, mode os.FileMode, recreate bool, paths ...string) *exec.Cmd {
					return exec.Command("reexeced-thing", append(
						[]string{
							"-rootfsPath", rootfsPath,
							"-uid", strconv.Itoa(uid),
							"-gid", strconv.Itoa(gid),
							"-recreate", fmt.Sprintf("%t", recreate),
							"-perm", strconv.FormatUint(uint64(mode.Perm()), 8),
						}, paths...)...)
				},

				CommandRunner: commandRunner,
			},
		}

		returnedBundle = rule.Apply(goci.Bundle(), gardener.DesiredContainerSpec{
			RootFSPath: rootfsPath,
			Privileged: privileged,
		})
	})

	AfterEach(func() {
		Expect(os.RemoveAll(rootfsPath)).To(Succeed())
	})

	It("applies the rootfs to the passed bundle", func() {
		Expect(returnedBundle.Spec.Root.Path).To(Equal(rootfsPath))
	})

	Describe("creating needed directories", func() {
		Context("when the container is privileged", func() {
Esempio n. 6
0
package bundlerules_test

import (
	"strings"

	"code.cloudfoundry.org/guardian/gardener"
	"code.cloudfoundry.org/guardian/rundmc/bundlerules"
	"code.cloudfoundry.org/guardian/rundmc/goci"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Hostname", func() {
	It("sets the correct hostname in the bundle", func() {
		newBndl := bundlerules.Hostname{}.Apply(goci.Bundle(), gardener.DesiredContainerSpec{
			Hostname: "banana",
		})

		Expect(newBndl.Hostname()).To(Equal("banana"))
	})

	Context("when the hostname is longer than 49 characters", func() {
		It("should use the last 49 characters of it", func() {
			newBndl := bundlerules.Hostname{}.Apply(goci.Bundle(), gardener.DesiredContainerSpec{
				Hostname: strings.Repeat("banana", 9),
			})

			Expect(newBndl.Hostname()).To(Equal("a" + strings.Repeat("banana", 8)))
		})
	})
})
Esempio n. 7
0
		preparer runrunc.ExecPreparer
	)

	BeforeEach(func() {
		logger = lagertest.NewTestLogger("test")
		bundleLoader = new(fakes.FakeBundleLoader)
		users = new(fakes.FakeUserLookupper)
		mkdirer = new(fakes.FakeMkdirer)

		var err error
		bundlePath, err = ioutil.TempDir("", "bundle")
		Expect(err).NotTo(HaveOccurred())

		bundleLoader.LoadStub = func(path string) (goci.Bndl, error) {
			bndl := goci.Bundle()
			return bndl, nil
		}

		users.LookupReturns(&user.ExecUser{}, nil)

		Expect(ioutil.WriteFile(filepath.Join(bundlePath, "pidfile"), []byte("999"), 0644)).To(Succeed())
		preparer = runrunc.NewExecPreparer(bundleLoader, users, mkdirer, []string{"foo", "bar", "brains"})
	})

	It("passes a process.json with the correct path and args", func() {
		spec, err := preparer.Prepare(logger, bundlePath, garden.ProcessSpec{Path: "to enlightenment", Args: []string{"infinity", "and beyond"}})
		Expect(err).NotTo(HaveOccurred())

		Expect(spec.Args).To(Equal([]string{"to enlightenment", "infinity", "and beyond"}))
	})
Esempio n. 8
0
package bundlerules_test

import (
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/opencontainers/runtime-spec/specs-go"

	"code.cloudfoundry.org/garden"
	"code.cloudfoundry.org/guardian/gardener"
	"code.cloudfoundry.org/guardian/rundmc/bundlerules"
	"code.cloudfoundry.org/guardian/rundmc/goci"
)

var _ = Describe("LimitsRule", func() {
	It("sets the correct memory limit in bundle resources", func() {
		newBndl := bundlerules.Limits{}.Apply(goci.Bundle(), gardener.DesiredContainerSpec{
			Limits: garden.Limits{
				Memory: garden.MemoryLimits{LimitInBytes: 4096},
			},
		})

		Expect(*(newBndl.Resources().Memory.Limit)).To(BeNumerically("==", 4096))
		Expect(*(newBndl.Resources().Memory.Swap)).To(BeNumerically("==", 4096))
	})

	It("sets the correct CPU limit in bundle resources", func() {
		newBndl := bundlerules.Limits{}.Apply(goci.Bundle(), gardener.DesiredContainerSpec{
			Limits: garden.Limits{
				CPU: garden.CPULimits{LimitInShares: 1},
			},
		})
Esempio n. 9
0
import (
	"code.cloudfoundry.org/guardian/gardener"
	"code.cloudfoundry.org/guardian/rundmc/bundlerules"
	"code.cloudfoundry.org/guardian/rundmc/goci"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Env Rule", func() {
	var (
		newBndl goci.Bndl
		rule    bundlerules.Env
	)

	JustBeforeEach(func() {
		rule = bundlerules.Env{}
		newBndl = rule.Apply(goci.Bundle(), gardener.DesiredContainerSpec{
			Env: []string{
				"TEST=banana",
				"CONTAINER_NAME=hello",
			},
		})
	})

	It("sets the environment onto the bundle process", func() {
		Expect(newBndl.Spec.Process.Env).To(Equal([]string{
			"TEST=banana", "CONTAINER_NAME=hello",
		}))
	})
})