diff options
137 files changed, 1629 insertions, 668 deletions
diff --git a/cmd/podman/cliconfig/create.go b/cmd/podman/cliconfig/create.go index 49ab3d827..5fb2eed10 100644 --- a/cmd/podman/cliconfig/create.go +++ b/cmd/podman/cliconfig/create.go @@ -24,4 +24,5 @@ type BuildValues struct { type CpValues struct { PodmanCommand Extract bool + Pause bool } diff --git a/cmd/podman/container.go b/cmd/podman/container.go index 530175a55..839ae3a0e 100644 --- a/cmd/podman/container.go +++ b/cmd/podman/container.go @@ -54,6 +54,7 @@ var ( _checkpointCommand, _containerExistsCommand, _contInspectSubCommand, + _cpCommand, _diffCommand, _exportCommand, _createCommand, diff --git a/cmd/podman/cp.go b/cmd/podman/cp.go index 8240cc193..907bde4b9 100644 --- a/cmd/podman/cp.go +++ b/cmd/podman/cp.go @@ -13,10 +13,12 @@ import ( "github.com/containers/libpod/cmd/podman/cliconfig" "github.com/containers/libpod/cmd/podman/libpodruntime" "github.com/containers/libpod/libpod" + "github.com/containers/libpod/pkg/rootless" "github.com/containers/storage" "github.com/containers/storage/pkg/archive" "github.com/containers/storage/pkg/chrootarchive" "github.com/containers/storage/pkg/idtools" + securejoin "github.com/cyphar/filepath-securejoin" digest "github.com/opencontainers/go-digest" specs "github.com/opencontainers/runtime-spec/specs-go" "github.com/pkg/errors" @@ -49,6 +51,7 @@ func init() { cpCommand.Command = _cpCommand flags := cpCommand.Flags() flags.BoolVar(&cpCommand.Extract, "extract", false, "Extract the tar file into the destination directory.") + flags.BoolVar(&cpCommand.Pause, "pause", true, "Pause the container while copying") cpCommand.SetHelpTemplate(HelpTemplate()) cpCommand.SetUsageTemplate(UsageTemplate()) rootCmd.AddCommand(cpCommand.Command) @@ -66,11 +69,10 @@ func cpCmd(c *cliconfig.CpValues) error { } defer runtime.Shutdown(false) - extract := c.Flag("extract").Changed - return copyBetweenHostAndContainer(runtime, args[0], args[1], extract) + return copyBetweenHostAndContainer(runtime, args[0], args[1], c.Extract, c.Pause) } -func copyBetweenHostAndContainer(runtime *libpod.Runtime, src string, dest string, extract bool) error { +func copyBetweenHostAndContainer(runtime *libpod.Runtime, src string, dest string, extract bool, pause bool) error { srcCtr, srcPath := parsePath(runtime, src) destCtr, destPath := parsePath(runtime, dest) @@ -93,6 +95,38 @@ func copyBetweenHostAndContainer(runtime *libpod.Runtime, src string, dest strin return err } defer ctr.Unmount(false) + + // We can't pause rootless containers. + if pause && rootless.IsRootless() { + state, err := ctr.State() + if err != nil { + return err + } + if state == libpod.ContainerStateRunning { + return errors.Errorf("cannot copy into running rootless container with pause set - pass --pause=false to force copying") + } + } + + if pause && !rootless.IsRootless() { + if err := ctr.Pause(); err != nil { + // An invalid state error is fine. + // The container isn't running or is already paused. + // TODO: We can potentially start the container while + // the copy is running, which still allows a race where + // malicious code could mess with the symlink. + if errors.Cause(err) != libpod.ErrCtrStateInvalid { + return err + } + } else if err == nil { + // Only add the defer if we actually paused + defer func() { + if err := ctr.Unpause(); err != nil { + logrus.Errorf("Error unpausing container after copying: %v", err) + } + }() + } + } + user, err := getUser(mountPoint, ctr.User()) if err != nil { return err @@ -112,19 +146,38 @@ func copyBetweenHostAndContainer(runtime *libpod.Runtime, src string, dest strin var glob []string if isFromHostToCtr { if filepath.IsAbs(destPath) { - destPath = filepath.Join(mountPoint, destPath) - + cleanedPath, err := securejoin.SecureJoin(mountPoint, destPath) + if err != nil { + return err + } + destPath = cleanedPath } else { - if err = idtools.MkdirAllAndChownNew(filepath.Join(mountPoint, ctr.WorkingDir()), 0755, hostOwner); err != nil { + ctrWorkDir, err := securejoin.SecureJoin(mountPoint, ctr.WorkingDir()) + if err != nil { + return err + } + if err = idtools.MkdirAllAndChownNew(ctrWorkDir, 0755, hostOwner); err != nil { return errors.Wrapf(err, "error creating directory %q", destPath) } - destPath = filepath.Join(mountPoint, ctr.WorkingDir(), destPath) + cleanedPath, err := securejoin.SecureJoin(mountPoint, filepath.Join(ctr.WorkingDir(), destPath)) + if err != nil { + return err + } + destPath = cleanedPath } } else { if filepath.IsAbs(srcPath) { - srcPath = filepath.Join(mountPoint, srcPath) + cleanedPath, err := securejoin.SecureJoin(mountPoint, srcPath) + if err != nil { + return err + } + srcPath = cleanedPath } else { - srcPath = filepath.Join(mountPoint, ctr.WorkingDir(), srcPath) + cleanedPath, err := securejoin.SecureJoin(mountPoint, filepath.Join(ctr.WorkingDir(), srcPath)) + if err != nil { + return err + } + srcPath = cleanedPath } } glob, err = filepath.Glob(srcPath) diff --git a/cmd/podman/main_local.go b/cmd/podman/main_local.go index 5af05a11e..b4f21bd0c 100644 --- a/cmd/podman/main_local.go +++ b/cmd/podman/main_local.go @@ -4,11 +4,9 @@ package main import ( "context" - "io/ioutil" "log/syslog" "os" "runtime/pprof" - "strconv" "strings" "syscall" @@ -120,18 +118,10 @@ func setupRootless(cmd *cobra.Command, args []string) error { return errors.Wrapf(err, "could not get pause process pid file path") } - data, err := ioutil.ReadFile(pausePidPath) - if err != nil && !os.IsNotExist(err) { - return errors.Wrapf(err, "cannot read pause process pid file %s", pausePidPath) - } - if err == nil { - pausePid, err := strconv.Atoi(string(data)) - if err != nil { - return errors.Wrapf(err, "cannot parse pause pid file %s", pausePidPath) - } - became, ret, err := rootless.JoinUserAndMountNS(uint(pausePid), "") + if _, err := os.Stat(pausePidPath); err == nil { + became, ret, err := rootless.TryJoinFromFilePaths("", false, []string{pausePidPath}) if err != nil { - logrus.Errorf("cannot join pause process pid %d. You may need to remove %s and stop all containers", pausePid, pausePidPath) + logrus.Errorf("cannot join pause process. You may need to remove %s and stop all containers", pausePidPath) logrus.Errorf("you can use `system migrate` to recreate the pause process") logrus.Errorf(err.Error()) os.Exit(1) @@ -154,28 +144,13 @@ func setupRootless(cmd *cobra.Command, args []string) error { logrus.Errorf(err.Error()) os.Exit(1) } - var became bool - var ret int - if len(ctrs) == 0 { - became, ret, err = rootless.BecomeRootInUserNS(pausePidPath) - } else { - for _, ctr := range ctrs { - data, err := ioutil.ReadFile(ctr.Config().ConmonPidFile) - if err != nil { - logrus.Errorf(err.Error()) - continue - } - conmonPid, err := strconv.Atoi(string(data)) - if err != nil { - logrus.Errorf(err.Error()) - continue - } - became, ret, err = rootless.JoinUserAndMountNS(uint(conmonPid), pausePidPath) - if err == nil { - break - } - } + + paths := []string{} + for _, ctr := range ctrs { + paths = append(paths, ctr.Config().ConmonPidFile) } + + became, ret, err := rootless.TryJoinFromFilePaths(pausePidPath, true, paths) if err != nil { logrus.Errorf(err.Error()) os.Exit(1) @@ -185,6 +160,7 @@ func setupRootless(cmd *cobra.Command, args []string) error { } return nil } + func setRLimits() error { rlimits := new(syscall.Rlimit) rlimits.Cur = 1048576 diff --git a/cmd/podman/shared/container.go b/cmd/podman/shared/container.go index fe447d10d..55cc529e0 100644 --- a/cmd/podman/shared/container.go +++ b/cmd/podman/shared/container.go @@ -631,6 +631,10 @@ func GetCtrInspectInfo(config *libpod.ContainerConfig, ctrInspectData *inspect.C memKernel, memReservation, memSwap, memSwappiness, memDisableOOMKiller := getMemoryInfo(spec) pidsLimit := getPidsInfo(spec) cgroup := getCgroup(spec) + logConfig := inspect.LogConfig{ + config.LogDriver, + make(map[string]string), + } data := &inspect.ContainerData{ ctrInspectData, @@ -681,6 +685,7 @@ func GetCtrInspectInfo(config *libpod.ContainerConfig, ctrInspectData *inspect.C Ulimits: createArtifact.Resources.Ulimit, SecurityOpt: createArtifact.SecurityOpts, Tmpfs: createArtifact.Tmpfs, + LogConfig: &logConfig, }, &inspect.CtrConfig{ Hostname: spec.Hostname, diff --git a/cmd/podman/shared/create.go b/cmd/podman/shared/create.go index 3c9b17804..7cf230605 100644 --- a/cmd/podman/shared/create.go +++ b/cmd/podman/shared/create.go @@ -603,6 +603,11 @@ func ParseCreateOpts(ctx context.Context, c *GenericCLIResults, runtime *libpod. memorySwappiness := c.Int64("memory-swappiness") + logDriver := libpod.KubernetesLogging + if c.Changed("log-driver") { + logDriver = c.String("log-driver") + } + config := &cc.CreateConfig{ Annotations: annotations, BuiltinImgVolumes: ImageVolumes, @@ -635,7 +640,7 @@ func ParseCreateOpts(ctx context.Context, c *GenericCLIResults, runtime *libpod. IPAddress: c.String("ip"), Labels: labels, //LinkLocalIP: c.StringSlice("link-local-ip"), // Not implemented yet - LogDriver: c.String("log-driver"), + LogDriver: logDriver, LogDriverOpt: c.StringSlice("log-opt"), MacAddress: c.String("mac-address"), Name: c.String("name"), diff --git a/completions/bash/podman b/completions/bash/podman index 60d5fde52..49c8c0e52 100644 --- a/completions/bash/podman +++ b/completions/bash/podman @@ -486,6 +486,7 @@ __podman_complete_log_drivers() { none splunk syslog + k8s-file " -- "$cur" ) ) } @@ -500,6 +501,7 @@ __podman_complete_log_options() { local logentries_options="logentries-token" local syslog_options="env labels syslog-address syslog-facility syslog-format syslog-tls-ca-cert syslog-tls-cert syslog-tls-key syslog-tls-skip-verify tag" local splunk_options="env labels splunk-caname splunk-capath splunk-format splunk-gzip splunk-gzip-level splunk-index splunk-insecureskipverify splunk-source splunk-sourcetype splunk-token splunk-url splunk-verify-connection tag" + local k8s_file_options="env labels max-file max-size" local all_options="$fluentd_options $gcplogs_options $gelf_options $journald_options $logentries_options $json_file_options $syslog_options $splunk_options" @@ -525,6 +527,9 @@ __podman_complete_log_options() { json-file) COMPREPLY=( $( compgen -W "$json_file_options" -S = -- "$cur" ) ) ;; + k8s-file) + COMPREPLY=( $( compgen -W "$k8s_file_options" -S = -- "$cur" ) ) + ;; logentries) COMPREPLY=( $( compgen -W "$logentries_options" -S = -- "$cur" ) ) ;; @@ -764,6 +769,10 @@ _podman_container_commit() { _podman_commit } +_podman_container_cp() { + _podman_cp +} + _podman_container_create() { _podman_create } @@ -961,6 +970,7 @@ _podman_container() { attach checkpoint commit + cp create diff exec @@ -2378,6 +2388,7 @@ _podman_cp() { --help -h --extract + --pause " _complete_ "$boolean_options" } diff --git a/contrib/cirrus/container_test.sh b/contrib/cirrus/container_test.sh index 1fd9551db..6bd925f17 100644 --- a/contrib/cirrus/container_test.sh +++ b/contrib/cirrus/container_test.sh @@ -35,7 +35,7 @@ options=0 noremote=0 install_tools_made=0 -while getopts "biptuv" opt; do +while getopts "bitnuv" opt; do case "$opt" in b) build=1 options=1 diff --git a/docs/podman-build.1.md b/docs/podman-build.1.md index 4a26c0981..e2769c2a9 100644 --- a/docs/podman-build.1.md +++ b/docs/podman-build.1.md @@ -174,6 +174,18 @@ This is a Docker specific option to disable image verification to a Docker registry and is not supported by Podman. This flag is a NOOP and provided soley for scripting compatibility. +**--dns**=[] + +Set custom DNS servers + +**--dns-option**=[] + +Set custom DNS options + +**--dns-search**=[] + +Set custom DNS search domains + **--file, -f** *Dockerfile* Specifies a Dockerfile which contains instructions for building the image, diff --git a/docs/podman-container.1.md b/docs/podman-container.1.md index 564d791fa..eb53149bd 100644 --- a/docs/podman-container.1.md +++ b/docs/podman-container.1.md @@ -17,6 +17,7 @@ The container command allows you to manage containers | checkpoint | [podman-container-checkpoint(1)](podman-container-checkpoint.1.md) | Checkpoints one or more containers. | | cleanup | [podman-container-cleanup(1)](podman-container-cleanup.1.md) | Cleanup containers network and mountpoints. | | commit | [podman-commit(1)](podman-commit.1.md) | Create new image based on the changed container. | +| cp | [podman-cp(1)](podman-cp.1.md) | Copy files/folders between a container and the local filesystem. | | create | [podman-create(1)](podman-create.1.md) | Create a new container. | | diff | [podman-diff(1)](podman-diff.1.md) | Inspect changes on a container or image's filesystem. | | exec | [podman-exec(1)](podman-exec.1.md) | Execute a command in a running container. | diff --git a/docs/podman-cp.1.md b/docs/podman-cp.1.md index 406dd51df..76fe57a9e 100644 --- a/docs/podman-cp.1.md +++ b/docs/podman-cp.1.md @@ -61,6 +61,10 @@ If you use a : in a local machine path, you must be explicit with a relative or Extract the tar file into the destination directory. If the destination directory is not provided, extract the tar file into the root directory. +**--pause** + +Pause the container while copying into it to avoid potential security issues around symlinks. Defaults to *true*. + ## ALTERNATIVES Podman has much stronger capabilities than just `podman cp` to achieve copy files between host and container. diff --git a/docs/podman-create.1.md b/docs/podman-create.1.md index cbd6d9a99..eafc6e27f 100644 --- a/docs/podman-create.1.md +++ b/docs/podman-create.1.md @@ -380,7 +380,7 @@ Read in a line delimited file of labels Not implemented -**--log-driver**="*json-file*" +**--log-driver**="*k8s-file*" Logging driver for the container. Currently not supported. This flag is a NOOP provided soley for scripting compatibility. diff --git a/docs/podman-logs.1.md b/docs/podman-logs.1.md index ce5d890ce..7feae1b76 100644 --- a/docs/podman-logs.1.md +++ b/docs/podman-logs.1.md @@ -50,7 +50,7 @@ Show timestamps in the log outputs. The default is false To view a container's logs: ``` -podman logs b3f2436bdb978c1d33b1387afb5d7ba7e3243ed2ce908db431ac0069da86cb45 +podman logs -t b3f2436bdb978c1d33b1387afb5d7ba7e3243ed2ce908db431ac0069da86cb45 2017/08/07 10:16:21 Seeked /var/log/crio/pods/eb296bd56fab164d4d3cc46e5776b54414af3bf543d138746b25832c816b933b/c49f49788da14f776b7aa93fb97a2a71f9912f4e5a3e30397fca7dfe0ee0367b.log - &{Offset:0 Whence:0} 1:C 07 Aug 14:10:09.055 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo @@ -68,13 +68,13 @@ To view only the last two lines in container's log: ``` podman logs --tail 2 b3f2436bdb97 -1:M 07 Aug 14:10:09.056 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128. -1:M 07 Aug 14:10:09.056 # Server initialized +# WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128. +# Server initialized ``` To view a containers logs since a certain time: ``` -podman logs --since 2017-08-07T10:10:09.055837383-04:00 myserver +podman logs -t --since 2017-08-07T10:10:09.055837383-04:00 myserver 1:M 07 Aug 14:10:09.055 # Server can't set maximum open files to 10032 because of OS error: Operation not permitted. 1:M 07 Aug 14:10:09.055 # Current maximum open files is 4096. maxclients has been reduced to 4064 to compensate for low ulimit. If you need higher maxclients increase 'ulimit -n'. @@ -87,8 +87,8 @@ To view a container's logs generated in the last 10 minutes: ``` podman logs --since 10m myserver -1:M 07 Aug 14:10:09.055 # Server can't set maximum open files to 10032 because of OS error: Operation not permitted. -1:M 07 Aug 14:10:09.055 # Current maximum open files is 4096. maxclients has been reduced to 4064 to compensate for low ulimit. If you need higher maxclients increase 'ulimit -n'. +# Server can't set maximum open files to 10032 because of OS error: Operation not permitted. +# Current maximum open files is 4096. maxclients has been reduced to 4064 to compensate for low ulimit. If you need higher maxclients increase 'ulimit -n'. ``` ## SEE ALSO diff --git a/docs/podman-run.1.md b/docs/podman-run.1.md index 78e8a5d6e..a7091e89a 100644 --- a/docs/podman-run.1.md +++ b/docs/podman-run.1.md @@ -394,7 +394,7 @@ Read in a line delimited file of labels Not implemented -**--log-driver**="*json-file*" +**--log-driver**="*k8s-file*" Logging driver for the container. Currently not supported. This flag is a NOOP provided soley for scripting compatibility. diff --git a/hack/get_ci_vm.sh b/hack/get_ci_vm.sh index aed0042fb..12dd211f4 100755 --- a/hack/get_ci_vm.sh +++ b/hack/get_ci_vm.sh @@ -11,7 +11,7 @@ ${YEL}WARNING: This will not work without local sudo access to run podman,${NOR} ${YEL}possession of the proper ssh private key is required.${NOR} " # TODO: Many/most of these values should come from .cirrus.yml -ZONE="us-central1-a" +ZONE="${ZONE:-us-central1-a}" CPUS="2" MEMORY="4Gb" DISK="200" @@ -238,10 +238,14 @@ showrun --background tar cjf $TMPDIR/$TARBALL --warning=no-file-changed --exclud trap delvm INT # Allow deleting VM if CTRL-C during create # This fails if VM already exists: permit this usage to re-init -echo -e "\n${YEL}Trying to creating a VM named $VMNAME\n${RED}(might take a minute/two. Errors ignored).${NOR}" +echo -e "\n${YEL}Trying to creating a VM named $VMNAME${NOR}\n${YEL}in GCE region/zone $ZONE${NOR}" +echo -e "For faster access, export ZONE='something-closer-<any letter>'" +echo 'List of regions and zones: https://cloud.google.com/compute/docs/regions-zones/' +echo -e "${RED}(might take a minute/two. Errors ignored).${NOR}" showrun $CREATE_CMD || true # allow re-running commands below when "delete: N" # Any subsequent failure should prompt for VM deletion +trap - INT trap delvm EXIT echo -e "\n${YEL}Waiting up to 30s for ssh port to open${NOR}" diff --git a/libpod/container.go b/libpod/container.go index c07f4c78d..c8ab42fc3 100644 --- a/libpod/container.go +++ b/libpod/container.go @@ -51,6 +51,15 @@ const CgroupfsDefaultCgroupParent = "/libpod_parent" // manager in libpod const SystemdDefaultCgroupParent = "machine.slice" +// JournaldLogging is the string conmon expects to specify journald logging +const JournaldLogging = "journald" + +// KubernetesLogging is the string conmon expects when specifying to use the kubernetes logging format +const KubernetesLogging = "k8s-file" + +// JSONLogging is the string conmon expects when specifying to use the json logging format +const JSONLogging = "json-file" + // DefaultWaitInterval is the default interval between container status checks // while waiting. const DefaultWaitInterval = 250 * time.Millisecond @@ -368,6 +377,8 @@ type ContainerConfig struct { CgroupParent string `json:"cgroupParent"` // LogPath log location LogPath string `json:"logPath"` + // LogDriver driver for logs + LogDriver string `json:"logDriver"` // File containing the conmon PID ConmonPidFile string `json:"conmonPidFile,omitempty"` // RestartPolicy indicates what action the container will take upon @@ -775,6 +786,11 @@ func (c *Container) RestartRetries() uint { return c.config.RestartRetries } +// LogDriver returns the log driver for this container +func (c *Container) LogDriver() string { + return c.config.LogDriver +} + // RuntimeName returns the name of the runtime func (c *Container) RuntimeName() string { return c.runtime.ociRuntime.name diff --git a/libpod/container_log.go b/libpod/container_log.go index e998ad316..374e5a1fc 100644 --- a/libpod/container_log.go +++ b/libpod/container_log.go @@ -19,6 +19,13 @@ const ( // zeroes are not trimmed, taken from // https://github.com/golang/go/issues/19635 logTimeFormat = "2006-01-02T15:04:05.000000000Z07:00" + + // partialLogType signifies a log line that exceeded the buffer + // length and needed to spill into a new line + partialLogType = "P" + + // fullLogType signifies a log line is full + fullLogType = "F" ) // LogOptions is the options you can use for logs @@ -53,6 +60,15 @@ func (r *Runtime) Log(containers []*Container, options *LogOptions, logChannel c // ReadLog reads a containers log based on the input options and returns loglines over a channel func (c *Container) ReadLog(options *LogOptions, logChannel chan *LogLine) error { + // TODO Skip sending logs until journald logs can be read + // TODO make this not a magic string + if c.LogDriver() == JournaldLogging { + return c.readFromJournal(options, logChannel) + } + return c.readFromLogFile(options, logChannel) +} + +func (c *Container) readFromLogFile(options *LogOptions, logChannel chan *LogLine) error { t, tailLog, err := getLogFile(c.LogPath(), options) if err != nil { // If the log file does not exist, this is not fatal. @@ -191,7 +207,7 @@ func newLogLine(line string) (*LogLine, error) { if len(splitLine) < 4 { return nil, errors.Errorf("'%s' is not a valid container log line", line) } - logTime, err := time.Parse(time.RFC3339Nano, splitLine[0]) + logTime, err := time.Parse(logTimeFormat, splitLine[0]) if err != nil { return nil, errors.Wrapf(err, "unable to convert time %s from container log", splitLine[0]) } @@ -206,7 +222,7 @@ func newLogLine(line string) (*LogLine, error) { // Partial returns a bool if the log line is a partial log type func (l *LogLine) Partial() bool { - if l.ParseLogType == "P" { + if l.ParseLogType == partialLogType { return true } return false diff --git a/libpod/container_log_linux.go b/libpod/container_log_linux.go new file mode 100644 index 000000000..e549673a6 --- /dev/null +++ b/libpod/container_log_linux.go @@ -0,0 +1,143 @@ +//+build linux +//+build systemd + +package libpod + +import ( + "fmt" + "io" + "strings" + "time" + + journal "github.com/coreos/go-systemd/sdjournal" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" +) + +const ( + // journaldLogOut is the journald priority signifying stdout + journaldLogOut = "6" + + // journaldLogErr is the journald priority signifying stderr + journaldLogErr = "3" + + // bufLen is the length of the buffer to read from a k8s-file + // formatted log line + // let's set it as 2k just to be safe if k8s-file format ever changes + bufLen = 16384 +) + +func (c *Container) readFromJournal(options *LogOptions, logChannel chan *LogLine) error { + var config journal.JournalReaderConfig + config.NumFromTail = options.Tail + config.Formatter = journalFormatter + defaultTime := time.Time{} + if options.Since != defaultTime { + // coreos/go-systemd/sdjournal doesn't correctly handle requests for data in the future + // return nothing instead of fasely printing + if time.Now().Before(options.Since) { + return nil + } + config.Since = time.Since(options.Since) + } + config.Matches = append(config.Matches, journal.Match{ + Field: "CONTAINER_ID_FULL", + Value: c.ID(), + }) + options.WaitGroup.Add(1) + + r, err := journal.NewJournalReader(config) + if err != nil { + return err + } + if r == nil { + return errors.Errorf("journal reader creation failed") + } + if options.Tail == 0 { + r.Rewind() + } + + if options.Follow { + go func() { + follower := FollowBuffer{logChannel} + err := r.Follow(nil, follower) + if err != nil { + logrus.Debugf(err.Error()) + } + r.Close() + options.WaitGroup.Done() + return + }() + return nil + } + + go func() { + bytes := make([]byte, bufLen) + // /me complains about no do-while in go + ec, err := r.Read(bytes) + for ec != 0 && err == nil { + // because we are reusing bytes, we need to make + // sure the old data doesn't get into the new line + bytestr := string(bytes[:ec]) + logLine, err2 := newLogLine(bytestr) + if err2 != nil { + logrus.Error(err2) + continue + } + logChannel <- logLine + ec, err = r.Read(bytes) + } + if err != nil && err != io.EOF { + logrus.Error(err) + } + r.Close() + options.WaitGroup.Done() + }() + return nil +} + +func journalFormatter(entry *journal.JournalEntry) (string, error) { + usec := entry.RealtimeTimestamp + tsString := time.Unix(0, int64(usec)*int64(time.Microsecond)).Format(logTimeFormat) + output := fmt.Sprintf("%s ", tsString) + priority, ok := entry.Fields["PRIORITY"] + if !ok { + return "", errors.Errorf("no PRIORITY field present in journal entry") + } + if priority == journaldLogOut { + output += "stdout " + } else if priority == journaldLogErr { + output += "stderr " + } else { + return "", errors.Errorf("unexpected PRIORITY field in journal entry") + } + + // if CONTAINER_PARTIAL_MESSAGE is defined, the log type is "P" + if _, ok := entry.Fields["CONTAINER_PARTIAL_MESSAGE"]; ok { + output += fmt.Sprintf("%s ", partialLogType) + } else { + output += fmt.Sprintf("%s ", fullLogType) + } + + // Finally, append the message + msg, ok := entry.Fields["MESSAGE"] + if !ok { + return "", fmt.Errorf("no MESSAGE field present in journal entry") + } + output += strings.TrimSpace(msg) + return output, nil +} + +type FollowBuffer struct { + logChannel chan *LogLine +} + +func (f FollowBuffer) Write(p []byte) (int, error) { + bytestr := string(p) + logLine, err := newLogLine(bytestr) + if err != nil { + return -1, err + } + f.logChannel <- logLine + return len(p), nil +} diff --git a/libpod/container_log_unsupported.go b/libpod/container_log_unsupported.go new file mode 100644 index 000000000..0ec5740e2 --- /dev/null +++ b/libpod/container_log_unsupported.go @@ -0,0 +1,11 @@ +//+build !linux !systemd + +package libpod + +import ( + "github.com/pkg/errors" +) + +func (c *Container) readFromJournal(options *LogOptions, logChannel chan *LogLine) error { + return errors.Wrapf(ErrOSNotSupported, "Journald logging only enabled with systemd on linux") +} diff --git a/libpod/oci.go b/libpod/oci.go index abc6214b9..7138108c5 100644 --- a/libpod/oci.go +++ b/libpod/oci.go @@ -367,8 +367,6 @@ func (r *OCIRuntime) execContainer(c *Container, cmd, capAdd, env []string, tty args := []string{} // TODO - should we maintain separate logpaths for exec sessions? - args = append(args, "--log", c.LogPath()) - args = append(args, "exec") if cwd != "" { @@ -402,7 +400,7 @@ func (r *OCIRuntime) execContainer(c *Container, cmd, capAdd, env []string, tty args = append(args, "--env", envVar) } - // Append container ID and command + // Append container ID, name and command args = append(args, c.ID()) args = append(args, cmd...) diff --git a/libpod/oci_linux.go b/libpod/oci_linux.go index 1c1e4a203..7c1c18052 100644 --- a/libpod/oci_linux.go +++ b/libpod/oci_linux.go @@ -214,10 +214,10 @@ func (r *OCIRuntime) createOCIContainer(ctr *Container, cgroupParent string, res } args = append(args, "-c", ctr.ID()) args = append(args, "-u", ctr.ID()) + args = append(args, "-n", ctr.Name()) args = append(args, "-r", r.path) args = append(args, "-b", ctr.bundlePath()) args = append(args, "-p", filepath.Join(ctr.state.RunDir, "pidfile")) - args = append(args, "-l", ctr.LogPath()) args = append(args, "--exit-dir", r.exitsDir) if ctr.config.ConmonPidFile != "" { args = append(args, "--conmon-pidfile", ctr.config.ConmonPidFile) @@ -237,6 +237,13 @@ func (r *OCIRuntime) createOCIContainer(ctr *Container, cgroupParent string, res if r.logSizeMax >= 0 { args = append(args, "--log-size-max", fmt.Sprintf("%v", r.logSizeMax)) } + + logDriver := KubernetesLogging + if ctr.LogDriver() != "" { + logDriver = ctr.LogDriver() + } + args = append(args, "-l", fmt.Sprintf("%s:%s", logDriver, ctr.LogPath())) + if r.noPivot { args = append(args, "--no-pivot") } diff --git a/libpod/options.go b/libpod/options.go index 7ec7dfe63..20aa51981 100644 --- a/libpod/options.go +++ b/libpod/options.go @@ -979,6 +979,27 @@ func WithStaticIP(ip net.IP) CtrCreateOption { } } +// WithLogDriver sets the log driver for the container +func WithLogDriver(driver string) CtrCreateOption { + return func(ctr *Container) error { + if ctr.valid { + return ErrCtrFinalized + } + switch driver { + case "": + return errors.Wrapf(ErrInvalidArg, "log driver must be set") + case JournaldLogging, KubernetesLogging, JSONLogging: + break + default: + return errors.Wrapf(ErrInvalidArg, "invalid log driver") + } + + ctr.config.LogDriver = driver + + return nil + } +} + // WithLogPath sets the path to the log file. func WithLogPath(path string) CtrCreateOption { return func(ctr *Container) error { diff --git a/libpod/runtime_ctr.go b/libpod/runtime_ctr.go index c7758055f..0c8d3edab 100644 --- a/libpod/runtime_ctr.go +++ b/libpod/runtime_ctr.go @@ -167,7 +167,7 @@ func (r *Runtime) newContainer(ctx context.Context, rSpec *spec.Spec, options .. }() if rootless.IsRootless() && ctr.config.ConmonPidFile == "" { - ctr.config.ConmonPidFile = filepath.Join(ctr.config.StaticDir, "conmon.pid") + ctr.config.ConmonPidFile = filepath.Join(ctr.state.RunDir, "conmon.pid") } // Go through named volumes and add them. @@ -196,7 +196,7 @@ func (r *Runtime) newContainer(ctx context.Context, rSpec *spec.Spec, options .. } } - if ctr.config.LogPath == "" { + if ctr.config.LogPath == "" && ctr.config.LogDriver != JournaldLogging { ctr.config.LogPath = filepath.Join(ctr.config.StaticDir, "ctr.log") } diff --git a/pkg/inspect/inspect.go b/pkg/inspect/inspect.go index 693755aa8..2082bb3a6 100644 --- a/pkg/inspect/inspect.go +++ b/pkg/inspect/inspect.go @@ -103,7 +103,7 @@ type CtrConfig struct { // LogConfig holds the log information for a container type LogConfig struct { - Type string `json:"Type"` // TODO + Type string `json:"Type"` Config map[string]string `json:"Config"` //idk type, TODO } diff --git a/pkg/rootless/rootless_linux.c b/pkg/rootless/rootless_linux.c index 098ca7830..2356882e7 100644 --- a/pkg/rootless/rootless_linux.c +++ b/pkg/rootless/rootless_linux.c @@ -69,6 +69,19 @@ rootless_gid () static void do_pause () { + int i; + struct sigaction act; + int const sig[] = + { + SIGALRM, SIGHUP, SIGINT, SIGPIPE, SIGQUIT, SIGTERM, SIGPOLL, + SIGPROF, SIGVTALRM, SIGXCPU, SIGXFSZ, 0 + }; + + act.sa_handler = SIG_IGN; + + for (i = 0; sig[i]; i++) + sigaction (sig[i], &act, NULL); + prctl (PR_SET_NAME, "podman pause", NULL, NULL, NULL); while (1) pause (); @@ -333,6 +346,26 @@ syscall_clone (unsigned long flags, void *child_stack) #endif } +int +reexec_in_user_namespace_wait (int pid, int options) +{ + pid_t p; + int status; + + do + p = waitpid (pid, &status, 0); + while (p < 0 && errno == EINTR); + + if (p < 0) + return -1; + + if (WIFEXITED (status)) + return WEXITSTATUS (status); + if (WIFSIGNALED (status)) + return 128 + WTERMSIG (status); + return -1; +} + static int create_pause_process (const char *pause_pid_file_path, char **argv) { @@ -356,6 +389,8 @@ create_pause_process (const char *pause_pid_file_path, char **argv) while (r < 0 && errno == EINTR); close (p[0]); + reexec_in_user_namespace_wait(r, 0); + return r == 1 && b == '0' ? 0 : -1; } else @@ -560,8 +595,51 @@ check_proc_sys_userns_file (const char *path) } } +static int +copy_file_to_fd (const char *file_to_read, int outfd) +{ + char buf[512]; + int fd; + + fd = open (file_to_read, O_RDONLY); + if (fd < 0) + return fd; + + for (;;) + { + ssize_t r, w, t = 0; + + do + r = read (fd, buf, sizeof buf); + while (r < 0 && errno == EINTR); + if (r < 0) + { + close (fd); + return r; + } + + if (r == 0) + break; + + while (t < r) + { + do + w = write (outfd, &buf[t], r - t); + while (w < 0 && errno == EINTR); + if (w < 0) + { + close (fd); + return w; + } + t += w; + } + } + close (fd); + return 0; +} + int -reexec_in_user_namespace (int ready, char *pause_pid_file_path) +reexec_in_user_namespace (int ready, char *pause_pid_file_path, char *file_to_read, int outputfd) { int ret; pid_t pid; @@ -574,6 +652,7 @@ reexec_in_user_namespace (int ready, char *pause_pid_file_path) char *listen_pid = NULL; bool do_socket_activation = false; char *cwd = getcwd (NULL, 0); + sigset_t sigset, oldsigset; if (cwd == NULL) { @@ -584,11 +663,11 @@ reexec_in_user_namespace (int ready, char *pause_pid_file_path) listen_pid = getenv("LISTEN_PID"); listen_fds = getenv("LISTEN_FDS"); - if (listen_pid != NULL && listen_fds != NULL) { - if (strtol(listen_pid, NULL, 10) == getpid()) { - do_socket_activation = true; + if (listen_pid != NULL && listen_fds != NULL) + { + if (strtol(listen_pid, NULL, 10) == getpid()) + do_socket_activation = true; } - } sprintf (uid, "%d", geteuid ()); sprintf (gid, "%d", getegid ()); @@ -621,6 +700,22 @@ reexec_in_user_namespace (int ready, char *pause_pid_file_path) return pid; } + if (sigfillset (&sigset) < 0) + { + fprintf (stderr, "cannot fill sigset: %s\n", strerror (errno)); + _exit (EXIT_FAILURE); + } + if (sigdelset (&sigset, SIGCHLD) < 0) + { + fprintf (stderr, "cannot sigdelset(SIGCHLD): %s\n", strerror (errno)); + _exit (EXIT_FAILURE); + } + if (sigprocmask (SIG_BLOCK, &sigset, &oldsigset) < 0) + { + fprintf (stderr, "cannot block signals: %s\n", strerror (errno)); + _exit (EXIT_FAILURE); + } + argv = get_cmd_line_args (ppid); if (argv == NULL) { @@ -628,11 +723,12 @@ reexec_in_user_namespace (int ready, char *pause_pid_file_path) _exit (EXIT_FAILURE); } - if (do_socket_activation) { - char s[32]; - sprintf (s, "%d", getpid()); - setenv ("LISTEN_PID", s, true); - } + if (do_socket_activation) + { + char s[32]; + sprintf (s, "%d", getpid()); + setenv ("LISTEN_PID", s, true); + } setenv ("_CONTAINERS_USERNS_CONFIGURED", "init", 1); setenv ("_CONTAINERS_ROOTLESS_UID", uid, 1); @@ -685,27 +781,20 @@ reexec_in_user_namespace (int ready, char *pause_pid_file_path) while (ret < 0 && errno == EINTR); close (ready); - execvp (argv[0], argv); - - _exit (EXIT_FAILURE); -} - -int -reexec_in_user_namespace_wait (int pid) -{ - pid_t p; - int status; + if (sigprocmask (SIG_SETMASK, &oldsigset, NULL) < 0) + { + fprintf (stderr, "cannot block signals: %s\n", strerror (errno)); + _exit (EXIT_FAILURE); + } - do - p = waitpid (pid, &status, 0); - while (p < 0 && errno == EINTR); + if (file_to_read && file_to_read[0]) + { + ret = copy_file_to_fd (file_to_read, outputfd); + close (outputfd); + _exit (ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE); + } - if (p < 0) - return -1; + execvp (argv[0], argv); - if (WIFEXITED (status)) - return WEXITSTATUS (status); - if (WIFSIGNALED (status)) - return 128 + WTERMSIG (status); - return -1; + _exit (EXIT_FAILURE); } diff --git a/pkg/rootless/rootless_linux.go b/pkg/rootless/rootless_linux.go index 9132c0fe5..d302b1777 100644 --- a/pkg/rootless/rootless_linux.go +++ b/pkg/rootless/rootless_linux.go @@ -26,8 +26,8 @@ import ( #include <stdlib.h> extern uid_t rootless_uid(); extern uid_t rootless_gid(); -extern int reexec_in_user_namespace(int ready, char *pause_pid_file_path); -extern int reexec_in_user_namespace_wait(int pid); +extern int reexec_in_user_namespace(int ready, char *pause_pid_file_path, char *file_to_read, int fd); +extern int reexec_in_user_namespace_wait(int pid, int options); extern int reexec_userns_join(int userns, int mountns, char *pause_pid_file_path); */ import "C" @@ -194,10 +194,24 @@ func getUserNSFirstChild(fd uintptr) (*os.File, error) { } } -// JoinUserAndMountNS re-exec podman in a new userNS and join the user and mount +func enableLinger(pausePid string) { + if pausePid == "" { + return + } + // If we are trying to write a pause pid file, make sure we can leave processes + // running longer than the user session. + err := exec.Command("loginctl", "enable-linger", fmt.Sprintf("%d", GetRootlessUID())).Run() + if err != nil { + logrus.Warnf("cannot run `loginctl enable-linger` for the current user: %v", err) + } +} + +// joinUserAndMountNS re-exec podman in a new userNS and join the user and mount // namespace of the specified PID without looking up its parent. Useful to join directly // the conmon process. -func JoinUserAndMountNS(pid uint, pausePid string) (bool, int, error) { +func joinUserAndMountNS(pid uint, pausePid string) (bool, int, error) { + enableLinger(pausePid) + if os.Geteuid() == 0 || os.Getenv("_CONTAINERS_USERNS_CONFIGURED") != "" { return false, -1, nil } @@ -226,7 +240,7 @@ func JoinUserAndMountNS(pid uint, pausePid string) (bool, int, error) { return false, -1, errors.Errorf("cannot re-exec process") } - ret := C.reexec_in_user_namespace_wait(pidC) + ret := C.reexec_in_user_namespace_wait(pidC, 0) if ret < 0 { return false, -1, errors.New("error waiting for the re-exec process") } @@ -234,11 +248,7 @@ func JoinUserAndMountNS(pid uint, pausePid string) (bool, int, error) { return true, int(ret), nil } -// BecomeRootInUserNS re-exec podman in a new userNS. It returns whether podman was re-executed -// into a new user namespace and the return code from the re-executed podman process. -// If podman was re-executed the caller needs to propagate the error code returned by the child -// process. -func BecomeRootInUserNS(pausePid string) (bool, int, error) { +func becomeRootInUserNS(pausePid, fileToRead string, fileOutput *os.File) (bool, int, error) { if os.Geteuid() == 0 || os.Getenv("_CONTAINERS_USERNS_CONFIGURED") != "" { if os.Getenv("_CONTAINERS_USERNS_CONFIGURED") == "init" { return false, 0, runInUser() @@ -249,6 +259,13 @@ func BecomeRootInUserNS(pausePid string) (bool, int, error) { cPausePid := C.CString(pausePid) defer C.free(unsafe.Pointer(cPausePid)) + cFileToRead := C.CString(fileToRead) + defer C.free(unsafe.Pointer(cFileToRead)) + var fileOutputFD C.int + if fileOutput != nil { + fileOutputFD = C.int(fileOutput.Fd()) + } + runtime.LockOSThread() defer runtime.UnlockOSThread() @@ -262,7 +279,7 @@ func BecomeRootInUserNS(pausePid string) (bool, int, error) { defer w.Close() defer w.Write([]byte("0")) - pidC := C.reexec_in_user_namespace(C.int(r.Fd()), cPausePid) + pidC := C.reexec_in_user_namespace(C.int(r.Fd()), cPausePid, cFileToRead, fileOutputFD) pid := int(pidC) if pid < 0 { return false, -1, errors.Errorf("cannot re-exec process") @@ -328,6 +345,10 @@ func BecomeRootInUserNS(pausePid string) (bool, int, error) { return false, -1, errors.Wrapf(err, "read from sync pipe") } + if fileOutput != nil { + return true, 0, nil + } + if b[0] == '2' { // We have lost the race for writing the PID file, as probably another // process created a namespace and wrote the PID. @@ -336,7 +357,7 @@ func BecomeRootInUserNS(pausePid string) (bool, int, error) { if err == nil { pid, err := strconv.ParseUint(string(data), 10, 0) if err == nil { - return JoinUserAndMountNS(uint(pid), "") + return joinUserAndMountNS(uint(pid), "") } } return false, -1, errors.Wrapf(err, "error setting up the process") @@ -368,10 +389,96 @@ func BecomeRootInUserNS(pausePid string) (bool, int, error) { } }() - ret := C.reexec_in_user_namespace_wait(pidC) + ret := C.reexec_in_user_namespace_wait(pidC, 0) if ret < 0 { return false, -1, errors.New("error waiting for the re-exec process") } return true, int(ret), nil } + +// BecomeRootInUserNS re-exec podman in a new userNS. It returns whether podman was re-executed +// into a new user namespace and the return code from the re-executed podman process. +// If podman was re-executed the caller needs to propagate the error code returned by the child +// process. +func BecomeRootInUserNS(pausePid string) (bool, int, error) { + enableLinger(pausePid) + return becomeRootInUserNS(pausePid, "", nil) +} + +// TryJoinFromFilePaths attempts to join the namespaces of the pid files in paths. +// This is useful when there are already running containers and we +// don't have a pause process yet. We can use the paths to the conmon +// processes to attempt joining their namespaces. +// If needNewNamespace is set, the file is read from a temporary user +// namespace, this is useful for containers that are running with a +// different uidmap and the unprivileged user has no way to read the +// file owned by the root in the container. +func TryJoinFromFilePaths(pausePidPath string, needNewNamespace bool, paths []string) (bool, int, error) { + if len(paths) == 0 { + return BecomeRootInUserNS(pausePidPath) + } + + var lastErr error + var pausePid int + + for _, path := range paths { + if !needNewNamespace { + data, err := ioutil.ReadFile(path) + if err != nil { + lastErr = err + continue + } + + pausePid, err = strconv.Atoi(string(data)) + if err != nil { + lastErr = errors.Wrapf(err, "cannot parse file %s", path) + continue + } + + lastErr = nil + break + } else { + fds, err := syscall.Socketpair(syscall.AF_UNIX, syscall.SOCK_DGRAM, 0) + if err != nil { + lastErr = err + continue + } + + r, w := os.NewFile(uintptr(fds[0]), "read file"), os.NewFile(uintptr(fds[1]), "write file") + + defer w.Close() + defer r.Close() + + if _, _, err := becomeRootInUserNS("", path, w); err != nil { + lastErr = err + continue + } + + w.Close() + defer func() { + r.Close() + C.reexec_in_user_namespace_wait(-1, 0) + }() + + b := make([]byte, 32) + + n, err := r.Read(b) + if err != nil { + lastErr = errors.Wrapf(err, "cannot read %s\n", path) + continue + } + + pausePid, err = strconv.Atoi(string(b[:n])) + if err == nil { + lastErr = nil + break + } + } + } + if lastErr != nil { + return false, 0, lastErr + } + + return joinUserAndMountNS(uint(pausePid), pausePidPath) +} diff --git a/pkg/rootless/rootless_unsupported.go b/pkg/rootless/rootless_unsupported.go index 221baff97..c063adee5 100644 --- a/pkg/rootless/rootless_unsupported.go +++ b/pkg/rootless/rootless_unsupported.go @@ -29,10 +29,14 @@ func GetRootlessGID() int { return -1 } -// JoinUserAndMountNS re-exec podman in a new userNS and join the user and mount -// namespace of the specified PID without looking up its parent. Useful to join directly -// the conmon process. It is a convenience function for JoinUserAndMountNSWithOpts -// with a default configuration. -func JoinUserAndMountNS(pid uint, pausePid string) (bool, int, error) { +// TryJoinFromFilePaths attempts to join the namespaces of the pid files in paths. +// This is useful when there are already running containers and we +// don't have a pause process yet. We can use the paths to the conmon +// processes to attempt joining their namespaces. +// If needNewNamespace is set, the file is read from a temporary user +// namespace, this is useful for containers that are running with a +// different uidmap and the unprivileged user has no way to read the +// file owned by the root in the container. +func TryJoinFromFilePaths(pausePidPath string, needNewNamespace bool, paths []string) (bool, int, error) { return false, -1, errors.New("this function is not supported on this os") } diff --git a/pkg/spec/createconfig.go b/pkg/spec/createconfig.go index 9979e773c..e4501aaac 100644 --- a/pkg/spec/createconfig.go +++ b/pkg/spec/createconfig.go @@ -319,6 +319,9 @@ func (c *CreateConfig) getContainerCreateOptions(runtime *libpod.Runtime, pod *l if logPath != "" { options = append(options, libpod.WithLogPath(logPath)) } + + options = append(options, libpod.WithLogDriver(c.LogDriver)) + if c.IPAddress != "" { ip := net.ParseIP(c.IPAddress) if ip == nil { diff --git a/pkg/spec/storage.go b/pkg/spec/storage.go index dcc149b55..e221b5cb5 100644 --- a/pkg/spec/storage.go +++ b/pkg/spec/storage.go @@ -797,7 +797,7 @@ func initFSMounts(inputMounts []spec.Mount) []spec.Mount { if m.Type == TypeBind { m.Options = util.ProcessOptions(m.Options) } - if m.Type == TypeTmpfs { + if m.Type == TypeTmpfs && filepath.Clean(m.Destination) != "/dev" { m.Options = append(m.Options, "tmpcopyup") } mounts = append(mounts, m) diff --git a/test/e2e/attach_test.go b/test/e2e/attach_test.go index a843fe7ff..7233d169c 100644 --- a/test/e2e/attach_test.go +++ b/test/e2e/attach_test.go @@ -26,7 +26,7 @@ var _ = Describe("Podman attach", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreAllArtifacts() + podmanTest.SeedImages() }) AfterEach(func() { diff --git a/test/e2e/checkpoint_test.go b/test/e2e/checkpoint_test.go index c2f5a592c..95ec21433 100644 --- a/test/e2e/checkpoint_test.go +++ b/test/e2e/checkpoint_test.go @@ -28,7 +28,7 @@ var _ = Describe("Podman checkpoint", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreAllArtifacts() + podmanTest.SeedImages() // Check if the runtime implements checkpointing. Currently only // runc's checkpoint/restore implementation is supported. cmd := exec.Command(podmanTest.OCIRuntime, "checkpoint", "-h") @@ -221,7 +221,6 @@ var _ = Describe("Podman checkpoint", func() { }) It("podman checkpoint container with established tcp connections", func() { - podmanTest.RestoreArtifact(redis) session := podmanTest.Podman([]string{"run", "-it", "--security-opt", "seccomp=unconfined", "-d", redis}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) diff --git a/test/e2e/commit_test.go b/test/e2e/commit_test.go index bf20ac999..50577fdfb 100644 --- a/test/e2e/commit_test.go +++ b/test/e2e/commit_test.go @@ -24,7 +24,7 @@ var _ = Describe("Podman commit", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreAllArtifacts() + podmanTest.SeedImages() }) AfterEach(func() { diff --git a/test/e2e/common_test.go b/test/e2e/common_test.go index 3c7675b35..0a388dc42 100644 --- a/test/e2e/common_test.go +++ b/test/e2e/common_test.go @@ -100,12 +100,23 @@ var _ = SynchronizedBeforeSuite(func() []byte { } } + // make cache dir + if err := os.MkdirAll(ImageCacheDir, 0777); err != nil { + fmt.Printf("%q\n", err) + os.Exit(1) + } + for _, image := range CACHE_IMAGES { if err := podman.CreateArtifact(image); err != nil { fmt.Printf("%q\n", err) os.Exit(1) } } + + // If running localized tests, the cache dir is created and populated. if the + // tests are remote, this is a no-op + populateCache(podman) + host := GetHostDistributionInfo() if host.Distribution == "rhel" && strings.HasPrefix(host.Version, "7") { f, err := os.OpenFile("/proc/sys/user/max_user_namespaces", os.O_WRONLY, 0644) @@ -136,53 +147,29 @@ func (p *PodmanTestIntegration) Setup() { p.ArtifactPath = ARTIFACT_DIR } -// var _ = BeforeSuite(func() { -// cwd, _ := os.Getwd() -// INTEGRATION_ROOT = filepath.Join(cwd, "../../") -// podman := PodmanTestCreate("/tmp") -// podman.ArtifactPath = ARTIFACT_DIR -// if _, err := os.Stat(ARTIFACT_DIR); os.IsNotExist(err) { -// if err = os.Mkdir(ARTIFACT_DIR, 0777); err != nil { -// fmt.Printf("%q\n", err) -// os.Exit(1) -// } -// } -// }) -// for _, image := range CACHE_IMAGES { -// if err := podman.CreateArtifact(image); err != nil { -// fmt.Printf("%q\n", err) -// os.Exit(1) -// } -// } -// host := GetHostDistributionInfo() -// if host.Distribution == "rhel" && strings.HasPrefix(host.Version, "7") { -// f, err := os.OpenFile("/proc/sys/user/max_user_namespaces", os.O_WRONLY, 0644) -// if err != nil { -// fmt.Println("Unable to enable userspace on RHEL 7") -// os.Exit(1) -// } -// _, err = f.WriteString("15000") -// if err != nil { -// fmt.Println("Unable to enable userspace on RHEL 7") -// os.Exit(1) -// } -// f.Close() -// } -// path, err := ioutil.TempDir("", "libpodlock") -// if err != nil { -// fmt.Println(err) -// os.Exit(1) -// } -// LockTmpDir = path -// }) - -var _ = AfterSuite(func() { - sort.Sort(testResultsSortedLength{testResults}) - fmt.Println("integration timing results") - for _, result := range testResults { - fmt.Printf("%s\t\t%f\n", result.name, result.length) - } -}) +var _ = SynchronizedAfterSuite(func() {}, + func() { + sort.Sort(testResultsSortedLength{testResults}) + fmt.Println("integration timing results") + for _, result := range testResults { + fmt.Printf("%s\t\t%f\n", result.name, result.length) + } + + // previous crio-run + tempdir, err := CreateTempDirInTempDir() + if err != nil { + os.Exit(1) + } + podmanTest := PodmanTestCreate(tempdir) + + if err := os.RemoveAll(podmanTest.CrioRoot); err != nil { + fmt.Printf("%q\n", err) + } + + // for localized tests, this removes the image cache dir and for remote tests + // this is a no-op + removeCache() + }) // PodmanTestCreate creates a PodmanTestIntegration instance for the tests func PodmanTestCreateUtil(tempDir string, remote bool) *PodmanTestIntegration { @@ -244,12 +231,18 @@ func PodmanTestCreateUtil(tempDir string, remote bool) *PodmanTestIntegration { os.Setenv("DISABLE_HC_SYSTEMD", "true") CNIConfigDir := "/etc/cni/net.d" + storageFs := STORAGE_FS + if rootless.IsRootless() { + storageFs = ROOTLESS_STORAGE_FS + } p := &PodmanTestIntegration{ PodmanTest: PodmanTest{ - PodmanBinary: podmanBinary, - ArtifactPath: ARTIFACT_DIR, - TempDir: tempDir, - RemoteTest: remote, + PodmanBinary: podmanBinary, + ArtifactPath: ARTIFACT_DIR, + TempDir: tempDir, + RemoteTest: remote, + ImageCacheFS: storageFs, + ImageCacheDir: ImageCacheDir, }, ConmonBinary: conmonBinary, CrioRoot: filepath.Join(tempDir, "crio"), @@ -304,10 +297,10 @@ func (p *PodmanTestIntegration) CreateArtifact(image string) error { dest := strings.Split(image, "/") destName := fmt.Sprintf("/tmp/%s.tar", strings.Replace(strings.Join(strings.Split(dest[len(dest)-1], "/"), ""), ":", "-", -1)) if _, err := os.Stat(destName); os.IsNotExist(err) { - pull := p.Podman([]string{"pull", image}) + pull := p.PodmanNoCache([]string{"pull", image}) pull.Wait(90) - save := p.Podman([]string{"save", "-o", destName, image}) + save := p.PodmanNoCache([]string{"save", "-o", destName, image}) save.Wait(90) fmt.Printf("\n") } else { @@ -390,7 +383,7 @@ func (p *PodmanTestIntegration) BuildImage(dockerfile, imageName string, layers dockerfilePath := filepath.Join(p.TempDir, "Dockerfile") err := ioutil.WriteFile(dockerfilePath, []byte(dockerfile), 0755) Expect(err).To(BeNil()) - session := p.Podman([]string{"build", "--layers=" + layers, "-t", imageName, "--file", dockerfilePath, p.TempDir}) + session := p.PodmanNoCache([]string{"build", "--layers=" + layers, "-t", imageName, "--file", dockerfilePath, p.TempDir}) session.Wait(120) Expect(session.ExitCode()).To(Equal(0)) } @@ -465,7 +458,7 @@ func (p *PodmanTestIntegration) PullImages(images []string) error { // PullImage pulls a single image // TODO should the timeout be configurable? func (p *PodmanTestIntegration) PullImage(image string) error { - session := p.Podman([]string{"pull", image}) + session := p.PodmanNoCache([]string{"pull", image}) session.Wait(60) Expect(session.ExitCode()).To(Equal(0)) return nil @@ -508,3 +501,9 @@ func (p *PodmanTestIntegration) RunTopContainerInPod(name, pod string) *PodmanSe podmanArgs = append(podmanArgs, "-d", ALPINE, "top") return p.Podman(podmanArgs) } + +func (p *PodmanTestIntegration) ImageExistsInMainStore(idOrName string) bool { + results := p.PodmanNoCache([]string{"image", "exists", idOrName}) + results.WaitWithDefaultTimeout() + return Expect(results.ExitCode()).To(Equal(0)) +} diff --git a/test/e2e/config.go b/test/e2e/config.go index 3fdb9e116..5e0000e09 100644 --- a/test/e2e/config.go +++ b/test/e2e/config.go @@ -7,4 +7,5 @@ var ( infra = "k8s.gcr.io/pause:3.1" BB = "docker.io/library/busybox:latest" healthcheck = "docker.io/libpod/alpine_healthcheck:latest" + ImageCacheDir = "/tmp/podman/imagecachedir" ) diff --git a/test/e2e/config_amd64.go b/test/e2e/config_amd64.go index d02de7a6e..01aa8445a 100644 --- a/test/e2e/config_amd64.go +++ b/test/e2e/config_amd64.go @@ -1,7 +1,9 @@ package integration var ( + STORAGE_FS = "vfs" STORAGE_OPTIONS = "--storage-driver vfs" + ROOTLESS_STORAGE_FS = "vfs" ROOTLESS_STORAGE_OPTIONS = "--storage-driver vfs" CACHE_IMAGES = []string{ALPINE, BB, fedoraMinimal, nginx, redis, registry, infra, labels, healthcheck} nginx = "quay.io/libpod/alpine_nginx:latest" diff --git a/test/e2e/config_ppc64le.go b/test/e2e/config_ppc64le.go index d1737fa6f..569a34efb 100644 --- a/test/e2e/config_ppc64le.go +++ b/test/e2e/config_ppc64le.go @@ -1,7 +1,9 @@ package integration var ( + STORAGE_FS = "overlay" STORAGE_OPTIONS = "--storage-driver overlay" + ROOTLESS_STORAGE_FS = "vfs" ROOTLESS_STORAGE_OPTIONS = "--storage-driver vfs" CACHE_IMAGES = []string{ALPINE, BB, fedoraMinimal, nginx, redis, infra, labels} nginx = "quay.io/libpod/alpine_nginx-ppc64le:latest" diff --git a/test/e2e/cp_test.go b/test/e2e/cp_test.go index f8df5d3d0..983d61b58 100644 --- a/test/e2e/cp_test.go +++ b/test/e2e/cp_test.go @@ -28,7 +28,7 @@ var _ = Describe("Podman cp", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreAllArtifacts() + podmanTest.SeedImages() }) AfterEach(func() { @@ -42,14 +42,15 @@ var _ = Describe("Podman cp", func() { srcPath := filepath.Join(podmanTest.RunRoot, "cp_test.txt") dstPath := filepath.Join(podmanTest.RunRoot, "cp_from_container") fromHostToContainer := []byte("copy from host to container") - err := ioutil.WriteFile(srcPath, fromHostToContainer, 0644) - Expect(err).To(BeNil()) session := podmanTest.Podman([]string{"create", ALPINE, "cat", "foo"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) name := session.OutputToString() + err := ioutil.WriteFile(srcPath, fromHostToContainer, 0644) + Expect(err).To(BeNil()) + session = podmanTest.Podman([]string{"cp", srcPath, name + ":foo"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) @@ -63,16 +64,17 @@ var _ = Describe("Podman cp", func() { srcPath := filepath.Join(podmanTest.RunRoot, "cp_test.txt") dstDir := filepath.Join(podmanTest.RunRoot, "receive") fromHostToContainer := []byte("copy from host to container directory") - err := ioutil.WriteFile(srcPath, fromHostToContainer, 0644) - Expect(err).To(BeNil()) - err = os.Mkdir(dstDir, 0755) - Expect(err).To(BeNil()) session := podmanTest.Podman([]string{"create", ALPINE, "ls", "foodir/"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) name := session.OutputToString() + err := ioutil.WriteFile(srcPath, fromHostToContainer, 0644) + Expect(err).To(BeNil()) + err = os.Mkdir(dstDir, 0755) + Expect(err).To(BeNil()) + session = podmanTest.Podman([]string{"cp", srcPath, name + ":foodir/"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) @@ -87,14 +89,15 @@ var _ = Describe("Podman cp", func() { It("podman cp dir to dir", func() { testDirPath := filepath.Join(podmanTest.RunRoot, "TestDir") - err := os.Mkdir(testDirPath, 0755) - Expect(err).To(BeNil()) session := podmanTest.Podman([]string{"create", ALPINE, "ls", "/foodir"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) name := session.OutputToString() + err := os.Mkdir(testDirPath, 0755) + Expect(err).To(BeNil()) + session = podmanTest.Podman([]string{"cp", testDirPath, name + ":/foodir"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) @@ -105,6 +108,11 @@ var _ = Describe("Podman cp", func() { }) It("podman cp stdin/stdout", func() { + session := podmanTest.Podman([]string{"create", ALPINE, "ls", "foo"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + name := session.OutputToString() + testDirPath := filepath.Join(podmanTest.RunRoot, "TestDir") err := os.Mkdir(testDirPath, 0755) Expect(err).To(BeNil()) @@ -112,11 +120,6 @@ var _ = Describe("Podman cp", func() { _, err = cmd.Output() Expect(err).To(BeNil()) - session := podmanTest.Podman([]string{"create", ALPINE, "ls", "foo"}) - session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(Equal(0)) - name := session.OutputToString() - data, err := ioutil.ReadFile("foo.tar.gz") reader := strings.NewReader(string(data)) cmd.Stdin = reader @@ -133,6 +136,10 @@ var _ = Describe("Podman cp", func() { }) It("podman cp tar", func() { + session := podmanTest.Podman([]string{"create", "--name", "testctr", ALPINE, "ls", "-l", "foo"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + path, err := os.Getwd() Expect(err).To(BeNil()) testDirPath := filepath.Join(path, "TestDir") @@ -142,10 +149,6 @@ var _ = Describe("Podman cp", func() { _, err = cmd.Output() Expect(err).To(BeNil()) - session := podmanTest.Podman([]string{"create", "--name", "testctr", ALPINE, "ls", "-l", "foo"}) - session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(Equal(0)) - session = podmanTest.Podman([]string{"cp", "file.tar", "testctr:/foo/"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) @@ -158,4 +161,27 @@ var _ = Describe("Podman cp", func() { os.Remove("file.tar") os.RemoveAll(testDirPath) }) + + It("podman cp symlink", func() { + srcPath := filepath.Join(podmanTest.RunRoot, "cp_test.txt") + fromHostToContainer := []byte("copy from host to container") + err := ioutil.WriteFile(srcPath, fromHostToContainer, 0644) + Expect(err).To(BeNil()) + + session := podmanTest.Podman([]string{"run", "-d", ALPINE, "top"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + name := session.OutputToString() + + session = podmanTest.Podman([]string{"exec", name, "ln", "-s", "/tmp", "/test"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + + session = podmanTest.Podman([]string{"cp", "--pause=false", srcPath, name + ":/test"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + + _, err = os.Stat("/tmp/cp_test.txt") + Expect(err).To(Not(BeNil())) + }) }) diff --git a/test/e2e/create_staticip_test.go b/test/e2e/create_staticip_test.go index 6c4ca1cb8..11301856b 100644 --- a/test/e2e/create_staticip_test.go +++ b/test/e2e/create_staticip_test.go @@ -25,7 +25,7 @@ var _ = Describe("Podman create with --ip flag", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreAllArtifacts() + podmanTest.SeedImages() // Cleanup the CNI networks used by the tests os.RemoveAll("/var/lib/cni/networks/podman") }) diff --git a/test/e2e/create_test.go b/test/e2e/create_test.go index f3367337e..e2b4a7cf4 100644 --- a/test/e2e/create_test.go +++ b/test/e2e/create_test.go @@ -24,7 +24,7 @@ var _ = Describe("Podman create", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreAllArtifacts() + podmanTest.SeedImages() }) AfterEach(func() { diff --git a/test/e2e/diff_test.go b/test/e2e/diff_test.go index 920b920c0..0f53d9bc8 100644 --- a/test/e2e/diff_test.go +++ b/test/e2e/diff_test.go @@ -23,7 +23,7 @@ var _ = Describe("Podman diff", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreAllArtifacts() + podmanTest.SeedImages() }) AfterEach(func() { diff --git a/test/e2e/events_test.go b/test/e2e/events_test.go index 5ac5c9860..c5eedda3c 100644 --- a/test/e2e/events_test.go +++ b/test/e2e/events_test.go @@ -23,7 +23,7 @@ var _ = Describe("Podman events", func() { os.Exit(1) } podmanTest = PodmanTestCreate(tempdir) - podmanTest.RestoreAllArtifacts() + podmanTest.SeedImages() }) AfterEach(func() { diff --git a/test/e2e/exec_test.go b/test/e2e/exec_test.go index 2a10e52b1..f42831ebb 100644 --- a/test/e2e/exec_test.go +++ b/test/e2e/exec_test.go @@ -24,7 +24,7 @@ var _ = Describe("Podman exec", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreAllArtifacts() + podmanTest.SeedImages() }) AfterEach(func() { @@ -123,7 +123,6 @@ var _ = Describe("Podman exec", func() { }) It("podman exec with user only in container", func() { - podmanTest.RestoreArtifact(fedoraMinimal) testUser := "test123" setup := podmanTest.Podman([]string{"run", "--name", "test1", "-d", fedoraMinimal, "sleep", "60"}) setup.WaitWithDefaultTimeout() diff --git a/test/e2e/exists_test.go b/test/e2e/exists_test.go index 71c6c1820..1486427c5 100644 --- a/test/e2e/exists_test.go +++ b/test/e2e/exists_test.go @@ -48,7 +48,6 @@ var _ = Describe("Podman image|container exists", func() { Expect(session.ExitCode()).To(Equal(1)) }) It("podman container exists in local storage by name", func() { - SkipIfRemote() setup := podmanTest.RunTopContainer("foobar") setup.WaitWithDefaultTimeout() Expect(setup.ExitCode()).To(Equal(0)) @@ -58,7 +57,6 @@ var _ = Describe("Podman image|container exists", func() { Expect(session.ExitCode()).To(Equal(0)) }) It("podman container exists in local storage by container ID", func() { - SkipIfRemote() setup := podmanTest.RunTopContainer("") setup.WaitWithDefaultTimeout() Expect(setup.ExitCode()).To(Equal(0)) @@ -69,7 +67,6 @@ var _ = Describe("Podman image|container exists", func() { Expect(session.ExitCode()).To(Equal(0)) }) It("podman container exists in local storage by short container ID", func() { - SkipIfRemote() setup := podmanTest.RunTopContainer("") setup.WaitWithDefaultTimeout() Expect(setup.ExitCode()).To(Equal(0)) @@ -80,14 +77,12 @@ var _ = Describe("Podman image|container exists", func() { Expect(session.ExitCode()).To(Equal(0)) }) It("podman container does not exist in local storage", func() { - SkipIfRemote() session := podmanTest.Podman([]string{"container", "exists", "foobar"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(1)) }) It("podman pod exists in local storage by name", func() { - SkipIfRemote() setup, rc, _ := podmanTest.CreatePod("foobar") setup.WaitWithDefaultTimeout() Expect(rc).To(Equal(0)) @@ -97,7 +92,6 @@ var _ = Describe("Podman image|container exists", func() { Expect(session.ExitCode()).To(Equal(0)) }) It("podman pod exists in local storage by container ID", func() { - SkipIfRemote() setup, rc, podID := podmanTest.CreatePod("") setup.WaitWithDefaultTimeout() Expect(rc).To(Equal(0)) @@ -107,7 +101,6 @@ var _ = Describe("Podman image|container exists", func() { Expect(session.ExitCode()).To(Equal(0)) }) It("podman pod exists in local storage by short container ID", func() { - SkipIfRemote() setup, rc, podID := podmanTest.CreatePod("") setup.WaitWithDefaultTimeout() Expect(rc).To(Equal(0)) @@ -117,6 +110,7 @@ var _ = Describe("Podman image|container exists", func() { Expect(session.ExitCode()).To(Equal(0)) }) It("podman pod does not exist in local storage", func() { + // The exit code for non-existing pod is incorrect (125 vs 1) SkipIfRemote() session := podmanTest.Podman([]string{"pod", "exists", "foobar"}) session.WaitWithDefaultTimeout() diff --git a/test/e2e/export_test.go b/test/e2e/export_test.go index 71ddb518a..8406b0e73 100644 --- a/test/e2e/export_test.go +++ b/test/e2e/export_test.go @@ -23,7 +23,7 @@ var _ = Describe("Podman export", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreAllArtifacts() + podmanTest.SeedImages() }) AfterEach(func() { diff --git a/test/e2e/generate_kube_test.go b/test/e2e/generate_kube_test.go index 2f0af7e5f..95d46476d 100644 --- a/test/e2e/generate_kube_test.go +++ b/test/e2e/generate_kube_test.go @@ -25,7 +25,7 @@ var _ = Describe("Podman generate kube", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreAllArtifacts() + podmanTest.SeedImages() }) AfterEach(func() { diff --git a/test/e2e/generate_systemd_test.go b/test/e2e/generate_systemd_test.go index 940e894bc..5bb040206 100644 --- a/test/e2e/generate_systemd_test.go +++ b/test/e2e/generate_systemd_test.go @@ -23,7 +23,7 @@ var _ = Describe("Podman generate systemd", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreAllArtifacts() + podmanTest.SeedImages() }) AfterEach(func() { diff --git a/test/e2e/healthcheck_run_test.go b/test/e2e/healthcheck_run_test.go index 60be86ebc..be54cf1bd 100644 --- a/test/e2e/healthcheck_run_test.go +++ b/test/e2e/healthcheck_run_test.go @@ -24,7 +24,8 @@ var _ = Describe("Podman healthcheck run", func() { os.Exit(1) } podmanTest = PodmanTestCreate(tempdir) - podmanTest.RestoreAllArtifacts() + podmanTest.Setup() + podmanTest.SeedImages() }) AfterEach(func() { @@ -42,7 +43,6 @@ var _ = Describe("Podman healthcheck run", func() { }) It("podman healthcheck on valid container", func() { - podmanTest.RestoreArtifact(healthcheck) session := podmanTest.Podman([]string{"run", "-dt", "--name", "hc", healthcheck}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) @@ -63,7 +63,6 @@ var _ = Describe("Podman healthcheck run", func() { }) It("podman healthcheck on stopped container", func() { - podmanTest.RestoreArtifact(healthcheck) session := podmanTest.Podman([]string{"run", "-dt", "--name", "hc", healthcheck, "ls"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) diff --git a/test/e2e/history_test.go b/test/e2e/history_test.go index 9e519dd9c..231e8b856 100644 --- a/test/e2e/history_test.go +++ b/test/e2e/history_test.go @@ -22,7 +22,7 @@ var _ = Describe("Podman history", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreAllArtifacts() + podmanTest.SeedImages() }) AfterEach(func() { diff --git a/test/e2e/images_test.go b/test/e2e/images_test.go index 23455163b..07d61e885 100644 --- a/test/e2e/images_test.go +++ b/test/e2e/images_test.go @@ -25,7 +25,7 @@ var _ = Describe("Podman images", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreAllArtifacts() + podmanTest.SeedImages() }) AfterEach(func() { @@ -44,14 +44,15 @@ var _ = Describe("Podman images", func() { }) It("podman images with no images prints header", func() { - rmi := podmanTest.Podman([]string{"rmi", "-a"}) + rmi := podmanTest.PodmanNoCache([]string{"rmi", "-a"}) rmi.WaitWithDefaultTimeout() Expect(rmi.ExitCode()).To(Equal(0)) - session := podmanTest.Podman([]string{"images"}) + session := podmanTest.PodmanNoCache([]string{"images"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) Expect(len(session.OutputToStringArray())).To(Equal(1)) + Expect(session.LineInOutputContains("REPOSITORY")).To(BeTrue()) }) It("podman image List", func() { @@ -65,15 +66,16 @@ var _ = Describe("Podman images", func() { It("podman images with multiple tags", func() { // tag "docker.io/library/alpine:latest" to "foo:{a,b,c}" - session := podmanTest.Podman([]string{"tag", ALPINE, "foo:a", "foo:b", "foo:c"}) + podmanTest.RestoreAllArtifacts() + session := podmanTest.PodmanNoCache([]string{"tag", ALPINE, "foo:a", "foo:b", "foo:c"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) // tag "foo:c" to "bar:{a,b}" - session = podmanTest.Podman([]string{"tag", "foo:c", "bar:a", "bar:b"}) + session = podmanTest.PodmanNoCache([]string{"tag", "foo:c", "bar:a", "bar:b"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) // check all previous and the newly tagged images - session = podmanTest.Podman([]string{"images"}) + session = podmanTest.PodmanNoCache([]string{"images"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) session.LineInOutputContainsTag("docker.io/library/alpine", "latest") @@ -83,7 +85,7 @@ var _ = Describe("Podman images", func() { session.LineInOutputContainsTag("foo", "c") session.LineInOutputContainsTag("bar", "a") session.LineInOutputContainsTag("bar", "b") - session = podmanTest.Podman([]string{"images", "-qn"}) + session = podmanTest.PodmanNoCache([]string{"images", "-qn"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) Expect(len(session.OutputToStringArray())).To(BeNumerically("==", 2)) @@ -119,19 +121,20 @@ var _ = Describe("Podman images", func() { }) It("podman images filter by image name", func() { - session := podmanTest.Podman([]string{"images", "-q", ALPINE}) + podmanTest.RestoreAllArtifacts() + session := podmanTest.PodmanNoCache([]string{"images", "-q", ALPINE}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) Expect(len(session.OutputToStringArray())).To(Equal(1)) - session = podmanTest.Podman([]string{"tag", ALPINE, "foo:a"}) + session = podmanTest.PodmanNoCache([]string{"tag", ALPINE, "foo:a"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - session = podmanTest.Podman([]string{"tag", BB, "foo:b"}) + session = podmanTest.PodmanNoCache([]string{"tag", BB, "foo:b"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - session = podmanTest.Podman([]string{"images", "-q", "foo"}) + session = podmanTest.PodmanNoCache([]string{"images", "-q", "foo"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) Expect(len(session.OutputToStringArray())).To(Equal(2)) @@ -141,24 +144,25 @@ var _ = Describe("Podman images", func() { if podmanTest.RemoteTest { Skip("Does not work on remote client") } - result := podmanTest.Podman([]string{"images", "-q", "-f", "reference=docker.io*"}) + podmanTest.RestoreAllArtifacts() + result := podmanTest.PodmanNoCache([]string{"images", "-q", "-f", "reference=docker.io*"}) result.WaitWithDefaultTimeout() Expect(result.ExitCode()).To(Equal(0)) Expect(len(result.OutputToStringArray())).To(Equal(2)) - retapline := podmanTest.Podman([]string{"images", "-f", "reference=a*pine"}) + retapline := podmanTest.PodmanNoCache([]string{"images", "-f", "reference=a*pine"}) retapline.WaitWithDefaultTimeout() Expect(retapline.ExitCode()).To(Equal(0)) Expect(len(retapline.OutputToStringArray())).To(Equal(2)) Expect(retapline.LineInOutputContains("alpine")) - retapline = podmanTest.Podman([]string{"images", "-f", "reference=alpine"}) + retapline = podmanTest.PodmanNoCache([]string{"images", "-f", "reference=alpine"}) retapline.WaitWithDefaultTimeout() Expect(retapline.ExitCode()).To(Equal(0)) Expect(len(retapline.OutputToStringArray())).To(Equal(2)) Expect(retapline.LineInOutputContains("alpine")) - retnone := podmanTest.Podman([]string{"images", "-q", "-f", "reference=bogus"}) + retnone := podmanTest.PodmanNoCache([]string{"images", "-q", "-f", "reference=bogus"}) retnone.WaitWithDefaultTimeout() Expect(retnone.ExitCode()).To(Equal(0)) Expect(len(retnone.OutputToStringArray())).To(Equal(0)) @@ -182,14 +186,15 @@ RUN apk update && apk add man if podmanTest.RemoteTest { Skip("Does not work on remote client") } - rmi := podmanTest.Podman([]string{"rmi", "busybox"}) + podmanTest.RestoreAllArtifacts() + rmi := podmanTest.PodmanNoCache([]string{"rmi", "busybox"}) rmi.WaitWithDefaultTimeout() Expect(rmi.ExitCode()).To(Equal(0)) dockerfile := `FROM docker.io/library/alpine:latest ` podmanTest.BuildImage(dockerfile, "foobar.com/before:latest", "false") - result := podmanTest.Podman([]string{"images", "-q", "-f", "after=docker.io/library/alpine:latest"}) + result := podmanTest.PodmanNoCache([]string{"images", "-q", "-f", "after=docker.io/library/alpine:latest"}) result.WaitWithDefaultTimeout() Expect(result.ExitCode()).To(Equal(0)) Expect(len(result.OutputToStringArray())).To(Equal(0)) @@ -199,14 +204,15 @@ RUN apk update && apk add man if podmanTest.RemoteTest { Skip("Does not work on remote client") } - rmi := podmanTest.Podman([]string{"image", "rm", "busybox"}) + podmanTest.RestoreAllArtifacts() + rmi := podmanTest.PodmanNoCache([]string{"image", "rm", "busybox"}) rmi.WaitWithDefaultTimeout() Expect(rmi.ExitCode()).To(Equal(0)) dockerfile := `FROM docker.io/library/alpine:latest ` podmanTest.BuildImage(dockerfile, "foobar.com/before:latest", "false") - result := podmanTest.Podman([]string{"image", "list", "-q", "-f", "after=docker.io/library/alpine:latest"}) + result := podmanTest.PodmanNoCache([]string{"image", "list", "-q", "-f", "after=docker.io/library/alpine:latest"}) result.WaitWithDefaultTimeout() Expect(result.ExitCode()).To(Equal(0)) Expect(len(result.OutputToStringArray())).To(Equal(0)) @@ -282,18 +288,19 @@ RUN apk update && apk add man if podmanTest.RemoteTest { Skip("Does not work on remote client") } + podmanTest.RestoreAllArtifacts() dockerfile := `FROM docker.io/library/alpine:latest RUN mkdir hello RUN touch test.txt ENV foo=bar ` podmanTest.BuildImage(dockerfile, "test", "true") - session := podmanTest.Podman([]string{"images"}) + session := podmanTest.PodmanNoCache([]string{"images"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) Expect(len(session.OutputToStringArray())).To(Equal(4)) - session2 := podmanTest.Podman([]string{"images", "--all"}) + session2 := podmanTest.PodmanNoCache([]string{"images", "--all"}) session2.WaitWithDefaultTimeout() Expect(session2.ExitCode()).To(Equal(0)) Expect(len(session2.OutputToStringArray())).To(Equal(6)) diff --git a/test/e2e/import_test.go b/test/e2e/import_test.go index e819d819c..84a91a783 100644 --- a/test/e2e/import_test.go +++ b/test/e2e/import_test.go @@ -25,7 +25,7 @@ var _ = Describe("Podman import", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreAllArtifacts() + podmanTest.SeedImages() }) AfterEach(func() { @@ -62,14 +62,11 @@ var _ = Describe("Podman import", func() { export.WaitWithDefaultTimeout() Expect(export.ExitCode()).To(Equal(0)) - importImage := podmanTest.Podman([]string{"import", outfile}) + importImage := podmanTest.PodmanNoCache([]string{"import", outfile}) importImage.WaitWithDefaultTimeout() Expect(importImage.ExitCode()).To(Equal(0)) - results := podmanTest.Podman([]string{"images", "-q"}) - results.WaitWithDefaultTimeout() - Expect(results.ExitCode()).To(Equal(0)) - Expect(len(results.OutputToStringArray())).To(Equal(3)) + Expect(podmanTest.ImageExistsInMainStore(importImage.OutputToString())).To(BeTrue()) }) It("podman import with message flag", func() { diff --git a/test/e2e/init_test.go b/test/e2e/init_test.go index 5865930a5..919fe4abf 100644 --- a/test/e2e/init_test.go +++ b/test/e2e/init_test.go @@ -22,7 +22,7 @@ var _ = Describe("Podman init", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreAllArtifacts() + podmanTest.SeedImages() }) AfterEach(func() { diff --git a/test/e2e/inspect_test.go b/test/e2e/inspect_test.go index 34328828f..ccd8602c4 100644 --- a/test/e2e/inspect_test.go +++ b/test/e2e/inspect_test.go @@ -23,7 +23,7 @@ var _ = Describe("Podman inspect", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreAllArtifacts() + podmanTest.SeedImages() }) AfterEach(func() { diff --git a/test/e2e/kill_test.go b/test/e2e/kill_test.go index 3286180a4..017fe4a3f 100644 --- a/test/e2e/kill_test.go +++ b/test/e2e/kill_test.go @@ -22,7 +22,7 @@ var _ = Describe("Podman kill", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreAllArtifacts() + podmanTest.SeedImages() }) AfterEach(func() { diff --git a/test/e2e/libpod_suite_remoteclient_test.go b/test/e2e/libpod_suite_remoteclient_test.go index b7fd8537d..c8210f7d1 100644 --- a/test/e2e/libpod_suite_remoteclient_test.go +++ b/test/e2e/libpod_suite_remoteclient_test.go @@ -30,7 +30,13 @@ func SkipIfRootless() { // Podman is the exec call to podman on the filesystem func (p *PodmanTestIntegration) Podman(args []string) *PodmanSessionIntegration { - podmanSession := p.PodmanBase(args) + podmanSession := p.PodmanBase(args, false) + return &PodmanSessionIntegration{podmanSession} +} + +// PodmanNoCache calls podman with out adding the imagecache +func (p *PodmanTestIntegration) PodmanNoCache(args []string) *PodmanSessionIntegration { + podmanSession := p.PodmanBase(args, true) return &PodmanSessionIntegration{podmanSession} } @@ -145,6 +151,21 @@ func getVarlinkOptions(p *PodmanTestIntegration, args []string) []string { return podmanOptions } +func (p *PodmanTestIntegration) RestoreArtifactToCache(image string) error { + fmt.Printf("Restoring %s...\n", image) + dest := strings.Split(image, "/") + destName := fmt.Sprintf("/tmp/%s.tar", strings.Replace(strings.Join(strings.Split(dest[len(dest)-1], "/"), ""), ":", "-", -1)) + p.CrioRoot = p.ImageCacheDir + restore := p.PodmanNoCache([]string{"load", "-q", "-i", destName}) + restore.WaitWithDefaultTimeout() + return nil +} + +// SeedImages restores all the artifacts into the main store for remote tests +func (p *PodmanTestIntegration) SeedImages() error { + return p.RestoreAllArtifacts() +} + // RestoreArtifact puts the cached image into our test store func (p *PodmanTestIntegration) RestoreArtifact(image string) error { fmt.Printf("Restoring %s...\n", image) @@ -169,3 +190,6 @@ func (p *PodmanTestIntegration) DelayForVarlink() { time.Sleep(1 * time.Second) } } + +func populateCache(podman *PodmanTestIntegration) {} +func removeCache() {} diff --git a/test/e2e/libpod_suite_test.go b/test/e2e/libpod_suite_test.go index 0a85c625d..8d993ee72 100644 --- a/test/e2e/libpod_suite_test.go +++ b/test/e2e/libpod_suite_test.go @@ -23,13 +23,19 @@ func SkipIfRootless() { // Podman is the exec call to podman on the filesystem func (p *PodmanTestIntegration) Podman(args []string) *PodmanSessionIntegration { - podmanSession := p.PodmanBase(args) + podmanSession := p.PodmanBase(args, false) + return &PodmanSessionIntegration{podmanSession} +} + +// PodmanNoCache calls the podman command with no configured imagecache +func (p *PodmanTestIntegration) PodmanNoCache(args []string) *PodmanSessionIntegration { + podmanSession := p.PodmanBase(args, true) return &PodmanSessionIntegration{podmanSession} } // PodmanAsUser is the exec call to podman on the filesystem with the specified uid/gid and environment func (p *PodmanTestIntegration) PodmanAsUser(args []string, uid, gid uint32, cwd string, env []string) *PodmanSessionIntegration { - podmanSession := p.PodmanAsUserBase(args, uid, gid, cwd, env) + podmanSession := p.PodmanAsUserBase(args, uid, gid, cwd, env, false) return &PodmanSessionIntegration{podmanSession} } @@ -75,9 +81,40 @@ func (p *PodmanTestIntegration) RestoreArtifact(image string) error { fmt.Printf("Restoring %s...\n", image) dest := strings.Split(image, "/") destName := fmt.Sprintf("/tmp/%s.tar", strings.Replace(strings.Join(strings.Split(dest[len(dest)-1], "/"), ""), ":", "-", -1)) - restore := p.Podman([]string{"load", "-q", "-i", destName}) + restore := p.PodmanNoCache([]string{"load", "-q", "-i", destName}) restore.Wait(90) return nil } + +// RestoreArtifactToCache populates the imagecache from tarballs that were cached earlier +func (p *PodmanTestIntegration) RestoreArtifactToCache(image string) error { + fmt.Printf("Restoring %s...\n", image) + dest := strings.Split(image, "/") + destName := fmt.Sprintf("/tmp/%s.tar", strings.Replace(strings.Join(strings.Split(dest[len(dest)-1], "/"), ""), ":", "-", -1)) + + p.CrioRoot = p.ImageCacheDir + restore := p.PodmanNoCache([]string{"load", "-q", "-i", destName}) + restore.WaitWithDefaultTimeout() + return nil +} + func (p *PodmanTestIntegration) StopVarlink() {} func (p *PodmanTestIntegration) DelayForVarlink() {} + +func populateCache(podman *PodmanTestIntegration) { + for _, image := range CACHE_IMAGES { + podman.RestoreArtifactToCache(image) + } +} + +func removeCache() { + // Remove cache dirs + if err := os.RemoveAll(ImageCacheDir); err != nil { + fmt.Printf("%q\n", err) + } +} + +// SeedImages is a no-op for localized testing +func (p *PodmanTestIntegration) SeedImages() error { + return nil +} diff --git a/test/e2e/load_test.go b/test/e2e/load_test.go index 0e193640e..9209e1770 100644 --- a/test/e2e/load_test.go +++ b/test/e2e/load_test.go @@ -3,6 +3,7 @@ package integration import ( + "fmt" "os" "path/filepath" @@ -38,7 +39,11 @@ var _ = Describe("Podman load", func() { It("podman load input flag", func() { outfile := filepath.Join(podmanTest.TempDir, "alpine.tar") - save := podmanTest.Podman([]string{"save", "-o", outfile, ALPINE}) + images := podmanTest.PodmanNoCache([]string{"images"}) + images.WaitWithDefaultTimeout() + fmt.Println(images.OutputToStringArray()) + + save := podmanTest.PodmanNoCache([]string{"save", "-o", outfile, ALPINE}) save.WaitWithDefaultTimeout() Expect(save.ExitCode()).To(Equal(0)) @@ -46,7 +51,7 @@ var _ = Describe("Podman load", func() { rmi.WaitWithDefaultTimeout() Expect(rmi.ExitCode()).To(Equal(0)) - result := podmanTest.Podman([]string{"load", "-i", outfile}) + result := podmanTest.PodmanNoCache([]string{"load", "-i", outfile}) result.WaitWithDefaultTimeout() Expect(result.ExitCode()).To(Equal(0)) }) @@ -54,7 +59,7 @@ var _ = Describe("Podman load", func() { It("podman load compressed tar file", func() { outfile := filepath.Join(podmanTest.TempDir, "alpine.tar") - save := podmanTest.Podman([]string{"save", "-o", outfile, ALPINE}) + save := podmanTest.PodmanNoCache([]string{"save", "-o", outfile, ALPINE}) save.WaitWithDefaultTimeout() Expect(save.ExitCode()).To(Equal(0)) @@ -62,11 +67,11 @@ var _ = Describe("Podman load", func() { Expect(compress.ExitCode()).To(Equal(0)) outfile = outfile + ".gz" - rmi := podmanTest.Podman([]string{"rmi", ALPINE}) + rmi := podmanTest.PodmanNoCache([]string{"rmi", ALPINE}) rmi.WaitWithDefaultTimeout() Expect(rmi.ExitCode()).To(Equal(0)) - result := podmanTest.Podman([]string{"load", "-i", outfile}) + result := podmanTest.PodmanNoCache([]string{"load", "-i", outfile}) result.WaitWithDefaultTimeout() Expect(result.ExitCode()).To(Equal(0)) }) @@ -74,15 +79,15 @@ var _ = Describe("Podman load", func() { It("podman load oci-archive image", func() { outfile := filepath.Join(podmanTest.TempDir, "alpine.tar") - save := podmanTest.Podman([]string{"save", "-o", outfile, "--format", "oci-archive", ALPINE}) + save := podmanTest.PodmanNoCache([]string{"save", "-o", outfile, "--format", "oci-archive", ALPINE}) save.WaitWithDefaultTimeout() Expect(save.ExitCode()).To(Equal(0)) - rmi := podmanTest.Podman([]string{"rmi", ALPINE}) + rmi := podmanTest.PodmanNoCache([]string{"rmi", ALPINE}) rmi.WaitWithDefaultTimeout() Expect(rmi.ExitCode()).To(Equal(0)) - result := podmanTest.Podman([]string{"load", "-i", outfile}) + result := podmanTest.PodmanNoCache([]string{"load", "-i", outfile}) result.WaitWithDefaultTimeout() Expect(result.ExitCode()).To(Equal(0)) }) @@ -90,15 +95,15 @@ var _ = Describe("Podman load", func() { It("podman load oci-archive with signature", func() { outfile := filepath.Join(podmanTest.TempDir, "alpine.tar") - save := podmanTest.Podman([]string{"save", "-o", outfile, "--format", "oci-archive", ALPINE}) + save := podmanTest.PodmanNoCache([]string{"save", "-o", outfile, "--format", "oci-archive", ALPINE}) save.WaitWithDefaultTimeout() Expect(save.ExitCode()).To(Equal(0)) - rmi := podmanTest.Podman([]string{"rmi", ALPINE}) + rmi := podmanTest.PodmanNoCache([]string{"rmi", ALPINE}) rmi.WaitWithDefaultTimeout() Expect(rmi.ExitCode()).To(Equal(0)) - result := podmanTest.Podman([]string{"load", "--signature-policy", "/etc/containers/policy.json", "-i", outfile}) + result := podmanTest.PodmanNoCache([]string{"load", "--signature-policy", "/etc/containers/policy.json", "-i", outfile}) result.WaitWithDefaultTimeout() Expect(result.ExitCode()).To(Equal(0)) }) @@ -106,15 +111,15 @@ var _ = Describe("Podman load", func() { It("podman load with quiet flag", func() { outfile := filepath.Join(podmanTest.TempDir, "alpine.tar") - save := podmanTest.Podman([]string{"save", "-o", outfile, ALPINE}) + save := podmanTest.PodmanNoCache([]string{"save", "-o", outfile, ALPINE}) save.WaitWithDefaultTimeout() Expect(save.ExitCode()).To(Equal(0)) - rmi := podmanTest.Podman([]string{"rmi", ALPINE}) + rmi := podmanTest.PodmanNoCache([]string{"rmi", ALPINE}) rmi.WaitWithDefaultTimeout() Expect(rmi.ExitCode()).To(Equal(0)) - result := podmanTest.Podman([]string{"load", "-q", "-i", outfile}) + result := podmanTest.PodmanNoCache([]string{"load", "-q", "-i", outfile}) result.WaitWithDefaultTimeout() Expect(result.ExitCode()).To(Equal(0)) }) @@ -122,7 +127,7 @@ var _ = Describe("Podman load", func() { It("podman load directory", func() { outdir := filepath.Join(podmanTest.TempDir, "alpine") - save := podmanTest.Podman([]string{"save", "--format", "oci-dir", "-o", outdir, ALPINE}) + save := podmanTest.PodmanNoCache([]string{"save", "--format", "oci-dir", "-o", outdir, ALPINE}) save.WaitWithDefaultTimeout() Expect(save.ExitCode()).To(Equal(0)) @@ -136,7 +141,7 @@ var _ = Describe("Podman load", func() { }) It("podman load bogus file", func() { - save := podmanTest.Podman([]string{"load", "-i", "foobar.tar"}) + save := podmanTest.PodmanNoCache([]string{"load", "-i", "foobar.tar"}) save.WaitWithDefaultTimeout() Expect(save.ExitCode()).ToNot(Equal(0)) }) @@ -148,75 +153,75 @@ var _ = Describe("Podman load", func() { outfile := filepath.Join(podmanTest.TempDir, "alpine.tar") alpVersion := "docker.io/library/alpine:3.2" - pull := podmanTest.Podman([]string{"pull", alpVersion}) + pull := podmanTest.PodmanNoCache([]string{"pull", alpVersion}) pull.WaitWithDefaultTimeout() Expect(pull.ExitCode()).To(Equal(0)) - save := podmanTest.Podman([]string{"save", "-o", outfile, ALPINE, alpVersion}) + save := podmanTest.PodmanNoCache([]string{"save", "-o", outfile, ALPINE, alpVersion}) save.WaitWithDefaultTimeout() Expect(save.ExitCode()).To(Equal(0)) - rmi := podmanTest.Podman([]string{"rmi", ALPINE, alpVersion}) + rmi := podmanTest.PodmanNoCache([]string{"rmi", ALPINE, alpVersion}) rmi.WaitWithDefaultTimeout() Expect(rmi.ExitCode()).To(Equal(0)) - result := podmanTest.Podman([]string{"load", "-i", outfile}) + result := podmanTest.PodmanNoCache([]string{"load", "-i", outfile}) result.WaitWithDefaultTimeout() Expect(result.ExitCode()).To(Equal(0)) - inspect := podmanTest.Podman([]string{"inspect", ALPINE}) + inspect := podmanTest.PodmanNoCache([]string{"inspect", ALPINE}) inspect.WaitWithDefaultTimeout() Expect(result.ExitCode()).To(Equal(0)) - inspect = podmanTest.Podman([]string{"inspect", alpVersion}) + inspect = podmanTest.PodmanNoCache([]string{"inspect", alpVersion}) inspect.WaitWithDefaultTimeout() Expect(result.ExitCode()).To(Equal(0)) }) It("podman load localhost registry from scratch", func() { outfile := filepath.Join(podmanTest.TempDir, "load_test.tar.gz") - setup := podmanTest.Podman([]string{"tag", ALPINE, "hello:world"}) + setup := podmanTest.PodmanNoCache([]string{"tag", ALPINE, "hello:world"}) setup.WaitWithDefaultTimeout() Expect(setup.ExitCode()).To(Equal(0)) - setup = podmanTest.Podman([]string{"save", "-o", outfile, "--format", "oci-archive", "hello:world"}) + setup = podmanTest.PodmanNoCache([]string{"save", "-o", outfile, "--format", "oci-archive", "hello:world"}) setup.WaitWithDefaultTimeout() Expect(setup.ExitCode()).To(Equal(0)) - setup = podmanTest.Podman([]string{"rmi", "hello:world"}) + setup = podmanTest.PodmanNoCache([]string{"rmi", "hello:world"}) setup.WaitWithDefaultTimeout() Expect(setup.ExitCode()).To(Equal(0)) - load := podmanTest.Podman([]string{"load", "-i", outfile}) + load := podmanTest.PodmanNoCache([]string{"load", "-i", outfile}) load.WaitWithDefaultTimeout() Expect(load.ExitCode()).To(Equal(0)) - result := podmanTest.Podman([]string{"images", "hello:world"}) + result := podmanTest.PodmanNoCache([]string{"images", "hello:world"}) result.WaitWithDefaultTimeout() Expect(result.LineInOutputContains("docker")).To(Not(BeTrue())) Expect(result.LineInOutputContains("localhost")).To(BeTrue()) }) It("podman load localhost registry from scratch and :latest", func() { + podmanTest.RestoreArtifact(fedoraMinimal) outfile := filepath.Join(podmanTest.TempDir, "load_test.tar.gz") - podmanTest.RestoreArtifact("fedora-minimal:latest") - setup := podmanTest.Podman([]string{"tag", "fedora-minimal", "hello"}) + setup := podmanTest.PodmanNoCache([]string{"tag", "fedora-minimal", "hello"}) setup.WaitWithDefaultTimeout() Expect(setup.ExitCode()).To(Equal(0)) - setup = podmanTest.Podman([]string{"save", "-o", outfile, "--format", "oci-archive", "hello"}) + setup = podmanTest.PodmanNoCache([]string{"save", "-o", outfile, "--format", "oci-archive", "hello"}) setup.WaitWithDefaultTimeout() Expect(setup.ExitCode()).To(Equal(0)) - setup = podmanTest.Podman([]string{"rmi", "hello"}) + setup = podmanTest.PodmanNoCache([]string{"rmi", "hello"}) setup.WaitWithDefaultTimeout() Expect(setup.ExitCode()).To(Equal(0)) - load := podmanTest.Podman([]string{"load", "-i", outfile}) + load := podmanTest.PodmanNoCache([]string{"load", "-i", outfile}) load.WaitWithDefaultTimeout() Expect(load.ExitCode()).To(Equal(0)) - result := podmanTest.Podman([]string{"images", "hello:latest"}) + result := podmanTest.PodmanNoCache([]string{"images", "hello:latest"}) result.WaitWithDefaultTimeout() Expect(result.LineInOutputContains("docker")).To(Not(BeTrue())) Expect(result.LineInOutputContains("localhost")).To(BeTrue()) @@ -225,23 +230,23 @@ var _ = Describe("Podman load", func() { It("podman load localhost registry from dir", func() { outfile := filepath.Join(podmanTest.TempDir, "load") - setup := podmanTest.Podman([]string{"tag", BB, "hello:world"}) + setup := podmanTest.PodmanNoCache([]string{"tag", BB, "hello:world"}) setup.WaitWithDefaultTimeout() Expect(setup.ExitCode()).To(Equal(0)) - setup = podmanTest.Podman([]string{"save", "-o", outfile, "--format", "oci-dir", "hello:world"}) + setup = podmanTest.PodmanNoCache([]string{"save", "-o", outfile, "--format", "oci-dir", "hello:world"}) setup.WaitWithDefaultTimeout() Expect(setup.ExitCode()).To(Equal(0)) - setup = podmanTest.Podman([]string{"rmi", "hello:world"}) + setup = podmanTest.PodmanNoCache([]string{"rmi", "hello:world"}) setup.WaitWithDefaultTimeout() Expect(setup.ExitCode()).To(Equal(0)) - load := podmanTest.Podman([]string{"load", "-i", outfile}) + load := podmanTest.PodmanNoCache([]string{"load", "-i", outfile}) load.WaitWithDefaultTimeout() Expect(load.ExitCode()).To(Equal(0)) - result := podmanTest.Podman([]string{"images", "load:latest"}) + result := podmanTest.PodmanNoCache([]string{"images", "load:latest"}) result.WaitWithDefaultTimeout() Expect(result.LineInOutputContains("docker")).To(Not(BeTrue())) Expect(result.LineInOutputContains("localhost")).To(BeTrue()) @@ -250,17 +255,17 @@ var _ = Describe("Podman load", func() { It("podman load xz compressed image", func() { outfile := filepath.Join(podmanTest.TempDir, "bb.tar") - save := podmanTest.Podman([]string{"save", "-o", outfile, BB}) + save := podmanTest.PodmanNoCache([]string{"save", "-o", outfile, BB}) save.WaitWithDefaultTimeout() Expect(save.ExitCode()).To(Equal(0)) session := SystemExec("xz", []string{outfile}) Expect(session.ExitCode()).To(Equal(0)) - rmi := podmanTest.Podman([]string{"rmi", BB}) + rmi := podmanTest.PodmanNoCache([]string{"rmi", BB}) rmi.WaitWithDefaultTimeout() Expect(rmi.ExitCode()).To(Equal(0)) - result := podmanTest.Podman([]string{"load", "-i", outfile + ".xz"}) + result := podmanTest.PodmanNoCache([]string{"load", "-i", outfile + ".xz"}) result.WaitWithDefaultTimeout() Expect(result.ExitCode()).To(Equal(0)) }) diff --git a/test/e2e/logs_test.go b/test/e2e/logs_test.go index 2c82182cf..cc50c4d95 100644 --- a/test/e2e/logs_test.go +++ b/test/e2e/logs_test.go @@ -23,7 +23,7 @@ var _ = Describe("Podman logs", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreAllArtifacts() + podmanTest.SeedImages() }) AfterEach(func() { @@ -140,4 +140,82 @@ var _ = Describe("Podman logs", func() { results.WaitWithDefaultTimeout() Expect(results.ExitCode()).To(BeZero()) }) + + It("podman journald logs for container", func() { + Skip("need to verify images have correct packages for journald") + logc := podmanTest.Podman([]string{"run", "--log-driver", "journald", "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) + logc.WaitWithDefaultTimeout() + Expect(logc.ExitCode()).To(Equal(0)) + cid := logc.OutputToString() + + results := podmanTest.Podman([]string{"logs", cid}) + results.WaitWithDefaultTimeout() + Expect(results.ExitCode()).To(Equal(0)) + Expect(len(results.OutputToStringArray())).To(Equal(3)) + }) + + It("podman journald logs tail two lines", func() { + Skip("need to verify images have correct packages for journald") + logc := podmanTest.Podman([]string{"run", "--log-driver", "journald", "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) + logc.WaitWithDefaultTimeout() + Expect(logc.ExitCode()).To(Equal(0)) + cid := logc.OutputToString() + + results := podmanTest.Podman([]string{"logs", "--tail", "2", cid}) + results.WaitWithDefaultTimeout() + Expect(results.ExitCode()).To(Equal(0)) + Expect(len(results.OutputToStringArray())).To(Equal(2)) + }) + + It("podman journald logs tail 99 lines", func() { + Skip("need to verify images have correct packages for journald") + logc := podmanTest.Podman([]string{"run", "--log-driver", "journald", "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) + logc.WaitWithDefaultTimeout() + Expect(logc.ExitCode()).To(Equal(0)) + cid := logc.OutputToString() + + results := podmanTest.Podman([]string{"logs", "--tail", "99", cid}) + results.WaitWithDefaultTimeout() + Expect(results.ExitCode()).To(Equal(0)) + Expect(len(results.OutputToStringArray())).To(Equal(3)) + }) + + It("podman journald logs tail 2 lines with timestamps", func() { + Skip("need to verify images have correct packages for journald") + logc := podmanTest.Podman([]string{"run", "--log-driver", "journald", "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) + logc.WaitWithDefaultTimeout() + Expect(logc.ExitCode()).To(Equal(0)) + cid := logc.OutputToString() + + results := podmanTest.Podman([]string{"logs", "--tail", "2", "-t", cid}) + results.WaitWithDefaultTimeout() + Expect(results.ExitCode()).To(Equal(0)) + Expect(len(results.OutputToStringArray())).To(Equal(2)) + }) + + It("podman journald logs latest with since time", func() { + Skip("need to verify images have correct packages for journald") + logc := podmanTest.Podman([]string{"run", "--log-driver", "journald", "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) + logc.WaitWithDefaultTimeout() + Expect(logc.ExitCode()).To(Equal(0)) + cid := logc.OutputToString() + + results := podmanTest.Podman([]string{"logs", "--since", "2017-08-07T10:10:09.056611202-04:00", cid}) + results.WaitWithDefaultTimeout() + Expect(results.ExitCode()).To(Equal(0)) + Expect(len(results.OutputToStringArray())).To(Equal(3)) + }) + + It("podman journald logs latest with since duration", func() { + Skip("need to verify images have correct packages for journald") + logc := podmanTest.Podman([]string{"run", "--log-driver", "journald", "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) + logc.WaitWithDefaultTimeout() + Expect(logc.ExitCode()).To(Equal(0)) + cid := logc.OutputToString() + + results := podmanTest.Podman([]string{"logs", "--since", "10m", cid}) + results.WaitWithDefaultTimeout() + Expect(results.ExitCode()).To(Equal(0)) + Expect(len(results.OutputToStringArray())).To(Equal(3)) + }) }) diff --git a/test/e2e/mount_test.go b/test/e2e/mount_test.go index b361e0057..61abdf6fc 100644 --- a/test/e2e/mount_test.go +++ b/test/e2e/mount_test.go @@ -24,7 +24,7 @@ var _ = Describe("Podman mount", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreAllArtifacts() + podmanTest.SeedImages() }) AfterEach(func() { diff --git a/test/e2e/namespace_test.go b/test/e2e/namespace_test.go index 28d050be3..88b48cb06 100644 --- a/test/e2e/namespace_test.go +++ b/test/e2e/namespace_test.go @@ -24,7 +24,7 @@ var _ = Describe("Podman namespaces", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreAllArtifacts() + podmanTest.SeedImages() }) AfterEach(func() { diff --git a/test/e2e/pause_test.go b/test/e2e/pause_test.go index c47189a0e..01fb6d91b 100644 --- a/test/e2e/pause_test.go +++ b/test/e2e/pause_test.go @@ -27,7 +27,7 @@ var _ = Describe("Podman pause", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreAllArtifacts() + podmanTest.SeedImages() }) AfterEach(func() { @@ -249,7 +249,6 @@ var _ = Describe("Podman pause", func() { }) It("Pause a bunch of running containers", func() { - podmanTest.RestoreArtifact(nginx) for i := 0; i < 3; i++ { name := fmt.Sprintf("test%d", i) run := podmanTest.Podman([]string{"run", "-dt", "--name", name, nginx}) @@ -277,7 +276,6 @@ var _ = Describe("Podman pause", func() { }) It("Unpause a bunch of running containers", func() { - podmanTest.RestoreArtifact(nginx) for i := 0; i < 3; i++ { name := fmt.Sprintf("test%d", i) run := podmanTest.Podman([]string{"run", "-dt", "--name", name, nginx}) diff --git a/test/e2e/pod_create_test.go b/test/e2e/pod_create_test.go index 84966f77b..2efa36141 100644 --- a/test/e2e/pod_create_test.go +++ b/test/e2e/pod_create_test.go @@ -22,7 +22,7 @@ var _ = Describe("Podman pod create", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreAllArtifacts() + podmanTest.SeedImages() }) AfterEach(func() { diff --git a/test/e2e/pod_infra_container_test.go b/test/e2e/pod_infra_container_test.go index 82f35999c..c8763de9f 100644 --- a/test/e2e/pod_infra_container_test.go +++ b/test/e2e/pod_infra_container_test.go @@ -25,8 +25,7 @@ var _ = Describe("Podman pod create", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreAllArtifacts() - podmanTest.RestoreArtifact(infra) + podmanTest.SeedImages() }) AfterEach(func() { @@ -113,12 +112,10 @@ var _ = Describe("Podman pod create", func() { session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - podmanTest.RestoreArtifact(nginx) session = podmanTest.Podman([]string{"run", "-d", "--pod", podID, nginx}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - podmanTest.RestoreArtifact(fedoraMinimal) session = podmanTest.Podman([]string{"run", "--pod", podID, fedoraMinimal, "curl", "localhost:80"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) @@ -138,7 +135,6 @@ var _ = Describe("Podman pod create", func() { session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - podmanTest.RestoreArtifact(fedoraMinimal) session = podmanTest.Podman([]string{"run", "--pod", podID, fedoraMinimal, "/bin/sh", "-c", "'touch /dev/shm/hi'"}) session.WaitWithDefaultTimeout() if session.ExitCode() != 0 { @@ -216,7 +212,6 @@ var _ = Describe("Podman pod create", func() { session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - podmanTest.RestoreArtifact(nginx) session = podmanTest.Podman([]string{"run", "-d", "--pod", podID, nginx}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) diff --git a/test/e2e/pod_inspect_test.go b/test/e2e/pod_inspect_test.go index d1a023153..488dd1685 100644 --- a/test/e2e/pod_inspect_test.go +++ b/test/e2e/pod_inspect_test.go @@ -22,7 +22,7 @@ var _ = Describe("Podman pod inspect", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreAllArtifacts() + podmanTest.SeedImages() }) AfterEach(func() { diff --git a/test/e2e/pod_kill_test.go b/test/e2e/pod_kill_test.go index 23a8ea97e..7cf67bbfc 100644 --- a/test/e2e/pod_kill_test.go +++ b/test/e2e/pod_kill_test.go @@ -23,7 +23,7 @@ var _ = Describe("Podman pod kill", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreAllArtifacts() + podmanTest.SeedImages() }) AfterEach(func() { diff --git a/test/e2e/pod_pause_test.go b/test/e2e/pod_pause_test.go index ab828853b..619ee6f12 100644 --- a/test/e2e/pod_pause_test.go +++ b/test/e2e/pod_pause_test.go @@ -25,7 +25,7 @@ var _ = Describe("Podman pod pause", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreAllArtifacts() + podmanTest.SeedImages() }) AfterEach(func() { diff --git a/test/e2e/pod_pod_namespaces.go b/test/e2e/pod_pod_namespaces.go index 9d6321c0e..83c877f5a 100644 --- a/test/e2e/pod_pod_namespaces.go +++ b/test/e2e/pod_pod_namespaces.go @@ -25,8 +25,7 @@ var _ = Describe("Podman pod create", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreAllArtifacts() - podmanTest.RestoreArtifact(infra) + podmanTest.SeedImages() }) AfterEach(func() { diff --git a/test/e2e/pod_prune_test.go b/test/e2e/pod_prune_test.go index 8a4ba2399..da0d425cb 100644 --- a/test/e2e/pod_prune_test.go +++ b/test/e2e/pod_prune_test.go @@ -22,7 +22,7 @@ var _ = Describe("Podman pod prune", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreAllArtifacts() + podmanTest.SeedImages() }) AfterEach(func() { diff --git a/test/e2e/pod_ps_test.go b/test/e2e/pod_ps_test.go index 8513c6c2e..6d5873caa 100644 --- a/test/e2e/pod_ps_test.go +++ b/test/e2e/pod_ps_test.go @@ -24,7 +24,7 @@ var _ = Describe("Podman ps", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreAllArtifacts() + podmanTest.SeedImages() }) AfterEach(func() { diff --git a/test/e2e/pod_restart_test.go b/test/e2e/pod_restart_test.go index 7b19ecc94..691fe5f0c 100644 --- a/test/e2e/pod_restart_test.go +++ b/test/e2e/pod_restart_test.go @@ -22,7 +22,7 @@ var _ = Describe("Podman pod restart", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreAllArtifacts() + podmanTest.SeedImages() }) AfterEach(func() { diff --git a/test/e2e/pod_rm_test.go b/test/e2e/pod_rm_test.go index 7417a1298..0d3f47f30 100644 --- a/test/e2e/pod_rm_test.go +++ b/test/e2e/pod_rm_test.go @@ -23,7 +23,7 @@ var _ = Describe("Podman pod rm", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreAllArtifacts() + podmanTest.SeedImages() }) AfterEach(func() { diff --git a/test/e2e/pod_start_test.go b/test/e2e/pod_start_test.go index 967fbc2da..2722cb5b3 100644 --- a/test/e2e/pod_start_test.go +++ b/test/e2e/pod_start_test.go @@ -22,7 +22,7 @@ var _ = Describe("Podman pod start", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreAllArtifacts() + podmanTest.SeedImages() }) AfterEach(func() { diff --git a/test/e2e/pod_stats_test.go b/test/e2e/pod_stats_test.go index 6018b4494..01176f97c 100644 --- a/test/e2e/pod_stats_test.go +++ b/test/e2e/pod_stats_test.go @@ -25,7 +25,7 @@ var _ = Describe("Podman pod stats", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreAllArtifacts() + podmanTest.SeedImages() }) AfterEach(func() { diff --git a/test/e2e/pod_stop_test.go b/test/e2e/pod_stop_test.go index 9fd9e3ef4..361a63a7f 100644 --- a/test/e2e/pod_stop_test.go +++ b/test/e2e/pod_stop_test.go @@ -22,7 +22,7 @@ var _ = Describe("Podman pod stop", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreAllArtifacts() + podmanTest.SeedImages() }) AfterEach(func() { diff --git a/test/e2e/pod_top_test.go b/test/e2e/pod_top_test.go index 420e4aca9..c313b0675 100644 --- a/test/e2e/pod_top_test.go +++ b/test/e2e/pod_top_test.go @@ -26,7 +26,7 @@ var _ = Describe("Podman top", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreAllArtifacts() + podmanTest.SeedImages() }) AfterEach(func() { diff --git a/test/e2e/port_test.go b/test/e2e/port_test.go index 7cf3e16bf..e45118361 100644 --- a/test/e2e/port_test.go +++ b/test/e2e/port_test.go @@ -26,7 +26,7 @@ var _ = Describe("Podman port", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreAllArtifacts() + podmanTest.SeedImages() }) AfterEach(func() { @@ -49,7 +49,6 @@ var _ = Describe("Podman port", func() { }) It("podman port -l nginx", func() { - podmanTest.RestoreArtifact(nginx) session := podmanTest.Podman([]string{"run", "-dt", "-P", nginx}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) @@ -62,7 +61,6 @@ var _ = Describe("Podman port", func() { }) It("podman container port -l nginx", func() { - podmanTest.RestoreArtifact(nginx) session := podmanTest.Podman([]string{"container", "run", "-dt", "-P", nginx}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) @@ -75,7 +73,6 @@ var _ = Describe("Podman port", func() { }) It("podman port -l port nginx", func() { - podmanTest.RestoreArtifact(nginx) session := podmanTest.Podman([]string{"run", "-dt", "-P", nginx}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) @@ -88,7 +85,6 @@ var _ = Describe("Podman port", func() { }) It("podman port -a nginx", func() { - podmanTest.RestoreArtifact(nginx) session := podmanTest.Podman([]string{"run", "-dt", "-P", nginx}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) diff --git a/test/e2e/prune_test.go b/test/e2e/prune_test.go index 377c9f5e1..df0525a79 100644 --- a/test/e2e/prune_test.go +++ b/test/e2e/prune_test.go @@ -28,7 +28,7 @@ var _ = Describe("Podman prune", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreAllArtifacts() + podmanTest.SeedImages() }) AfterEach(func() { @@ -77,11 +77,12 @@ var _ = Describe("Podman prune", func() { }) It("podman image prune unused images", func() { - prune := podmanTest.Podman([]string{"image", "prune", "-a"}) + podmanTest.RestoreAllArtifacts() + prune := podmanTest.PodmanNoCache([]string{"image", "prune", "-a"}) prune.WaitWithDefaultTimeout() Expect(prune.ExitCode()).To(Equal(0)) - images := podmanTest.Podman([]string{"images", "-aq"}) + images := podmanTest.PodmanNoCache([]string{"images", "-aq"}) images.WaitWithDefaultTimeout() // all images are unused, so they all should be deleted! Expect(len(images.OutputToStringArray())).To(Equal(0)) @@ -89,12 +90,13 @@ var _ = Describe("Podman prune", func() { It("podman system image prune unused images", func() { SkipIfRemote() + podmanTest.RestoreAllArtifacts() podmanTest.BuildImage(pruneImage, "alpine_bash:latest", "true") - prune := podmanTest.Podman([]string{"system", "prune", "-a", "--force"}) + prune := podmanTest.PodmanNoCache([]string{"system", "prune", "-a", "--force"}) prune.WaitWithDefaultTimeout() Expect(prune.ExitCode()).To(Equal(0)) - images := podmanTest.Podman([]string{"images", "-aq"}) + images := podmanTest.PodmanNoCache([]string{"images", "-aq"}) images.WaitWithDefaultTimeout() // all images are unused, so they all should be deleted! Expect(len(images.OutputToStringArray())).To(Equal(0)) diff --git a/test/e2e/ps_test.go b/test/e2e/ps_test.go index 7edb350f3..b0a28501a 100644 --- a/test/e2e/ps_test.go +++ b/test/e2e/ps_test.go @@ -27,7 +27,7 @@ var _ = Describe("Podman ps", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreAllArtifacts() + podmanTest.SeedImages() }) AfterEach(func() { diff --git a/test/e2e/pull_test.go b/test/e2e/pull_test.go index 4e4e80d56..d6e7b44d1 100644 --- a/test/e2e/pull_test.go +++ b/test/e2e/pull_test.go @@ -28,7 +28,6 @@ var _ = Describe("Podman pull", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreAllArtifacts() }) AfterEach(func() { @@ -39,132 +38,135 @@ var _ = Describe("Podman pull", func() { }) It("podman pull from docker a not existing image", func() { - session := podmanTest.Podman([]string{"pull", "ibetthisdoesntexistthere:foo"}) + session := podmanTest.PodmanNoCache([]string{"pull", "ibetthisdoesntexistthere:foo"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Not(Equal(0))) }) It("podman pull from docker with tag", func() { - session := podmanTest.Podman([]string{"pull", "busybox:glibc"}) + session := podmanTest.PodmanNoCache([]string{"pull", "busybox:glibc"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - session = podmanTest.Podman([]string{"rmi", "busybox:glibc"}) + session = podmanTest.PodmanNoCache([]string{"rmi", "busybox:glibc"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) }) It("podman pull from docker without tag", func() { - session := podmanTest.Podman([]string{"pull", "busybox"}) + session := podmanTest.PodmanNoCache([]string{"pull", "busybox"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - session = podmanTest.Podman([]string{"rmi", "busybox"}) + session = podmanTest.PodmanNoCache([]string{"rmi", "busybox"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) }) It("podman pull from alternate registry with tag", func() { - session := podmanTest.Podman([]string{"pull", nginx}) + session := podmanTest.PodmanNoCache([]string{"pull", nginx}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - session = podmanTest.Podman([]string{"rmi", nginx}) + session = podmanTest.PodmanNoCache([]string{"rmi", nginx}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) }) It("podman pull from alternate registry without tag", func() { - session := podmanTest.Podman([]string{"pull", "quay.io/libpod/alpine_nginx"}) + session := podmanTest.PodmanNoCache([]string{"pull", "quay.io/libpod/alpine_nginx"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - session = podmanTest.Podman([]string{"rmi", "quay.io/libpod/alpine_nginx"}) + session = podmanTest.PodmanNoCache([]string{"rmi", "quay.io/libpod/alpine_nginx"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) }) It("podman pull by digest", func() { - session := podmanTest.Podman([]string{"pull", "alpine@sha256:1072e499f3f655a032e88542330cf75b02e7bdf673278f701d7ba61629ee3ebe"}) + session := podmanTest.PodmanNoCache([]string{"pull", "alpine@sha256:1072e499f3f655a032e88542330cf75b02e7bdf673278f701d7ba61629ee3ebe"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - session = podmanTest.Podman([]string{"rmi", "alpine:none"}) + session = podmanTest.PodmanNoCache([]string{"rmi", "alpine:none"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) }) It("podman pull bogus image", func() { - session := podmanTest.Podman([]string{"pull", "umohnani/get-started"}) + session := podmanTest.PodmanNoCache([]string{"pull", "umohnani/get-started"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Not(Equal(0))) }) It("podman pull from docker-archive", func() { + podmanTest.RestoreArtifact(ALPINE) tarfn := filepath.Join(podmanTest.TempDir, "alp.tar") - session := podmanTest.Podman([]string{"save", "-o", tarfn, "alpine"}) + session := podmanTest.PodmanNoCache([]string{"save", "-o", tarfn, "alpine"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - session = podmanTest.Podman([]string{"rmi", "alpine"}) + session = podmanTest.PodmanNoCache([]string{"rmi", "alpine"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - session = podmanTest.Podman([]string{"pull", fmt.Sprintf("docker-archive:%s", tarfn)}) + session = podmanTest.PodmanNoCache([]string{"pull", fmt.Sprintf("docker-archive:%s", tarfn)}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - session = podmanTest.Podman([]string{"rmi", "alpine"}) + session = podmanTest.PodmanNoCache([]string{"rmi", "alpine"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) }) It("podman pull from oci-archive", func() { + podmanTest.RestoreArtifact(ALPINE) tarfn := filepath.Join(podmanTest.TempDir, "oci-alp.tar") - session := podmanTest.Podman([]string{"save", "--format", "oci-archive", "-o", tarfn, "alpine"}) + session := podmanTest.PodmanNoCache([]string{"save", "--format", "oci-archive", "-o", tarfn, "alpine"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - session = podmanTest.Podman([]string{"rmi", "alpine"}) + session = podmanTest.PodmanNoCache([]string{"rmi", "alpine"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - session = podmanTest.Podman([]string{"pull", fmt.Sprintf("oci-archive:%s", tarfn)}) + session = podmanTest.PodmanNoCache([]string{"pull", fmt.Sprintf("oci-archive:%s", tarfn)}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - session = podmanTest.Podman([]string{"rmi", "alpine"}) + session = podmanTest.PodmanNoCache([]string{"rmi", "alpine"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) }) It("podman pull from local directory", func() { + podmanTest.RestoreArtifact(ALPINE) dirpath := filepath.Join(podmanTest.TempDir, "alpine") os.MkdirAll(dirpath, os.ModePerm) imgPath := fmt.Sprintf("dir:%s", dirpath) - session := podmanTest.Podman([]string{"push", "alpine", imgPath}) + session := podmanTest.PodmanNoCache([]string{"push", "alpine", imgPath}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - session = podmanTest.Podman([]string{"rmi", "alpine"}) + session = podmanTest.PodmanNoCache([]string{"rmi", "alpine"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - session = podmanTest.Podman([]string{"pull", imgPath}) + session = podmanTest.PodmanNoCache([]string{"pull", imgPath}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - session = podmanTest.Podman([]string{"rmi", "alpine"}) + session = podmanTest.PodmanNoCache([]string{"rmi", "alpine"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) }) It("podman pull check quiet", func() { podmanTest.RestoreArtifact(ALPINE) - setup := podmanTest.Podman([]string{"images", ALPINE, "-q", "--no-trunc"}) + setup := podmanTest.PodmanNoCache([]string{"images", ALPINE, "-q", "--no-trunc"}) setup.WaitWithDefaultTimeout() Expect(setup.ExitCode()).To(Equal(0)) shortImageId := strings.Split(setup.OutputToString(), ":")[1] - rmi := podmanTest.Podman([]string{"rmi", ALPINE}) + rmi := podmanTest.PodmanNoCache([]string{"rmi", ALPINE}) rmi.WaitWithDefaultTimeout() Expect(rmi.ExitCode()).To(Equal(0)) - pull := podmanTest.Podman([]string{"pull", "-q", ALPINE}) + pull := podmanTest.PodmanNoCache([]string{"pull", "-q", ALPINE}) pull.WaitWithDefaultTimeout() Expect(pull.ExitCode()).To(Equal(0)) @@ -172,17 +174,17 @@ var _ = Describe("Podman pull", func() { }) It("podman pull check all tags", func() { - session := podmanTest.Podman([]string{"pull", "--all-tags", "alpine"}) + session := podmanTest.PodmanNoCache([]string{"pull", "--all-tags", "alpine"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) Expect(session.LineInOuputStartsWith("Pulled Images:")).To(BeTrue()) - session = podmanTest.Podman([]string{"images"}) + session = podmanTest.PodmanNoCache([]string{"images"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) Expect(len(session.OutputToStringArray())).To(BeNumerically(">", 4)) - rmi := podmanTest.Podman([]string{"rmi", "-a", "-f"}) + rmi := podmanTest.PodmanNoCache([]string{"rmi", "-a", "-f"}) rmi.WaitWithDefaultTimeout() Expect(rmi.ExitCode()).To(Equal(0)) }) diff --git a/test/e2e/push_test.go b/test/e2e/push_test.go index 009067482..de2416868 100644 --- a/test/e2e/push_test.go +++ b/test/e2e/push_test.go @@ -38,22 +38,18 @@ var _ = Describe("Podman push", func() { }) It("podman push to containers/storage", func() { - session := podmanTest.Podman([]string{"push", ALPINE, "containers-storage:busybox:test"}) + session := podmanTest.PodmanNoCache([]string{"push", ALPINE, "containers-storage:busybox:test"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - session = podmanTest.Podman([]string{"rmi", ALPINE}) - session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(Equal(0)) - - session = podmanTest.Podman([]string{"rmi", "busybox:test"}) + session = podmanTest.PodmanNoCache([]string{"rmi", ALPINE}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) }) It("podman push to dir", func() { bbdir := filepath.Join(podmanTest.TempDir, "busybox") - session := podmanTest.Podman([]string{"push", "--remove-signatures", ALPINE, + session := podmanTest.PodmanNoCache([]string{"push", "--remove-signatures", ALPINE, fmt.Sprintf("dir:%s", bbdir)}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) @@ -65,8 +61,7 @@ var _ = Describe("Podman push", func() { } lock := GetPortLock("5000") defer lock.Unlock() - podmanTest.RestoreArtifact(registry) - session := podmanTest.Podman([]string{"run", "-d", "--name", "registry", "-p", "5000:5000", registry, "/entrypoint.sh", "/etc/docker/registry/config.yml"}) + session := podmanTest.PodmanNoCache([]string{"run", "-d", "--name", "registry", "-p", "5000:5000", registry, "/entrypoint.sh", "/etc/docker/registry/config.yml"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) @@ -74,7 +69,7 @@ var _ = Describe("Podman push", func() { Skip("Can not start docker registry.") } - push := podmanTest.Podman([]string{"push", "--tls-verify=false", "--remove-signatures", ALPINE, "localhost:5000/my-alpine"}) + push := podmanTest.PodmanNoCache([]string{"push", "--tls-verify=false", "--remove-signatures", ALPINE, "localhost:5000/my-alpine"}) push.WaitWithDefaultTimeout() Expect(push.ExitCode()).To(Equal(0)) }) @@ -106,8 +101,7 @@ var _ = Describe("Podman push", func() { } lock := GetPortLock("5000") defer lock.Unlock() - podmanTest.RestoreArtifact(registry) - session := podmanTest.Podman([]string{"run", "--entrypoint", "htpasswd", registry, "-Bbn", "podmantest", "test"}) + session := podmanTest.PodmanNoCache([]string{"run", "--entrypoint", "htpasswd", registry, "-Bbn", "podmantest", "test"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) @@ -117,7 +111,7 @@ var _ = Describe("Podman push", func() { f.WriteString(session.OutputToString()) f.Sync() - session = podmanTest.Podman([]string{"run", "-d", "-p", "5000:5000", "--name", "registry", "-v", + session = podmanTest.PodmanNoCache([]string{"run", "-d", "-p", "5000:5000", "--name", "registry", "-v", strings.Join([]string{authPath, "/auth"}, ":"), "-e", "REGISTRY_AUTH=htpasswd", "-e", "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm", "-e", "REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd", "-v", strings.Join([]string{certPath, "/certs"}, ":"), "-e", "REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt", @@ -129,36 +123,36 @@ var _ = Describe("Podman push", func() { Skip("Can not start docker registry.") } - session = podmanTest.Podman([]string{"logs", "registry"}) + session = podmanTest.PodmanNoCache([]string{"logs", "registry"}) session.WaitWithDefaultTimeout() - push := podmanTest.Podman([]string{"push", "--creds=podmantest:test", ALPINE, "localhost:5000/tlstest"}) + push := podmanTest.PodmanNoCache([]string{"push", "--creds=podmantest:test", ALPINE, "localhost:5000/tlstest"}) push.WaitWithDefaultTimeout() Expect(push.ExitCode()).To(Not(Equal(0))) - push = podmanTest.Podman([]string{"push", "--creds=podmantest:test", "--tls-verify=false", ALPINE, "localhost:5000/tlstest"}) + push = podmanTest.PodmanNoCache([]string{"push", "--creds=podmantest:test", "--tls-verify=false", ALPINE, "localhost:5000/tlstest"}) push.WaitWithDefaultTimeout() Expect(push.ExitCode()).To(Equal(0)) setup := SystemExec("cp", []string{filepath.Join(certPath, "domain.crt"), "/etc/containers/certs.d/localhost:5000/ca.crt"}) Expect(setup.ExitCode()).To(Equal(0)) - push = podmanTest.Podman([]string{"push", "--creds=podmantest:wrongpasswd", ALPINE, "localhost:5000/credstest"}) + push = podmanTest.PodmanNoCache([]string{"push", "--creds=podmantest:wrongpasswd", ALPINE, "localhost:5000/credstest"}) push.WaitWithDefaultTimeout() Expect(push.ExitCode()).To(Not(Equal(0))) - push = podmanTest.Podman([]string{"push", "--creds=podmantest:test", "--cert-dir=fakedir", ALPINE, "localhost:5000/certdirtest"}) + push = podmanTest.PodmanNoCache([]string{"push", "--creds=podmantest:test", "--cert-dir=fakedir", ALPINE, "localhost:5000/certdirtest"}) push.WaitWithDefaultTimeout() Expect(push.ExitCode()).To(Not(Equal(0))) - push = podmanTest.Podman([]string{"push", "--creds=podmantest:test", ALPINE, "localhost:5000/defaultflags"}) + push = podmanTest.PodmanNoCache([]string{"push", "--creds=podmantest:test", ALPINE, "localhost:5000/defaultflags"}) push.WaitWithDefaultTimeout() Expect(push.ExitCode()).To(Equal(0)) }) It("podman push to docker-archive", func() { tarfn := filepath.Join(podmanTest.TempDir, "alp.tar") - session := podmanTest.Podman([]string{"push", ALPINE, + session := podmanTest.PodmanNoCache([]string{"push", ALPINE, fmt.Sprintf("docker-archive:%s:latest", tarfn)}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) @@ -177,7 +171,7 @@ var _ = Describe("Podman push", func() { Skip("Docker is not available") } - session := podmanTest.Podman([]string{"push", ALPINE, "docker-daemon:alpine:podmantest"}) + session := podmanTest.PodmanNoCache([]string{"push", ALPINE, "docker-daemon:alpine:podmantest"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) @@ -191,7 +185,7 @@ var _ = Describe("Podman push", func() { It("podman push to oci-archive", func() { tarfn := filepath.Join(podmanTest.TempDir, "alp.tar") - session := podmanTest.Podman([]string{"push", ALPINE, + session := podmanTest.PodmanNoCache([]string{"push", ALPINE, fmt.Sprintf("oci-archive:%s:latest", tarfn)}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) @@ -208,7 +202,7 @@ var _ = Describe("Podman push", func() { setup := SystemExec("ostree", []string{strings.Join([]string{"--repo=", ostreePath}, ""), "init"}) Expect(setup.ExitCode()).To(Equal(0)) - session := podmanTest.Podman([]string{"push", ALPINE, strings.Join([]string{"ostree:alp@", ostreePath}, "")}) + session := podmanTest.PodmanNoCache([]string{"push", ALPINE, strings.Join([]string{"ostree:alp@", ostreePath}, "")}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) @@ -216,7 +210,7 @@ var _ = Describe("Podman push", func() { It("podman push to docker-archive no reference", func() { tarfn := filepath.Join(podmanTest.TempDir, "alp.tar") - session := podmanTest.Podman([]string{"push", ALPINE, + session := podmanTest.PodmanNoCache([]string{"push", ALPINE, fmt.Sprintf("docker-archive:%s", tarfn)}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) @@ -224,7 +218,7 @@ var _ = Describe("Podman push", func() { It("podman push to oci-archive no reference", func() { ociarc := filepath.Join(podmanTest.TempDir, "alp-oci") - session := podmanTest.Podman([]string{"push", ALPINE, + session := podmanTest.PodmanNoCache([]string{"push", ALPINE, fmt.Sprintf("oci-archive:%s", ociarc)}) session.WaitWithDefaultTimeout() diff --git a/test/e2e/restart_test.go b/test/e2e/restart_test.go index 7a9a466d8..2b515f53b 100644 --- a/test/e2e/restart_test.go +++ b/test/e2e/restart_test.go @@ -23,7 +23,7 @@ var _ = Describe("Podman restart", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreAllArtifacts() + podmanTest.SeedImages() }) AfterEach(func() { diff --git a/test/e2e/rm_test.go b/test/e2e/rm_test.go index 29150d67c..2dbabbf6a 100644 --- a/test/e2e/rm_test.go +++ b/test/e2e/rm_test.go @@ -22,7 +22,7 @@ var _ = Describe("Podman rm", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreAllArtifacts() + podmanTest.SeedImages() }) AfterEach(func() { diff --git a/test/e2e/rmi_test.go b/test/e2e/rmi_test.go index e034f24cf..1687bf764 100644 --- a/test/e2e/rmi_test.go +++ b/test/e2e/rmi_test.go @@ -41,14 +41,14 @@ var _ = Describe("Podman rmi", func() { }) It("podman rmi with fq name", func() { - session := podmanTest.Podman([]string{"rmi", ALPINE}) + session := podmanTest.PodmanNoCache([]string{"rmi", ALPINE}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) }) It("podman rmi with short name", func() { - session := podmanTest.Podman([]string{"rmi", "alpine"}) + session := podmanTest.PodmanNoCache([]string{"rmi", "alpine"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) @@ -56,9 +56,9 @@ var _ = Describe("Podman rmi", func() { It("podman rmi all images", func() { podmanTest.PullImages([]string{nginx}) - session := podmanTest.Podman([]string{"rmi", "-a"}) + session := podmanTest.PodmanNoCache([]string{"rmi", "-a"}) session.WaitWithDefaultTimeout() - images := podmanTest.Podman([]string{"images"}) + images := podmanTest.PodmanNoCache([]string{"images"}) images.WaitWithDefaultTimeout() fmt.Println(images.OutputToStringArray()) Expect(session.ExitCode()).To(Equal(0)) @@ -67,22 +67,22 @@ var _ = Describe("Podman rmi", func() { It("podman rmi all images forcibly with short options", func() { podmanTest.PullImages([]string{nginx}) - session := podmanTest.Podman([]string{"rmi", "-fa"}) + session := podmanTest.PodmanNoCache([]string{"rmi", "-fa"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) }) It("podman rmi tagged image", func() { - setup := podmanTest.Podman([]string{"images", "-q", ALPINE}) + setup := podmanTest.PodmanNoCache([]string{"images", "-q", ALPINE}) setup.WaitWithDefaultTimeout() Expect(setup.ExitCode()).To(Equal(0)) - session := podmanTest.Podman([]string{"tag", "alpine", "foo:bar", "foo"}) + session := podmanTest.PodmanNoCache([]string{"tag", "alpine", "foo:bar", "foo"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - result := podmanTest.Podman([]string{"images", "-q", "foo"}) + result := podmanTest.PodmanNoCache([]string{"images", "-q", "foo"}) result.WaitWithDefaultTimeout() Expect(result.ExitCode()).To(Equal(0)) @@ -90,95 +90,95 @@ var _ = Describe("Podman rmi", func() { }) It("podman rmi image with tags by ID cannot be done without force", func() { - setup := podmanTest.Podman([]string{"images", "-q", ALPINE}) + setup := podmanTest.PodmanNoCache([]string{"images", "-q", ALPINE}) setup.WaitWithDefaultTimeout() Expect(setup.ExitCode()).To(Equal(0)) alpineId := setup.OutputToString() - session := podmanTest.Podman([]string{"tag", "alpine", "foo:bar", "foo"}) + session := podmanTest.PodmanNoCache([]string{"tag", "alpine", "foo:bar", "foo"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) // Trying without --force should fail - result := podmanTest.Podman([]string{"rmi", alpineId}) + result := podmanTest.PodmanNoCache([]string{"rmi", alpineId}) result.WaitWithDefaultTimeout() Expect(result.ExitCode()).ToNot(Equal(0)) // With --force it should work - resultForce := podmanTest.Podman([]string{"rmi", "-f", alpineId}) + resultForce := podmanTest.PodmanNoCache([]string{"rmi", "-f", alpineId}) resultForce.WaitWithDefaultTimeout() Expect(resultForce.ExitCode()).To(Equal(0)) }) It("podman rmi image that is a parent of another image", func() { SkipIfRemote() - session := podmanTest.Podman([]string{"rmi", "-fa"}) + session := podmanTest.PodmanNoCache([]string{"rmi", "-fa"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - session = podmanTest.Podman([]string{"run", "--name", "c_test", ALPINE, "true"}) + session = podmanTest.PodmanNoCache([]string{"run", "--name", "c_test", ALPINE, "true"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - session = podmanTest.Podman([]string{"commit", "-q", "c_test", "test"}) + session = podmanTest.PodmanNoCache([]string{"commit", "-q", "c_test", "test"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - session = podmanTest.Podman([]string{"rm", "c_test"}) + session = podmanTest.PodmanNoCache([]string{"rm", "c_test"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - session = podmanTest.Podman([]string{"rmi", ALPINE}) + session = podmanTest.PodmanNoCache([]string{"rmi", ALPINE}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - session = podmanTest.Podman([]string{"images", "-q"}) + session = podmanTest.PodmanNoCache([]string{"images", "-q"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) Expect(len(session.OutputToStringArray())).To(Equal(1)) - session = podmanTest.Podman([]string{"images", "-q", "-a"}) + session = podmanTest.PodmanNoCache([]string{"images", "-q", "-a"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) Expect(len(session.OutputToStringArray())).To(Equal(2)) untaggedImg := session.OutputToStringArray()[1] - session = podmanTest.Podman([]string{"rmi", "-f", untaggedImg}) + session = podmanTest.PodmanNoCache([]string{"rmi", "-f", untaggedImg}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Not(Equal(0))) }) It("podman rmi image that is created from another named imaged", func() { SkipIfRemote() - session := podmanTest.Podman([]string{"rmi", "-fa"}) + session := podmanTest.PodmanNoCache([]string{"rmi", "-fa"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - session = podmanTest.Podman([]string{"create", "--name", "c_test1", ALPINE, "true"}) + session = podmanTest.PodmanNoCache([]string{"create", "--name", "c_test1", ALPINE, "true"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - session = podmanTest.Podman([]string{"commit", "-q", "c_test1", "test1"}) + session = podmanTest.PodmanNoCache([]string{"commit", "-q", "c_test1", "test1"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - session = podmanTest.Podman([]string{"create", "--name", "c_test2", "test1", "true"}) + session = podmanTest.PodmanNoCache([]string{"create", "--name", "c_test2", "test1", "true"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - session = podmanTest.Podman([]string{"commit", "-q", "c_test2", "test2"}) + session = podmanTest.PodmanNoCache([]string{"commit", "-q", "c_test2", "test2"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - session = podmanTest.Podman([]string{"rm", "-a"}) + session = podmanTest.PodmanNoCache([]string{"rm", "-a"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - session = podmanTest.Podman([]string{"rmi", "test2"}) + session = podmanTest.PodmanNoCache([]string{"rmi", "test2"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - session = podmanTest.Podman([]string{"images", "-q"}) + session = podmanTest.PodmanNoCache([]string{"images", "-q"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) Expect(len(session.OutputToStringArray())).To(Equal(2)) @@ -186,7 +186,7 @@ var _ = Describe("Podman rmi", func() { It("podman rmi with cached images", func() { SkipIfRemote() - session := podmanTest.Podman([]string{"rmi", "-fa"}) + session := podmanTest.PodmanNoCache([]string{"rmi", "-fa"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) @@ -205,51 +205,51 @@ var _ = Describe("Podman rmi", func() { ` podmanTest.BuildImage(dockerfile, "test2", "true") - session = podmanTest.Podman([]string{"images", "-q", "-a"}) + session = podmanTest.PodmanNoCache([]string{"images", "-q", "-a"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) numOfImages := len(session.OutputToStringArray()) - session = podmanTest.Podman([]string{"rmi", "test2"}) + session = podmanTest.PodmanNoCache([]string{"rmi", "test2"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - session = podmanTest.Podman([]string{"images", "-q", "-a"}) + session = podmanTest.PodmanNoCache([]string{"images", "-q", "-a"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) Expect(numOfImages - len(session.OutputToStringArray())).To(Equal(2)) - session = podmanTest.Podman([]string{"rmi", "test"}) + session = podmanTest.PodmanNoCache([]string{"rmi", "test"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - session = podmanTest.Podman([]string{"images", "-q", "-a"}) + session = podmanTest.PodmanNoCache([]string{"images", "-q", "-a"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) Expect(len(session.OutputToStringArray())).To(Equal(1)) podmanTest.BuildImage(dockerfile, "test3", "true") - session = podmanTest.Podman([]string{"rmi", ALPINE}) + session = podmanTest.PodmanNoCache([]string{"rmi", ALPINE}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - session = podmanTest.Podman([]string{"rmi", "test3"}) + session = podmanTest.PodmanNoCache([]string{"rmi", "test3"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - session = podmanTest.Podman([]string{"images", "-q", "-a"}) + session = podmanTest.PodmanNoCache([]string{"images", "-q", "-a"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) Expect(len(session.OutputToString())).To(Equal(0)) }) It("podman rmi -a with no images should be exit 0", func() { - session := podmanTest.Podman([]string{"rmi", "-fa"}) + session := podmanTest.PodmanNoCache([]string{"rmi", "-fa"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - session2 := podmanTest.Podman([]string{"rmi", "-fa"}) + session2 := podmanTest.PodmanNoCache([]string{"rmi", "-fa"}) session2.WaitWithDefaultTimeout() Expect(session2.ExitCode()).To(Equal(0)) }) @@ -265,12 +265,12 @@ RUN find $LOCAL ` podmanTest.BuildImage(dockerfile, "test", "true") - session := podmanTest.Podman([]string{"rmi", "-a"}) + session := podmanTest.PodmanNoCache([]string{"rmi", "-a"}) session.WaitWithDefaultTimeout() fmt.Println(session.OutputToString()) Expect(session.ExitCode()).To(Equal(0)) - images := podmanTest.Podman([]string{"images", "-aq"}) + images := podmanTest.PodmanNoCache([]string{"images", "-aq"}) images.WaitWithDefaultTimeout() Expect(images.ExitCode()).To(Equal(0)) Expect(len(images.OutputToStringArray())).To(Equal(0)) @@ -279,7 +279,7 @@ RUN find $LOCAL // Don't rerun all tests; just assume that if we get that diagnostic, // we're getting rmi It("podman image rm is the same as rmi", func() { - session := podmanTest.Podman([]string{"image", "rm"}) + session := podmanTest.PodmanNoCache([]string{"image", "rm"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(125)) Expect(session.LineInOutputContains("image name or ID must be specified")) diff --git a/test/e2e/run_cgroup_parent_test.go b/test/e2e/run_cgroup_parent_test.go index 0d04c5f03..1fb9f6871 100644 --- a/test/e2e/run_cgroup_parent_test.go +++ b/test/e2e/run_cgroup_parent_test.go @@ -25,7 +25,7 @@ var _ = Describe("Podman run with --cgroup-parent", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreArtifact(fedoraMinimal) + podmanTest.SeedImages() }) AfterEach(func() { diff --git a/test/e2e/run_cleanup_test.go b/test/e2e/run_cleanup_test.go index b20e37794..73647b6bb 100644 --- a/test/e2e/run_cleanup_test.go +++ b/test/e2e/run_cleanup_test.go @@ -24,7 +24,7 @@ var _ = Describe("Podman run exit", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreAllArtifacts() + podmanTest.RestoreArtifact(ALPINE) }) AfterEach(func() { diff --git a/test/e2e/run_cpu_test.go b/test/e2e/run_cpu_test.go index 42a66865c..87f89b1dd 100644 --- a/test/e2e/run_cpu_test.go +++ b/test/e2e/run_cpu_test.go @@ -24,7 +24,7 @@ var _ = Describe("Podman run cpu", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreAllArtifacts() + podmanTest.SeedImages() }) AfterEach(func() { diff --git a/test/e2e/run_device_test.go b/test/e2e/run_device_test.go index fac09b78d..2e537a9f9 100644 --- a/test/e2e/run_device_test.go +++ b/test/e2e/run_device_test.go @@ -24,7 +24,7 @@ var _ = Describe("Podman run device", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreAllArtifacts() + podmanTest.SeedImages() }) AfterEach(func() { diff --git a/test/e2e/run_dns_test.go b/test/e2e/run_dns_test.go index 0f4dd6742..f1196ff38 100644 --- a/test/e2e/run_dns_test.go +++ b/test/e2e/run_dns_test.go @@ -24,7 +24,7 @@ var _ = Describe("Podman run dns", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreAllArtifacts() + podmanTest.SeedImages() }) AfterEach(func() { diff --git a/test/e2e/run_entrypoint_test.go b/test/e2e/run_entrypoint_test.go index ee9fd1263..b1344a371 100644 --- a/test/e2e/run_entrypoint_test.go +++ b/test/e2e/run_entrypoint_test.go @@ -24,7 +24,7 @@ var _ = Describe("Podman run entrypoint", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreArtifact(ALPINE) + podmanTest.SeedImages() }) AfterEach(func() { diff --git a/test/e2e/run_exit_test.go b/test/e2e/run_exit_test.go index da4cf7ee7..861d6b3b7 100644 --- a/test/e2e/run_exit_test.go +++ b/test/e2e/run_exit_test.go @@ -24,7 +24,7 @@ var _ = Describe("Podman run exit", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreAllArtifacts() + podmanTest.SeedImages() }) AfterEach(func() { diff --git a/test/e2e/run_memory_test.go b/test/e2e/run_memory_test.go index 05d0b7a18..8fe90c8d8 100644 --- a/test/e2e/run_memory_test.go +++ b/test/e2e/run_memory_test.go @@ -25,7 +25,7 @@ var _ = Describe("Podman run memory", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreAllArtifacts() + podmanTest.SeedImages() }) AfterEach(func() { diff --git a/test/e2e/run_networking_test.go b/test/e2e/run_networking_test.go index 93919925c..1497a651b 100644 --- a/test/e2e/run_networking_test.go +++ b/test/e2e/run_networking_test.go @@ -25,7 +25,7 @@ var _ = Describe("Podman run networking", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreAllArtifacts() + podmanTest.SeedImages() }) AfterEach(func() { @@ -78,7 +78,6 @@ var _ = Describe("Podman run networking", func() { }) It("podman run network expose ports in image metadata", func() { - podmanTest.RestoreArtifact(nginx) session := podmanTest.Podman([]string{"create", "-dt", "-P", nginx}) session.Wait(90) Expect(session.ExitCode()).To(Equal(0)) diff --git a/test/e2e/run_ns_test.go b/test/e2e/run_ns_test.go index 51f921bce..6ba0d1aba 100644 --- a/test/e2e/run_ns_test.go +++ b/test/e2e/run_ns_test.go @@ -25,7 +25,7 @@ var _ = Describe("Podman run ns", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreArtifact(fedoraMinimal) + podmanTest.SeedImages() }) AfterEach(func() { diff --git a/test/e2e/run_passwd_test.go b/test/e2e/run_passwd_test.go index becbc5bfa..bd6a0e036 100644 --- a/test/e2e/run_passwd_test.go +++ b/test/e2e/run_passwd_test.go @@ -24,7 +24,7 @@ var _ = Describe("Podman run passwd", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreAllArtifacts() + podmanTest.SeedImages() }) AfterEach(func() { diff --git a/test/e2e/run_privileged_test.go b/test/e2e/run_privileged_test.go index 16011b2fd..f2c424483 100644 --- a/test/e2e/run_privileged_test.go +++ b/test/e2e/run_privileged_test.go @@ -25,7 +25,7 @@ var _ = Describe("Podman privileged container tests", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreAllArtifacts() + podmanTest.SeedImages() }) AfterEach(func() { diff --git a/test/e2e/run_restart_test.go b/test/e2e/run_restart_test.go index 9976b45e8..8bbdf2056 100644 --- a/test/e2e/run_restart_test.go +++ b/test/e2e/run_restart_test.go @@ -24,7 +24,7 @@ var _ = Describe("Podman run restart containers", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreAllArtifacts() + podmanTest.SeedImages() }) AfterEach(func() { diff --git a/test/e2e/run_selinux_test.go b/test/e2e/run_selinux_test.go index 4d2bad49c..a2228411e 100644 --- a/test/e2e/run_selinux_test.go +++ b/test/e2e/run_selinux_test.go @@ -25,7 +25,7 @@ var _ = Describe("Podman run", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreAllArtifacts() + podmanTest.SeedImages() if !selinux.GetEnabled() { Skip("SELinux not enabled") } diff --git a/test/e2e/run_signal_test.go b/test/e2e/run_signal_test.go index e482adb84..3a5ed483c 100644 --- a/test/e2e/run_signal_test.go +++ b/test/e2e/run_signal_test.go @@ -33,7 +33,7 @@ var _ = Describe("Podman run with --sig-proxy", func() { } podmanTest = PodmanTestCreate(tmpdir) podmanTest.Setup() - podmanTest.RestoreArtifact(fedoraMinimal) + podmanTest.SeedImages() }) AfterEach(func() { diff --git a/test/e2e/run_staticip_test.go b/test/e2e/run_staticip_test.go index 318a7a62d..9753cfc9c 100644 --- a/test/e2e/run_staticip_test.go +++ b/test/e2e/run_staticip_test.go @@ -25,7 +25,7 @@ var _ = Describe("Podman run with --ip flag", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreAllArtifacts() + podmanTest.SeedImages() // Cleanup the CNI networks used by the tests os.RemoveAll("/var/lib/cni/networks/podman") }) diff --git a/test/e2e/run_test.go b/test/e2e/run_test.go index f908fe154..31720ea04 100644 --- a/test/e2e/run_test.go +++ b/test/e2e/run_test.go @@ -32,7 +32,7 @@ var _ = Describe("Podman run", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreAllArtifacts() + podmanTest.SeedImages() }) AfterEach(func() { @@ -51,7 +51,6 @@ var _ = Describe("Podman run", func() { It("podman run a container based on a complex local image name", func() { SkipIfRootless() imageName := strings.TrimPrefix(nginx, "quay.io/") - podmanTest.RestoreArtifact(nginx) session := podmanTest.Podman([]string{"run", imageName, "ls"}) session.WaitWithDefaultTimeout() Expect(session.ErrorToString()).ToNot(ContainSubstring("Trying to pull")) @@ -59,7 +58,6 @@ var _ = Describe("Podman run", func() { }) It("podman run a container based on on a short name with localhost", func() { - podmanTest.RestoreArtifact(nginx) tag := podmanTest.Podman([]string{"tag", nginx, "localhost/libpod/alpine_nginx:latest"}) tag.WaitWithDefaultTimeout() @@ -73,7 +71,6 @@ var _ = Describe("Podman run", func() { }) It("podman container run a container based on on a short name with localhost", func() { - podmanTest.RestoreArtifact(nginx) tag := podmanTest.Podman([]string{"image", "tag", nginx, "localhost/libpod/alpine_nginx:latest"}) tag.WaitWithDefaultTimeout() @@ -229,7 +226,6 @@ var _ = Describe("Podman run", func() { It("podman run limits test", func() { SkipIfRootless() - podmanTest.RestoreArtifact(fedoraMinimal) session := podmanTest.Podman([]string{"run", "--rm", "--ulimit", "rtprio=99", "--cap-add=sys_nice", fedoraMinimal, "cat", "/proc/self/sched"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) @@ -349,11 +345,12 @@ var _ = Describe("Podman run", func() { }) It("podman run tagged image", func() { - tag := podmanTest.Podman([]string{"tag", "busybox", "bb"}) + podmanTest.RestoreArtifact(BB) + tag := podmanTest.PodmanNoCache([]string{"tag", "busybox", "bb"}) tag.WaitWithDefaultTimeout() Expect(tag.ExitCode()).To(Equal(0)) - session := podmanTest.Podman([]string{"run", "--rm", "bb", "ls"}) + session := podmanTest.PodmanNoCache([]string{"run", "--rm", "bb", "ls"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) }) @@ -536,15 +533,10 @@ var _ = Describe("Podman run", func() { }) It("podman run with built-in volume image", func() { - podmanTest.RestoreArtifact(redis) session := podmanTest.Podman([]string{"run", "--rm", redis, "ls"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - session = podmanTest.Podman([]string{"rmi", redis}) - session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(Equal(0)) - dockerfile := `FROM busybox RUN mkdir -p /myvol/data && chown -R mail.0 /myvol VOLUME ["/myvol/data"] @@ -555,10 +547,6 @@ USER mail` session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) Expect(session.OutputToString()).To(ContainSubstring("mail root")) - - session = podmanTest.Podman([]string{"rmi", "test"}) - session.WaitWithDefaultTimeout() - Expect(session.ExitCode()).To(Equal(0)) }) It("podman run --volumes-from flag", func() { @@ -571,7 +559,6 @@ USER mail` err = ioutil.WriteFile(volFile, []byte(data), 0755) Expect(err).To(BeNil()) - podmanTest.RestoreArtifact(redis) session := podmanTest.Podman([]string{"create", "--volume", vol + ":/myvol", redis, "sh"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) @@ -587,7 +574,6 @@ USER mail` }) It("podman run --volumes-from flag with built-in volumes", func() { - podmanTest.RestoreArtifact(redis) session := podmanTest.Podman([]string{"create", redis, "sh"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) @@ -641,7 +627,6 @@ USER mail` }) It("podman run findmnt nothing shared", func() { - podmanTest.RestoreArtifact(fedoraMinimal) vol1 := filepath.Join(podmanTest.TempDir, "vol-test1") err := os.MkdirAll(vol1, 0755) Expect(err).To(BeNil()) @@ -657,7 +642,6 @@ USER mail` }) It("podman run findmnt shared", func() { - podmanTest.RestoreArtifact(fedoraMinimal) vol1 := filepath.Join(podmanTest.TempDir, "vol-test1") err := os.MkdirAll(vol1, 0755) Expect(err).To(BeNil()) @@ -765,10 +749,9 @@ USER mail` }) It("podman run with restart-policy always restarts containers", func() { - podmanTest.RestoreArtifact(fedoraMinimal) testDir := filepath.Join(podmanTest.RunRoot, "restart-test") - err := os.Mkdir(testDir, 0755) + err := os.MkdirAll(testDir, 0755) Expect(err).To(BeNil()) aliveFile := filepath.Join(testDir, "running") diff --git a/test/e2e/run_userns_test.go b/test/e2e/run_userns_test.go index ce6971cd1..be3f7df49 100644 --- a/test/e2e/run_userns_test.go +++ b/test/e2e/run_userns_test.go @@ -31,7 +31,7 @@ var _ = Describe("Podman UserNS support", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreAllArtifacts() + podmanTest.SeedImages() }) AfterEach(func() { diff --git a/test/e2e/run_volume_test.go b/test/e2e/run_volume_test.go index d031ca143..d89c80909 100644 --- a/test/e2e/run_volume_test.go +++ b/test/e2e/run_volume_test.go @@ -26,7 +26,7 @@ var _ = Describe("Podman run with volumes", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreAllArtifacts() + podmanTest.SeedImages() }) AfterEach(func() { diff --git a/test/e2e/runlabel_test.go b/test/e2e/runlabel_test.go index f52a2b8fc..5ef68603e 100644 --- a/test/e2e/runlabel_test.go +++ b/test/e2e/runlabel_test.go @@ -37,7 +37,7 @@ var _ = Describe("podman container runlabel", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreAllArtifacts() + podmanTest.SeedImages() }) AfterEach(func() { diff --git a/test/e2e/save_test.go b/test/e2e/save_test.go index ffb5182d6..be1ede962 100644 --- a/test/e2e/save_test.go +++ b/test/e2e/save_test.go @@ -37,7 +37,7 @@ var _ = Describe("Podman save", func() { It("podman save output flag", func() { outfile := filepath.Join(podmanTest.TempDir, "alpine.tar") - save := podmanTest.Podman([]string{"save", "-o", outfile, ALPINE}) + save := podmanTest.PodmanNoCache([]string{"save", "-o", outfile, ALPINE}) save.WaitWithDefaultTimeout() Expect(save.ExitCode()).To(Equal(0)) }) @@ -45,7 +45,7 @@ var _ = Describe("Podman save", func() { It("podman save oci flag", func() { outfile := filepath.Join(podmanTest.TempDir, "alpine.tar") - save := podmanTest.Podman([]string{"save", "-o", outfile, "--format", "oci-archive", ALPINE}) + save := podmanTest.PodmanNoCache([]string{"save", "-o", outfile, "--format", "oci-archive", ALPINE}) save.WaitWithDefaultTimeout() Expect(save.ExitCode()).To(Equal(0)) }) @@ -54,7 +54,7 @@ var _ = Describe("Podman save", func() { Skip("Pipe redirection in ginkgo probably wont work") outfile := filepath.Join(podmanTest.TempDir, "alpine.tar") - save := podmanTest.Podman([]string{"save", ALPINE, ">", outfile}) + save := podmanTest.PodmanNoCache([]string{"save", ALPINE, ">", outfile}) save.WaitWithDefaultTimeout() Expect(save.ExitCode()).To(Equal(0)) }) @@ -62,7 +62,7 @@ var _ = Describe("Podman save", func() { It("podman save quiet flag", func() { outfile := filepath.Join(podmanTest.TempDir, "alpine.tar") - save := podmanTest.Podman([]string{"save", "-q", "-o", outfile, ALPINE}) + save := podmanTest.PodmanNoCache([]string{"save", "-q", "-o", outfile, ALPINE}) save.WaitWithDefaultTimeout() Expect(save.ExitCode()).To(Equal(0)) }) @@ -70,7 +70,7 @@ var _ = Describe("Podman save", func() { It("podman save bogus image", func() { outfile := filepath.Join(podmanTest.TempDir, "alpine.tar") - save := podmanTest.Podman([]string{"save", "-o", outfile, "FOOBAR"}) + save := podmanTest.PodmanNoCache([]string{"save", "-o", outfile, "FOOBAR"}) save.WaitWithDefaultTimeout() Expect(save.ExitCode()).To(Not(Equal(0))) }) @@ -81,7 +81,7 @@ var _ = Describe("Podman save", func() { } outdir := filepath.Join(podmanTest.TempDir, "save") - save := podmanTest.Podman([]string{"save", "--format", "oci-dir", "-o", outdir, ALPINE}) + save := podmanTest.PodmanNoCache([]string{"save", "--format", "oci-dir", "-o", outdir, ALPINE}) save.WaitWithDefaultTimeout() Expect(save.ExitCode()).To(Equal(0)) }) @@ -92,7 +92,7 @@ var _ = Describe("Podman save", func() { } outdir := filepath.Join(podmanTest.TempDir, "save") - save := podmanTest.Podman([]string{"save", "--format", "docker-dir", "-o", outdir, ALPINE}) + save := podmanTest.PodmanNoCache([]string{"save", "--format", "docker-dir", "-o", outdir, ALPINE}) save.WaitWithDefaultTimeout() Expect(save.ExitCode()).To(Equal(0)) }) @@ -103,7 +103,7 @@ var _ = Describe("Podman save", func() { } outdir := filepath.Join(podmanTest.TempDir, "save") - save := podmanTest.Podman([]string{"save", "--compress", "--format", "docker-dir", "-o", outdir, ALPINE}) + save := podmanTest.PodmanNoCache([]string{"save", "--compress", "--format", "docker-dir", "-o", outdir, ALPINE}) save.WaitWithDefaultTimeout() Expect(save.ExitCode()).To(Equal(0)) }) @@ -111,7 +111,7 @@ var _ = Describe("Podman save", func() { It("podman save bad filename", func() { outdir := filepath.Join(podmanTest.TempDir, "save:colon") - save := podmanTest.Podman([]string{"save", "--compress", "--format", "docker-dir", "-o", outdir, ALPINE}) + save := podmanTest.PodmanNoCache([]string{"save", "--compress", "--format", "docker-dir", "-o", outdir, ALPINE}) save.WaitWithDefaultTimeout() Expect(save.ExitCode()).To(Not(Equal(0))) }) diff --git a/test/e2e/search_test.go b/test/e2e/search_test.go index 72b083de8..3b1da859c 100644 --- a/test/e2e/search_test.go +++ b/test/e2e/search_test.go @@ -75,8 +75,8 @@ registries = ['{{.Host}}:{{.Port}}']` podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() + podmanTest.SeedImages() - podmanTest.RestoreAllArtifacts() }) AfterEach(func() { @@ -168,7 +168,6 @@ registries = ['{{.Host}}:{{.Port}}']` lock := GetPortLock(registryEndpoints[0].Port) defer lock.Unlock() - podmanTest.RestoreArtifact(registry) fakereg := podmanTest.Podman([]string{"run", "-d", "--name", "registry", "-p", fmt.Sprintf("%s:5000", registryEndpoints[0].Port), registry, "/entrypoint.sh", "/etc/docker/registry/config.yml"}) @@ -196,7 +195,6 @@ registries = ['{{.Host}}:{{.Port}}']` } lock := GetPortLock(registryEndpoints[3].Port) defer lock.Unlock() - podmanTest.RestoreArtifact(registry) registry := podmanTest.Podman([]string{"run", "-d", "--name", "registry3", "-p", fmt.Sprintf("%s:5000", registryEndpoints[3].Port), registry, "/entrypoint.sh", "/etc/docker/registry/config.yml"}) @@ -207,11 +205,12 @@ registries = ['{{.Host}}:{{.Port}}']` Skip("Can not start docker registry.") } + podmanTest.RestoreArtifact(ALPINE) image := fmt.Sprintf("%s/my-alpine", registryEndpoints[3].Address()) - push := podmanTest.Podman([]string{"push", "--tls-verify=false", "--remove-signatures", ALPINE, image}) + push := podmanTest.PodmanNoCache([]string{"push", "--tls-verify=false", "--remove-signatures", ALPINE, image}) push.WaitWithDefaultTimeout() Expect(push.ExitCode()).To(Equal(0)) - search := podmanTest.Podman([]string{"search", image, "--tls-verify=false"}) + search := podmanTest.PodmanNoCache([]string{"search", image, "--tls-verify=false"}) search.WaitWithDefaultTimeout() Expect(search.ExitCode()).To(Equal(0)) @@ -225,7 +224,6 @@ registries = ['{{.Host}}:{{.Port}}']` lock := GetPortLock(registryEndpoints[4].Port) defer lock.Unlock() - podmanTest.RestoreArtifact(registry) 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() @@ -235,8 +233,9 @@ registries = ['{{.Host}}:{{.Port}}']` Skip("Can not start docker registry.") } + podmanTest.RestoreArtifact(ALPINE) image := fmt.Sprintf("%s/my-alpine", registryEndpoints[4].Address()) - push := podmanTest.Podman([]string{"push", "--tls-verify=false", "--remove-signatures", ALPINE, image}) + push := podmanTest.PodmanNoCache([]string{"push", "--tls-verify=false", "--remove-signatures", ALPINE, image}) push.WaitWithDefaultTimeout() Expect(push.ExitCode()).To(Equal(0)) @@ -246,7 +245,7 @@ registries = ['{{.Host}}:{{.Port}}']` podmanTest.setRegistriesConfigEnv(buffer.Bytes()) ioutil.WriteFile(fmt.Sprintf("%s/registry4.conf", tempdir), buffer.Bytes(), 0644) - search := podmanTest.Podman([]string{"search", image}) + search := podmanTest.PodmanNoCache([]string{"search", image}) search.WaitWithDefaultTimeout() Expect(search.ExitCode()).To(Equal(0)) @@ -264,7 +263,6 @@ registries = ['{{.Host}}:{{.Port}}']` } lock := GetPortLock(registryEndpoints[5].Port) defer lock.Unlock() - podmanTest.RestoreArtifact(registry) registry := podmanTest.Podman([]string{"run", "-d", "-p", fmt.Sprintf("%s:5000", registryEndpoints[5].Port), "--name", "registry5", registry}) registry.WaitWithDefaultTimeout() @@ -274,8 +272,9 @@ registries = ['{{.Host}}:{{.Port}}']` Skip("Can not start docker registry.") } + podmanTest.RestoreArtifact(ALPINE) image := fmt.Sprintf("%s/my-alpine", registryEndpoints[5].Address()) - push := podmanTest.Podman([]string{"push", "--tls-verify=false", "--remove-signatures", ALPINE, image}) + push := podmanTest.PodmanNoCache([]string{"push", "--tls-verify=false", "--remove-signatures", ALPINE, image}) push.WaitWithDefaultTimeout() Expect(push.ExitCode()).To(Equal(0)) @@ -284,7 +283,7 @@ registries = ['{{.Host}}:{{.Port}}']` podmanTest.setRegistriesConfigEnv(buffer.Bytes()) ioutil.WriteFile(fmt.Sprintf("%s/registry5.conf", tempdir), buffer.Bytes(), 0644) - search := podmanTest.Podman([]string{"search", image, "--tls-verify=true"}) + search := podmanTest.PodmanNoCache([]string{"search", image, "--tls-verify=true"}) search.WaitWithDefaultTimeout() Expect(search.ExitCode()).To(Equal(0)) @@ -302,7 +301,6 @@ registries = ['{{.Host}}:{{.Port}}']` } lock := GetPortLock(registryEndpoints[6].Port) defer lock.Unlock() - podmanTest.RestoreArtifact(registry) registry := podmanTest.Podman([]string{"run", "-d", "-p", fmt.Sprintf("%s:5000", registryEndpoints[6].Port), "--name", "registry6", registry}) registry.WaitWithDefaultTimeout() @@ -312,8 +310,9 @@ registries = ['{{.Host}}:{{.Port}}']` Skip("Can not start docker registry.") } + podmanTest.RestoreArtifact(ALPINE) image := fmt.Sprintf("%s/my-alpine", registryEndpoints[6].Address()) - push := podmanTest.Podman([]string{"push", "--tls-verify=false", "--remove-signatures", ALPINE, image}) + push := podmanTest.PodmanNoCache([]string{"push", "--tls-verify=false", "--remove-signatures", ALPINE, image}) push.WaitWithDefaultTimeout() Expect(push.ExitCode()).To(Equal(0)) @@ -322,7 +321,7 @@ registries = ['{{.Host}}:{{.Port}}']` podmanTest.setRegistriesConfigEnv(buffer.Bytes()) ioutil.WriteFile(fmt.Sprintf("%s/registry6.conf", tempdir), buffer.Bytes(), 0644) - search := podmanTest.Podman([]string{"search", image}) + search := podmanTest.PodmanNoCache([]string{"search", image}) search.WaitWithDefaultTimeout() Expect(search.ExitCode()).To(Equal(0)) @@ -343,7 +342,6 @@ registries = ['{{.Host}}:{{.Port}}']` lock8 := GetPortLock("6000") defer lock8.Unlock() - podmanTest.RestoreArtifact(registry) registryLocal := podmanTest.Podman([]string{"run", "-d", "--net=host", "-p", fmt.Sprintf("%s:5000", registryEndpoints[7].Port), "--name", "registry7", registry}) registryLocal.WaitWithDefaultTimeout() @@ -361,7 +359,8 @@ registries = ['{{.Host}}:{{.Port}}']` Skip("Can not start docker registry.") } - push := podmanTest.Podman([]string{"push", "--tls-verify=false", "--remove-signatures", ALPINE, "localhost:6000/my-alpine"}) + podmanTest.RestoreArtifact(ALPINE) + push := podmanTest.PodmanNoCache([]string{"push", "--tls-verify=false", "--remove-signatures", ALPINE, "localhost:6000/my-alpine"}) push.WaitWithDefaultTimeout() Expect(push.ExitCode()).To(Equal(0)) @@ -371,7 +370,7 @@ registries = ['{{.Host}}:{{.Port}}']` podmanTest.setRegistriesConfigEnv(buffer.Bytes()) ioutil.WriteFile(fmt.Sprintf("%s/registry8.conf", tempdir), buffer.Bytes(), 0644) - search := podmanTest.Podman([]string{"search", "my-alpine"}) + search := podmanTest.PodmanNoCache([]string{"search", "my-alpine"}) search.WaitWithDefaultTimeout() Expect(search.ExitCode()).To(Equal(0)) diff --git a/test/e2e/start_test.go b/test/e2e/start_test.go index c92da9777..fc1203ed1 100644 --- a/test/e2e/start_test.go +++ b/test/e2e/start_test.go @@ -22,7 +22,7 @@ var _ = Describe("Podman start", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreAllArtifacts() + podmanTest.SeedImages() }) AfterEach(func() { diff --git a/test/e2e/stats_test.go b/test/e2e/stats_test.go index 05f24539f..45511edb8 100644 --- a/test/e2e/stats_test.go +++ b/test/e2e/stats_test.go @@ -26,7 +26,7 @@ var _ = Describe("Podman stats", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreAllArtifacts() + podmanTest.SeedImages() }) AfterEach(func() { diff --git a/test/e2e/stop_test.go b/test/e2e/stop_test.go index e201204df..77ab6dbb0 100644 --- a/test/e2e/stop_test.go +++ b/test/e2e/stop_test.go @@ -23,7 +23,7 @@ var _ = Describe("Podman stop", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreAllArtifacts() + podmanTest.SeedImages() }) AfterEach(func() { diff --git a/test/e2e/system_df_test.go b/test/e2e/system_df_test.go index 92787f17c..bbbdf30b0 100644 --- a/test/e2e/system_df_test.go +++ b/test/e2e/system_df_test.go @@ -25,7 +25,8 @@ var _ = Describe("podman system df", func() { os.Exit(1) } podmanTest = PodmanTestCreate(tempdir) - podmanTest.RestoreAllArtifacts() + podmanTest.Setup() + podmanTest.SeedImages() }) AfterEach(func() { @@ -55,7 +56,7 @@ var _ = Describe("podman system df", func() { images := strings.Fields(session.OutputToStringArray()[1]) containers := strings.Fields(session.OutputToStringArray()[2]) volumes := strings.Fields(session.OutputToStringArray()[3]) - Expect(images[1]).To(Equal("2")) + Expect(images[1]).To(Equal("9")) Expect(containers[1]).To(Equal("2")) Expect(volumes[2]).To(Equal("1")) }) diff --git a/test/e2e/systemd_test.go b/test/e2e/systemd_test.go index 52efc9fca..91604867d 100644 --- a/test/e2e/systemd_test.go +++ b/test/e2e/systemd_test.go @@ -27,7 +27,7 @@ var _ = Describe("Podman systemd", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreAllArtifacts() + podmanTest.SeedImages() systemd_unit_file = `[Unit] Description=redis container [Service] diff --git a/test/e2e/tag_test.go b/test/e2e/tag_test.go index 26d6dfa75..2b513015b 100644 --- a/test/e2e/tag_test.go +++ b/test/e2e/tag_test.go @@ -33,11 +33,11 @@ var _ = Describe("Podman tag", func() { }) It("podman tag shortname:latest", func() { - session := podmanTest.Podman([]string{"tag", ALPINE, "foobar:latest"}) + session := podmanTest.PodmanNoCache([]string{"tag", ALPINE, "foobar:latest"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - results := podmanTest.Podman([]string{"inspect", "foobar:latest"}) + results := podmanTest.PodmanNoCache([]string{"inspect", "foobar:latest"}) results.WaitWithDefaultTimeout() Expect(results.ExitCode()).To(Equal(0)) inspectData := results.InspectImageJSON() @@ -46,11 +46,11 @@ var _ = Describe("Podman tag", func() { }) It("podman tag shortname", func() { - session := podmanTest.Podman([]string{"tag", ALPINE, "foobar"}) + session := podmanTest.PodmanNoCache([]string{"tag", ALPINE, "foobar"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - results := podmanTest.Podman([]string{"inspect", "foobar:latest"}) + results := podmanTest.PodmanNoCache([]string{"inspect", "foobar:latest"}) results.WaitWithDefaultTimeout() Expect(results.ExitCode()).To(Equal(0)) inspectData := results.InspectImageJSON() @@ -59,11 +59,11 @@ var _ = Describe("Podman tag", func() { }) It("podman tag shortname:tag", func() { - session := podmanTest.Podman([]string{"tag", ALPINE, "foobar:new"}) + session := podmanTest.PodmanNoCache([]string{"tag", ALPINE, "foobar:new"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - results := podmanTest.Podman([]string{"inspect", "foobar:new"}) + results := podmanTest.PodmanNoCache([]string{"inspect", "foobar:new"}) results.WaitWithDefaultTimeout() Expect(results.ExitCode()).To(Equal(0)) inspectData := results.InspectImageJSON() @@ -72,15 +72,15 @@ var _ = Describe("Podman tag", func() { }) It("podman tag shortname image no tag", func() { - session := podmanTest.Podman([]string{"tag", ALPINE, "foobar"}) + session := podmanTest.PodmanNoCache([]string{"tag", ALPINE, "foobar"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - results := podmanTest.Podman([]string{"tag", "foobar", "barfoo"}) + results := podmanTest.PodmanNoCache([]string{"tag", "foobar", "barfoo"}) results.WaitWithDefaultTimeout() Expect(results.ExitCode()).To(Equal(0)) - verify := podmanTest.Podman([]string{"inspect", "barfoo"}) + verify := podmanTest.PodmanNoCache([]string{"inspect", "barfoo"}) verify.WaitWithDefaultTimeout() Expect(verify.ExitCode()).To(Equal(0)) }) diff --git a/test/e2e/top_test.go b/test/e2e/top_test.go index 4c2cdb7b5..b62d242f1 100644 --- a/test/e2e/top_test.go +++ b/test/e2e/top_test.go @@ -24,7 +24,7 @@ var _ = Describe("Podman top", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreAllArtifacts() + podmanTest.SeedImages() }) AfterEach(func() { diff --git a/test/e2e/tree_test.go b/test/e2e/tree_test.go index 9740adada..2db7aeb5e 100644 --- a/test/e2e/tree_test.go +++ b/test/e2e/tree_test.go @@ -22,7 +22,8 @@ var _ = Describe("Podman image tree", func() { os.Exit(1) } podmanTest = PodmanTestCreate(tempdir) - podmanTest.RestoreAllArtifacts() + podmanTest.Setup() + podmanTest.RestoreArtifact(BB) }) AfterEach(func() { @@ -36,7 +37,7 @@ var _ = Describe("Podman image tree", func() { if podmanTest.RemoteTest { Skip("Does not work on remote client") } - session := podmanTest.Podman([]string{"pull", "docker.io/library/busybox:latest"}) + session := podmanTest.PodmanNoCache([]string{"pull", "docker.io/library/busybox:latest"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) @@ -47,17 +48,17 @@ ENV foo=bar ` podmanTest.BuildImage(dockerfile, "test:latest", "true") - session = podmanTest.Podman([]string{"image", "tree", "test:latest"}) + session = podmanTest.PodmanNoCache([]string{"image", "tree", "test:latest"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - session = podmanTest.Podman([]string{"image", "tree", "--whatrequires", "docker.io/library/busybox:latest"}) + session = podmanTest.PodmanNoCache([]string{"image", "tree", "--whatrequires", "docker.io/library/busybox:latest"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - session = podmanTest.Podman([]string{"rmi", "test:latest"}) + session = podmanTest.PodmanNoCache([]string{"rmi", "test:latest"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - session = podmanTest.Podman([]string{"rmi", "docker.io/library/busybox:latest"}) + session = podmanTest.PodmanNoCache([]string{"rmi", "docker.io/library/busybox:latest"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) }) diff --git a/test/e2e/trust_test.go b/test/e2e/trust_test.go index 493c4a7d5..8c97e6b28 100644 --- a/test/e2e/trust_test.go +++ b/test/e2e/trust_test.go @@ -27,7 +27,7 @@ var _ = Describe("Podman trust", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreAllArtifacts() + podmanTest.SeedImages() }) AfterEach(func() { diff --git a/test/e2e/unshare_test.go b/test/e2e/unshare_test.go index 1e3f06a62..5f342ffc3 100644 --- a/test/e2e/unshare_test.go +++ b/test/e2e/unshare_test.go @@ -32,7 +32,7 @@ var _ = Describe("Podman unshare", func() { podmanTest.CgroupManager = "cgroupfs" podmanTest.StorageOptions = ROOTLESS_STORAGE_OPTIONS podmanTest.Setup() - podmanTest.RestoreAllArtifacts() + podmanTest.SeedImages() }) AfterEach(func() { diff --git a/test/e2e/version_test.go b/test/e2e/version_test.go index 35ee21e49..2c8b3068c 100644 --- a/test/e2e/version_test.go +++ b/test/e2e/version_test.go @@ -27,6 +27,7 @@ var _ = Describe("Podman version", func() { podmanTest.Cleanup() f := CurrentGinkgoTestDescription() processTestResult(f) + podmanTest.SeedImages() }) diff --git a/test/e2e/volume_create_test.go b/test/e2e/volume_create_test.go index dccecd457..041a9e6f0 100644 --- a/test/e2e/volume_create_test.go +++ b/test/e2e/volume_create_test.go @@ -22,7 +22,7 @@ var _ = Describe("Podman volume create", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreAllArtifacts() + podmanTest.SeedImages() }) AfterEach(func() { diff --git a/test/e2e/volume_inspect_test.go b/test/e2e/volume_inspect_test.go index e7f20ce7b..0683c6bbf 100644 --- a/test/e2e/volume_inspect_test.go +++ b/test/e2e/volume_inspect_test.go @@ -22,7 +22,7 @@ var _ = Describe("Podman volume inspect", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreAllArtifacts() + podmanTest.SeedImages() }) AfterEach(func() { diff --git a/test/e2e/volume_ls_test.go b/test/e2e/volume_ls_test.go index 1f0177def..da2d7ae77 100644 --- a/test/e2e/volume_ls_test.go +++ b/test/e2e/volume_ls_test.go @@ -22,7 +22,7 @@ var _ = Describe("Podman volume ls", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreAllArtifacts() + podmanTest.SeedImages() }) AfterEach(func() { diff --git a/test/e2e/volume_prune_test.go b/test/e2e/volume_prune_test.go index 55a95c8c9..ba249278b 100644 --- a/test/e2e/volume_prune_test.go +++ b/test/e2e/volume_prune_test.go @@ -24,7 +24,7 @@ var _ = Describe("Podman volume prune", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreAllArtifacts() + podmanTest.SeedImages() }) AfterEach(func() { diff --git a/test/e2e/volume_rm_test.go b/test/e2e/volume_rm_test.go index 39628d56f..5dcf51ccd 100644 --- a/test/e2e/volume_rm_test.go +++ b/test/e2e/volume_rm_test.go @@ -22,7 +22,7 @@ var _ = Describe("Podman volume rm", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreAllArtifacts() + podmanTest.SeedImages() }) AfterEach(func() { diff --git a/test/e2e/wait_test.go b/test/e2e/wait_test.go index 28a4c1e40..c03116b01 100644 --- a/test/e2e/wait_test.go +++ b/test/e2e/wait_test.go @@ -22,7 +22,7 @@ var _ = Describe("Podman wait", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.RestoreAllArtifacts() + podmanTest.SeedImages() }) AfterEach(func() { diff --git a/test/utils/podmantest_test.go b/test/utils/podmantest_test.go index 28f294a94..cb31d5548 100644 --- a/test/utils/podmantest_test.go +++ b/test/utils/podmantest_test.go @@ -23,7 +23,7 @@ var _ = Describe("PodmanTest test", func() { FakeOutputs["check"] = []string{"check"} os.Setenv("HOOK_OPTION", "hook_option") env := os.Environ() - session := podmanTest.PodmanAsUserBase([]string{"check"}, 1000, 1000, "", env) + session := podmanTest.PodmanAsUserBase([]string{"check"}, 1000, 1000, "", env, true) os.Unsetenv("HOOK_OPTION") session.WaitWithDefaultTimeout() Expect(session.Command.Process).ShouldNot(BeNil()) diff --git a/test/utils/utils.go b/test/utils/utils.go index beadab549..98031385d 100644 --- a/test/utils/utils.go +++ b/test/utils/utils.go @@ -42,6 +42,8 @@ type PodmanTest struct { VarlinkSession *os.Process VarlinkEndpoint string VarlinkCommand *exec.Cmd + ImageCacheDir string + ImageCacheFS string } // PodmanSession wraps the gexec.session so we can extend it @@ -63,7 +65,7 @@ func (p *PodmanTest) MakeOptions(args []string) []string { // PodmanAsUserBase exec podman as user. uid and gid is set for credentials useage. env is used // to record the env for debugging -func (p *PodmanTest) PodmanAsUserBase(args []string, uid, gid uint32, cwd string, env []string) *PodmanSession { +func (p *PodmanTest) PodmanAsUserBase(args []string, uid, gid uint32, cwd string, env []string, nocache bool) *PodmanSession { var command *exec.Cmd podmanOptions := p.MakeOptions(args) podmanBinary := p.PodmanBinary @@ -71,6 +73,10 @@ func (p *PodmanTest) PodmanAsUserBase(args []string, uid, gid uint32, cwd string podmanBinary = p.RemotePodmanBinary env = append(env, fmt.Sprintf("PODMAN_VARLINK_ADDRESS=%s", p.VarlinkEndpoint)) } + if !nocache && !p.RemoteTest { + cacheOptions := []string{"--storage-opt", fmt.Sprintf("%s.imagestore=%s", p.ImageCacheFS, p.ImageCacheDir)} + podmanOptions = append(cacheOptions, podmanOptions...) + } if env == nil { fmt.Printf("Running: %s %s\n", podmanBinary, strings.Join(podmanOptions, " ")) @@ -99,8 +105,8 @@ func (p *PodmanTest) PodmanAsUserBase(args []string, uid, gid uint32, cwd string } // PodmanBase exec podman with default env. -func (p *PodmanTest) PodmanBase(args []string) *PodmanSession { - return p.PodmanAsUserBase(args, 0, 0, "", nil) +func (p *PodmanTest) PodmanBase(args []string, nocache bool) *PodmanSession { + return p.PodmanAsUserBase(args, 0, 0, "", nil, nocache) } // WaitForContainer waits on a started container @@ -118,7 +124,7 @@ func (p *PodmanTest) WaitForContainer() bool { // containers are currently running. func (p *PodmanTest) NumberOfContainersRunning() int { var containers []string - ps := p.PodmanBase([]string{"ps", "-q"}) + ps := p.PodmanBase([]string{"ps", "-q"}, true) ps.WaitWithDefaultTimeout() Expect(ps.ExitCode()).To(Equal(0)) for _, i := range ps.OutputToStringArray() { @@ -133,7 +139,7 @@ func (p *PodmanTest) NumberOfContainersRunning() int { // containers are currently defined. func (p *PodmanTest) NumberOfContainers() int { var containers []string - ps := p.PodmanBase([]string{"ps", "-aq"}) + ps := p.PodmanBase([]string{"ps", "-aq"}, true) ps.WaitWithDefaultTimeout() Expect(ps.ExitCode()).To(Equal(0)) for _, i := range ps.OutputToStringArray() { @@ -148,7 +154,7 @@ func (p *PodmanTest) NumberOfContainers() int { // pods are currently defined. func (p *PodmanTest) NumberOfPods() int { var pods []string - ps := p.PodmanBase([]string{"pod", "ps", "-q"}) + ps := p.PodmanBase([]string{"pod", "ps", "-q"}, true) ps.WaitWithDefaultTimeout() Expect(ps.ExitCode()).To(Equal(0)) for _, i := range ps.OutputToStringArray() { @@ -164,7 +170,7 @@ func (p *PodmanTest) NumberOfPods() int { func (p *PodmanTest) GetContainerStatus() string { var podmanArgs = []string{"ps"} podmanArgs = append(podmanArgs, "--all", "--format={{.Status}}") - session := p.PodmanBase(podmanArgs) + session := p.PodmanBase(podmanArgs, true) session.WaitWithDefaultTimeout() return session.OutputToString() } @@ -172,7 +178,7 @@ func (p *PodmanTest) GetContainerStatus() string { // WaitContainerReady waits process or service inside container start, and ready to be used. func (p *PodmanTest) WaitContainerReady(id string, expStr string, timeout int, step int) bool { startTime := time.Now() - s := p.PodmanBase([]string{"logs", id}) + s := p.PodmanBase([]string{"logs", id}, true) s.WaitWithDefaultTimeout() for { @@ -185,7 +191,7 @@ func (p *PodmanTest) WaitContainerReady(id string, expStr string, timeout int, s return true } time.Sleep(time.Duration(step) * time.Second) - s = p.PodmanBase([]string{"logs", id}) + s = p.PodmanBase([]string{"logs", id}, true) s.WaitWithDefaultTimeout() } } diff --git a/transfer.md b/transfer.md index 79b6d3461..7cfd5a85d 100644 --- a/transfer.md +++ b/transfer.md @@ -91,10 +91,11 @@ Those Docker commands currently do not have equivalents in `podman`: | Missing command | Description| | :--- | :--- | +| `docker container update` | podman does not support altering running containers. We recommend recreating containers with the correct arguments.| +| `docker container rename` | podman does not support `container rename` - or the `rename` shorthand. We recommend using `podman rm` and `podman create` to create a container with a specific name.| | `docker network` || | `docker node` || | `docker plugin` | podman does not support plugins. We recommend you use alternative OCI Runtimes or OCI Runtime Hooks to alter behavior of podman.| -| `docker rename` | podman does not support rename, you need to use `podman rm` and `podman create` to rename a container.| | `docker secret` || | `docker service` || | `docker stack` || diff --git a/vendor.conf b/vendor.conf index 5c41d6908..65bfcd77a 100644 --- a/vendor.conf +++ b/vendor.conf @@ -21,7 +21,7 @@ github.com/mattn/go-isatty v0.0.4 github.com/VividCortex/ewma v1.1.1 github.com/containers/storage v1.12.7 github.com/containers/psgo v1.3.0 -github.com/coreos/go-systemd v14 +github.com/coreos/go-systemd v17 github.com/coreos/pkg v4 github.com/cri-o/ocicni 0c180f981b27ef6036fa5be29bcb4dd666e406eb github.com/cyphar/filepath-securejoin v0.2.1 diff --git a/vendor/github.com/coreos/go-systemd/NOTICE b/vendor/github.com/coreos/go-systemd/NOTICE new file mode 100644 index 000000000..23a0ada2f --- /dev/null +++ b/vendor/github.com/coreos/go-systemd/NOTICE @@ -0,0 +1,5 @@ +CoreOS Project +Copyright 2018 CoreOS, Inc + +This product includes software developed at CoreOS, Inc. +(http://www.coreos.com/). diff --git a/vendor/github.com/coreos/go-systemd/README.md b/vendor/github.com/coreos/go-systemd/README.md index cb87a1124..cad04a803 100644 --- a/vendor/github.com/coreos/go-systemd/README.md +++ b/vendor/github.com/coreos/go-systemd/README.md @@ -6,9 +6,11 @@ Go bindings to systemd. The project has several packages: - `activation` - for writing and using socket activation from Go +- `daemon` - for notifying systemd of service status changes - `dbus` - for starting/stopping/inspecting running services and units - `journal` - for writing to systemd's logging service, journald - `sdjournal` - for reading from journald by wrapping its C API +- `login1` - for integration with the systemd logind API - `machine1` - for registering machines/containers with systemd - `unit` - for (de)serialization and comparison of unit files @@ -18,10 +20,9 @@ An example HTTP server using socket activation can be quickly set up by followin https://github.com/coreos/go-systemd/tree/master/examples/activation/httpserver -## Journal +## systemd Service Notification -Using the pure-Go `journal` package you can submit journal entries directly to systemd's journal, taking advantage of features like indexed key/value pairs for each log entry. -The `sdjournal` package provides read access to the journal by wrapping around journald's native C API; consequently it requires cgo and the journal headers to be available. +The `daemon` package is an implementation of the [sd_notify protocol](https://www.freedesktop.org/software/systemd/man/sd_notify.html#Description). It can be used to inform systemd of service start-up completion, watchdog events, and other status changes. ## D-Bus @@ -45,6 +46,20 @@ Create `/etc/dbus-1/system-local.conf` that looks like this: </busconfig> ``` +## Journal + +### Writing to the Journal + +Using the pure-Go `journal` package you can submit journal entries directly to systemd's journal, taking advantage of features like indexed key/value pairs for each log entry. + +### Reading from the Journal + +The `sdjournal` package provides read access to the journal by wrapping around journald's native C API; consequently it requires cgo and the journal headers to be available. + +## logind + +The `login1` package provides functions to integrate with the [systemd logind API](http://www.freedesktop.org/wiki/Software/systemd/logind/). + ## machined The `machine1` package allows interaction with the [systemd machined D-Bus API](http://www.freedesktop.org/wiki/Software/systemd/machined/). diff --git a/vendor/github.com/coreos/go-systemd/activation/files.go b/vendor/github.com/coreos/go-systemd/activation/files.go index c8e85fcd5..29dd18def 100644 --- a/vendor/github.com/coreos/go-systemd/activation/files.go +++ b/vendor/github.com/coreos/go-systemd/activation/files.go @@ -18,18 +18,26 @@ package activation import ( "os" "strconv" + "strings" "syscall" ) -// based on: https://gist.github.com/alberts/4640792 const ( + // listenFdsStart corresponds to `SD_LISTEN_FDS_START`. listenFdsStart = 3 ) +// Files returns a slice containing a `os.File` object for each +// file descriptor passed to this process via systemd fd-passing protocol. +// +// The order of the file descriptors is preserved in the returned slice. +// `unsetEnv` is typically set to `true` in order to avoid clashes in +// fd usage and to avoid leaking environment flags to child processes. func Files(unsetEnv bool) []*os.File { if unsetEnv { defer os.Unsetenv("LISTEN_PID") defer os.Unsetenv("LISTEN_FDS") + defer os.Unsetenv("LISTEN_FDNAMES") } pid, err := strconv.Atoi(os.Getenv("LISTEN_PID")) @@ -42,10 +50,17 @@ func Files(unsetEnv bool) []*os.File { return nil } + names := strings.Split(os.Getenv("LISTEN_FDNAMES"), ":") + files := make([]*os.File, 0, nfds) for fd := listenFdsStart; fd < listenFdsStart+nfds; fd++ { syscall.CloseOnExec(fd) - files = append(files, os.NewFile(uintptr(fd), "LISTEN_FD_"+strconv.Itoa(fd))) + name := "LISTEN_FD_" + strconv.Itoa(fd) + offset := fd - listenFdsStart + if offset < len(names) && len(names[offset]) > 0 { + name = names[offset] + } + files = append(files, os.NewFile(uintptr(fd), name)) } return files diff --git a/vendor/github.com/coreos/go-systemd/activation/listeners.go b/vendor/github.com/coreos/go-systemd/activation/listeners.go index fd5dfc709..bb5cc2311 100644 --- a/vendor/github.com/coreos/go-systemd/activation/listeners.go +++ b/vendor/github.com/coreos/go-systemd/activation/listeners.go @@ -25,13 +25,33 @@ import ( // The order of the file descriptors is preserved in the returned slice. // Nil values are used to fill any gaps. For example if systemd were to return file descriptors // corresponding with "udp, tcp, tcp", then the slice would contain {nil, net.Listener, net.Listener} -func Listeners(unsetEnv bool) ([]net.Listener, error) { - files := Files(unsetEnv) +func Listeners() ([]net.Listener, error) { + files := Files(true) listeners := make([]net.Listener, len(files)) for i, f := range files { if pc, err := net.FileListener(f); err == nil { listeners[i] = pc + f.Close() + } + } + return listeners, nil +} + +// ListenersWithNames maps a listener name to a set of net.Listener instances. +func ListenersWithNames() (map[string][]net.Listener, error) { + files := Files(true) + listeners := map[string][]net.Listener{} + + for _, f := range files { + if pc, err := net.FileListener(f); err == nil { + current, ok := listeners[f.Name()] + if !ok { + listeners[f.Name()] = []net.Listener{pc} + } else { + listeners[f.Name()] = append(current, pc) + } + f.Close() } } return listeners, nil @@ -40,8 +60,8 @@ func Listeners(unsetEnv bool) ([]net.Listener, error) { // TLSListeners returns a slice containing a net.listener for each matching TCP socket type // passed to this process. // It uses default Listeners func and forces TCP sockets handlers to use TLS based on tlsConfig. -func TLSListeners(unsetEnv bool, tlsConfig *tls.Config) ([]net.Listener, error) { - listeners, err := Listeners(unsetEnv) +func TLSListeners(tlsConfig *tls.Config) ([]net.Listener, error) { + listeners, err := Listeners() if listeners == nil || err != nil { return nil, err @@ -58,3 +78,26 @@ func TLSListeners(unsetEnv bool, tlsConfig *tls.Config) ([]net.Listener, error) return listeners, err } + +// TLSListenersWithNames maps a listener name to a net.Listener with +// the associated TLS configuration. +func TLSListenersWithNames(tlsConfig *tls.Config) (map[string][]net.Listener, error) { + listeners, err := ListenersWithNames() + + if listeners == nil || err != nil { + return nil, err + } + + if tlsConfig != nil && err == nil { + for _, ll := range listeners { + // Activate TLS only for TCP sockets + for i, l := range ll { + if l.Addr().Network() == "tcp" { + ll[i] = tls.NewListener(l, tlsConfig) + } + } + } + } + + return listeners, err +} diff --git a/vendor/github.com/coreos/go-systemd/activation/packetconns.go b/vendor/github.com/coreos/go-systemd/activation/packetconns.go index 48b2ca029..a97206785 100644 --- a/vendor/github.com/coreos/go-systemd/activation/packetconns.go +++ b/vendor/github.com/coreos/go-systemd/activation/packetconns.go @@ -24,13 +24,14 @@ import ( // The order of the file descriptors is preserved in the returned slice. // Nil values are used to fill any gaps. For example if systemd were to return file descriptors // corresponding with "udp, tcp, udp", then the slice would contain {net.PacketConn, nil, net.PacketConn} -func PacketConns(unsetEnv bool) ([]net.PacketConn, error) { - files := Files(unsetEnv) +func PacketConns() ([]net.PacketConn, error) { + files := Files(true) conns := make([]net.PacketConn, len(files)) for i, f := range files { if pc, err := net.FilePacketConn(f); err == nil { conns[i] = pc + f.Close() } } return conns, nil diff --git a/vendor/github.com/coreos/go-systemd/dbus/dbus.go b/vendor/github.com/coreos/go-systemd/dbus/dbus.go index c1694fb52..1d54810af 100644 --- a/vendor/github.com/coreos/go-systemd/dbus/dbus.go +++ b/vendor/github.com/coreos/go-systemd/dbus/dbus.go @@ -16,6 +16,7 @@ package dbus import ( + "encoding/hex" "fmt" "os" "strconv" @@ -60,6 +61,27 @@ func PathBusEscape(path string) string { return string(n) } +// pathBusUnescape is the inverse of PathBusEscape. +func pathBusUnescape(path string) string { + if path == "_" { + return "" + } + n := []byte{} + for i := 0; i < len(path); i++ { + c := path[i] + if c == '_' && i+2 < len(path) { + res, err := hex.DecodeString(path[i+1 : i+3]) + if err == nil { + n = append(n, res...) + } + i += 2 + } else { + n = append(n, c) + } + } + return string(n) +} + // Conn is a connection to systemd's dbus endpoint. type Conn struct { // sysconn/sysobj are only used to call dbus methods @@ -74,13 +96,18 @@ type Conn struct { jobs map[dbus.ObjectPath]chan<- string sync.Mutex } - subscriber struct { + subStateSubscriber struct { updateCh chan<- *SubStateUpdate errCh chan<- error sync.Mutex ignore map[dbus.ObjectPath]int64 cleanIgnore int64 } + propertiesSubscriber struct { + updateCh chan<- *PropertiesUpdate + errCh chan<- error + sync.Mutex + } } // New establishes a connection to any available bus and authenticates. @@ -152,7 +179,7 @@ func NewConnection(dialBus func() (*dbus.Conn, error)) (*Conn, error) { sigobj: systemdObject(sigconn), } - c.subscriber.ignore = make(map[dbus.ObjectPath]int64) + c.subStateSubscriber.ignore = make(map[dbus.ObjectPath]int64) c.jobListener.jobs = make(map[dbus.ObjectPath]chan<- string) // Setup the listeners on jobs so that we can get completions diff --git a/vendor/github.com/coreos/go-systemd/dbus/methods.go b/vendor/github.com/coreos/go-systemd/dbus/methods.go index ab17f7cc7..0b4207229 100644 --- a/vendor/github.com/coreos/go-systemd/dbus/methods.go +++ b/vendor/github.com/coreos/go-systemd/dbus/methods.go @@ -1,4 +1,4 @@ -// Copyright 2015 CoreOS, Inc. +// Copyright 2015, 2018 CoreOS, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -16,6 +16,7 @@ package dbus import ( "errors" + "fmt" "path" "strconv" @@ -148,14 +149,27 @@ func (c *Conn) ResetFailedUnit(name string) error { return c.sysobj.Call("org.freedesktop.systemd1.Manager.ResetFailedUnit", 0, name).Store() } -// getProperties takes the unit name and returns all of its dbus object properties, for the given dbus interface -func (c *Conn) getProperties(unit string, dbusInterface string) (map[string]interface{}, error) { +// SystemState returns the systemd state. Equivalent to `systemctl is-system-running`. +func (c *Conn) SystemState() (*Property, error) { + var err error + var prop dbus.Variant + + obj := c.sysconn.Object("org.freedesktop.systemd1", "/org/freedesktop/systemd1") + err = obj.Call("org.freedesktop.DBus.Properties.Get", 0, "org.freedesktop.systemd1.Manager", "SystemState").Store(&prop) + if err != nil { + return nil, err + } + + return &Property{Name: "SystemState", Value: prop}, nil +} + +// getProperties takes the unit path and returns all of its dbus object properties, for the given dbus interface +func (c *Conn) getProperties(path dbus.ObjectPath, dbusInterface string) (map[string]interface{}, error) { var err error var props map[string]dbus.Variant - path := unitPath(unit) if !path.IsValid() { - return nil, errors.New("invalid unit name: " + unit) + return nil, fmt.Errorf("invalid unit name: %v", path) } obj := c.sysconn.Object("org.freedesktop.systemd1", path) @@ -172,9 +186,15 @@ func (c *Conn) getProperties(unit string, dbusInterface string) (map[string]inte return out, nil } -// GetUnitProperties takes the unit name and returns all of its dbus object properties. +// GetUnitProperties takes the (unescaped) unit name and returns all of its dbus object properties. func (c *Conn) GetUnitProperties(unit string) (map[string]interface{}, error) { - return c.getProperties(unit, "org.freedesktop.systemd1.Unit") + path := unitPath(unit) + return c.getProperties(path, "org.freedesktop.systemd1.Unit") +} + +// GetUnitProperties takes the (escaped) unit path and returns all of its dbus object properties. +func (c *Conn) GetUnitPathProperties(path dbus.ObjectPath) (map[string]interface{}, error) { + return c.getProperties(path, "org.freedesktop.systemd1.Unit") } func (c *Conn) getProperty(unit string, dbusInterface string, propertyName string) (*Property, error) { @@ -208,7 +228,8 @@ func (c *Conn) GetServiceProperty(service string, propertyName string) (*Propert // Valid values for unitType: Service, Socket, Target, Device, Mount, Automount, Snapshot, Timer, Swap, Path, Slice, Scope // return "dbus.Error: Unknown interface" if the unitType is not the correct type of the unit func (c *Conn) GetUnitTypeProperties(unit string, unitType string) (map[string]interface{}, error) { - return c.getProperties(unit, "org.freedesktop.systemd1."+unitType) + path := unitPath(unit) + return c.getProperties(path, "org.freedesktop.systemd1."+unitType) } // SetUnitProperties() may be used to modify certain unit properties at runtime. @@ -292,6 +313,7 @@ func (c *Conn) ListUnitsByPatterns(states []string, patterns []string) ([]UnitSt // names and returns an UnitStatus array. Comparing to ListUnitsByPatterns // method, this method returns statuses even for inactive or non-existing // units. Input array should contain exact unit names, but not patterns. +// Note: Requires systemd v230 or higher func (c *Conn) ListUnitsByNames(units []string) ([]UnitStatus, error) { return c.listUnitsInternal(c.sysobj.Call("org.freedesktop.systemd1.Manager.ListUnitsByNames", 0, units).Store) } @@ -563,3 +585,8 @@ func (c *Conn) Reload() error { func unitPath(name string) dbus.ObjectPath { return dbus.ObjectPath("/org/freedesktop/systemd1/unit/" + PathBusEscape(name)) } + +// unitName returns the unescaped base element of the supplied escaped path +func unitName(dpath dbus.ObjectPath) string { + return pathBusUnescape(path.Base(string(dpath))) +} diff --git a/vendor/github.com/coreos/go-systemd/dbus/set.go b/vendor/github.com/coreos/go-systemd/dbus/set.go index f92e6fbed..17c5d4856 100644 --- a/vendor/github.com/coreos/go-systemd/dbus/set.go +++ b/vendor/github.com/coreos/go-systemd/dbus/set.go @@ -36,7 +36,7 @@ func (s *set) Length() int { } func (s *set) Values() (values []string) { - for val, _ := range s.data { + for val := range s.data { values = append(values, val) } return diff --git a/vendor/github.com/coreos/go-systemd/dbus/subscription.go b/vendor/github.com/coreos/go-systemd/dbus/subscription.go index 996451445..70e63a6f1 100644 --- a/vendor/github.com/coreos/go-systemd/dbus/subscription.go +++ b/vendor/github.com/coreos/go-systemd/dbus/subscription.go @@ -16,6 +16,7 @@ package dbus import ( "errors" + "log" "time" "github.com/godbus/dbus" @@ -36,22 +37,12 @@ func (c *Conn) Subscribe() error { c.sigconn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0, "type='signal',interface='org.freedesktop.DBus.Properties',member='PropertiesChanged'") - err := c.sigobj.Call("org.freedesktop.systemd1.Manager.Subscribe", 0).Store() - if err != nil { - return err - } - - return nil + return c.sigobj.Call("org.freedesktop.systemd1.Manager.Subscribe", 0).Store() } // Unsubscribe this connection from systemd dbus events. func (c *Conn) Unsubscribe() error { - err := c.sigobj.Call("org.freedesktop.systemd1.Manager.Unsubscribe", 0).Store() - if err != nil { - return err - } - - return nil + return c.sigobj.Call("org.freedesktop.systemd1.Manager.Unsubscribe", 0).Store() } func (c *Conn) dispatch() { @@ -70,7 +61,8 @@ func (c *Conn) dispatch() { c.jobComplete(signal) } - if c.subscriber.updateCh == nil { + if c.subStateSubscriber.updateCh == nil && + c.propertiesSubscriber.updateCh == nil { continue } @@ -84,6 +76,12 @@ func (c *Conn) dispatch() { case "org.freedesktop.DBus.Properties.PropertiesChanged": if signal.Body[0].(string) == "org.freedesktop.systemd1.Unit" { unitPath = signal.Path + + if len(signal.Body) >= 2 { + if changed, ok := signal.Body[1].(map[string]dbus.Variant); ok { + c.sendPropertiesUpdate(unitPath, changed) + } + } } } @@ -169,42 +167,80 @@ type SubStateUpdate struct { // is full, it attempts to write an error to errCh; if errCh is full, the error // passes silently. func (c *Conn) SetSubStateSubscriber(updateCh chan<- *SubStateUpdate, errCh chan<- error) { - c.subscriber.Lock() - defer c.subscriber.Unlock() - c.subscriber.updateCh = updateCh - c.subscriber.errCh = errCh + if c == nil { + msg := "nil receiver" + select { + case errCh <- errors.New(msg): + default: + log.Printf("full error channel while reporting: %s\n", msg) + } + return + } + + c.subStateSubscriber.Lock() + defer c.subStateSubscriber.Unlock() + c.subStateSubscriber.updateCh = updateCh + c.subStateSubscriber.errCh = errCh } -func (c *Conn) sendSubStateUpdate(path dbus.ObjectPath) { - c.subscriber.Lock() - defer c.subscriber.Unlock() +func (c *Conn) sendSubStateUpdate(unitPath dbus.ObjectPath) { + c.subStateSubscriber.Lock() + defer c.subStateSubscriber.Unlock() + + if c.subStateSubscriber.updateCh == nil { + return + } - if c.shouldIgnore(path) { + isIgnored := c.shouldIgnore(unitPath) + defer c.cleanIgnore() + if isIgnored { return } - info, err := c.GetUnitProperties(string(path)) + info, err := c.GetUnitPathProperties(unitPath) if err != nil { select { - case c.subscriber.errCh <- err: + case c.subStateSubscriber.errCh <- err: default: + log.Printf("full error channel while reporting: %s\n", err) } + return } + defer c.updateIgnore(unitPath, info) - name := info["Id"].(string) - substate := info["SubState"].(string) + name, ok := info["Id"].(string) + if !ok { + msg := "failed to cast info.Id" + select { + case c.subStateSubscriber.errCh <- errors.New(msg): + default: + log.Printf("full error channel while reporting: %s\n", err) + } + return + } + substate, ok := info["SubState"].(string) + if !ok { + msg := "failed to cast info.SubState" + select { + case c.subStateSubscriber.errCh <- errors.New(msg): + default: + log.Printf("full error channel while reporting: %s\n", msg) + } + return + } update := &SubStateUpdate{name, substate} select { - case c.subscriber.updateCh <- update: + case c.subStateSubscriber.updateCh <- update: default: + msg := "update channel is full" select { - case c.subscriber.errCh <- errors.New("update channel full!"): + case c.subStateSubscriber.errCh <- errors.New(msg): default: + log.Printf("full error channel while reporting: %s\n", msg) } + return } - - c.updateIgnore(path, info) } // The ignore functions work around a wart in the systemd dbus interface. @@ -222,29 +258,76 @@ func (c *Conn) sendSubStateUpdate(path dbus.ObjectPath) { // the properties). func (c *Conn) shouldIgnore(path dbus.ObjectPath) bool { - t, ok := c.subscriber.ignore[path] + t, ok := c.subStateSubscriber.ignore[path] return ok && t >= time.Now().UnixNano() } func (c *Conn) updateIgnore(path dbus.ObjectPath, info map[string]interface{}) { - c.cleanIgnore() + loadState, ok := info["LoadState"].(string) + if !ok { + return + } // unit is unloaded - it will trigger bad systemd dbus behavior - if info["LoadState"].(string) == "not-found" { - c.subscriber.ignore[path] = time.Now().UnixNano() + ignoreInterval + if loadState == "not-found" { + c.subStateSubscriber.ignore[path] = time.Now().UnixNano() + ignoreInterval } } // without this, ignore would grow unboundedly over time func (c *Conn) cleanIgnore() { now := time.Now().UnixNano() - if c.subscriber.cleanIgnore < now { - c.subscriber.cleanIgnore = now + cleanIgnoreInterval + if c.subStateSubscriber.cleanIgnore < now { + c.subStateSubscriber.cleanIgnore = now + cleanIgnoreInterval - for p, t := range c.subscriber.ignore { + for p, t := range c.subStateSubscriber.ignore { if t < now { - delete(c.subscriber.ignore, p) + delete(c.subStateSubscriber.ignore, p) } } } } + +// PropertiesUpdate holds a map of a unit's changed properties +type PropertiesUpdate struct { + UnitName string + Changed map[string]dbus.Variant +} + +// SetPropertiesSubscriber writes to updateCh when any unit's properties +// change. Every property change reported by systemd will be sent; that is, no +// transitions will be "missed" (as they might be with SetSubStateSubscriber). +// However, state changes will only be written to the channel with non-blocking +// writes. If updateCh is full, it attempts to write an error to errCh; if +// errCh is full, the error passes silently. +func (c *Conn) SetPropertiesSubscriber(updateCh chan<- *PropertiesUpdate, errCh chan<- error) { + c.propertiesSubscriber.Lock() + defer c.propertiesSubscriber.Unlock() + c.propertiesSubscriber.updateCh = updateCh + c.propertiesSubscriber.errCh = errCh +} + +// we don't need to worry about shouldIgnore() here because +// sendPropertiesUpdate doesn't call GetProperties() +func (c *Conn) sendPropertiesUpdate(unitPath dbus.ObjectPath, changedProps map[string]dbus.Variant) { + c.propertiesSubscriber.Lock() + defer c.propertiesSubscriber.Unlock() + + if c.propertiesSubscriber.updateCh == nil { + return + } + + update := &PropertiesUpdate{unitName(unitPath), changedProps} + + select { + case c.propertiesSubscriber.updateCh <- update: + default: + msg := "update channel is full" + select { + case c.propertiesSubscriber.errCh <- errors.New(msg): + default: + log.Printf("full error channel while reporting: %s\n", msg) + } + return + } +} diff --git a/vendor/github.com/coreos/go-systemd/journal/journal.go b/vendor/github.com/coreos/go-systemd/journal/journal.go index 7f434990d..ef85a3ba2 100644 --- a/vendor/github.com/coreos/go-systemd/journal/journal.go +++ b/vendor/github.com/coreos/go-systemd/journal/journal.go @@ -103,7 +103,10 @@ func Send(message string, priority Priority, vars map[string]string) error { if !ok { return journalError("can't send file through non-Unix connection") } - unixConn.WriteMsgUnix([]byte{}, rights, nil) + _, _, err = unixConn.WriteMsgUnix([]byte{}, rights, nil) + if err != nil { + return journalError(err.Error()) + } } else if err != nil { return journalError(err.Error()) } @@ -165,7 +168,7 @@ func tempFd() (*os.File, error) { if err != nil { return nil, err } - syscall.Unlink(file.Name()) + err = syscall.Unlink(file.Name()) if err != nil { return nil, err } diff --git a/vendor/github.com/coreos/go-systemd/sdjournal/journal.go b/vendor/github.com/coreos/go-systemd/sdjournal/journal.go index b00d606c1..9f3d92342 100644 --- a/vendor/github.com/coreos/go-systemd/sdjournal/journal.go +++ b/vendor/github.com/coreos/go-systemd/sdjournal/journal.go @@ -47,6 +47,15 @@ package sdjournal // return sd_journal_open_directory(ret, path, flags); // } // +// int +// my_sd_journal_open_files(void *f, sd_journal **ret, const char **paths, int flags) +// { +// int (*sd_journal_open_files)(sd_journal **, const char **, int); +// +// sd_journal_open_files = f; +// return sd_journal_open_files(ret, paths, flags); +// } +// // void // my_sd_journal_close(void *f, sd_journal *j) // { @@ -282,9 +291,19 @@ package sdjournal // sd_journal_restart_unique(j); // } // +// int +// my_sd_journal_get_catalog(void *f, sd_journal *j, char **ret) +// { +// int(*sd_journal_get_catalog)(sd_journal *, char **); +// +// sd_journal_get_catalog = f; +// return sd_journal_get_catalog(j, ret); +// } +// import "C" import ( "bytes" + "errors" "fmt" "strings" "sync" @@ -352,6 +371,12 @@ const ( IndefiniteWait time.Duration = 1<<63 - 1 ) +var ( + // ErrNoTestCursor gets returned when using TestCursor function and cursor + // parameter is not the same as the current cursor position. + ErrNoTestCursor = errors.New("Cursor parameter is not the same as current position") +) + // Journal is a Go wrapper of an sd_journal structure. type Journal struct { cjournal *C.sd_journal @@ -396,8 +421,7 @@ func NewJournal() (j *Journal, err error) { } // NewJournalFromDir returns a new Journal instance pointing to a journal residing -// in a given directory. The supplied path may be relative or absolute; if -// relative, it will be converted to an absolute path before being opened. +// in a given directory. func NewJournalFromDir(path string) (j *Journal, err error) { j = &Journal{} @@ -417,6 +441,32 @@ func NewJournalFromDir(path string) (j *Journal, err error) { return j, nil } +// NewJournalFromFiles returns a new Journal instance pointing to a journals residing +// in a given files. +func NewJournalFromFiles(paths ...string) (j *Journal, err error) { + j = &Journal{} + + sd_journal_open_files, err := getFunction("sd_journal_open_files") + if err != nil { + return nil, err + } + + // by making the slice 1 elem too long, we guarantee it'll be null-terminated + cPaths := make([]*C.char, len(paths)+1) + for idx, path := range paths { + p := C.CString(path) + cPaths[idx] = p + defer C.free(unsafe.Pointer(p)) + } + + r := C.my_sd_journal_open_files(sd_journal_open_files, &j.cjournal, &cPaths[0], 0) + if r < 0 { + return nil, fmt.Errorf("failed to open journals in paths %q: %d", paths, syscall.Errno(-r)) + } + + return j, nil +} + // Close closes a journal opened with NewJournal. func (j *Journal) Close() error { sd_journal_close, err := getFunction("sd_journal_close") @@ -598,7 +648,8 @@ func (j *Journal) getData(field string) (unsafe.Pointer, C.int, error) { } // GetData gets the data object associated with a specific field from the -// current journal entry. +// the journal entry referenced by the last completed Next/Previous function +// call. To call GetData, you must have first called one of these functions. func (j *Journal) GetData(field string) (string, error) { d, l, err := j.getData(field) if err != nil { @@ -609,7 +660,9 @@ func (j *Journal) GetData(field string) (string, error) { } // GetDataValue gets the data object associated with a specific field from the -// current journal entry, returning only the value of the object. +// journal entry referenced by the last completed Next/Previous function call, +// returning only the value of the object. To call GetDataValue, you must first +// have called one of the Next/Previous functions. func (j *Journal) GetDataValue(field string) (string, error) { val, err := j.GetData(field) if err != nil { @@ -620,7 +673,8 @@ func (j *Journal) GetDataValue(field string) (string, error) { } // GetDataBytes gets the data object associated with a specific field from the -// current journal entry. +// journal entry referenced by the last completed Next/Previous function call. +// To call GetDataBytes, you must first have called one of these functions. func (j *Journal) GetDataBytes(field string) ([]byte, error) { d, l, err := j.getData(field) if err != nil { @@ -631,7 +685,9 @@ func (j *Journal) GetDataBytes(field string) ([]byte, error) { } // GetDataValueBytes gets the data object associated with a specific field from the -// current journal entry, returning only the value of the object. +// journal entry referenced by the last completed Next/Previous function call, +// returning only the value of the object. To call GetDataValueBytes, you must first +// have called one of the Next/Previous functions. func (j *Journal) GetDataValueBytes(field string) ([]byte, error) { val, err := j.GetDataBytes(field) if err != nil { @@ -641,9 +697,10 @@ func (j *Journal) GetDataValueBytes(field string) ([]byte, error) { return bytes.SplitN(val, []byte("="), 2)[1], nil } -// GetEntry returns a full representation of a journal entry with -// all key-value pairs of data as well as address fields (cursor, realtime -// timestamp and monotonic timestamp) +// GetEntry returns a full representation of the journal entry referenced by the +// last completed Next/Previous function call, with all key-value pairs of data +// as well as address fields (cursor, realtime timestamp and monotonic timestamp). +// To call GetEntry, you must first have called one of the Next/Previous functions. func (j *Journal) GetEntry() (*JournalEntry, error) { sd_journal_get_realtime_usec, err := getFunction("sd_journal_get_realtime_usec") if err != nil { @@ -731,7 +788,7 @@ func (j *Journal) GetEntry() (*JournalEntry, error) { return entry, nil } -// SetDataThresold sets the data field size threshold for data returned by +// SetDataThreshold sets the data field size threshold for data returned by // GetData. To retrieve the complete data fields this threshold should be // turned off by setting it to 0, so that the library always returns the // complete data objects. @@ -752,8 +809,10 @@ func (j *Journal) SetDataThreshold(threshold uint64) error { return nil } -// GetRealtimeUsec gets the realtime (wallclock) timestamp of the current -// journal entry. +// GetRealtimeUsec gets the realtime (wallclock) timestamp of the journal +// entry referenced by the last completed Next/Previous function call. To +// call GetRealtimeUsec, you must first have called one of the Next/Previous +// functions. func (j *Journal) GetRealtimeUsec() (uint64, error) { var usec C.uint64_t @@ -773,7 +832,10 @@ func (j *Journal) GetRealtimeUsec() (uint64, error) { return uint64(usec), nil } -// GetMonotonicUsec gets the monotonic timestamp of the current journal entry. +// GetMonotonicUsec gets the monotonic timestamp of the journal entry +// referenced by the last completed Next/Previous function call. To call +// GetMonotonicUsec, you must first have called one of the Next/Previous +// functions. func (j *Journal) GetMonotonicUsec() (uint64, error) { var usec C.uint64_t var boot_id C.sd_id128_t @@ -794,7 +856,9 @@ func (j *Journal) GetMonotonicUsec() (uint64, error) { return uint64(usec), nil } -// GetCursor gets the cursor of the current journal entry. +// GetCursor gets the cursor of the last journal entry reeferenced by the +// last completed Next/Previous function call. To call GetCursor, you must +// first have called one of the Next/Previous functions. func (j *Journal) GetCursor() (string, error) { sd_journal_get_cursor, err := getFunction("sd_journal_get_cursor") if err != nil { @@ -836,13 +900,16 @@ func (j *Journal) TestCursor(cursor string) error { if r < 0 { return fmt.Errorf("failed to test to cursor %q: %d", cursor, syscall.Errno(-r)) + } else if r == 0 { + return ErrNoTestCursor } return nil } // SeekHead seeks to the beginning of the journal, i.e. the oldest available -// entry. +// entry. This call must be followed by a call to Next before any call to +// Get* will return data about the first element. func (j *Journal) SeekHead() error { sd_journal_seek_head, err := getFunction("sd_journal_seek_head") if err != nil { @@ -861,7 +928,8 @@ func (j *Journal) SeekHead() error { } // SeekTail may be used to seek to the end of the journal, i.e. the most recent -// available entry. +// available entry. This call must be followed by a call to Next before any +// call to Get* will return data about the last element. func (j *Journal) SeekTail() error { sd_journal_seek_tail, err := getFunction("sd_journal_seek_tail") if err != nil { @@ -880,7 +948,8 @@ func (j *Journal) SeekTail() error { } // SeekRealtimeUsec seeks to the entry with the specified realtime (wallclock) -// timestamp, i.e. CLOCK_REALTIME. +// timestamp, i.e. CLOCK_REALTIME. This call must be followed by a call to +// Next/Previous before any call to Get* will return data about the sought entry. func (j *Journal) SeekRealtimeUsec(usec uint64) error { sd_journal_seek_realtime_usec, err := getFunction("sd_journal_seek_realtime_usec") if err != nil { @@ -898,7 +967,9 @@ func (j *Journal) SeekRealtimeUsec(usec uint64) error { return nil } -// SeekCursor seeks to a concrete journal cursor. +// SeekCursor seeks to a concrete journal cursor. This call must be +// followed by a call to Next/Previous before any call to Get* will return +// data about the sought entry. func (j *Journal) SeekCursor(cursor string) error { sd_journal_seek_cursor, err := getFunction("sd_journal_seek_cursor") if err != nil { @@ -937,7 +1008,7 @@ func (j *Journal) Wait(timeout time.Duration) int { // equivalent hex value. to = 0xffffffffffffffff } else { - to = uint64(time.Now().Add(timeout).Unix() / 1000) + to = uint64(timeout / time.Microsecond) } j.mu.Lock() r := C.my_sd_journal_wait(sd_journal_wait, j.cjournal, C.uint64_t(to)) @@ -1022,3 +1093,28 @@ func (j *Journal) GetUniqueValues(field string) ([]string, error) { return result, nil } + +// GetCatalog retrieves a message catalog entry for the journal entry referenced +// by the last completed Next/Previous function call. To call GetCatalog, you +// must first have called one of these functions. +func (j *Journal) GetCatalog() (string, error) { + sd_journal_get_catalog, err := getFunction("sd_journal_get_catalog") + if err != nil { + return "", err + } + + var c *C.char + + j.mu.Lock() + r := C.my_sd_journal_get_catalog(sd_journal_get_catalog, j.cjournal, &c) + j.mu.Unlock() + defer C.free(unsafe.Pointer(c)) + + if r < 0 { + return "", fmt.Errorf("failed to retrieve catalog entry for current journal entry: %d", syscall.Errno(-r)) + } + + catalog := C.GoString(c) + + return catalog, nil +} diff --git a/vendor/github.com/coreos/go-systemd/sdjournal/read.go b/vendor/github.com/coreos/go-systemd/sdjournal/read.go index b581f03b4..51a060fb5 100644 --- a/vendor/github.com/coreos/go-systemd/sdjournal/read.go +++ b/vendor/github.com/coreos/go-systemd/sdjournal/read.go @@ -21,10 +21,13 @@ import ( "io" "log" "strings" + "sync" "time" ) var ( + // ErrExpired gets returned when the Follow function runs into the + // specified timeout. ErrExpired = errors.New("Timeout expired") ) @@ -44,6 +47,11 @@ type JournalReaderConfig struct { // If not empty, the journal instance will point to a journal residing // in this directory. The supplied path may be relative or absolute. Path string + + // If not nil, Formatter will be used to translate the resulting entries + // into strings. If not set, the default format (timestamp and message field) + // will be used. If Formatter returns an error, Read will stop and return the error. + Formatter func(entry *JournalEntry) (string, error) } // JournalReader is an io.ReadCloser which provides a simple interface for iterating through the @@ -51,12 +59,20 @@ type JournalReaderConfig struct { type JournalReader struct { journal *Journal msgReader *strings.Reader + formatter func(entry *JournalEntry) (string, error) } // NewJournalReader creates a new JournalReader with configuration options that are similar to the // systemd journalctl tool's iteration and filtering features. func NewJournalReader(config JournalReaderConfig) (*JournalReader, error) { - r := &JournalReader{} + // use simpleMessageFormatter as default formatter. + if config.Formatter == nil { + config.Formatter = simpleMessageFormatter + } + + r := &JournalReader{ + formatter: config.Formatter, + } // Open the journal var err error @@ -71,7 +87,9 @@ func NewJournalReader(config JournalReaderConfig) (*JournalReader, error) { // Add any supplied matches for _, m := range config.Matches { - r.journal.AddMatch(m.String()) + if err = r.journal.AddMatch(m.String()); err != nil { + return nil, err + } } // Set the start position based on options @@ -118,14 +136,10 @@ func NewJournalReader(config JournalReaderConfig) (*JournalReader, error) { // don't fit in the read buffer. Callers should keep calling until 0 and/or an // error is returned. func (r *JournalReader) Read(b []byte) (int, error) { - var err error - if r.msgReader == nil { - var c uint64 - // Advance the journal cursor. It has to be called at least one time // before reading - c, err = r.journal.Next() + c, err := r.journal.Next() // An unexpected error if err != nil { @@ -137,10 +151,13 @@ func (r *JournalReader) Read(b []byte) (int, error) { return 0, io.EOF } - // Build a message - var msg string - msg, err = r.buildMessage() + entry, err := r.journal.GetEntry() + if err != nil { + return 0, err + } + // Build a message + msg, err := r.formatter(entry) if err != nil { return 0, err } @@ -148,8 +165,7 @@ func (r *JournalReader) Read(b []byte) (int, error) { } // Copy and return the message - var sz int - sz, err = r.msgReader.Read(b) + sz, err := r.msgReader.Read(b) if err == io.EOF { // The current entry has been fully read. Don't propagate this // EOF, so the next entry can be read at the next Read() @@ -180,80 +196,76 @@ func (r *JournalReader) Rewind() error { // Follow synchronously follows the JournalReader, writing each new journal entry to writer. The // follow will continue until a single time.Time is received on the until channel. -func (r *JournalReader) Follow(until <-chan time.Time, writer io.Writer) (err error) { +func (r *JournalReader) Follow(until <-chan time.Time, writer io.Writer) error { // Process journal entries and events. Entries are flushed until the tail or // timeout is reached, and then we wait for new events or the timeout. var msg = make([]byte, 64*1<<(10)) + var waitCh = make(chan int, 1) + var waitGroup sync.WaitGroup + defer waitGroup.Wait() + process: for { c, err := r.Read(msg) if err != nil && err != io.EOF { - break process + return err } select { case <-until: return ErrExpired default: - if c > 0 { - if _, err = writer.Write(msg[:c]); err != nil { - break process - } - continue process + } + if c > 0 { + if _, err = writer.Write(msg[:c]); err != nil { + return err } + continue process } // We're at the tail, so wait for new events or time out. // Holds journal events to process. Tightly bounded for now unless there's a // reason to unblock the journal watch routine more quickly. - events := make(chan int, 1) - pollDone := make(chan bool, 1) - go func() { - for { - select { - case <-pollDone: - return + for { + waitGroup.Add(1) + go func() { + status := r.journal.Wait(100 * time.Millisecond) + waitCh <- status + waitGroup.Done() + }() + + select { + case <-until: + return ErrExpired + case e := <-waitCh: + switch e { + case SD_JOURNAL_NOP: + // the journal did not change since the last invocation + case SD_JOURNAL_APPEND, SD_JOURNAL_INVALIDATE: + continue process default: - events <- r.journal.Wait(time.Duration(1) * time.Second) - } - } - }() + if e < 0 { + return fmt.Errorf("received error event: %d", e) + } - select { - case <-until: - pollDone <- true - return ErrExpired - case e := <-events: - pollDone <- true - switch e { - case SD_JOURNAL_NOP, SD_JOURNAL_APPEND, SD_JOURNAL_INVALIDATE: - // TODO: need to account for any of these? - default: - log.Printf("Received unknown event: %d\n", e) + log.Printf("received unknown event: %d\n", e) + } } - continue process } } - - return } -// buildMessage returns a string representing the current journal entry in a simple format which +// simpleMessageFormatter is the default formatter. +// It returns a string representing the current journal entry in a simple format which // includes the entry timestamp and MESSAGE field. -func (r *JournalReader) buildMessage() (string, error) { - var msg string - var usec uint64 - var err error - - if msg, err = r.journal.GetData("MESSAGE"); err != nil { - return "", err - } - - if usec, err = r.journal.GetRealtimeUsec(); err != nil { - return "", err +func simpleMessageFormatter(entry *JournalEntry) (string, error) { + msg, ok := entry.Fields["MESSAGE"] + if !ok { + return "", fmt.Errorf("no MESSAGE field present in journal entry") } + usec := entry.RealtimeTimestamp timestamp := time.Unix(0, int64(usec)*int64(time.Microsecond)) return fmt.Sprintf("%s %s\n", timestamp, msg), nil |