concourse/worker/backend/backend.go

172 lines
4.2 KiB
Go

package backend
import (
"context"
"fmt"
"time"
"code.cloudfoundry.org/garden"
"github.com/concourse/concourse/worker/backend/libcontainerd"
bespec "github.com/concourse/concourse/worker/backend/spec"
"github.com/containerd/containerd/cio"
"github.com/containerd/containerd/namespaces"
specs "github.com/opencontainers/runtime-spec/specs-go"
)
var _ garden.Backend = (*Backend)(nil)
type Backend struct {
client libcontainerd.Client
namespace string
}
func New(client libcontainerd.Client, namespace string) Backend {
return Backend{
namespace: namespace,
client: client,
}
}
// Start initializes the client.
//
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
}
// Stop closes the client's underlying connections and frees any resources
// associated with it.
//
func (b *Backend) Stop() {
_ = b.client.Stop()
}
func (b *Backend) GraceTime(container garden.Container) (duration time.Duration) {
return
}
// Pings the garden server in order to check connectivity.
//
func (b *Backend) Ping() (err error) {
err = b.client.Version(context.Background())
return
}
// Capacity returns the physical capacity of the server's machine.
//
// Errors:
// * None.
func (b *Backend) Capacity() (capacity garden.Capacity, err error) { return }
// Create creates a new container.
//
func (b *Backend) Create(gdnSpec garden.ContainerSpec) (container garden.Container, err error) {
var (
oci *specs.Spec
ctx = namespaces.WithNamespace(context.Background(), b.namespace)
)
oci, err = bespec.OciSpec(gdnSpec)
if err != nil {
err = fmt.Errorf("failed to convert garden spec to oci spec: %w", err)
return
}
cont, err := b.client.NewContainer(ctx,
gdnSpec.Handle, gdnSpec.Properties, oci,
)
if err != nil {
err = fmt.Errorf("failed to create a container in containerd: %w", err)
return
}
_, err = cont.NewTask(ctx, cio.NullIO)
if err != nil {
err = fmt.Errorf("failed to create a task in container: %w", err)
return
}
return
}
// Destroy destroys a container.
//
// When a container is destroyed, its resource allocations are released,
// its filesystem is removed, and all references to its handle are removed.
//
// All resources that have been acquired during the lifetime of the container are released.
// Examples of these resources are its subnet, its UID, and ports that were redirected to the container.
//
// TODO: list the resources that can be acquired during the lifetime of a container.
//
// Errors:
// * TODO.
func (b *Backend) Destroy(handle string) (err error) { return }
// Containers lists all containers filtered by Properties (which are ANDed together).
//
// Errors:
// * None.
func (b *Backend) Containers(properties garden.Properties) (containers []garden.Container, err error) {
var ctx = namespaces.WithNamespace(context.Background(), b.namespace)
filters, err := propertiesToFilterList(properties)
if err != nil {
return
}
res, err := b.client.Containers(ctx, filters...)
if err != nil {
return
}
containers = make([]garden.Container, len(res))
for idx := range res {
gContainer := NewContainer()
containers[idx] = &gContainer
}
return
}
// BulkInfo returns info or error for a list of containers.
func (b *Backend) BulkInfo(handles []string) (info map[string]garden.ContainerInfoEntry, err error) {
return
}
// BulkMetrics returns metrics or error for a list of containers.
func (b *Backend) BulkMetrics(handles []string) (metrics map[string]garden.ContainerMetricsEntry, err error) {
return
}
// Lookup returns the container with the specified handle.
//
// Errors:
// * Container not found.
func (b *Backend) Lookup(handle string) (container garden.Container, err error) { return }
// propertiesToFilterList converts a set of garden properties to a list of
// filters as expected by containerd.
//
func propertiesToFilterList(properties garden.Properties) (filters []string, err error) {
filters = make([]string, len(properties))
idx := 0
for k, v := range properties {
if k == "" || v == "" {
err = fmt.Errorf("key or value must not be empty")
return
}
filters[idx] = k + "=" + v
idx++
}
return
}