Skip to content

Commit

Permalink
Create depot directories for containers
Browse files Browse the repository at this point in the history
Signed-off-by: Gareth Smith <[email protected]>
  • Loading branch information
julz authored and totherme committed Sep 7, 2015
1 parent ed02d28 commit 55d8e00
Show file tree
Hide file tree
Showing 16 changed files with 795 additions and 0 deletions.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
# Guardian

A simple single-host OCI container manager.

## Components

- **Gardeners Question Time (GQT):** A venerable British radio programme. And also a test suite.
- **Gardener:** Orchestrates the other components. Implements the Cloud Foundry Garden API.
- **RunDMC:** A tiny wrappper around RunC to manage a collection of RunC containers.
89 changes: 89 additions & 0 deletions cmd/guardian/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package main

import (
"flag"
"os"
"os/signal"
"syscall"

"github.com/cloudfoundry-incubator/cf-debug-server"
"github.com/cloudfoundry-incubator/cf-lager"
"github.com/cloudfoundry-incubator/garden/server"
"github.com/cloudfoundry-incubator/guardian/gardener"
"github.com/cloudfoundry-incubator/guardian/rundmc"
"github.com/pivotal-golang/lager"
)

var listenNetwork = flag.String(
"listenNetwork",
"unix",
"how to listen on the address (unix, tcp, etc.)",
)

var listenAddr = flag.String(
"listenAddr",
"/tmp/garden.sock",
"address to listen on",
)

var depotPath = flag.String(
"depot",
"",
"directory in which to store containers",
)

var graceTime = flag.Duration(
"containerGraceTime",
0,
"time after which to destroy idle containers",
)

func main() {
cf_debug_server.AddFlags(flag.CommandLine)
cf_lager.AddFlags(flag.CommandLine)
flag.Parse()

logger, _ := cf_lager.New("guardian")

if *depotPath == "" {
missing("-depot")
}

backend := &gardener.Gardener{
Containerizer: &rundmc.Containerizer{
Depot: &rundmc.DirectoryDepot{
Dir: *depotPath,
},
},
}

gardenServer := server.New(*listenNetwork, *listenAddr, *graceTime, backend, logger)

err := gardenServer.Start()
if err != nil {
logger.Fatal("failed-to-start-server", err)
}

signals := make(chan os.Signal, 1)

go func() {
<-signals
gardenServer.Stop()
os.Exit(0)
}()

signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP)

logger.Info("started", lager.Data{
"network": *listenNetwork,
"addr": *listenAddr,
})

select {}
}

func missing(flagName string) {
println("missing " + flagName)
println()
flag.Usage()
}
53 changes: 53 additions & 0 deletions gardener/fakes/fake_containerizer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// This file was generated by counterfeiter
package fakes

import (
"sync"

"github.com/cloudfoundry-incubator/guardian/gardener"
)

type FakeContainerizer struct {
CreateStub func(spec gardener.DesiredContainerSpec) error
createMutex sync.RWMutex
createArgsForCall []struct {
spec gardener.DesiredContainerSpec
}
createReturns struct {
result1 error
}
}

func (fake *FakeContainerizer) Create(spec gardener.DesiredContainerSpec) error {
fake.createMutex.Lock()
fake.createArgsForCall = append(fake.createArgsForCall, struct {
spec gardener.DesiredContainerSpec
}{spec})
fake.createMutex.Unlock()
if fake.CreateStub != nil {
return fake.CreateStub(spec)
} else {
return fake.createReturns.result1
}
}

func (fake *FakeContainerizer) CreateCallCount() int {
fake.createMutex.RLock()
defer fake.createMutex.RUnlock()
return len(fake.createArgsForCall)
}

func (fake *FakeContainerizer) CreateArgsForCall(i int) gardener.DesiredContainerSpec {
fake.createMutex.RLock()
defer fake.createMutex.RUnlock()
return fake.createArgsForCall[i].spec
}

func (fake *FakeContainerizer) CreateReturns(result1 error) {
fake.CreateStub = nil
fake.createReturns = struct {
result1 error
}{result1}
}

var _ gardener.Containerizer = new(FakeContainerizer)
140 changes: 140 additions & 0 deletions gardener/gardener.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
package gardener

import (
"io"
"time"

"github.com/cloudfoundry-incubator/garden"
)

//go:generate counterfeiter . Containerizer
type Containerizer interface {
Create(spec DesiredContainerSpec) error
}

type DesiredContainerSpec struct {
Handle string
}

type Gardener struct {
Containerizer Containerizer
}

func (g *Gardener) Create(spec garden.ContainerSpec) (garden.Container, error) {
g.Containerizer.Create(DesiredContainerSpec{
Handle: spec.Handle,
})

return &container{}, nil
}

func (g *Gardener) Start() error { return nil }
func (g *Gardener) Stop() {}
func (g *Gardener) GraceTime(garden.Container) time.Duration { return 0 }
func (g *Gardener) Ping() error { return nil }
func (g *Gardener) Capacity() (garden.Capacity, error) { return garden.Capacity{}, nil }
func (g *Gardener) Destroy(handle string) error { return nil }
func (g *Gardener) Containers(garden.Properties) ([]garden.Container, error) { return nil, nil }

func (g *Gardener) BulkInfo(handles []string) (map[string]garden.ContainerInfoEntry, error) {
return nil, nil
}

func (g *Gardener) BulkMetrics(handles []string) (map[string]garden.ContainerMetricsEntry, error) {
return nil, nil
}

func (g *Gardener) Lookup(handle string) (garden.Container, error) {
return nil, nil
}

type container struct {
}

func (c *container) Handle() string {
return ""
}

func (c *container) Run(spec garden.ProcessSpec, io garden.ProcessIO) (garden.Process, error) {
return nil, nil
}

func (c *container) Stop(kill bool) error {
return nil
}

func (c *container) Info() (garden.ContainerInfo, error) {
return garden.ContainerInfo{}, nil
}

func (c *container) StreamIn(garden.StreamInSpec) error {
return nil
}

func (c *container) StreamOut(garden.StreamOutSpec) (io.ReadCloser, error) {
return nil, nil
}

func (c *container) LimitBandwidth(limits garden.BandwidthLimits) error {
return nil
}

func (c *container) CurrentBandwidthLimits() (garden.BandwidthLimits, error) {
return garden.BandwidthLimits{}, nil
}

func (c *container) LimitCPU(limits garden.CPULimits) error {
return nil
}

func (c *container) CurrentCPULimits() (garden.CPULimits, error) {
return garden.CPULimits{}, nil
}

func (c *container) LimitDisk(limits garden.DiskLimits) error {
return nil
}

func (c *container) CurrentDiskLimits() (garden.DiskLimits, error) {
return garden.DiskLimits{}, nil
}

func (c *container) LimitMemory(limits garden.MemoryLimits) error {
return nil
}

func (c *container) CurrentMemoryLimits() (garden.MemoryLimits, error) {
return garden.MemoryLimits{}, nil
}

func (c *container) NetIn(hostPort, containerPort uint32) (uint32, uint32, error) {
return 0, 0, nil
}

func (c *container) NetOut(netOutRule garden.NetOutRule) error {
return nil
}

func (c *container) Attach(processID uint32, io garden.ProcessIO) (garden.Process, error) {
return nil, nil
}

func (c *container) Metrics() (garden.Metrics, error) {
return garden.Metrics{}, nil
}

func (c *container) Properties() (garden.Properties, error) {
return nil, nil
}

func (c *container) Property(name string) (string, error) {
return "", nil
}

func (c *container) SetProperty(name string, value string) error {
return nil
}

func (c *container) RemoveProperty(name string) error {
return nil
}
13 changes: 13 additions & 0 deletions gardener/gardener_suite_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package gardener_test

import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"

"testing"
)

func TestGardener(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Gardener Suite")
}
37 changes: 37 additions & 0 deletions gardener/gardener_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package gardener_test

import (
"github.com/cloudfoundry-incubator/garden"
"github.com/cloudfoundry-incubator/guardian/gardener"
"github.com/cloudfoundry-incubator/guardian/gardener/fakes"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)

var _ = Describe("Gardener", func() {
var (
containerizer *fakes.FakeContainerizer
gdnr *gardener.Gardener
)

BeforeEach(func() {
containerizer = new(fakes.FakeContainerizer)
gdnr = &gardener.Gardener{
Containerizer: containerizer,
}
})

Describe("creating a container", func() {
It("asks the containerizer to create a container", func() {
_, err := gdnr.Create(garden.ContainerSpec{
Handle: "bob",
})

Expect(err).NotTo(HaveOccurred())
Expect(containerizer.CreateCallCount()).To(Equal(1))
Expect(containerizer.CreateArgsForCall(0)).To(Equal(gardener.DesiredContainerSpec{
Handle: "bob",
}))
})
})
})
42 changes: 42 additions & 0 deletions gqt/create_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package gqt_test

import (
"path/filepath"

"github.com/cloudfoundry-incubator/garden"
"github.com/cloudfoundry-incubator/guardian/gqt/runner"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/onsi/gomega/gexec"
)

var _ = Describe("Creating a Container", func() {
var client *runner.RunningGarden

Context("after creating a container", func() {
BeforeEach(func() {
client = startGarden()
_, err := client.Create(garden.ContainerSpec{
Handle: "fred",
})
Expect(err).NotTo(HaveOccurred())
})

It("should create a depot subdirectory based on the container handle", func() {
Expect(filepath.Join(client.DepotDir, "fred")).To(BeADirectory())
})

Describe("created container directories", func() {
It("should have a config.json", func() {
Expect(filepath.Join(client.DepotDir, "fred", "config.json")).To(BeARegularFile())
})
})
})
})

func startGarden(argv ...string) *runner.RunningGarden {
gardenBin, err := gexec.Build("github.com/cloudfoundry-incubator/guardian/cmd/guardian")
Expect(err).NotTo(HaveOccurred())

return runner.Start(gardenBin, argv...)
}
Loading

0 comments on commit 55d8e00

Please sign in to comment.