summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/kpod/ps.go11
-rw-r--r--libkpod/config.go5
-rw-r--r--libkpod/container.go157
-rw-r--r--libkpod/container_server.go775
-rw-r--r--libkpod/kill.go45
-rw-r--r--libkpod/rename.go114
-rw-r--r--libkpod/sandbox/sandbox.go484
-rw-r--r--libkpod/stats.go111
-rw-r--r--libkpod/stop.go36
-rw-r--r--libkpod/wait.go42
-rw-r--r--oci/container.go260
-rw-r--r--oci/finished.go14
-rw-r--r--oci/finished_32.go14
-rw-r--r--oci/history.go31
-rw-r--r--oci/memory_store.go92
-rw-r--r--oci/oci.go748
-rw-r--r--oci/store.go27
17 files changed, 7 insertions, 2959 deletions
diff --git a/cmd/kpod/ps.go b/cmd/kpod/ps.go
index 36ce18515..4148edf68 100644
--- a/cmd/kpod/ps.go
+++ b/cmd/kpod/ps.go
@@ -15,7 +15,6 @@ import (
"github.com/pkg/errors"
"github.com/projectatomic/libpod/cmd/kpod/formats"
"github.com/projectatomic/libpod/libpod"
- "github.com/projectatomic/libpod/oci"
"github.com/urfave/cli"
"k8s.io/apimachinery/pkg/fields"
)
@@ -491,7 +490,7 @@ func getJSONOutput(containers []*libpod.Container, nSpace bool) ([]psJSONParams,
Names: cc.Name,
Labels: cc.Labels,
Mounts: cc.Spec.Mounts,
- ContainerRunning: conState.String() == oci.ContainerStateRunning,
+ ContainerRunning: conState == libpod.ContainerStateRunning,
Namespaces: ns,
}
psOutput = append(psOutput, params)
@@ -605,7 +604,7 @@ type FilterParamsPS struct {
}
// parseFilter takes a filter string and a list of containers and filters it
-func parseFilter(filter string, containers []*oci.Container) (*FilterParamsPS, error) {
+func parseFilter(filter string, containers []*libpod.Container) (*FilterParamsPS, error) {
params := new(FilterParamsPS)
allFilters := strings.Split(filter, ",")
@@ -630,13 +629,13 @@ func parseFilter(filter string, containers []*oci.Container) (*FilterParamsPS, e
params.ancestor = pair[1]
case "before":
if ctr, err := findContainer(containers, pair[1]); err == nil {
- params.before = ctr.CreatedAt()
+ params.before = ctr.Config().CreatedTime
} else {
return nil, errors.Wrapf(err, "no such container %q", pair[1])
}
case "since":
if ctr, err := findContainer(containers, pair[1]); err == nil {
- params.before = ctr.CreatedAt()
+ params.before = ctr.Config().CreatedTime
} else {
return nil, errors.Wrapf(err, "no such container %q", pair[1])
}
@@ -650,7 +649,7 @@ func parseFilter(filter string, containers []*oci.Container) (*FilterParamsPS, e
}
// findContainer finds a container with a specific name or id from a list of containers
-func findContainer(containers []*oci.Container, ref string) (*oci.Container, error) {
+func findContainer(containers []*libpod.Container, ref string) (*libpod.Container, error) {
for _, ctr := range containers {
if strings.HasPrefix(ctr.ID(), ref) || ctr.Name() == ref {
return ctr, nil
diff --git a/libkpod/config.go b/libkpod/config.go
index 84d3ce897..b95ff18ca 100644
--- a/libkpod/config.go
+++ b/libkpod/config.go
@@ -6,7 +6,6 @@ import (
"github.com/BurntSushi/toml"
"github.com/opencontainers/selinux/go-selinux"
- "github.com/projectatomic/libpod/oci"
)
// Default paths if none are specified
@@ -21,9 +20,9 @@ const (
apparmorProfileName = "crio-default"
cniConfigDir = "/etc/cni/net.d/"
cniBinDir = "/opt/cni/bin/"
- cgroupManager = oci.CgroupfsCgroupsManager
+ cgroupManager = "" //oci.CgroupfsCgroupsManager
lockPath = "/run/crio.lock"
- containerExitsDir = oci.ContainerExitsDir
+ containerExitsDir = "" //oci.ContainerExitsDir
)
// Config represents the entire set of configuration values that can be set for
diff --git a/libkpod/container.go b/libkpod/container.go
deleted file mode 100644
index e0ff348d0..000000000
--- a/libkpod/container.go
+++ /dev/null
@@ -1,157 +0,0 @@
-package libkpod
-
-import (
- "fmt"
-
- cstorage "github.com/containers/storage"
- "github.com/pkg/errors"
- "github.com/projectatomic/libpod/libkpod/sandbox"
- "github.com/projectatomic/libpod/oci"
- "github.com/projectatomic/libpod/pkg/registrar"
-)
-
-// GetStorageContainer searches for a container with the given name or ID in the given store
-func (c *ContainerServer) GetStorageContainer(container string) (*cstorage.Container, error) {
- ociCtr, err := c.LookupContainer(container)
- if err != nil {
- return nil, err
- }
- return c.store.Container(ociCtr.ID())
-}
-
-// GetContainerTopLayerID gets the ID of the top layer of the given container
-func (c *ContainerServer) GetContainerTopLayerID(containerID string) (string, error) {
- ctr, err := c.GetStorageContainer(containerID)
- if err != nil {
- return "", err
- }
- return ctr.LayerID, nil
-}
-
-// GetContainerRwSize Gets the size of the mutable top layer of the container
-func (c *ContainerServer) GetContainerRwSize(containerID string) (int64, error) {
- container, err := c.store.Container(containerID)
- if err != nil {
- return 0, err
- }
-
- // Get the size of the top layer by calculating the size of the diff
- // between the layer and its parent. The top layer of a container is
- // the only RW layer, all others are immutable
- layer, err := c.store.Layer(container.LayerID)
- if err != nil {
- return 0, err
- }
- return c.store.DiffSize(layer.Parent, layer.ID)
-}
-
-// GetContainerRootFsSize gets the size of the container's root filesystem
-// A container FS is split into two parts. The first is the top layer, a
-// mutable layer, and the rest is the RootFS: the set of immutable layers
-// that make up the image on which the container is based
-func (c *ContainerServer) GetContainerRootFsSize(containerID string) (int64, error) {
- container, err := c.store.Container(containerID)
- if err != nil {
- return 0, err
- }
-
- // Ignore the size of the top layer. The top layer is a mutable RW layer
- // and is not considered a part of the rootfs
- rwLayer, err := c.store.Layer(container.LayerID)
- if err != nil {
- return 0, err
- }
- layer, err := c.store.Layer(rwLayer.Parent)
- if err != nil {
- return 0, err
- }
-
- size := int64(0)
- for layer.Parent != "" {
- layerSize, err := c.store.DiffSize(layer.Parent, layer.ID)
- if err != nil {
- return size, errors.Wrapf(err, "getting diffsize of layer %q and its parent %q", layer.ID, layer.Parent)
- }
- size += layerSize
- layer, err = c.store.Layer(layer.Parent)
- if err != nil {
- return 0, err
- }
- }
- // Get the size of the last layer. Has to be outside of the loop
- // because the parent of the last layer is "", andlstore.Get("")
- // will return an error
- layerSize, err := c.store.DiffSize(layer.Parent, layer.ID)
- return size + layerSize, err
-}
-
-// GetContainerFromRequest gets an oci container matching the specified full or partial id
-func (c *ContainerServer) GetContainerFromRequest(cid string) (*oci.Container, error) {
- if cid == "" {
- return nil, fmt.Errorf("container ID should not be empty")
- }
-
- containerID, err := c.ctrIDIndex.Get(cid)
- if err != nil {
- return nil, fmt.Errorf("container with ID starting with %s not found: %v", cid, err)
- }
-
- ctr := c.GetContainer(containerID)
- if ctr == nil {
- return nil, fmt.Errorf("specified container not found: %s", containerID)
- }
- return ctr, nil
-}
-
-func (c *ContainerServer) getSandboxFromRequest(pid string) (*sandbox.Sandbox, error) {
- if pid == "" {
- return nil, fmt.Errorf("pod ID should not be empty")
- }
-
- podID, err := c.podIDIndex.Get(pid)
- if err != nil {
- return nil, fmt.Errorf("pod with ID starting with %s not found: %v", pid, err)
- }
-
- sb := c.GetSandbox(podID)
- if sb == nil {
- return nil, fmt.Errorf("specified pod not found: %s", podID)
- }
- return sb, nil
-}
-
-// LookupContainer returns the container with the given name or full or partial id
-func (c *ContainerServer) LookupContainer(idOrName string) (*oci.Container, error) {
- if idOrName == "" {
- return nil, fmt.Errorf("container ID or name should not be empty")
- }
-
- ctrID, err := c.ctrNameIndex.Get(idOrName)
- if err != nil {
- if err == registrar.ErrNameNotReserved {
- ctrID = idOrName
- } else {
- return nil, err
- }
- }
-
- return c.GetContainerFromRequest(ctrID)
-}
-
-// LookupSandbox returns the pod sandbox with the given name or full or partial id
-func (c *ContainerServer) LookupSandbox(idOrName string) (*sandbox.Sandbox, error) {
- if idOrName == "" {
- return nil, fmt.Errorf("container ID or name should not be empty")
- }
-
- podID, err := c.podNameIndex.Get(idOrName)
- if err != nil {
- if err == registrar.ErrNameNotReserved {
- podID = idOrName
- } else {
- return nil, err
- }
- }
-
- return c.getSandboxFromRequest(podID)
-}
diff --git a/libkpod/container_server.go b/libkpod/container_server.go
deleted file mode 100644
index 8e0e09978..000000000
--- a/libkpod/container_server.go
+++ /dev/null
@@ -1,775 +0,0 @@
-package libkpod
-
-import (
- "encoding/json"
- "fmt"
- "os"
- "path/filepath"
- "sync"
- "time"
-
- "github.com/containers/image/types"
- cstorage "github.com/containers/storage"
- "github.com/docker/docker/pkg/ioutils"
- "github.com/docker/docker/pkg/truncindex"
- "github.com/opencontainers/runc/libcontainer"
- rspec "github.com/opencontainers/runtime-spec/specs-go"
- "github.com/opencontainers/selinux/go-selinux"
- "github.com/opencontainers/selinux/go-selinux/label"
- "github.com/pkg/errors"
- "github.com/projectatomic/libpod/libkpod/sandbox"
- "github.com/projectatomic/libpod/oci"
- "github.com/projectatomic/libpod/pkg/annotations"
- "github.com/projectatomic/libpod/pkg/registrar"
- "github.com/projectatomic/libpod/pkg/storage"
- "github.com/sirupsen/logrus"
- pb "k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
-)
-
-// ContainerServer implements the ImageServer
-type ContainerServer struct {
- runtime *oci.Runtime
- store cstorage.Store
- storageImageServer storage.ImageServer
- storageRuntimeServer storage.RuntimeServer
- updateLock sync.RWMutex
- ctrNameIndex *registrar.Registrar
- ctrIDIndex *truncindex.TruncIndex
- podNameIndex *registrar.Registrar
- podIDIndex *truncindex.TruncIndex
- hooks map[string]HookParams
-
- imageContext *types.SystemContext
- stateLock sync.Locker
- state *containerServerState
- config *Config
-}
-
-// Runtime returns the oci runtime for the ContainerServer
-func (c *ContainerServer) Runtime() *oci.Runtime {
- return c.runtime
-}
-
-// Hooks returns the oci hooks for the ContainerServer
-func (c *ContainerServer) Hooks() map[string]HookParams {
- return c.hooks
-}
-
-// 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
-}
-
-// Config gets the configuration for the ContainerServer
-func (c *ContainerServer) Config() *Config {
- return c.config
-}
-
-// StorageRuntimeServer gets the runtime server for the ContainerServer
-func (c *ContainerServer) StorageRuntimeServer() storage.RuntimeServer {
- return c.storageRuntimeServer
-}
-
-// New creates a new ContainerServer with options provided
-func New(config *Config) (*ContainerServer, error) {
- store, err := cstorage.GetStore(cstorage.StoreOptions{
- RunRoot: config.RunRoot,
- GraphRoot: config.Root,
- GraphDriverName: config.Storage,
- GraphDriverOptions: config.StorageOptions,
- })
- if err != nil {
- return nil, err
- }
-
- imageService, err := storage.GetImageService(store, config.DefaultTransport, config.InsecureRegistries, config.Registries)
- if err != nil {
- return nil, err
- }
-
- storageRuntimeService := storage.GetRuntimeService(imageService, config.PauseImage)
- if err != nil {
- return nil, err
- }
-
- runtime, err := oci.New(config.Runtime, config.RuntimeUntrustedWorkload, config.DefaultWorkloadTrust, config.Conmon, config.ConmonEnv, config.CgroupManager, config.ContainerExitsDir, config.LogSizeMax, config.NoPivot)
- if err != nil {
- return nil, err
- }
-
- var lock sync.Locker
- if config.FileLocking {
- fileLock, err := cstorage.GetLockfile(lockPath)
- if err != nil {
- return nil, fmt.Errorf("error obtaining lockfile: %v", err)
- }
- lock = fileLock
- } else {
- lock = new(sync.Mutex)
- }
-
- hooks := make(map[string]HookParams)
- // If hooks directory is set in config use it
- if config.HooksDirPath != "" {
- if err := readHooks(config.HooksDirPath, hooks); err != nil {
- return nil, err
- }
- // If user overrode default hooks, this means it is in a test, so don't
- // use OverrideHooksDirPath
- if config.HooksDirPath == DefaultHooksDirPath {
- if err := readHooks(OverrideHooksDirPath, hooks); err != nil {
- return nil, err
- }
- }
- }
-
- return &ContainerServer{
- runtime: runtime,
- store: store,
- storageImageServer: imageService,
- storageRuntimeServer: storageRuntimeService,
- ctrNameIndex: registrar.NewRegistrar(),
- ctrIDIndex: truncindex.NewTruncIndex([]string{}),
- podNameIndex: registrar.NewRegistrar(),
- podIDIndex: truncindex.NewTruncIndex([]string{}),
- imageContext: &types.SystemContext{SignaturePolicyPath: config.SignaturePolicyPath},
- hooks: hooks,
- stateLock: lock,
- state: &containerServerState{
- containers: oci.NewMemoryStore(),
- infraContainers: oci.NewMemoryStore(),
- sandboxes: make(map[string]*sandbox.Sandbox),
- processLevels: make(map[string]int),
- },
- config: config,
- }, nil
-}
-
-// Update makes changes to the server's state (lists of pods and containers) to
-// reflect the list of pods and containers that are stored on disk, possibly
-// having been modified by other parties
-func (c *ContainerServer) Update() error {
- c.updateLock.Lock()
- defer c.updateLock.Unlock()
-
- containers, err := c.store.Containers()
- if err != nil && !os.IsNotExist(errors.Cause(err)) {
- logrus.Warnf("could not read containers and sandboxes: %v", err)
- return err
- }
- newPods := map[string]*storage.RuntimeContainerMetadata{}
- oldPods := map[string]string{}
- removedPods := map[string]string{}
- newPodContainers := map[string]*storage.RuntimeContainerMetadata{}
- oldPodContainers := map[string]string{}
- removedPodContainers := map[string]string{}
- for _, container := range containers {
- if c.HasSandbox(container.ID) {
- // FIXME: do we need to reload/update any info about the sandbox?
- oldPods[container.ID] = container.ID
- oldPodContainers[container.ID] = container.ID
- continue
- }
- if c.GetContainer(container.ID) != nil {
- // FIXME: do we need to reload/update any info about the container?
- oldPodContainers[container.ID] = container.ID
- continue
- }
- // not previously known, so figure out what it is
- metadata, err2 := c.storageRuntimeServer.GetContainerMetadata(container.ID)
- if err2 != nil {
- logrus.Errorf("error parsing metadata for %s: %v, ignoring", container.ID, err2)
- continue
- }
- if metadata.Pod {
- newPods[container.ID] = &metadata
- } else {
- newPodContainers[container.ID] = &metadata
- }
- }
- c.ctrIDIndex.Iterate(func(id string) {
- if _, ok := oldPodContainers[id]; !ok {
- // this container's ID wasn't in the updated list -> removed
- removedPodContainers[id] = id
- } else {
- ctr := c.GetContainer(id)
- if ctr != nil {
- // if the container exists, update its state
- c.ContainerStateFromDisk(c.GetContainer(id))
- }
- }
- })
- for removedPodContainer := range removedPodContainers {
- // forget this container
- ctr := c.GetContainer(removedPodContainer)
- if ctr == nil {
- logrus.Warnf("bad state when getting container removed %+v", removedPodContainer)
- continue
- }
- c.ReleaseContainerName(ctr.Name())
- c.RemoveContainer(ctr)
- if err = c.ctrIDIndex.Delete(ctr.ID()); err != nil {
- return err
- }
- logrus.Debugf("forgetting removed pod container %s", ctr.ID())
- }
- c.PodIDIndex().Iterate(func(id string) {
- if _, ok := oldPods[id]; !ok {
- // this pod's ID wasn't in the updated list -> removed
- removedPods[id] = id
- }
- })
- for removedPod := range removedPods {
- // forget this pod
- sb := c.GetSandbox(removedPod)
- if sb == nil {
- logrus.Warnf("bad state when getting pod to remove %+v", removedPod)
- continue
- }
- podInfraContainer := sb.InfraContainer()
- c.ReleaseContainerName(podInfraContainer.Name())
- c.RemoveContainer(podInfraContainer)
- if err = c.ctrIDIndex.Delete(podInfraContainer.ID()); err != nil {
- return err
- }
- sb.RemoveInfraContainer()
- c.ReleasePodName(sb.Name())
- c.RemoveSandbox(sb.ID())
- if err = c.podIDIndex.Delete(sb.ID()); err != nil {
- return err
- }
- logrus.Debugf("forgetting removed pod %s", sb.ID())
- }
- for sandboxID := range newPods {
- // load this pod
- if err = c.LoadSandbox(sandboxID); err != nil {
- logrus.Warnf("could not load new pod sandbox %s: %v, ignoring", sandboxID, err)
- } else {
- logrus.Debugf("loaded new pod sandbox %s", sandboxID, err)
- }
- }
- for containerID := range newPodContainers {
- // load this container
- if err = c.LoadContainer(containerID); err != nil {
- logrus.Warnf("could not load new sandbox container %s: %v, ignoring", containerID, err)
- } else {
- logrus.Debugf("loaded new pod container %s", containerID, err)
- }
- }
- return nil
-}
-
-// LoadSandbox loads a sandbox from the disk into the sandbox store
-func (c *ContainerServer) LoadSandbox(id string) error {
- config, err := c.store.FromContainerDirectory(id, "config.json")
- if err != nil {
- return err
- }
- var m rspec.Spec
- if err = json.Unmarshal(config, &m); err != nil {
- return err
- }
- labels := make(map[string]string)
- if err = json.Unmarshal([]byte(m.Annotations[annotations.Labels]), &labels); err != nil {
- return err
- }
- name := m.Annotations[annotations.Name]
- name, err = c.ReservePodName(id, name)
- if err != nil {
- return err
- }
- defer func() {
- if err != nil {
- c.ReleasePodName(name)
- }
- }()
- var metadata pb.PodSandboxMetadata
- if err = json.Unmarshal([]byte(m.Annotations[annotations.Metadata]), &metadata); err != nil {
- return err
- }
-
- ip := m.Annotations[annotations.IP]
-
- processLabel, mountLabel, err := label.InitLabels(label.DupSecOpt(m.Process.SelinuxLabel))
- if err != nil {
- return err
- }
-
- kubeAnnotations := make(map[string]string)
- if err = json.Unmarshal([]byte(m.Annotations[annotations.Annotations]), &kubeAnnotations); err != nil {
- return err
- }
-
- privileged := isTrue(m.Annotations[annotations.PrivilegedRuntime])
- trusted := isTrue(m.Annotations[annotations.TrustedSandbox])
-
- sb, err := sandbox.New(id, name, m.Annotations[annotations.KubeName], filepath.Dir(m.Annotations[annotations.LogPath]), "", labels, kubeAnnotations, processLabel, mountLabel, &metadata, m.Annotations[annotations.ShmPath], "", privileged, trusted, m.Annotations[annotations.ResolvPath], "", nil)
- if err != nil {
- return err
- }
- sb.AddHostnamePath(m.Annotations[annotations.HostnamePath])
- sb.AddIP(ip)
-
- // We add a netNS only if we can load a permanent one.
- // Otherwise, the sandbox will live in the host namespace.
- netNsPath, err := configNetNsPath(m)
- if err == nil {
- nsErr := sb.NetNsJoin(netNsPath, sb.Name())
- // If we can't load the networking namespace
- // because it's closed, we just set the sb netns
- // pointer to nil. Otherwise we return an error.
- if nsErr != nil && nsErr != sandbox.ErrClosedNetNS {
- return nsErr
- }
- }
-
- c.AddSandbox(sb)
-
- defer func() {
- if err != nil {
- c.RemoveSandbox(sb.ID())
- }
- }()
-
- sandboxPath, err := c.store.ContainerRunDirectory(id)
- if err != nil {
- return err
- }
-
- sandboxDir, err := c.store.ContainerDirectory(id)
- if err != nil {
- return err
- }
-
- cname, err := c.ReserveContainerName(m.Annotations[annotations.ContainerID], m.Annotations[annotations.ContainerName])
- if err != nil {
- return err
- }
- defer func() {
- if err != nil {
- c.ReleaseContainerName(cname)
- }
- }()
-
- created, err := time.Parse(time.RFC3339Nano, m.Annotations[annotations.Created])
- if err != nil {
- return err
- }
-
- scontainer, err := oci.NewContainer(m.Annotations[annotations.ContainerID], cname, sandboxPath, m.Annotations[annotations.LogPath], sb.NetNs(), labels, m.Annotations, kubeAnnotations, "", "", "", nil, id, false, false, false, privileged, trusted, sandboxDir, created, m.Annotations["org.opencontainers.image.stopSignal"])
- if err != nil {
- return err
- }
- scontainer.SetSpec(&m)
- scontainer.SetMountPoint(m.Annotations[annotations.MountPoint])
-
- if m.Annotations[annotations.Volumes] != "" {
- containerVolumes := []oci.ContainerVolume{}
- if err = json.Unmarshal([]byte(m.Annotations[annotations.Volumes]), &containerVolumes); err != nil {
- return fmt.Errorf("failed to unmarshal container volumes: %v", err)
- }
- if containerVolumes != nil {
- for _, cv := range containerVolumes {
- scontainer.AddVolume(cv)
- }
- }
- }
-
- c.ContainerStateFromDisk(scontainer)
-
- if err = label.ReserveLabel(processLabel); err != nil {
- return err
- }
- sb.SetInfraContainer(scontainer)
- if err = c.ctrIDIndex.Add(scontainer.ID()); err != nil {
- return err
- }
- if err = c.podIDIndex.Add(id); err != nil {
- return err
- }
- return nil
-}
-
-func configNetNsPath(spec rspec.Spec) (string, error) {
- for _, ns := range spec.Linux.Namespaces {
- if ns.Type != rspec.NetworkNamespace {
- continue
- }
-
- if ns.Path == "" {
- return "", fmt.Errorf("empty networking namespace")
- }
-
- return ns.Path, nil
- }
-
- return "", fmt.Errorf("missing networking namespace")
-}
-
-// LoadContainer loads a container from the disk into the container store
-func (c *ContainerServer) LoadContainer(id string) error {
- config, err := c.store.FromContainerDirectory(id, "config.json")
- if err != nil {
- return err
- }
- var m rspec.Spec
- if err = json.Unmarshal(config, &m); err != nil {
- return err
- }
- labels := make(map[string]string)
- if err = json.Unmarshal([]byte(m.Annotations[annotations.Labels]), &labels); err != nil {
- return err
- }
- name := m.Annotations[annotations.Name]
- name, err = c.ReserveContainerName(id, name)
- if err != nil {
- return err
- }
-
- defer func() {
- if err != nil {
- c.ReleaseContainerName(name)
- }
- }()
-
- var metadata pb.ContainerMetadata
- if err = json.Unmarshal([]byte(m.Annotations[annotations.Metadata]), &metadata); err != nil {
- return err
- }
- sb := c.GetSandbox(m.Annotations[annotations.SandboxID])
- if sb == nil {
- return fmt.Errorf("could not get sandbox with id %s, skipping", m.Annotations[annotations.SandboxID])
- }
-
- tty := isTrue(m.Annotations[annotations.TTY])
- stdin := isTrue(m.Annotations[annotations.Stdin])
- stdinOnce := isTrue(m.Annotations[annotations.StdinOnce])
-
- containerPath, err := c.store.ContainerRunDirectory(id)
- if err != nil {
- return err
- }
-
- containerDir, err := c.store.ContainerDirectory(id)
- if err != nil {
- return err
- }
-
- img, ok := m.Annotations[annotations.Image]
- if !ok {
- img = ""
- }
-
- imgName, ok := m.Annotations[annotations.ImageName]
- if !ok {
- imgName = ""
- }
-
- imgRef, ok := m.Annotations[annotations.ImageRef]
- if !ok {
- imgRef = ""
- }
-
- kubeAnnotations := make(map[string]string)
- if err = json.Unmarshal([]byte(m.Annotations[annotations.Annotations]), &kubeAnnotations); err != nil {
- return err
- }
-
- created, err := time.Parse(time.RFC3339Nano, m.Annotations[annotations.Created])
- if err != nil {
- return err
- }
-
- ctr, err := oci.NewContainer(id, name, containerPath, m.Annotations[annotations.LogPath], sb.NetNs(), labels, m.Annotations, kubeAnnotations, img, imgName, imgRef, &metadata, sb.ID(), tty, stdin, stdinOnce, sb.Privileged(), sb.Trusted(), containerDir, created, m.Annotations["org.opencontainers.image.stopSignal"])
- if err != nil {
- return err
- }
- ctr.SetSpec(&m)
- ctr.SetMountPoint(m.Annotations[annotations.MountPoint])
-
- c.ContainerStateFromDisk(ctr)
-
- c.AddContainer(ctr)
- return c.ctrIDIndex.Add(id)
-}
-
-func isTrue(annotaton string) bool {
- return annotaton == "true"
-}
-
-// 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)
- if err != nil && errors.Cause(err) != cstorage.ErrLayerUsedByContainer {
- return err
- }
- return nil
-}
-
-type containerServerState struct {
- containers oci.ContainerStorer
- infraContainers oci.ContainerStorer
- sandboxes map[string]*sandbox.Sandbox
- // processLevels The number of sandboxes using the same SELinux MCS level. Need to release MCS Level, when count reaches 0
- processLevels map[string]int
-}
-
-// 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)
-}
-
-// AddInfraContainer adds a container to the container state store
-func (c *ContainerServer) AddInfraContainer(ctr *oci.Container) {
- c.stateLock.Lock()
- defer c.stateLock.Unlock()
- c.state.infraContainers.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)
-}
-
-// GetInfraContainer returns a container by its ID
-func (c *ContainerServer) GetInfraContainer(id string) *oci.Container {
- c.stateLock.Lock()
- defer c.stateLock.Unlock()
- return c.state.infraContainers.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())
-}
-
-// RemoveInfraContainer removes a container from the container state store
-func (c *ContainerServer) RemoveInfraContainer(ctr *oci.Container) {
- c.stateLock.Lock()
- defer c.stateLock.Unlock()
- c.state.infraContainers.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()
-}
-
-// ListContainers returns a list of all containers stored by the server state
-// that match the given filter function
-func (c *ContainerServer) ListContainers(filters ...func(*oci.Container) bool) ([]*oci.Container, error) {
- containers := c.listContainers()
- if len(filters) == 0 {
- return containers, nil
- }
- filteredContainers := make([]*oci.Container, 0, len(containers))
- for _, container := range containers {
- for _, filter := range filters {
- if filter(container) {
- filteredContainers = append(filteredContainers, container)
- }
- }
- }
- return filteredContainers, nil
-}
-
-// 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
- c.state.processLevels[selinux.NewContext(sb.ProcessLabel())["level"]]++
-}
-
-// 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()
- processLabel := c.state.sandboxes[id].ProcessLabel()
- delete(c.state.sandboxes, id)
- level := selinux.NewContext(processLabel)["level"]
- c.state.processLevels[level]--
- if c.state.processLevels[level] == 0 {
- label.ReleaseLabel(processLabel)
- delete(c.state.processLevels, level)
- }
-}
-
-// 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
-}
-
-// LibcontainerStats gets the stats for the container with the given id from runc/libcontainer
-func (c *ContainerServer) LibcontainerStats(ctr *oci.Container) (*libcontainer.Stats, error) {
- // TODO: make this not hardcoded
- // was: c.runtime.Path(ociContainer) but that returns /usr/bin/runc - how do we get /run/runc?
- // runroot is /var/run/runc
- // Hardcoding probably breaks ClearContainers compatibility
- factory, err := loadFactory("/run/runc")
- if err != nil {
- return nil, err
- }
- container, err := factory.Load(ctr.ID())
- if err != nil {
- return nil, err
- }
- return container.Stats()
-}
diff --git a/libkpod/kill.go b/libkpod/kill.go
deleted file mode 100644
index 74c525818..000000000
--- a/libkpod/kill.go
+++ /dev/null
@@ -1,45 +0,0 @@
-package libkpod
-
-import (
- "github.com/docker/docker/pkg/signal"
- "github.com/pkg/errors"
- "github.com/projectatomic/libpod/oci"
- "github.com/projectatomic/libpod/utils"
- "os"
- "syscall"
-)
-
-// Reverse lookup signal string from its map
-func findStringInSignalMap(killSignal syscall.Signal) (string, error) {
- for k, v := range signal.SignalMap {
- if v == killSignal {
- return k, nil
- }
- }
- return "", errors.Errorf("unable to convert signal to string")
-
-}
-
-// ContainerKill sends the user provided signal to the containers primary process.
-func (c *ContainerServer) ContainerKill(container string, killSignal syscall.Signal) (string, error) { // nolint
- ctr, err := c.LookupContainer(container)
- if err != nil {
- return "", errors.Wrapf(err, "failed to find container %s", container)
- }
- c.runtime.UpdateStatus(ctr)
- cStatus := c.runtime.ContainerStatus(ctr)
-
- // If the container is not running, error and move on.
- if cStatus.Status != oci.ContainerStateRunning {
- return "", errors.Errorf("cannot kill container %s: it is not running", container)
- }
- signalString, err := findStringInSignalMap(killSignal)
- if err != nil {
- return "", err
- }
- if err := utils.ExecCmdWithStdStreams(os.Stdin, os.Stdout, os.Stderr, c.runtime.Path(ctr), "kill", ctr.ID(), signalString); err != nil {
- return "", err
- }
- c.ContainerStateToDisk(ctr)
- return ctr.ID(), nil
-}
diff --git a/libkpod/rename.go b/libkpod/rename.go
deleted file mode 100644
index cdb2bfc04..000000000
--- a/libkpod/rename.go
+++ /dev/null
@@ -1,114 +0,0 @@
-package libkpod
-
-import (
- "encoding/json"
- "path/filepath"
-
- "k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
-
- "github.com/docker/docker/pkg/ioutils"
- "github.com/opencontainers/runtime-tools/generate"
- "github.com/projectatomic/libpod/oci"
- "github.com/projectatomic/libpod/pkg/annotations"
-)
-
-const configFile = "config.json"
-
-// ContainerRename renames the given container
-func (c *ContainerServer) ContainerRename(container, name string) error {
- ctr, err := c.LookupContainer(container)
- if err != nil {
- return err
- }
-
- oldName := ctr.Name()
- _, err = c.ReserveContainerName(ctr.ID(), name)
- if err != nil {
- return err
- }
- defer func() {
- if err != nil {
- c.ReleaseContainerName(name)
- } else {
- c.ReleaseContainerName(oldName)
- }
- }()
-
- // Update state.json
- if err = c.updateStateName(ctr, name); err != nil {
- return err
- }
-
- // Update config.json
- configRuntimePath := filepath.Join(ctr.BundlePath(), configFile)
- if err = updateConfigName(configRuntimePath, name); err != nil {
- return err
- }
- configStoragePath := filepath.Join(ctr.Dir(), configFile)
- if err = updateConfigName(configStoragePath, name); err != nil {
- return err
- }
-
- // Update containers.json
- if err = c.store.SetNames(ctr.ID(), []string{name}); err != nil {
- return err
- }
- return nil
-}
-
-func updateConfigName(configPath, name string) error {
- specgen, err := generate.NewFromFile(configPath)
- if err != nil {
- return err
- }
- specgen.AddAnnotation(annotations.Name, name)
- specgen.AddAnnotation(annotations.Metadata, updateMetadata(specgen.Spec().Annotations, name))
-
- return specgen.SaveToFile(configPath, generate.ExportOptions{})
-}
-
-func (c *ContainerServer) updateStateName(ctr *oci.Container, name string) error {
- ctr.State().Annotations[annotations.Name] = name
- ctr.State().Annotations[annotations.Metadata] = updateMetadata(ctr.State().Annotations, name)
- // This is taken directly from c.ContainerStateToDisk(), which can't be used because of the call to UpdateStatus() in the first line
- 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))
-}
-
-// Attempts to update a metadata annotation
-func updateMetadata(specAnnotations map[string]string, name string) string {
- oldMetadata := specAnnotations[annotations.Metadata]
- containerType := specAnnotations[annotations.ContainerType]
- if containerType == "container" {
- metadata := runtime.ContainerMetadata{}
- err := json.Unmarshal([]byte(oldMetadata), metadata)
- if err != nil {
- return oldMetadata
- }
- metadata.Name = name
- m, err := json.Marshal(metadata)
- if err != nil {
- return oldMetadata
- }
- return string(m)
- } else if containerType == "sandbox" {
- metadata := runtime.PodSandboxMetadata{}
- err := json.Unmarshal([]byte(oldMetadata), metadata)
- if err != nil {
- return oldMetadata
- }
- metadata.Name = name
- m, err := json.Marshal(metadata)
- if err != nil {
- return oldMetadata
- }
- return string(m)
- } else {
- return specAnnotations[annotations.Metadata]
- }
-}
diff --git a/libkpod/sandbox/sandbox.go b/libkpod/sandbox/sandbox.go
deleted file mode 100644
index a61c5a4f7..000000000
--- a/libkpod/sandbox/sandbox.go
+++ /dev/null
@@ -1,484 +0,0 @@
-package sandbox
-
-import (
- "crypto/rand"
- "errors"
- "fmt"
- "os"
- "path/filepath"
- "sync"
-
- "github.com/containernetworking/plugins/pkg/ns"
- "github.com/docker/docker/pkg/mount"
- "github.com/docker/docker/pkg/symlink"
- "github.com/projectatomic/libpod/oci"
- "github.com/sirupsen/logrus"
- "golang.org/x/sys/unix"
- "k8s.io/apimachinery/pkg/fields"
- pb "k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
- "k8s.io/kubernetes/pkg/kubelet/network/hostport"
-)
-
-// NetNs handles data pertaining a network namespace
-type NetNs struct {
- sync.Mutex
- ns ns.NetNS
- symlink *os.File
- closed bool
- restored bool
-}
-
-func (ns *NetNs) symlinkCreate(name string) error {
- b := make([]byte, 4)
- _, randErr := rand.Reader.Read(b)
- if randErr != nil {
- return randErr
- }
-
- nsName := fmt.Sprintf("%s-%x", name, b)
- symlinkPath := filepath.Join(NsRunDir, nsName)
-
- if err := os.Symlink(ns.ns.Path(), symlinkPath); err != nil {
- return err
- }
-
- fd, err := os.Open(symlinkPath)
- if err != nil {
- if removeErr := os.RemoveAll(symlinkPath); removeErr != nil {
- return removeErr
- }
-
- return err
- }
-
- ns.symlink = fd
-
- return nil
-}
-
-func (ns *NetNs) symlinkRemove() error {
- if err := ns.symlink.Close(); err != nil {
- return err
- }
-
- return os.RemoveAll(ns.symlink.Name())
-}
-
-func isSymbolicLink(path string) (bool, error) {
- fi, err := os.Lstat(path)
- if err != nil {
- return false, err
- }
-
- return fi.Mode()&os.ModeSymlink == os.ModeSymlink, nil
-}
-
-// NetNsGet returns the NetNs associated with the given nspath and name
-func NetNsGet(nspath, name string) (*NetNs, error) {
- if err := ns.IsNSorErr(nspath); err != nil {
- return nil, ErrClosedNetNS
- }
-
- symlink, symlinkErr := isSymbolicLink(nspath)
- if symlinkErr != nil {
- return nil, symlinkErr
- }
-
- var resolvedNsPath string
- if symlink {
- path, err := os.Readlink(nspath)
- if err != nil {
- return nil, err
- }
- resolvedNsPath = path
- } else {
- resolvedNsPath = nspath
- }
-
- netNS, err := ns.GetNS(resolvedNsPath)
- if err != nil {
- return nil, err
- }
-
- netNs := &NetNs{ns: netNS, closed: false, restored: true}
-
- if symlink {
- fd, err := os.Open(nspath)
- if err != nil {
- return nil, err
- }
-
- netNs.symlink = fd
- } else {
- if err := netNs.symlinkCreate(name); err != nil {
- return nil, err
- }
- }
-
- return netNs, nil
-}
-
-// HostNetNsPath returns the current network namespace for the host
-func HostNetNsPath() (string, error) {
- netNS, err := ns.GetCurrentNS()
- if err != nil {
- return "", err
- }
-
- defer netNS.Close()
- return netNS.Path(), nil
-}
-
-// Sandbox contains data surrounding kubernetes sandboxes on the server
-type Sandbox struct {
- id string
- namespace string
- // OCI pod name (eg "<namespace>-<name>-<attempt>")
- name string
- // Kubernetes pod name (eg, "<name>")
- kubeName string
- logDir string
- labels fields.Set
- annotations map[string]string
- infraContainer *oci.Container
- containers oci.ContainerStorer
- processLabel string
- mountLabel string
- netns *NetNs
- metadata *pb.PodSandboxMetadata
- shmPath string
- cgroupParent string
- privileged bool
- trusted bool
- resolvPath string
- hostnamePath string
- hostname string
- portMappings []*hostport.PortMapping
- stopped bool
- // ipv4 or ipv6 cache
- ip string
-}
-
-const (
- // DefaultShmSize is the default shm size
- DefaultShmSize = 64 * 1024 * 1024
- // NsRunDir is the default directory in which running network namespaces
- // are stored
- NsRunDir = "/var/run/netns"
- // PodInfraCommand is the default command when starting a pod infrastructure
- // container
- PodInfraCommand = "/pause"
-)
-
-var (
- // ErrIDEmpty is the erro returned when the id of the sandbox is empty
- ErrIDEmpty = errors.New("PodSandboxId should not be empty")
- // ErrClosedNetNS is the error returned when the network namespace of the
- // sandbox is closed
- ErrClosedNetNS = errors.New("PodSandbox networking namespace is closed")
-)
-
-// New creates and populates a new pod sandbox
-// New sandboxes have no containers, no infra container, and no network namespaces associated with them
-// An infra container must be attached before the sandbox is added to the state
-func New(id, namespace, name, kubeName, logDir string, labels, annotations map[string]string, processLabel, mountLabel string, metadata *pb.PodSandboxMetadata, shmPath, cgroupParent string, privileged, trusted bool, resolvPath, hostname string, portMappings []*hostport.PortMapping) (*Sandbox, error) {
- sb := new(Sandbox)
- sb.id = id
- sb.namespace = namespace
- sb.name = name
- sb.kubeName = kubeName
- sb.logDir = logDir
- sb.labels = labels
- sb.annotations = annotations
- sb.containers = oci.NewMemoryStore()
- sb.processLabel = processLabel
- sb.mountLabel = mountLabel
- sb.metadata = metadata
- sb.shmPath = shmPath
- sb.cgroupParent = cgroupParent
- sb.privileged = privileged
- sb.trusted = trusted
- sb.resolvPath = resolvPath
- sb.hostname = hostname
- sb.portMappings = portMappings
-
- return sb, nil
-}
-
-// AddIP stores the ip in the sandbox
-func (s *Sandbox) AddIP(ip string) {
- s.ip = ip
-}
-
-// IP returns the ip of the sandbox
-func (s *Sandbox) IP() string {
- return s.ip
-}
-
-// ID returns the id of the sandbox
-func (s *Sandbox) ID() string {
- return s.id
-}
-
-// Namespace returns the namespace for the sandbox
-func (s *Sandbox) Namespace() string {
- return s.namespace
-}
-
-// Name returns the name of the sandbox
-func (s *Sandbox) Name() string {
- return s.name
-}
-
-// KubeName returns the kubernetes name for the sandbox
-func (s *Sandbox) KubeName() string {
- return s.kubeName
-}
-
-// LogDir returns the location of the logging directory for the sandbox
-func (s *Sandbox) LogDir() string {
- return s.logDir
-}
-
-// Labels returns the labels associated with the sandbox
-func (s *Sandbox) Labels() fields.Set {
- return s.labels
-}
-
-// Annotations returns a list of annotations for the sandbox
-func (s *Sandbox) Annotations() map[string]string {
- return s.annotations
-}
-
-// InfraContainer returns the infrastructure container for the sandbox
-func (s *Sandbox) InfraContainer() *oci.Container {
- return s.infraContainer
-}
-
-// Containers returns the ContainerStorer that contains information on all
-// of the containers in the sandbox
-func (s *Sandbox) Containers() oci.ContainerStorer {
- return s.containers
-}
-
-// ProcessLabel returns the process label for the sandbox
-func (s *Sandbox) ProcessLabel() string {
- return s.processLabel
-}
-
-// MountLabel returns the mount label for the sandbox
-func (s *Sandbox) MountLabel() string {
- return s.mountLabel
-}
-
-// Metadata returns a set of metadata about the sandbox
-func (s *Sandbox) Metadata() *pb.PodSandboxMetadata {
- return s.metadata
-}
-
-// ShmPath returns the shm path of the sandbox
-func (s *Sandbox) ShmPath() string {
- return s.shmPath
-}
-
-// CgroupParent returns the cgroup parent of the sandbox
-func (s *Sandbox) CgroupParent() string {
- return s.cgroupParent
-}
-
-// Privileged returns whether or not the containers in the sandbox are
-// privileged containers
-func (s *Sandbox) Privileged() bool {
- return s.privileged
-}
-
-// Trusted returns whether or not the containers in the sandbox are trusted
-func (s *Sandbox) Trusted() bool {
- return s.trusted
-}
-
-// ResolvPath returns the resolv path for the sandbox
-func (s *Sandbox) ResolvPath() string {
- return s.resolvPath
-}
-
-// AddHostnamePath adds the hostname path to the sandbox
-func (s *Sandbox) AddHostnamePath(hostname string) {
- s.hostnamePath = hostname
-}
-
-// HostnamePath retrieves the hostname path from a sandbox
-func (s *Sandbox) HostnamePath() string {
- return s.hostnamePath
-}
-
-// Hostname returns the hsotname of the sandbox
-func (s *Sandbox) Hostname() string {
- return s.hostname
-}
-
-// PortMappings returns a list of port mappings between the host and the sandbox
-func (s *Sandbox) PortMappings() []*hostport.PortMapping {
- return s.portMappings
-}
-
-// AddContainer adds a container to the sandbox
-func (s *Sandbox) AddContainer(c *oci.Container) {
- s.containers.Add(c.Name(), c)
-}
-
-// GetContainer retrieves a container from the sandbox
-func (s *Sandbox) GetContainer(name string) *oci.Container {
- return s.containers.Get(name)
-}
-
-// RemoveContainer deletes a container from the sandbox
-func (s *Sandbox) RemoveContainer(c *oci.Container) {
- s.containers.Delete(c.Name())
-}
-
-// SetInfraContainer sets the infrastructure container of a sandbox
-// Attempts to set the infrastructure container after one is already present will throw an error
-func (s *Sandbox) SetInfraContainer(infraCtr *oci.Container) error {
- if s.infraContainer != nil {
- return fmt.Errorf("sandbox already has an infra container")
- } else if infraCtr == nil {
- return fmt.Errorf("must provide non-nil infra container")
- }
-
- s.infraContainer = infraCtr
-
- return nil
-}
-
-// RemoveInfraContainer removes the infrastructure container of a sandbox
-func (s *Sandbox) RemoveInfraContainer() {
- s.infraContainer = nil
-}
-
-// NetNs retrieves the network namespace of the sandbox
-// If the sandbox uses the host namespace, nil is returned
-func (s *Sandbox) NetNs() ns.NetNS {
- if s.netns == nil {
- return nil
- }
-
- return s.netns.ns
-}
-
-// NetNsPath returns the path to the network namespace of the sandbox.
-// If the sandbox uses the host namespace, nil is returned
-func (s *Sandbox) NetNsPath() string {
- if s.netns == nil {
- return ""
- }
-
- return s.netns.symlink.Name()
-}
-
-// NetNsCreate creates a new network namespace for the sandbox
-func (s *Sandbox) NetNsCreate() error {
- if s.netns != nil {
- return fmt.Errorf("net NS already created")
- }
-
- netNS, err := ns.NewNS()
- if err != nil {
- return err
- }
-
- s.netns = &NetNs{
- ns: netNS,
- closed: false,
- }
-
- if err := s.netns.symlinkCreate(s.name); err != nil {
- logrus.Warnf("Could not create nentns symlink %v", err)
-
- if err1 := s.netns.ns.Close(); err1 != nil {
- return err1
- }
-
- return err
- }
-
- return nil
-}
-
-// SetStopped sets the sandbox state to stopped.
-// This should be set after a stop operation succeeds
-// so that subsequent stops can return fast.
-func (s *Sandbox) SetStopped() {
- s.stopped = true
-}
-
-// Stopped returns whether the sandbox state has been
-// set to stopped.
-func (s *Sandbox) Stopped() bool {
- return s.stopped
-}
-
-// NetNsJoin attempts to join the sandbox to an existing network namespace
-// This will fail if the sandbox is already part of a network namespace
-func (s *Sandbox) NetNsJoin(nspath, name string) error {
- if s.netns != nil {
- return fmt.Errorf("sandbox already has a network namespace, cannot join another")
- }
-
- netNS, err := NetNsGet(nspath, name)
- if err != nil {
- return err
- }
-
- s.netns = netNS
-
- return nil
-}
-
-// NetNsRemove removes the network namespace associated with the sandbox
-func (s *Sandbox) NetNsRemove() error {
- if s.netns == nil {
- logrus.Warn("no networking namespace")
- return nil
- }
-
- s.netns.Lock()
- defer s.netns.Unlock()
-
- if s.netns.closed {
- // netNsRemove() can be called multiple
- // times without returning an error.
- return nil
- }
-
- if err := s.netns.symlinkRemove(); err != nil {
- return err
- }
-
- if err := s.netns.ns.Close(); err != nil {
- return err
- }
-
- if s.netns.restored {
- // we got namespaces in the form of
- // /var/run/netns/cni-0d08effa-06eb-a963-f51a-e2b0eceffc5d
- // but /var/run on most system is symlinked to /run so we first resolve
- // the symlink and then try and see if it's mounted
- fp, err := symlink.FollowSymlinkInScope(s.netns.ns.Path(), "/")
- if err != nil {
- return err
- }
- if mounted, err := mount.Mounted(fp); err == nil && mounted {
- if err := unix.Unmount(fp, unix.MNT_DETACH); err != nil {
- return err
- }
- }
-
- if err := os.RemoveAll(s.netns.ns.Path()); err != nil {
- return err
- }
- }
-
- s.netns.closed = true
- return nil
-}
diff --git a/libkpod/stats.go b/libkpod/stats.go
deleted file mode 100644
index 8e74577d4..000000000
--- a/libkpod/stats.go
+++ /dev/null
@@ -1,111 +0,0 @@
-package libkpod
-
-import (
- "path/filepath"
- "syscall"
- "time"
-
- "strings"
-
- "github.com/opencontainers/runc/libcontainer"
- "github.com/projectatomic/libpod/oci"
-)
-
-// ContainerStats contains the statistics information for a running container
-type ContainerStats struct {
- Container string
- CPU float64
- cpuNano uint64
- systemNano uint64
- MemUsage uint64
- MemLimit uint64
- MemPerc float64
- NetInput uint64
- NetOutput uint64
- BlockInput uint64
- BlockOutput uint64
- PIDs uint64
-}
-
-// GetContainerStats gets the running stats for a given container
-func (c *ContainerServer) GetContainerStats(ctr *oci.Container, previousStats *ContainerStats) (*ContainerStats, error) {
- previousCPU := previousStats.cpuNano
- previousSystem := previousStats.systemNano
- libcontainerStats, err := c.LibcontainerStats(ctr)
- if err != nil {
- return nil, err
- }
- cgroupStats := libcontainerStats.CgroupStats
- stats := new(ContainerStats)
- stats.Container = ctr.ID()
- stats.CPU = calculateCPUPercent(libcontainerStats, previousCPU, previousSystem)
- stats.MemUsage = cgroupStats.MemoryStats.Usage.Usage
- stats.MemLimit = getMemLimit(cgroupStats.MemoryStats.Usage.Limit)
- stats.MemPerc = float64(stats.MemUsage) / float64(stats.MemLimit)
- stats.PIDs = cgroupStats.PidsStats.Current
- stats.BlockInput, stats.BlockOutput = calculateBlockIO(libcontainerStats)
- stats.NetInput, stats.NetOutput = getContainerNetIO(libcontainerStats)
-
- return stats, nil
-}
-
-func loadFactory(root string) (libcontainer.Factory, error) {
- abs, err := filepath.Abs(root)
- if err != nil {
- return nil, err
- }
- cgroupManager := libcontainer.Cgroupfs
- return libcontainer.New(abs, cgroupManager, libcontainer.CriuPath(""))
-}
-
-// getMemory limit returns the memory limit for a given cgroup
-// If the configured memory limit is larger than the total memory on the sys, the
-// physical system memory size is returned
-func getMemLimit(cgroupLimit uint64) uint64 {
- si := &syscall.Sysinfo_t{}
- err := syscall.Sysinfo(si)
- if err != nil {
- return cgroupLimit
- }
-
- physicalLimit := uint64(si.Totalram)
- if cgroupLimit > physicalLimit {
- return physicalLimit
- }
- return cgroupLimit
-}
-
-// Returns the total number of bytes transmitted and received for the given container stats
-func getContainerNetIO(stats *libcontainer.Stats) (received uint64, transmitted uint64) {
- for _, iface := range stats.Interfaces {
- received += iface.RxBytes
- transmitted += iface.TxBytes
- }
- return
-}
-
-func calculateCPUPercent(stats *libcontainer.Stats, previousCPU, previousSystem uint64) float64 {
- var (
- cpuPercent = 0.0
- cpuDelta = float64(stats.CgroupStats.CpuStats.CpuUsage.TotalUsage - previousCPU)
- systemDelta = float64(uint64(time.Now().UnixNano()) - previousSystem)
- )
- if systemDelta > 0.0 && cpuDelta > 0.0 {
- // gets a ratio of container cpu usage total, multiplies it by the number of cores (4 cores running
- // at 100% utilization should be 400% utilization), and multiplies that by 100 to get a percentage
- cpuPercent = (cpuDelta / systemDelta) * float64(len(stats.CgroupStats.CpuStats.CpuUsage.PercpuUsage)) * 100
- }
- return cpuPercent
-}
-
-func calculateBlockIO(stats *libcontainer.Stats) (read uint64, write uint64) {
- for _, blkIOEntry := range stats.CgroupStats.BlkioStats.IoServiceBytesRecursive {
- switch strings.ToLower(blkIOEntry.Op) {
- case "read":
- read += blkIOEntry.Value
- case "write":
- write += blkIOEntry.Value
- }
- }
- return
-}
diff --git a/libkpod/stop.go b/libkpod/stop.go
deleted file mode 100644
index 4ce7db740..000000000
--- a/libkpod/stop.go
+++ /dev/null
@@ -1,36 +0,0 @@
-package libkpod
-
-import (
- "github.com/pkg/errors"
- "github.com/projectatomic/libpod/oci"
- "golang.org/x/net/context"
-)
-
-// ContainerStop stops a running container with a grace period (i.e., timeout).
-func (c *ContainerServer) ContainerStop(ctx context.Context, container string, timeout int64) (string, error) {
- ctr, err := c.LookupContainer(container)
- if err != nil {
- return "", errors.Wrapf(err, "failed to find container %s", container)
- }
- ctrID := ctr.ID()
-
- cStatus := c.runtime.ContainerStatus(ctr)
- switch cStatus.Status {
-
- case oci.ContainerStatePaused:
- return "", errors.Errorf("cannot stop paused container %s", ctrID)
- default:
- if cStatus.Status != oci.ContainerStateStopped {
- if err := c.runtime.StopContainer(ctx, ctr, timeout); err != nil {
- return "", errors.Wrapf(err, "failed to stop container %s", ctrID)
- }
- if err := c.storageRuntimeServer.StopContainer(ctrID); err != nil {
- return "", errors.Wrapf(err, "failed to unmount container %s", ctrID)
- }
- }
- }
-
- c.ContainerStateToDisk(ctr)
-
- return ctrID, nil
-}
diff --git a/libkpod/wait.go b/libkpod/wait.go
deleted file mode 100644
index e972a0ba0..000000000
--- a/libkpod/wait.go
+++ /dev/null
@@ -1,42 +0,0 @@
-package libkpod
-
-import (
- "github.com/pkg/errors"
- "github.com/projectatomic/libpod/oci"
- "k8s.io/apimachinery/pkg/util/wait"
-)
-
-func isStopped(c *ContainerServer, ctr *oci.Container) bool {
- c.runtime.UpdateStatus(ctr)
- cStatus := c.runtime.ContainerStatus(ctr)
- if cStatus.Status == oci.ContainerStateStopped {
- return true
- }
- return false
-}
-
-// ContainerWait stops a running container with a grace period (i.e., timeout).
-func (c *ContainerServer) ContainerWait(container string) (int32, error) {
- ctr, err := c.LookupContainer(container)
- if err != nil {
- return 0, errors.Wrapf(err, "failed to find container %s", container)
- }
-
- err = wait.PollImmediateInfinite(1,
- func() (bool, error) {
- if !isStopped(c, ctr) {
- return false, nil
- } else { // nolint
- return true, nil // nolint
- } // nolint
-
- },
- )
-
- if err != nil {
- return 0, err
- }
- exitCode := ctr.State().ExitCode
- c.ContainerStateToDisk(ctr)
- return exitCode, nil
-}
diff --git a/oci/container.go b/oci/container.go
deleted file mode 100644
index c0eff2fd1..000000000
--- a/oci/container.go
+++ /dev/null
@@ -1,260 +0,0 @@
-package oci
-
-import (
- "encoding/json"
- "fmt"
- "os"
- "path/filepath"
- "strings"
- "sync"
- "time"
-
- "github.com/containernetworking/plugins/pkg/ns"
- "github.com/docker/docker/pkg/signal"
- specs "github.com/opencontainers/runtime-spec/specs-go"
- "k8s.io/apimachinery/pkg/fields"
- pb "k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
-)
-
-const (
- defaultStopSignal = "TERM"
-)
-
-// Container represents a runtime container.
-type Container struct {
- id string
- name string
- logPath string
- labels fields.Set
- annotations fields.Set
- crioAnnotations fields.Set
- image string
- sandbox string
- netns ns.NetNS
- terminal bool
- stdin bool
- stdinOnce bool
- privileged bool
- trusted bool
- state *ContainerState
- metadata *pb.ContainerMetadata
- opLock sync.Locker
- // this is the /var/run/storage/... directory, erased on reboot
- bundlePath string
- // this is the /var/lib/storage/... directory
- dir string
- stopSignal string
- imageName string
- imageRef string
- volumes []ContainerVolume
- mountPoint string
- spec *specs.Spec
-}
-
-// ContainerVolume is a bind mount for the container.
-type ContainerVolume struct {
- ContainerPath string `json:"container_path"`
- HostPath string `json:"host_path"`
- Readonly bool `json:"readonly"`
-}
-
-// ContainerState represents the status of a container.
-type ContainerState struct {
- specs.State
- Created time.Time `json:"created"`
- Started time.Time `json:"started,omitempty"`
- Finished time.Time `json:"finished,omitempty"`
- ExitCode int32 `json:"exitCode,omitempty"`
- OOMKilled bool `json:"oomKilled,omitempty"`
- Error string `json:"error,omitempty"`
-}
-
-// NewContainer creates a container object.
-func NewContainer(id string, name string, bundlePath string, logPath string, netns ns.NetNS, labels map[string]string, crioAnnotations map[string]string, annotations map[string]string, image string, imageName string, imageRef string, metadata *pb.ContainerMetadata, sandbox string, terminal bool, stdin bool, stdinOnce bool, privileged bool, trusted bool, dir string, created time.Time, stopSignal string) (*Container, error) {
- state := &ContainerState{}
- state.Created = created
- c := &Container{
- id: id,
- name: name,
- bundlePath: bundlePath,
- logPath: logPath,
- labels: labels,
- sandbox: sandbox,
- netns: netns,
- terminal: terminal,
- stdin: stdin,
- stdinOnce: stdinOnce,
- privileged: privileged,
- trusted: trusted,
- metadata: metadata,
- annotations: annotations,
- crioAnnotations: crioAnnotations,
- image: image,
- imageName: imageName,
- imageRef: imageRef,
- dir: dir,
- state: state,
- stopSignal: stopSignal,
- opLock: new(sync.Mutex),
- }
- return c, nil
-}
-
-// SetSpec loads the OCI spec in the container struct
-func (c *Container) SetSpec(s *specs.Spec) {
- c.spec = s
-}
-
-// Spec returns a copy of the spec for the container
-func (c *Container) Spec() specs.Spec {
- return *c.spec
-}
-
-// GetStopSignal returns the container's own stop signal configured from the
-// image configuration or the default one.
-func (c *Container) GetStopSignal() string {
- if c.stopSignal == "" {
- return defaultStopSignal
- }
- cleanSignal := strings.TrimPrefix(strings.ToUpper(c.stopSignal), "SIG")
- _, ok := signal.SignalMap[cleanSignal]
- if !ok {
- return defaultStopSignal
- }
- return cleanSignal
-}
-
-// FromDisk restores container's state from disk
-func (c *Container) FromDisk() error {
- jsonSource, err := os.Open(c.StatePath())
- if err != nil {
- return err
- }
- defer jsonSource.Close()
-
- dec := json.NewDecoder(jsonSource)
- return dec.Decode(c.state)
-}
-
-// StatePath returns the containers state.json path
-func (c *Container) StatePath() string {
- return filepath.Join(c.dir, "state.json")
-}
-
-// CreatedAt returns the container creation time
-func (c *Container) CreatedAt() time.Time {
- return c.state.Created
-}
-
-// Name returns the name of the container.
-func (c *Container) Name() string {
- return c.name
-}
-
-// ID returns the id of the container.
-func (c *Container) ID() string {
- return c.id
-}
-
-// BundlePath returns the bundlePath of the container.
-func (c *Container) BundlePath() string {
- return c.bundlePath
-}
-
-// LogPath returns the log path of the container.
-func (c *Container) LogPath() string {
- return c.logPath
-}
-
-// Labels returns the labels of the container.
-func (c *Container) Labels() map[string]string {
- return c.labels
-}
-
-// Annotations returns the annotations of the container.
-func (c *Container) Annotations() map[string]string {
- return c.annotations
-}
-
-// CrioAnnotations returns the crio annotations of the container.
-func (c *Container) CrioAnnotations() map[string]string {
- return c.crioAnnotations
-}
-
-// Image returns the image of the container.
-func (c *Container) Image() string {
- return c.image
-}
-
-// ImageName returns the image name of the container.
-func (c *Container) ImageName() string {
- return c.imageName
-}
-
-// ImageRef returns the image ref of the container.
-func (c *Container) ImageRef() string {
- return c.imageRef
-}
-
-// Sandbox returns the sandbox name of the container.
-func (c *Container) Sandbox() string {
- return c.sandbox
-}
-
-// Dir returns the the dir of the container
-func (c *Container) Dir() string {
- return c.dir
-}
-
-// NetNsPath returns the path to the network namespace of the container.
-func (c *Container) NetNsPath() (string, error) {
- if c.state == nil {
- return "", fmt.Errorf("container state is not populated")
- }
-
- if c.netns == nil {
- return fmt.Sprintf("/proc/%d/ns/net", c.state.Pid), nil
- }
-
- return c.netns.Path(), nil
-}
-
-// Metadata returns the metadata of the container.
-func (c *Container) Metadata() *pb.ContainerMetadata {
- return c.metadata
-}
-
-// State returns the state of the running container
-func (c *Container) State() *ContainerState {
- c.opLock.Lock()
- defer c.opLock.Unlock()
- return c.state
-}
-
-// AddVolume adds a volume to list of container volumes.
-func (c *Container) AddVolume(v ContainerVolume) {
- c.volumes = append(c.volumes, v)
-}
-
-// Volumes returns the list of container volumes.
-func (c *Container) Volumes() []ContainerVolume {
- return c.volumes
-
-}
-
-// SetMountPoint sets the container mount point
-func (c *Container) SetMountPoint(mp string) {
- c.mountPoint = mp
-}
-
-// MountPoint returns the container mount point
-func (c *Container) MountPoint() string {
- return c.mountPoint
-}
-
-// SetState sets the conainer state
-//
-// XXX: DO NOT EVER USE THIS, THIS IS JUST USEFUL FOR MOCKING!!!
-func (c *Container) SetState(state *ContainerState) {
- c.state = state
-}
diff --git a/oci/finished.go b/oci/finished.go
deleted file mode 100644
index 9fedbfb7a..000000000
--- a/oci/finished.go
+++ /dev/null
@@ -1,14 +0,0 @@
-// +build !arm,!386
-
-package oci
-
-import (
- "os"
- "syscall"
- "time"
-)
-
-func getFinishedTime(fi os.FileInfo) time.Time {
- st := fi.Sys().(*syscall.Stat_t)
- return time.Unix(st.Ctim.Sec, st.Ctim.Nsec)
-}
diff --git a/oci/finished_32.go b/oci/finished_32.go
deleted file mode 100644
index 3f24b1baa..000000000
--- a/oci/finished_32.go
+++ /dev/null
@@ -1,14 +0,0 @@
-// +build arm 386
-
-package oci
-
-import (
- "os"
- "syscall"
- "time"
-)
-
-func getFinishedTime(fi os.FileInfo) time.Time {
- st := fi.Sys().(*syscall.Stat_t)
- return time.Unix(int64(st.Ctim.Sec), int64(st.Ctim.Nsec))
-}
diff --git a/oci/history.go b/oci/history.go
deleted file mode 100644
index 2ced41d61..000000000
--- a/oci/history.go
+++ /dev/null
@@ -1,31 +0,0 @@
-package oci
-
-import "sort"
-
-// History is a convenience type for storing a list of containers,
-// sorted by creation date in descendant order.
-type History []*Container
-
-// Len returns the number of containers in the history.
-func (history *History) Len() int {
- return len(*history)
-}
-
-// Less compares two containers and returns true if the second one
-// was created before the first one.
-func (history *History) Less(i, j int) bool {
- containers := *history
- // FIXME: state access should be serialized
- return containers[j].state.Created.Before(containers[i].state.Created)
-}
-
-// Swap switches containers i and j positions in the history.
-func (history *History) Swap(i, j int) {
- containers := *history
- containers[i], containers[j] = containers[j], containers[i]
-}
-
-// sort orders the history by creation date in descendant order.
-func (history *History) sort() {
- sort.Sort(history)
-}
diff --git a/oci/memory_store.go b/oci/memory_store.go
deleted file mode 100644
index 6223ce7f0..000000000
--- a/oci/memory_store.go
+++ /dev/null
@@ -1,92 +0,0 @@
-package oci
-
-import "sync"
-
-// memoryStore implements a Store in memory.
-type memoryStore struct {
- s map[string]*Container
- sync.RWMutex
-}
-
-// NewMemoryStore initializes a new memory store.
-func NewMemoryStore() ContainerStorer {
- return &memoryStore{
- s: make(map[string]*Container),
- }
-}
-
-// Add appends a new container to the memory store.
-// It overrides the id if it existed before.
-func (c *memoryStore) Add(id string, cont *Container) {
- c.Lock()
- c.s[id] = cont
- c.Unlock()
-}
-
-// Get returns a container from the store by id.
-func (c *memoryStore) Get(id string) *Container {
- c.RLock()
- res := c.s[id]
- c.RUnlock()
- return res
-}
-
-// Delete removes a container from the store by id.
-func (c *memoryStore) Delete(id string) {
- c.Lock()
- delete(c.s, id)
- c.Unlock()
-}
-
-// List returns a sorted list of containers from the store.
-// The containers are ordered by creation date.
-func (c *memoryStore) List() []*Container {
- containers := History(c.all())
- containers.sort()
- return containers
-}
-
-// Size returns the number of containers in the store.
-func (c *memoryStore) Size() int {
- c.RLock()
- defer c.RUnlock()
- return len(c.s)
-}
-
-// First returns the first container found in the store by a given filter.
-func (c *memoryStore) First(filter StoreFilter) *Container {
- for _, cont := range c.all() {
- if filter(cont) {
- return cont
- }
- }
- return nil
-}
-
-// ApplyAll calls the reducer function with every container in the store.
-// This operation is asynchronous in the memory store.
-// NOTE: Modifications to the store MUST NOT be done by the StoreReducer.
-func (c *memoryStore) ApplyAll(apply StoreReducer) {
- wg := new(sync.WaitGroup)
- for _, cont := range c.all() {
- wg.Add(1)
- go func(container *Container) {
- apply(container)
- wg.Done()
- }(cont)
- }
-
- wg.Wait()
-}
-
-func (c *memoryStore) all() []*Container {
- c.RLock()
- containers := make([]*Container, 0, len(c.s))
- for _, cont := range c.s {
- containers = append(containers, cont)
- }
- c.RUnlock()
- return containers
-}
-
-var _ ContainerStorer = &memoryStore{}
diff --git a/oci/oci.go b/oci/oci.go
deleted file mode 100644
index 2e7e44b84..000000000
--- a/oci/oci.go
+++ /dev/null
@@ -1,748 +0,0 @@
-package oci
-
-import (
- "bytes"
- "encoding/json"
- "fmt"
- "io/ioutil"
- "os"
- "os/exec"
- "path/filepath"
- "strconv"
- "strings"
- "syscall"
- "time"
-
- "github.com/containerd/cgroups"
- rspec "github.com/opencontainers/runtime-spec/specs-go"
- "github.com/projectatomic/libpod/utils"
- "github.com/sirupsen/logrus"
- "golang.org/x/net/context"
- "golang.org/x/sys/unix"
- kwait "k8s.io/apimachinery/pkg/util/wait"
-)
-
-const (
- // ContainerStateCreated represents the created state of a container
- ContainerStateCreated = "created"
- // ContainerStatePaused represents the paused state of a container
- ContainerStatePaused = "paused"
- // ContainerStateRunning represents the running state of a container
- ContainerStateRunning = "running"
- // ContainerStateStopped represents the stopped state of a container
- ContainerStateStopped = "stopped"
- // ContainerCreateTimeout represents the value of container creating timeout
- ContainerCreateTimeout = 240 * time.Second
-
- // CgroupfsCgroupsManager represents cgroupfs native cgroup manager
- CgroupfsCgroupsManager = "cgroupfs"
- // SystemdCgroupsManager represents systemd native cgroup manager
- SystemdCgroupsManager = "systemd"
- // ContainerExitsDir is the location of container exit dirs
- ContainerExitsDir = "/var/run/crio/exits"
- // ContainerAttachSocketDir is the location for container attach sockets
- ContainerAttachSocketDir = "/var/run/crio"
-
- // killContainerTimeout is the timeout that we wait for the container to
- // be SIGKILLed.
- killContainerTimeout = 2 * time.Minute
-)
-
-// New creates a new Runtime with options provided
-func New(runtimeTrustedPath string,
- runtimeUntrustedPath string,
- trustLevel string,
- conmonPath string,
- conmonEnv []string,
- cgroupManager string,
- containerExitsDir string,
- logSizeMax int64,
- noPivot bool) (*Runtime, error) {
- r := &Runtime{
- name: filepath.Base(runtimeTrustedPath),
- trustedPath: runtimeTrustedPath,
- untrustedPath: runtimeUntrustedPath,
- trustLevel: trustLevel,
- conmonPath: conmonPath,
- conmonEnv: conmonEnv,
- cgroupManager: cgroupManager,
- containerExitsDir: containerExitsDir,
- logSizeMax: logSizeMax,
- noPivot: noPivot,
- }
- return r, nil
-}
-
-// Runtime stores the information about a oci runtime
-type Runtime struct {
- name string
- trustedPath string
- untrustedPath string
- trustLevel string
- conmonPath string
- conmonEnv []string
- cgroupManager string
- containerExitsDir string
- logSizeMax int64
- noPivot bool
-}
-
-// syncInfo is used to return data from monitor process to daemon
-type syncInfo struct {
- Pid int `json:"pid"`
- Message string `json:"message,omitempty"`
-}
-
-// exitCodeInfo is used to return the monitored process exit code to the daemon
-type exitCodeInfo struct {
- ExitCode int32 `json:"exit_code"`
- Message string `json:"message,omitempty"`
-}
-
-// Name returns the name of the OCI Runtime
-func (r *Runtime) Name() string {
- return r.name
-}
-
-// Path returns the full path the OCI Runtime executable.
-// Depending if the container is privileged and/or trusted,
-// this will return either the trusted or untrusted runtime path.
-func (r *Runtime) Path(c *Container) string {
- if !c.trusted {
- // We have an explicitly untrusted container.
- if c.privileged {
- logrus.Warnf("Running an untrusted but privileged container")
- return r.trustedPath
- }
-
- if r.untrustedPath != "" {
- return r.untrustedPath
- }
-
- return r.trustedPath
- }
-
- // Our container is trusted. Let's look at the configured trust level.
- if r.trustLevel == "trusted" {
- return r.trustedPath
- }
-
- // Our container is trusted, but we are running untrusted.
- // We will use the untrusted container runtime if it's set
- // and if it's not a privileged container.
- if c.privileged || r.untrustedPath == "" {
- return r.trustedPath
- }
-
- return r.untrustedPath
-}
-
-// Version returns the version of the OCI Runtime
-func (r *Runtime) Version() (string, error) {
- runtimeVersion, err := getOCIVersion(r.trustedPath, "-v")
- if err != nil {
- return "", err
- }
- return runtimeVersion, nil
-}
-
-func getOCIVersion(name string, args ...string) (string, error) {
- out, err := utils.ExecCmd(name, args...)
- if err != nil {
- return "", err
- }
-
- firstLine := out[:strings.Index(out, "\n")]
- v := firstLine[strings.LastIndex(firstLine, " ")+1:]
- return v, nil
-}
-
-// CreateContainer creates a container.
-func (r *Runtime) CreateContainer(c *Container, cgroupParent string) (err error) {
- var stderrBuf bytes.Buffer
- parentPipe, childPipe, err := newPipe()
- childStartPipe, parentStartPipe, err := newPipe()
- if err != nil {
- return fmt.Errorf("error creating socket pair: %v", err)
- }
- defer parentPipe.Close()
- defer parentStartPipe.Close()
-
- var args []string
- if r.cgroupManager == SystemdCgroupsManager {
- args = append(args, "-s")
- }
- args = append(args, "-c", c.id)
- args = append(args, "-u", c.id)
- args = append(args, "-r", r.Path(c))
- args = append(args, "-b", c.bundlePath)
- args = append(args, "-p", filepath.Join(c.bundlePath, "pidfile"))
- args = append(args, "-l", c.logPath)
- args = append(args, "--exit-dir", r.containerExitsDir)
- args = append(args, "--socket-dir-path", ContainerAttachSocketDir)
- if r.logSizeMax >= 0 {
- args = append(args, "--log-size-max", fmt.Sprintf("%v", r.logSizeMax))
- }
- if r.noPivot {
- args = append(args, "--no-pivot")
- }
- if c.terminal {
- args = append(args, "-t")
- } else if c.stdin {
- args = append(args, "-i")
- }
- logrus.WithFields(logrus.Fields{
- "args": args,
- }).Debugf("running conmon: %s", r.conmonPath)
-
- cmd := exec.Command(r.conmonPath, args...)
- cmd.Dir = c.bundlePath
- cmd.SysProcAttr = &syscall.SysProcAttr{
- Setpgid: true,
- }
- cmd.Stdin = os.Stdin
- cmd.Stdout = os.Stdout
- cmd.Stderr = os.Stderr
- if c.terminal {
- cmd.Stderr = &stderrBuf
- }
- cmd.ExtraFiles = append(cmd.ExtraFiles, childPipe, childStartPipe)
- // 0, 1 and 2 are stdin, stdout and stderr
- cmd.Env = append(r.conmonEnv, fmt.Sprintf("_OCI_SYNCPIPE=%d", 3))
- cmd.Env = append(cmd.Env, fmt.Sprintf("_OCI_STARTPIPE=%d", 4))
-
- err = cmd.Start()
- if err != nil {
- childPipe.Close()
- return err
- }
-
- // We don't need childPipe on the parent side
- childPipe.Close()
- childStartPipe.Close()
-
- // Move conmon to specified cgroup
- if r.cgroupManager == SystemdCgroupsManager {
- logrus.Infof("Running conmon under slice %s and unitName %s", cgroupParent, createUnitName("crio-conmon", c.id))
- if err = utils.RunUnderSystemdScope(cmd.Process.Pid, cgroupParent, createUnitName("crio-conmon", c.id)); err != nil {
- logrus.Warnf("Failed to add conmon to systemd sandbox cgroup: %v", err)
- }
- } else {
- control, err := cgroups.New(cgroups.V1, cgroups.StaticPath(filepath.Join(cgroupParent, "/crio-conmon-"+c.id)), &rspec.LinuxResources{})
- if err != nil {
- logrus.Warnf("Failed to add conmon to cgroupfs sandbox cgroup: %v", err)
- } else {
- // Here we should defer a crio-connmon- cgroup hierarchy deletion, but it will
- // always fail as conmon's pid is still there.
- // Fortunately, kubelet takes care of deleting this for us, so the leak will
- // only happens in corner case where one does a manual deletion of the container
- // through e.g. runc. This should be handled by implementing a conmon monitoring
- // routine that does the cgroup cleanup once conmon is terminated.
- if err := control.Add(cgroups.Process{Pid: cmd.Process.Pid}); err != nil {
- logrus.Warnf("Failed to add conmon to cgroupfs sandbox cgroup: %v", err)
- }
- }
- }
-
- /* We set the cgroup, now the child can start creating children */
- someData := []byte{0}
- _, err = parentStartPipe.Write(someData)
- if err != nil {
- return err
- }
-
- /* Wait for initial setup and fork, and reap child */
- err = cmd.Wait()
- if err != nil {
- return err
- }
-
- // We will delete all container resources if creation fails
- defer func() {
- if err != nil {
- r.DeleteContainer(c)
- }
- }()
-
- // Wait to get container pid from conmon
- type syncStruct struct {
- si *syncInfo
- err error
- }
- ch := make(chan syncStruct)
- go func() {
- var si *syncInfo
- if err = json.NewDecoder(parentPipe).Decode(&si); err != nil {
- ch <- syncStruct{err: err}
- return
- }
- ch <- syncStruct{si: si}
- }()
-
- select {
- case ss := <-ch:
- if ss.err != nil {
- return fmt.Errorf("error reading container (probably exited) json message: %v", ss.err)
- }
- logrus.Debugf("Received container pid: %d", ss.si.Pid)
- if ss.si.Pid == -1 {
- if ss.si.Message != "" {
- logrus.Errorf("Container creation error: %s", ss.si.Message)
- return fmt.Errorf("container create failed: %s", ss.si.Message)
- }
- logrus.Errorf("Container creation failed")
- return fmt.Errorf("container create failed")
- }
- case <-time.After(ContainerCreateTimeout):
- logrus.Errorf("Container creation timeout (%v)", ContainerCreateTimeout)
- return fmt.Errorf("create container timeout")
- }
- return nil
-}
-
-func createUnitName(prefix string, name string) string {
- return fmt.Sprintf("%s-%s.scope", prefix, name)
-}
-
-// StartContainer starts a container.
-func (r *Runtime) StartContainer(c *Container) error {
- c.opLock.Lock()
- defer c.opLock.Unlock()
- if err := utils.ExecCmdWithStdStreams(os.Stdin, os.Stdout, os.Stderr, r.Path(c), "start", c.id); err != nil {
- return err
- }
- c.state.Started = time.Now()
- return nil
-}
-
-// ExecSyncResponse is returned from ExecSync.
-type ExecSyncResponse struct {
- Stdout []byte
- Stderr []byte
- ExitCode int32
-}
-
-// ExecSyncError wraps command's streams, exit code and error on ExecSync error.
-type ExecSyncError struct {
- Stdout bytes.Buffer
- Stderr bytes.Buffer
- ExitCode int32
- Err error
-}
-
-func (e ExecSyncError) Error() string {
- return fmt.Sprintf("command error: %+v, stdout: %s, stderr: %s, exit code %d", e.Err, e.Stdout.Bytes(), e.Stderr.Bytes(), e.ExitCode)
-}
-
-func prepareExec() (pidFile, parentPipe, childPipe *os.File, err error) {
- parentPipe, childPipe, err = os.Pipe()
- if err != nil {
- return nil, nil, nil, err
- }
-
- pidFile, err = ioutil.TempFile("", "pidfile")
- if err != nil {
- parentPipe.Close()
- childPipe.Close()
- return nil, nil, nil, err
- }
-
- return
-}
-
-func parseLog(log []byte) (stdout, stderr []byte) {
- // Split the log on newlines, which is what separates entries.
- lines := bytes.SplitAfter(log, []byte{'\n'})
- for _, line := range lines {
- // Ignore empty lines.
- if len(line) == 0 {
- continue
- }
-
- // The format of log lines is "DATE pipe REST".
- parts := bytes.SplitN(line, []byte{' '}, 3)
- if len(parts) < 3 {
- // Ignore the line if it's formatted incorrectly, but complain
- // about it so it can be debugged.
- logrus.Warnf("hit invalid log format: %q", string(line))
- continue
- }
-
- pipe := string(parts[1])
- content := parts[2]
-
- switch pipe {
- case "stdout":
- stdout = append(stdout, content...)
- case "stderr":
- stderr = append(stderr, content...)
- default:
- // Complain about unknown pipes.
- logrus.Warnf("hit invalid log format [unknown pipe %s]: %q", pipe, string(line))
- continue
- }
- }
-
- return stdout, stderr
-}
-
-// ExecSync execs a command in a container and returns it's stdout, stderr and return code.
-func (r *Runtime) ExecSync(c *Container, command []string, timeout int64) (resp *ExecSyncResponse, err error) {
- pidFile, parentPipe, childPipe, err := prepareExec()
- if err != nil {
- return nil, ExecSyncError{
- ExitCode: -1,
- Err: err,
- }
- }
- defer parentPipe.Close()
- defer func() {
- if e := os.Remove(pidFile.Name()); e != nil {
- logrus.Warnf("could not remove temporary PID file %s", pidFile.Name())
- }
- }()
-
- logFile, err := ioutil.TempFile("", "crio-log-"+c.id)
- if err != nil {
- return nil, ExecSyncError{
- ExitCode: -1,
- Err: err,
- }
- }
- logPath := logFile.Name()
- defer func() {
- logFile.Close()
- os.RemoveAll(logPath)
- }()
-
- f, err := ioutil.TempFile("", "exec-process")
- if err != nil {
- return nil, ExecSyncError{
- ExitCode: -1,
- Err: err,
- }
- }
- defer os.RemoveAll(f.Name())
-
- var args []string
- args = append(args, "-c", c.id)
- args = append(args, "-r", r.Path(c))
- args = append(args, "-p", pidFile.Name())
- args = append(args, "-e")
- if c.terminal {
- args = append(args, "-t")
- }
- if timeout > 0 {
- args = append(args, "-T")
- args = append(args, fmt.Sprintf("%d", timeout))
- }
- args = append(args, "-l", logPath)
- args = append(args, "--socket-dir-path", ContainerAttachSocketDir)
-
- pspec := c.Spec().Process
- pspec.Env = append(pspec.Env, r.conmonEnv...)
- pspec.Args = command
- processJSON, err := json.Marshal(pspec)
- if err != nil {
- return nil, ExecSyncError{
- ExitCode: -1,
- Err: err,
- }
- }
-
- if err := ioutil.WriteFile(f.Name(), processJSON, 0644); err != nil {
- return nil, ExecSyncError{
- ExitCode: -1,
- Err: err,
- }
- }
-
- args = append(args, "--exec-process-spec", f.Name())
-
- cmd := exec.Command(r.conmonPath, args...)
-
- var stdoutBuf, stderrBuf bytes.Buffer
- cmd.Stdout = &stdoutBuf
- cmd.Stderr = &stderrBuf
- cmd.ExtraFiles = append(cmd.ExtraFiles, childPipe)
- // 0, 1 and 2 are stdin, stdout and stderr
- cmd.Env = append(r.conmonEnv, fmt.Sprintf("_OCI_SYNCPIPE=%d", 3))
-
- err = cmd.Start()
- if err != nil {
- childPipe.Close()
- return nil, ExecSyncError{
- Stdout: stdoutBuf,
- Stderr: stderrBuf,
- ExitCode: -1,
- Err: err,
- }
- }
-
- // We don't need childPipe on the parent side
- childPipe.Close()
-
- err = cmd.Wait()
- if err != nil {
- if exitErr, ok := err.(*exec.ExitError); ok {
- if status, ok := exitErr.Sys().(unix.WaitStatus); ok {
- return nil, ExecSyncError{
- Stdout: stdoutBuf,
- Stderr: stderrBuf,
- ExitCode: int32(status.ExitStatus()),
- Err: err,
- }
- }
- } else {
- return nil, ExecSyncError{
- Stdout: stdoutBuf,
- Stderr: stderrBuf,
- ExitCode: -1,
- Err: err,
- }
- }
- }
-
- var ec *exitCodeInfo
- if err := json.NewDecoder(parentPipe).Decode(&ec); err != nil {
- return nil, ExecSyncError{
- Stdout: stdoutBuf,
- Stderr: stderrBuf,
- ExitCode: -1,
- Err: err,
- }
- }
-
- logrus.Infof("Received container exit code: %v, message: %s", ec.ExitCode, ec.Message)
-
- if ec.ExitCode == -1 {
- return nil, ExecSyncError{
- Stdout: stdoutBuf,
- Stderr: stderrBuf,
- ExitCode: -1,
- Err: fmt.Errorf(ec.Message),
- }
- }
-
- // The actual logged output is not the same as stdoutBuf and stderrBuf,
- // which are used for getting error information. For the actual
- // ExecSyncResponse we have to read the logfile.
- // XXX: Currently runC dups the same console over both stdout and stderr,
- // so we can't differentiate between the two.
-
- logBytes, err := ioutil.ReadFile(logPath)
- if err != nil {
- return nil, ExecSyncError{
- Stdout: stdoutBuf,
- Stderr: stderrBuf,
- ExitCode: -1,
- Err: err,
- }
- }
-
- // We have to parse the log output into {stdout, stderr} buffers.
- stdoutBytes, stderrBytes := parseLog(logBytes)
- return &ExecSyncResponse{
- Stdout: stdoutBytes,
- Stderr: stderrBytes,
- ExitCode: ec.ExitCode,
- }, nil
-}
-
-func waitContainerStop(ctx context.Context, c *Container, timeout time.Duration) error {
- done := make(chan struct{})
- // we could potentially re-use "done" channel to exit the loop on timeout
- // but we use another channel "chControl" so that we won't never incur in the
- // case the "done" channel is closed in the "default" select case and we also
- // reach the timeout in the select below. If that happens we could raise
- // a panic closing a closed channel so better be safe and use another new
- // channel just to control the loop.
- chControl := make(chan struct{})
- go func() {
- for {
- select {
- case <-chControl:
- return
- default:
- // Check if the process is still around
- err := unix.Kill(c.state.Pid, 0)
- if err == unix.ESRCH {
- close(done)
- return
- }
- time.Sleep(100 * time.Millisecond)
- }
- }
- }()
- select {
- case <-done:
- return nil
- case <-ctx.Done():
- close(chControl)
- return ctx.Err()
- case <-time.After(timeout):
- close(chControl)
- err := unix.Kill(c.state.Pid, unix.SIGKILL)
- if err != nil && err != unix.ESRCH {
- return fmt.Errorf("failed to kill process: %v", err)
- }
- }
-
- c.state.Finished = time.Now()
- return nil
-}
-
-// StopContainer stops a container. Timeout is given in seconds.
-func (r *Runtime) StopContainer(ctx context.Context, c *Container, timeout int64) error {
- c.opLock.Lock()
- defer c.opLock.Unlock()
-
- // Check if the process is around before sending a signal
- err := unix.Kill(c.state.Pid, 0)
- if err == unix.ESRCH {
- c.state.Finished = time.Now()
- return nil
- }
-
- if timeout > 0 {
- if err := utils.ExecCmdWithStdStreams(os.Stdin, os.Stdout, os.Stderr, r.Path(c), "kill", c.id, c.GetStopSignal()); err != nil {
- return fmt.Errorf("failed to stop container %s, %v", c.id, err)
- }
- err = waitContainerStop(ctx, c, time.Duration(timeout)*time.Second)
- if err == nil {
- return nil
- }
- logrus.Warnf("Stop container %q timed out: %v", c.ID(), err)
- }
-
- if err := utils.ExecCmdWithStdStreams(os.Stdin, os.Stdout, os.Stderr, r.Path(c), "kill", "--all", c.id, "KILL"); err != nil {
- return fmt.Errorf("failed to stop container %s, %v", c.id, err)
- }
-
- return waitContainerStop(ctx, c, killContainerTimeout)
-}
-
-// DeleteContainer deletes a container.
-func (r *Runtime) DeleteContainer(c *Container) error {
- c.opLock.Lock()
- defer c.opLock.Unlock()
- _, err := utils.ExecCmd(r.Path(c), "delete", "--force", c.id)
- return err
-}
-
-// SetStartFailed sets the container state appropriately after a start failure
-func (r *Runtime) SetStartFailed(c *Container, err error) {
- c.opLock.Lock()
- defer c.opLock.Unlock()
- // adjust finished and started times
- c.state.Finished, c.state.Started = c.state.Created, c.state.Created
- c.state.Error = err.Error()
-}
-
-// UpdateStatus refreshes the status of the container.
-func (r *Runtime) UpdateStatus(c *Container) error {
- c.opLock.Lock()
- defer c.opLock.Unlock()
- out, err := exec.Command(r.Path(c), "state", c.id).CombinedOutput()
- if err != nil {
- // there are many code paths that could lead to have a bad state in the
- // underlying runtime.
- // On any error like a container went away or we rebooted and containers
- // went away we do not error out stopping kubernetes to recover.
- // We always populate the fields below so kube can restart/reschedule
- // containers failing.
- c.state.Status = ContainerStateStopped
- c.state.Finished = time.Now()
- c.state.ExitCode = 255
- return nil
- }
- if err := json.NewDecoder(bytes.NewBuffer(out)).Decode(&c.state); err != nil {
- return fmt.Errorf("failed to decode container status for %s: %s", c.id, err)
- }
-
- if c.state.Status == ContainerStateStopped {
- exitFilePath := filepath.Join(r.containerExitsDir, c.id)
- var fi os.FileInfo
- err = kwait.ExponentialBackoff(
- kwait.Backoff{
- Duration: 500 * time.Millisecond,
- Factor: 1.2,
- Steps: 6,
- },
- func() (bool, error) {
- var err error
- fi, err = os.Stat(exitFilePath)
- if err != nil {
- // wait longer
- return false, nil
- }
- return true, nil
- })
- if err != nil {
- logrus.Warnf("failed to find container exit file: %v", err)
- c.state.ExitCode = -1
- } else {
- c.state.Finished = getFinishedTime(fi)
- statusCodeStr, err := ioutil.ReadFile(exitFilePath)
- if err != nil {
- return fmt.Errorf("failed to read exit file: %v", err)
- }
- statusCode, err := strconv.Atoi(string(statusCodeStr))
- if err != nil {
- return fmt.Errorf("status code conversion failed: %v", err)
- }
- c.state.ExitCode = int32(statusCode)
- }
-
- oomFilePath := filepath.Join(c.bundlePath, "oom")
- if _, err = os.Stat(oomFilePath); err == nil {
- c.state.OOMKilled = true
- }
- }
-
- return nil
-}
-
-// ContainerStatus returns the state of a container.
-func (r *Runtime) ContainerStatus(c *Container) *ContainerState {
- c.opLock.Lock()
- defer c.opLock.Unlock()
- return c.state
-}
-
-// newPipe creates a unix socket pair for communication
-func newPipe() (parent *os.File, child *os.File, err error) {
- fds, err := unix.Socketpair(unix.AF_LOCAL, unix.SOCK_STREAM|unix.SOCK_CLOEXEC, 0)
- if err != nil {
- return nil, nil, err
- }
- return os.NewFile(uintptr(fds[1]), "parent"), os.NewFile(uintptr(fds[0]), "child"), nil
-}
-
-// RuntimeReady checks if the runtime is up and ready to accept
-// basic containers e.g. container only needs host network.
-func (r *Runtime) RuntimeReady() (bool, error) {
- return true, nil
-}
-
-// NetworkReady checks if the runtime network is up and ready to
-// accept containers which require container network.
-func (r *Runtime) NetworkReady() (bool, error) {
- return true, nil
-}
-
-// PauseContainer pauses a container.
-func (r *Runtime) PauseContainer(c *Container) error {
- c.opLock.Lock()
- defer c.opLock.Unlock()
- _, err := utils.ExecCmd(r.Path(c), "pause", c.id)
- return err
-}
-
-// UnpauseContainer unpauses a container.
-func (r *Runtime) UnpauseContainer(c *Container) error {
- c.opLock.Lock()
- defer c.opLock.Unlock()
- _, err := utils.ExecCmd(r.Path(c), "resume", c.id)
- return err
-}
diff --git a/oci/store.go b/oci/store.go
deleted file mode 100644
index 1d27a0f9e..000000000
--- a/oci/store.go
+++ /dev/null
@@ -1,27 +0,0 @@
-package oci
-
-// StoreFilter defines a function to filter
-// container in the store.
-type StoreFilter func(*Container) bool
-
-// StoreReducer defines a function to
-// manipulate containers in the store
-type StoreReducer func(*Container)
-
-// ContainerStorer defines an interface that any container store must implement.
-type ContainerStorer interface {
- // Add appends a new container to the store.
- Add(string, *Container)
- // Get returns a container from the store by the identifier it was stored with.
- Get(string) *Container
- // Delete removes a container from the store by the identifier it was stored with.
- Delete(string)
- // List returns a list of containers from the store.
- List() []*Container
- // Size returns the number of containers in the store.
- Size() int
- // First returns the first container found in the store by a given filter.
- First(StoreFilter) *Container
- // ApplyAll calls the reducer function with every container in the store.
- ApplyAll(StoreReducer)
-}