summaryrefslogtreecommitdiff
path: root/cmd/podmanV2
diff options
context:
space:
mode:
Diffstat (limited to 'cmd/podmanV2')
-rw-r--r--cmd/podmanV2/Makefile12
-rw-r--r--cmd/podmanV2/containers/cleanup.go75
-rw-r--r--cmd/podmanV2/containers/create.go1
-rw-r--r--cmd/podmanV2/containers/diff.go67
-rw-r--r--cmd/podmanV2/containers/init.go60
-rw-r--r--cmd/podmanV2/containers/kill.go7
-rw-r--r--cmd/podmanV2/containers/logs.go108
-rw-r--r--cmd/podmanV2/containers/ps.go146
-rw-r--r--cmd/podmanV2/containers/run.go39
-rw-r--r--cmd/podmanV2/containers/wait.go7
-rw-r--r--cmd/podmanV2/diff.go74
-rw-r--r--cmd/podmanV2/images/diff.go63
-rw-r--r--cmd/podmanV2/images/history.go48
-rw-r--r--cmd/podmanV2/images/list.go64
-rw-r--r--cmd/podmanV2/images/load.go42
-rw-r--r--cmd/podmanV2/images/search.go157
-rw-r--r--cmd/podmanV2/images/tag.go11
-rw-r--r--cmd/podmanV2/inspect.go2
-rw-r--r--cmd/podmanV2/pods/create.go15
-rw-r--r--cmd/podmanV2/pods/pod.go30
-rw-r--r--cmd/podmanV2/pods/ps.go83
-rw-r--r--cmd/podmanV2/registry/registry.go14
-rw-r--r--cmd/podmanV2/report/diff.go44
-rw-r--r--cmd/podmanV2/report/templates.go73
-rw-r--r--cmd/podmanV2/system/info.go74
-rw-r--r--cmd/podmanV2/system/service.go124
-rw-r--r--cmd/podmanV2/system/system.go8
-rw-r--r--cmd/podmanV2/system/varlink.go56
-rw-r--r--cmd/podmanV2/system/version.go6
29 files changed, 1198 insertions, 312 deletions
diff --git a/cmd/podmanV2/Makefile b/cmd/podmanV2/Makefile
index b847a9385..01d551212 100644
--- a/cmd/podmanV2/Makefile
+++ b/cmd/podmanV2/Makefile
@@ -1,2 +1,10 @@
-all:
- CGO_ENABLED=1 GO111MODULE=off go build -tags 'ABISupport systemd seccomp'
+all: podman podman-remote
+
+podman:
+ CGO_ENABLED=1 GO111MODULE=off go build -tags 'ABISupport systemd varlink seccomp'
+
+podman-remote:
+ CGO_ENABLED=1 GO111MODULE=off go build -tags '!ABISupport systemd seccomp' -o podmanV2-remote
+
+clean:
+ rm podmanV2 podmanV2-remote
diff --git a/cmd/podmanV2/containers/cleanup.go b/cmd/podmanV2/containers/cleanup.go
new file mode 100644
index 000000000..3f45db160
--- /dev/null
+++ b/cmd/podmanV2/containers/cleanup.go
@@ -0,0 +1,75 @@
+package containers
+
+import (
+ "fmt"
+
+ "github.com/containers/libpod/cmd/podmanV2/parse"
+ "github.com/containers/libpod/cmd/podmanV2/registry"
+ "github.com/containers/libpod/cmd/podmanV2/utils"
+ "github.com/containers/libpod/pkg/domain/entities"
+ "github.com/spf13/cobra"
+)
+
+var (
+ cleanupDescription = `
+ podman container cleanup
+
+ Cleans up mount points and network stacks on one or more containers from the host. The container name or ID can be used. This command is used internally when running containers, but can also be used if container cleanup has failed when a container exits.
+`
+ cleanupCommand = &cobra.Command{
+ Use: "cleanup [flags] CONTAINER [CONTAINER...]",
+ Short: "Cleanup network and mountpoints of one or more containers",
+ Long: cleanupDescription,
+ RunE: cleanup,
+ Args: func(cmd *cobra.Command, args []string) error {
+ return parse.CheckAllLatestAndCIDFile(cmd, args, false, false)
+ },
+ Example: `podman container cleanup --latest
+ podman container cleanup ctrID1 ctrID2 ctrID3
+ podman container cleanup --all`,
+ }
+)
+
+var (
+ cleanupOptions entities.ContainerCleanupOptions
+)
+
+func init() {
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Mode: []entities.EngineMode{entities.ABIMode},
+ Parent: containerCmd,
+ Command: cleanupCommand,
+ })
+ flags := cleanupCommand.Flags()
+ flags.BoolVarP(&cleanupOptions.All, "all", "a", false, "Cleans up all containers")
+ flags.BoolVarP(&cleanupOptions.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
+ flags.BoolVar(&cleanupOptions.Remove, "rm", false, "After cleanup, remove the container entirely")
+ flags.BoolVar(&cleanupOptions.RemoveImage, "rmi", false, "After cleanup, remove the image entirely")
+
+}
+
+func cleanup(cmd *cobra.Command, args []string) error {
+ var (
+ errs utils.OutputErrors
+ )
+ responses, err := registry.ContainerEngine().ContainerCleanup(registry.GetContext(), args, cleanupOptions)
+ if err != nil {
+ return err
+ }
+ for _, r := range responses {
+ if r.CleanErr == nil && r.RmErr == nil && r.RmiErr == nil {
+ fmt.Println(r.Id)
+ continue
+ }
+ if r.RmErr != nil {
+ errs = append(errs, r.RmErr)
+ }
+ if r.RmiErr != nil {
+ errs = append(errs, r.RmiErr)
+ }
+ if r.CleanErr != nil {
+ errs = append(errs, r.CleanErr)
+ }
+ }
+ return errs.PrintErrors()
+}
diff --git a/cmd/podmanV2/containers/create.go b/cmd/podmanV2/containers/create.go
index fd5300966..63daf1702 100644
--- a/cmd/podmanV2/containers/create.go
+++ b/cmd/podmanV2/containers/create.go
@@ -40,6 +40,7 @@ func init() {
})
//common.GetCreateFlags(createCommand)
flags := createCommand.Flags()
+ flags.SetInterspersed(false)
flags.AddFlagSet(common.GetCreateFlags(&cliVals))
flags.AddFlagSet(common.GetNetFlags())
flags.SetNormalizeFunc(common.AliasFlags)
diff --git a/cmd/podmanV2/containers/diff.go b/cmd/podmanV2/containers/diff.go
new file mode 100644
index 000000000..3009cdfad
--- /dev/null
+++ b/cmd/podmanV2/containers/diff.go
@@ -0,0 +1,67 @@
+package containers
+
+import (
+ "github.com/containers/libpod/cmd/podmanV2/registry"
+ "github.com/containers/libpod/cmd/podmanV2/report"
+ "github.com/containers/libpod/pkg/domain/entities"
+ "github.com/pkg/errors"
+ "github.com/spf13/cobra"
+)
+
+var (
+ // podman container _diff_
+ diffCmd = &cobra.Command{
+ Use: "diff [flags] CONTAINER",
+ Args: registry.IdOrLatestArgs,
+ Short: "Inspect changes on container's file systems",
+ Long: `Displays changes on a container filesystem. The container will be compared to its parent layer.`,
+ PreRunE: preRunE,
+ RunE: diff,
+ Example: `podman container diff myCtr
+ podman container diff -l --format json myCtr`,
+ }
+ diffOpts *entities.DiffOptions
+)
+
+func init() {
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
+ Command: diffCmd,
+ Parent: containerCmd,
+ })
+
+ diffOpts = &entities.DiffOptions{}
+ flags := diffCmd.Flags()
+ flags.BoolVar(&diffOpts.Archive, "archive", true, "Save the diff as a tar archive")
+ _ = flags.MarkHidden("archive")
+ flags.StringVar(&diffOpts.Format, "format", "", "Change the output format")
+
+ if !registry.IsRemote() {
+ flags.BoolVarP(&diffOpts.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
+ }
+}
+
+func diff(cmd *cobra.Command, args []string) error {
+ if len(args) == 0 && !diffOpts.Latest {
+ return errors.New("container must be specified: podman container diff [options [...]] ID-NAME")
+ }
+
+ results, err := registry.ContainerEngine().ContainerDiff(registry.GetContext(), args[0], entities.DiffOptions{})
+ if err != nil {
+ return err
+ }
+
+ switch diffOpts.Format {
+ case "":
+ return report.ChangesToTable(results)
+ case "json":
+ return report.ChangesToJSON(results)
+ default:
+ return errors.New("only supported value for '--format' is 'json'")
+ }
+}
+
+func Diff(cmd *cobra.Command, args []string, options entities.DiffOptions) error {
+ diffOpts = &options
+ return diff(cmd, args)
+}
diff --git a/cmd/podmanV2/containers/init.go b/cmd/podmanV2/containers/init.go
new file mode 100644
index 000000000..dd1e1d21b
--- /dev/null
+++ b/cmd/podmanV2/containers/init.go
@@ -0,0 +1,60 @@
+package containers
+
+import (
+ "fmt"
+
+ "github.com/containers/libpod/cmd/podmanV2/parse"
+ "github.com/containers/libpod/cmd/podmanV2/registry"
+ "github.com/containers/libpod/cmd/podmanV2/utils"
+ "github.com/containers/libpod/pkg/domain/entities"
+ "github.com/spf13/cobra"
+)
+
+var (
+ initDescription = `Initialize one or more containers, creating the OCI spec and mounts for inspection. Container names or IDs can be used.`
+
+ initCommand = &cobra.Command{
+ Use: "init [flags] CONTAINER [CONTAINER...]",
+ Short: "Initialize one or more containers",
+ Long: initDescription,
+ PreRunE: preRunE,
+ RunE: initContainer,
+ Args: func(cmd *cobra.Command, args []string) error {
+ return parse.CheckAllLatestAndCIDFile(cmd, args, false, false)
+ },
+ Example: `podman init --latest
+ podman init 3c45ef19d893
+ podman init test1`,
+ }
+)
+
+var (
+ initOptions entities.ContainerInitOptions
+)
+
+func init() {
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
+ Command: initCommand,
+ })
+ flags := initCommand.Flags()
+ flags.BoolVarP(&initOptions.All, "all", "a", false, "Initialize all containers")
+ flags.BoolVarP(&initOptions.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
+ _ = flags.MarkHidden("latest")
+}
+
+func initContainer(cmd *cobra.Command, args []string) error {
+ var errs utils.OutputErrors
+ report, err := registry.ContainerEngine().ContainerInit(registry.GetContext(), args, initOptions)
+ if err != nil {
+ return err
+ }
+ for _, r := range report {
+ if r.Err == nil {
+ fmt.Println(r.Id)
+ } else {
+ errs = append(errs, r.Err)
+ }
+ }
+ return errs.PrintErrors()
+}
diff --git a/cmd/podmanV2/containers/kill.go b/cmd/podmanV2/containers/kill.go
index 6e6debfec..3155d1f34 100644
--- a/cmd/podmanV2/containers/kill.go
+++ b/cmd/podmanV2/containers/kill.go
@@ -2,6 +2,7 @@ package containers
import (
"context"
+ "errors"
"fmt"
"github.com/containers/libpod/cmd/podmanV2/parse"
@@ -54,9 +55,13 @@ func kill(cmd *cobra.Command, args []string) error {
)
// Check if the signalString provided by the user is valid
// Invalid signals will return err
- if _, err = signal.ParseSignalNameOrNumber(killOptions.Signal); err != nil {
+ sig, err := signal.ParseSignalNameOrNumber(killOptions.Signal)
+ if err != nil {
return err
}
+ if sig < 1 || sig > 64 {
+ return errors.New("valid signals are 1 through 64")
+ }
responses, err := registry.ContainerEngine().ContainerKill(context.Background(), args, killOptions)
if err != nil {
return err
diff --git a/cmd/podmanV2/containers/logs.go b/cmd/podmanV2/containers/logs.go
new file mode 100644
index 000000000..d1a179495
--- /dev/null
+++ b/cmd/podmanV2/containers/logs.go
@@ -0,0 +1,108 @@
+package containers
+
+import (
+ "os"
+
+ "github.com/containers/libpod/cmd/podmanV2/registry"
+ "github.com/containers/libpod/pkg/domain/entities"
+ "github.com/containers/libpod/pkg/util"
+ "github.com/pkg/errors"
+ "github.com/spf13/cobra"
+ "github.com/spf13/pflag"
+)
+
+// logsOptionsWrapper wraps entities.LogsOptions and prevents leaking
+// CLI-only fields into the API types.
+type logsOptionsWrapper struct {
+ entities.ContainerLogsOptions
+
+ SinceRaw string
+}
+
+var (
+ logsOptions logsOptionsWrapper
+ logsDescription = `Retrieves logs for one or more containers.
+
+ This does not guarantee execution order when combined with podman run (i.e., your run may not have generated any logs at the time you execute podman logs).
+`
+ logsCommand = &cobra.Command{
+ Use: "logs [flags] CONTAINER [CONTAINER...]",
+ Short: "Fetch the logs of one or more container",
+ Long: logsDescription,
+ RunE: logs,
+ PreRunE: preRunE,
+ Example: `podman logs ctrID
+ podman logs --names ctrID1 ctrID2
+ podman logs --tail 2 mywebserver
+ podman logs --follow=true --since 10m ctrID
+ podman logs mywebserver mydbserver`,
+ }
+
+ containerLogsCommand = &cobra.Command{
+ Use: logsCommand.Use,
+ Short: logsCommand.Short,
+ Long: logsCommand.Long,
+ PreRunE: logsCommand.PreRunE,
+ RunE: logsCommand.RunE,
+ Example: `podman container logs ctrID
+ podman container logs --names ctrID1 ctrID2
+ podman container logs --tail 2 mywebserver
+ podman container logs --follow=true --since 10m ctrID
+ podman container logs mywebserver mydbserver`,
+ }
+)
+
+func init() {
+ // logs
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Mode: []entities.EngineMode{entities.ABIMode},
+ Command: logsCommand,
+ })
+
+ logsCommand.SetHelpTemplate(registry.HelpTemplate())
+ logsCommand.SetUsageTemplate(registry.UsageTemplate())
+
+ flags := logsCommand.Flags()
+ logsFlags(flags)
+
+ // container logs
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Mode: []entities.EngineMode{entities.ABIMode},
+ Command: containerLogsCommand,
+ Parent: containerCmd,
+ })
+
+ containerLogsFlags := containerLogsCommand.Flags()
+ logsFlags(containerLogsFlags)
+}
+
+func logsFlags(flags *pflag.FlagSet) {
+ flags.BoolVar(&logsOptions.Details, "details", false, "Show extra details provided to the logs")
+ flags.BoolVarP(&logsOptions.Follow, "follow", "f", false, "Follow log output. The default is false")
+ flags.BoolVarP(&logsOptions.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
+ flags.StringVar(&logsOptions.SinceRaw, "since", "", "Show logs since TIMESTAMP")
+ flags.Int64Var(&logsOptions.Tail, "tail", -1, "Output the specified number of LINES at the end of the logs. Defaults to -1, which prints all lines")
+ flags.BoolVarP(&logsOptions.Timestamps, "timestamps", "t", false, "Output the timestamps in the log")
+ flags.BoolVarP(&logsOptions.Names, "names", "n", false, "Output the container name in the log")
+ flags.SetInterspersed(false)
+ _ = flags.MarkHidden("details")
+}
+
+func logs(cmd *cobra.Command, args []string) error {
+ if len(args) > 0 && logsOptions.Latest {
+ return errors.New("no containers can be specified when using 'latest'")
+ }
+ if !logsOptions.Latest && len(args) < 1 {
+ return errors.New("specify at least one container name or ID to log")
+ }
+ if logsOptions.SinceRaw != "" {
+ // parse time, error out if something is wrong
+ since, err := util.ParseInputTime(logsOptions.SinceRaw)
+ if err != nil {
+ return errors.Wrapf(err, "error parsing --since %q", logsOptions.SinceRaw)
+ }
+ logsOptions.Since = since
+ }
+ logsOptions.Writer = os.Stdout
+ return registry.ContainerEngine().ContainerLogs(registry.GetContext(), args, logsOptions.ContainerLogsOptions)
+}
diff --git a/cmd/podmanV2/containers/ps.go b/cmd/podmanV2/containers/ps.go
index 2397eb8c0..8c1d44842 100644
--- a/cmd/podmanV2/containers/ps.go
+++ b/cmd/podmanV2/containers/ps.go
@@ -4,8 +4,6 @@ import (
"encoding/json"
"fmt"
"os"
- "sort"
- "strconv"
"strings"
"text/tabwriter"
"text/template"
@@ -13,12 +11,8 @@ import (
tm "github.com/buger/goterm"
"github.com/containers/buildah/pkg/formats"
- "github.com/containers/libpod/cmd/podman/shared"
"github.com/containers/libpod/cmd/podmanV2/registry"
- "github.com/containers/libpod/cmd/podmanV2/report"
"github.com/containers/libpod/pkg/domain/entities"
- "github.com/cri-o/ocicni/pkg/ocicni"
- "github.com/docker/go-units"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
@@ -44,9 +38,6 @@ var (
filters []string
noTrunc bool
defaultHeaders string = "CONTAINER ID\tIMAGE\tCOMMAND\tCREATED\tSTATUS\tPORTS\tNAMES"
-
-// CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
-
)
func init() {
@@ -143,7 +134,6 @@ func getResponses() ([]entities.ListContainer, error) {
}
func ps(cmd *cobra.Command, args []string) error {
- // []string to map[string][]string
for _, f := range filters {
split := strings.SplitN(f, "=", 2)
if len(split) == 1 {
@@ -178,8 +168,7 @@ func ps(cmd *cobra.Command, args []string) error {
if !listOpts.Quiet && !cmd.Flag("format").Changed {
format = headers + format
}
- funcs := report.AppendFuncMap(psFuncMap)
- tmpl, err := template.New("listPods").Funcs(funcs).Parse(format)
+ tmpl, err := template.New("listContainers").Parse(format)
if err != nil {
return err
}
@@ -217,7 +206,7 @@ func createPsOut() (string, string) {
var row string
if listOpts.Namespace {
headers := "CONTAINER ID\tNAMES\tPID\tCGROUPNS\tIPC\tMNT\tNET\tPIDN\tUSERNS\tUTS\n"
- row := "{{.ID}}\t{{names .Names}}\t{{.Pid}}\t{{.Namespaces.Cgroup}}\t{{.Namespaces.IPC}}\t{{.Namespaces.MNT}}\t{{.Namespaces.NET}}\t{{.Namespaces.PIDNS}}\t{{.Namespaces.User}}\t{{.Namespaces.UTS}}\n"
+ row := "{{.ID}}\t{{.Names}}\t{{.Pid}}\t{{.Namespaces.Cgroup}}\t{{.Namespaces.IPC}}\t{{.Namespaces.MNT}}\t{{.Namespaces.NET}}\t{{.Namespaces.PIDNS}}\t{{.Namespaces.User}}\t{{.Namespaces.UTS}}\n"
return headers, row
}
headers := defaultHeaders
@@ -226,7 +215,7 @@ func createPsOut() (string, string) {
} else {
row += "{{slice .ID 0 12}}"
}
- row += "\t{{.Image}}\t{{cmd .Command}}\t{{humanDuration .Created}}\t{{state .}}\t{{ports .Ports}}\t{{names .Names}}"
+ row += "\t{{.Image}}\t{{.Command}}\t{{.CreatedHuman}}\t{{.State}}\t{{.Ports}}\t{{.Names}}"
if listOpts.Pod {
headers += "\tPOD ID\tPODNAME"
@@ -240,7 +229,7 @@ func createPsOut() (string, string) {
if listOpts.Size {
headers += "\tSIZE"
- row += "\t{{consize .Size}}"
+ row += "\t{{.Size}}"
}
if !strings.HasSuffix(headers, "\n") {
headers += "\n"
@@ -250,130 +239,3 @@ func createPsOut() (string, string) {
}
return headers, row
}
-
-var psFuncMap = template.FuncMap{
- "cmd": func(conCommand []string) string {
- return strings.Join(conCommand, " ")
- },
- "state": func(con entities.ListContainer) string {
- var state string
- switch con.State {
- case "running":
- t := units.HumanDuration(time.Since(time.Unix(con.StartedAt, 0)))
- state = "Up " + t + " ago"
- case "configured":
- state = "Created"
- case "exited":
- t := units.HumanDuration(time.Since(time.Unix(con.ExitedAt, 0)))
- state = fmt.Sprintf("Exited (%d) %s ago", con.ExitCode, t)
- default:
- state = con.State
- }
- return state
- },
- "ports": func(ports []ocicni.PortMapping) string {
- if len(ports) == 0 {
- return ""
- }
- return portsToString(ports)
- },
- "names": func(names []string) string {
- return names[0]
- },
- "consize": func(csize shared.ContainerSize) string {
- virt := units.HumanSizeWithPrecision(float64(csize.RootFsSize), 3)
- s := units.HumanSizeWithPrecision(float64(csize.RwSize), 3)
- return fmt.Sprintf("%s (virtual %s)", s, virt)
- },
-}
-
-// portsToString converts the ports used to a string of the from "port1, port2"
-// and also groups a continuous list of ports into a readable format.
-func portsToString(ports []ocicni.PortMapping) string {
- type portGroup struct {
- first int32
- last int32
- }
- var portDisplay []string
- if len(ports) == 0 {
- return ""
- }
- //Sort the ports, so grouping continuous ports become easy.
- sort.Slice(ports, func(i, j int) bool {
- return comparePorts(ports[i], ports[j])
- })
-
- // portGroupMap is used for grouping continuous ports.
- portGroupMap := make(map[string]*portGroup)
- var groupKeyList []string
-
- for _, v := range ports {
-
- hostIP := v.HostIP
- if hostIP == "" {
- hostIP = "0.0.0.0"
- }
- // If hostPort and containerPort are not same, consider as individual port.
- if v.ContainerPort != v.HostPort {
- portDisplay = append(portDisplay, fmt.Sprintf("%s:%d->%d/%s", hostIP, v.HostPort, v.ContainerPort, v.Protocol))
- continue
- }
-
- portMapKey := fmt.Sprintf("%s/%s", hostIP, v.Protocol)
-
- portgroup, ok := portGroupMap[portMapKey]
- if !ok {
- portGroupMap[portMapKey] = &portGroup{first: v.ContainerPort, last: v.ContainerPort}
- // This list is required to traverse portGroupMap.
- groupKeyList = append(groupKeyList, portMapKey)
- continue
- }
-
- if portgroup.last == (v.ContainerPort - 1) {
- portgroup.last = v.ContainerPort
- continue
- }
- }
- // For each portMapKey, format group list and appned to output string.
- for _, portKey := range groupKeyList {
- group := portGroupMap[portKey]
- portDisplay = append(portDisplay, formatGroup(portKey, group.first, group.last))
- }
- return strings.Join(portDisplay, ", ")
-}
-
-func comparePorts(i, j ocicni.PortMapping) bool {
- if i.ContainerPort != j.ContainerPort {
- return i.ContainerPort < j.ContainerPort
- }
-
- if i.HostIP != j.HostIP {
- return i.HostIP < j.HostIP
- }
-
- if i.HostPort != j.HostPort {
- return i.HostPort < j.HostPort
- }
-
- return i.Protocol < j.Protocol
-}
-
-// formatGroup returns the group as <IP:startPort:lastPort->startPort:lastPort/Proto>
-// e.g 0.0.0.0:1000-1006->1000-1006/tcp.
-func formatGroup(key string, start, last int32) string {
- parts := strings.Split(key, "/")
- groupType := parts[0]
- var ip string
- if len(parts) > 1 {
- ip = parts[0]
- groupType = parts[1]
- }
- group := strconv.Itoa(int(start))
- if start != last {
- group = fmt.Sprintf("%s-%d", group, last)
- }
- if ip != "" {
- group = fmt.Sprintf("%s:%s->%s", ip, group, group)
- }
- return fmt.Sprintf("%s/%s", group, groupType)
-}
diff --git a/cmd/podmanV2/containers/run.go b/cmd/podmanV2/containers/run.go
index bd90aee2f..0bf0f90f8 100644
--- a/cmd/podmanV2/containers/run.go
+++ b/cmd/podmanV2/containers/run.go
@@ -5,15 +5,14 @@ import (
"os"
"strings"
- "github.com/sirupsen/logrus"
-
- "github.com/containers/libpod/pkg/domain/entities"
-
+ "github.com/containers/common/pkg/config"
"github.com/containers/libpod/cmd/podmanV2/common"
"github.com/containers/libpod/cmd/podmanV2/registry"
"github.com/containers/libpod/libpod/define"
+ "github.com/containers/libpod/pkg/domain/entities"
"github.com/containers/libpod/pkg/specgen"
"github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)
@@ -46,6 +45,7 @@ func init() {
Command: runCommand,
})
flags := runCommand.Flags()
+ flags.SetInterspersed(false)
flags.AddFlagSet(common.GetCreateFlags(&cliVals))
flags.AddFlagSet(common.GetNetFlags())
flags.SetNormalizeFunc(common.AliasFlags)
@@ -74,6 +74,30 @@ func run(cmd *cobra.Command, args []string) error {
return err
}
+ ie, err := registry.NewImageEngine(cmd, args)
+ if err != nil {
+ return err
+ }
+ br, err := ie.Exists(registry.GetContext(), args[0])
+ if err != nil {
+ return err
+ }
+ pullPolicy, err := config.ValidatePullPolicy(cliVals.Pull)
+ if err != nil {
+ return err
+ }
+ if !br.Value || pullPolicy == config.PullImageAlways {
+ if pullPolicy == config.PullImageNever {
+ return errors.New("unable to find a name and tag match for busybox in repotags: no such image")
+ }
+ _, pullErr := ie.Pull(registry.GetContext(), args[0], entities.ImagePullOptions{
+ Authfile: cliVals.Authfile,
+ Quiet: cliVals.Quiet,
+ })
+ if pullErr != nil {
+ return pullErr
+ }
+ }
// If -i is not set, clear stdin
if !cliVals.Interactive {
runOpts.InputStream = nil
@@ -108,15 +132,18 @@ func run(cmd *cobra.Command, args []string) error {
}
runOpts.Spec = s
report, err := registry.ContainerEngine().ContainerRun(registry.GetContext(), runOpts)
+ // report.ExitCode is set by ContainerRun even it it returns an error
+ if report != nil {
+ registry.SetExitCode(report.ExitCode)
+ }
if err != nil {
return err
}
if cliVals.Detach {
fmt.Println(report.Id)
}
- registry.SetExitCode(report.ExitCode)
if runRmi {
- _, err := registry.ImageEngine().Delete(registry.GetContext(), []string{report.Id}, entities.ImageDeleteOptions{})
+ _, err := registry.ImageEngine().Delete(registry.GetContext(), []string{args[0]}, entities.ImageDeleteOptions{})
if err != nil {
logrus.Errorf("%s", errors.Wrapf(err, "failed removing image"))
}
diff --git a/cmd/podmanV2/containers/wait.go b/cmd/podmanV2/containers/wait.go
index bf3c86200..2171f2073 100644
--- a/cmd/podmanV2/containers/wait.go
+++ b/cmd/podmanV2/containers/wait.go
@@ -5,7 +5,6 @@ import (
"fmt"
"time"
- "github.com/containers/libpod/cmd/podmanV2/parse"
"github.com/containers/libpod/cmd/podmanV2/registry"
"github.com/containers/libpod/cmd/podmanV2/utils"
"github.com/containers/libpod/libpod/define"
@@ -23,9 +22,7 @@ var (
Long: waitDescription,
RunE: wait,
PersistentPreRunE: preRunE,
- Args: func(cmd *cobra.Command, args []string) error {
- return parse.CheckAllLatestAndCIDFile(cmd, args, false, false)
- },
+ Args: registry.IdOrLatestArgs,
Example: `podman wait --latest
podman wait --interval 5000 ctrID
podman wait ctrID1 ctrID2`,
@@ -73,7 +70,7 @@ func wait(cmd *cobra.Command, args []string) error {
}
for _, r := range responses {
if r.Error == nil {
- fmt.Println(r.Id)
+ fmt.Println(r.ExitCode)
} else {
errs = append(errs, r.Error)
}
diff --git a/cmd/podmanV2/diff.go b/cmd/podmanV2/diff.go
new file mode 100644
index 000000000..6e4263370
--- /dev/null
+++ b/cmd/podmanV2/diff.go
@@ -0,0 +1,74 @@
+package main
+
+import (
+ "fmt"
+
+ "github.com/containers/libpod/cmd/podmanV2/containers"
+ "github.com/containers/libpod/cmd/podmanV2/images"
+ "github.com/containers/libpod/cmd/podmanV2/registry"
+ "github.com/containers/libpod/pkg/domain/entities"
+ "github.com/spf13/cobra"
+)
+
+// Inspect is one of the outlier commands in that it operates on images/containers/...
+
+var (
+ // Command: podman _diff_ Object_ID
+ diffDescription = `Displays changes on a container or image's filesystem. The container or image will be compared to its parent layer.`
+ diffCmd = &cobra.Command{
+ Use: "diff [flags] {CONTAINER_ID | IMAGE_ID}",
+ Args: registry.IdOrLatestArgs,
+ Short: "Display the changes of object's file system",
+ Long: diffDescription,
+ TraverseChildren: true,
+ RunE: diff,
+ Example: `podman diff imageID
+ podman diff ctrID
+ podman diff --format json redis:alpine`,
+ }
+
+ diffOpts = entities.DiffOptions{}
+)
+
+func init() {
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
+ Command: diffCmd,
+ })
+ diffCmd.SetHelpTemplate(registry.HelpTemplate())
+ diffCmd.SetUsageTemplate(registry.UsageTemplate())
+
+ flags := diffCmd.Flags()
+ flags.BoolVar(&diffOpts.Archive, "archive", true, "Save the diff as a tar archive")
+ _ = flags.MarkHidden("archive")
+ flags.StringVar(&diffOpts.Format, "format", "", "Change the output format")
+
+ if !registry.IsRemote() {
+ flags.BoolVarP(&diffOpts.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
+ }
+}
+
+func diff(cmd *cobra.Command, args []string) error {
+ ie, err := registry.NewImageEngine(cmd, args)
+ if err != nil {
+ return err
+ }
+
+ if found, err := ie.Exists(registry.GetContext(), args[0]); err != nil {
+ return err
+ } else if found.Value {
+ return images.Diff(cmd, args, diffOpts)
+ }
+
+ ce, err := registry.NewContainerEngine(cmd, args)
+ if err != nil {
+ return err
+ }
+
+ if found, err := ce.ContainerExists(registry.GetContext(), args[0]); err != nil {
+ return err
+ } else if found.Value {
+ return containers.Diff(cmd, args, diffOpts)
+ }
+ return fmt.Errorf("%s not found on system", args[0])
+}
diff --git a/cmd/podmanV2/images/diff.go b/cmd/podmanV2/images/diff.go
new file mode 100644
index 000000000..e913a603a
--- /dev/null
+++ b/cmd/podmanV2/images/diff.go
@@ -0,0 +1,63 @@
+package images
+
+import (
+ "github.com/containers/libpod/cmd/podmanV2/registry"
+ "github.com/containers/libpod/cmd/podmanV2/report"
+ "github.com/containers/libpod/pkg/domain/entities"
+ "github.com/pkg/errors"
+ "github.com/spf13/cobra"
+)
+
+var (
+ // podman container _inspect_
+ diffCmd = &cobra.Command{
+ Use: "diff [flags] CONTAINER",
+ Args: registry.IdOrLatestArgs,
+ Short: "Inspect changes on image's file systems",
+ Long: `Displays changes on a image's filesystem. The image will be compared to its parent layer.`,
+ PreRunE: preRunE,
+ RunE: diff,
+ Example: `podman image diff myImage
+ podman image diff --format json redis:alpine`,
+ }
+ diffOpts *entities.DiffOptions
+)
+
+func init() {
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
+ Command: diffCmd,
+ Parent: imageCmd,
+ })
+
+ diffOpts = &entities.DiffOptions{}
+ flags := diffCmd.Flags()
+ flags.BoolVar(&diffOpts.Archive, "archive", true, "Save the diff as a tar archive")
+ _ = flags.MarkHidden("archive")
+ flags.StringVar(&diffOpts.Format, "format", "", "Change the output format")
+}
+
+func diff(cmd *cobra.Command, args []string) error {
+ if len(args) == 0 && !diffOpts.Latest {
+ return errors.New("image must be specified: podman image diff [options [...]] ID-NAME")
+ }
+
+ results, err := registry.ImageEngine().Diff(registry.GetContext(), args[0], entities.DiffOptions{})
+ if err != nil {
+ return err
+ }
+
+ switch diffOpts.Format {
+ case "":
+ return report.ChangesToTable(results)
+ case "json":
+ return report.ChangesToJSON(results)
+ default:
+ return errors.New("only supported value for '--format' is 'json'")
+ }
+}
+
+func Diff(cmd *cobra.Command, args []string, options entities.DiffOptions) error {
+ diffOpts = &options
+ return diff(cmd, args)
+}
diff --git a/cmd/podmanV2/images/history.go b/cmd/podmanV2/images/history.go
index f6f15e2f2..48575b33a 100644
--- a/cmd/podmanV2/images/history.go
+++ b/cmd/podmanV2/images/history.go
@@ -8,10 +8,11 @@ import (
"text/tabwriter"
"text/template"
"time"
+ "unicode"
"github.com/containers/libpod/cmd/podmanV2/registry"
- "github.com/containers/libpod/cmd/podmanV2/report"
"github.com/containers/libpod/pkg/domain/entities"
+ "github.com/docker/go-units"
jsoniter "github.com/json-iterator/go"
"github.com/pkg/errors"
"github.com/spf13/cobra"
@@ -86,10 +87,13 @@ func history(cmd *cobra.Command, args []string) error {
}
return err
}
-
+ var hr []historyreporter
+ for _, l := range results.Layers {
+ hr = append(hr, historyreporter{l})
+ }
// Defaults
hdr := "ID\tCREATED\tCREATED BY\tSIZE\tCOMMENT\n"
- row := "{{slice .ID 0 12}}\t{{humanDuration .Created}}\t{{ellipsis .CreatedBy 45}}\t{{.Size}}\t{{.Comment}}\n"
+ row := "{{.ID}}\t{{.Created}}\t{{.CreatedBy}}\t{{.Size}}\t{{.Comment}}\n"
if len(opts.format) > 0 {
hdr = ""
@@ -100,9 +104,9 @@ func history(cmd *cobra.Command, args []string) error {
} else {
switch {
case opts.human:
- row = "{{slice .ID 0 12}}\t{{humanDuration .Created}}\t{{ellipsis .CreatedBy 45}}\t{{humanSize .Size}}\t{{.Comment}}\n"
+ row = "{{.ID}}\t{{.Created}}\t{{.CreatedBy}}\t{{.Size}}\t{{.Comment}}\n"
case opts.noTrunc:
- row = "{{.ID}}\t{{humanDuration .Created}}\t{{.CreatedBy}}\t{{humanSize .Size}}\t{{.Comment}}\n"
+ row = "{{.ID}}\t{{.Created}}\t{{.CreatedBy}}\t{{.Size}}\t{{.Comment}}\n"
case opts.quiet:
hdr = ""
row = "{{.ID}}\n"
@@ -110,14 +114,40 @@ func history(cmd *cobra.Command, args []string) error {
}
format := hdr + "{{range . }}" + row + "{{end}}"
- tmpl := template.Must(template.New("report").Funcs(report.PodmanTemplateFuncs()).Parse(format))
+ tmpl := template.Must(template.New("report").Parse(format))
w := tabwriter.NewWriter(os.Stdout, 8, 2, 2, ' ', 0)
-
- _, _ = w.Write(report.ReportHeader("id", "created", "created by", "size", "comment"))
- err = tmpl.Execute(w, results.Layers)
+ err = tmpl.Execute(w, hr)
if err != nil {
fmt.Fprintln(os.Stderr, errors.Wrapf(err, "Failed to print report"))
}
w.Flush()
return nil
}
+
+type historyreporter struct {
+ entities.ImageHistoryLayer
+}
+
+func (h historyreporter) Created() string {
+ return units.HumanDuration(time.Since(time.Unix(h.ImageHistoryLayer.Created, 0))) + " ago"
+}
+
+func (h historyreporter) Size() string {
+ s := units.HumanSizeWithPrecision(float64(h.ImageHistoryLayer.Size), 3)
+ i := strings.LastIndexFunc(s, unicode.IsNumber)
+ return s[:i+1] + " " + s[i+1:]
+}
+
+func (h historyreporter) CreatedBy() string {
+ if len(h.ImageHistoryLayer.CreatedBy) > 45 {
+ return h.ImageHistoryLayer.CreatedBy[:45-3] + "..."
+ }
+ return h.ImageHistoryLayer.CreatedBy
+}
+
+func (h historyreporter) ID() string {
+ if !opts.noTrunc && len(h.ImageHistoryLayer.ID) >= 12 {
+ return h.ImageHistoryLayer.ID[0:12]
+ }
+ return h.ImageHistoryLayer.ID
+}
diff --git a/cmd/podmanV2/images/list.go b/cmd/podmanV2/images/list.go
index 2d6cb3596..d594a4323 100644
--- a/cmd/podmanV2/images/list.go
+++ b/cmd/podmanV2/images/list.go
@@ -9,10 +9,11 @@ import (
"text/tabwriter"
"text/template"
"time"
+ "unicode"
"github.com/containers/libpod/cmd/podmanV2/registry"
- "github.com/containers/libpod/cmd/podmanV2/report"
"github.com/containers/libpod/pkg/domain/entities"
+ "github.com/docker/go-units"
jsoniter "github.com/json-iterator/go"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
@@ -130,16 +131,13 @@ func writeJSON(imageS []*entities.ImageSummary) error {
}
func writeTemplate(imageS []*entities.ImageSummary, err error) error {
- type image struct {
- entities.ImageSummary
- Repository string `json:"repository,omitempty"`
- Tag string `json:"tag,omitempty"`
- }
-
- imgs := make([]image, 0, len(imageS))
+ var (
+ hdr, row string
+ )
+ imgs := make([]imageReporter, 0, len(imageS))
for _, e := range imageS {
for _, tag := range e.RepoTags {
- var h image
+ var h imageReporter
h.ImageSummary = *e
h.Repository, h.Tag = tokenRepoTag(tag)
imgs = append(imgs, h)
@@ -148,11 +146,16 @@ func writeTemplate(imageS []*entities.ImageSummary, err error) error {
listFlag.readOnly = true
}
}
-
- hdr, row := imageListFormat(listFlag)
+ if len(listFlag.format) < 1 {
+ hdr, row = imageListFormat(listFlag)
+ } else {
+ row = listFlag.format
+ if !strings.HasSuffix(row, "\n") {
+ row += "\n"
+ }
+ }
format := hdr + "{{range . }}" + row + "{{end}}"
-
- tmpl := template.Must(template.New("list").Funcs(report.PodmanTemplateFuncs()).Parse(format))
+ tmpl := template.Must(template.New("list").Parse(format))
w := tabwriter.NewWriter(os.Stdout, 8, 2, 2, ' ', 0)
defer w.Flush()
return tmpl.Execute(w, imgs)
@@ -200,7 +203,7 @@ func sortFunc(key string, data []*entities.ImageSummary) func(i, j int) bool {
func imageListFormat(flags listFlagType) (string, string) {
if flags.quiet {
- return "", "{{slice .ID 0 12}}\n"
+ return "", "{{.ID}}\n"
}
// Defaults
@@ -216,15 +219,15 @@ func imageListFormat(flags listFlagType) (string, string) {
if flags.noTrunc {
row += "\tsha256:{{.ID}}"
} else {
- row += "\t{{slice .ID 0 12}}"
+ row += "\t{{.ID}}"
}
hdr += "\tCREATED\tSIZE"
- row += "\t{{humanDuration .Created}}\t{{humanSize .Size}}"
+ row += "\t{{.Created}}\t{{.Size}}"
if flags.history {
hdr += "\tHISTORY"
- row += "\t{{if .History}}{{join .History \", \"}}{{else}}<none>{{end}}"
+ row += "\t{{if .History}}{{.History}}{{else}}<none>{{end}}"
}
if flags.readOnly {
@@ -241,3 +244,30 @@ func imageListFormat(flags listFlagType) (string, string) {
row += "\n"
return hdr, row
}
+
+type imageReporter struct {
+ Repository string `json:"repository,omitempty"`
+ Tag string `json:"tag,omitempty"`
+ entities.ImageSummary
+}
+
+func (i imageReporter) ID() string {
+ if !listFlag.noTrunc && len(i.ImageSummary.ID) >= 12 {
+ return i.ImageSummary.ID[0:12]
+ }
+ return i.ImageSummary.ID
+}
+
+func (i imageReporter) Created() string {
+ return units.HumanDuration(time.Since(time.Unix(i.ImageSummary.Created, 0))) + " ago"
+}
+
+func (i imageReporter) Size() string {
+ s := units.HumanSizeWithPrecision(float64(i.ImageSummary.Size), 3)
+ j := strings.LastIndexFunc(s, unicode.IsNumber)
+ return s[:j+1] + " " + s[j+1:]
+}
+
+func (i imageReporter) History() string {
+ return strings.Join(i.ImageSummary.History, ", ")
+}
diff --git a/cmd/podmanV2/images/load.go b/cmd/podmanV2/images/load.go
index f60dc4908..315dbed3a 100644
--- a/cmd/podmanV2/images/load.go
+++ b/cmd/podmanV2/images/load.go
@@ -3,11 +3,18 @@ package images
import (
"context"
"fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "github.com/containers/image/v5/docker/reference"
+ "github.com/containers/libpod/cmd/podmanV2/parse"
"github.com/containers/libpod/cmd/podmanV2/registry"
- "github.com/containers/libpod/libpod/image"
"github.com/containers/libpod/pkg/domain/entities"
+ "github.com/containers/libpod/pkg/util"
+ "github.com/pkg/errors"
"github.com/spf13/cobra"
+ "golang.org/x/crypto/ssh/terminal"
)
var (
@@ -46,11 +53,40 @@ func init() {
func load(cmd *cobra.Command, args []string) error {
if len(args) > 0 {
- repo, err := image.NormalizedTag(args[0])
+ ref, err := reference.Parse(args[0])
if err != nil {
return err
}
- loadOpts.Name = repo.Name()
+ if t, ok := ref.(reference.Tagged); ok {
+ loadOpts.Tag = t.Tag()
+ } else {
+ loadOpts.Tag = "latest"
+ }
+ if r, ok := ref.(reference.Named); ok {
+ fmt.Println(r.Name())
+ loadOpts.Name = r.Name()
+ }
+ }
+ if len(loadOpts.Input) > 0 {
+ if err := parse.ValidateFileName(loadOpts.Input); err != nil {
+ return err
+ }
+ } else {
+ if terminal.IsTerminal(int(os.Stdin.Fd())) {
+ return errors.Errorf("cannot read from terminal. Use command-line redirection or the --input flag.")
+ }
+ outFile, err := ioutil.TempFile(util.Tmpdir(), "podman")
+ if err != nil {
+ return errors.Errorf("error creating file %v", err)
+ }
+ defer os.Remove(outFile.Name())
+ defer outFile.Close()
+
+ _, err = io.Copy(outFile, os.Stdin)
+ if err != nil {
+ return errors.Errorf("error copying file %v", err)
+ }
+ loadOpts.Input = outFile.Name()
}
response, err := registry.ImageEngine().Load(context.Background(), loadOpts)
if err != nil {
diff --git a/cmd/podmanV2/images/search.go b/cmd/podmanV2/images/search.go
new file mode 100644
index 000000000..2ab9735ec
--- /dev/null
+++ b/cmd/podmanV2/images/search.go
@@ -0,0 +1,157 @@
+package images
+
+import (
+ "reflect"
+ "strings"
+
+ buildahcli "github.com/containers/buildah/pkg/cli"
+ "github.com/containers/buildah/pkg/formats"
+ "github.com/containers/image/v5/types"
+ "github.com/containers/libpod/cmd/podmanV2/registry"
+ "github.com/containers/libpod/pkg/domain/entities"
+ "github.com/containers/libpod/pkg/util/camelcase"
+ "github.com/pkg/errors"
+ "github.com/spf13/cobra"
+ "github.com/spf13/pflag"
+)
+
+// searchOptionsWrapper wraps entities.ImagePullOptions and prevents leaking
+// CLI-only fields into the API types.
+type searchOptionsWrapper struct {
+ entities.ImageSearchOptions
+ // CLI only flags
+ TLSVerifyCLI bool // Used to convert to an optional bool later
+ Format string // For go templating
+}
+
+var (
+ searchOptions = searchOptionsWrapper{}
+ searchDescription = `Search registries for a given image. Can search all the default registries or a specific registry.
+
+ Users can limit the number of results, and filter the output based on certain conditions.`
+
+ // Command: podman search
+ searchCmd = &cobra.Command{
+ Use: "search [flags] TERM",
+ Short: "Search registry for image",
+ Long: searchDescription,
+ PreRunE: preRunE,
+ RunE: imageSearch,
+ Args: cobra.ExactArgs(1),
+ Example: `podman search --filter=is-official --limit 3 alpine
+ podman search registry.fedoraproject.org/ # only works with v2 registries
+ podman search --format "table {{.Index}} {{.Name}}" registry.fedoraproject.org/fedora`,
+ }
+
+ // Command: podman image search
+ imageSearchCmd = &cobra.Command{
+ Use: searchCmd.Use,
+ Short: searchCmd.Short,
+ Long: searchCmd.Long,
+ PreRunE: searchCmd.PreRunE,
+ RunE: searchCmd.RunE,
+ Args: searchCmd.Args,
+ Example: `podman image search --filter=is-official --limit 3 alpine
+ podman image search registry.fedoraproject.org/ # only works with v2 registries
+ podman image search --format "table {{.Index}} {{.Name}}" registry.fedoraproject.org/fedora`,
+ }
+)
+
+func init() {
+ // search
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
+ Command: searchCmd,
+ })
+
+ searchCmd.SetHelpTemplate(registry.HelpTemplate())
+ searchCmd.SetUsageTemplate(registry.UsageTemplate())
+ flags := searchCmd.Flags()
+ searchFlags(flags)
+
+ // images search
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
+ Command: imageSearchCmd,
+ Parent: imageCmd,
+ })
+
+ imageSearchFlags := imageSearchCmd.Flags()
+ searchFlags(imageSearchFlags)
+}
+
+// searchFlags set the flags for the pull command.
+func searchFlags(flags *pflag.FlagSet) {
+ flags.StringSliceVarP(&searchOptions.Filters, "filter", "f", []string{}, "Filter output based on conditions provided (default [])")
+ flags.StringVar(&searchOptions.Format, "format", "", "Change the output format to a Go template")
+ flags.IntVar(&searchOptions.Limit, "limit", 0, "Limit the number of results")
+ flags.BoolVar(&searchOptions.NoTrunc, "no-trunc", false, "Do not truncate the output")
+ flags.StringVar(&searchOptions.Authfile, "authfile", buildahcli.GetDefaultAuthFile(), "Path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override")
+ flags.BoolVar(&searchOptions.TLSVerifyCLI, "tls-verify", true, "Require HTTPS and verify certificates when contacting registries")
+ if registry.IsRemote() {
+ _ = flags.MarkHidden("authfile")
+ _ = flags.MarkHidden("tls-verify")
+ }
+}
+
+// imageSearch implements the command for searching images.
+func imageSearch(cmd *cobra.Command, args []string) error {
+ searchTerm := ""
+ switch len(args) {
+ case 1:
+ searchTerm = args[0]
+ default:
+ return errors.Errorf("search requires exactly one argument")
+ }
+
+ sarchOptsAPI := searchOptions.ImageSearchOptions
+ // TLS verification in c/image is controlled via a `types.OptionalBool`
+ // which allows for distinguishing among set-true, set-false, unspecified
+ // which is important to implement a sane way of dealing with defaults of
+ // boolean CLI flags.
+ if cmd.Flags().Changed("tls-verify") {
+ sarchOptsAPI.TLSVerify = types.NewOptionalBool(pullOptions.TLSVerifyCLI)
+ }
+
+ searchReport, err := registry.ImageEngine().Search(registry.GetContext(), searchTerm, sarchOptsAPI)
+ if err != nil {
+ return err
+ }
+
+ format := genSearchFormat(searchOptions.Format)
+ if len(searchReport) == 0 {
+ return nil
+ }
+ out := formats.StdoutTemplateArray{Output: searchToGeneric(searchReport), Template: format, Fields: searchHeaderMap()}
+ return out.Out()
+}
+
+// searchHeaderMap returns the headers of a SearchResult.
+func searchHeaderMap() map[string]string {
+ s := new(entities.ImageSearchReport)
+ v := reflect.Indirect(reflect.ValueOf(s))
+ values := make(map[string]string, v.NumField())
+
+ for i := 0; i < v.NumField(); i++ {
+ key := v.Type().Field(i).Name
+ value := key
+ values[key] = strings.ToUpper(strings.Join(camelcase.Split(value), " "))
+ }
+ return values
+}
+
+func genSearchFormat(format string) string {
+ if format != "" {
+ // "\t" from the command line is not being recognized as a tab
+ // replacing the string "\t" to a tab character if the user passes in "\t"
+ return strings.Replace(format, `\t`, "\t", -1)
+ }
+ return "table {{.Index}}\t{{.Name}}\t{{.Description}}\t{{.Stars}}\t{{.Official}}\t{{.Automated}}\t"
+}
+
+func searchToGeneric(params []entities.ImageSearchReport) (genericParams []interface{}) {
+ for _, v := range params {
+ genericParams = append(genericParams, interface{}(v))
+ }
+ return genericParams
+}
diff --git a/cmd/podmanV2/images/tag.go b/cmd/podmanV2/images/tag.go
index f66fe7857..f8799d4a7 100644
--- a/cmd/podmanV2/images/tag.go
+++ b/cmd/podmanV2/images/tag.go
@@ -9,11 +9,12 @@ import (
var (
tagDescription = "Adds one or more additional names to locally-stored image."
tagCommand = &cobra.Command{
- Use: "tag [flags] IMAGE TARGET_NAME [TARGET_NAME...]",
- Short: "Add an additional name to a local image",
- Long: tagDescription,
- RunE: tag,
- Args: cobra.MinimumNArgs(2),
+ Use: "tag [flags] IMAGE TARGET_NAME [TARGET_NAME...]",
+ Short: "Add an additional name to a local image",
+ Long: tagDescription,
+ RunE: tag,
+ PreRunE: preRunE,
+ Args: cobra.MinimumNArgs(2),
Example: `podman tag 0e3bbc2 fedora:latest
podman tag imageID:latest myNewImage:newTag
podman tag httpd myregistryhost:5000/fedora/httpd:v2`,
diff --git a/cmd/podmanV2/inspect.go b/cmd/podmanV2/inspect.go
index 4975cf632..15d7579ea 100644
--- a/cmd/podmanV2/inspect.go
+++ b/cmd/podmanV2/inspect.go
@@ -12,7 +12,7 @@ import (
"github.com/spf13/cobra"
)
-// Inspect is one of the out layer commands in that it operates on images/containers/...
+// Inspect is one of the outlier commands in that it operates on images/containers/...
var (
inspectOpts *entities.InspectOptions
diff --git a/cmd/podmanV2/pods/create.go b/cmd/podmanV2/pods/create.go
index ab8957ee3..2aaf0cd2c 100644
--- a/cmd/podmanV2/pods/create.go
+++ b/cmd/podmanV2/pods/create.go
@@ -123,6 +123,21 @@ func create(cmd *cobra.Command, args []string) error {
}
}
+ if !createOptions.Infra {
+ if cmd.Flag("infra-command").Changed {
+ return errors.New("cannot set infra-command without an infra container")
+ }
+ createOptions.InfraCommand = ""
+ if cmd.Flag("infra-image").Changed {
+ return errors.New("cannot set infra-image without an infra container")
+ }
+ createOptions.InfraImage = ""
+ if cmd.Flag("share").Changed {
+ return errors.New("cannot set share namespaces without an infra container")
+ }
+ createOptions.Share = nil
+ }
+
response, err := registry.ContainerEngine().PodCreate(context.Background(), createOptions)
if err != nil {
return err
diff --git a/cmd/podmanV2/pods/pod.go b/cmd/podmanV2/pods/pod.go
index 3766893bb..81c0d33e1 100644
--- a/cmd/podmanV2/pods/pod.go
+++ b/cmd/podmanV2/pods/pod.go
@@ -1,9 +1,6 @@
package pods
import (
- "strings"
- "text/template"
-
"github.com/containers/libpod/cmd/podmanV2/registry"
"github.com/containers/libpod/pkg/domain/entities"
"github.com/spf13/cobra"
@@ -21,33 +18,6 @@ var (
}
)
-var podFuncMap = template.FuncMap{
- "numCons": func(cons []*entities.ListPodContainer) int {
- return len(cons)
- },
- "podcids": func(cons []*entities.ListPodContainer) string {
- var ctrids []string
- for _, c := range cons {
- ctrids = append(ctrids, c.Id[:12])
- }
- return strings.Join(ctrids, ",")
- },
- "podconnames": func(cons []*entities.ListPodContainer) string {
- var ctrNames []string
- for _, c := range cons {
- ctrNames = append(ctrNames, c.Names[:12])
- }
- return strings.Join(ctrNames, ",")
- },
- "podconstatuses": func(cons []*entities.ListPodContainer) string {
- var statuses []string
- for _, c := range cons {
- statuses = append(statuses, c.Status)
- }
- return strings.Join(statuses, ",")
- },
-}
-
func init() {
registry.Commands = append(registry.Commands, registry.CliCommand{
Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
diff --git a/cmd/podmanV2/pods/ps.go b/cmd/podmanV2/pods/ps.go
index 9875263ac..3dac607df 100644
--- a/cmd/podmanV2/pods/ps.go
+++ b/cmd/podmanV2/pods/ps.go
@@ -9,9 +9,11 @@ import (
"strings"
"text/tabwriter"
"text/template"
+ "time"
+
+ "github.com/docker/go-units"
"github.com/containers/libpod/cmd/podmanV2/registry"
- "github.com/containers/libpod/cmd/podmanV2/report"
"github.com/containers/libpod/pkg/domain/entities"
"github.com/pkg/errors"
"github.com/spf13/cobra"
@@ -65,6 +67,7 @@ func pods(cmd *cobra.Command, args []string) error {
var (
w io.Writer = os.Stdout
row string
+ lpr []ListPodReporter
)
if cmd.Flag("filter").Changed {
for _, f := range strings.Split(inputFilters, ",") {
@@ -88,6 +91,10 @@ func pods(cmd *cobra.Command, args []string) error {
fmt.Println(string(b))
return nil
}
+
+ for _, r := range responses {
+ lpr = append(lpr, ListPodReporter{r})
+ }
headers, row := createPodPsOut()
if psInput.Quiet {
if noTrunc {
@@ -106,15 +113,14 @@ func pods(cmd *cobra.Command, args []string) error {
if !psInput.Quiet && !cmd.Flag("format").Changed {
format = headers + format
}
- funcs := report.AppendFuncMap(podFuncMap)
- tmpl, err := template.New("listPods").Funcs(funcs).Parse(format)
+ tmpl, err := template.New("listPods").Parse(format)
if err != nil {
return err
}
if !psInput.Quiet {
w = tabwriter.NewWriter(os.Stdout, 8, 2, 2, ' ', 0)
}
- if err := tmpl.Execute(w, responses); err != nil {
+ if err := tmpl.Execute(w, lpr); err != nil {
return err
}
if flusher, ok := w.(interface{ Flush() error }); ok {
@@ -132,20 +138,19 @@ func createPodPsOut() (string, string) {
row += "{{slice .Id 0 12}}"
}
- row += "\t{{.Name}}\t{{.Status}}\t{{humanDurationFromTime .Created}}"
+ row += "\t{{.Name}}\t{{.Status}}\t{{.Created}}"
- //rowFormat string = "{{slice .Id 0 12}}\t{{.Name}}\t{{.Status}}\t{{humanDurationFromTime .Created}}"
if psInput.CtrIds {
headers += "\tIDS"
- row += "\t{{podcids .Containers}}"
+ row += "\t{{.ContainerIds}}"
}
if psInput.CtrNames {
headers += "\tNAMES"
- row += "\t{{podconnames .Containers}}"
+ row += "\t{{.ContainerNames}}"
}
if psInput.CtrStatus {
headers += "\tSTATUS"
- row += "\t{{podconstatuses .Containers}}"
+ row += "\t{{.ContainerStatuses}}"
}
if psInput.Namespace {
headers += "\tCGROUP\tNAMESPACES"
@@ -153,7 +158,7 @@ func createPodPsOut() (string, string) {
}
if !psInput.CtrStatus && !psInput.CtrNames && !psInput.CtrIds {
headers += "\t# OF CONTAINERS"
- row += "\t{{numCons .Containers}}"
+ row += "\t{{.NumberOfContainers}}"
}
headers += "\tINFRA ID\n"
@@ -164,3 +169,61 @@ func createPodPsOut() (string, string) {
}
return headers, row
}
+
+// ListPodReporter is a struct for pod ps output
+type ListPodReporter struct {
+ *entities.ListPodsReport
+}
+
+// Created returns a human readable created time/date
+func (l ListPodReporter) Created() string {
+ return units.HumanDuration(time.Since(l.ListPodsReport.Created)) + " ago"
+}
+
+// NumberofContainers returns an int representation for
+// the number of containers belonging to the pod
+func (l ListPodReporter) NumberOfContainers() int {
+ return len(l.Containers)
+}
+
+// Added for backwards compatibility with podmanv1
+func (l ListPodReporter) InfraID() string {
+ return l.InfraId()
+}
+
+// InfraId returns the infra container id for the pod
+// depending on trunc
+func (l ListPodReporter) InfraId() string {
+ if noTrunc {
+ return l.ListPodsReport.InfraId
+ }
+ return l.ListPodsReport.InfraId[0:12]
+}
+
+func (l ListPodReporter) ContainerIds() string {
+ var ctrids []string
+ for _, c := range l.Containers {
+ id := c.Id
+ if !noTrunc {
+ id = id[0:12]
+ }
+ ctrids = append(ctrids, id)
+ }
+ return strings.Join(ctrids, ",")
+}
+
+func (l ListPodReporter) ContainerNames() string {
+ var ctrNames []string
+ for _, c := range l.Containers {
+ ctrNames = append(ctrNames, c.Names)
+ }
+ return strings.Join(ctrNames, ",")
+}
+
+func (l ListPodReporter) ContainerStatuses() string {
+ var statuses []string
+ for _, c := range l.Containers {
+ statuses = append(statuses, c.Status)
+ }
+ return strings.Join(statuses, ",")
+}
diff --git a/cmd/podmanV2/registry/registry.go b/cmd/podmanV2/registry/registry.go
index 401f82718..07c2b33ff 100644
--- a/cmd/podmanV2/registry/registry.go
+++ b/cmd/podmanV2/registry/registry.go
@@ -9,7 +9,11 @@ import (
"github.com/spf13/cobra"
)
-type CobraFuncs func(cmd *cobra.Command, args []string) error
+// DefaultAPIAddress is the default address of the REST socket
+const DefaultAPIAddress = "unix:/run/podman/podman.sock"
+
+// DefaultVarlinkAddress is the default address of the varlink socket
+const DefaultVarlinkAddress = "unix:/run/podman/io.podman"
type CliCommand struct {
Mode []entities.EngineMode
@@ -113,6 +117,14 @@ func SubCommandExists(cmd *cobra.Command, args []string) error {
return errors.Errorf("missing command '%[1]s COMMAND'\nTry '%[1]s --help' for more information.", cmd.CommandPath())
}
+// IdOrLatestArgs used to validate a nameOrId was provided or the "--latest" flag
+func IdOrLatestArgs(cmd *cobra.Command, args []string) error {
+ if len(args) > 1 || (len(args) == 0 && !cmd.Flag("latest").Changed) {
+ return errors.New(`command requires a name, id or the "--latest" flag`)
+ }
+ return nil
+}
+
type podmanContextKey string
var podmanFactsKey = podmanContextKey("engineOptions")
diff --git a/cmd/podmanV2/report/diff.go b/cmd/podmanV2/report/diff.go
new file mode 100644
index 000000000..b36189d75
--- /dev/null
+++ b/cmd/podmanV2/report/diff.go
@@ -0,0 +1,44 @@
+package report
+
+import (
+ "fmt"
+ "os"
+
+ "github.com/containers/libpod/pkg/domain/entities"
+ "github.com/containers/storage/pkg/archive"
+ jsoniter "github.com/json-iterator/go"
+ "github.com/pkg/errors"
+)
+
+type ChangesReportJSON struct {
+ Changed []string `json:"changed,omitempty"`
+ Added []string `json:"added,omitempty"`
+ Deleted []string `json:"deleted,omitempty"`
+}
+
+func ChangesToJSON(diffs *entities.DiffReport) error {
+ body := ChangesReportJSON{}
+ for _, row := range diffs.Changes {
+ switch row.Kind {
+ case archive.ChangeAdd:
+ body.Added = append(body.Added, row.Path)
+ case archive.ChangeDelete:
+ body.Deleted = append(body.Deleted, row.Path)
+ case archive.ChangeModify:
+ body.Changed = append(body.Changed, row.Path)
+ default:
+ return errors.Errorf("output kind %q not recognized", row.Kind)
+ }
+ }
+
+ json := jsoniter.ConfigCompatibleWithStandardLibrary
+ enc := json.NewEncoder(os.Stdout)
+ return enc.Encode(body)
+}
+
+func ChangesToTable(diffs *entities.DiffReport) error {
+ for _, row := range diffs.Changes {
+ fmt.Fprintln(os.Stdout, row.String())
+ }
+ return nil
+}
diff --git a/cmd/podmanV2/report/templates.go b/cmd/podmanV2/report/templates.go
deleted file mode 100644
index e46048e97..000000000
--- a/cmd/podmanV2/report/templates.go
+++ /dev/null
@@ -1,73 +0,0 @@
-package report
-
-import (
- "strings"
- "text/template"
- "time"
- "unicode"
-
- "github.com/docker/go-units"
-)
-
-var defaultFuncMap = template.FuncMap{
- "ellipsis": func(s string, length int) string {
- if len(s) > length {
- return s[:length-3] + "..."
- }
- return s
- },
- "humanDuration": func(t int64) string {
- return units.HumanDuration(time.Since(time.Unix(t, 0))) + " ago"
- },
- "humanDurationFromTime": func(t time.Time) string {
- return units.HumanDuration(time.Since(t)) + " ago"
- },
- "humanSize": func(sz int64) string {
- s := units.HumanSizeWithPrecision(float64(sz), 3)
- i := strings.LastIndexFunc(s, unicode.IsNumber)
- return s[:i+1] + " " + s[i+1:]
- },
- "join": strings.Join,
- "lower": strings.ToLower,
- "rfc3339": func(t int64) string {
- return time.Unix(t, 0).Format(time.RFC3339)
- },
- "replace": strings.Replace,
- "split": strings.Split,
- "title": strings.Title,
- "upper": strings.ToUpper,
- // TODO: Remove after Go 1.14 port
- "slice": func(s string, i, j int) string {
- if i > j || len(s) < i {
- return s
- }
- if len(s) < j {
- return s[i:]
- }
- return s[i:j]
- },
-}
-
-func ReportHeader(columns ...string) []byte {
- hdr := make([]string, len(columns))
- for i, h := range columns {
- hdr[i] = strings.ToUpper(h)
- }
- return []byte(strings.Join(hdr, "\t") + "\n")
-}
-
-func AppendFuncMap(funcMap template.FuncMap) template.FuncMap {
- merged := PodmanTemplateFuncs()
- for k, v := range funcMap {
- merged[k] = v
- }
- return merged
-}
-
-func PodmanTemplateFuncs() template.FuncMap {
- merged := make(template.FuncMap)
- for k, v := range defaultFuncMap {
- merged[k] = v
- }
- return merged
-}
diff --git a/cmd/podmanV2/system/info.go b/cmd/podmanV2/system/info.go
new file mode 100644
index 000000000..69b2871b7
--- /dev/null
+++ b/cmd/podmanV2/system/info.go
@@ -0,0 +1,74 @@
+package system
+
+import (
+ "encoding/json"
+ "fmt"
+ "os"
+ "text/template"
+
+ "github.com/containers/libpod/cmd/podmanV2/registry"
+ "github.com/containers/libpod/pkg/domain/entities"
+ "github.com/spf13/cobra"
+ "gopkg.in/yaml.v2"
+)
+
+var (
+ infoDescription = `Display information pertaining to the host, current storage stats, and build of podman.
+
+ Useful for the user and when reporting issues.
+`
+ infoCommand = &cobra.Command{
+ Use: "info",
+ Args: cobra.NoArgs,
+ Long: infoDescription,
+ Short: "Display podman system information",
+ PreRunE: preRunE,
+ RunE: info,
+ Example: `podman info`,
+ }
+)
+
+var (
+ inFormat string
+ debug bool
+)
+
+func init() {
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
+ Command: infoCommand,
+ })
+ flags := infoCommand.Flags()
+ 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")
+}
+
+func info(cmd *cobra.Command, args []string) error {
+ info, err := registry.ContainerEngine().Info(registry.GetContext())
+ if err != nil {
+ return err
+ }
+
+ if inFormat == "json" {
+ b, err := json.MarshalIndent(info, "", " ")
+ if err != nil {
+ return err
+ }
+ fmt.Println(string(b))
+ return nil
+ }
+ if !cmd.Flag("format").Changed {
+ b, err := yaml.Marshal(info)
+ if err != nil {
+ return err
+ }
+ fmt.Println(string(b))
+ return nil
+ }
+ tmpl, err := template.New("info").Parse(inFormat)
+ if err != nil {
+ return err
+ }
+ err = tmpl.Execute(os.Stdout, info)
+ return err
+}
diff --git a/cmd/podmanV2/system/service.go b/cmd/podmanV2/system/service.go
new file mode 100644
index 000000000..5573f7039
--- /dev/null
+++ b/cmd/podmanV2/system/service.go
@@ -0,0 +1,124 @@
+package system
+
+import (
+ "fmt"
+ "os"
+ "path/filepath"
+ "time"
+
+ "github.com/containers/libpod/cmd/podmanV2/registry"
+ "github.com/containers/libpod/pkg/domain/entities"
+ "github.com/containers/libpod/pkg/rootless"
+ "github.com/containers/libpod/pkg/systemd"
+ "github.com/containers/libpod/pkg/util"
+ "github.com/sirupsen/logrus"
+ "github.com/spf13/cobra"
+)
+
+var (
+ srvDescription = `Run an API service
+
+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`,
+ }
+
+ srvArgs = struct {
+ Timeout int64
+ Varlink bool
+ }{}
+)
+
+func init() {
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Mode: []entities.EngineMode{entities.ABIMode},
+ Command: srvCmd,
+ Parent: systemCmd,
+ })
+
+ 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.")
+}
+
+func service(cmd *cobra.Command, args []string) error {
+ apiURI, err := resolveApiURI(args)
+ if err != nil {
+ return err
+ }
+ logrus.Infof("using API endpoint: \"%s\"", apiURI)
+
+ opts := entities.ServiceOptions{
+ URI: apiURI,
+ Timeout: time.Duration(srvArgs.Timeout) * time.Second,
+ Command: cmd,
+ }
+
+ if srvArgs.Varlink {
+ return registry.ContainerEngine().VarlinkService(registry.GetContext(), opts)
+ }
+
+ logrus.Warn("This function is EXPERIMENTAL")
+ fmt.Fprintf(os.Stderr, "This function is EXPERIMENTAL.\n")
+ return registry.ContainerEngine().RestService(registry.GetContext(), opts)
+}
+
+func resolveApiURI(_url []string) (string, error) {
+
+ // When determining _*THE*_ listening endpoint --
+ // 1) User input wins always
+ // 2) systemd socket activation
+ // 3) rootless honors XDG_RUNTIME_DIR
+ // 4) if varlink -- adapter.DefaultVarlinkAddress
+ // 5) lastly adapter.DefaultAPIAddress
+
+ if _url == nil {
+ if v, found := os.LookupEnv("PODMAN_SOCKET"); found {
+ _url = []string{v}
+ }
+ }
+
+ switch {
+ case len(_url) > 0:
+ return _url[0], nil
+ case systemd.SocketActivated():
+ logrus.Info("using systemd socket activation to determine API endpoint")
+ return "", nil
+ case rootless.IsRootless():
+ xdg, err := util.GetRuntimeDir()
+ if err != nil {
+ return "", err
+ }
+
+ socketName := "podman.sock"
+ if srvArgs.Varlink {
+ socketName = "io.podman"
+ }
+ socketDir := filepath.Join(xdg, "podman", socketName)
+ if _, err := os.Stat(filepath.Dir(socketDir)); err != nil {
+ if os.IsNotExist(err) {
+ if err := os.Mkdir(filepath.Dir(socketDir), 0755); err != nil {
+ return "", err
+ }
+ } else {
+ return "", err
+ }
+ }
+ return "unix:" + socketDir, nil
+ case srvArgs.Varlink:
+ return registry.DefaultVarlinkAddress, nil
+ default:
+ return registry.DefaultAPIAddress, nil
+ }
+}
diff --git a/cmd/podmanV2/system/system.go b/cmd/podmanV2/system/system.go
index 4e805c7bd..b44632187 100644
--- a/cmd/podmanV2/system/system.go
+++ b/cmd/podmanV2/system/system.go
@@ -8,7 +8,7 @@ import (
var (
// Command: podman _system_
- cmd = &cobra.Command{
+ systemCmd = &cobra.Command{
Use: "system",
Short: "Manage podman",
Long: "Manage podman",
@@ -21,10 +21,10 @@ var (
func init() {
registry.Commands = append(registry.Commands, registry.CliCommand{
Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
- Command: cmd,
+ Command: systemCmd,
})
- cmd.SetHelpTemplate(registry.HelpTemplate())
- cmd.SetUsageTemplate(registry.UsageTemplate())
+ systemCmd.SetHelpTemplate(registry.HelpTemplate())
+ systemCmd.SetUsageTemplate(registry.UsageTemplate())
}
func preRunE(cmd *cobra.Command, args []string) error {
diff --git a/cmd/podmanV2/system/varlink.go b/cmd/podmanV2/system/varlink.go
new file mode 100644
index 000000000..da9af6fe4
--- /dev/null
+++ b/cmd/podmanV2/system/varlink.go
@@ -0,0 +1,56 @@
+package system
+
+import (
+ "time"
+
+ "github.com/containers/libpod/cmd/podmanV2/registry"
+ "github.com/containers/libpod/pkg/domain/entities"
+ "github.com/spf13/cobra"
+)
+
+var (
+ varlinkDescription = `Run varlink interface. Podman varlink listens on the specified unix domain socket for incoming connects.
+
+ Tools speaking varlink protocol can remotely manage pods, containers and images.
+`
+ varlinkCmd = &cobra.Command{
+ Use: "varlink [flags] [URI]",
+ Args: cobra.MinimumNArgs(1),
+ Short: "Run varlink interface",
+ Long: varlinkDescription,
+ PreRunE: preRunE,
+ RunE: varlinkE,
+ Example: `podman varlink unix:/run/podman/io.podman
+ podman varlink --timeout 5000 unix:/run/podman/io.podman`,
+ }
+ varlinkArgs = struct {
+ Timeout int64
+ }{}
+)
+
+func init() {
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
+ Command: varlinkCmd,
+ })
+ varlinkCmd.SetHelpTemplate(registry.HelpTemplate())
+ varlinkCmd.SetUsageTemplate(registry.UsageTemplate())
+
+ 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")
+
+}
+
+func varlinkE(cmd *cobra.Command, args []string) error {
+ uri := registry.DefaultVarlinkAddress
+ if len(args) > 0 {
+ uri = args[0]
+ }
+ opts := entities.ServiceOptions{
+ URI: uri,
+ Timeout: time.Duration(varlinkArgs.Timeout) * time.Second,
+ Command: cmd,
+ }
+ return registry.ContainerEngine().VarlinkService(registry.GetContext(), opts)
+}
diff --git a/cmd/podmanV2/system/version.go b/cmd/podmanV2/system/version.go
index e8002056b..8d6e8b7a8 100644
--- a/cmd/podmanV2/system/version.go
+++ b/cmd/podmanV2/system/version.go
@@ -24,7 +24,7 @@ var (
RunE: version,
PersistentPreRunE: preRunE,
}
- format string
+ versionFormat string
)
type versionStruct struct {
@@ -38,7 +38,7 @@ func init() {
Command: versionCommand,
})
flags := versionCommand.Flags()
- flags.StringVarP(&format, "format", "f", "", "Change the output format to JSON or a Go template")
+ flags.StringVarP(&versionFormat, "format", "f", "", "Change the output format to JSON or a Go template")
}
func version(cmd *cobra.Command, args []string) error {
@@ -62,7 +62,7 @@ func version(cmd *cobra.Command, args []string) error {
v.Server = v.Client
//}
- versionOutputFormat := format
+ versionOutputFormat := versionFormat
if versionOutputFormat != "" {
if strings.Join(strings.Fields(versionOutputFormat), "") == "{{json.}}" {
versionOutputFormat = formats.JSONString