From c81e065149da73ae904aa19ee46a23d1ab8ce55c Mon Sep 17 00:00:00 2001
From: Brent Baude <bbaude@redhat.com>
Date: Fri, 20 Mar 2020 14:00:05 -0500
Subject: [PATCH] podmanv2 enable remote wait

enable remote container wait with condition

Signed-off-by: Brent Baude <bbaude@redhat.com>
---
 cmd/podmanV2/containers/exists.go     |  6 ++--
 cmd/podmanV2/containers/inspect.go    |  2 --
 cmd/podmanV2/containers/wait.go       | 22 +++++++++++---
 cmd/podmanV2/root.go                  |  2 +-
 pkg/bindings/containers/containers.go |  5 ++--
 pkg/bindings/test/common_test.go      |  5 ++--
 pkg/bindings/test/containers_test.go  |  7 +++--
 pkg/bindings/test/pods_test.go        |  2 +-
 pkg/domain/entities/containers.go     |  8 ++++--
 pkg/domain/infra/abi/containers.go    |  7 +----
 pkg/domain/infra/tunnel/containers.go | 19 ++++++++++++-
 pkg/domain/infra/tunnel/helpers.go    | 41 +++++++++++++++++++++++++++
 12 files changed, 100 insertions(+), 26 deletions(-)
 create mode 100644 pkg/domain/infra/tunnel/helpers.go

diff --git a/cmd/podmanV2/containers/exists.go b/cmd/podmanV2/containers/exists.go
index 93989b54ae..3aff150be3 100644
--- a/cmd/podmanV2/containers/exists.go
+++ b/cmd/podmanV2/containers/exists.go
@@ -10,7 +10,9 @@ import (
 )
 
 var (
-	containerExistsCommand = &cobra.Command{
+	containerExistsDescription = `If the named container exists in local storage, podman container exists exits with 0, otherwise the exit code will be 1.`
+
+	existsCommand = &cobra.Command{
 		Use:   "exists CONTAINER",
 		Short: "Check if a container exists in local storage",
 		Long:  containerExistsDescription,
@@ -23,7 +25,7 @@ var (
 func init() {
 	registry.Commands = append(registry.Commands, registry.CliCommand{
 		Mode:    []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
-		Command: containerExistsCommand,
+		Command: existsCommand,
 		Parent:  containerCmd,
 	})
 }
diff --git a/cmd/podmanV2/containers/inspect.go b/cmd/podmanV2/containers/inspect.go
index 355924984b..635be47890 100644
--- a/cmd/podmanV2/containers/inspect.go
+++ b/cmd/podmanV2/containers/inspect.go
@@ -7,8 +7,6 @@ import (
 )
 
 var (
-	containerExistsDescription = `If the named container exists in local storage, podman container exists exits with 0, otherwise the exit code will be 1.`
-
 	// podman container _inspect_
 	inspectCmd = &cobra.Command{
 		Use:     "inspect [flags] CONTAINER",
diff --git a/cmd/podmanV2/containers/wait.go b/cmd/podmanV2/containers/wait.go
index d18064c3c9..27acb3348b 100644
--- a/cmd/podmanV2/containers/wait.go
+++ b/cmd/podmanV2/containers/wait.go
@@ -6,6 +6,7 @@ import (
 	"time"
 
 	"github.com/containers/libpod/cmd/podmanV2/registry"
+	"github.com/containers/libpod/libpod/define"
 	"github.com/containers/libpod/pkg/domain/entities"
 	"github.com/pkg/errors"
 	"github.com/spf13/cobra"
@@ -25,7 +26,10 @@ var (
 	}
 )
 
-var waitFlags = entities.WaitOptions{}
+var (
+	waitFlags     = entities.WaitOptions{}
+	waitCondition string
+)
 
 func init() {
 	registry.Commands = append(registry.Commands, registry.CliCommand{
@@ -34,15 +38,20 @@ func init() {
 		Parent:  containerCmd,
 	})
 
-	waitCommand.SetHelpTemplate(registry.HelpTemplate())
-	waitCommand.SetUsageTemplate(registry.UsageTemplate())
 	flags := waitCommand.Flags()
 	flags.DurationVarP(&waitFlags.Interval, "interval", "i", time.Duration(250), "Milliseconds to wait before polling for completion")
 	flags.BoolVarP(&waitFlags.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
-	flags.StringVar(&waitFlags.Condition, "condition", "stopped", "Condition to wait on")
+	flags.StringVar(&waitCondition, "condition", "stopped", "Condition to wait on")
+	if registry.EngineOpts.EngineMode == entities.ABIMode {
+		// TODO: This is the same as V1.  We could skip creating the flag altogether in V2...
+		_ = flags.MarkHidden("latest")
+	}
 }
 
 func wait(cmd *cobra.Command, args []string) error {
+	var (
+		err error
+	)
 	if waitFlags.Latest && len(args) > 0 {
 		return errors.New("cannot combine latest flag and arguments")
 	}
@@ -50,6 +59,11 @@ func wait(cmd *cobra.Command, args []string) error {
 		return errors.New("interval must be greater then 0")
 	}
 
+	waitFlags.Condition, err = define.StringToContainerStatus(waitCondition)
+	if err != nil {
+		return err
+	}
+
 	responses, err := registry.ContainerEngine().ContainerWait(context.Background(), args, waitFlags)
 	if err != nil {
 		return err
diff --git a/cmd/podmanV2/root.go b/cmd/podmanV2/root.go
index 92805ff306..24b083b9fa 100644
--- a/cmd/podmanV2/root.go
+++ b/cmd/podmanV2/root.go
@@ -25,7 +25,7 @@ func init() {
 	var dummyVersion bool
 	rootCmd.PersistentFlags().BoolVarP(&dummyVersion, "version", "v", false, "Version of podman")
 	rootCmd.PersistentFlags().StringVarP(&registry.EngineOpts.Uri, "remote", "r", "", "URL to access podman service")
-	rootCmd.PersistentFlags().StringSliceVarP(&registry.EngineOpts.Identities, "identity", "i", []string{}, "path to SSH identity file")
+	rootCmd.PersistentFlags().StringSliceVar(&registry.EngineOpts.Identities, "identity", []string{}, "path to SSH identity file")
 }
 
 func Execute() {
diff --git a/pkg/bindings/containers/containers.go b/pkg/bindings/containers/containers.go
index f298dbba13..534555a00e 100644
--- a/pkg/bindings/containers/containers.go
+++ b/pkg/bindings/containers/containers.go
@@ -7,6 +7,7 @@ import (
 	"strconv"
 
 	"github.com/containers/libpod/libpod"
+	"github.com/containers/libpod/libpod/define"
 	lpapiv2 "github.com/containers/libpod/pkg/api/handlers/libpod"
 	"github.com/containers/libpod/pkg/bindings"
 )
@@ -212,7 +213,7 @@ func Unpause(ctx context.Context, nameOrID string) error {
 // Wait blocks until the given container reaches a condition. If not provided, the condition will
 // default to stopped.  If the condition is stopped, an exit code for the container will be provided. The
 // nameOrID can be a container name or a partial/full ID.
-func Wait(ctx context.Context, nameOrID string, condition *string) (int32, error) {
+func Wait(ctx context.Context, nameOrID string, condition *define.ContainerStatus) (int32, error) { //nolint
 	var exitCode int32
 	conn, err := bindings.GetClient(ctx)
 	if err != nil {
@@ -220,7 +221,7 @@ func Wait(ctx context.Context, nameOrID string, condition *string) (int32, error
 	}
 	params := url.Values{}
 	if condition != nil {
-		params.Set("condition", *condition)
+		params.Set("condition", condition.String())
 	}
 	response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/wait", params, nameOrID)
 	if err != nil {
diff --git a/pkg/bindings/test/common_test.go b/pkg/bindings/test/common_test.go
index 409e620a33..6b8d6788c7 100644
--- a/pkg/bindings/test/common_test.go
+++ b/pkg/bindings/test/common_test.go
@@ -3,6 +3,7 @@ package test_bindings
 import (
 	"context"
 	"fmt"
+	"github.com/containers/libpod/libpod/define"
 	"io/ioutil"
 	"os"
 	"os/exec"
@@ -205,8 +206,8 @@ func (b *bindingTest) RunTopContainer(containerName *string, insidePod *bool, po
 	if err != nil {
 		return "", err
 	}
-	waiting := "running"
-	_, err = containers.Wait(b.conn, ctr.ID, &waiting)
+	wait := define.ContainerStateRunning
+	_, err = containers.Wait(b.conn, ctr.ID, &wait)
 	return ctr.ID, err
 }
 
diff --git a/pkg/bindings/test/containers_test.go b/pkg/bindings/test/containers_test.go
index afb0cc19b6..f5465c803a 100644
--- a/pkg/bindings/test/containers_test.go
+++ b/pkg/bindings/test/containers_test.go
@@ -1,6 +1,7 @@
 package test_bindings
 
 import (
+	"github.com/containers/libpod/libpod/define"
 	"net/http"
 	"strconv"
 	"strings"
@@ -282,8 +283,8 @@ var _ = Describe("Podman containers ", func() {
 		var (
 			name           = "top"
 			exitCode int32 = -1
-			pause          = "paused"
-			unpause        = "running"
+			pause          = define.ContainerStatePaused
+			running        = define.ContainerStateRunning
 		)
 		errChan := make(chan error)
 		_, err := bt.RunTopContainer(&name, nil, nil)
@@ -301,7 +302,7 @@ var _ = Describe("Podman containers ", func() {
 
 		errChan = make(chan error)
 		go func() {
-			_, waitErr := containers.Wait(bt.conn, name, &unpause)
+			_, waitErr := containers.Wait(bt.conn, name, &running)
 			errChan <- waitErr
 			close(errChan)
 		}()
diff --git a/pkg/bindings/test/pods_test.go b/pkg/bindings/test/pods_test.go
index fae1deca42..bcf8e69b89 100644
--- a/pkg/bindings/test/pods_test.go
+++ b/pkg/bindings/test/pods_test.go
@@ -81,7 +81,7 @@ var _ = Describe("Podman pods", func() {
 	It("List pods with filters", func() {
 		var newpod2 string = "newpod2"
 		bt.Podcreate(&newpod2)
-		_, err = bt.RunTopContainer(nil, &trueFlag, &newpod)
+		_, err = bt.RunTopContainer(nil, &bindings.PTrue, &newpod)
 		Expect(err).To(BeNil())
 
 		// Expected err with invalid filter params
diff --git a/pkg/domain/entities/containers.go b/pkg/domain/entities/containers.go
index 45ce1f1fba..0e1208b3b4 100644
--- a/pkg/domain/entities/containers.go
+++ b/pkg/domain/entities/containers.go
@@ -1,9 +1,13 @@
 package entities
 
-import "time"
+import (
+	"time"
+
+	"github.com/containers/libpod/libpod/define"
+)
 
 type WaitOptions struct {
-	Condition string
+	Condition define.ContainerStatus
 	Interval  time.Duration
 	Latest    bool
 }
diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go
index 2332c28740..cdcd772466 100644
--- a/pkg/domain/infra/abi/containers.go
+++ b/pkg/domain/infra/abi/containers.go
@@ -24,18 +24,13 @@ func (ic *ContainerEngine) ContainerWait(ctx context.Context, namesOrIds []strin
 	var (
 		responses []entities.WaitReport
 	)
-	condition, err := define.StringToContainerStatus(options.Condition)
-	if err != nil {
-		return nil, err
-	}
-
 	ctrs, err := shortcuts.GetContainersByContext(false, options.Latest, namesOrIds, ic.Libpod)
 	if err != nil {
 		return nil, err
 	}
 	for _, c := range ctrs {
 		response := entities.WaitReport{Id: c.ID()}
-		exitCode, err := c.WaitForConditionWithInterval(options.Interval, condition)
+		exitCode, err := c.WaitForConditionWithInterval(options.Interval, options.Condition)
 		if err != nil {
 			response.Error = err
 		} else {
diff --git a/pkg/domain/infra/tunnel/containers.go b/pkg/domain/infra/tunnel/containers.go
index d2d93d51bd..8bf74126df 100644
--- a/pkg/domain/infra/tunnel/containers.go
+++ b/pkg/domain/infra/tunnel/containers.go
@@ -13,7 +13,24 @@ func (ic *ContainerEngine) ContainerExists(ctx context.Context, nameOrId string)
 }
 
 func (ic *ContainerEngine) ContainerWait(ctx context.Context, namesOrIds []string, options entities.WaitOptions) ([]entities.WaitReport, error) {
-	return nil, nil
+	var (
+		responses []entities.WaitReport
+	)
+	cons, err := getContainersByContext(ic.ClientCxt, false, namesOrIds)
+	if err != nil {
+		return nil, err
+	}
+	for _, c := range cons {
+		response := entities.WaitReport{Id: c.ID}
+		exitCode, err := containers.Wait(ic.ClientCxt, c.ID, &options.Condition)
+		if err != nil {
+			response.Error = err
+		} else {
+			response.ExitCode = exitCode
+		}
+		responses = append(responses, response)
+	}
+	return responses, nil
 }
 
 func (r *ContainerEngine) ContainerDelete(ctx context.Context, opts entities.ContainerDeleteOptions) (*entities.ContainerDeleteReport, error) {
diff --git a/pkg/domain/infra/tunnel/helpers.go b/pkg/domain/infra/tunnel/helpers.go
new file mode 100644
index 0000000000..d5a3224c29
--- /dev/null
+++ b/pkg/domain/infra/tunnel/helpers.go
@@ -0,0 +1,41 @@
+package tunnel
+
+import (
+	"context"
+
+	"github.com/containers/libpod/pkg/api/handlers/libpod"
+	"github.com/containers/libpod/pkg/bindings"
+	"github.com/containers/libpod/pkg/bindings/containers"
+	"github.com/containers/libpod/pkg/util"
+	"github.com/pkg/errors"
+)
+
+func getContainersByContext(contextWithConnection context.Context, all bool, namesOrIds []string) ([]libpod.ListContainer, error) {
+	var (
+		cons []libpod.ListContainer
+	)
+	if all && len(namesOrIds) > 0 {
+		return nil, errors.New("cannot lookup containers and all")
+	}
+	c, err := containers.List(contextWithConnection, nil, &bindings.PTrue, nil, nil, nil, &bindings.PTrue)
+	if err != nil {
+		return nil, err
+	}
+	if all {
+		return c, err
+	}
+	for _, id := range namesOrIds {
+		var found bool
+		for _, con := range c {
+			if id == con.ID || util.StringInSlice(id, con.Names) {
+				cons = append(cons, con)
+				found = true
+				break
+			}
+		}
+		if !found {
+			return nil, errors.Errorf("unable to find container %q", id)
+		}
+	}
+	return cons, nil
+}