summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbaude <bbaude@redhat.com>2020-05-01 12:57:41 -0500
committerbaude <bbaude@redhat.com>2020-05-05 12:24:33 -0500
commit25312bb5b4e2bd4e122703006fc85bbf080e5e7c (patch)
treef2728cef53f71fcf1c04ff76ab928770fc5c9e50
parent4a1331d0afd9a21ff9465916d4006ff7297ae07c (diff)
downloadpodman-25312bb5b4e2bd4e122703006fc85bbf080e5e7c.tar.gz
podman-25312bb5b4e2bd4e122703006fc85bbf080e5e7c.tar.bz2
podman-25312bb5b4e2bd4e122703006fc85bbf080e5e7c.zip
v2 system subcommand
add system df, info, load, renumber, and migrate Refactor for specialized libpod engines add the ability to prune images, volumes, containers, and pods Signed-off-by: baude <bbaude@redhat.com>
-rw-r--r--cmd/podman/images/load.go1
-rw-r--r--cmd/podman/system/df.go282
-rw-r--r--cmd/podman/system/migrate.go63
-rw-r--r--cmd/podman/system/renumber.go57
-rw-r--r--cmd/podman/system/reset.go82
-rw-r--r--libpod/volume.go13
-rw-r--r--pkg/domain/entities/engine.go9
-rw-r--r--pkg/domain/entities/engine_container.go1
-rw-r--r--pkg/domain/entities/engine_system.go14
-rw-r--r--pkg/domain/entities/system.go57
-rw-r--r--pkg/domain/infra/abi/runtime.go5
-rw-r--r--pkg/domain/infra/abi/system.go177
-rw-r--r--pkg/domain/infra/runtime_abi.go31
-rw-r--r--pkg/domain/infra/runtime_abi_unsupported.go14
-rw-r--r--pkg/domain/infra/runtime_image_proxy.go21
-rw-r--r--pkg/domain/infra/runtime_proxy.go8
-rw-r--r--pkg/domain/infra/tunnel/system.go6
-rw-r--r--test/e2e/system_df_test.go1
-rw-r--r--test/e2e/system_reset_test.go1
19 files changed, 817 insertions, 26 deletions
diff --git a/cmd/podman/images/load.go b/cmd/podman/images/load.go
index d34c794c6..4bbffd432 100644
--- a/cmd/podman/images/load.go
+++ b/cmd/podman/images/load.go
@@ -78,7 +78,6 @@ func load(cmd *cobra.Command, args []string) error {
loadOpts.Tag = "latest"
}
if r, ok := ref.(reference.Named); ok {
- fmt.Println(r.Name())
loadOpts.Name = r.Name()
}
}
diff --git a/cmd/podman/system/df.go b/cmd/podman/system/df.go
new file mode 100644
index 000000000..7caa8e39a
--- /dev/null
+++ b/cmd/podman/system/df.go
@@ -0,0 +1,282 @@
+package system
+
+import (
+ "fmt"
+ "html/template"
+ "io"
+ "os"
+ "strings"
+ "text/tabwriter"
+ "time"
+
+ "github.com/containers/libpod/cmd/podman/registry"
+ "github.com/containers/libpod/cmd/podman/validate"
+ "github.com/containers/libpod/pkg/domain/entities"
+ "github.com/docker/go-units"
+ "github.com/spf13/cobra"
+)
+
+var (
+ dfSystemDescription = `
+ podman system df
+
+ Show podman disk usage
+ `
+ dfSystemCommand = &cobra.Command{
+ Use: "df",
+ Args: validate.NoArgs,
+ Short: "Show podman disk usage",
+ Long: dfSystemDescription,
+ RunE: df,
+ }
+)
+
+var (
+ dfOptions entities.SystemDfOptions
+)
+
+func init() {
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Mode: []entities.EngineMode{entities.ABIMode},
+ Command: dfSystemCommand,
+ Parent: systemCmd,
+ })
+ flags := dfSystemCommand.Flags()
+ flags.BoolVarP(&dfOptions.Verbose, "verbose", "v", false, "Show detailed information on disk usage")
+ flags.StringVar(&dfOptions.Format, "format", "", "Pretty-print images using a Go template")
+}
+
+func df(cmd *cobra.Command, args []string) error {
+ reports, err := registry.ContainerEngine().SystemDf(registry.Context(), dfOptions)
+ if err != nil {
+ return err
+ }
+ if dfOptions.Verbose {
+ return printVerbose(reports)
+ }
+ return printSummary(reports, dfOptions.Format)
+}
+
+func printSummary(reports *entities.SystemDfReport, userFormat string) error {
+
+ var (
+ dfSummaries []*dfSummary
+ active int
+ size, reclaimable int64
+ format string = "{{.Type}}\t{{.Total}}\t{{.Active}}\t{{.Size}}\t{{.Reclaimable}}\n"
+ w io.Writer = os.Stdout
+ )
+
+ // Images
+ if len(userFormat) > 0 {
+ format = userFormat
+ }
+
+ for _, i := range reports.Images {
+ if i.Containers > 0 {
+ active += 1
+ }
+ size += i.Size
+ if i.Containers < 1 {
+ reclaimable += i.Size
+ }
+ }
+
+ imageSummary := dfSummary{
+ Type: "Images",
+ Total: len(reports.Images),
+ Active: active,
+ size: size,
+ reclaimable: reclaimable,
+ }
+ dfSummaries = append(dfSummaries, &imageSummary)
+
+ // Containers
+
+ var (
+ conActive int
+ conSize, conReclaimable int64
+ )
+ for _, c := range reports.Containers {
+ if c.Status == "running" {
+ conActive += 1
+ } else {
+ conReclaimable += c.RWSize
+ }
+ conSize += c.RWSize
+ }
+
+ containerSummary := dfSummary{
+ Type: "Containers",
+ Total: len(reports.Containers),
+ Active: conActive,
+ size: conSize,
+ reclaimable: conReclaimable,
+ }
+
+ dfSummaries = append(dfSummaries, &containerSummary)
+
+ // Volumes
+ var (
+ activeVolumes int
+ volumesSize, volumesReclaimable int64
+ )
+
+ for _, v := range reports.Volumes {
+ activeVolumes += v.Links
+ volumesSize += v.Size
+ volumesReclaimable += v.Size
+ }
+ volumeSummary := dfSummary{
+ Type: "Local Volumes",
+ Total: len(reports.Volumes),
+ Active: activeVolumes,
+ size: volumesSize,
+ reclaimable: volumesReclaimable,
+ }
+
+ dfSummaries = append(dfSummaries, &volumeSummary)
+
+ headers := "TYPE\tTOTAL\tACTIVE\tSIZE\tRECLAIMABLE\n"
+ format = "{{range . }}" + format + "{{end}}"
+ if len(userFormat) == 0 {
+ format = headers + format
+ }
+ return writeTemplate(w, format, dfSummaries)
+}
+
+func printVerbose(reports *entities.SystemDfReport) error {
+ var (
+ dfImages []*dfImage
+ dfContainers []*dfContainer
+ dfVolumes []*dfVolume
+ w io.Writer = os.Stdout
+ )
+
+ // Images
+ fmt.Print("\nImages space usage:\n\n")
+ // convert to dfImage for output
+ for _, d := range reports.Images {
+ dfImages = append(dfImages, &dfImage{SystemDfImageReport: d})
+ }
+ imageHeaders := "REPOSITORY\tTAG\tIMAGE ID\tCREATED\tSIZE\tSHARED SIZE\tUNIQUE SIZE\tCONTAINERS\n"
+ imageRow := "{{.Repository}}\t{{.Tag}}\t{{.ImageID}}\t{{.Created}}\t{{.Size}}\t{{.SharedSize}}\t{{.UniqueSize}}\t{{.Containers}}\n"
+ format := imageHeaders + "{{range . }}" + imageRow + "{{end}}"
+ if err := writeTemplate(w, format, dfImages); err != nil {
+ return nil
+ }
+
+ // Containers
+ fmt.Print("\nContainers space usage:\n\n")
+
+ // convert to dfContainers for output
+ for _, d := range reports.Containers {
+ dfContainers = append(dfContainers, &dfContainer{SystemDfContainerReport: d})
+ }
+ containerHeaders := "CONTAINER ID\tIMAGE\tCOMMAND\tLOCAL VOLUMES\tSIZE\tCREATED\tSTATUS\tNAMES\n"
+ containerRow := "{{.ContainerID}}\t{{.Image}}\t{{.Command}}\t{{.LocalVolumes}}\t{{.Size}}\t{{.Created}}\t{{.Status}}\t{{.Names}}\n"
+ format = containerHeaders + "{{range . }}" + containerRow + "{{end}}"
+ if err := writeTemplate(w, format, dfContainers); err != nil {
+ return nil
+ }
+
+ // Volumes
+ fmt.Print("\nLocal Volumes space usage:\n\n")
+
+ // convert to dfVolume for output
+ for _, d := range reports.Volumes {
+ dfVolumes = append(dfVolumes, &dfVolume{SystemDfVolumeReport: d})
+ }
+ volumeHeaders := "VOLUME NAME\tLINKS\tSIZE\n"
+ volumeRow := "{{.VolumeName}}\t{{.Links}}\t{{.Size}}\n"
+ format = volumeHeaders + "{{range . }}" + volumeRow + "{{end}}"
+ return writeTemplate(w, format, dfVolumes)
+}
+
+func writeTemplate(w io.Writer, format string, output interface{}) error {
+ tmpl, err := template.New("dfout").Parse(format)
+ if err != nil {
+ return err
+ }
+ w = tabwriter.NewWriter(w, 8, 2, 2, ' ', 0) //nolint
+ if err := tmpl.Execute(w, output); err != nil {
+ return err
+ }
+ if flusher, ok := w.(interface{ Flush() error }); ok {
+ return flusher.Flush()
+ }
+ return nil
+}
+
+type dfImage struct {
+ *entities.SystemDfImageReport
+}
+
+func (d *dfImage) ImageID() string {
+ return d.SystemDfImageReport.ImageID[0:12]
+}
+
+func (d *dfImage) Created() string {
+ return units.HumanDuration(time.Since(d.SystemDfImageReport.Created))
+}
+
+func (d *dfImage) Size() string {
+ return units.HumanSize(float64(d.SystemDfImageReport.Size))
+}
+
+func (d *dfImage) SharedSize() string {
+ return units.HumanSize(float64(d.SystemDfImageReport.SharedSize))
+}
+
+func (d *dfImage) UniqueSize() string {
+ return units.HumanSize(float64(d.SystemDfImageReport.UniqueSize))
+}
+
+type dfContainer struct {
+ *entities.SystemDfContainerReport
+}
+
+func (d *dfContainer) ContainerID() string {
+ return d.SystemDfContainerReport.ContainerID[0:12]
+}
+
+func (d *dfContainer) Image() string {
+ return d.SystemDfContainerReport.Image[0:12]
+}
+
+func (d *dfContainer) Command() string {
+ return strings.Join(d.SystemDfContainerReport.Command, " ")
+}
+
+func (d *dfContainer) Size() string {
+ return units.HumanSize(float64(d.SystemDfContainerReport.Size))
+}
+
+func (d *dfContainer) Created() string {
+ return units.HumanDuration(time.Since(d.SystemDfContainerReport.Created))
+}
+
+type dfVolume struct {
+ *entities.SystemDfVolumeReport
+}
+
+func (d *dfVolume) Size() string {
+ return units.HumanSize(float64(d.SystemDfVolumeReport.Size))
+}
+
+type dfSummary struct {
+ Type string
+ Total int
+ Active int
+ size int64
+ reclaimable int64
+}
+
+func (d *dfSummary) Size() string {
+ return units.HumanSize(float64(d.size))
+}
+
+func (d *dfSummary) Reclaimable() string {
+ percent := int(float64(d.reclaimable)/float64(d.size)) * 100
+ return fmt.Sprintf("%s (%d%%)", units.HumanSize(float64(d.reclaimable)), percent)
+}
diff --git a/cmd/podman/system/migrate.go b/cmd/podman/system/migrate.go
new file mode 100644
index 000000000..13aa162c7
--- /dev/null
+++ b/cmd/podman/system/migrate.go
@@ -0,0 +1,63 @@
+package system
+
+import (
+ "fmt"
+ "os"
+
+ "github.com/containers/libpod/cmd/podman/registry"
+ "github.com/containers/libpod/cmd/podman/validate"
+ "github.com/containers/libpod/pkg/domain/entities"
+ "github.com/containers/libpod/pkg/domain/infra"
+ "github.com/spf13/cobra"
+)
+
+var (
+ migrateDescription = `
+ podman system migrate
+
+ Migrate existing containers to a new version of Podman.
+`
+
+ migrateCommand = &cobra.Command{
+ Use: "migrate",
+ Args: validate.NoArgs,
+ Short: "Migrate containers",
+ Long: migrateDescription,
+ Run: migrate,
+ }
+)
+
+var (
+ migrateOptions entities.SystemMigrateOptions
+)
+
+func init() {
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Mode: []entities.EngineMode{entities.ABIMode},
+ Command: migrateCommand,
+ Parent: systemCmd,
+ })
+
+ flags := migrateCommand.Flags()
+ flags.StringVar(&migrateOptions.NewRuntime, "new-runtime", "", "Specify a new runtime for all containers")
+}
+
+func migrate(cmd *cobra.Command, args []string) {
+ // Shutdown all running engines, `renumber` will hijack repository
+ registry.ContainerEngine().Shutdown(registry.Context())
+ registry.ImageEngine().Shutdown(registry.Context())
+
+ engine, err := infra.NewSystemEngine(entities.MigrateMode, registry.PodmanConfig())
+ if err != nil {
+ fmt.Println(err)
+ os.Exit(125)
+ }
+ defer engine.Shutdown(registry.Context())
+
+ err = engine.Migrate(registry.Context(), cmd.Flags(), registry.PodmanConfig(), migrateOptions)
+ if err != nil {
+ fmt.Println(err)
+ os.Exit(125)
+ }
+ os.Exit(0)
+}
diff --git a/cmd/podman/system/renumber.go b/cmd/podman/system/renumber.go
new file mode 100644
index 000000000..5ee6b3be6
--- /dev/null
+++ b/cmd/podman/system/renumber.go
@@ -0,0 +1,57 @@
+package system
+
+import (
+ "fmt"
+ "os"
+
+ "github.com/containers/libpod/cmd/podman/registry"
+ "github.com/containers/libpod/cmd/podman/validate"
+ "github.com/containers/libpod/pkg/domain/entities"
+ "github.com/containers/libpod/pkg/domain/infra"
+ "github.com/spf13/cobra"
+)
+
+var (
+ renumberDescription = `
+ podman system renumber
+
+ Migrate lock numbers to handle a change in maximum number of locks.
+ Mandatory after the number of locks in libpod.conf is changed.
+`
+
+ renumberCommand = &cobra.Command{
+ Use: "renumber",
+ Args: validate.NoArgs,
+ Short: "Migrate lock numbers",
+ Long: renumberDescription,
+ Run: renumber,
+ }
+)
+
+func init() {
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Mode: []entities.EngineMode{entities.ABIMode},
+ Command: renumberCommand,
+ Parent: systemCmd,
+ })
+
+}
+func renumber(cmd *cobra.Command, args []string) {
+ // Shutdown all running engines, `renumber` will hijack all methods
+ registry.ContainerEngine().Shutdown(registry.Context())
+ registry.ImageEngine().Shutdown(registry.Context())
+
+ engine, err := infra.NewSystemEngine(entities.RenumberMode, registry.PodmanConfig())
+ if err != nil {
+ fmt.Println(err)
+ os.Exit(125)
+ }
+ defer engine.Shutdown(registry.Context())
+
+ err = engine.Renumber(registry.Context(), cmd.Flags(), registry.PodmanConfig())
+ if err != nil {
+ fmt.Println(err)
+ os.Exit(125)
+ }
+ os.Exit(0)
+}
diff --git a/cmd/podman/system/reset.go b/cmd/podman/system/reset.go
new file mode 100644
index 000000000..22ddc7529
--- /dev/null
+++ b/cmd/podman/system/reset.go
@@ -0,0 +1,82 @@
+package system
+
+import (
+ "bufio"
+ "fmt"
+ "os"
+ "strings"
+
+ "github.com/containers/libpod/cmd/podman/registry"
+ "github.com/containers/libpod/cmd/podman/validate"
+ "github.com/containers/libpod/pkg/domain/entities"
+ "github.com/containers/libpod/pkg/domain/infra"
+ "github.com/pkg/errors"
+ "github.com/spf13/cobra"
+)
+
+var (
+ systemResetDescription = `Reset podman storage back to default state"
+
+ All containers will be stopped and removed, and all images, volumes and container content will be removed.
+`
+ systemResetCommand = &cobra.Command{
+ Use: "reset",
+ Args: validate.NoArgs,
+ Short: "Reset podman storage",
+ Long: systemResetDescription,
+ Run: reset,
+ }
+)
+
+var (
+ systemResetOptions entities.SystemResetOptions
+)
+
+func init() {
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Mode: []entities.EngineMode{entities.ABIMode},
+ Command: systemResetCommand,
+ Parent: systemCmd,
+ })
+ flags := systemResetCommand.Flags()
+ flags.BoolVarP(&systemResetOptions.Force, "force", "f", false, "Do not prompt for confirmation")
+}
+
+func reset(cmd *cobra.Command, args []string) {
+ // Prompt for confirmation if --force is not set
+ if !systemResetOptions.Force {
+ reader := bufio.NewReader(os.Stdin)
+ fmt.Print(`
+WARNING! This will remove:
+ - all containers
+ - all pods
+ - all images
+ - all build cache
+Are you sure you want to continue? [y/N] `)
+ answer, err := reader.ReadString('\n')
+ if err != nil {
+ fmt.Println(errors.Wrapf(err, "error reading input"))
+ os.Exit(1)
+ }
+ if strings.ToLower(answer)[0] != 'y' {
+ os.Exit(0)
+ }
+ }
+
+ // Shutdown all running engines, `reset` will hijack repository
+ registry.ContainerEngine().Shutdown(registry.Context())
+ registry.ImageEngine().Shutdown(registry.Context())
+
+ engine, err := infra.NewSystemEngine(entities.ResetMode, registry.PodmanConfig())
+ if err != nil {
+ fmt.Println(err)
+ os.Exit(125)
+ }
+ defer engine.Shutdown(registry.Context())
+
+ if err := engine.Reset(registry.Context(), systemResetOptions); err != nil {
+ fmt.Println(err)
+ os.Exit(125)
+ }
+ os.Exit(0)
+}
diff --git a/libpod/volume.go b/libpod/volume.go
index 70099d6f4..82f389833 100644
--- a/libpod/volume.go
+++ b/libpod/volume.go
@@ -3,6 +3,7 @@ package libpod
import (
"time"
+ "github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/libpod/lock"
)
@@ -133,3 +134,15 @@ func (v *Volume) Config() (*VolumeConfig, error) {
err := JSONDeepCopy(v.config, &config)
return &config, err
}
+
+// VolumeInUse goes through the container dependencies of a volume
+// and checks if the volume is being used by any container.
+func (v *Volume) VolumesInUse() ([]string, error) {
+ v.lock.Lock()
+ defer v.lock.Unlock()
+
+ if !v.valid {
+ return nil, define.ErrVolumeRemoved
+ }
+ return v.runtime.state.VolumeInUse(v)
+}
diff --git a/pkg/domain/entities/engine.go b/pkg/domain/entities/engine.go
index f45218d14..265c9f36f 100644
--- a/pkg/domain/entities/engine.go
+++ b/pkg/domain/entities/engine.go
@@ -12,9 +12,18 @@ import (
// EngineMode is the connection type podman is using to access libpod
type EngineMode string
+// EngineSetup calls out whether a "normal" or specialized engine should be created
+type EngineSetup string
+
const (
ABIMode = EngineMode("abi")
TunnelMode = EngineMode("tunnel")
+
+ MigrateMode = EngineSetup("migrate")
+ NoFDsMode = EngineSetup("disablefds")
+ NormalMode = EngineSetup("normal")
+ RenumberMode = EngineSetup("renumber")
+ ResetMode = EngineSetup("reset")
)
// Convert EngineMode to String
diff --git a/pkg/domain/entities/engine_container.go b/pkg/domain/entities/engine_container.go
index 734f72e5f..98e4d841f 100644
--- a/pkg/domain/entities/engine_container.go
+++ b/pkg/domain/entities/engine_container.go
@@ -65,6 +65,7 @@ type ContainerEngine interface {
PodUnpause(ctx context.Context, namesOrIds []string, options PodunpauseOptions) ([]*PodUnpauseReport, error)
SetupRootless(ctx context.Context, cmd *cobra.Command) error
Shutdown(ctx context.Context)
+ SystemDf(ctx context.Context, options SystemDfOptions) (*SystemDfReport, error)
VarlinkService(ctx context.Context, opts ServiceOptions) error
VolumeCreate(ctx context.Context, opts VolumeCreateOptions) (*IdOrNameResponse, error)
VolumeInspect(ctx context.Context, namesOrIds []string, opts VolumeInspectOptions) ([]*VolumeInspectReport, error)
diff --git a/pkg/domain/entities/engine_system.go b/pkg/domain/entities/engine_system.go
new file mode 100644
index 000000000..e2000f5cb
--- /dev/null
+++ b/pkg/domain/entities/engine_system.go
@@ -0,0 +1,14 @@
+package entities
+
+import (
+ "context"
+
+ "github.com/spf13/pflag"
+)
+
+type SystemEngine interface {
+ Renumber(ctx context.Context, flags *pflag.FlagSet, config *PodmanConfig) error
+ Migrate(ctx context.Context, flags *pflag.FlagSet, config *PodmanConfig, options SystemMigrateOptions) error
+ Reset(ctx context.Context, options SystemResetOptions) error
+ Shutdown(ctx context.Context)
+}
diff --git a/pkg/domain/entities/system.go b/pkg/domain/entities/system.go
index de93a382f..c62f40025 100644
--- a/pkg/domain/entities/system.go
+++ b/pkg/domain/entities/system.go
@@ -26,3 +26,60 @@ type SystemPruneReport struct {
*ImagePruneReport
VolumePruneReport []*VolumePruneReport
}
+
+// SystemMigrateOptions describes the options needed for the
+// cli to migrate runtimes of containers
+type SystemMigrateOptions struct {
+ NewRuntime string
+}
+
+// SystemDfOptions describes the options for getting df information
+type SystemDfOptions struct {
+ Format string
+ Verbose bool
+}
+
+// SystemDfReport describes the response for df information
+type SystemDfReport struct {
+ Images []*SystemDfImageReport
+ Containers []*SystemDfContainerReport
+ Volumes []*SystemDfVolumeReport
+}
+
+// SystemDfImageReport describes an image for use with df
+type SystemDfImageReport struct {
+ Repository string
+ Tag string
+ ImageID string
+ Created time.Time
+ Size int64
+ SharedSize int64
+ UniqueSize int64
+ Containers int
+}
+
+// SystemDfContainerReport describes a container for use with df
+type SystemDfContainerReport struct {
+ ContainerID string
+ Image string
+ Command []string
+ LocalVolumes int
+ Size int64
+ RWSize int64
+ Created time.Time
+ Status string
+ Names string
+}
+
+// SystemDfVolumeReport describes a volume and its size
+type SystemDfVolumeReport struct {
+ VolumeName string
+ Links int
+ Size int64
+}
+
+// SystemResetOptions describes the options for resetting your
+// container runtime storage, etc
+type SystemResetOptions struct {
+ Force bool
+}
diff --git a/pkg/domain/infra/abi/runtime.go b/pkg/domain/infra/abi/runtime.go
index fba422d8e..b9020e9a5 100644
--- a/pkg/domain/infra/abi/runtime.go
+++ b/pkg/domain/infra/abi/runtime.go
@@ -16,4 +16,9 @@ type ContainerEngine struct {
Libpod *libpod.Runtime
}
+// Container-related runtime linked against libpod library
+type SystemEngine struct {
+ Libpod *libpod.Runtime
+}
+
var shutdownSync sync.Once
diff --git a/pkg/domain/infra/abi/system.go b/pkg/domain/infra/abi/system.go
index ab1b282d8..692fcfa0f 100644
--- a/pkg/domain/infra/abi/system.go
+++ b/pkg/domain/infra/abi/system.go
@@ -5,6 +5,7 @@ import (
"fmt"
"io/ioutil"
"os"
+ "path/filepath"
"strconv"
"syscall"
@@ -18,9 +19,11 @@ import (
iopodmanAPI "github.com/containers/libpod/pkg/varlinkapi"
"github.com/containers/libpod/utils"
"github.com/containers/libpod/version"
+ "github.com/docker/distribution/reference"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
+ "github.com/spf13/pflag"
"github.com/varlink/go/varlink"
)
@@ -213,3 +216,177 @@ func (ic *ContainerEngine) SystemPrune(ctx context.Context, options entities.Sys
}
return systemPruneReport, nil
}
+
+func (ic *ContainerEngine) SystemDf(ctx context.Context, options entities.SystemDfOptions) (*entities.SystemDfReport, error) {
+ var (
+ dfImages []*entities.SystemDfImageReport
+ dfContainers []*entities.SystemDfContainerReport
+ dfVolumes []*entities.SystemDfVolumeReport
+ runningContainers []string
+ )
+
+ // Get Images and iterate them
+ imgs, err := ic.Libpod.ImageRuntime().GetImages()
+ if err != nil {
+ return nil, err
+ }
+ for _, i := range imgs {
+ var sharedSize uint64
+ cons, err := i.Containers()
+ if err != nil {
+ return nil, err
+ }
+ imageSize, err := i.Size(ctx)
+ if err != nil {
+ return nil, err
+ }
+ uniqueSize := *imageSize
+
+ parent, err := i.GetParent(ctx)
+ if err != nil {
+ return nil, err
+ }
+ if parent != nil {
+ parentSize, err := parent.Size(ctx)
+ if err != nil {
+ return nil, err
+ }
+ uniqueSize = *parentSize - *imageSize
+ sharedSize = *imageSize - uniqueSize
+ }
+ var name, repository, tag string
+ for _, n := range i.Names() {
+ if len(n) > 0 {
+ name = n
+ break
+ }
+ }
+
+ named, err := reference.ParseNormalizedNamed(name)
+ if err != nil {
+ return nil, err
+ }
+ repository = named.Name()
+ if tagged, isTagged := named.(reference.NamedTagged); isTagged {
+ tag = tagged.Tag()
+ }
+
+ report := entities.SystemDfImageReport{
+ Repository: repository,
+ Tag: tag,
+ ImageID: i.ID(),
+ Created: i.Created(),
+ Size: int64(*imageSize),
+ SharedSize: int64(sharedSize),
+ UniqueSize: int64(uniqueSize),
+ Containers: len(cons),
+ }
+ dfImages = append(dfImages, &report)
+ }
+
+ // GetContainers and iterate them
+ cons, err := ic.Libpod.GetAllContainers()
+ if err != nil {
+ return nil, err
+ }
+ for _, c := range cons {
+ iid, _ := c.Image()
+ conSize, err := c.RootFsSize()
+ if err != nil {
+ return nil, err
+ }
+ state, err := c.State()
+ if err != nil {
+ return nil, err
+ }
+ rwsize, err := c.RWSize()
+ if err != nil {
+ return nil, err
+ }
+ report := entities.SystemDfContainerReport{
+ ContainerID: c.ID(),
+ Image: iid,
+ Command: c.Command(),
+ LocalVolumes: len(c.UserVolumes()),
+ RWSize: rwsize,
+ Size: conSize,
+ Created: c.CreatedTime(),
+ Status: state.String(),
+ Names: c.Name(),
+ }
+ dfContainers = append(dfContainers, &report)
+ }
+
+ // Get volumes and iterate them
+ vols, err := ic.Libpod.GetAllVolumes()
+ if err != nil {
+ return nil, err
+ }
+
+ running, err := ic.Libpod.GetRunningContainers()
+ if err != nil {
+ return nil, err
+ }
+ for _, c := range running {
+ runningContainers = append(runningContainers, c.ID())
+ }
+
+ for _, v := range vols {
+ var consInUse int
+ volSize, err := sizeOfPath(v.MountPoint())
+ if err != nil {
+ return nil, err
+ }
+ inUse, err := v.VolumesInUse()
+ if err != nil {
+ return nil, err
+ }
+ for _, viu := range inUse {
+ if util.StringInSlice(viu, runningContainers) {
+ consInUse += 1
+ }
+ }
+ report := entities.SystemDfVolumeReport{
+ VolumeName: v.Name(),
+ Links: consInUse,
+ Size: volSize,
+ }
+ dfVolumes = append(dfVolumes, &report)
+ }
+ return &entities.SystemDfReport{
+ Images: dfImages,
+ Containers: dfContainers,
+ Volumes: dfVolumes,
+ }, nil
+}
+
+// sizeOfPath determines the file usage of a given path. it was called volumeSize in v1
+// and now is made to be generic and take a path instead of a libpod volume
+func sizeOfPath(path string) (int64, error) {
+ var size int64
+ err := filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
+ if err == nil && !info.IsDir() {
+ size += info.Size()
+ }
+ return err
+ })
+ return size, err
+}
+
+func (se *SystemEngine) Reset(ctx context.Context, options entities.SystemResetOptions) error {
+ return se.Libpod.Reset(ctx)
+}
+
+func (se *SystemEngine) Renumber(ctx context.Context, flags *pflag.FlagSet, config *entities.PodmanConfig) error {
+ return nil
+}
+
+func (s SystemEngine) Migrate(ctx context.Context, flags *pflag.FlagSet, config *entities.PodmanConfig, options entities.SystemMigrateOptions) error {
+ return nil
+}
+
+func (s SystemEngine) Shutdown(ctx context.Context) {
+ if err := s.Libpod.Shutdown(false); err != nil {
+ logrus.Error(err)
+ }
+}
diff --git a/pkg/domain/infra/runtime_abi.go b/pkg/domain/infra/runtime_abi.go
index 7aa6986a7..67c1cd534 100644
--- a/pkg/domain/infra/runtime_abi.go
+++ b/pkg/domain/infra/runtime_abi.go
@@ -6,8 +6,10 @@ import (
"context"
"fmt"
+ "github.com/containers/libpod/libpod"
"github.com/containers/libpod/pkg/bindings"
"github.com/containers/libpod/pkg/domain/entities"
+ "github.com/containers/libpod/pkg/domain/infra/abi"
"github.com/containers/libpod/pkg/domain/infra/tunnel"
)
@@ -36,3 +38,32 @@ func NewImageEngine(facts *entities.PodmanConfig) (entities.ImageEngine, error)
}
return nil, fmt.Errorf("runtime mode '%v' is not supported", facts.EngineMode)
}
+
+// NewSystemEngine factory provides a libpod runtime for specialized system operations
+func NewSystemEngine(setup entities.EngineSetup, facts *entities.PodmanConfig) (entities.SystemEngine, error) {
+ switch facts.EngineMode {
+ case entities.ABIMode:
+ var r *libpod.Runtime
+ var err error
+ switch setup {
+ case entities.NormalMode:
+ r, err = GetRuntime(context.Background(), facts.FlagSet, facts)
+ case entities.RenumberMode:
+ r, err = GetRuntimeRenumber(context.Background(), facts.FlagSet, facts)
+ case entities.ResetMode:
+ r, err = GetRuntimeRenumber(context.Background(), facts.FlagSet, facts)
+ case entities.MigrateMode:
+ name, flagErr := facts.FlagSet.GetString("new-runtime")
+ if flagErr != nil {
+ return nil, flagErr
+ }
+ r, err = GetRuntimeMigrate(context.Background(), facts.FlagSet, facts, name)
+ case entities.NoFDsMode:
+ r, err = GetRuntimeDisableFDs(context.Background(), facts.FlagSet, facts)
+ }
+ return &abi.SystemEngine{Libpod: r}, err
+ case entities.TunnelMode:
+ return nil, fmt.Errorf("tunnel system runtime not supported")
+ }
+ return nil, fmt.Errorf("runtime mode '%v' is not supported", facts.EngineMode)
+}
diff --git a/pkg/domain/infra/runtime_abi_unsupported.go b/pkg/domain/infra/runtime_abi_unsupported.go
new file mode 100644
index 000000000..c4e25e990
--- /dev/null
+++ b/pkg/domain/infra/runtime_abi_unsupported.go
@@ -0,0 +1,14 @@
+// +build !ABISupport
+
+package infra
+
+import (
+ "errors"
+
+ "github.com/containers/libpod/pkg/domain/entities"
+)
+
+// NewSystemEngine factory provides a libpod runtime for specialized system operations
+func NewSystemEngine(setup entities.EngineSetup, facts *entities.PodmanConfig) (entities.SystemEngine, error) {
+ return nil, errors.New("not implemented")
+}
diff --git a/pkg/domain/infra/runtime_image_proxy.go b/pkg/domain/infra/runtime_image_proxy.go
deleted file mode 100644
index ea5d0e6f2..000000000
--- a/pkg/domain/infra/runtime_image_proxy.go
+++ /dev/null
@@ -1,21 +0,0 @@
-// +build ABISupport
-
-package infra
-
-import (
- "context"
-
- "github.com/containers/libpod/pkg/domain/entities"
- "github.com/containers/libpod/pkg/domain/infra/abi"
- "github.com/spf13/pflag"
-)
-
-// ContainerEngine Image Proxy will be EOL'ed after podman is separated from libpod repo
-
-func NewLibpodImageRuntime(flags *pflag.FlagSet, opts *entities.PodmanConfig) (entities.ImageEngine, error) {
- r, err := GetRuntime(context.Background(), flags, opts)
- if err != nil {
- return nil, err
- }
- return &abi.ImageEngine{Libpod: r}, nil
-}
diff --git a/pkg/domain/infra/runtime_proxy.go b/pkg/domain/infra/runtime_proxy.go
index 41193fd89..e7002e20f 100644
--- a/pkg/domain/infra/runtime_proxy.go
+++ b/pkg/domain/infra/runtime_proxy.go
@@ -19,3 +19,11 @@ func NewLibpodRuntime(flags *flag.FlagSet, opts *entities.PodmanConfig) (entitie
}
return &abi.ContainerEngine{Libpod: r}, nil
}
+
+func NewLibpodImageRuntime(flags *flag.FlagSet, opts *entities.PodmanConfig) (entities.ImageEngine, error) {
+ r, err := GetRuntime(context.Background(), flags, opts)
+ if err != nil {
+ return nil, err
+ }
+ return &abi.ImageEngine{Libpod: r}, nil
+}
diff --git a/pkg/domain/infra/tunnel/system.go b/pkg/domain/infra/tunnel/system.go
index 18cb6c75a..448fbed1f 100644
--- a/pkg/domain/infra/tunnel/system.go
+++ b/pkg/domain/infra/tunnel/system.go
@@ -3,7 +3,6 @@ package tunnel
import (
"context"
"errors"
- "fmt"
"github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/pkg/bindings/system"
@@ -25,6 +24,9 @@ func (ic *ContainerEngine) SetupRootless(_ context.Context, cmd *cobra.Command)
// SystemPrune prunes unused data from the system.
func (ic *ContainerEngine) SystemPrune(ctx context.Context, options entities.SystemPruneOptions) (*entities.SystemPruneReport, error) {
- fmt.Println("in tunnel")
return system.Prune(ic.ClientCxt, &options.All, &options.Volume)
}
+
+func (ic *ContainerEngine) SystemDf(ctx context.Context, options entities.SystemDfOptions) (*entities.SystemDfReport, error) {
+ panic(errors.New("system df is not supported on remote clients"))
+}
diff --git a/test/e2e/system_df_test.go b/test/e2e/system_df_test.go
index 5f261fcbf..bbbdf30b0 100644
--- a/test/e2e/system_df_test.go
+++ b/test/e2e/system_df_test.go
@@ -20,7 +20,6 @@ var _ = Describe("podman system df", func() {
)
BeforeEach(func() {
- Skip(v2fail)
tempdir, err = CreateTempDirInTempDir()
if err != nil {
os.Exit(1)
diff --git a/test/e2e/system_reset_test.go b/test/e2e/system_reset_test.go
index f17747648..e5ce69739 100644
--- a/test/e2e/system_reset_test.go
+++ b/test/e2e/system_reset_test.go
@@ -17,7 +17,6 @@ var _ = Describe("podman system reset", func() {
)
BeforeEach(func() {
- Skip(v2fail)
tempdir, err = CreateTempDirInTempDir()
if err != nil {
os.Exit(1)