diff options
Diffstat (limited to 'cmd/podman/system')
-rw-r--r-- | cmd/podman/system/df.go | 282 | ||||
-rw-r--r-- | cmd/podman/system/events.go | 8 | ||||
-rw-r--r-- | cmd/podman/system/info.go | 26 | ||||
-rw-r--r-- | cmd/podman/system/migrate.go | 63 | ||||
-rw-r--r-- | cmd/podman/system/prune.go | 103 | ||||
-rw-r--r-- | cmd/podman/system/renumber.go | 57 | ||||
-rw-r--r-- | cmd/podman/system/reset.go | 80 | ||||
-rw-r--r-- | cmd/podman/system/service.go | 27 | ||||
-rw-r--r-- | cmd/podman/system/system.go | 3 | ||||
-rw-r--r-- | cmd/podman/system/unshare.go | 50 | ||||
-rw-r--r-- | cmd/podman/system/varlink.go | 7 | ||||
-rw-r--r-- | cmd/podman/system/version.go | 89 |
12 files changed, 719 insertions, 76 deletions
diff --git a/cmd/podman/system/df.go b/cmd/podman/system/df.go new file mode 100644 index 000000000..8fe035209 --- /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, entities.TunnelMode}, + 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/events.go b/cmd/podman/system/events.go index 31dd9aa77..27e80138e 100644 --- a/cmd/podman/system/events.go +++ b/cmd/podman/system/events.go @@ -5,10 +5,11 @@ import ( "context" "html/template" "os" + "strings" "github.com/containers/buildah/pkg/formats" - "github.com/containers/libpod/cmd/podman/common" "github.com/containers/libpod/cmd/podman/registry" + "github.com/containers/libpod/cmd/podman/validate" "github.com/containers/libpod/libpod/events" "github.com/containers/libpod/pkg/domain/entities" "github.com/pkg/errors" @@ -19,7 +20,7 @@ var ( eventsDescription = "Monitor podman events" eventsCommand = &cobra.Command{ Use: "events", - Args: common.NoArgs, + Args: validate.NoArgs, Short: "Show podman events", Long: eventsDescription, RunE: eventsCmd, @@ -54,6 +55,9 @@ func eventsCmd(cmd *cobra.Command, args []string) error { eventsError error tmpl *template.Template ) + if strings.Join(strings.Fields(eventFormat), "") == "{{json.}}" { + eventFormat = formats.JSONString + } if eventFormat != formats.JSONString { tmpl, err = template.New("events").Parse(eventFormat) if err != nil { diff --git a/cmd/podman/system/info.go b/cmd/podman/system/info.go index 143796938..dad63bcd4 100644 --- a/cmd/podman/system/info.go +++ b/cmd/podman/system/info.go @@ -5,11 +5,12 @@ import ( "os" "text/template" - "github.com/containers/libpod/cmd/podman/common" "github.com/containers/libpod/cmd/podman/registry" + "github.com/containers/libpod/cmd/podman/validate" "github.com/containers/libpod/pkg/domain/entities" "github.com/ghodss/yaml" "github.com/spf13/cobra" + "github.com/spf13/pflag" ) var ( @@ -19,12 +20,21 @@ var ( ` infoCommand = &cobra.Command{ Use: "info", - Args: common.NoArgs, + Args: validate.NoArgs, Long: infoDescription, Short: "Display podman system information", RunE: info, Example: `podman info`, } + + systemInfoCommand = &cobra.Command{ + Args: infoCommand.Args, + Use: infoCommand.Use, + Short: infoCommand.Short, + Long: infoCommand.Long, + RunE: infoCommand.RunE, + Example: `podman system info`, + } ) var ( @@ -37,7 +47,17 @@ func init() { Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode}, Command: infoCommand, }) - flags := infoCommand.Flags() + infoFlags(infoCommand.Flags()) + + registry.Commands = append(registry.Commands, registry.CliCommand{ + Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode}, + Command: systemInfoCommand, + Parent: systemCmd, + }) + infoFlags(systemInfoCommand.Flags()) +} + +func infoFlags(flags *pflag.FlagSet) { flags.BoolVarP(&debug, "debug", "D", false, "Display additional debug information") flags.StringVarP(&inFormat, "format", "f", "", "Change the output format to JSON or a Go template") } 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/prune.go b/cmd/podman/system/prune.go new file mode 100644 index 000000000..cc9b473f1 --- /dev/null +++ b/cmd/podman/system/prune.go @@ -0,0 +1,103 @@ +package system + +import ( + "bufio" + "context" + "fmt" + "os" + "strings" + + "github.com/containers/libpod/cmd/podman/registry" + "github.com/containers/libpod/cmd/podman/utils" + "github.com/containers/libpod/cmd/podman/validate" + "github.com/containers/libpod/pkg/domain/entities" + "github.com/pkg/errors" + "github.com/spf13/cobra" +) + +var ( + pruneOptions = entities.SystemPruneOptions{} + + pruneDescription = fmt.Sprintf(` + podman system prune + + Remove unused data +`) + + pruneCommand = &cobra.Command{ + Use: "prune [flags]", + Short: "Remove unused data", + Args: validate.NoArgs, + Long: pruneDescription, + RunE: prune, + Example: `podman system prune`, + } + force bool +) + +func init() { + registry.Commands = append(registry.Commands, registry.CliCommand{ + Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode}, + Command: pruneCommand, + Parent: systemCmd, + }) + flags := pruneCommand.Flags() + flags.BoolVarP(&force, "force", "f", false, "Do not prompt for confirmation. The default is false") + flags.BoolVarP(&pruneOptions.All, "all", "a", false, "Remove all unused data") + flags.BoolVar(&pruneOptions.Volume, "volumes", false, "Prune volumes") + +} + +func prune(cmd *cobra.Command, args []string) error { + // Prompt for confirmation if --force is not set + if !force { + reader := bufio.NewReader(os.Stdin) + volumeString := "" + if pruneOptions.Volume { + volumeString = ` + - all volumes not used by at least one container` + } + fmt.Printf(` +WARNING! This will remove: + - all stopped containers%s + - all stopped pods + - all dangling images + - all build cache +Are you sure you want to continue? [y/N] `, volumeString) + answer, err := reader.ReadString('\n') + if err != nil { + return errors.Wrapf(err, "error reading input") + } + if strings.ToLower(answer)[0] != 'y' { + return nil + } + } + // TODO: support for filters in system prune + response, err := registry.ContainerEngine().SystemPrune(context.Background(), pruneOptions) + if err != nil { + return err + } + // Print pod prune results + fmt.Println("Deleted Pods") + err = utils.PrintPodPruneResults(response.PodPruneReport) + if err != nil { + return err + } + // Print container prune results + fmt.Println("Deleted Containers") + err = utils.PrintContainerPruneResults(response.ContainerPruneReport) + if err != nil { + return err + } + // Print Volume prune results + if pruneOptions.Volume { + fmt.Println("Deleted Volumes") + err = utils.PrintVolumePruneResults(response.VolumePruneReport) + if err != nil { + return err + } + } + // Print Images prune results + fmt.Println("Deleted Images") + return utils.PrintImagePruneResults(response.ImagePruneReport) +} 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..6caa91690 --- /dev/null +++ b/cmd/podman/system/reset.go @@ -0,0 +1,80 @@ +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, + } + + forceFlag bool +) + +func init() { + registry.Commands = append(registry.Commands, registry.CliCommand{ + Mode: []entities.EngineMode{entities.ABIMode}, + Command: systemResetCommand, + Parent: systemCmd, + }) + flags := systemResetCommand.Flags() + flags.BoolVarP(&forceFlag, "force", "f", false, "Do not prompt for confirmation") +} + +func reset(cmd *cobra.Command, args []string) { + // Prompt for confirmation if --force is not set + if !forceFlag { + 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()); err != nil { + fmt.Println(err) + os.Exit(125) + } + os.Exit(0) +} diff --git a/cmd/podman/system/service.go b/cmd/podman/system/service.go index f4b91dd78..0f42ae28b 100644 --- a/cmd/podman/system/service.go +++ b/cmd/podman/system/service.go @@ -1,3 +1,5 @@ +// +build linux + package system import ( @@ -15,6 +17,7 @@ import ( "github.com/containers/libpod/pkg/util" "github.com/sirupsen/logrus" "github.com/spf13/cobra" + "github.com/spf13/pflag" ) var ( @@ -24,13 +27,12 @@ Enable a listening service for API access to Podman commands. ` srvCmd = &cobra.Command{ - Use: "service [flags] [URI]", - Args: cobra.MaximumNArgs(1), - Short: "Run API service", - Long: srvDescription, - RunE: service, - Example: `podman system service --time=0 unix:///tmp/podman.sock - podman system service --varlink --time=0 unix:///tmp/podman.sock`, + Use: "service [flags] [URI]", + Args: cobra.MaximumNArgs(1), + Short: "Run API service", + Long: srvDescription, + RunE: service, + Example: `podman system service --time=0 unix:///tmp/podman.sock`, } srvArgs = struct { @@ -48,10 +50,17 @@ func init() { flags := srvCmd.Flags() flags.Int64VarP(&srvArgs.Timeout, "time", "t", 5, "Time until the service session expires in seconds. Use 0 to disable the timeout") - flags.Int64Var(&srvArgs.Timeout, "timeout", 5, "Time until the service session expires in seconds. Use 0 to disable the timeout") flags.BoolVar(&srvArgs.Varlink, "varlink", false, "Use legacy varlink service instead of REST") _ = flags.MarkDeprecated("varlink", "valink API is deprecated.") + flags.SetNormalizeFunc(aliasTimeoutFlag) +} + +func aliasTimeoutFlag(_ *pflag.FlagSet, name string) pflag.NormalizedName { + if name == "timeout" { + name = "time" + } + return pflag.NormalizedName(name) } func service(cmd *cobra.Command, args []string) error { @@ -139,6 +148,6 @@ func resolveApiURI(_url []string) (string, error) { case srvArgs.Varlink: return registry.DefaultVarlinkAddress, nil default: - return registry.DefaultAPIAddress, nil + return registry.DefaultRootAPIAddress, nil } } diff --git a/cmd/podman/system/system.go b/cmd/podman/system/system.go index 2d55e8c13..d9691ad2a 100644 --- a/cmd/podman/system/system.go +++ b/cmd/podman/system/system.go @@ -2,6 +2,7 @@ package system import ( "github.com/containers/libpod/cmd/podman/registry" + "github.com/containers/libpod/cmd/podman/validate" "github.com/containers/libpod/pkg/domain/entities" "github.com/spf13/cobra" ) @@ -16,7 +17,7 @@ var ( Short: "Manage podman", Long: "Manage podman", TraverseChildren: true, - RunE: registry.SubCommandExists, + RunE: validate.SubCommandExists, } ) diff --git a/cmd/podman/system/unshare.go b/cmd/podman/system/unshare.go new file mode 100644 index 000000000..7db5d36d2 --- /dev/null +++ b/cmd/podman/system/unshare.go @@ -0,0 +1,50 @@ +package system + +import ( + "os" + + "github.com/containers/libpod/cmd/podman/registry" + "github.com/containers/libpod/pkg/domain/entities" + "github.com/containers/libpod/pkg/rootless" + "github.com/pkg/errors" + "github.com/spf13/cobra" +) + +var ( + unshareDescription = "Runs a command in a modified user namespace." + unshareCommand = &cobra.Command{ + Use: "unshare [flags] [COMMAND [ARG]]", + Short: "Run a command in a modified user namespace", + Long: unshareDescription, + RunE: unshare, + Example: `podman unshare id + podman unshare cat /proc/self/uid_map, + podman unshare podman-script.sh`, + } +) + +func init() { + registry.Commands = append(registry.Commands, registry.CliCommand{ + Mode: []entities.EngineMode{entities.ABIMode}, + Command: unshareCommand, + }) + flags := unshareCommand.Flags() + flags.SetInterspersed(false) +} + +func unshare(cmd *cobra.Command, args []string) error { + if isRootless := rootless.IsRootless(); !isRootless { + return errors.Errorf("please use unshare with rootless") + } + // exec the specified command, if there is one + if len(args) < 1 { + // try to exec the shell, if one's set + shell, shellSet := os.LookupEnv("SHELL") + if !shellSet { + return errors.Errorf("no command specified and no $SHELL specified") + } + args = []string{shell} + } + + return registry.ContainerEngine().Unshare(registry.Context(), args) +} diff --git a/cmd/podman/system/varlink.go b/cmd/podman/system/varlink.go index c83f5ff76..6a38b3d28 100644 --- a/cmd/podman/system/varlink.go +++ b/cmd/podman/system/varlink.go @@ -1,3 +1,5 @@ +// +build linux + package system import ( @@ -20,7 +22,7 @@ var ( Long: varlinkDescription, RunE: varlinkE, Example: `podman varlink unix:/run/podman/io.podman - podman varlink --timeout 5000 unix:/run/podman/io.podman`, + podman varlink --time 5000 unix:/run/podman/io.podman`, } varlinkArgs = struct { Timeout int64 @@ -34,8 +36,7 @@ func init() { }) flags := varlinkCmd.Flags() flags.Int64VarP(&varlinkArgs.Timeout, "time", "t", 1000, "Time until the varlink session expires in milliseconds. Use 0 to disable the timeout") - flags.Int64Var(&varlinkArgs.Timeout, "timeout", 1000, "Time until the varlink session expires in milliseconds. Use 0 to disable the timeout") - + flags.SetNormalizeFunc(aliasTimeoutFlag) } func varlinkE(cmd *cobra.Command, args []string) error { diff --git a/cmd/podman/system/version.go b/cmd/podman/system/version.go index b0f4eb528..92a3225b6 100644 --- a/cmd/podman/system/version.go +++ b/cmd/podman/system/version.go @@ -6,35 +6,25 @@ import ( "os" "strings" "text/tabwriter" - "time" "github.com/containers/buildah/pkg/formats" - "github.com/containers/libpod/cmd/podman/common" "github.com/containers/libpod/cmd/podman/registry" + "github.com/containers/libpod/cmd/podman/validate" "github.com/containers/libpod/libpod/define" "github.com/containers/libpod/pkg/domain/entities" - "github.com/pkg/errors" "github.com/spf13/cobra" ) var ( versionCommand = &cobra.Command{ Use: "version", - Args: common.NoArgs, + Args: validate.NoArgs, Short: "Display the Podman Version Information", RunE: version, - Annotations: map[string]string{ - registry.ParentNSRequired: "", - }, } versionFormat string ) -type versionStruct struct { - Client define.Version - Server define.Version -} - func init() { registry.Commands = append(registry.Commands, registry.CliCommand{ Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode}, @@ -45,78 +35,61 @@ func init() { } func version(cmd *cobra.Command, args []string) error { - var ( - v versionStruct - err error - ) - v.Client, err = define.GetVersion() + versions, err := registry.ContainerEngine().Version(registry.Context()) if err != nil { - return errors.Wrapf(err, "unable to determine version") + return err } - // TODO we need to discuss how to implement - // this more. current endpoints dont have a - // version endpoint. maybe we use info? - //if remote { - // v.Server, err = getRemoteVersion(c) - // if err != nil { - // return err - // } - //} else { - v.Server = v.Client - //} - versionOutputFormat := versionFormat - if versionOutputFormat != "" { - if strings.Join(strings.Fields(versionOutputFormat), "") == "{{json.}}" { - versionOutputFormat = formats.JSONString + switch { + case versionFormat == "json", versionFormat == "{{ json .}}": + s, err := json.MarshalToString(versions) + if err != nil { + return err + } + _, err = io.WriteString(os.Stdout, s) + return err + case cmd.Flag("format").Changed: + if !strings.HasSuffix(versionFormat, "\n") { + versionFormat += "\n" } - var out formats.Writer - switch versionOutputFormat { - case formats.JSONString: - out = formats.JSONStruct{Output: v} - return out.Out() - default: - out = formats.StdoutTemplate{Output: v, Template: versionOutputFormat} - err := out.Out() - if err != nil { - // On Failure, assume user is using older version of podman version --format and check client - out = formats.StdoutTemplate{Output: v.Client, Template: versionOutputFormat} - if err1 := out.Out(); err1 != nil { - return err - } + out := formats.StdoutTemplate{Output: versions, Template: versionFormat} + err := out.Out() + if err != nil { + // On Failure, assume user is using older version of podman version --format and check client + versionFormat = strings.Replace(versionFormat, ".Server.", ".", 1) + out = formats.StdoutTemplate{Output: versions.Client, Template: versionFormat} + if err1 := out.Out(); err1 != nil { + return err } } return nil } + w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0) defer w.Flush() - if registry.IsRemote() { + if versions.Server != nil { if _, err := fmt.Fprintf(w, "Client:\n"); err != nil { return err } - formatVersion(w, v.Client) + formatVersion(w, versions.Client) if _, err := fmt.Fprintf(w, "\nServer:\n"); err != nil { return err } - formatVersion(w, v.Server) + formatVersion(w, versions.Server) } else { - formatVersion(w, v.Client) + formatVersion(w, versions.Client) } return nil } -func formatVersion(writer io.Writer, version define.Version) { +func formatVersion(writer io.Writer, version *define.Version) { fmt.Fprintf(writer, "Version:\t%s\n", version.Version) - fmt.Fprintf(writer, "RemoteAPI Version:\t%d\n", version.RemoteAPIVersion) + fmt.Fprintf(writer, "API Version:\t%d\n", version.APIVersion) fmt.Fprintf(writer, "Go Version:\t%s\n", version.GoVersion) if version.GitCommit != "" { fmt.Fprintf(writer, "Git Commit:\t%s\n", version.GitCommit) } - // Prints out the build time in readable format - if version.Built != 0 { - fmt.Fprintf(writer, "Built:\t%s\n", time.Unix(version.Built, 0).Format(time.ANSIC)) - } - + fmt.Fprintf(writer, "Built:\t%s\n", version.BuiltTime) fmt.Fprintf(writer, "OS/Arch:\t%s\n", version.OsArch) } |