summaryrefslogtreecommitdiff
path: root/libpod
diff options
context:
space:
mode:
Diffstat (limited to 'libpod')
-rw-r--r--libpod/container_commit.go2
-rw-r--r--libpod/container_inspect.go3
-rw-r--r--libpod/define/podstate.go19
-rw-r--r--libpod/image/config.go6
-rw-r--r--libpod/image/image.go12
-rw-r--r--libpod/image/parts.go2
-rw-r--r--libpod/options.go11
-rw-r--r--libpod/pod_status.go59
-rw-r--r--libpod/runtime_ctr.go47
-rw-r--r--libpod/runtime_pod.go28
-rw-r--r--libpod/runtime_pod_linux.go2
-rw-r--r--libpod/volume.go14
-rw-r--r--libpod/volume_inspect.go10
13 files changed, 189 insertions, 26 deletions
diff --git a/libpod/container_commit.go b/libpod/container_commit.go
index ccc23621e..fa6e95b38 100644
--- a/libpod/container_commit.go
+++ b/libpod/container_commit.go
@@ -137,7 +137,7 @@ func (c *Container) Commit(ctx context.Context, destImage string, options Contai
if err != nil {
return nil, errors.Wrapf(err, "volume %s used in container %s has been removed", v.Name, c.ID())
}
- if vol.IsCtrSpecific() {
+ if vol.Anonymous() {
importBuilder.AddVolume(v.Dest)
}
}
diff --git a/libpod/container_inspect.go b/libpod/container_inspect.go
index 01f2d93bd..641bc8a91 100644
--- a/libpod/container_inspect.go
+++ b/libpod/container_inspect.go
@@ -1014,6 +1014,9 @@ func (c *Container) generateInspectContainerHostConfig(ctrSpec *spec.Spec, named
hostConfig.ShmSize = c.config.ShmSize
hostConfig.Runtime = "oci"
+ // Default CPUShares is 1024, but we may overwrite below.
+ hostConfig.CpuShares = 1024
+
// This is very expensive to initialize.
// So we don't want to initialize it unless we absolutely have to - IE,
// there are things that require a major:minor to path translation.
diff --git a/libpod/define/podstate.go b/libpod/define/podstate.go
new file mode 100644
index 000000000..2b59aabfb
--- /dev/null
+++ b/libpod/define/podstate.go
@@ -0,0 +1,19 @@
+package define
+
+const (
+ // PodStateCreated indicates the pod is created but has not been started
+ PodStateCreated = "Created"
+ // PodStateErrored indicates the pod is in an errored state where
+ // information about it can no longer be retrieved
+ PodStateErrored = "Error"
+ // PodStateExited indicates the pod ran but has been stopped
+ PodStateExited = "Exited"
+ // PodStatePaused indicates the pod has been paused
+ PodStatePaused = "Paused"
+ // PodStateRunning indicates that one or more of the containers in
+ // the pod is running
+ PodStateRunning = "Running"
+ // PodStateStopped indicates all of the containers belonging to the pod
+ // are stopped.
+ PodStateStopped = "Stopped"
+)
diff --git a/libpod/image/config.go b/libpod/image/config.go
index bb84175a3..efd83d343 100644
--- a/libpod/image/config.go
+++ b/libpod/image/config.go
@@ -1,5 +1,11 @@
package image
+const (
+ // LatestTag describes the tag used to refer to the latest version
+ // of an image
+ LatestTag = "latest"
+)
+
// ImageDeleteResponse is the response for removing an image from storage and containers
// what was untagged vs actually removed
type ImageDeleteResponse struct { //nolint
diff --git a/libpod/image/image.go b/libpod/image/image.go
index 6ea49e2a9..355249b12 100644
--- a/libpod/image/image.go
+++ b/libpod/image/image.go
@@ -831,7 +831,8 @@ func (i *Image) History(ctx context.Context) ([]*History, error) {
id := "<missing>"
if x == numHistories {
id = i.ID()
- } else if layer != nil {
+ }
+ if layer != nil {
if !oci.History[x].EmptyLayer {
size = layer.UncompressedSize
}
@@ -1012,6 +1013,15 @@ func (i *Image) Inspect(ctx context.Context) (*inspect.ImageData, error) {
History: ociv1Img.History,
NamesHistory: i.NamesHistory(),
}
+ if manifestType == manifest.DockerV2Schema2MediaType {
+ hc, err := i.GetHealthCheck(ctx)
+ if err != nil {
+ return nil, err
+ }
+ if hc != nil {
+ data.HealthCheck = hc
+ }
+ }
return data, nil
}
diff --git a/libpod/image/parts.go b/libpod/image/parts.go
index d4677f935..d6c98783b 100644
--- a/libpod/image/parts.go
+++ b/libpod/image/parts.go
@@ -67,7 +67,7 @@ func (ip *imageParts) suspiciousRefNameTagValuesForSearch() (string, string, str
} else if _, hasDigest := ip.unnormalizedRef.(reference.Digested); hasDigest {
tag = "none"
} else {
- tag = "latest"
+ tag = LatestTag
}
return registry, imageName, tag
}
diff --git a/libpod/options.go b/libpod/options.go
index 593037382..923e7292c 100644
--- a/libpod/options.go
+++ b/libpod/options.go
@@ -1546,17 +1546,16 @@ func WithVolumeGID(gid int) VolumeCreateOption {
}
}
-// withSetCtrSpecific sets a bool notifying libpod that a volume was created
-// specifically for a container.
-// These volumes will be removed when the container is removed and volumes are
-// also specified for removal.
-func withSetCtrSpecific() VolumeCreateOption {
+// withSetAnon sets a bool notifying libpod that this volume is anonymous and
+// should be removed when containers using it are removed and volumes are
+// specified for removal.
+func withSetAnon() VolumeCreateOption {
return func(volume *Volume) error {
if volume.valid {
return define.ErrVolumeFinalized
}
- volume.config.IsCtrSpecific = true
+ volume.config.IsAnon = true
return nil
}
diff --git a/libpod/pod_status.go b/libpod/pod_status.go
new file mode 100644
index 000000000..3a44c4457
--- /dev/null
+++ b/libpod/pod_status.go
@@ -0,0 +1,59 @@
+package libpod
+
+import "github.com/containers/libpod/libpod/define"
+
+// GetPodStatus determines the status of the pod based on the
+// statuses of the containers in the pod.
+// Returns a string representation of the pod status
+func (p *Pod) GetPodStatus() (string, error) {
+ ctrStatuses, err := p.Status()
+ if err != nil {
+ return define.PodStateErrored, err
+ }
+ return CreatePodStatusResults(ctrStatuses)
+}
+
+func CreatePodStatusResults(ctrStatuses map[string]define.ContainerStatus) (string, error) {
+ ctrNum := len(ctrStatuses)
+ if ctrNum == 0 {
+ return define.PodStateCreated, nil
+ }
+ statuses := map[string]int{
+ define.PodStateStopped: 0,
+ define.PodStateRunning: 0,
+ define.PodStatePaused: 0,
+ define.PodStateCreated: 0,
+ define.PodStateErrored: 0,
+ }
+ for _, ctrStatus := range ctrStatuses {
+ switch ctrStatus {
+ case define.ContainerStateExited:
+ fallthrough
+ case define.ContainerStateStopped:
+ statuses[define.PodStateStopped]++
+ case define.ContainerStateRunning:
+ statuses[define.PodStateRunning]++
+ case define.ContainerStatePaused:
+ statuses[define.PodStatePaused]++
+ case define.ContainerStateCreated, define.ContainerStateConfigured:
+ statuses[define.PodStateCreated]++
+ default:
+ statuses[define.PodStateErrored]++
+ }
+ }
+
+ switch {
+ case statuses[define.PodStateRunning] > 0:
+ return define.PodStateRunning, nil
+ case statuses[define.PodStatePaused] == ctrNum:
+ return define.PodStatePaused, nil
+ case statuses[define.PodStateStopped] == ctrNum:
+ return define.PodStateExited, nil
+ case statuses[define.PodStateStopped] > 0:
+ return define.PodStateStopped, nil
+ case statuses[define.PodStateErrored] > 0:
+ return define.PodStateErrored, nil
+ default:
+ return define.PodStateCreated, nil
+ }
+}
diff --git a/libpod/runtime_ctr.go b/libpod/runtime_ctr.go
index de7cfd3b8..3ad09f27c 100644
--- a/libpod/runtime_ctr.go
+++ b/libpod/runtime_ctr.go
@@ -319,7 +319,7 @@ func (r *Runtime) setupContainer(ctx context.Context, ctr *Container) (c *Contai
// The volume does not exist, so we need to create it.
volOptions := []VolumeCreateOption{WithVolumeName(vol.Name), WithVolumeUID(ctr.RootUID()), WithVolumeGID(ctr.RootGID())}
if isAnonymous {
- volOptions = append(volOptions, withSetCtrSpecific())
+ volOptions = append(volOptions, withSetAnon())
}
newVol, err := r.newVolume(ctx, volOptions...)
if err != nil {
@@ -569,7 +569,7 @@ func (r *Runtime) removeContainer(ctx context.Context, c *Container, force bool,
for _, v := range c.config.NamedVolumes {
if volume, err := runtime.state.Volume(v.Name); err == nil {
- if !volume.IsCtrSpecific() {
+ if !volume.Anonymous() {
continue
}
if err := runtime.removeVolume(ctx, volume, false); err != nil && errors.Cause(err) != define.ErrNoSuchVolume {
@@ -707,7 +707,7 @@ func (r *Runtime) evictContainer(ctx context.Context, idOrName string, removeVol
for _, v := range c.config.NamedVolumes {
if volume, err := r.state.Volume(v.Name); err == nil {
- if !volume.IsCtrSpecific() {
+ if !volume.Anonymous() {
continue
}
if err := r.removeVolume(ctx, volume, false); err != nil && err != define.ErrNoSuchVolume && err != define.ErrVolumeBeingUsed {
@@ -836,3 +836,44 @@ func (r *Runtime) GetLatestContainer() (*Container, error) {
}
return ctrs[lastCreatedIndex], nil
}
+
+// PruneContainers removes stopped and exited containers from localstorage. A set of optional filters
+// can be provided to be more granular.
+func (r *Runtime) PruneContainers(filterFuncs []ContainerFilter) (map[string]int64, map[string]error, error) {
+ pruneErrors := make(map[string]error)
+ prunedContainers := make(map[string]int64)
+ // We add getting the exited and stopped containers via a filter
+ containerStateFilter := func(c *Container) bool {
+ if c.PodID() != "" {
+ return false
+ }
+ state, err := c.State()
+ if err != nil {
+ logrus.Error(err)
+ return false
+ }
+ if state == define.ContainerStateStopped || state == define.ContainerStateExited {
+ return true
+ }
+ return false
+ }
+ filterFuncs = append(filterFuncs, containerStateFilter)
+ delContainers, err := r.GetContainers(filterFuncs...)
+ if err != nil {
+ return nil, nil, err
+ }
+ for _, c := range delContainers {
+ ctr := c
+ size, err := ctr.RWSize()
+ if err != nil {
+ pruneErrors[ctr.ID()] = err
+ continue
+ }
+ err = r.RemoveContainer(context.Background(), ctr, false, false)
+ pruneErrors[ctr.ID()] = err
+ if err != nil {
+ prunedContainers[ctr.ID()] = size
+ }
+ }
+ return prunedContainers, pruneErrors, nil
+}
diff --git a/libpod/runtime_pod.go b/libpod/runtime_pod.go
index 66f9b10c9..e1dc31391 100644
--- a/libpod/runtime_pod.go
+++ b/libpod/runtime_pod.go
@@ -182,3 +182,31 @@ func (r *Runtime) GetRunningPods() ([]*Pod, error) {
}
return runningPods, nil
}
+
+// PrunePods removes unused pods and their containers from local storage.
+// If force is given, then running pods are also included in the pruning.
+func (r *Runtime) PrunePods() (map[string]error, error) {
+ response := make(map[string]error)
+ states := []string{define.PodStateStopped, define.PodStateExited}
+ filterFunc := func(p *Pod) bool {
+ state, _ := p.GetPodStatus()
+ for _, status := range states {
+ if state == status {
+ return true
+ }
+ }
+ return false
+ }
+ pods, err := r.Pods(filterFunc)
+ if err != nil {
+ return nil, err
+ }
+ if len(pods) < 1 {
+ return response, nil
+ }
+ for _, pod := range pods {
+ err := r.removePod(context.TODO(), pod, true, false)
+ response[pod.ID()] = err
+ }
+ return response, nil
+}
diff --git a/libpod/runtime_pod_linux.go b/libpod/runtime_pod_linux.go
index 450c64d24..5b0111b85 100644
--- a/libpod/runtime_pod_linux.go
+++ b/libpod/runtime_pod_linux.go
@@ -261,7 +261,7 @@ func (r *Runtime) removePod(ctx context.Context, p *Pod, removeCtrs, force bool)
logrus.Errorf("Error retrieving volume %s: %v", volName, err)
continue
}
- if !volume.IsCtrSpecific() {
+ if !volume.Anonymous() {
continue
}
if err := r.removeVolume(ctx, volume, false); err != nil {
diff --git a/libpod/volume.go b/libpod/volume.go
index c4771bbb8..1ffed872e 100644
--- a/libpod/volume.go
+++ b/libpod/volume.go
@@ -38,9 +38,8 @@ type VolumeConfig struct {
// a list of mount options. For other drivers, they are passed to the
// volume driver handling the volume.
Options map[string]string `json:"volumeOptions,omitempty"`
- // Whether this volume was created for a specific container and will be
- // removed with it.
- IsCtrSpecific bool `json:"ctrSpecific"`
+ // Whether this volume is anonymous (will be removed on container exit)
+ IsAnon bool `json:"isAnon"`
// UID the volume will be created as.
UID int `json:"uid"`
// GID the volume will be created as.
@@ -106,11 +105,10 @@ func (v *Volume) Options() map[string]string {
return options
}
-// IsCtrSpecific returns whether this volume was created specifically for a
-// given container. Images with this set to true will be removed when the
-// container is removed with the Volumes parameter set to true.
-func (v *Volume) IsCtrSpecific() bool {
- return v.config.IsCtrSpecific
+// Anonymous returns whether this volume is anonymous. Anonymous volumes were
+// created with a container, and will be removed when that container is removed.
+func (v *Volume) Anonymous() bool {
+ return v.config.IsAnon
}
// UID returns the UID the volume will be created as.
diff --git a/libpod/volume_inspect.go b/libpod/volume_inspect.go
index c333b8961..136f9da5e 100644
--- a/libpod/volume_inspect.go
+++ b/libpod/volume_inspect.go
@@ -37,10 +37,10 @@ type InspectVolumeData struct {
UID int `json:"UID,omitempty"`
// GID is the GID that the volume was created with.
GID int `json:"GID,omitempty"`
- // ContainerSpecific indicates that the volume was created as part of a
- // specific container, and will be removed when that container is
- // removed.
- ContainerSpecific bool `json:"ContainerSpecific,omitempty"`
+ // Anonymous indicates that the volume was created as an anonymous
+ // volume for a specific container, and will be be removed when any
+ // container using it is removed.
+ Anonymous bool `json:"Anonymous,omitempty"`
}
// Inspect provides detailed information about the configuration of the given
@@ -67,7 +67,7 @@ func (v *Volume) Inspect() (*InspectVolumeData, error) {
}
data.UID = v.config.UID
data.GID = v.config.GID
- data.ContainerSpecific = v.config.IsCtrSpecific
+ data.Anonymous = v.config.IsAnon
return data, nil
}