From 25312bb5b4e2bd4e122703006fc85bbf080e5e7c Mon Sep 17 00:00:00 2001 From: baude Date: Fri, 1 May 2020 12:57:41 -0500 Subject: 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 --- cmd/podman/images/load.go | 1 - cmd/podman/system/df.go | 282 ++++++++++++++++++++++++++++ cmd/podman/system/migrate.go | 63 +++++++ cmd/podman/system/renumber.go | 57 ++++++ cmd/podman/system/reset.go | 82 ++++++++ libpod/volume.go | 13 ++ pkg/domain/entities/engine.go | 9 + pkg/domain/entities/engine_container.go | 1 + pkg/domain/entities/engine_system.go | 14 ++ pkg/domain/entities/system.go | 57 ++++++ pkg/domain/infra/abi/runtime.go | 5 + pkg/domain/infra/abi/system.go | 177 +++++++++++++++++ pkg/domain/infra/runtime_abi.go | 31 +++ pkg/domain/infra/runtime_abi_unsupported.go | 14 ++ pkg/domain/infra/runtime_image_proxy.go | 21 --- pkg/domain/infra/runtime_proxy.go | 8 + pkg/domain/infra/tunnel/system.go | 6 +- test/e2e/system_df_test.go | 1 - test/e2e/system_reset_test.go | 1 - 19 files changed, 817 insertions(+), 26 deletions(-) create mode 100644 cmd/podman/system/df.go create mode 100644 cmd/podman/system/migrate.go create mode 100644 cmd/podman/system/renumber.go create mode 100644 cmd/podman/system/reset.go create mode 100644 pkg/domain/entities/engine_system.go create mode 100644 pkg/domain/infra/runtime_abi_unsupported.go delete mode 100644 pkg/domain/infra/runtime_image_proxy.go 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) -- cgit v1.2.3-54-g00ecf