worker: add runner that brings `containerd` up

previously, the `containerd` runner would always assume that
`containerd` was already up and running.

this commit follows more closely what we do for `gdn`, creating a runner
that takes care of bringing `containerd` up, and another runner
responsible for providing the garden server (whose backend
implementation we provide).

this way, having `--garden-use-containerd`, we're able to get the
following:

	parallel:
	  - containerdRunner
	  - gardenServerRunner

note.: this commit DOES NOT resolve the race between `containerdRunner`
and `gardenServerRunner`.

Signed-off-by: Ciro S. Costa <cscosta@pivotal.io>
This commit is contained in:
Ciro S. Costa 2019-11-13 14:36:28 +00:00
parent 9e2a36c9c6
commit 7cd61f6ea2
5 changed files with 136 additions and 17 deletions

1
go.sum
View File

@ -540,6 +540,7 @@ github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7q
github.com/prometheus/procfs v0.0.0-20170216223256-a1dba9ce8bae/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a h1:9a8MnZMP0X2nLJdBg+pBmGgkJlSaKC2KaQmTCk1XDtE=
github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190522114515-bc1a522cf7b1 h1:Lo6mRUjdS99f3zxYOUalftWHUoOGaDRqFk1+j0Q57/I=
github.com/prometheus/procfs v0.0.0-20190522114515-bc1a522cf7b1/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/racksec/srslog v0.0.0-20180709174129-a4725f04ec91 h1:3hihQaxFTzBL1t5bTYaPhEwL4rxD3zjSgu4afGzgQqI=
github.com/racksec/srslog v0.0.0-20180709174129-a4725f04ec91/go.mod h1:eTUUVgGNb+mCsEJeJnwl/Kaaem9IXKa1ZZL5zN4fTag=

View File

@ -2,6 +2,7 @@ package backend
import (
"context"
"fmt"
"time"
"code.cloudfoundry.org/garden"
@ -20,9 +21,15 @@ func New(client libcontainerd.Client) Backend {
}
}
// setup?
// Start sets up the connectivity to `containerd`.
//
func (b *Backend) Start() (err error) {
err = b.client.Init()
if err != nil {
err = fmt.Errorf("failed to initialize contianerd client: %w", err)
return
}
return
}

View File

@ -10,19 +10,25 @@ import (
//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 . Client
type Client interface {
Init() (err error)
Version(ctx context.Context) (err error)
}
type client struct {
addr string
containerd *containerd.Client
}
func New(address string) (c *client, err error) {
c = new(client)
func New(addr string) *client {
return &client{
addr: addr,
}
}
c.containerd, err = containerd.New(address)
func (c *client) Init() (err error) {
c.containerd, err = containerd.New(c.addr)
if err != nil {
err = fmt.Errorf("failed to connect to addr %s: %w", address, err)
err = fmt.Errorf("failed to connect to addr %s: %w", c.addr, err)
return
}

View File

@ -9,6 +9,16 @@ import (
)
type FakeClient struct {
InitStub func() error
initMutex sync.RWMutex
initArgsForCall []struct {
}
initReturns struct {
result1 error
}
initReturnsOnCall map[int]struct {
result1 error
}
VersionStub func(context.Context) error
versionMutex sync.RWMutex
versionArgsForCall []struct {
@ -24,6 +34,58 @@ type FakeClient struct {
invocationsMutex sync.RWMutex
}
func (fake *FakeClient) Init() error {
fake.initMutex.Lock()
ret, specificReturn := fake.initReturnsOnCall[len(fake.initArgsForCall)]
fake.initArgsForCall = append(fake.initArgsForCall, struct {
}{})
fake.recordInvocation("Init", []interface{}{})
fake.initMutex.Unlock()
if fake.InitStub != nil {
return fake.InitStub()
}
if specificReturn {
return ret.result1
}
fakeReturns := fake.initReturns
return fakeReturns.result1
}
func (fake *FakeClient) InitCallCount() int {
fake.initMutex.RLock()
defer fake.initMutex.RUnlock()
return len(fake.initArgsForCall)
}
func (fake *FakeClient) InitCalls(stub func() error) {
fake.initMutex.Lock()
defer fake.initMutex.Unlock()
fake.InitStub = stub
}
func (fake *FakeClient) InitReturns(result1 error) {
fake.initMutex.Lock()
defer fake.initMutex.Unlock()
fake.InitStub = nil
fake.initReturns = struct {
result1 error
}{result1}
}
func (fake *FakeClient) InitReturnsOnCall(i int, result1 error) {
fake.initMutex.Lock()
defer fake.initMutex.Unlock()
fake.InitStub = nil
if fake.initReturnsOnCall == nil {
fake.initReturnsOnCall = make(map[int]struct {
result1 error
})
}
fake.initReturnsOnCall[i] = struct {
result1 error
}{result1}
}
func (fake *FakeClient) Version(arg1 context.Context) error {
fake.versionMutex.Lock()
ret, specificReturn := fake.versionReturnsOnCall[len(fake.versionArgsForCall)]
@ -87,6 +149,8 @@ func (fake *FakeClient) VersionReturnsOnCall(i int, result1 error) {
func (fake *FakeClient) Invocations() map[string][][]interface{} {
fake.invocationsMutex.RLock()
defer fake.invocationsMutex.RUnlock()
fake.initMutex.RLock()
defer fake.initMutex.RUnlock()
fake.versionMutex.RLock()
defer fake.versionMutex.RUnlock()
copiedInvocations := map[string][][]interface{}{}

View File

@ -1,30 +1,71 @@
package workercmd
import (
"fmt"
"os"
"os/exec"
"path/filepath"
"syscall"
"code.cloudfoundry.org/garden/server"
"code.cloudfoundry.org/lager"
concourseCmd "github.com/concourse/concourse/cmd"
"github.com/concourse/concourse/worker/backend"
"github.com/concourse/concourse/worker/backend/libcontainerd"
"github.com/tedsuo/ifrit"
"github.com/tedsuo/ifrit/grouper"
)
func (cmd *WorkerCommand) containerdRunner(logger lager.Logger) (ifrit.Runner, error) {
client, err := libcontainerd.New("address")
if err != nil {
return nil, fmt.Errorf("failed to instantiate containerd client: %w", err)
}
func containerdGardenServer(logger lager.Logger, bindAddr, containerdAddr string) *server.GardenServer {
backend := backend.New(libcontainerd.New(containerdAddr))
backend := backend.New(client)
server := server.New(
return server.New(
"tcp",
cmd.bindAddr(),
bindAddr,
0,
&backend,
logger,
)
return gardenServerRunner{logger, server}, nil
}
// TODO for gdn server, use a `restarter`?
//
func (cmd *WorkerCommand) containerdRunner(logger lager.Logger) (ifrit.Runner, error) {
// set PATH accordingly
//
// TODO - should this be done elsewhere?
//
if binDir := concourseCmd.DiscoverAsset("bin"); binDir != "" {
err := os.Setenv("PATH", binDir+":"+os.Getenv("PATH"))
if err != nil {
return nil, err
}
}
containerdSock := filepath.Join(cmd.WorkDir.Path(), "containerd.sock")
containerdArgs := []string{
"--address", containerdSock,
"--root", filepath.Join(cmd.WorkDir.Path(), "containerd"),
}
containerdCmd := exec.Command("containerd", containerdArgs...)
containerdCmd.Stdout = os.Stdout
containerdCmd.Stderr = os.Stderr
containerdCmd.SysProcAttr = &syscall.SysProcAttr{
Pdeathsig: syscall.SIGKILL,
}
return grouper.NewOrdered(os.Interrupt, grouper.Members{
{
Name: "containerd",
Runner: cmdRunner{cmd: containerdCmd},
},
{
Name: "containerd-backend",
Runner: gardenServerRunner{
logger,
containerdGardenServer(logger, cmd.bindAddr(), containerdSock),
},
},
}), nil
}