aboutsummaryrefslogtreecommitdiff
path: root/libpod
diff options
context:
space:
mode:
Diffstat (limited to 'libpod')
-rw-r--r--libpod/container.go12
-rw-r--r--libpod/container_darwin.go14
-rw-r--r--libpod/container_internal.go43
-rw-r--r--libpod/container_internal_linux.go52
-rw-r--r--libpod/container_internal_unsupported.go7
-rw-r--r--libpod/container_linux.go23
-rw-r--r--libpod/container_windows.go14
-rw-r--r--libpod/errors.go4
-rw-r--r--libpod/networking_linux.go (renamed from libpod/networking.go)16
-rw-r--r--libpod/oci.go27
-rw-r--r--libpod/oci_linux.go41
-rw-r--r--libpod/oci_unsupported.go7
-rw-r--r--libpod/runtime_pod.go246
-rw-r--r--libpod/runtime_pod_linux.go249
-rw-r--r--libpod/runtime_pod_unsupported.go16
-rw-r--r--libpod/stats.go35
-rw-r--r--libpod/stats_config.go18
-rw-r--r--libpod/stats_unsupported.go8
18 files changed, 482 insertions, 350 deletions
diff --git a/libpod/container.go b/libpod/container.go
index b7189ae0b..2931aee30 100644
--- a/libpod/container.go
+++ b/libpod/container.go
@@ -8,7 +8,6 @@ import (
"github.com/containernetworking/cni/pkg/types"
cnitypes "github.com/containernetworking/cni/pkg/types/current"
- "github.com/containernetworking/plugins/pkg/ns"
"github.com/containers/storage"
"github.com/cri-o/ocicni/pkg/ocicni"
spec "github.com/opencontainers/runtime-spec/specs-go"
@@ -141,10 +140,6 @@ type containerState struct {
OOMKilled bool `json:"oomKilled,omitempty"`
// PID is the PID of a running container
PID int `json:"pid,omitempty"`
- // NetNSPath is the path of the container's network namespace
- // Will only be set if config.CreateNetNS is true, or the container was
- // told to join another container's network namespace
- NetNS ns.NetNS `json:"-"`
// ExecSessions contains active exec sessions for container
// Exec session ID is mapped to PID of exec process
ExecSessions map[string]*ExecSession `json:"execSessions,omitempty"`
@@ -177,6 +172,13 @@ type containerState struct {
// ExtensionStageHooks holds hooks which will be executed by libpod
// and not delegated to the OCI runtime.
ExtensionStageHooks map[string][]spec.Hook `json:"extensionStageHooks,omitempty"`
+
+ // Special container state attributes for Linux
+ containerStateLinux
+ // Special container state attributes for Windows
+ containerStateWindows
+ // Special container state attributes for Darwin
+ containerStateDarwin
}
// ExecSession contains information on an active exec session
diff --git a/libpod/container_darwin.go b/libpod/container_darwin.go
new file mode 100644
index 000000000..948ed9f2a
--- /dev/null
+++ b/libpod/container_darwin.go
@@ -0,0 +1,14 @@
+// +build darwin
+
+package libpod
+
+type containerStateDarwin struct {
+}
+
+// containerStateLinux is intentionally left as a blank stub
+type containerStateLinux struct {
+}
+
+// containerStateWindows is intentionally left as a blank stub
+type containerStateWindows struct {
+}
diff --git a/libpod/container_internal.go b/libpod/container_internal.go
index 07bb5c6d1..22b398709 100644
--- a/libpod/container_internal.go
+++ b/libpod/container_internal.go
@@ -14,7 +14,6 @@ import (
"syscall"
"time"
- "github.com/containerd/cgroups"
"github.com/containers/storage"
"github.com/containers/storage/pkg/archive"
"github.com/containers/storage/pkg/chrootarchive"
@@ -810,47 +809,6 @@ func (c *Container) prepare() (err error) {
return nil
}
-// cleanupCgroup cleans up residual CGroups after container execution
-// This is a no-op for the systemd cgroup driver
-func (c *Container) cleanupCgroups() error {
- if !c.state.CgroupCreated {
- logrus.Debugf("Cgroups are not present, ignoring...")
- return nil
- }
-
- if c.runtime.config.CgroupManager == SystemdCgroupsManager {
- return nil
- }
-
- // Remove the base path of the container's cgroups
- path := filepath.Join(c.config.CgroupParent, fmt.Sprintf("libpod-%s", c.ID()))
-
- logrus.Debugf("Removing CGroup %s", path)
-
- cgroup, err := cgroups.Load(cgroups.V1, cgroups.StaticPath(path))
- if err != nil {
- // It's fine for the cgroup to not exist
- // We want it gone, it's gone
- if err == cgroups.ErrCgroupDeleted {
- return nil
- }
-
- return err
- }
-
- if err := cgroup.Delete(); err != nil {
- return err
- }
-
- c.state.CgroupCreated = false
-
- if c.valid {
- return c.save()
- }
-
- return nil
-}
-
// cleanupNetwork unmounts and cleans up the container's network
func (c *Container) cleanupNetwork() error {
if c.state.NetNS == nil {
@@ -1258,6 +1216,7 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) {
return nil, errors.Wrapf(err, "error setting up OCI Hooks")
}
}
+
// Bind builtin image volumes
if c.config.Rootfs == "" && c.config.ImageVolumes {
if err := c.addImageVolumes(ctx, &g); err != nil {
diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go
new file mode 100644
index 000000000..41b8a86fc
--- /dev/null
+++ b/libpod/container_internal_linux.go
@@ -0,0 +1,52 @@
+// +build linux
+
+package libpod
+
+import (
+ "fmt"
+ "path/filepath"
+
+ "github.com/containerd/cgroups"
+ "github.com/sirupsen/logrus"
+)
+
+// cleanupCgroup cleans up residual CGroups after container execution
+// This is a no-op for the systemd cgroup driver
+func (c *Container) cleanupCgroups() error {
+ if !c.state.CgroupCreated {
+ logrus.Debugf("Cgroups are not present, ignoring...")
+ return nil
+ }
+
+ if c.runtime.config.CgroupManager == SystemdCgroupsManager {
+ return nil
+ }
+
+ // Remove the base path of the container's cgroups
+ path := filepath.Join(c.config.CgroupParent, fmt.Sprintf("libpod-%s", c.ID()))
+
+ logrus.Debugf("Removing CGroup %s", path)
+
+ cgroup, err := cgroups.Load(cgroups.V1, cgroups.StaticPath(path))
+ if err != nil {
+ // It's fine for the cgroup to not exist
+ // We want it gone, it's gone
+ if err == cgroups.ErrCgroupDeleted {
+ return nil
+ }
+
+ return err
+ }
+
+ if err := cgroup.Delete(); err != nil {
+ return err
+ }
+
+ c.state.CgroupCreated = false
+
+ if c.valid {
+ return c.save()
+ }
+
+ return nil
+}
diff --git a/libpod/container_internal_unsupported.go b/libpod/container_internal_unsupported.go
new file mode 100644
index 000000000..015536850
--- /dev/null
+++ b/libpod/container_internal_unsupported.go
@@ -0,0 +1,7 @@
+// +build !linux
+
+package libpod
+
+func (c *Container) cleanupCgroups() error {
+ return ErrOSNotSupported
+}
diff --git a/libpod/container_linux.go b/libpod/container_linux.go
new file mode 100644
index 000000000..b271a3089
--- /dev/null
+++ b/libpod/container_linux.go
@@ -0,0 +1,23 @@
+// +build linux
+
+package libpod
+
+import (
+ "github.com/containernetworking/plugins/pkg/ns"
+)
+
+type containerStateLinux struct {
+
+ // NetNSPath is the path of the container's network namespace
+ // Will only be set if config.CreateNetNS is true, or the container was
+ // told to join another container's network namespace
+ NetNS ns.NetNS `json:"-"`
+}
+
+// containerStateWindows is intentionally left as a blank stub
+type containerStateWindows struct {
+}
+
+// containerStateDarwin is intentionally left as a blank stub
+type containerStateDarwin struct {
+}
diff --git a/libpod/container_windows.go b/libpod/container_windows.go
new file mode 100644
index 000000000..db2bf24d7
--- /dev/null
+++ b/libpod/container_windows.go
@@ -0,0 +1,14 @@
+// +build windows
+
+package libpod
+
+type containerStateWindows struct {
+}
+
+// containerStateLinux is intentionally left as a blank stub
+type containerStateLinux struct {
+}
+
+// containerStateDarwin is intentionally left as a blank stub
+type containerStateDarwin struct {
+}
diff --git a/libpod/errors.go b/libpod/errors.go
index 782104cf0..ddd586e29 100644
--- a/libpod/errors.go
+++ b/libpod/errors.go
@@ -66,4 +66,8 @@ var (
// ErrNotImplemented indicates that the requested functionality is not
// yet present
ErrNotImplemented = errors.New("not yet implemented")
+
+ // ErrOSNotSupported indicates the function is not available on the particular
+ // OS.
+ ErrOSNotSupported = errors.New("No support for this OS yet")
)
diff --git a/libpod/networking.go b/libpod/networking_linux.go
index afa18b534..ee90b765c 100644
--- a/libpod/networking.go
+++ b/libpod/networking_linux.go
@@ -1,3 +1,5 @@
+// +build linux
+
package libpod
import (
@@ -15,6 +17,7 @@ import (
"github.com/pkg/errors"
"github.com/projectatomic/libpod/utils"
"github.com/sirupsen/logrus"
+ "github.com/vishvananda/netlink"
"golang.org/x/sys/unix"
)
@@ -212,3 +215,16 @@ func (r *Runtime) teardownNetNS(ctr *Container) error {
return nil
}
+
+func getContainerNetIO(ctr *Container) (*netlink.LinkStatistics, error) {
+ var netStats *netlink.LinkStatistics
+ err := ns.WithNetNSPath(ctr.state.NetNS.Path(), func(_ ns.NetNS) error {
+ link, err := netlink.LinkByName(ocicni.DefaultInterfaceName)
+ if err != nil {
+ return err
+ }
+ netStats = link.Attrs().Statistics
+ return nil
+ })
+ return netStats, err
+}
diff --git a/libpod/oci.go b/libpod/oci.go
index dfed3d6b8..3a7d6be3a 100644
--- a/libpod/oci.go
+++ b/libpod/oci.go
@@ -15,11 +15,10 @@ import (
"syscall"
"time"
- "github.com/containerd/cgroups"
"github.com/containers/storage/pkg/idtools"
"github.com/coreos/go-systemd/activation"
spec "github.com/opencontainers/runtime-spec/specs-go"
- selinux "github.com/opencontainers/selinux/go-selinux"
+ "github.com/opencontainers/selinux/go-selinux"
"github.com/opencontainers/selinux/go-selinux/label"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@@ -323,7 +322,6 @@ func (r *OCIRuntime) createOCIContainer(ctr *Container, cgroupParent string) (er
fds := activation.Files(false)
cmd.ExtraFiles = append(cmd.ExtraFiles, fds...)
}
-
if selinux.GetEnabled() {
// Set the label of the conmon process to be level :s0
// This will allow the container processes to talk to fifo-files
@@ -361,27 +359,8 @@ func (r *OCIRuntime) createOCIContainer(ctr *Container, cgroupParent string) (er
childStartPipe.Close()
// Move conmon to specified cgroup
- if os.Getuid() == 0 {
- if r.cgroupManager == SystemdCgroupsManager {
- unitName := createUnitName("libpod-conmon", ctr.ID())
-
- logrus.Infof("Running conmon under slice %s and unitName %s", cgroupParent, unitName)
- if err = utils.RunUnderSystemdScope(cmd.Process.Pid, cgroupParent, unitName); err != nil {
- logrus.Warnf("Failed to add conmon to systemd sandbox cgroup: %v", err)
- }
- } else {
- cgroupPath := filepath.Join(ctr.config.CgroupParent, fmt.Sprintf("libpod-%s", ctr.ID()), "conmon")
- control, err := cgroups.New(cgroups.V1, cgroups.StaticPath(cgroupPath), &spec.LinuxResources{})
- if err != nil {
- logrus.Warnf("Failed to add conmon to cgroupfs sandbox cgroup: %v", err)
- } else {
- // we need to remove this defer and delete the cgroup once conmon exits
- // maybe need a conmon monitor?
- if err := control.Add(cgroups.Process{Pid: cmd.Process.Pid}); err != nil {
- logrus.Warnf("Failed to add conmon to cgroupfs sandbox cgroup: %v", err)
- }
- }
- }
+ if err := r.moveConmonToCgroup(ctr, cgroupParent, cmd); err != nil {
+ return err
}
/* We set the cgroup, now the child can start creating children */
diff --git a/libpod/oci_linux.go b/libpod/oci_linux.go
new file mode 100644
index 000000000..14373cbb2
--- /dev/null
+++ b/libpod/oci_linux.go
@@ -0,0 +1,41 @@
+// +build linux
+
+package libpod
+
+import (
+ "fmt"
+ "os"
+ "os/exec"
+ "path/filepath"
+
+ "github.com/containerd/cgroups"
+ spec "github.com/opencontainers/runtime-spec/specs-go"
+ "github.com/projectatomic/libpod/utils"
+ "github.com/sirupsen/logrus"
+)
+
+func (r *OCIRuntime) moveConmonToCgroup(ctr *Container, cgroupParent string, cmd *exec.Cmd) error {
+ if os.Getuid() == 0 {
+ if r.cgroupManager == SystemdCgroupsManager {
+ unitName := createUnitName("libpod-conmon", ctr.ID())
+
+ logrus.Infof("Running conmon under slice %s and unitName %s", cgroupParent, unitName)
+ if err := utils.RunUnderSystemdScope(cmd.Process.Pid, cgroupParent, unitName); err != nil {
+ logrus.Warnf("Failed to add conmon to systemd sandbox cgroup: %v", err)
+ }
+ } else {
+ cgroupPath := filepath.Join(ctr.config.CgroupParent, fmt.Sprintf("libpod-%s", ctr.ID()), "conmon")
+ control, err := cgroups.New(cgroups.V1, cgroups.StaticPath(cgroupPath), &spec.LinuxResources{})
+ if err != nil {
+ logrus.Warnf("Failed to add conmon to cgroupfs sandbox cgroup: %v", err)
+ } else {
+ // we need to remove this defer and delete the cgroup once conmon exits
+ // maybe need a conmon monitor?
+ if err := control.Add(cgroups.Process{Pid: cmd.Process.Pid}); err != nil {
+ logrus.Warnf("Failed to add conmon to cgroupfs sandbox cgroup: %v", err)
+ }
+ }
+ }
+ }
+ return nil
+}
diff --git a/libpod/oci_unsupported.go b/libpod/oci_unsupported.go
new file mode 100644
index 000000000..6e5601eac
--- /dev/null
+++ b/libpod/oci_unsupported.go
@@ -0,0 +1,7 @@
+// +build !linux
+
+package libpod
+
+func moveConmonToCgroup() error {
+ return ErrOSNotSupported
+}
diff --git a/libpod/runtime_pod.go b/libpod/runtime_pod.go
index 067a110fa..af277c5cc 100644
--- a/libpod/runtime_pod.go
+++ b/libpod/runtime_pod.go
@@ -1,16 +1,5 @@
package libpod
-import (
- "context"
- "path"
- "path/filepath"
- "strings"
-
- "github.com/containerd/cgroups"
- "github.com/pkg/errors"
- "github.com/sirupsen/logrus"
-)
-
// Contains the public Runtime API for pods
// A PodCreateOption is a functional option which alters the Pod created by
@@ -22,241 +11,6 @@ type PodCreateOption func(*Pod) error
// will include the pod, a false return will exclude it.
type PodFilter func(*Pod) bool
-// NewPod makes a new, empty pod
-func (r *Runtime) NewPod(options ...PodCreateOption) (*Pod, error) {
- r.lock.Lock()
- defer r.lock.Unlock()
-
- if !r.valid {
- return nil, ErrRuntimeStopped
- }
-
- pod, err := newPod(r.lockDir, r)
- if err != nil {
- return nil, errors.Wrapf(err, "error creating pod")
- }
-
- for _, option := range options {
- if err := option(pod); err != nil {
- return nil, errors.Wrapf(err, "error running pod create option")
- }
- }
-
- if pod.config.Name == "" {
- name, err := r.generateName()
- if err != nil {
- return nil, err
- }
- pod.config.Name = name
- }
-
- pod.valid = true
-
- // Check CGroup parent sanity, and set it if it was not set
- switch r.config.CgroupManager {
- case CgroupfsCgroupsManager:
- if pod.config.CgroupParent == "" {
- pod.config.CgroupParent = CgroupfsDefaultCgroupParent
- } else if strings.HasSuffix(path.Base(pod.config.CgroupParent), ".slice") {
- return nil, errors.Wrapf(ErrInvalidArg, "systemd slice received as cgroup parent when using cgroupfs")
- }
- // Creating CGroup path is currently a NOOP until proper systemd
- // cgroup management is merged
- case SystemdCgroupsManager:
- if pod.config.CgroupParent == "" {
- pod.config.CgroupParent = SystemdDefaultCgroupParent
- } else if len(pod.config.CgroupParent) < 6 || !strings.HasSuffix(path.Base(pod.config.CgroupParent), ".slice") {
- return nil, errors.Wrapf(ErrInvalidArg, "did not receive systemd slice as cgroup parent when using systemd to manage cgroups")
- }
- // If we are set to use pod cgroups, set the cgroup parent that
- // all containers in the pod will share
- // No need to create it with cgroupfs - the first container to
- // launch should do it for us
- if pod.config.UsePodCgroup {
- pod.state.CgroupPath = filepath.Join(pod.config.CgroupParent, pod.ID())
- }
- default:
- return nil, errors.Wrapf(ErrInvalidArg, "unsupported CGroup manager: %s - cannot validate cgroup parent", r.config.CgroupManager)
- }
-
- if err := r.state.AddPod(pod); err != nil {
- return nil, errors.Wrapf(err, "error adding pod to state")
- }
-
- return nil, ErrNotImplemented
-}
-
-// RemovePod removes a pod
-// If removeCtrs is specified, containers will be removed
-// Otherwise, a pod that is not empty will return an error and not be removed
-// If force is specified with removeCtrs, all containers will be stopped before
-// being removed
-// Otherwise, the pod will not be removed if any containers are running
-func (r *Runtime) RemovePod(ctx context.Context, p *Pod, removeCtrs, force bool) error {
- r.lock.Lock()
- defer r.lock.Unlock()
-
- if !r.valid {
- return ErrRuntimeStopped
- }
-
- p.lock.Lock()
- defer p.lock.Unlock()
-
- if !p.valid {
- return ErrPodRemoved
- }
-
- ctrs, err := r.state.PodContainers(p)
- if err != nil {
- return err
- }
-
- numCtrs := len(ctrs)
-
- if !removeCtrs && numCtrs > 0 {
- return errors.Wrapf(ErrCtrExists, "pod %s contains containers and cannot be removed", p.ID())
- }
-
- // Go through and lock all containers so we can operate on them all at once
- dependencies := make(map[string][]string)
- for _, ctr := range ctrs {
- ctr.lock.Lock()
- defer ctr.lock.Unlock()
-
- // Sync all containers
- if err := ctr.syncContainer(); err != nil {
- return err
- }
-
- // Check if the container is in a good state to be removed
- if ctr.state.State == ContainerStatePaused {
- return errors.Wrapf(ErrCtrStateInvalid, "pod %s contains paused container %s, cannot remove", p.ID(), ctr.ID())
- }
-
- if ctr.state.State == ContainerStateUnknown {
- return errors.Wrapf(ErrCtrStateInvalid, "pod %s contains container %s with invalid state", p.ID(), ctr.ID())
- }
-
- // If the container is running and force is not set we can't do anything
- if ctr.state.State == ContainerStateRunning && !force {
- return errors.Wrapf(ErrCtrStateInvalid, "pod %s contains container %s which is running", p.ID(), ctr.ID())
- }
-
- // If the container has active exec sessions and force is not set we can't do anything
- if len(ctr.state.ExecSessions) != 0 && !force {
- return errors.Wrapf(ErrCtrStateInvalid, "pod %s contains container %s which has active exec sessions", p.ID(), ctr.ID())
- }
-
- deps, err := r.state.ContainerInUse(ctr)
- if err != nil {
- return err
- }
- dependencies[ctr.ID()] = deps
- }
-
- // Check if containers have dependencies
- // If they do, and the dependencies are not in the pod, error
- for ctr, deps := range dependencies {
- for _, dep := range deps {
- if _, ok := dependencies[dep]; !ok {
- return errors.Wrapf(ErrCtrExists, "container %s depends on container %s not in pod %s", ctr, dep, p.ID())
- }
- }
- }
-
- // First loop through all containers and stop them
- // Do not remove in this loop to ensure that we don't remove unless all
- // containers are in a good state
- if force {
- for _, ctr := range ctrs {
- // If force is set and the container is running, stop it now
- if ctr.state.State == ContainerStateRunning {
- if err := r.ociRuntime.stopContainer(ctr, ctr.StopTimeout()); err != nil {
- return errors.Wrapf(err, "error stopping container %s to remove pod %s", ctr.ID(), p.ID())
- }
-
- // Sync again to pick up stopped state
- if err := ctr.syncContainer(); err != nil {
- return err
- }
- }
- // If the container has active exec sessions, stop them now
- if len(ctr.state.ExecSessions) != 0 {
- if err := r.ociRuntime.execStopContainer(ctr, ctr.StopTimeout()); err != nil {
- return err
- }
- }
- }
- }
-
- // Start removing containers
- // We can remove containers even if they have dependencies now
- // As we have guaranteed their dependencies are in the pod
- for _, ctr := range ctrs {
- // Clean up network namespace, cgroups, mounts
- if err := ctr.cleanup(); err != nil {
- return err
- }
-
- // Stop container's storage
- if err := ctr.teardownStorage(); err != nil {
- return err
- }
-
- // Delete the container from runtime (only if we are not
- // ContainerStateConfigured)
- if ctr.state.State != ContainerStateConfigured {
- if err := ctr.delete(ctx); err != nil {
- return err
- }
- }
- }
-
- // Remove containers from the state
- if err := r.state.RemovePodContainers(p); err != nil {
- return err
- }
-
- // Mark containers invalid
- for _, ctr := range ctrs {
- ctr.valid = false
- }
-
- // Remove pod cgroup, if present
- if p.state.CgroupPath != "" {
- switch p.runtime.config.CgroupManager {
- case SystemdCgroupsManager:
- // NOOP for now, until proper systemd cgroup management
- // is implemented
- case CgroupfsCgroupsManager:
- // Delete the cgroupfs cgroup
- logrus.Debugf("Removing pod cgroup %s", p.state.CgroupPath)
-
- cgroup, err := cgroups.Load(cgroups.V1, cgroups.StaticPath(p.state.CgroupPath))
- if err != nil && err != cgroups.ErrCgroupDeleted {
- return err
- } else if err == nil {
- if err := cgroup.Delete(); err != nil {
- return err
- }
- }
- default:
- return errors.Wrapf(ErrInvalidArg, "unknown cgroups manager %s specified", p.runtime.config.CgroupManager)
- }
- }
-
- // Remove pod from state
- if err := r.state.RemovePod(p); err != nil {
- return err
- }
-
- // Mark pod invalid
- p.valid = false
-
- return nil
-}
-
// GetPod retrieves a pod by its ID
func (r *Runtime) GetPod(id string) (*Pod, error) {
r.lock.RLock()
diff --git a/libpod/runtime_pod_linux.go b/libpod/runtime_pod_linux.go
new file mode 100644
index 000000000..0edac9dbe
--- /dev/null
+++ b/libpod/runtime_pod_linux.go
@@ -0,0 +1,249 @@
+// +build linux
+
+package libpod
+
+import (
+ "context"
+ "path"
+ "path/filepath"
+ "strings"
+
+ "github.com/containerd/cgroups"
+ "github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
+)
+
+// NewPod makes a new, empty pod
+func (r *Runtime) NewPod(options ...PodCreateOption) (*Pod, error) {
+ r.lock.Lock()
+ defer r.lock.Unlock()
+
+ if !r.valid {
+ return nil, ErrRuntimeStopped
+ }
+
+ pod, err := newPod(r.lockDir, r)
+ if err != nil {
+ return nil, errors.Wrapf(err, "error creating pod")
+ }
+
+ for _, option := range options {
+ if err := option(pod); err != nil {
+ return nil, errors.Wrapf(err, "error running pod create option")
+ }
+ }
+
+ if pod.config.Name == "" {
+ name, err := r.generateName()
+ if err != nil {
+ return nil, err
+ }
+ pod.config.Name = name
+ }
+
+ pod.valid = true
+
+ // Check CGroup parent sanity, and set it if it was not set
+ switch r.config.CgroupManager {
+ case CgroupfsCgroupsManager:
+ if pod.config.CgroupParent == "" {
+ pod.config.CgroupParent = CgroupfsDefaultCgroupParent
+ } else if strings.HasSuffix(path.Base(pod.config.CgroupParent), ".slice") {
+ return nil, errors.Wrapf(ErrInvalidArg, "systemd slice received as cgroup parent when using cgroupfs")
+ }
+ // Creating CGroup path is currently a NOOP until proper systemd
+ // cgroup management is merged
+ case SystemdCgroupsManager:
+ if pod.config.CgroupParent == "" {
+ pod.config.CgroupParent = SystemdDefaultCgroupParent
+ } else if len(pod.config.CgroupParent) < 6 || !strings.HasSuffix(path.Base(pod.config.CgroupParent), ".slice") {
+ return nil, errors.Wrapf(ErrInvalidArg, "did not receive systemd slice as cgroup parent when using systemd to manage cgroups")
+ }
+ // If we are set to use pod cgroups, set the cgroup parent that
+ // all containers in the pod will share
+ // No need to create it with cgroupfs - the first container to
+ // launch should do it for us
+ if pod.config.UsePodCgroup {
+ pod.state.CgroupPath = filepath.Join(pod.config.CgroupParent, pod.ID())
+ }
+ default:
+ return nil, errors.Wrapf(ErrInvalidArg, "unsupported CGroup manager: %s - cannot validate cgroup parent", r.config.CgroupManager)
+ }
+
+ if err := r.state.AddPod(pod); err != nil {
+ return nil, errors.Wrapf(err, "error adding pod to state")
+ }
+
+ return nil, ErrNotImplemented
+}
+
+// RemovePod removes a pod
+// If removeCtrs is specified, containers will be removed
+// Otherwise, a pod that is not empty will return an error and not be removed
+// If force is specified with removeCtrs, all containers will be stopped before
+// being removed
+// Otherwise, the pod will not be removed if any containers are running
+func (r *Runtime) RemovePod(ctx context.Context, p *Pod, removeCtrs, force bool) error {
+ r.lock.Lock()
+ defer r.lock.Unlock()
+
+ if !r.valid {
+ return ErrRuntimeStopped
+ }
+
+ p.lock.Lock()
+ defer p.lock.Unlock()
+
+ if !p.valid {
+ return ErrPodRemoved
+ }
+
+ ctrs, err := r.state.PodContainers(p)
+ if err != nil {
+ return err
+ }
+
+ numCtrs := len(ctrs)
+
+ if !removeCtrs && numCtrs > 0 {
+ return errors.Wrapf(ErrCtrExists, "pod %s contains containers and cannot be removed", p.ID())
+ }
+
+ // Go through and lock all containers so we can operate on them all at once
+ dependencies := make(map[string][]string)
+ for _, ctr := range ctrs {
+ ctr.lock.Lock()
+ defer ctr.lock.Unlock()
+
+ // Sync all containers
+ if err := ctr.syncContainer(); err != nil {
+ return err
+ }
+
+ // Check if the container is in a good state to be removed
+ if ctr.state.State == ContainerStatePaused {
+ return errors.Wrapf(ErrCtrStateInvalid, "pod %s contains paused container %s, cannot remove", p.ID(), ctr.ID())
+ }
+
+ if ctr.state.State == ContainerStateUnknown {
+ return errors.Wrapf(ErrCtrStateInvalid, "pod %s contains container %s with invalid state", p.ID(), ctr.ID())
+ }
+
+ // If the container is running and force is not set we can't do anything
+ if ctr.state.State == ContainerStateRunning && !force {
+ return errors.Wrapf(ErrCtrStateInvalid, "pod %s contains container %s which is running", p.ID(), ctr.ID())
+ }
+
+ // If the container has active exec sessions and force is not set we can't do anything
+ if len(ctr.state.ExecSessions) != 0 && !force {
+ return errors.Wrapf(ErrCtrStateInvalid, "pod %s contains container %s which has active exec sessions", p.ID(), ctr.ID())
+ }
+
+ deps, err := r.state.ContainerInUse(ctr)
+ if err != nil {
+ return err
+ }
+ dependencies[ctr.ID()] = deps
+ }
+
+ // Check if containers have dependencies
+ // If they do, and the dependencies are not in the pod, error
+ for ctr, deps := range dependencies {
+ for _, dep := range deps {
+ if _, ok := dependencies[dep]; !ok {
+ return errors.Wrapf(ErrCtrExists, "container %s depends on container %s not in pod %s", ctr, dep, p.ID())
+ }
+ }
+ }
+
+ // First loop through all containers and stop them
+ // Do not remove in this loop to ensure that we don't remove unless all
+ // containers are in a good state
+ if force {
+ for _, ctr := range ctrs {
+ // If force is set and the container is running, stop it now
+ if ctr.state.State == ContainerStateRunning {
+ if err := r.ociRuntime.stopContainer(ctr, ctr.StopTimeout()); err != nil {
+ return errors.Wrapf(err, "error stopping container %s to remove pod %s", ctr.ID(), p.ID())
+ }
+
+ // Sync again to pick up stopped state
+ if err := ctr.syncContainer(); err != nil {
+ return err
+ }
+ }
+ // If the container has active exec sessions, stop them now
+ if len(ctr.state.ExecSessions) != 0 {
+ if err := r.ociRuntime.execStopContainer(ctr, ctr.StopTimeout()); err != nil {
+ return err
+ }
+ }
+ }
+ }
+
+ // Start removing containers
+ // We can remove containers even if they have dependencies now
+ // As we have guaranteed their dependencies are in the pod
+ for _, ctr := range ctrs {
+ // Clean up network namespace, cgroups, mounts
+ if err := ctr.cleanup(); err != nil {
+ return err
+ }
+
+ // Stop container's storage
+ if err := ctr.teardownStorage(); err != nil {
+ return err
+ }
+
+ // Delete the container from runtime (only if we are not
+ // ContainerStateConfigured)
+ if ctr.state.State != ContainerStateConfigured {
+ if err := ctr.delete(ctx); err != nil {
+ return err
+ }
+ }
+ }
+
+ // Remove containers from the state
+ if err := r.state.RemovePodContainers(p); err != nil {
+ return err
+ }
+
+ // Mark containers invalid
+ for _, ctr := range ctrs {
+ ctr.valid = false
+ }
+
+ // Remove pod cgroup, if present
+ if p.state.CgroupPath != "" {
+ switch p.runtime.config.CgroupManager {
+ case SystemdCgroupsManager:
+ // NOOP for now, until proper systemd cgroup management
+ // is implemented
+ case CgroupfsCgroupsManager:
+ // Delete the cgroupfs cgroup
+ logrus.Debugf("Removing pod cgroup %s", p.state.CgroupPath)
+
+ cgroup, err := cgroups.Load(cgroups.V1, cgroups.StaticPath(p.state.CgroupPath))
+ if err != nil && err != cgroups.ErrCgroupDeleted {
+ return err
+ } else if err == nil {
+ if err := cgroup.Delete(); err != nil {
+ return err
+ }
+ }
+ default:
+ return errors.Wrapf(ErrInvalidArg, "unknown cgroups manager %s specified", p.runtime.config.CgroupManager)
+ }
+ }
+
+ // Remove pod from state
+ if err := r.state.RemovePod(p); err != nil {
+ return err
+ }
+
+ // Mark pod invalid
+ p.valid = false
+
+ return nil
+}
diff --git a/libpod/runtime_pod_unsupported.go b/libpod/runtime_pod_unsupported.go
new file mode 100644
index 000000000..b22f151d8
--- /dev/null
+++ b/libpod/runtime_pod_unsupported.go
@@ -0,0 +1,16 @@
+// +build !linux
+
+package libpod
+
+import (
+ "context"
+)
+
+// NewPod makes a new, empty pod
+func (r *Runtime) NewPod(options ...PodCreateOption) (*Pod, error) {
+ return nil, ErrOSNotSupported
+}
+
+func (r *Runtime) RemovePod(ctx context.Context, p *Pod, removeCtrs, force bool) error {
+ return ErrOSNotSupported
+}
diff --git a/libpod/stats.go b/libpod/stats.go
index 52bcc901d..262c1ac00 100644
--- a/libpod/stats.go
+++ b/libpod/stats.go
@@ -1,3 +1,5 @@
+// +build linux
+
package libpod
import (
@@ -6,29 +8,9 @@ import (
"time"
"github.com/containerd/cgroups"
- "github.com/containernetworking/plugins/pkg/ns"
- "github.com/cri-o/ocicni/pkg/ocicni"
"github.com/pkg/errors"
- "github.com/vishvananda/netlink"
)
-// ContainerStats contains the statistics information for a running container
-type ContainerStats struct {
- ContainerID string
- Name 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 *Container) GetContainerStats(previousStats *ContainerStats) (*ContainerStats, error) {
stats := new(ContainerStats)
@@ -103,19 +85,6 @@ func getMemLimit(cgroupLimit uint64) uint64 {
return cgroupLimit
}
-func getContainerNetIO(ctr *Container) (*netlink.LinkStatistics, error) {
- var netStats *netlink.LinkStatistics
- err := ns.WithNetNSPath(ctr.state.NetNS.Path(), func(_ ns.NetNS) error {
- link, err := netlink.LinkByName(ocicni.DefaultInterfaceName)
- if err != nil {
- return err
- }
- netStats = link.Attrs().Statistics
- return nil
- })
- return netStats, err
-}
-
func calculateCPUPercent(stats *cgroups.Metrics, previousCPU, previousSystem uint64) float64 {
var (
cpuPercent = 0.0
diff --git a/libpod/stats_config.go b/libpod/stats_config.go
new file mode 100644
index 000000000..9c7d97298
--- /dev/null
+++ b/libpod/stats_config.go
@@ -0,0 +1,18 @@
+package libpod
+
+// ContainerStats contains the statistics information for a running container
+type ContainerStats struct {
+ ContainerID string
+ Name string
+ CPU float64
+ CPUNano uint64
+ SystemNano uint64
+ MemUsage uint64
+ MemLimit uint64
+ MemPerc float64
+ NetInput uint64
+ NetOutput uint64
+ BlockInput uint64
+ BlockOutput uint64
+ PIDs uint64
+}
diff --git a/libpod/stats_unsupported.go b/libpod/stats_unsupported.go
new file mode 100644
index 000000000..7117413eb
--- /dev/null
+++ b/libpod/stats_unsupported.go
@@ -0,0 +1,8 @@
+// +build !linux
+
+package libpod
+
+// GetContainerStats gets the running stats for a given container
+func (c *Container) GetContainerStats(previousStats *ContainerStats) (*ContainerStats, error) {
+ return nil, ErrOSNotSupported
+}