158893bd1a
Signed-off-by: Matthew Heon <mheon@redhat.com>
268 lines
8 KiB
Go
268 lines
8 KiB
Go
package libkpod
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"sync"
|
|
|
|
"github.com/Sirupsen/logrus"
|
|
"github.com/containers/image/types"
|
|
cstorage "github.com/containers/storage"
|
|
"github.com/docker/docker/pkg/ioutils"
|
|
"github.com/docker/docker/pkg/registrar"
|
|
"github.com/docker/docker/pkg/truncindex"
|
|
"github.com/kubernetes-incubator/cri-o/libkpod/sandbox"
|
|
"github.com/kubernetes-incubator/cri-o/oci"
|
|
"github.com/kubernetes-incubator/cri-o/pkg/storage"
|
|
)
|
|
|
|
// ContainerServer implements the ImageServer
|
|
type ContainerServer struct {
|
|
runtime *oci.Runtime
|
|
store cstorage.Store
|
|
storageImageServer storage.ImageServer
|
|
ctrNameIndex *registrar.Registrar
|
|
ctrIDIndex *truncindex.TruncIndex
|
|
podNameIndex *registrar.Registrar
|
|
podIDIndex *truncindex.TruncIndex
|
|
|
|
imageContext *types.SystemContext
|
|
stateLock sync.Locker
|
|
state *containerServerState
|
|
}
|
|
|
|
// Runtime returns the oci runtime for the ContainerServer
|
|
func (c *ContainerServer) Runtime() *oci.Runtime {
|
|
return c.runtime
|
|
}
|
|
|
|
// Store returns the Store for the ContainerServer
|
|
func (c *ContainerServer) Store() cstorage.Store {
|
|
return c.store
|
|
}
|
|
|
|
// StorageImageServer returns the ImageServer for the ContainerServer
|
|
func (c *ContainerServer) StorageImageServer() storage.ImageServer {
|
|
return c.storageImageServer
|
|
}
|
|
|
|
// CtrNameIndex returns the Registrar for the ContainerServer
|
|
func (c *ContainerServer) CtrNameIndex() *registrar.Registrar {
|
|
return c.ctrNameIndex
|
|
}
|
|
|
|
// CtrIDIndex returns the TruncIndex for the ContainerServer
|
|
func (c *ContainerServer) CtrIDIndex() *truncindex.TruncIndex {
|
|
return c.ctrIDIndex
|
|
}
|
|
|
|
// PodNameIndex returns the index of pod names
|
|
func (c *ContainerServer) PodNameIndex() *registrar.Registrar {
|
|
return c.podNameIndex
|
|
}
|
|
|
|
// PodIDIndex returns the index of pod IDs
|
|
func (c *ContainerServer) PodIDIndex() *truncindex.TruncIndex {
|
|
return c.podIDIndex
|
|
}
|
|
|
|
// ImageContext returns the SystemContext for the ContainerServer
|
|
func (c *ContainerServer) ImageContext() *types.SystemContext {
|
|
return c.imageContext
|
|
}
|
|
|
|
// New creates a new ContainerServer with options provided
|
|
func New(runtime *oci.Runtime, store cstorage.Store, imageService storage.ImageServer, signaturePolicyPath string) *ContainerServer {
|
|
return &ContainerServer{
|
|
runtime: runtime,
|
|
store: store,
|
|
storageImageServer: imageService,
|
|
ctrNameIndex: registrar.NewRegistrar(),
|
|
ctrIDIndex: truncindex.NewTruncIndex([]string{}),
|
|
podNameIndex: registrar.NewRegistrar(),
|
|
podIDIndex: truncindex.NewTruncIndex([]string{}),
|
|
imageContext: &types.SystemContext{SignaturePolicyPath: signaturePolicyPath},
|
|
stateLock: new(sync.Mutex),
|
|
state: &containerServerState{
|
|
containers: oci.NewMemoryStore(),
|
|
sandboxes: make(map[string]*sandbox.Sandbox),
|
|
},
|
|
}
|
|
}
|
|
|
|
// ContainerStateFromDisk retrieves information on the state of a running container
|
|
// from the disk
|
|
func (c *ContainerServer) ContainerStateFromDisk(ctr *oci.Container) error {
|
|
if err := ctr.FromDisk(); err != nil {
|
|
return err
|
|
}
|
|
// ignore errors, this is a best effort to have up-to-date info about
|
|
// a given container before its state gets stored
|
|
c.runtime.UpdateStatus(ctr)
|
|
|
|
return nil
|
|
}
|
|
|
|
// ContainerStateToDisk writes the container's state information to a JSON file
|
|
// on disk
|
|
func (c *ContainerServer) ContainerStateToDisk(ctr *oci.Container) error {
|
|
// ignore errors, this is a best effort to have up-to-date info about
|
|
// a given container before its state gets stored
|
|
c.Runtime().UpdateStatus(ctr)
|
|
|
|
jsonSource, err := ioutils.NewAtomicFileWriter(ctr.StatePath(), 0644)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer jsonSource.Close()
|
|
enc := json.NewEncoder(jsonSource)
|
|
return enc.Encode(c.runtime.ContainerStatus(ctr))
|
|
}
|
|
|
|
// ReserveContainerName holds a name for a container that is being created
|
|
func (c *ContainerServer) ReserveContainerName(id, name string) (string, error) {
|
|
if err := c.ctrNameIndex.Reserve(name, id); err != nil {
|
|
if err == registrar.ErrNameReserved {
|
|
id, err := c.ctrNameIndex.Get(name)
|
|
if err != nil {
|
|
logrus.Warnf("conflict, ctr name %q already reserved", name)
|
|
return "", err
|
|
}
|
|
return "", fmt.Errorf("conflict, name %q already reserved for ctr %q", name, id)
|
|
}
|
|
return "", fmt.Errorf("error reserving ctr name %s", name)
|
|
}
|
|
return name, nil
|
|
}
|
|
|
|
// ReleaseContainerName releases a container name from the index so that it can
|
|
// be used by other containers
|
|
func (c *ContainerServer) ReleaseContainerName(name string) {
|
|
c.ctrNameIndex.Release(name)
|
|
}
|
|
|
|
// ReservePodName holds a name for a pod that is being created
|
|
func (c *ContainerServer) ReservePodName(id, name string) (string, error) {
|
|
if err := c.podNameIndex.Reserve(name, id); err != nil {
|
|
if err == registrar.ErrNameReserved {
|
|
id, err := c.podNameIndex.Get(name)
|
|
if err != nil {
|
|
logrus.Warnf("conflict, pod name %q already reserved", name)
|
|
return "", err
|
|
}
|
|
return "", fmt.Errorf("conflict, name %q already reserved for pod %q", name, id)
|
|
}
|
|
return "", fmt.Errorf("error reserving pod name %q", name)
|
|
}
|
|
return name, nil
|
|
}
|
|
|
|
// ReleasePodName releases a pod name from the index so it can be used by other
|
|
// pods
|
|
func (c *ContainerServer) ReleasePodName(name string) {
|
|
c.podNameIndex.Release(name)
|
|
}
|
|
|
|
// Shutdown attempts to shut down the server's storage cleanly
|
|
func (c *ContainerServer) Shutdown() error {
|
|
_, err := c.store.Shutdown(false)
|
|
return err
|
|
}
|
|
|
|
type containerServerState struct {
|
|
containers oci.ContainerStorer
|
|
sandboxes map[string]*sandbox.Sandbox
|
|
}
|
|
|
|
// AddContainer adds a container to the container state store
|
|
func (c *ContainerServer) AddContainer(ctr *oci.Container) {
|
|
c.stateLock.Lock()
|
|
defer c.stateLock.Unlock()
|
|
sandbox := c.state.sandboxes[ctr.Sandbox()]
|
|
sandbox.AddContainer(ctr)
|
|
c.state.containers.Add(ctr.ID(), ctr)
|
|
}
|
|
|
|
// GetContainer returns a container by its ID
|
|
func (c *ContainerServer) GetContainer(id string) *oci.Container {
|
|
c.stateLock.Lock()
|
|
defer c.stateLock.Unlock()
|
|
return c.state.containers.Get(id)
|
|
}
|
|
|
|
// HasContainer checks if a container exists in the state
|
|
func (c *ContainerServer) HasContainer(id string) bool {
|
|
c.stateLock.Lock()
|
|
defer c.stateLock.Unlock()
|
|
ctr := c.state.containers.Get(id)
|
|
return ctr != nil
|
|
}
|
|
|
|
// RemoveContainer removes a container from the container state store
|
|
func (c *ContainerServer) RemoveContainer(ctr *oci.Container) {
|
|
c.stateLock.Lock()
|
|
defer c.stateLock.Unlock()
|
|
sbID := ctr.Sandbox()
|
|
sb := c.state.sandboxes[sbID]
|
|
sb.RemoveContainer(ctr)
|
|
c.state.containers.Delete(ctr.ID())
|
|
}
|
|
|
|
// ListContainers returns a list of all containers stored by the server state
|
|
func (c *ContainerServer) ListContainers() []*oci.Container {
|
|
c.stateLock.Lock()
|
|
defer c.stateLock.Unlock()
|
|
return c.state.containers.List()
|
|
}
|
|
|
|
// AddSandbox adds a sandbox to the sandbox state store
|
|
func (c *ContainerServer) AddSandbox(sb *sandbox.Sandbox) {
|
|
c.stateLock.Lock()
|
|
defer c.stateLock.Unlock()
|
|
c.state.sandboxes[sb.ID()] = sb
|
|
}
|
|
|
|
// GetSandbox returns a sandbox by its ID
|
|
func (c *ContainerServer) GetSandbox(id string) *sandbox.Sandbox {
|
|
c.stateLock.Lock()
|
|
defer c.stateLock.Unlock()
|
|
return c.state.sandboxes[id]
|
|
}
|
|
|
|
// GetSandboxContainer returns a sandbox's infra container
|
|
func (c *ContainerServer) GetSandboxContainer(id string) *oci.Container {
|
|
c.stateLock.Lock()
|
|
defer c.stateLock.Unlock()
|
|
sb, ok := c.state.sandboxes[id]
|
|
if !ok {
|
|
return nil
|
|
}
|
|
return sb.InfraContainer()
|
|
}
|
|
|
|
// HasSandbox checks if a sandbox exists in the state
|
|
func (c *ContainerServer) HasSandbox(id string) bool {
|
|
c.stateLock.Lock()
|
|
defer c.stateLock.Unlock()
|
|
_, ok := c.state.sandboxes[id]
|
|
return ok
|
|
}
|
|
|
|
// RemoveSandbox removes a sandbox from the state store
|
|
func (c *ContainerServer) RemoveSandbox(id string) {
|
|
c.stateLock.Lock()
|
|
defer c.stateLock.Unlock()
|
|
delete(c.state.sandboxes, id)
|
|
}
|
|
|
|
// ListSandboxes lists all sandboxes in the state store
|
|
func (c *ContainerServer) ListSandboxes() []*sandbox.Sandbox {
|
|
c.stateLock.Lock()
|
|
defer c.stateLock.Unlock()
|
|
sbArray := make([]*sandbox.Sandbox, 0, len(c.state.sandboxes))
|
|
for _, sb := range c.state.sandboxes {
|
|
sbArray = append(sbArray, sb)
|
|
}
|
|
|
|
return sbArray
|
|
}
|