mirror of
https://github.com/containers/podman.git
synced 2025-05-20 08:36:23 +08:00
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>
This commit is contained in:
@ -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()
|
||||
}
|
||||
}
|
||||
|
282
cmd/podman/system/df.go
Normal file
282
cmd/podman/system/df.go
Normal file
@ -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)
|
||||
}
|
63
cmd/podman/system/migrate.go
Normal file
63
cmd/podman/system/migrate.go
Normal file
@ -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)
|
||||
}
|
57
cmd/podman/system/renumber.go
Normal file
57
cmd/podman/system/renumber.go
Normal file
@ -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)
|
||||
}
|
82
cmd/podman/system/reset.go
Normal file
82
cmd/podman/system/reset.go
Normal file
@ -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)
|
||||
}
|
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
14
pkg/domain/entities/engine_system.go
Normal file
14
pkg/domain/entities/engine_system.go
Normal file
@ -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)
|
||||
}
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
14
pkg/domain/infra/runtime_abi_unsupported.go
Normal file
14
pkg/domain/infra/runtime_abi_unsupported.go
Normal file
@ -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")
|
||||
}
|
@ -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
|
||||
}
|
@ -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
|
||||
}
|
||||
|
@ -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"))
|
||||
}
|
||||
|
@ -20,7 +20,6 @@ var _ = Describe("podman system df", func() {
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
Skip(v2fail)
|
||||
tempdir, err = CreateTempDirInTempDir()
|
||||
if err != nil {
|
||||
os.Exit(1)
|
||||
|
@ -17,7 +17,6 @@ var _ = Describe("podman system reset", func() {
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
Skip(v2fail)
|
||||
tempdir, err = CreateTempDirInTempDir()
|
||||
if err != nil {
|
||||
os.Exit(1)
|
||||
|
Reference in New Issue
Block a user