Implement podman-remote rm

* refactor command output to use one function
* Add new worker pool parallel operations
* Implement podman-remote umount
* Refactored podman wait to use printCmdOutput()

Signed-off-by: Jhon Honce <jhonce@redhat.com>
This commit is contained in:
Jhon Honce
2019-03-05 16:11:28 -07:00
parent fe79bdd07e
commit 09ff62429a
21 changed files with 597 additions and 277 deletions

View File

@ -24,12 +24,10 @@ func getMainCommands() []*cobra.Command {
_portCommand, _portCommand,
_refreshCommand, _refreshCommand,
_restartCommand, _restartCommand,
_rmCommand,
_searchCommand, _searchCommand,
_startCommand, _startCommand,
_statsCommand, _statsCommand,
_topCommand, _topCommand,
_umountCommand,
_unpauseCommand, _unpauseCommand,
} }

View File

@ -1,9 +1,6 @@
package main package main
import ( import (
"fmt"
"reflect"
"github.com/containers/libpod/cmd/podman/cliconfig" "github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/pkg/adapter" "github.com/containers/libpod/pkg/adapter"
"github.com/docker/docker/pkg/signal" "github.com/docker/docker/pkg/signal"
@ -71,21 +68,5 @@ func killCmd(c *cliconfig.KillValues) error {
if err != nil { if err != nil {
return err return err
} }
return printCmdResults(ok, failures)
for _, id := range ok {
fmt.Println(id)
}
if len(failures) > 0 {
keys := reflect.ValueOf(failures).MapKeys()
lastKey := keys[len(keys)-1].String()
lastErr := failures[lastKey]
delete(failures, lastKey)
for _, err := range failures {
outputError(err)
}
return lastErr
}
return nil
} }

View File

@ -54,11 +54,13 @@ var mainCommands = []*cobra.Command{
podCommand.Command, podCommand.Command,
_pullCommand, _pullCommand,
_pushCommand, _pushCommand,
_rmCommand,
&_rmiCommand, &_rmiCommand,
_runCommand, _runCommand,
_saveCommand, _saveCommand,
_stopCommand, _stopCommand,
_tagCommand, _tagCommand,
_umountCommand,
_versionCommand, _versionCommand,
_waitCommand, _waitCommand,
imageCommand.Command, imageCommand.Command,

View File

@ -4,12 +4,9 @@ import (
"fmt" "fmt"
"github.com/containers/libpod/cmd/podman/cliconfig" "github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/cmd/podman/libpodruntime"
"github.com/containers/libpod/cmd/podman/shared"
"github.com/containers/libpod/libpod" "github.com/containers/libpod/libpod"
"github.com/containers/libpod/libpod/image" "github.com/containers/libpod/pkg/adapter"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@ -48,78 +45,29 @@ func init() {
markFlagHiddenForRemoteClient("latest", flags) markFlagHiddenForRemoteClient("latest", flags)
} }
// saveCmd saves the image to either docker-archive or oci // rmCmd removes one or more containers
func rmCmd(c *cliconfig.RmValues) error { func rmCmd(c *cliconfig.RmValues) error {
var ( runtime, err := adapter.GetRuntime(&c.PodmanCommand)
deleteFuncs []shared.ParallelWorkerInput
)
ctx := getContext()
runtime, err := libpodruntime.GetRuntime(&c.PodmanCommand)
if err != nil { if err != nil {
return errors.Wrapf(err, "could not get runtime") return errors.Wrapf(err, "could not get runtime")
} }
defer runtime.Shutdown(false) defer runtime.Shutdown(false)
failureCnt := 0 ok, failures, err := runtime.RemoveContainers(getContext(), c)
delContainers, err := getAllOrLatestContainers(&c.PodmanCommand, runtime, -1, "all")
if err != nil { if err != nil {
if c.Force && len(c.InputArgs) > 0 { if errors.Cause(err) == libpod.ErrNoSuchCtr {
if errors.Cause(err) == libpod.ErrNoSuchCtr { if len(c.InputArgs) > 1 {
err = nil exitCode = 125
} else { } else {
failureCnt++
}
runtime.RemoveContainersFromStorage(c.InputArgs)
}
if len(delContainers) == 0 {
if err != nil && failureCnt == 0 {
exitCode = 1 exitCode = 1
} }
return err
}
if err != nil {
if errors.Cause(err) == libpod.ErrNoSuchCtr {
exitCode = 1
}
fmt.Println(err.Error())
} }
return err
} }
for _, container := range delContainers { if len(failures) > 0 {
con := container
f := func() error {
return runtime.RemoveContainer(ctx, con, c.Force, c.Volumes)
}
deleteFuncs = append(deleteFuncs, shared.ParallelWorkerInput{
ContainerID: con.ID(),
ParallelFunc: f,
})
}
maxWorkers := shared.Parallelize("rm")
if c.GlobalIsSet("max-workers") {
maxWorkers = c.GlobalFlags.MaxWorks
}
logrus.Debugf("Setting maximum workers to %d", maxWorkers)
// Run the parallel funcs
deleteErrors, errCount := shared.ParallelExecuteWorkerPool(maxWorkers, deleteFuncs)
err = printParallelOutput(deleteErrors, errCount)
if err != nil {
for _, result := range deleteErrors {
if result != nil && errors.Cause(result) != image.ErrNoSuchCtr {
failureCnt++
}
}
if failureCnt == 0 {
exitCode = 1
}
}
if failureCnt > 0 {
exitCode = 125 exitCode = 125
} }
return err return printCmdResults(ok, failures)
} }

View File

@ -0,0 +1,133 @@
package shared
import (
"reflect"
"runtime"
"strings"
"sync"
"github.com/sirupsen/logrus"
)
// JobFunc provides the function signature for the pool'ed functions
type JobFunc func() error
// Job defines the function to run
type Job struct {
ID string
Fn JobFunc
}
// JobResult defines the results from the function ran
type JobResult struct {
Job Job
Err error
}
// Pool defines the worker pool and queues
type Pool struct {
id string
wg *sync.WaitGroup
jobs chan Job
results chan JobResult
size int
capacity int
}
// NewPool creates and initializes a new Pool
func NewPool(id string, size int, capacity int) *Pool {
var wg sync.WaitGroup
// min for int...
s := size
if s > capacity {
s = capacity
}
return &Pool{
id,
&wg,
make(chan Job, capacity),
make(chan JobResult, capacity),
s,
capacity,
}
}
// Add Job to pool for parallel processing
func (p *Pool) Add(job Job) {
p.wg.Add(1)
p.jobs <- job
}
// Run the Job's in the pool, gather and return results
func (p *Pool) Run() ([]string, map[string]error, error) {
var (
ok = []string{}
failures = map[string]error{}
)
for w := 0; w < p.size; w++ {
w := w
go p.newWorker(w)
}
close(p.jobs)
p.wg.Wait()
close(p.results)
for r := range p.results {
if r.Err == nil {
ok = append(ok, r.Job.ID)
} else {
failures[r.Job.ID] = r.Err
}
}
if logrus.GetLevel() == logrus.DebugLevel {
for i, f := range failures {
logrus.Debugf("Pool[%s, %s: %s]", p.id, i, f.Error())
}
}
return ok, failures, nil
}
// newWorker creates new parallel workers to monitor jobs channel from Pool
func (p *Pool) newWorker(slot int) {
for job := range p.jobs {
err := job.Fn()
p.results <- JobResult{job, err}
if logrus.GetLevel() == logrus.DebugLevel {
n := strings.Split(runtime.FuncForPC(reflect.ValueOf(job.Fn).Pointer()).Name(), ".")
logrus.Debugf("Worker#%d finished job %s/%s (%v)", slot, n[2:], job.ID, err)
}
p.wg.Done()
}
}
// DefaultPoolSize provides the maximum number of parallel workers (int) as calculated by a basic
// heuristic. This can be overriden by the --max-workers primary switch to podman.
func DefaultPoolSize(name string) int {
numCpus := runtime.NumCPU()
switch name {
case "kill":
case "pause":
case "rm":
case "unpause":
if numCpus <= 3 {
return numCpus * 3
}
return numCpus * 4
case "ps":
return 8
case "restart":
return numCpus * 2
case "stop":
if numCpus <= 2 {
return 4
} else {
return numCpus * 3
}
}
return 3
}

View File

@ -1,9 +1,6 @@
package main package main
import ( import (
"fmt"
"reflect"
"github.com/containers/libpod/cmd/podman/cliconfig" "github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/libpod" "github.com/containers/libpod/libpod"
"github.com/containers/libpod/pkg/adapter" "github.com/containers/libpod/pkg/adapter"
@ -68,21 +65,5 @@ func stopCmd(c *cliconfig.StopValues) error {
if err != nil { if err != nil {
return err return err
} }
return printCmdResults(ok, failures)
for _, id := range ok {
fmt.Println(id)
}
if len(failures) > 0 {
keys := reflect.ValueOf(failures).MapKeys()
lastKey := keys[len(keys)-1].String()
lastErr := failures[lastKey]
delete(failures, lastKey)
for _, err := range failures {
outputError(err)
}
return lastErr
}
return nil
} }

View File

@ -1,20 +1,16 @@
package main package main
import ( import (
"fmt"
"github.com/containers/libpod/cmd/podman/cliconfig" "github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/cmd/podman/libpodruntime" "github.com/containers/libpod/pkg/adapter"
"github.com/containers/libpod/libpod"
"github.com/containers/storage"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
var ( var (
umountCommand cliconfig.UmountValues umountCommand cliconfig.UmountValues
description = `Container storage increments a mount counter each time a container is mounted.
description = `Container storage increments a mount counter each time a container is mounted.
When a container is unmounted, the mount counter is decremented. The container's root filesystem is physically unmounted only when the mount counter reaches zero indicating no other processes are using the mount. When a container is unmounted, the mount counter is decremented. The container's root filesystem is physically unmounted only when the mount counter reaches zero indicating no other processes are using the mount.
@ -51,42 +47,15 @@ func init() {
} }
func umountCmd(c *cliconfig.UmountValues) error { func umountCmd(c *cliconfig.UmountValues) error {
runtime, err := libpodruntime.GetRuntime(&c.PodmanCommand) runtime, err := adapter.GetRuntime(&c.PodmanCommand)
if err != nil { if err != nil {
return errors.Wrapf(err, "could not get runtime") return errors.Wrapf(err, "error creating runtime")
} }
defer runtime.Shutdown(false) defer runtime.Shutdown(false)
force := c.Force ok, failures, err := runtime.UmountRootFilesystems(getContext(), c)
umountAll := c.All
containers, err := getAllOrLatestContainers(&c.PodmanCommand, runtime, -1, "all")
if err != nil { if err != nil {
if len(containers) == 0 { return err
return err
}
fmt.Println(err.Error())
} }
return printCmdResults(ok, failures)
umountContainerErrStr := "error unmounting container"
var lastError error
for _, ctr := range containers {
ctrState, err := ctr.State()
if ctrState == libpod.ContainerStateRunning || err != nil {
continue
}
if err = ctr.Unmount(force); err != nil {
if umountAll && errors.Cause(err) == storage.ErrLayerNotMounted {
continue
}
if lastError != nil {
logrus.Error(lastError)
}
lastError = errors.Wrapf(err, "%s %s", umountContainerErrStr, ctr.ID())
continue
}
fmt.Printf("%s\n", ctr.ID())
}
return lastError
} }

View File

@ -2,11 +2,12 @@ package main
import ( import (
"fmt" "fmt"
"reflect"
"github.com/spf13/pflag" "github.com/spf13/pflag"
) )
//printParallelOutput takes the map of parallel worker results and outputs them // printParallelOutput takes the map of parallel worker results and outputs them
// to stdout // to stdout
func printParallelOutput(m map[string]error, errCount int) error { func printParallelOutput(m map[string]error, errCount int) error {
var lastError error var lastError error
@ -23,6 +24,26 @@ func printParallelOutput(m map[string]error, errCount int) error {
return lastError return lastError
} }
// print results from CLI command
func printCmdResults(ok []string, failures map[string]error) error {
for _, id := range ok {
fmt.Println(id)
}
if len(failures) > 0 {
keys := reflect.ValueOf(failures).MapKeys()
lastKey := keys[len(keys)-1].String()
lastErr := failures[lastKey]
delete(failures, lastKey)
for _, err := range failures {
outputError(err)
}
return lastErr
}
return nil
}
// markFlagHiddenForRemoteClient makes the flag not appear as part of the CLI // markFlagHiddenForRemoteClient makes the flag not appear as part of the CLI
// on the remote-client // on the remote-client
func markFlagHiddenForRemoteClient(flagName string, flags *pflag.FlagSet) { func markFlagHiddenForRemoteClient(flagName string, flags *pflag.FlagSet) {
@ -30,3 +51,29 @@ func markFlagHiddenForRemoteClient(flagName string, flags *pflag.FlagSet) {
flags.MarkHidden(flagName) flags.MarkHidden(flagName)
} }
} }
// TODO: remove when adapter package takes over this functionality
// func joinContainerOrCreateRootlessUserNS(runtime *libpod.Runtime, ctr *libpod.Container) (bool, int, error) {
// if os.Geteuid() == 0 {
// return false, 0, nil
// }
// s, err := ctr.State()
// if err != nil {
// return false, -1, err
// }
// opts := rootless.Opts{
// Argument: ctr.ID(),
// }
// if s == libpod.ContainerStateRunning || s == libpod.ContainerStatePaused {
// data, err := ioutil.ReadFile(ctr.Config().ConmonPidFile)
// if err != nil {
// return false, -1, errors.Wrapf(err, "cannot read conmon PID file %q", ctr.Config().ConmonPidFile)
// }
// conmonPid, err := strconv.Atoi(string(data))
// if err != nil {
// return false, -1, errors.Wrapf(err, "cannot parse PID %q", data)
// }
// return rootless.JoinDirectUserAndMountNSWithOpts(uint(conmonPid), &opts)
// }
// return rootless.BecomeRootInUserNSWithOpts(&opts)
// }

View File

@ -1,8 +1,6 @@
package main package main
import ( import (
"fmt"
"reflect"
"time" "time"
"github.com/containers/libpod/cmd/podman/cliconfig" "github.com/containers/libpod/cmd/podman/cliconfig"
@ -62,21 +60,5 @@ func waitCmd(c *cliconfig.WaitValues) error {
if err != nil { if err != nil {
return err return err
} }
return printCmdResults(ok, failures)
for _, id := range ok {
fmt.Println(id)
}
if len(failures) > 0 {
keys := reflect.ValueOf(failures).MapKeys()
lastKey := keys[len(keys)-1].String()
lastErr := failures[lastKey]
delete(failures, lastKey)
for _, err := range failures {
outputError(err)
}
return lastErr
}
return nil
} }

View File

@ -15,7 +15,7 @@ import (
"github.com/containers/libpod/pkg/lookup" "github.com/containers/libpod/pkg/lookup"
"github.com/containers/storage/pkg/stringid" "github.com/containers/storage/pkg/stringid"
"github.com/docker/docker/oci/caps" "github.com/docker/docker/oci/caps"
opentracing "github.com/opentracing/opentracing-go" "github.com/opentracing/opentracing-go"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"k8s.io/apimachinery/pkg/util/wait" "k8s.io/apimachinery/pkg/util/wait"
@ -174,7 +174,7 @@ func (c *Container) StopWithTimeout(timeout uint) error {
if c.state.State == ContainerStateConfigured || if c.state.State == ContainerStateConfigured ||
c.state.State == ContainerStateUnknown || c.state.State == ContainerStateUnknown ||
c.state.State == ContainerStatePaused { c.state.State == ContainerStatePaused {
return errors.Wrapf(ErrCtrStateInvalid, "can only stop created, running, or stopped containers") return errors.Wrapf(ErrCtrStateInvalid, "can only stop created, running, or stopped containers. %s in state %s", c.ID(), c.state.State.String())
} }
if c.state.State == ContainerStateStopped || if c.state.State == ContainerStateStopped ||

View File

@ -948,7 +948,7 @@ func (c *Container) start() error {
// Internal, non-locking function to stop container // Internal, non-locking function to stop container
func (c *Container) stop(timeout uint) error { func (c *Container) stop(timeout uint) error {
logrus.Debugf("Stopping ctr %s with timeout %d", c.ID(), timeout) logrus.Debugf("Stopping ctr %s (timeout %d)", c.ID(), timeout)
if err := c.runtime.ociRuntime.stopContainer(c, timeout); err != nil { if err := c.runtime.ociRuntime.stopContainer(c, timeout); err != nil {
return err return err
@ -1064,14 +1064,16 @@ func (c *Container) mountStorage() (string, error) {
func (c *Container) cleanupStorage() error { func (c *Container) cleanupStorage() error {
if !c.state.Mounted { if !c.state.Mounted {
// Already unmounted, do nothing // Already unmounted, do nothing
logrus.Debugf("Storage is already unmounted, skipping...") logrus.Debugf("Container %s storage is already unmounted, skipping...", c.ID())
return nil return nil
} }
for _, mount := range c.config.Mounts { for _, mount := range c.config.Mounts {
if err := c.unmountSHM(mount); err != nil { if err := c.unmountSHM(mount); err != nil {
return err return err
} }
} }
if c.config.Rootfs != "" { if c.config.Rootfs != "" {
return nil return nil
} }

View File

@ -30,7 +30,7 @@ import (
spec "github.com/opencontainers/runtime-spec/specs-go" spec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/opencontainers/runtime-tools/generate" "github.com/opencontainers/runtime-tools/generate"
"github.com/opencontainers/selinux/go-selinux/label" "github.com/opencontainers/selinux/go-selinux/label"
opentracing "github.com/opentracing/opentracing-go" "github.com/opentracing/opentracing-go"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
@ -48,6 +48,8 @@ func (c *Container) unmountSHM(mount string) error {
if err := unix.Unmount(mount, unix.MNT_DETACH); err != nil { if err := unix.Unmount(mount, unix.MNT_DETACH); err != nil {
if err != syscall.EINVAL { if err != syscall.EINVAL {
logrus.Warnf("container %s failed to unmount %s : %v", c.ID(), mount, err) logrus.Warnf("container %s failed to unmount %s : %v", c.ID(), mount, err)
} else {
logrus.Debugf("container %s failed to unmount %s : %v", c.ID(), mount, err)
} }
} }
return nil return nil

View File

@ -143,6 +143,7 @@ func waitContainerStop(ctr *Container, timeout time.Duration) error {
return nil return nil
case <-time.After(timeout): case <-time.After(timeout):
close(chControl) close(chControl)
logrus.Debugf("container %s did not die within timeout %d", ctr.ID(), timeout)
return errors.Errorf("container %s did not die within timeout", ctr.ID()) return errors.Errorf("container %s did not die within timeout", ctr.ID())
} }
} }

View File

@ -18,6 +18,7 @@ import (
"github.com/containers/libpod/cmd/podman/shared" "github.com/containers/libpod/cmd/podman/shared"
"github.com/containers/libpod/libpod" "github.com/containers/libpod/libpod"
"github.com/containers/libpod/pkg/adapter/shortcuts" "github.com/containers/libpod/pkg/adapter/shortcuts"
"github.com/containers/storage"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
@ -62,37 +63,115 @@ func (r *LocalRuntime) StopContainers(ctx context.Context, cli *cliconfig.StopVa
timeout = &t timeout = &t
} }
var ( maxWorkers := shared.DefaultPoolSize("stop")
ok = []string{} if cli.GlobalIsSet("max-workers") {
failures = map[string]error{} maxWorkers = cli.GlobalFlags.MaxWorks
) }
logrus.Debugf("Setting maximum stop workers to %d", maxWorkers)
ctrs, err := shortcuts.GetContainersByContext(cli.All, cli.Latest, cli.InputArgs, r.Runtime) ctrs, err := shortcuts.GetContainersByContext(cli.All, cli.Latest, cli.InputArgs, r.Runtime)
if err != nil { if err != nil {
return ok, failures, err return nil, nil, err
} }
pool := shared.NewPool("stop", maxWorkers, len(ctrs))
for _, c := range ctrs { for _, c := range ctrs {
c := c
if timeout == nil { if timeout == nil {
t := c.StopTimeout() t := c.StopTimeout()
timeout = &t timeout = &t
logrus.Debugf("Set timeout to container %s default (%d)", c.ID(), *timeout) logrus.Debugf("Set timeout to container %s default (%d)", c.ID(), *timeout)
} }
if err := c.StopWithTimeout(*timeout); err == nil {
ok = append(ok, c.ID()) pool.Add(shared.Job{
} else if errors.Cause(err) == libpod.ErrCtrStopped { c.ID(),
ok = append(ok, c.ID()) func() error {
logrus.Debugf("Container %s is already stopped", c.ID()) err := c.StopWithTimeout(*timeout)
} else { if err != nil {
failures[c.ID()] = err if errors.Cause(err) == libpod.ErrCtrStopped {
} logrus.Debugf("Container %s is already stopped", c.ID())
return nil
}
logrus.Debugf("Failed to stop container %s: %s", c.ID(), err.Error())
}
return err
},
})
} }
return ok, failures, nil return pool.Run()
} }
// KillContainers sends signal to container(s) based on CLI inputs. // KillContainers sends signal to container(s) based on CLI inputs.
// Returns list of successful id(s), map of failed id(s) + error, or error not from container // Returns list of successful id(s), map of failed id(s) + error, or error not from container
func (r *LocalRuntime) KillContainers(ctx context.Context, cli *cliconfig.KillValues, signal syscall.Signal) ([]string, map[string]error, error) { func (r *LocalRuntime) KillContainers(ctx context.Context, cli *cliconfig.KillValues, signal syscall.Signal) ([]string, map[string]error, error) {
maxWorkers := shared.DefaultPoolSize("kill")
if cli.GlobalIsSet("max-workers") {
maxWorkers = cli.GlobalFlags.MaxWorks
}
logrus.Debugf("Setting maximum kill workers to %d", maxWorkers)
ctrs, err := shortcuts.GetContainersByContext(cli.All, cli.Latest, cli.InputArgs, r.Runtime)
if err != nil {
return nil, nil, err
}
pool := shared.NewPool("kill", maxWorkers, len(ctrs))
for _, c := range ctrs {
c := c
pool.Add(shared.Job{
c.ID(),
func() error {
return c.Kill(uint(signal))
},
})
}
return pool.Run()
}
// RemoveContainers removes container(s) based on CLI inputs.
func (r *LocalRuntime) RemoveContainers(ctx context.Context, cli *cliconfig.RmValues) ([]string, map[string]error, error) {
var (
ok = []string{}
failures = map[string]error{}
)
maxWorkers := shared.DefaultPoolSize("rm")
if cli.GlobalIsSet("max-workers") {
maxWorkers = cli.GlobalFlags.MaxWorks
}
logrus.Debugf("Setting maximum rm workers to %d", maxWorkers)
ctrs, err := shortcuts.GetContainersByContext(cli.All, cli.Latest, cli.InputArgs, r.Runtime)
if err != nil {
// Force may be used to remove containers no longer found in the database
if cli.Force && len(cli.InputArgs) > 0 && errors.Cause(err) == libpod.ErrNoSuchCtr {
r.RemoveContainersFromStorage(cli.InputArgs)
}
return ok, failures, err
}
pool := shared.NewPool("rm", maxWorkers, len(ctrs))
for _, c := range ctrs {
c := c
pool.Add(shared.Job{
c.ID(),
func() error {
err := r.RemoveContainer(ctx, c, cli.Force, cli.Volumes)
if err != nil {
logrus.Debugf("Failed to remove container %s: %s", c.ID(), err.Error())
}
return err
},
})
}
return pool.Run()
}
// UmountRootFilesystems removes container(s) based on CLI inputs.
func (r *LocalRuntime) UmountRootFilesystems(ctx context.Context, cli *cliconfig.UmountValues) ([]string, map[string]error, error) {
var ( var (
ok = []string{} ok = []string{}
failures = map[string]error{} failures = map[string]error{}
@ -103,11 +182,25 @@ func (r *LocalRuntime) KillContainers(ctx context.Context, cli *cliconfig.KillVa
return ok, failures, err return ok, failures, err
} }
for _, c := range ctrs { for _, ctr := range ctrs {
if err := c.Kill(uint(signal)); err == nil { state, err := ctr.State()
ok = append(ok, c.ID()) if err != nil {
logrus.Debugf("Error umounting container %s state: %s", ctr.ID(), err.Error())
continue
}
if state == libpod.ContainerStateRunning {
logrus.Debugf("Error umounting container %s, is running", ctr.ID())
continue
}
if err := ctr.Unmount(cli.Force); err != nil {
if cli.All && errors.Cause(err) == storage.ErrLayerNotMounted {
logrus.Debugf("Error umounting container %s, storage.ErrLayerNotMounted", ctr.ID())
continue
}
failures[ctr.ID()] = errors.Wrapf(err, "error unmounting continaner %s", ctr.ID())
} else { } else {
failures[c.ID()] = err ok = append(ok, ctr.ID())
} }
} }
return ok, failures, nil return ok, failures, nil

View File

@ -12,11 +12,12 @@ import (
"github.com/containers/libpod/cmd/podman/cliconfig" "github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/cmd/podman/shared" "github.com/containers/libpod/cmd/podman/shared"
"github.com/containers/libpod/cmd/podman/varlink"
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/pkg/inspect"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
iopodman "github.com/containers/libpod/cmd/podman/varlink"
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/pkg/inspect"
"github.com/varlink/go/varlink" "github.com/varlink/go/varlink"
) )
@ -128,7 +129,7 @@ func (c *Container) Name() string {
return c.config.Name return c.config.Name
} }
// StopContainers stops requested containers using CLI inputs. // StopContainers stops requested containers using varlink.
// Returns the list of stopped container ids, map of failed to stop container ids + errors, or any non-container error // Returns the list of stopped container ids, map of failed to stop container ids + errors, or any non-container error
func (r *LocalRuntime) StopContainers(ctx context.Context, cli *cliconfig.StopValues) ([]string, map[string]error, error) { func (r *LocalRuntime) StopContainers(ctx context.Context, cli *cliconfig.StopValues) ([]string, map[string]error, error) {
var ( var (
@ -152,7 +153,7 @@ func (r *LocalRuntime) StopContainers(ctx context.Context, cli *cliconfig.StopVa
return ok, failures, nil return ok, failures, nil
} }
// KillContainers sends signal to container(s) based on CLI inputs. // KillContainers sends signal to container(s) based on varlink.
// Returns list of successful id(s), map of failed id(s) + error, or error not from container // Returns list of successful id(s), map of failed id(s) + error, or error not from container
func (r *LocalRuntime) KillContainers(ctx context.Context, cli *cliconfig.KillValues, signal syscall.Signal) ([]string, map[string]error, error) { func (r *LocalRuntime) KillContainers(ctx context.Context, cli *cliconfig.KillValues, signal syscall.Signal) ([]string, map[string]error, error) {
var ( var (
@ -176,6 +177,52 @@ func (r *LocalRuntime) KillContainers(ctx context.Context, cli *cliconfig.KillVa
return ok, failures, nil return ok, failures, nil
} }
// RemoveContainer removes container(s) based on varlink inputs.
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)
if err != nil {
return nil, nil, err
}
var (
ok = []string{}
failures = map[string]error{}
)
for _, id := range ids {
_, err := iopodman.RemoveContainer().Call(r.Conn, id, cli.Force, cli.Volumes)
if err != nil {
failures[id] = err
} else {
ok = append(ok, id)
}
}
return ok, failures, nil
}
// UmountRootFilesystems umounts container(s) root filesystems based on varlink inputs
func (r *LocalRuntime) UmountRootFilesystems(ctx context.Context, cli *cliconfig.UmountValues) ([]string, map[string]error, error) {
ids, err := iopodman.GetContainersByContext().Call(r.Conn, cli.All, cli.Latest, cli.InputArgs)
if err != nil {
return nil, nil, err
}
var (
ok = []string{}
failures = map[string]error{}
)
for _, id := range ids {
err := iopodman.UnmountContainer().Call(r.Conn, id, cli.Force)
if err != nil {
failures[id] = err
} else {
ok = append(ok, id)
}
}
return ok, failures, nil
}
// WaitOnContainers waits for all given container(s) to stop. // WaitOnContainers waits for all given container(s) to stop.
// interval is currently ignored. // interval is currently ignored.
func (r *LocalRuntime) WaitOnContainers(ctx context.Context, cli *cliconfig.WaitValues, interval time.Duration) ([]string, map[string]error, error) { func (r *LocalRuntime) WaitOnContainers(ctx context.Context, cli *cliconfig.WaitValues, interval time.Duration) ([]string, map[string]error, error) {
@ -227,7 +274,7 @@ func BatchContainerOp(ctr *Container, opts shared.PsOptions) (shared.BatchContai
// Logs one or more containers over a varlink connection // Logs one or more containers over a varlink connection
func (r *LocalRuntime) Log(c *cliconfig.LogsValues, options *libpod.LogOptions) error { func (r *LocalRuntime) Log(c *cliconfig.LogsValues, options *libpod.LogOptions) error {
//GetContainersLogs // GetContainersLogs
reply, err := iopodman.GetContainersLogs().Send(r.Conn, uint64(varlink.More), c.InputArgs, c.Follow, c.Latest, options.Since.Format(time.RFC3339Nano), int64(c.Tail), c.Timestamps) reply, err := iopodman.GetContainersLogs().Send(r.Conn, uint64(varlink.More), c.InputArgs, c.Follow, c.Latest, options.Since.Format(time.RFC3339Nano), int64(c.Tail), c.Timestamps)
if err != nil { if err != nil {
return errors.Wrapf(err, "failed to get container logs") return errors.Wrapf(err, "failed to get container logs")

View File

@ -310,6 +310,46 @@ func (r *LocalRuntime) HealthCheck(c *cliconfig.HealthCheckValues) (libpod.Healt
return r.Runtime.HealthCheck(c.InputArgs[0]) return r.Runtime.HealthCheck(c.InputArgs[0])
} }
// JoinOrCreateRootlessPod joins the specified pod if it is running or it creates a new user namespace
// if the pod is stopped
// func (r *LocalRuntime) JoinOrCreateRootlessPod(pod *Pod) (bool, int, error) {
// if os.Geteuid() == 0 {
// return false, 0, nil
// }
// opts := rootless.Opts{
// Argument: pod.ID(),
// }
//
// inspect, err := pod.Inspect()
// if err != nil {
// return false, 0, err
// }
// for _, ctr := range inspect.Containers {
// prevCtr, err := r.LookupContainer(ctr.ID)
// if err != nil {
// return false, -1, err
// }
// s, err := prevCtr.State()
// if err != nil {
// return false, -1, err
// }
// if s != libpod.ContainerStateRunning && s != libpod.ContainerStatePaused {
// continue
// }
// data, err := ioutil.ReadFile(prevCtr.Config().ConmonPidFile)
// if err != nil {
// return false, -1, errors.Wrapf(err, "cannot read conmon PID file %q", prevCtr.Config().ConmonPidFile)
// }
// conmonPid, err := strconv.Atoi(string(data))
// if err != nil {
// return false, -1, errors.Wrapf(err, "cannot parse PID %q", data)
// }
// return rootless.JoinDirectUserAndMountNSWithOpts(uint(conmonPid), &opts)
// }
//
// return rootless.BecomeRootInUserNSWithOpts(&opts)
// }
// Events is a wrapper to libpod to obtain libpod/podman events // Events is a wrapper to libpod to obtain libpod/podman events
func (r *LocalRuntime) Events(c *cliconfig.EventValues) error { func (r *LocalRuntime) Events(c *cliconfig.EventValues) error {
var ( var (
@ -363,3 +403,28 @@ func (r *LocalRuntime) Events(c *cliconfig.EventValues) error {
func (r *LocalRuntime) Diff(c *cliconfig.DiffValues, to string) ([]archive.Change, error) { func (r *LocalRuntime) Diff(c *cliconfig.DiffValues, to string) ([]archive.Change, error) {
return r.Runtime.GetDiff("", to) return r.Runtime.GetDiff("", to)
} }
// func (r *LocalRuntime) joinContainerOrCreateRootlessUserNS(ctr *libpod.Container) (bool, int, error) {
// if os.Geteuid() == 0 {
// return false, 0, nil
// }
// s, err := ctr.State()
// if err != nil {
// return false, -1, err
// }
// opts := rootless.Opts{
// Argument: ctr.ID(),
// }
// if s == libpod.ContainerStateRunning || s == libpod.ContainerStatePaused {
// data, err := ioutil.ReadFile(ctr.Config().ConmonPidFile)
// if err != nil {
// return false, -1, errors.Wrapf(err, "Container %s cannot read conmon PID file %q", ctr.ID(), ctr.Config().ConmonPidFile)
// }
// conmonPid, err := strconv.Atoi(string(data))
// if err != nil {
// return false, -1, errors.Wrapf(err, "Container %s cannot parse PID %q", ctr.ID(), data)
// }
// return rootless.JoinDirectUserAndMountNSWithOpts(uint(conmonPid), &opts)
// }
// return rootless.BecomeRootInUserNSWithOpts(&opts)
// }

View File

@ -1,6 +1,8 @@
package shortcuts package shortcuts
import "github.com/containers/libpod/libpod" import (
"github.com/containers/libpod/libpod"
)
// GetPodsByContext gets pods whether all, latest, or a slice of names/ids // GetPodsByContext gets pods whether all, latest, or a slice of names/ids
func GetPodsByContext(all, latest bool, pods []string, runtime *libpod.Runtime) ([]*libpod.Pod, error) { func GetPodsByContext(all, latest bool, pods []string, runtime *libpod.Runtime) ([]*libpod.Pod, error) {
@ -27,28 +29,23 @@ func GetPodsByContext(all, latest bool, pods []string, runtime *libpod.Runtime)
} }
// GetContainersByContext gets pods whether all, latest, or a slice of names/ids // GetContainersByContext gets pods whether all, latest, or a slice of names/ids
func GetContainersByContext(all, latest bool, names []string, runtime *libpod.Runtime) ([]*libpod.Container, error) { func GetContainersByContext(all, latest bool, names []string, runtime *libpod.Runtime) (ctrs []*libpod.Container, err error) {
var ctrs = []*libpod.Container{} var ctr *libpod.Container
ctrs = []*libpod.Container{}
if all { if all {
return runtime.GetAllContainers() ctrs, err = runtime.GetAllContainers()
} } else if latest {
ctr, err = runtime.GetLatestContainer()
if latest {
c, err := runtime.GetLatestContainer()
if err != nil {
return nil, err
}
ctrs = append(ctrs, c)
return ctrs, nil
}
for _, c := range names {
ctr, err := runtime.LookupContainer(c)
if err != nil {
return nil, err
}
ctrs = append(ctrs, ctr) ctrs = append(ctrs, ctr)
} else {
for _, n := range names {
ctr, e := runtime.LookupContainer(n)
if e != nil && err == nil {
err = e
}
ctrs = append(ctrs, ctr)
}
} }
return ctrs, nil return
} }

View File

@ -3,7 +3,6 @@ package integration
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"github.com/containers/libpod/pkg/rootless"
"io/ioutil" "io/ioutil"
"os" "os"
"os/exec" "os/exec"
@ -12,6 +11,7 @@ import (
"strings" "strings"
"testing" "testing"
"github.com/containers/libpod/pkg/rootless"
"github.com/containers/storage" "github.com/containers/storage"
"github.com/containers/libpod/pkg/inspect" "github.com/containers/libpod/pkg/inspect"
@ -86,7 +86,7 @@ func TestLibpod(t *testing.T) {
} }
var _ = SynchronizedBeforeSuite(func() []byte { var _ = SynchronizedBeforeSuite(func() []byte {
//Cache images // Cache images
cwd, _ := os.Getwd() cwd, _ := os.Getwd()
INTEGRATION_ROOT = filepath.Join(cwd, "../../") INTEGRATION_ROOT = filepath.Join(cwd, "../../")
podman := PodmanTestCreate("/tmp") podman := PodmanTestCreate("/tmp")
@ -134,18 +134,18 @@ func (p *PodmanTestIntegration) Setup() {
p.ArtifactPath = ARTIFACT_DIR p.ArtifactPath = ARTIFACT_DIR
} }
//var _ = BeforeSuite(func() { // var _ = BeforeSuite(func() {
// cwd, _ := os.Getwd() // cwd, _ := os.Getwd()
// INTEGRATION_ROOT = filepath.Join(cwd, "../../") // INTEGRATION_ROOT = filepath.Join(cwd, "../../")
// podman := PodmanTestCreate("/tmp") // podman := PodmanTestCreate("/tmp")
// podman.ArtifactPath = ARTIFACT_DIR // podman.ArtifactPath = ARTIFACT_DIR
// if _, err := os.Stat(ARTIFACT_DIR); os.IsNotExist(err) { // if _, err := os.Stat(ARTIFACT_DIR); os.IsNotExist(err) {
// if err = os.Mkdir(ARTIFACT_DIR, 0777); err != nil { // if err = os.Mkdir(ARTIFACT_DIR, 0777); err != nil {
// fmt.Printf("%q\n", err) // fmt.Printf("%q\n", err)
// os.Exit(1) // os.Exit(1)
// } // }
// } // }
//}) // })
// for _, image := range CACHE_IMAGES { // for _, image := range CACHE_IMAGES {
// if err := podman.CreateArtifact(image); err != nil { // if err := podman.CreateArtifact(image); err != nil {
// fmt.Printf("%q\n", err) // fmt.Printf("%q\n", err)
@ -172,7 +172,7 @@ func (p *PodmanTestIntegration) Setup() {
// os.Exit(1) // os.Exit(1)
// } // }
// LockTmpDir = path // LockTmpDir = path
//}) // })
var _ = AfterSuite(func() { var _ = AfterSuite(func() {
sort.Sort(testResultsSortedLength{testResults}) sort.Sort(testResultsSortedLength{testResults})

View File

@ -61,9 +61,12 @@ func (p *PodmanTestIntegration) PodmanPID(args []string) (*PodmanSessionIntegrat
func (p *PodmanTestIntegration) Cleanup() { func (p *PodmanTestIntegration) Cleanup() {
// Remove all containers // Remove all containers
stopall := p.Podman([]string{"stop", "-a", "--timeout", "0"}) stopall := p.Podman([]string{"stop", "-a", "--timeout", "0"})
stopall.WaitWithDefaultTimeout() // stopall.WaitWithDefaultTimeout()
stopall.Wait(90)
session := p.Podman([]string{"rm", "-fa"}) session := p.Podman([]string{"rm", "-fa"})
session.Wait(90) session.Wait(90)
// Nuke tempdir // Nuke tempdir
if err := os.RemoveAll(p.TempDir); err != nil { if err := os.RemoveAll(p.TempDir); err != nil {
fmt.Printf("%q\n", err) fmt.Printf("%q\n", err)
@ -141,7 +144,7 @@ func (p *PodmanTestIntegration) CreatePod(name string) (*PodmanSessionIntegratio
return session, session.ExitCode(), session.OutputToString() return session, session.ExitCode(), session.OutputToString()
} }
//RunTopContainer runs a simple container in the background that // RunTopContainer runs a simple container in the background that
// runs top. If the name passed != "", it will have a name // runs top. If the name passed != "", it will have a name
func (p *PodmanTestIntegration) RunTopContainer(name string) *PodmanSessionIntegration { func (p *PodmanTestIntegration) RunTopContainer(name string) *PodmanSessionIntegration {
var podmanArgs = []string{"run"} var podmanArgs = []string{"run"}
@ -161,7 +164,7 @@ func (p *PodmanTestIntegration) RunTopContainerInPod(name, pod string) *PodmanSe
return p.Podman(podmanArgs) return p.Podman(podmanArgs)
} }
//RunLsContainer runs a simple container in the background that // RunLsContainer runs a simple container in the background that
// simply runs ls. If the name passed != "", it will have a name // simply runs ls. If the name passed != "", it will have a name
func (p *PodmanTestIntegration) RunLsContainer(name string) (*PodmanSessionIntegration, int, string) { func (p *PodmanTestIntegration) RunLsContainer(name string) (*PodmanSessionIntegration, int, string) {
var podmanArgs = []string{"run"} var podmanArgs = []string{"run"}
@ -215,13 +218,19 @@ func PodmanTestCreate(tempDir string) *PodmanTestIntegration {
return PodmanTestCreateUtil(tempDir, false) return PodmanTestCreateUtil(tempDir, false)
} }
//MakeOptions assembles all the podman main options // MakeOptions assembles all the podman main options
func (p *PodmanTestIntegration) makeOptions(args []string) []string { func (p *PodmanTestIntegration) makeOptions(args []string) []string {
podmanOptions := strings.Split(fmt.Sprintf("--root %s --runroot %s --runtime %s --conmon %s --cni-config-dir %s --cgroup-manager %s --tmpdir %s", var debug string
p.CrioRoot, p.RunRoot, p.OCIRuntime, p.ConmonBinary, p.CNIConfigDir, p.CgroupManager, p.TmpDir), " ") if _, ok := os.LookupEnv("DEBUG"); ok {
debug = "--log-level=debug --syslog=true "
}
podmanOptions := strings.Split(fmt.Sprintf("%s--root %s --runroot %s --runtime %s --conmon %s --cni-config-dir %s --cgroup-manager %s --tmpdir %s",
debug, p.CrioRoot, p.RunRoot, p.OCIRuntime, p.ConmonBinary, p.CNIConfigDir, p.CgroupManager, p.TmpDir), " ")
if os.Getenv("HOOK_OPTION") != "" { if os.Getenv("HOOK_OPTION") != "" {
podmanOptions = append(podmanOptions, os.Getenv("HOOK_OPTION")) podmanOptions = append(podmanOptions, os.Getenv("HOOK_OPTION"))
} }
podmanOptions = append(podmanOptions, strings.Split(p.StorageOptions, " ")...) podmanOptions = append(podmanOptions, strings.Split(p.StorageOptions, " ")...)
podmanOptions = append(podmanOptions, args...) podmanOptions = append(podmanOptions, args...)
return podmanOptions return podmanOptions

View File

@ -3,47 +3,79 @@
package integration package integration
import ( import (
"bytes"
"fmt"
"io/ioutil"
"os" "os"
"strconv" "strconv"
"text/template"
. "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"
) )
type endpoint struct {
Host string
Port string
}
func (e *endpoint) Address() string {
return fmt.Sprintf("%s:%s", e.Host, e.Port)
}
var _ = Describe("Podman search", func() { var _ = Describe("Podman search", func() {
var ( var (
tempdir string tempdir string
err error err error
podmanTest *PodmanTestIntegration podmanTest *PodmanTestIntegration
) )
const regFileContents = `
[registries.search]
registries = ['localhost:5000']
[registries.insecure] var registryEndpoints = []endpoint{
registries = ['localhost:5000']` {"localhost", "5001"},
{"localhost", "5002"},
{"localhost", "5003"},
{"localhost", "5004"},
{"localhost", "5005"},
{"localhost", "5006"},
{"localhost", "5007"},
{"localhost", "5008"},
{"localhost", "5009"},
}
const regFileContents = `
[registries.search]
registries = ['{{.Host}}:{{.Port}}']
[registries.insecure]
registries = ['{{.Host}}:{{.Port}}']`
registryFileTmpl := template.Must(template.New("registryFile").Parse(regFileContents))
const badRegFileContents = ` const badRegFileContents = `
[registries.search] [registries.search]
registries = ['localhost:5000'] registries = ['{{.Host}}:{{.Port}}']
# empty # empty
[registries.insecure] [registries.insecure]
registries = []` registries = []`
registryFileBadTmpl := template.Must(template.New("registryFileBad").Parse(badRegFileContents))
const regFileContents2 = ` const regFileContents2 = `
[registries.search] [registries.search]
registries = ['localhost:5000', 'localhost:6000'] registries = ['{{.Host}}:{{.Port}}', '{{.Host}}:6000']
[registries.insecure]
registries = ['{{.Host}}:{{.Port}}']`
registryFileTwoTmpl := template.Must(template.New("registryFileTwo").Parse(regFileContents2))
[registries.insecure]
registries = ['localhost:5000']`
BeforeEach(func() { BeforeEach(func() {
tempdir, err = CreateTempDirInTempDir() tempdir, err = CreateTempDirInTempDir()
if err != nil { if err != nil {
os.Exit(1) os.Exit(1)
} }
podmanTest = PodmanTestCreate(tempdir) podmanTest = PodmanTestCreate(tempdir)
podmanTest.Setup() podmanTest.Setup()
podmanTest.RestoreAllArtifacts() podmanTest.RestoreAllArtifacts()
}) })
@ -51,7 +83,6 @@ var _ = Describe("Podman search", func() {
podmanTest.Cleanup() podmanTest.Cleanup()
f := CurrentGinkgoTestDescription() f := CurrentGinkgoTestDescription()
processTestResult(f) processTestResult(f)
}) })
It("podman search", func() { It("podman search", func() {
@ -134,11 +165,13 @@ var _ = Describe("Podman search", func() {
if podmanTest.Host.Arch == "ppc64le" { if podmanTest.Host.Arch == "ppc64le" {
Skip("No registry image for ppc64le") Skip("No registry image for ppc64le")
} }
lock := GetPortLock("5000") lock := GetPortLock(registryEndpoints[0].Port)
defer lock.Unlock() defer lock.Unlock()
podmanTest.RestoreArtifact(registry) podmanTest.RestoreArtifact(registry)
fakereg := podmanTest.Podman([]string{"run", "-d", "--name", "registry", "-p", "5000:5000", registry, "/entrypoint.sh", "/etc/docker/registry/config.yml"}) fakereg := podmanTest.Podman([]string{"run", "-d", "--name", "registry",
"-p", fmt.Sprintf("%s:5000", registryEndpoints[0].Port),
registry, "/entrypoint.sh", "/etc/docker/registry/config.yml"})
fakereg.WaitWithDefaultTimeout() fakereg.WaitWithDefaultTimeout()
Expect(fakereg.ExitCode()).To(Equal(0)) Expect(fakereg.ExitCode()).To(Equal(0))
@ -146,7 +179,8 @@ var _ = Describe("Podman search", func() {
Skip("Can not start docker registry.") Skip("Can not start docker registry.")
} }
search := podmanTest.Podman([]string{"search", "localhost:5000/fake/image:andtag", "--tls-verify=false"}) search := podmanTest.Podman([]string{"search",
fmt.Sprintf("%s/fake/image:andtag", registryEndpoints[0].Address()), "--tls-verify=false"})
search.WaitWithDefaultTimeout() search.WaitWithDefaultTimeout()
// if this test succeeded, there will be no output (there is no entry named fake/image:andtag in an empty registry) // if this test succeeded, there will be no output (there is no entry named fake/image:andtag in an empty registry)
@ -160,10 +194,12 @@ var _ = Describe("Podman search", func() {
if podmanTest.Host.Arch == "ppc64le" { if podmanTest.Host.Arch == "ppc64le" {
Skip("No registry image for ppc64le") Skip("No registry image for ppc64le")
} }
lock := GetPortLock("5000") lock := GetPortLock(registryEndpoints[3].Port)
defer lock.Unlock() defer lock.Unlock()
podmanTest.RestoreArtifact(registry) podmanTest.RestoreArtifact(registry)
registry := podmanTest.Podman([]string{"run", "-d", "--name", "registry3", "-p", "5000:5000", registry, "/entrypoint.sh", "/etc/docker/registry/config.yml"}) registry := podmanTest.Podman([]string{"run", "-d", "--name", "registry3",
"-p", fmt.Sprintf("%s:5000", registryEndpoints[3].Port), registry,
"/entrypoint.sh", "/etc/docker/registry/config.yml"})
registry.WaitWithDefaultTimeout() registry.WaitWithDefaultTimeout()
Expect(registry.ExitCode()).To(Equal(0)) Expect(registry.ExitCode()).To(Equal(0))
@ -171,10 +207,11 @@ var _ = Describe("Podman search", func() {
Skip("Can not start docker registry.") Skip("Can not start docker registry.")
} }
push := podmanTest.Podman([]string{"push", "--tls-verify=false", "--remove-signatures", ALPINE, "localhost:5000/my-alpine"}) image := fmt.Sprintf("%s/my-alpine", registryEndpoints[3].Address())
push := podmanTest.Podman([]string{"push", "--tls-verify=false", "--remove-signatures", ALPINE, image})
push.WaitWithDefaultTimeout() push.WaitWithDefaultTimeout()
Expect(push.ExitCode()).To(Equal(0)) Expect(push.ExitCode()).To(Equal(0))
search := podmanTest.Podman([]string{"search", "localhost:5000/my-alpine", "--tls-verify=false"}) search := podmanTest.Podman([]string{"search", image, "--tls-verify=false"})
search.WaitWithDefaultTimeout() search.WaitWithDefaultTimeout()
Expect(search.ExitCode()).To(Equal(0)) Expect(search.ExitCode()).To(Equal(0))
@ -185,10 +222,12 @@ var _ = Describe("Podman search", func() {
if podmanTest.Host.Arch == "ppc64le" { if podmanTest.Host.Arch == "ppc64le" {
Skip("No registry image for ppc64le") Skip("No registry image for ppc64le")
} }
lock := GetPortLock("5000")
lock := GetPortLock(registryEndpoints[4].Port)
defer lock.Unlock() defer lock.Unlock()
podmanTest.RestoreArtifact(registry) podmanTest.RestoreArtifact(registry)
registry := podmanTest.Podman([]string{"run", "-d", "--name", "registry4", "-p", "5000:5000", registry, "/entrypoint.sh", "/etc/docker/registry/config.yml"}) registry := podmanTest.Podman([]string{"run", "-d", "-p", fmt.Sprintf("%s:5000", registryEndpoints[4].Port),
"--name", "registry4", registry, "/entrypoint.sh", "/etc/docker/registry/config.yml"})
registry.WaitWithDefaultTimeout() registry.WaitWithDefaultTimeout()
Expect(registry.ExitCode()).To(Equal(0)) Expect(registry.ExitCode()).To(Equal(0))
@ -196,14 +235,18 @@ var _ = Describe("Podman search", func() {
Skip("Can not start docker registry.") Skip("Can not start docker registry.")
} }
push := podmanTest.Podman([]string{"push", "--tls-verify=false", "--remove-signatures", ALPINE, "localhost:5000/my-alpine"}) image := fmt.Sprintf("%s/my-alpine", registryEndpoints[4].Address())
push := podmanTest.Podman([]string{"push", "--tls-verify=false", "--remove-signatures", ALPINE, image})
push.WaitWithDefaultTimeout() push.WaitWithDefaultTimeout()
Expect(push.ExitCode()).To(Equal(0)) Expect(push.ExitCode()).To(Equal(0))
// registries.conf set up // registries.conf set up
podmanTest.setRegistriesConfigEnv([]byte(regFileContents)) var buffer bytes.Buffer
registryFileTmpl.Execute(&buffer, registryEndpoints[4])
podmanTest.setRegistriesConfigEnv(buffer.Bytes())
ioutil.WriteFile(fmt.Sprintf("%s/registry4.conf", tempdir), buffer.Bytes(), 0644)
search := podmanTest.Podman([]string{"search", "localhost:5000/my-alpine"}) search := podmanTest.Podman([]string{"search", image})
search.WaitWithDefaultTimeout() search.WaitWithDefaultTimeout()
Expect(search.ExitCode()).To(Equal(0)) Expect(search.ExitCode()).To(Equal(0))
@ -219,24 +262,29 @@ var _ = Describe("Podman search", func() {
if podmanTest.Host.Arch == "ppc64le" { if podmanTest.Host.Arch == "ppc64le" {
Skip("No registry image for ppc64le") Skip("No registry image for ppc64le")
} }
lock := GetPortLock("5000") lock := GetPortLock(registryEndpoints[5].Port)
defer lock.Unlock() defer lock.Unlock()
podmanTest.RestoreArtifact(registry) podmanTest.RestoreArtifact(registry)
registry := podmanTest.Podman([]string{"run", "-d", "-p", "5000:5000", "--name", "registry5", registry}) registry := podmanTest.Podman([]string{"run", "-d", "-p", fmt.Sprintf("%s:5000", registryEndpoints[5].Port),
"--name", "registry5", registry})
registry.WaitWithDefaultTimeout() registry.WaitWithDefaultTimeout()
Expect(registry.ExitCode()).To(Equal(0)) Expect(registry.ExitCode()).To(Equal(0))
if !WaitContainerReady(podmanTest, "registry5", "listening on", 20, 1) { if !WaitContainerReady(podmanTest, "registry5", "listening on", 20, 1) {
Skip("Can not start docker registry.") Skip("Can not start docker registry.")
} }
push := podmanTest.Podman([]string{"push", "--tls-verify=false", "--remove-signatures", ALPINE, "localhost:5000/my-alpine"})
image := fmt.Sprintf("%s/my-alpine", registryEndpoints[5].Address())
push := podmanTest.Podman([]string{"push", "--tls-verify=false", "--remove-signatures", ALPINE, image})
push.WaitWithDefaultTimeout() push.WaitWithDefaultTimeout()
Expect(push.ExitCode()).To(Equal(0)) Expect(push.ExitCode()).To(Equal(0))
// registries.conf set up var buffer bytes.Buffer
podmanTest.setRegistriesConfigEnv([]byte(regFileContents)) registryFileTmpl.Execute(&buffer, registryEndpoints[5])
podmanTest.setRegistriesConfigEnv(buffer.Bytes())
ioutil.WriteFile(fmt.Sprintf("%s/registry5.conf", tempdir), buffer.Bytes(), 0644)
search := podmanTest.Podman([]string{"search", "localhost:5000/my-alpine", "--tls-verify=true"}) search := podmanTest.Podman([]string{"search", image, "--tls-verify=true"})
search.WaitWithDefaultTimeout() search.WaitWithDefaultTimeout()
Expect(search.ExitCode()).To(Equal(0)) Expect(search.ExitCode()).To(Equal(0))
@ -252,24 +300,29 @@ var _ = Describe("Podman search", func() {
if podmanTest.Host.Arch == "ppc64le" { if podmanTest.Host.Arch == "ppc64le" {
Skip("No registry image for ppc64le") Skip("No registry image for ppc64le")
} }
lock := GetPortLock("5000") lock := GetPortLock(registryEndpoints[6].Port)
defer lock.Unlock() defer lock.Unlock()
podmanTest.RestoreArtifact(registry) podmanTest.RestoreArtifact(registry)
registry := podmanTest.Podman([]string{"run", "-d", "-p", "5000:5000", "--name", "registry6", registry}) registry := podmanTest.Podman([]string{"run", "-d", "-p", fmt.Sprintf("%s:5000", registryEndpoints[6].Port),
"--name", "registry6", registry})
registry.WaitWithDefaultTimeout() registry.WaitWithDefaultTimeout()
Expect(registry.ExitCode()).To(Equal(0)) Expect(registry.ExitCode()).To(Equal(0))
if !WaitContainerReady(podmanTest, "registry6", "listening on", 20, 1) { if !WaitContainerReady(podmanTest, "registry6", "listening on", 20, 1) {
Skip("Can not start docker registry.") Skip("Can not start docker registry.")
} }
push := podmanTest.Podman([]string{"push", "--tls-verify=false", "--remove-signatures", ALPINE, "localhost:5000/my-alpine"})
image := fmt.Sprintf("%s/my-alpine", registryEndpoints[6].Address())
push := podmanTest.Podman([]string{"push", "--tls-verify=false", "--remove-signatures", ALPINE, image})
push.WaitWithDefaultTimeout() push.WaitWithDefaultTimeout()
Expect(push.ExitCode()).To(Equal(0)) Expect(push.ExitCode()).To(Equal(0))
// registries.conf set up var buffer bytes.Buffer
podmanTest.setRegistriesConfigEnv([]byte(badRegFileContents)) registryFileBadTmpl.Execute(&buffer, registryEndpoints[6])
podmanTest.setRegistriesConfigEnv(buffer.Bytes())
ioutil.WriteFile(fmt.Sprintf("%s/registry6.conf", tempdir), buffer.Bytes(), 0644)
search := podmanTest.Podman([]string{"search", "localhost:5000/my-alpine"}) search := podmanTest.Podman([]string{"search", image})
search.WaitWithDefaultTimeout() search.WaitWithDefaultTimeout()
Expect(search.ExitCode()).To(Equal(0)) Expect(search.ExitCode()).To(Equal(0))
@ -285,10 +338,14 @@ var _ = Describe("Podman search", func() {
if podmanTest.Host.Arch == "ppc64le" { if podmanTest.Host.Arch == "ppc64le" {
Skip("No registry image for ppc64le") Skip("No registry image for ppc64le")
} }
lock := GetPortLock("5000") lock7 := GetPortLock(registryEndpoints[7].Port)
defer lock.Unlock() defer lock7.Unlock()
lock8 := GetPortLock("6000")
defer lock8.Unlock()
podmanTest.RestoreArtifact(registry) podmanTest.RestoreArtifact(registry)
registryLocal := podmanTest.Podman([]string{"run", "-d", "-p", "5000:5000", "--name", "registry7", registry}) registryLocal := podmanTest.Podman([]string{"run", "-d", "-p", fmt.Sprintf("%s:5000", registryEndpoints[7].Port),
"--name", "registry7", registry})
registryLocal.WaitWithDefaultTimeout() registryLocal.WaitWithDefaultTimeout()
Expect(registryLocal.ExitCode()).To(Equal(0)) Expect(registryLocal.ExitCode()).To(Equal(0))
@ -303,12 +360,16 @@ var _ = Describe("Podman search", func() {
if !WaitContainerReady(podmanTest, "registry8", "listening on", 20, 1) { if !WaitContainerReady(podmanTest, "registry8", "listening on", 20, 1) {
Skip("Can not start docker registry.") Skip("Can not start docker registry.")
} }
push := podmanTest.Podman([]string{"push", "--tls-verify=false", "--remove-signatures", ALPINE, "localhost:6000/my-alpine"}) push := podmanTest.Podman([]string{"push", "--tls-verify=false", "--remove-signatures", ALPINE, "localhost:6000/my-alpine"})
push.WaitWithDefaultTimeout() push.WaitWithDefaultTimeout()
Expect(push.ExitCode()).To(Equal(0)) Expect(push.ExitCode()).To(Equal(0))
// registries.conf set up // registries.conf set up
podmanTest.setRegistriesConfigEnv([]byte(regFileContents2)) var buffer bytes.Buffer
registryFileTwoTmpl.Execute(&buffer, registryEndpoints[8])
podmanTest.setRegistriesConfigEnv(buffer.Bytes())
ioutil.WriteFile(fmt.Sprintf("%s/registry8.conf", tempdir), buffer.Bytes(), 0644)
search := podmanTest.Podman([]string{"search", "my-alpine"}) search := podmanTest.Podman([]string{"search", "my-alpine"})
search.WaitWithDefaultTimeout() search.WaitWithDefaultTimeout()

View File

@ -311,6 +311,8 @@ func (s *PodmanSession) IsJSONOutputValid() bool {
// WaitWithDefaultTimeout waits for process finished with defaultWaitTimeout // WaitWithDefaultTimeout waits for process finished with defaultWaitTimeout
func (s *PodmanSession) WaitWithDefaultTimeout() { func (s *PodmanSession) WaitWithDefaultTimeout() {
s.Wait(defaultWaitTimeout) s.Wait(defaultWaitTimeout)
os.Stdout.Sync()
os.Stderr.Sync()
fmt.Println("output:", s.OutputToString()) fmt.Println("output:", s.OutputToString())
} }