enable integration tests for remote-client

first pass at enabling a swath of integration tests for the
remote-client.

Signed-off-by: baude <bbaude@redhat.com>
This commit is contained in:
baude 2019-04-19 08:33:18 -05:00
parent 7b67c9601e
commit bc7b1ca03d
37 changed files with 167 additions and 89 deletions

5
API.md
View File

@ -259,6 +259,8 @@ in the [API.md](https://github.com/containers/libpod/blob/master/API.md) file in
[error ContainerNotFound](#ContainerNotFound) [error ContainerNotFound](#ContainerNotFound)
[error ErrCtrStopped](#ErrCtrStopped)
[error ErrorOccurred](#ErrorOccurred) [error ErrorOccurred](#ErrorOccurred)
[error ImageNotFound](#ImageNotFound) [error ImageNotFound](#ImageNotFound)
@ -1978,6 +1980,9 @@ force [bool](https://godoc.org/builtin#bool)
### <a name="ContainerNotFound"></a>type ContainerNotFound ### <a name="ContainerNotFound"></a>type ContainerNotFound
ContainerNotFound means the container could not be found by the provided name or ID in local storage. ContainerNotFound means the container could not be found by the provided name or ID in local storage.
### <a name="ErrCtrStopped"></a>type ErrCtrStopped
Container is already stopped
### <a name="ErrorOccurred"></a>type ErrorOccurred ### <a name="ErrorOccurred"></a>type ErrorOccurred
ErrorOccurred is a generic error for an error that occurs during the execution. The actual error message ErrorOccurred is a generic error for an error that occurs during the execution. The actual error message

View File

@ -3,10 +3,6 @@
package main package main
import ( import (
"os"
"github.com/containers/libpod/pkg/rootless"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@ -29,16 +25,6 @@ func profileOff(cmd *cobra.Command) error {
} }
func setupRootless(cmd *cobra.Command, args []string) error { func setupRootless(cmd *cobra.Command, args []string) error {
if rootless.IsRootless() {
became, ret, err := rootless.BecomeRootInUserNS()
if err != nil {
logrus.Errorf(err.Error())
os.Exit(1)
}
if became {
os.Exit(ret)
}
}
return nil return nil
} }

View File

@ -1255,3 +1255,6 @@ error RuntimeError (reason: string)
# The Podman endpoint requires that you use a streaming connection. # The Podman endpoint requires that you use a streaming connection.
error WantsMoreRequired (reason: string) error WantsMoreRequired (reason: string)
# Container is already stopped
error ErrCtrStopped (id: string)

View File

@ -14,8 +14,6 @@ then
exit 1 exit 1
fi fi
export PODMAN_VARLINK_ADDRESS=unix:/tmp/podman-$(id -u)
echo "." echo "."
echo "Hello, my name is $USER and I live in $PWD can I be your friend?" echo "Hello, my name is $USER and I live in $PWD can I be your friend?"

View File

@ -922,7 +922,7 @@ func makeRuntime(ctx context.Context, runtime *Runtime) (err error) {
if os.IsNotExist(errors.Cause(err)) { if os.IsNotExist(errors.Cause(err)) {
manager, err = lock.NewSHMLockManager(lockPath, runtime.config.NumLocks) manager, err = lock.NewSHMLockManager(lockPath, runtime.config.NumLocks)
if err != nil { if err != nil {
return err return errors.Wrapf(err, "failed to get new shm lock manager")
} }
} else if errors.Cause(err) == syscall.ERANGE && runtime.doRenumber { } else if errors.Cause(err) == syscall.ERANGE && runtime.doRenumber {
logrus.Debugf("Number of locks does not match - removing old locks") logrus.Debugf("Number of locks does not match - removing old locks")

View File

@ -234,15 +234,25 @@ func (r *LocalRuntime) StopContainers(ctx context.Context, cli *cliconfig.StopVa
ids, err := iopodman.GetContainersByContext().Call(r.Conn, cli.All, cli.Latest, cli.InputArgs) ids, err := iopodman.GetContainersByContext().Call(r.Conn, cli.All, cli.Latest, cli.InputArgs)
if err != nil { if err != nil {
return ok, failures, err return ok, failures, TranslateError(err)
} }
for _, id := range ids { for _, id := range ids {
stopped, err := iopodman.StopContainer().Call(r.Conn, id, int64(cli.Timeout)) if _, err := iopodman.StopContainer().Call(r.Conn, id, int64(cli.Timeout)); err != nil {
if err != nil { transError := TranslateError(err)
if errors.Cause(transError) == libpod.ErrCtrStopped {
ok = append(ok, id)
continue
}
if errors.Cause(transError) == libpod.ErrCtrStateInvalid && cli.All {
ok = append(ok, id)
continue
}
failures[id] = err failures[id] = err
} else { } else {
ok = append(ok, stopped) // We should be using ID here because in varlink, only successful returns
// include the string id
ok = append(ok, id)
} }
} }
return ok, failures, nil return ok, failures, nil
@ -310,7 +320,7 @@ func (r *LocalRuntime) KillContainers(ctx context.Context, cli *cliconfig.KillVa
func (r *LocalRuntime) RemoveContainers(ctx context.Context, cli *cliconfig.RmValues) ([]string, map[string]error, error) { func (r *LocalRuntime) RemoveContainers(ctx context.Context, cli *cliconfig.RmValues) ([]string, map[string]error, error) {
ids, err := iopodman.GetContainersByContext().Call(r.Conn, cli.All, cli.Latest, cli.InputArgs) ids, err := iopodman.GetContainersByContext().Call(r.Conn, cli.All, cli.Latest, cli.InputArgs)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, TranslateError(err)
} }
var ( var (

31
pkg/adapter/errors.go Normal file
View File

@ -0,0 +1,31 @@
// +build remoteclient
package adapter
import (
iopodman "github.com/containers/libpod/cmd/podman/varlink"
"github.com/containers/libpod/libpod"
"github.com/pkg/errors"
)
// TranslateMapErrors translates the errors a typical podman output struct
// from varlink errors to libpod errors
func TranslateMapErrors(failures map[string]error) map[string]error {
for k, v := range failures {
failures[k] = TranslateError(v)
}
return failures
}
// TranslateError converts a single varlink error to a libpod error
func TranslateError(err error) error {
switch err.(type) {
case *iopodman.ContainerNotFound:
return errors.Wrap(libpod.ErrNoSuchCtr, err.Error())
case *iopodman.ErrCtrStopped:
return errors.Wrap(libpod.ErrCtrStopped, err.Error())
case *iopodman.InvalidState:
return errors.Wrap(libpod.ErrCtrStateInvalid, err.Error())
}
return err
}

View File

@ -20,12 +20,7 @@ func (r RemoteRuntime) Info() ([]libpod.InfoData, error) {
registries := make(map[string]interface{}) registries := make(map[string]interface{})
insecureRegistries := make(map[string]interface{}) insecureRegistries := make(map[string]interface{})
conn, err := r.Connect() info, err := iopodman.GetInfo().Call(r.Conn)
if err != nil {
return nil, err
}
defer conn.Close()
info, err := iopodman.GetInfo().Call(conn)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -172,11 +172,15 @@ func (r *LocalRuntime) StartPods(ctx context.Context, cli *cliconfig.PodStartVal
// CreatePod creates a pod for the remote client over a varlink connection // CreatePod creates a pod for the remote client over a varlink connection
func (r *LocalRuntime) CreatePod(ctx context.Context, cli *cliconfig.PodCreateValues, labels map[string]string) (string, error) { func (r *LocalRuntime) CreatePod(ctx context.Context, cli *cliconfig.PodCreateValues, labels map[string]string) (string, error) {
var share []string
if cli.Share != "" {
share = strings.Split(cli.Share, ",")
}
pc := iopodman.PodCreate{ pc := iopodman.PodCreate{
Name: cli.Name, Name: cli.Name,
CgroupParent: cli.CgroupParent, CgroupParent: cli.CgroupParent,
Labels: labels, Labels: labels,
Share: strings.Split(cli.Share, ","), Share: share,
Infra: cli.Infra, Infra: cli.Infra,
InfraCommand: cli.InfraCommand, InfraCommand: cli.InfraCommand,
InfraImage: cli.InfraCommand, InfraImage: cli.InfraCommand,

View File

@ -119,6 +119,9 @@ func (i *LibpodAPI) GetContainersByContext(call iopodman.VarlinkCall, all, lates
ctrs, err := shortcuts.GetContainersByContext(all, latest, input, i.Runtime) ctrs, err := shortcuts.GetContainersByContext(all, latest, input, i.Runtime)
if err != nil { if err != nil {
if errors.Cause(err) == libpod.ErrNoSuchCtr {
return call.ReplyContainerNotFound("", err.Error())
}
return call.ReplyErrorOccurred(err.Error()) return call.ReplyErrorOccurred(err.Error())
} }
@ -359,7 +362,11 @@ func (i *LibpodAPI) StartContainer(call iopodman.VarlinkCall, name string) error
if state == libpod.ContainerStateRunning || state == libpod.ContainerStatePaused { if state == libpod.ContainerStateRunning || state == libpod.ContainerStatePaused {
return call.ReplyErrorOccurred("container is already running or paused") return call.ReplyErrorOccurred("container is already running or paused")
} }
if err := ctr.Start(getContext(), false); err != nil { recursive := false
if ctr.PodID() != "" {
recursive = true
}
if err := ctr.Start(getContext(), recursive); err != nil {
return call.ReplyErrorOccurred(err.Error()) return call.ReplyErrorOccurred(err.Error())
} }
return call.ReplyStartContainer(ctr.ID()) return call.ReplyStartContainer(ctr.ID())
@ -386,7 +393,13 @@ func (i *LibpodAPI) StopContainer(call iopodman.VarlinkCall, name string, timeou
if err != nil { if err != nil {
return call.ReplyContainerNotFound(name, err.Error()) return call.ReplyContainerNotFound(name, err.Error())
} }
if err := ctr.StopWithTimeout(uint(timeout)); err != nil && err != libpod.ErrCtrStopped { if err := ctr.StopWithTimeout(uint(timeout)); err != nil {
if errors.Cause(err) == libpod.ErrCtrStopped {
return call.ReplyErrCtrStopped(ctr.ID())
}
if errors.Cause(err) == libpod.ErrCtrStateInvalid {
return call.ReplyInvalidState(ctr.ID(), err.Error())
}
return call.ReplyErrorOccurred(err.Error()) return call.ReplyErrorOccurred(err.Error())
} }
return call.ReplyStopContainer(ctr.ID()) return call.ReplyStopContainer(ctr.ID())

View File

@ -6,7 +6,6 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"github.com/containers/libpod/pkg/adapter/shortcuts" "github.com/containers/libpod/pkg/adapter/shortcuts"
"github.com/containers/libpod/pkg/rootless"
"syscall" "syscall"
"github.com/containers/libpod/cmd/podman/shared" "github.com/containers/libpod/cmd/podman/shared"
@ -37,12 +36,9 @@ func (i *LibpodAPI) CreatePod(call iopodman.VarlinkCall, create iopodman.PodCrea
if !create.Infra { if !create.Infra {
return call.ReplyErrorOccurred("you must have an infra container to publish port bindings to the host") return call.ReplyErrorOccurred("you must have an infra container to publish port bindings to the host")
} }
if rootless.IsRootless() {
return call.ReplyErrorOccurred("rootless networking does not allow port binding to the host")
}
portBindings, err := shared.CreatePortBindings(create.Publish) portBindings, err := shared.CreatePortBindings(create.Publish)
if err != nil { if err != nil {
return err return call.ReplyErrorOccurred(err.Error())
} }
options = append(options, libpod.WithInfraContainerPorts(portBindings)) options = append(options, libpod.WithInfraContainerPorts(portBindings))

View File

@ -264,9 +264,14 @@ func PodmanTestCreateUtil(tempDir string, remote bool) *PodmanTestIntegration {
} }
if remote { if remote {
p.PodmanTest.RemotePodmanBinary = podmanRemoteBinary p.PodmanTest.RemotePodmanBinary = podmanRemoteBinary
if !rootless.IsRootless() {
uuid := stringid.GenerateNonCryptoID() uuid := stringid.GenerateNonCryptoID()
if !rootless.IsRootless() {
p.VarlinkEndpoint = fmt.Sprintf("unix:/run/podman/io.podman-%s", uuid) p.VarlinkEndpoint = fmt.Sprintf("unix:/run/podman/io.podman-%s", uuid)
} else {
runtimeDir := os.Getenv("XDG_RUNTIME_DIR")
socket := fmt.Sprintf("io.podman-%s", uuid)
fqpath := filepath.Join(runtimeDir, socket)
p.VarlinkEndpoint = fmt.Sprintf("unix:%s", fqpath)
} }
} }

View File

@ -1,5 +1,3 @@
// +build !remoteclient
package integration package integration
import ( import (

View File

@ -1,5 +1,3 @@
// +build !remoteclient
package integration package integration
import ( import (
@ -63,6 +61,7 @@ var _ = Describe("Podman diff", func() {
}) })
It("podman diff container and committed image", func() { It("podman diff container and committed image", func() {
SkipIfRemote()
session := podmanTest.Podman([]string{"run", "--name=diff-test", ALPINE, "touch", "/tmp/diff-test"}) session := podmanTest.Podman([]string{"run", "--name=diff-test", ALPINE, "touch", "/tmp/diff-test"})
session.WaitWithDefaultTimeout() session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0)) Expect(session.ExitCode()).To(Equal(0))

View File

@ -24,6 +24,7 @@ var _ = Describe("Podman Info", func() {
} }
podmanTest = PodmanTestCreate(tempdir) podmanTest = PodmanTestCreate(tempdir)
podmanTest.Setup() podmanTest.Setup()
podmanTest.DelayForVarlink()
}) })
AfterEach(func() { AfterEach(func() {

View File

@ -1,5 +1,3 @@
// +build !remoteclient
package integration package integration
import ( import (

View File

@ -3,13 +3,17 @@
package integration package integration
import ( import (
"bytes"
"fmt" "fmt"
"github.com/containers/libpod/pkg/rootless" "github.com/containers/libpod/pkg/rootless"
"io/ioutil" "io/ioutil"
"os" "os"
"os/exec" "os/exec"
"path/filepath" "path/filepath"
"strconv"
"strings" "strings"
"syscall"
"time"
"github.com/onsi/ginkgo" "github.com/onsi/ginkgo"
) )
@ -50,34 +54,77 @@ func PodmanTestCreate(tempDir string) *PodmanTestIntegration {
return pti return pti
} }
func (p *PodmanTestIntegration) ResetVarlinkAddress() {
os.Unsetenv("PODMAN_VARLINK_ADDRESS")
}
func (p *PodmanTestIntegration) SetVarlinkAddress(addr string) {
os.Setenv("PODMAN_VARLINK_ADDRESS", addr)
}
func (p *PodmanTestIntegration) StartVarlink() { func (p *PodmanTestIntegration) StartVarlink() {
if os.Geteuid() == 0 { if os.Geteuid() == 0 {
os.MkdirAll("/run/podman", 0755) os.MkdirAll("/run/podman", 0755)
} }
varlinkEndpoint := p.VarlinkEndpoint varlinkEndpoint := p.VarlinkEndpoint
if addr := os.Getenv("PODMAN_VARLINK_ADDRESS"); addr != "" { p.SetVarlinkAddress(p.VarlinkEndpoint)
varlinkEndpoint = addr
}
args := []string{"varlink", "--timeout", "0", varlinkEndpoint} args := []string{"varlink", "--timeout", "0", varlinkEndpoint}
podmanOptions := getVarlinkOptions(p, args) podmanOptions := getVarlinkOptions(p, args)
command := exec.Command(p.PodmanBinary, podmanOptions...) command := exec.Command(p.PodmanBinary, podmanOptions...)
fmt.Printf("Running: %s %s\n", p.PodmanBinary, strings.Join(podmanOptions, " ")) fmt.Printf("Running: %s %s\n", p.PodmanBinary, strings.Join(podmanOptions, " "))
command.Start() command.Start()
command.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
p.VarlinkCommand = command
p.VarlinkSession = command.Process p.VarlinkSession = command.Process
} }
func (p *PodmanTestIntegration) StopVarlink() { func (p *PodmanTestIntegration) StopVarlink() {
var out bytes.Buffer
var pids []int
varlinkSession := p.VarlinkSession varlinkSession := p.VarlinkSession
varlinkSession.Kill()
varlinkSession.Wait()
if !rootless.IsRootless() { if !rootless.IsRootless() {
if err := varlinkSession.Kill(); err != nil {
fmt.Fprintf(os.Stderr, "error on varlink stop-kill %q", err)
}
if _, err := varlinkSession.Wait(); err != nil {
fmt.Fprintf(os.Stderr, "error on varlink stop-wait %q", err)
}
} else {
p.ResetVarlinkAddress()
parentPid := fmt.Sprintf("%d", p.VarlinkSession.Pid)
pgrep := exec.Command("pgrep", "-P", parentPid)
fmt.Printf("running: pgrep %s\n", parentPid)
pgrep.Stdout = &out
err := pgrep.Run()
if err != nil {
fmt.Fprint(os.Stderr, "unable to find varlink pid")
}
for _, s := range strings.Split(out.String(), "\n") {
if len(s) == 0 {
continue
}
p, err := strconv.Atoi(s)
if err != nil {
fmt.Fprintf(os.Stderr, "unable to convert %s to int", s)
}
if p != 0 {
pids = append(pids, p)
}
}
pids = append(pids, p.VarlinkSession.Pid)
for _, pid := range pids {
syscall.Kill(pid, syscall.SIGKILL)
}
}
socket := strings.Split(p.VarlinkEndpoint, ":")[1] socket := strings.Split(p.VarlinkEndpoint, ":")[1]
if err := os.Remove(socket); err != nil { if err := os.Remove(socket); err != nil {
fmt.Println(err) fmt.Println(err)
} }
}
} }
//MakeOptions assembles all the podman main options //MakeOptions assembles all the podman main options
@ -110,3 +157,14 @@ func (p *PodmanTestIntegration) RestoreArtifact(image string) error {
command.Wait() command.Wait()
return nil return nil
} }
func (p *PodmanTestIntegration) DelayForVarlink() {
for i := 0; i < 5; i++ {
session := p.Podman([]string{"info"})
session.WaitWithDefaultTimeout()
if session.ExitCode() == 0 || i == 4 {
break
}
time.Sleep(1 * time.Second)
}
}

View File

@ -80,3 +80,4 @@ func (p *PodmanTestIntegration) RestoreArtifact(image string) error {
return nil return nil
} }
func (p *PodmanTestIntegration) StopVarlink() {} func (p *PodmanTestIntegration) StopVarlink() {}
func (p *PodmanTestIntegration) DelayForVarlink() {}

View File

@ -1,5 +1,3 @@
// +build !remoteclient
package integration package integration
import ( import (

View File

@ -1,5 +1,3 @@
// +build !remoteclient
package integration package integration
import ( import (

View File

@ -1,5 +1,3 @@
// +build !remoteclient
package integration package integration
import ( import (

View File

@ -1,5 +1,3 @@
// +build !remoteclient
package integration package integration
import ( import (

View File

@ -1,5 +1,3 @@
// +build !remoteclient
package integration package integration
import ( import (

View File

@ -1,5 +1,3 @@
// +build !remoteclient
package integration package integration
import ( import (

View File

@ -1,5 +1,3 @@
// +build !remoteclient
package integration package integration
import ( import (

View File

@ -1,5 +1,3 @@
// +build !remoteclient
package integration package integration
import ( import (

View File

@ -1,5 +1,3 @@
// +build !remoteclient
package integration package integration
import ( import (

View File

@ -1,5 +1,3 @@
// +build !remoteclient
package integration package integration
import ( import (

View File

@ -1,5 +1,3 @@
// +build !remoteclient
package integration package integration
import ( import (

View File

@ -1,5 +1,3 @@
// +build !remoteclient
package integration package integration
import ( import (

View File

@ -1,5 +1,3 @@
// +build !remoteclient
package integration package integration
import ( import (

View File

@ -273,6 +273,7 @@ var _ = Describe("Podman run", func() {
}) })
It("podman run notify_socket", func() { It("podman run notify_socket", func() {
SkipIfRemote()
host := GetHostDistributionInfo() host := GetHostDistributionInfo()
if host.Distribution != "rhel" && host.Distribution != "centos" && host.Distribution != "fedora" { if host.Distribution != "rhel" && host.Distribution != "centos" && host.Distribution != "fedora" {
Skip("this test requires a working runc") Skip("this test requires a working runc")

View File

@ -4,6 +4,7 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"github.com/containers/libpod/pkg/rootless"
. "github.com/containers/libpod/test/utils" . "github.com/containers/libpod/test/utils"
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
@ -75,6 +76,9 @@ var _ = Describe("Podman save", func() {
}) })
It("podman save to directory with oci format", func() { It("podman save to directory with oci format", func() {
if rootless.IsRootless() && podmanTest.RemoteTest {
Skip("Requires a fix in containers image for chown/lchown")
}
outdir := filepath.Join(podmanTest.TempDir, "save") outdir := filepath.Join(podmanTest.TempDir, "save")
save := podmanTest.Podman([]string{"save", "--format", "oci-dir", "-o", outdir, ALPINE}) save := podmanTest.Podman([]string{"save", "--format", "oci-dir", "-o", outdir, ALPINE})
@ -83,6 +87,9 @@ var _ = Describe("Podman save", func() {
}) })
It("podman save to directory with v2s2 docker format", func() { It("podman save to directory with v2s2 docker format", func() {
if rootless.IsRootless() && podmanTest.RemoteTest {
Skip("Requires a fix in containers image for chown/lchown")
}
outdir := filepath.Join(podmanTest.TempDir, "save") outdir := filepath.Join(podmanTest.TempDir, "save")
save := podmanTest.Podman([]string{"save", "--format", "docker-dir", "-o", outdir, ALPINE}) save := podmanTest.Podman([]string{"save", "--format", "docker-dir", "-o", outdir, ALPINE})
@ -91,6 +98,9 @@ var _ = Describe("Podman save", func() {
}) })
It("podman save to directory with docker format and compression", func() { It("podman save to directory with docker format and compression", func() {
if rootless.IsRootless() && podmanTest.RemoteTest {
Skip("Requires a fix in containers image for chown/lchown")
}
outdir := filepath.Join(podmanTest.TempDir, "save") outdir := filepath.Join(podmanTest.TempDir, "save")
save := podmanTest.Podman([]string{"save", "--compress", "--format", "docker-dir", "-o", outdir, ALPINE}) save := podmanTest.Podman([]string{"save", "--compress", "--format", "docker-dir", "-o", outdir, ALPINE})

View File

@ -1,5 +1,3 @@
// +build !remoteclient
package integration package integration
import ( import (

View File

@ -1,5 +1,3 @@
// +build !remoteclient
package integration package integration
import ( import (

View File

@ -1,5 +1,3 @@
// +build !remoteclient
package integration package integration
import ( import (

View File

@ -4,7 +4,6 @@ import (
"bufio" "bufio"
"encoding/json" "encoding/json"
"fmt" "fmt"
"github.com/containers/libpod/pkg/rootless"
"io/ioutil" "io/ioutil"
"os" "os"
"os/exec" "os/exec"
@ -42,6 +41,7 @@ type PodmanTest struct {
RemotePodmanBinary string RemotePodmanBinary string
VarlinkSession *os.Process VarlinkSession *os.Process
VarlinkEndpoint string VarlinkEndpoint string
VarlinkCommand *exec.Cmd
} }
// PodmanSession wraps the gexec.session so we can extend it // PodmanSession wraps the gexec.session so we can extend it
@ -69,10 +69,8 @@ func (p *PodmanTest) PodmanAsUserBase(args []string, uid, gid uint32, cwd string
podmanBinary := p.PodmanBinary podmanBinary := p.PodmanBinary
if p.RemoteTest { if p.RemoteTest {
podmanBinary = p.RemotePodmanBinary podmanBinary = p.RemotePodmanBinary
if !rootless.IsRootless() {
env = append(env, fmt.Sprintf("PODMAN_VARLINK_ADDRESS=%s", p.VarlinkEndpoint)) env = append(env, fmt.Sprintf("PODMAN_VARLINK_ADDRESS=%s", p.VarlinkEndpoint))
} }
}
if env == nil { if env == nil {
fmt.Printf("Running: %s %s\n", podmanBinary, strings.Join(podmanOptions, " ")) fmt.Printf("Running: %s %s\n", podmanBinary, strings.Join(podmanOptions, " "))