summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cirrus.yml1
-rw-r--r--Makefile10
-rw-r--r--cmd/podman/auto-update.go46
-rw-r--r--cmd/podman/containers/runlabel.go80
-rw-r--r--cmd/podman/containers/stats.go1
-rw-r--r--cmd/podman/login.go1
-rw-r--r--cmd/podman/logout.go1
-rw-r--r--cmd/podman/manifest/annotate.go2
-rw-r--r--cmd/podman/pods/create.go47
-rw-r--r--cmd/podman/registry/config.go29
-rw-r--r--cmd/podman/registry/config_abi.go7
-rw-r--r--cmd/podman/registry/config_tunnel.go7
-rw-r--r--cmd/podman/registry/registry.go20
-rw-r--r--cmd/podman/root.go2
-rw-r--r--cmd/podman/system/service.go2
-rwxr-xr-xcontrib/cirrus/setup_environment.sh2
-rw-r--r--docs/source/markdown/podman-network-create.1.md2
-rw-r--r--go.mod4
-rw-r--r--go.sum6
-rw-r--r--libpod/runtime.go2
-rw-r--r--pkg/bindings/manifests/manifests.go39
-rw-r--r--pkg/bindings/test/containers_test.go4
-rw-r--r--pkg/bindings/test/manifests_test.go40
-rw-r--r--pkg/bindings/test/pods_test.go10
-rw-r--r--pkg/bindings/test/system_test.go5
-rw-r--r--pkg/domain/entities/auto-update.go7
-rw-r--r--pkg/domain/entities/containers.go38
-rw-r--r--pkg/domain/entities/engine_container.go2
-rw-r--r--pkg/domain/infra/abi/auto-update.go13
-rw-r--r--pkg/domain/infra/abi/containers_runlabel.go280
-rw-r--r--pkg/domain/infra/abi/system.go1
-rw-r--r--pkg/domain/infra/tunnel/auto-update.go12
-rw-r--r--pkg/domain/infra/tunnel/containers.go4
-rw-r--r--pkg/domain/infra/tunnel/manifest.go50
-rw-r--r--pkg/specgen/generate/container.go13
-rw-r--r--pkg/specgen/pod_validate.go6
-rw-r--r--pkg/specgen/podspecgen.go2
-rw-r--r--test/e2e/runlabel_test.go1
-rw-r--r--test/e2e/stats_test.go20
-rw-r--r--test/system/250-generate-systemd.bats48
-rw-r--r--test/system/250-systemd.bats49
-rw-r--r--test/system/helpers.bash11
-rw-r--r--vendor/github.com/containers/common/pkg/auth/auth.go31
-rw-r--r--vendor/github.com/containers/common/pkg/auth/cli.go11
-rw-r--r--vendor/github.com/containers/common/pkg/config/config.go10
-rw-r--r--vendor/github.com/containers/common/pkg/config/default.go2
-rw-r--r--vendor/github.com/onsi/gomega/.travis.yml2
-rw-r--r--vendor/github.com/onsi/gomega/CHANGELOG.md8
-rw-r--r--vendor/github.com/onsi/gomega/gomega_dsl.go33
-rw-r--r--vendor/github.com/onsi/gomega/matchers.go19
-rw-r--r--vendor/github.com/onsi/gomega/matchers/have_http_status_matcher.go42
-rw-r--r--vendor/github.com/onsi/gomega/matchers/panic_matcher.go76
-rw-r--r--vendor/modules.txt4
53 files changed, 947 insertions, 218 deletions
diff --git a/.cirrus.yml b/.cirrus.yml
index 2aae343e8..7400ae0a8 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -644,7 +644,6 @@ special_testing_cross_task:
special_testing_bindings_task:
- skip: $CI == 'true'
depends_on:
- "gating"
- "varlink_api"
diff --git a/Makefile b/Makefile
index bce0f33a1..d1eb56aa8 100644
--- a/Makefile
+++ b/Makefile
@@ -189,7 +189,11 @@ podman: bin/podman
.PHONY: bin/podman-remote
bin/podman-remote: .gopathok $(SOURCES) go.mod go.sum $(PODMAN_VARLINK_DEPENDENCIES) ## Build with podman on remote environment
- $(GO_BUILD) $(BUILDFLAGS) -gcflags '$(GCFLAGS)' -asmflags '$(ASMFLAGS)' -ldflags '$(LDFLAGS_PODMAN)' -tags "!ABISupport $(BUILDTAGS) remoteclient" -o $@ $(PROJECT)/cmd/podman
+ $(GO_BUILD) $(BUILDFLAGS) -gcflags '$(GCFLAGS)' -asmflags '$(ASMFLAGS)' -ldflags '$(LDFLAGS_PODMAN)' -tags "!ABISupport remoteclient" -o $@ $(PROJECT)/cmd/podman
+
+.PHONY: bin/podman-remote-static
+podman-remote-static: bin/podman-remote-static
+ CGO_ENABLED=0 $(GO_BUILD) $(BUILDFLAGS) -gcflags '$(GCFLAGS)' -asmflags '$(ASMFLAGS)' -ldflags '$(LDFLAGS_PODMAN_STATIC)' -tags "!ABISupport containers_image_openpgp remoteclient" -o bin/podman-remote-static $(PROJECT)/cmd/podman
.PHONY: podman-remote
podman-remote: bin/podman-remote
@@ -373,7 +377,7 @@ MANPAGES_MD ?= $(wildcard docs/source/markdown/*.md pkg/*/docs/*.md)
MANPAGES ?= $(MANPAGES_MD:%.md=%)
MANPAGES_DEST ?= $(subst markdown,man, $(subst source,build,$(MANPAGES)))
-$(MANPAGES): %: %.md .gopathok
+$(MANPAGES): %: %.md .install.md2man docdir
@sed -e 's/\((podman.*\.md)\)//' -e 's/\[\(podman.*\)\]/\1/' $< | $(GOMD2MAN) -in /dev/stdin -out $(subst source/markdown,build/man,$@)
.PHONY: docs
@@ -381,7 +385,7 @@ docdir:
mkdir -p docs/build/man
.PHONY: docs
-docs: .install.md2man docdir $(MANPAGES) ## Generate documentation
+docs: $(MANPAGES) ## Generate documentation
.PHONE: xref_helpmsgs_manpages
xref_helpmsgs_manpages:
diff --git a/cmd/podman/auto-update.go b/cmd/podman/auto-update.go
new file mode 100644
index 000000000..758cbbc6f
--- /dev/null
+++ b/cmd/podman/auto-update.go
@@ -0,0 +1,46 @@
+package main
+
+import (
+ "fmt"
+
+ "github.com/containers/libpod/cmd/podman/registry"
+ "github.com/containers/libpod/pkg/domain/entities"
+ "github.com/containers/libpod/pkg/errorhandling"
+ "github.com/pkg/errors"
+ "github.com/spf13/cobra"
+)
+
+var (
+ autoUpdateDescription = `Auto update containers according to their auto-update policy.
+
+ Auto-update policies are specified with the "io.containers.autoupdate" label.
+ Note that this command is experimental.`
+ autoUpdateCommand = &cobra.Command{
+ Use: "auto-update [flags]",
+ Short: "Auto update containers according to their auto-update policy",
+ Long: autoUpdateDescription,
+ RunE: autoUpdate,
+ Example: `podman auto-update`,
+ }
+)
+
+func init() {
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Mode: []entities.EngineMode{entities.ABIMode},
+ Command: autoUpdateCommand,
+ })
+}
+
+func autoUpdate(cmd *cobra.Command, args []string) error {
+ if len(args) > 0 {
+ // Backwards compat. System tests expext this error string.
+ return errors.Errorf("`%s` takes no arguments", cmd.CommandPath())
+ }
+ report, failures := registry.ContainerEngine().AutoUpdate(registry.GetContext())
+ if report != nil {
+ for _, unit := range report.Units {
+ fmt.Println(unit)
+ }
+ }
+ return errorhandling.JoinErrors(failures)
+}
diff --git a/cmd/podman/containers/runlabel.go b/cmd/podman/containers/runlabel.go
new file mode 100644
index 000000000..11fa362b8
--- /dev/null
+++ b/cmd/podman/containers/runlabel.go
@@ -0,0 +1,80 @@
+package containers
+
+import (
+ "context"
+ "os"
+
+ "github.com/containers/common/pkg/auth"
+ "github.com/containers/image/v5/types"
+ "github.com/containers/libpod/cmd/podman/registry"
+ "github.com/containers/libpod/pkg/domain/entities"
+ "github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
+ "github.com/spf13/cobra"
+)
+
+// runlabelOptionsWrapper allows for combining API-only with CLI-only options
+// and to convert between them.
+type runlabelOptionsWrapper struct {
+ entities.ContainerRunlabelOptions
+ TLSVerifyCLI bool
+}
+
+var (
+ runlabelOptions = runlabelOptionsWrapper{}
+ runlabelDescription = "Executes a command as described by a container image label."
+ runlabelCommand = &cobra.Command{
+ Use: "runlabel [flags] LABEL IMAGE [ARG...]",
+ Short: "Execute the command described by an image label",
+ Long: runlabelDescription,
+ RunE: runlabel,
+ Args: cobra.MinimumNArgs(2),
+ Example: `podman container runlabel run imageID
+ podman container runlabel --pull install imageID arg1 arg2
+ podman container runlabel --display run myImage`,
+ }
+)
+
+func init() {
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Mode: []entities.EngineMode{entities.ABIMode},
+ Command: runlabelCommand,
+ Parent: containerCmd,
+ })
+
+ flags := rmCommand.Flags()
+ flags.StringVar(&runlabelOptions.Authfile, "authfile", auth.GetDefaultAuthFile(), "Path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override")
+ flags.StringVar(&runlabelOptions.CertDir, "cert-dir", "", "`Pathname` of a directory containing TLS certificates and keys")
+ flags.StringVar(&runlabelOptions.Credentials, "creds", "", "`Credentials` (USERNAME:PASSWORD) to use for authenticating to a registry")
+ flags.BoolVar(&runlabelOptions.Display, "display", false, "Preview the command that the label would run")
+ flags.StringVarP(&runlabelOptions.Name, "name", "n", "", "Assign a name to the container")
+ flags.StringVar(&runlabelOptions.Optional1, "opt1", "", "Optional parameter to pass for install")
+ flags.StringVar(&runlabelOptions.Optional2, "opt2", "", "Optional parameter to pass for install")
+ flags.StringVar(&runlabelOptions.Optional3, "opt3", "", "Optional parameter to pass for install")
+ flags.BoolP("pull", "p", false, "Pull the image if it does not exist locally prior to executing the label contents")
+ flags.BoolVarP(&runlabelOptions.Quiet, "quiet", "q", false, "Suppress output information when installing images")
+ flags.BoolVar(&runlabelOptions.Replace, "replace", false, "Replace existing container with a new one from the image")
+ flags.StringVar(&runlabelOptions.SignaturePolicy, "signature-policy", "", "`Pathname` of signature policy file (not usually used)")
+ flags.BoolVar(&runlabelOptions.TLSVerifyCLI, "tls-verify", true, "Require HTTPS and verify certificates when contacting registries")
+
+ // Hide the optional flags.
+ _ = flags.MarkHidden("opt1")
+ _ = flags.MarkHidden("opt2")
+ _ = flags.MarkHidden("opt3")
+
+ if err := flags.MarkDeprecated("pull", "podman will pull if not found in local storage"); err != nil {
+ logrus.Error("unable to mark pull flag deprecated")
+ }
+}
+
+func runlabel(cmd *cobra.Command, args []string) error {
+ if cmd.Flags().Changed("tls-verify") {
+ runlabelOptions.SkipTLSVerify = types.NewOptionalBool(!runlabelOptions.TLSVerifyCLI)
+ }
+ if runlabelOptions.Authfile != "" {
+ if _, err := os.Stat(runlabelOptions.Authfile); err != nil {
+ return errors.Wrapf(err, "error getting authfile %s", runlabelOptions.Authfile)
+ }
+ }
+ return registry.ContainerEngine().ContainerRunlabel(context.Background(), args[0], args[1], args[2:], runlabelOptions.ContainerRunlabelOptions)
+}
diff --git a/cmd/podman/containers/stats.go b/cmd/podman/containers/stats.go
index 3f9db671f..5b7f52cc7 100644
--- a/cmd/podman/containers/stats.go
+++ b/cmd/podman/containers/stats.go
@@ -234,7 +234,6 @@ func outputJSON(stats []*containerStats) error {
Pids: j.PIDS(),
})
}
-
b, err := json.MarshalIndent(jstats, "", " ")
if err != nil {
return err
diff --git a/cmd/podman/login.go b/cmd/podman/login.go
index 8413861f5..92f13d0e7 100644
--- a/cmd/podman/login.go
+++ b/cmd/podman/login.go
@@ -46,7 +46,6 @@ func init() {
// Podman flags.
flags.BoolVarP(&loginOptions.tlsVerify, "tls-verify", "", false, "Require HTTPS and verify certificates when contacting registries")
- flags.BoolVarP(&loginOptions.GetLoginSet, "get-login", "", false, "Return the current login user for the registry")
loginOptions.Stdin = os.Stdin
loginOptions.Stdout = os.Stdout
loginOptions.AcceptUnspecifiedRegistry = true
diff --git a/cmd/podman/logout.go b/cmd/podman/logout.go
index d0afc21b4..c016de8ae 100644
--- a/cmd/podman/logout.go
+++ b/cmd/podman/logout.go
@@ -37,7 +37,6 @@ func init() {
// Flags from the auth package.
flags.AddFlagSet(auth.GetLogoutFlags(&logoutOptions))
- logoutOptions.Stdin = os.Stdin
logoutOptions.Stdout = os.Stdout
logoutOptions.AcceptUnspecifiedRegistry = true
}
diff --git a/cmd/podman/manifest/annotate.go b/cmd/podman/manifest/annotate.go
index 21d4fb747..82ee1ffda 100644
--- a/cmd/podman/manifest/annotate.go
+++ b/cmd/podman/manifest/annotate.go
@@ -24,7 +24,7 @@ var (
func init() {
registry.Commands = append(registry.Commands, registry.CliCommand{
- Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
+ Mode: []entities.EngineMode{entities.ABIMode},
Command: annotateCmd,
Parent: manifestCmd,
})
diff --git a/cmd/podman/pods/create.go b/cmd/podman/pods/create.go
index 0a2016496..f97fa836a 100644
--- a/cmd/podman/pods/create.go
+++ b/cmd/podman/pods/create.go
@@ -17,6 +17,7 @@ import (
"github.com/containers/libpod/pkg/util"
"github.com/pkg/errors"
"github.com/spf13/cobra"
+ "github.com/spf13/pflag"
)
var (
@@ -59,6 +60,14 @@ func init() {
flags.StringVarP(&createOptions.Hostname, "hostname", "", "", "Set a hostname to the pod")
flags.StringVar(&podIDFile, "pod-id-file", "", "Write the pod ID to the file")
flags.StringVar(&share, "share", createconfig.DefaultKernelNamespaces, "A comma delimited list of kernel namespaces the pod will share")
+ flags.SetNormalizeFunc(aliasNetworkFlag)
+}
+
+func aliasNetworkFlag(_ *pflag.FlagSet, name string) pflag.NormalizedName {
+ if name == "net" {
+ name = "network"
+ }
+ return pflag.NormalizedName(name)
}
func create(cmd *cobra.Command, args []string) error {
@@ -105,29 +114,21 @@ func create(cmd *cobra.Command, args []string) error {
if err != nil {
return err
}
- netInput, err := cmd.Flags().GetString("network")
- if err != nil {
- return err
- }
- n := specgen.Namespace{}
- switch netInput {
- case "bridge":
- n.NSMode = specgen.Bridge
- case "host":
- n.NSMode = specgen.Host
- case "slip4netns":
- n.NSMode = specgen.Slirp
- default:
- if strings.HasPrefix(netInput, "container:") { // nolint
- split := strings.Split(netInput, ":")
- if len(split) != 2 {
- return errors.Errorf("invalid network paramater: %q", netInput)
- }
- n.NSMode = specgen.FromContainer
- n.Value = split[1]
- } else if strings.HasPrefix(netInput, "ns:") {
- return errors.New("the ns: network option is not supported for pods")
- } else {
+ if cmd.Flag("network").Changed {
+ netInput, err := cmd.Flags().GetString("network")
+ if err != nil {
+ return err
+ }
+ n := specgen.Namespace{}
+ switch netInput {
+ case "bridge":
+ n.NSMode = specgen.Bridge
+ case "host":
+ n.NSMode = specgen.Host
+ case "slirp4netns":
+ n.NSMode = specgen.Slirp
+ default:
+ // Container and NS mode are presently unsupported
n.NSMode = specgen.Bridge
createOptions.Net.CNINetworks = strings.Split(netInput, ",")
}
diff --git a/cmd/podman/registry/config.go b/cmd/podman/registry/config.go
index fc6eb538e..49d5bca74 100644
--- a/cmd/podman/registry/config.go
+++ b/cmd/podman/registry/config.go
@@ -22,6 +22,7 @@ const (
var (
podmanOptions entities.PodmanConfig
podmanSync sync.Once
+ abiSupport = false
)
// PodmanConfig returns an entities.PodmanConfig built up from
@@ -39,23 +40,31 @@ func newPodmanConfig() {
var mode entities.EngineMode
switch runtime.GOOS {
- case "darwin":
- fallthrough
- case "windows":
+ case "darwin", "windows":
mode = entities.TunnelMode
case "linux":
- mode = entities.ABIMode
+ // Some linux clients might only be compiled without ABI
+ // support (e.g., podman-remote).
+ if abiSupport {
+ mode = entities.ABIMode
+ } else {
+ mode = entities.TunnelMode
+ }
default:
fmt.Fprintf(os.Stderr, "%s is not a supported OS", runtime.GOOS)
os.Exit(1)
}
- // cobra.Execute() may not be called yet, so we peek at os.Args.
- for _, v := range os.Args {
- // Prefix checking works because of how default EngineMode's
- // have been defined.
- if strings.HasPrefix(v, "--remote") {
- mode = entities.TunnelMode
+ // Check if need to fallback to the tunnel mode if --remote is used.
+ if abiSupport && mode == entities.ABIMode {
+ // cobra.Execute() may not be called yet, so we peek at os.Args.
+ for _, v := range os.Args {
+ // Prefix checking works because of how default EngineMode's
+ // have been defined.
+ if strings.HasPrefix(v, "--remote") {
+ mode = entities.TunnelMode
+ break
+ }
}
}
diff --git a/cmd/podman/registry/config_abi.go b/cmd/podman/registry/config_abi.go
new file mode 100644
index 000000000..55430e1bf
--- /dev/null
+++ b/cmd/podman/registry/config_abi.go
@@ -0,0 +1,7 @@
+// +build ABISupport
+
+package registry
+
+func init() {
+ abiSupport = true
+}
diff --git a/cmd/podman/registry/config_tunnel.go b/cmd/podman/registry/config_tunnel.go
new file mode 100644
index 000000000..29e744dac
--- /dev/null
+++ b/cmd/podman/registry/config_tunnel.go
@@ -0,0 +1,7 @@
+// +build !ABISupport
+
+package registry
+
+func init() {
+ abiSupport = false
+}
diff --git a/cmd/podman/registry/registry.go b/cmd/podman/registry/registry.go
index 69e2babfc..71ee2bed0 100644
--- a/cmd/podman/registry/registry.go
+++ b/cmd/podman/registry/registry.go
@@ -2,14 +2,18 @@ package registry
import (
"context"
+ "path/filepath"
"github.com/containers/libpod/pkg/domain/entities"
"github.com/containers/libpod/pkg/domain/infra"
+ "github.com/containers/libpod/pkg/rootless"
+ "github.com/containers/libpod/pkg/util"
+ "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)
-// DefaultAPIAddress is the default address of the REST socket
-const DefaultAPIAddress = "unix:/run/podman/podman.sock"
+// DefaultRootAPIAddress is the default address of the REST socket
+const DefaultRootAPIAddress = "unix:/run/podman/podman.sock"
// DefaultVarlinkAddress is the default address of the varlink socket
const DefaultVarlinkAddress = "unix:/run/podman/io.podman"
@@ -98,3 +102,15 @@ func GetContextWithOptions() context.Context {
func GetContext() context.Context {
return Context()
}
+
+func DefaultAPIAddress() string {
+ if rootless.IsRootless() {
+ xdg, err := util.GetRuntimeDir()
+ if err != nil {
+ logrus.Warnf("Failed to get rootless runtime dir for DefaultAPIAddress: %s", err)
+ return DefaultRootAPIAddress
+ }
+ return "unix:" + filepath.Join(xdg, "podman", "podman.sock")
+ }
+ return DefaultRootAPIAddress
+}
diff --git a/cmd/podman/root.go b/cmd/podman/root.go
index 502b6c03c..7d6f6f823 100644
--- a/cmd/podman/root.go
+++ b/cmd/podman/root.go
@@ -208,7 +208,7 @@ func syslogHook() {
func rootFlags(opts *entities.PodmanConfig, flags *pflag.FlagSet) {
// V2 flags
- flags.StringVarP(&opts.Uri, "remote", "r", "", "URL to access Podman service")
+ flags.StringVarP(&opts.Uri, "remote", "r", registry.DefaultAPIAddress(), "URL to access Podman service")
flags.StringSliceVar(&opts.Identities, "identity", []string{}, "path to SSH identity file")
cfg := opts.Config
diff --git a/cmd/podman/system/service.go b/cmd/podman/system/service.go
index f4b91dd78..552c72f79 100644
--- a/cmd/podman/system/service.go
+++ b/cmd/podman/system/service.go
@@ -139,6 +139,6 @@ func resolveApiURI(_url []string) (string, error) {
case srvArgs.Varlink:
return registry.DefaultVarlinkAddress, nil
default:
- return registry.DefaultAPIAddress, nil
+ return registry.DefaultRootAPIAddress, nil
}
}
diff --git a/contrib/cirrus/setup_environment.sh b/contrib/cirrus/setup_environment.sh
index 6bec9625e..756240444 100755
--- a/contrib/cirrus/setup_environment.sh
+++ b/contrib/cirrus/setup_environment.sh
@@ -87,7 +87,7 @@ case "$CG_FS_TYPE" in
# Normally not something to do for stable testing
# but crun is new, and late-breaking fixes may be required
# on short notice
- dnf update -y crun
+ dnf update -y crun containers-common
fi
;;
*)
diff --git a/docs/source/markdown/podman-network-create.1.md b/docs/source/markdown/podman-network-create.1.md
index cbdfee4d0..45d9d9b0b 100644
--- a/docs/source/markdown/podman-network-create.1.md
+++ b/docs/source/markdown/podman-network-create.1.md
@@ -24,7 +24,7 @@ resolution.
**-d**, **--driver**
-Driver to manage the network (default "bridge"). Currently on `bridge` is supported.
+Driver to manage the network (default "bridge"). Currently only `bridge` is supported.
**--gateway**
diff --git a/go.mod b/go.mod
index 562622567..83fd19706 100644
--- a/go.mod
+++ b/go.mod
@@ -10,7 +10,7 @@ require (
github.com/containernetworking/cni v0.7.2-0.20200304161608-4fae32b84921
github.com/containernetworking/plugins v0.8.5
github.com/containers/buildah v1.14.9-0.20200501175434-42a48f9373d9
- github.com/containers/common v0.11.0
+ github.com/containers/common v0.11.1
github.com/containers/conmon v2.0.14+incompatible
github.com/containers/image/v5 v5.4.3
github.com/containers/psgo v1.5.0
@@ -35,7 +35,7 @@ require (
github.com/json-iterator/go v1.1.9
github.com/mrunalp/fileutils v0.0.0-20171103030105-7d4729fb3618
github.com/onsi/ginkgo v1.12.0
- github.com/onsi/gomega v1.9.0
+ github.com/onsi/gomega v1.10.0
github.com/opencontainers/go-digest v1.0.0-rc1
github.com/opencontainers/image-spec v1.0.2-0.20190823105129-775207bd45b6
github.com/opencontainers/runc v1.0.0-rc9
diff --git a/go.sum b/go.sum
index 136db27ee..489f17bf6 100644
--- a/go.sum
+++ b/go.sum
@@ -72,8 +72,8 @@ github.com/containers/buildah v1.14.9-0.20200501175434-42a48f9373d9 h1:EGegltin1
github.com/containers/buildah v1.14.9-0.20200501175434-42a48f9373d9/go.mod h1:+2aNsVcd4pVzmVAbOfWN5X+0Lpz2rtICSGXbTSCzdBU=
github.com/containers/common v0.10.0 h1:Km1foMJJBIxceA1/UCZcIuwf8sCF71sP5DwE6Oh1BEA=
github.com/containers/common v0.10.0/go.mod h1:6A/moCuQITXLqBe5A0WKKTcCfCmEQRbknI05HcPzOL0=
-github.com/containers/common v0.11.0 h1:uFSBIl9iqoTIv8icBe9lPrYKkmSiGrAWr0a2PyJLrO4=
-github.com/containers/common v0.11.0/go.mod h1:ag8p8Xp2o1wPAPz/+bA7LVQlDavtg3M15RZLBWt/2KE=
+github.com/containers/common v0.11.1 h1:i++kltFD92bKfDeE3B+Bpe5jYVTnAibmIUUUnXYKoPo=
+github.com/containers/common v0.11.1/go.mod h1:2w3QE6VUmhltGYW4wV00h4okq1Crs7hNI1ZD2I0QRUY=
github.com/containers/conmon v2.0.14+incompatible h1:knU1O1QxXy5YxtjMQVKEyCajROaehizK9FHaICl+P5Y=
github.com/containers/conmon v2.0.14+incompatible/go.mod h1:hgwZ2mtuDrppv78a/cOBNiCm6O0UMWGx1mu7P00nu5I=
github.com/containers/image/v5 v5.4.3 h1:zn2HR7uu4hpvT5QQHgjqonOzKDuM1I1UHUEmzZT5sbs=
@@ -334,6 +334,8 @@ github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1Cpa
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.9.0 h1:R1uwffexN6Pr340GtYRIdZmAiN4J+iw6WG4wog1DUXg=
github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
+github.com/onsi/gomega v1.10.0 h1:Gwkk+PTu/nfOwNMtUB/mRUv0X7ewW5dO4AERT1ThVKo=
+github.com/onsi/gomega v1.10.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ=
github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
diff --git a/libpod/runtime.go b/libpod/runtime.go
index e71483ef9..c1864683f 100644
--- a/libpod/runtime.go
+++ b/libpod/runtime.go
@@ -752,7 +752,7 @@ type DBConfig struct {
// mergeDBConfig merges the configuration from the database.
func (r *Runtime) mergeDBConfig(dbConfig *DBConfig) error {
- c := r.config.Engine
+ c := &r.config.Engine
if !r.storageSet.RunRootSet && dbConfig.StorageTmp != "" {
if r.storageConfig.RunRoot != dbConfig.StorageTmp &&
r.storageConfig.RunRoot != "" {
diff --git a/pkg/bindings/manifests/manifests.go b/pkg/bindings/manifests/manifests.go
index b85169410..3e0ef0325 100644
--- a/pkg/bindings/manifests/manifests.go
+++ b/pkg/bindings/manifests/manifests.go
@@ -125,23 +125,24 @@ func Push(ctx context.Context, name string, destination *string, all *bool) (str
return idr.ID, response.Process(&idr)
}
+// There is NO annotate endpoint. this binding could never work
// Annotate updates the image configuration of a given manifest list
-func Annotate(ctx context.Context, name, digest string, options image.ManifestAnnotateOpts) (string, error) {
- var idr handlers.IDResponse
- conn, err := bindings.GetClient(ctx)
- if err != nil {
- return "", err
- }
- params := url.Values{}
- params.Set("digest", digest)
- optionsString, err := jsoniter.MarshalToString(options)
- if err != nil {
- return "", err
- }
- stringReader := strings.NewReader(optionsString)
- response, err := conn.DoRequest(stringReader, http.MethodPost, "/manifests/%s/annotate", params, name)
- if err != nil {
- return "", err
- }
- return idr.ID, response.Process(&idr)
-}
+//func Annotate(ctx context.Context, name, digest string, options image.ManifestAnnotateOpts) (string, error) {
+// var idr handlers.IDResponse
+// conn, err := bindings.GetClient(ctx)
+// if err != nil {
+// return "", err
+// }
+// params := url.Values{}
+// params.Set("digest", digest)
+// optionsString, err := jsoniter.MarshalToString(options)
+// if err != nil {
+// return "", err
+// }
+// stringReader := strings.NewReader(optionsString)
+// response, err := conn.DoRequest(stringReader, http.MethodPost, "/manifests/%s/annotate", params, name)
+// if err != nil {
+// return "", err
+// }
+// return idr.ID, response.Process(&idr)
+//}
diff --git a/pkg/bindings/test/containers_test.go b/pkg/bindings/test/containers_test.go
index c79d89b73..f40d8ce46 100644
--- a/pkg/bindings/test/containers_test.go
+++ b/pkg/bindings/test/containers_test.go
@@ -531,7 +531,7 @@ var _ = Describe("Podman containers ", func() {
Expect(err).ToNot(BeNil())
})
- It("podman prune stoped containers", func() {
+ It("podman prune stopped containers", func() {
// Start and stop a container to enter in exited state.
var name = "top"
_, err := bt.RunTopContainer(&name, &bindings.PFalse, nil)
@@ -546,7 +546,7 @@ var _ = Describe("Podman containers ", func() {
Expect(len(pruneResponse.ID)).To(Equal(1))
})
- It("podman prune stoped containers with filters", func() {
+ It("podman prune stopped containers with filters", func() {
// Start and stop a container to enter in exited state.
var name = "top"
_, err := bt.RunTopContainer(&name, &bindings.PFalse, nil)
diff --git a/pkg/bindings/test/manifests_test.go b/pkg/bindings/test/manifests_test.go
index ddb75865c..71d626b7b 100644
--- a/pkg/bindings/test/manifests_test.go
+++ b/pkg/bindings/test/manifests_test.go
@@ -118,25 +118,27 @@ var _ = Describe("Podman containers ", func() {
Expect(len(data.Manifests)).To(BeZero())
})
- It("annotate manifest", func() {
- id, err := manifests.Create(bt.conn, []string{"quay.io/libpod/foobar:latest"}, []string{}, nil)
- Expect(err).To(BeNil())
- opts := image.ManifestAddOpts{Images: []string{"docker.io/library/alpine:latest"}}
-
- _, err = manifests.Add(bt.conn, id, opts)
- Expect(err).To(BeNil())
- data, err := manifests.Inspect(bt.conn, id)
- Expect(err).To(BeNil())
- Expect(len(data.Manifests)).To(BeNumerically("==", 1))
- digest := data.Manifests[0].Digest.String()
- annoOpts := image.ManifestAnnotateOpts{OS: "foo"}
- _, err = manifests.Annotate(bt.conn, id, digest, annoOpts)
- Expect(err).To(BeNil())
- list, err := manifests.Inspect(bt.conn, id)
- Expect(err).To(BeNil())
- Expect(len(list.Manifests)).To(BeNumerically("==", 1))
- Expect(list.Manifests[0].Platform.OS).To(Equal("foo"))
- })
+ // There is NO annotate endpoint, this could never work.:w
+
+ //It("annotate manifest", func() {
+ // id, err := manifests.Create(bt.conn, []string{"quay.io/libpod/foobar:latest"}, []string{}, nil)
+ // Expect(err).To(BeNil())
+ // opts := image.ManifestAddOpts{Images: []string{"docker.io/library/alpine:latest"}}
+ //
+ // _, err = manifests.Add(bt.conn, id, opts)
+ // Expect(err).To(BeNil())
+ // data, err := manifests.Inspect(bt.conn, id)
+ // Expect(err).To(BeNil())
+ // Expect(len(data.Manifests)).To(BeNumerically("==", 1))
+ // digest := data.Manifests[0].Digest.String()
+ // annoOpts := image.ManifestAnnotateOpts{OS: "foo"}
+ // _, err = manifests.Annotate(bt.conn, id, digest, annoOpts)
+ // Expect(err).To(BeNil())
+ // list, err := manifests.Inspect(bt.conn, id)
+ // Expect(err).To(BeNil())
+ // Expect(len(list.Manifests)).To(BeNumerically("==", 1))
+ // Expect(list.Manifests[0].Platform.OS).To(Equal("foo"))
+ //})
It("push manifest", func() {
Skip("TODO")
diff --git a/pkg/bindings/test/pods_test.go b/pkg/bindings/test/pods_test.go
index 8a0b9c7a6..49bbfa246 100644
--- a/pkg/bindings/test/pods_test.go
+++ b/pkg/bindings/test/pods_test.go
@@ -57,6 +57,11 @@ var _ = Describe("Podman pods", func() {
podSummary, err := pods.List(bt.conn, nil)
Expect(err).To(BeNil())
Expect(len(podSummary)).To(Equal(1))
+
+ // Start the pod
+ _, err = pods.Start(bt.conn, newpod)
+ Expect(err).To(BeNil())
+
// Adding an alpine container to the existing pod
_, err = bt.RunTopContainer(nil, &bindings.PTrue, &newpod)
Expect(err).To(BeNil())
@@ -83,6 +88,11 @@ var _ = Describe("Podman pods", func() {
It("List pods with filters", func() {
newpod2 := "newpod2"
bt.Podcreate(&newpod2)
+
+ // Start the pod
+ _, err = pods.Start(bt.conn, newpod)
+ Expect(err).To(BeNil())
+
_, err = bt.RunTopContainer(nil, &bindings.PTrue, &newpod)
Expect(err).To(BeNil())
diff --git a/pkg/bindings/test/system_test.go b/pkg/bindings/test/system_test.go
index 87e6d56dc..62ea32377 100644
--- a/pkg/bindings/test/system_test.go
+++ b/pkg/bindings/test/system_test.go
@@ -3,7 +3,6 @@ package test_bindings
import (
"time"
- "github.com/containers/libpod/pkg/api/handlers"
"github.com/containers/libpod/pkg/bindings"
"github.com/containers/libpod/pkg/bindings/containers"
"github.com/containers/libpod/pkg/bindings/pods"
@@ -39,8 +38,8 @@ var _ = Describe("Podman system", func() {
})
It("podman events", func() {
- eChan := make(chan handlers.Event, 1)
- var messages []handlers.Event
+ eChan := make(chan entities.Event, 1)
+ var messages []entities.Event
cancelChan := make(chan bool, 1)
go func() {
for e := range eChan {
diff --git a/pkg/domain/entities/auto-update.go b/pkg/domain/entities/auto-update.go
new file mode 100644
index 000000000..aef8fc46b
--- /dev/null
+++ b/pkg/domain/entities/auto-update.go
@@ -0,0 +1,7 @@
+package entities
+
+// AutoUpdateReport contains the results from running auto-update.
+type AutoUpdateReport struct {
+ // Units - the restarted systemd units during auto-update.
+ Units []string
+}
diff --git a/pkg/domain/entities/containers.go b/pkg/domain/entities/containers.go
index 071eff2fc..e5330e1ab 100644
--- a/pkg/domain/entities/containers.go
+++ b/pkg/domain/entities/containers.go
@@ -6,11 +6,49 @@ import (
"os"
"time"
+ "github.com/containers/image/v5/types"
"github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/pkg/specgen"
"github.com/cri-o/ocicni/pkg/ocicni"
)
+// ContainerRunlabelOptions are the options to execute container-runlabel.
+type ContainerRunlabelOptions struct {
+ // Authfile - path to an authentication file.
+ Authfile string
+ // CertDir - path to a directory containing TLS certifications and
+ // keys.
+ CertDir string
+ // Credentials - `user:password` to use when pulling an image.
+ Credentials string
+ // Display - do not execute but print the command.
+ Display bool
+ // Replace - replace an existing container with a new one from the
+ // image.
+ Replace bool
+ // Name - use this name when executing the runlabel container.
+ Name string
+ // Optional1 - fist optional parameter for install.
+ Optional1 string
+ // Optional2 - second optional parameter for install.
+ Optional2 string
+ // Optional3 - third optional parameter for install.
+ Optional3 string
+ // Pull - pull the specified image if it's not in the local storage.
+ Pull bool
+ // Quiet - suppress output when pulling images.
+ Quiet bool
+ // SignaturePolicy - path to a signature-policy file.
+ SignaturePolicy string
+ // SkipTLSVerify - skip HTTPS and certificate verifications when
+ // contacting registries.
+ SkipTLSVerify types.OptionalBool
+}
+
+// ContainerRunlabelReport contains the results from executing container-runlabel.
+type ContainerRunlabelReport struct {
+}
+
type WaitOptions struct {
Condition define.ContainerStatus
Interval time.Duration
diff --git a/pkg/domain/entities/engine_container.go b/pkg/domain/entities/engine_container.go
index 1bfac4514..7c93e6802 100644
--- a/pkg/domain/entities/engine_container.go
+++ b/pkg/domain/entities/engine_container.go
@@ -10,6 +10,7 @@ import (
)
type ContainerEngine interface {
+ AutoUpdate(ctx context.Context) (*AutoUpdateReport, []error)
Config(ctx context.Context) (*config.Config, error)
ContainerAttach(ctx context.Context, nameOrId string, options AttachOptions) error
ContainerCheckpoint(ctx context.Context, namesOrIds []string, options CheckpointOptions) ([]*CheckpointReport, error)
@@ -34,6 +35,7 @@ type ContainerEngine interface {
ContainerRestore(ctx context.Context, namesOrIds []string, options RestoreOptions) ([]*RestoreReport, error)
ContainerRm(ctx context.Context, namesOrIds []string, options RmOptions) ([]*RmReport, error)
ContainerRun(ctx context.Context, opts ContainerRunOptions) (*ContainerRunReport, error)
+ ContainerRunlabel(ctx context.Context, label string, image string, args []string, opts ContainerRunlabelOptions) error
ContainerStart(ctx context.Context, namesOrIds []string, options ContainerStartOptions) ([]*ContainerStartReport, error)
ContainerStats(ctx context.Context, namesOrIds []string, options ContainerStatsOptions) error
ContainerStop(ctx context.Context, namesOrIds []string, options StopOptions) ([]*StopReport, error)
diff --git a/pkg/domain/infra/abi/auto-update.go b/pkg/domain/infra/abi/auto-update.go
new file mode 100644
index 000000000..aa20664b4
--- /dev/null
+++ b/pkg/domain/infra/abi/auto-update.go
@@ -0,0 +1,13 @@
+package abi
+
+import (
+ "context"
+
+ "github.com/containers/libpod/pkg/autoupdate"
+ "github.com/containers/libpod/pkg/domain/entities"
+)
+
+func (ic *ContainerEngine) AutoUpdate(ctx context.Context) (*entities.AutoUpdateReport, []error) {
+ units, failures := autoupdate.AutoUpdate(ic.Libpod)
+ return &entities.AutoUpdateReport{Units: units}, failures
+}
diff --git a/pkg/domain/infra/abi/containers_runlabel.go b/pkg/domain/infra/abi/containers_runlabel.go
new file mode 100644
index 000000000..41f4444d5
--- /dev/null
+++ b/pkg/domain/infra/abi/containers_runlabel.go
@@ -0,0 +1,280 @@
+package abi
+
+import (
+ "context"
+ "fmt"
+ "os"
+ "path/filepath"
+ "strings"
+
+ "github.com/containers/image/v5/types"
+ "github.com/containers/libpod/libpod/define"
+ "github.com/containers/libpod/libpod/image"
+ "github.com/containers/libpod/pkg/domain/entities"
+ envLib "github.com/containers/libpod/pkg/env"
+ "github.com/containers/libpod/pkg/util"
+ "github.com/containers/libpod/utils"
+ "github.com/google/shlex"
+ "github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
+)
+
+func (ic *ContainerEngine) ContainerRunlabel(ctx context.Context, label string, imageRef string, args []string, options entities.ContainerRunlabelOptions) error {
+ // First, get the image and pull it if needed.
+ img, err := ic.runlabelImage(ctx, label, imageRef, options)
+ if err != nil {
+ return err
+ }
+ // Extract the runlabel from the image.
+ runlabel, err := img.GetLabel(ctx, label)
+ if err != nil {
+ return err
+ }
+
+ cmd, env, err := generateRunlabelCommand(runlabel, img, args, options)
+ if err != nil {
+ return err
+ }
+
+ stdErr := os.Stderr
+ stdOut := os.Stdout
+ stdIn := os.Stdin
+ if options.Quiet {
+ stdErr = nil
+ stdOut = nil
+ stdIn = nil
+ }
+
+ // If container already exists && --replace given -- Nuke it
+ if options.Replace {
+ for i, entry := range cmd {
+ if entry == "--name" {
+ name := cmd[i+1]
+ ctr, err := ic.Libpod.LookupContainer(name)
+ if err != nil {
+ if errors.Cause(err) != define.ErrNoSuchCtr {
+ logrus.Debugf("Error occurred searching for container %s: %s", name, err.Error())
+ return err
+ }
+ } else {
+ logrus.Debugf("Runlabel --replace option given. Container %s will be deleted. The new container will be named %s", ctr.ID(), name)
+ if err := ic.Libpod.RemoveContainer(ctx, ctr, true, false); err != nil {
+ return err
+ }
+ }
+ break
+ }
+ }
+ }
+
+ return utils.ExecCmdWithStdStreams(stdIn, stdOut, stdErr, env, cmd[0], cmd[1:]...)
+}
+
+// runlabelImage returns an image based on the specified image AND options.
+func (ic *ContainerEngine) runlabelImage(ctx context.Context, label string, imageRef string, options entities.ContainerRunlabelOptions) (*image.Image, error) {
+ // First, look up the image locally. If we get an error and requested
+ // to pull, fallthrough and pull it.
+ img, err := ic.Libpod.ImageRuntime().NewFromLocal(imageRef)
+ switch {
+ case err == nil:
+ return img, nil
+ case !options.Pull:
+ return nil, err
+ default:
+ // Fallthrough and pull!
+ }
+
+ // Parse credentials if specified.
+ var credentials *types.DockerAuthConfig
+ if options.Credentials != "" {
+ credentials, err = util.ParseRegistryCreds(options.Credentials)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ // Suppress pull progress bars if requested.
+ pullOutput := os.Stdout
+ if options.Quiet {
+ pullOutput = nil // c/image/copy takes care of the rest
+ }
+
+ // Pull the image.
+ dockerRegistryOptions := image.DockerRegistryOptions{
+ DockerCertPath: options.CertDir,
+ DockerInsecureSkipTLSVerify: options.SkipTLSVerify,
+ DockerRegistryCreds: credentials,
+ }
+
+ return ic.Libpod.ImageRuntime().New(ctx, imageRef, options.SignaturePolicy, options.Authfile, pullOutput, &dockerRegistryOptions, image.SigningOptions{}, &label, util.PullImageMissing)
+}
+
+// generateRunlabelCommand generates the to-be-executed command as a string
+// slice along with a base environment.
+func generateRunlabelCommand(runlabel string, img *image.Image, args []string, options entities.ContainerRunlabelOptions) ([]string, []string, error) {
+ var (
+ err error
+ name, imageName string
+ globalOpts string
+ cmd, env []string
+ )
+
+ // TODO: How do we get global opts as done in v1?
+
+ // Extract the imageName (or ID).
+ imgNames := img.Names()
+ if len(imgNames) == 0 {
+ imageName = img.ID()
+ } else {
+ imageName = imgNames[0]
+ }
+
+ // Use the user-specified name or extract one from the image.
+ if options.Name != "" {
+ name = options.Name
+ } else {
+ name, err = image.GetImageBaseName(imageName)
+ if err != nil {
+ return nil, nil, err
+ }
+ }
+
+ // Append the user-specified arguments to the runlabel (command).
+ if len(args) > 0 {
+ runlabel = fmt.Sprintf("%s %s", runlabel, strings.Join(args, " "))
+ }
+
+ cmd, err = generateCommand(runlabel, imageName, name, globalOpts)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ env = generateRunEnvironment(name, imageName, options)
+ env = append(env, "PODMAN_RUNLABEL_NESTED=1")
+ envmap, err := envLib.ParseSlice(env)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ envmapper := func(k string) string {
+ switch k {
+ case "OPT1":
+ return envmap["OPT1"]
+ case "OPT2":
+ return envmap["OPT2"]
+ case "OPT3":
+ return envmap["OPT3"]
+ case "PWD":
+ // I would prefer to use os.getenv but it appears PWD is not in the os env list.
+ d, err := os.Getwd()
+ if err != nil {
+ logrus.Error("unable to determine current working directory")
+ return ""
+ }
+ return d
+ }
+ return ""
+ }
+ newS := os.Expand(strings.Join(cmd, " "), envmapper)
+ cmd, err = shlex.Split(newS)
+ if err != nil {
+ return nil, nil, err
+ }
+ return cmd, env, nil
+}
+
+// generateCommand takes a label (string) and converts it to an executable command
+func generateCommand(command, imageName, name, globalOpts string) ([]string, error) {
+ var (
+ newCommand []string
+ )
+ if name == "" {
+ name = imageName
+ }
+
+ cmd, err := shlex.Split(command)
+ if err != nil {
+ return nil, err
+ }
+
+ prog, err := substituteCommand(cmd[0])
+ if err != nil {
+ return nil, err
+ }
+ newCommand = append(newCommand, prog)
+
+ for _, arg := range cmd[1:] {
+ var newArg string
+ switch arg {
+ case "IMAGE":
+ newArg = imageName
+ case "$IMAGE":
+ newArg = imageName
+ case "IMAGE=IMAGE":
+ newArg = fmt.Sprintf("IMAGE=%s", imageName)
+ case "IMAGE=$IMAGE":
+ newArg = fmt.Sprintf("IMAGE=%s", imageName)
+ case "NAME":
+ newArg = name
+ case "NAME=NAME":
+ newArg = fmt.Sprintf("NAME=%s", name)
+ case "NAME=$NAME":
+ newArg = fmt.Sprintf("NAME=%s", name)
+ case "$NAME":
+ newArg = name
+ case "$GLOBAL_OPTS":
+ newArg = globalOpts
+ default:
+ newArg = arg
+ }
+ newCommand = append(newCommand, newArg)
+ }
+ return newCommand, nil
+}
+
+// GenerateRunEnvironment merges the current environment variables with optional
+// environment variables provided by the user
+func generateRunEnvironment(name, imageName string, options entities.ContainerRunlabelOptions) []string {
+ newEnv := os.Environ()
+ if options.Optional1 != "" {
+ newEnv = append(newEnv, fmt.Sprintf("OPT1=%s", options.Optional1))
+ }
+ if options.Optional2 != "" {
+ newEnv = append(newEnv, fmt.Sprintf("OPT2=%s", options.Optional2))
+ }
+ if options.Optional3 != "" {
+ newEnv = append(newEnv, fmt.Sprintf("OPT3=%s", options.Optional3))
+ }
+ return newEnv
+}
+
+func substituteCommand(cmd string) (string, error) {
+ var (
+ newCommand string
+ )
+
+ // Replace cmd with "/proc/self/exe" if "podman" or "docker" is being
+ // used. If "/usr/bin/docker" is provided, we also sub in podman.
+ // Otherwise, leave the command unchanged.
+ if cmd == "podman" || filepath.Base(cmd) == "docker" {
+ newCommand = "/proc/self/exe"
+ } else {
+ newCommand = cmd
+ }
+
+ // If cmd is an absolute or relative path, check if the file exists.
+ // Throw an error if it doesn't exist.
+ if strings.Contains(newCommand, "/") || strings.HasPrefix(newCommand, ".") {
+ res, err := filepath.Abs(newCommand)
+ if err != nil {
+ return "", err
+ }
+ if _, err := os.Stat(res); !os.IsNotExist(err) {
+ return res, nil
+ } else if err != nil {
+ return "", err
+ }
+ }
+
+ return newCommand, nil
+}
diff --git a/pkg/domain/infra/abi/system.go b/pkg/domain/infra/abi/system.go
index 692fcfa0f..24c62465f 100644
--- a/pkg/domain/infra/abi/system.go
+++ b/pkg/domain/infra/abi/system.go
@@ -86,6 +86,7 @@ func (ic *ContainerEngine) SetupRootless(_ context.Context, cmd *cobra.Command)
}
}
}
+ return nil
}
pausePidPath, err := util.GetRootlessPauseProcessPidPath()
diff --git a/pkg/domain/infra/tunnel/auto-update.go b/pkg/domain/infra/tunnel/auto-update.go
new file mode 100644
index 000000000..fac033050
--- /dev/null
+++ b/pkg/domain/infra/tunnel/auto-update.go
@@ -0,0 +1,12 @@
+package tunnel
+
+import (
+ "context"
+
+ "github.com/containers/libpod/pkg/domain/entities"
+ "github.com/pkg/errors"
+)
+
+func (ic *ContainerEngine) AutoUpdate(ctx context.Context) (*entities.AutoUpdateReport, []error) {
+ return nil, []error{errors.New("not implemented")}
+}
diff --git a/pkg/domain/infra/tunnel/containers.go b/pkg/domain/infra/tunnel/containers.go
index 227b660f7..49a3069d6 100644
--- a/pkg/domain/infra/tunnel/containers.go
+++ b/pkg/domain/infra/tunnel/containers.go
@@ -14,6 +14,10 @@ import (
"github.com/pkg/errors"
)
+func (ic *ContainerEngine) ContainerRunlabel(ctx context.Context, label string, image string, args []string, options entities.ContainerRunlabelOptions) error {
+ return errors.New("not implemented")
+}
+
func (ic *ContainerEngine) ContainerExists(ctx context.Context, nameOrId string) (*entities.BoolReport, error) {
exists, err := containers.Exists(ic.ClientCxt, nameOrId)
return &entities.BoolReport{Value: exists}, err
diff --git a/pkg/domain/infra/tunnel/manifest.go b/pkg/domain/infra/tunnel/manifest.go
index 7d9a0fce1..9c1f5349a 100644
--- a/pkg/domain/infra/tunnel/manifest.go
+++ b/pkg/domain/infra/tunnel/manifest.go
@@ -64,32 +64,34 @@ func (ir *ImageEngine) ManifestAdd(ctx context.Context, opts entities.ManifestAd
return listID, nil
}
+// FIXME There is no endpoint for annotate and therefor this code is currently invalid
// ManifestAnnotate updates an entry of the manifest list
func (ir *ImageEngine) ManifestAnnotate(ctx context.Context, names []string, opts entities.ManifestAnnotateOptions) (string, error) {
- manifestAnnotateOpts := image.ManifestAnnotateOpts{
- Arch: opts.Arch,
- Features: opts.Features,
- OS: opts.OS,
- OSFeatures: opts.OSFeatures,
- OSVersion: opts.OSVersion,
- Variant: opts.Variant,
- }
- if len(opts.Annotation) > 0 {
- annotations := make(map[string]string)
- for _, annotationSpec := range opts.Annotation {
- spec := strings.SplitN(annotationSpec, "=", 2)
- if len(spec) != 2 {
- return "", errors.Errorf("no value given for annotation %q", spec[0])
- }
- annotations[spec[0]] = spec[1]
- }
- manifestAnnotateOpts.Annotation = annotations
- }
- updatedListID, err := manifests.Annotate(ctx, names[0], names[1], manifestAnnotateOpts)
- if err != nil {
- return updatedListID, errors.Wrapf(err, "error annotating %s of manifest list %s", names[1], names[0])
- }
- return fmt.Sprintf("%s :%s", updatedListID, names[1]), nil
+ return "", errors.New("not implemented")
+ // manifestAnnotateOpts := image.ManifestAnnotateOpts{
+ // Arch: opts.Arch,
+ // Features: opts.Features,
+ // OS: opts.OS,
+ // OSFeatures: opts.OSFeatures,
+ // OSVersion: opts.OSVersion,
+ // Variant: opts.Variant,
+ // }
+ // if len(opts.Annotation) > 0 {
+ // annotations := make(map[string]string)
+ // for _, annotationSpec := range opts.Annotation {
+ // spec := strings.SplitN(annotationSpec, "=", 2)
+ // if len(spec) != 2 {
+ // return "", errors.Errorf("no value given for annotation %q", spec[0])
+ // }
+ // annotations[spec[0]] = spec[1]
+ // }
+ // manifestAnnotateOpts.Annotation = annotations
+ // }
+ // updatedListID, err := manifests.Annotate(ctx, names[0], names[1], manifestAnnotateOpts)
+ // if err != nil {
+ // return updatedListID, errors.Wrapf(err, "error annotating %s of manifest list %s", names[1], names[0])
+ // }
+ // return fmt.Sprintf("%s :%s", updatedListID, names[1]), nil
}
// ManifestRemove removes the digest from manifest list
diff --git a/pkg/specgen/generate/container.go b/pkg/specgen/generate/container.go
index e4bd2991a..a217125f4 100644
--- a/pkg/specgen/generate/container.go
+++ b/pkg/specgen/generate/container.go
@@ -42,11 +42,13 @@ func CompleteSpec(ctx context.Context, r *libpod.Runtime, s *specgen.SpecGenerat
if err != nil {
return err
}
- sig, err := signal.ParseSignalNameOrNumber(stopSignal)
- if err != nil {
- return err
+ if stopSignal != "" {
+ sig, err := signal.ParseSignalNameOrNumber(stopSignal)
+ if err != nil {
+ return err
+ }
+ s.StopSignal = &sig
}
- s.StopSignal = &sig
}
rtc, err := r.GetConfig()
@@ -78,6 +80,9 @@ func CompleteSpec(ctx context.Context, r *libpod.Runtime, s *specgen.SpecGenerat
}
// labels from the image that dont exist already
+ if len(labels) > 0 && s.Labels == nil {
+ s.Labels = make(map[string]string)
+ }
for k, v := range labels {
if _, exists := s.Labels[k]; !exists {
s.Labels[k] = v
diff --git a/pkg/specgen/pod_validate.go b/pkg/specgen/pod_validate.go
index 98d59549e..08f1c0300 100644
--- a/pkg/specgen/pod_validate.go
+++ b/pkg/specgen/pod_validate.go
@@ -33,7 +33,7 @@ func (p *PodSpecGenerator) Validate() error {
}
// PodNetworkConfig
- if err := p.NetNS.validate(); err != nil {
+ if err := validateNetNS(&p.NetNS); err != nil {
return err
}
if p.NoInfra {
@@ -85,10 +85,6 @@ func (p *PodSpecGenerator) Validate() error {
return exclusivePodOptions("NoManageHosts", "HostAdd")
}
- if err := p.NetNS.validate(); err != nil {
- return err
- }
-
// Set Defaults
if p.NetNS.Value == "" {
if rootless.IsRootless() {
diff --git a/pkg/specgen/podspecgen.go b/pkg/specgen/podspecgen.go
index 682f3f215..11976233a 100644
--- a/pkg/specgen/podspecgen.go
+++ b/pkg/specgen/podspecgen.go
@@ -54,7 +54,7 @@ type PodNetworkConfig struct {
// namespace. This network will, by default, be shared with all
// containers in the pod.
// Cannot be set to FromContainer and FromPod.
- // Setting this to anything except "" conflicts with NoInfra=true.
+ // Setting this to anything except default conflicts with NoInfra=true.
// Defaults to Bridge as root and Slirp as rootless.
// Mandatory.
NetNS Namespace `json:"netns,omitempty"`
diff --git a/test/e2e/runlabel_test.go b/test/e2e/runlabel_test.go
index 83fdcabc9..41d61e9d9 100644
--- a/test/e2e/runlabel_test.go
+++ b/test/e2e/runlabel_test.go
@@ -31,7 +31,6 @@ var _ = Describe("podman container runlabel", func() {
)
BeforeEach(func() {
- Skip(v2fail)
tempdir, err = CreateTempDirInTempDir()
if err != nil {
os.Exit(1)
diff --git a/test/e2e/stats_test.go b/test/e2e/stats_test.go
index 762417a17..d3af44891 100644
--- a/test/e2e/stats_test.go
+++ b/test/e2e/stats_test.go
@@ -5,6 +5,7 @@ package integration
import (
"fmt"
"os"
+ "time"
"github.com/containers/libpod/pkg/cgroups"
. "github.com/containers/libpod/test/utils"
@@ -87,13 +88,24 @@ var _ = Describe("Podman stats", func() {
})
It("podman stats with json output", func() {
+ var found bool
session := podmanTest.RunTopContainer("")
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- session = podmanTest.Podman([]string{"stats", "--all", "--no-stream", "--format", "json"})
- session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
- Expect(session.IsJSONOutputValid()).To(BeTrue())
+ for i := 0; i < 5; i++ {
+ ps := podmanTest.Podman([]string{"ps", "-q"})
+ ps.WaitWithDefaultTimeout()
+ if len(ps.OutputToStringArray()) == 1 {
+ found = true
+ break
+ }
+ time.Sleep(time.Second)
+ }
+ Expect(found).To(BeTrue())
+ stats := podmanTest.Podman([]string{"stats", "--all", "--no-stream", "--format", "json"})
+ stats.WaitWithDefaultTimeout()
+ Expect(stats.ExitCode()).To(Equal(0))
+ Expect(stats.IsJSONOutputValid()).To(BeTrue())
})
It("podman stats on a container with no net ns", func() {
diff --git a/test/system/250-generate-systemd.bats b/test/system/250-generate-systemd.bats
deleted file mode 100644
index 6155d6ace..000000000
--- a/test/system/250-generate-systemd.bats
+++ /dev/null
@@ -1,48 +0,0 @@
-#!/usr/bin/env bats -*- bats -*-
-#
-# Tests generated configurations for systemd.
-#
-
-load helpers
-
-# Be extra paranoid in naming to avoid collisions.
-SERVICE_NAME="podman_test_$(random_string)"
-UNIT_DIR="$HOME/.config/systemd/user"
-UNIT_FILE="$UNIT_DIR/$SERVICE_NAME.service"
-
-# FIXME: the must run as root (because of CI). It's also broken...
-
-function setup() {
- skip_if_not_systemd
- skip_if_remote
-
- basic_setup
-
- if [ ! -d "$UNIT_DIR" ]; then
- mkdir -p "$UNIT_DIR"
- systemctl --user daemon-reload
- fi
-}
-
-function teardown() {
- rm -f "$UNIT_FILE"
- systemctl --user stop "$SERVICE_NAME"
- basic_teardown
-}
-
-@test "podman generate - systemd - basic" {
- run_podman create $IMAGE echo "I'm alive!"
- cid="$output"
-
- run_podman generate systemd $cid > "$UNIT_FILE"
-
- run systemctl --user start "$SERVICE_NAME"
- if [ $status -ne 0 ]; then
- die "The systemd service $SERVICE_NAME did not start correctly, output: $output"
- fi
-
- run_podman logs $cid
- is "$output" "I'm alive!" "Container output"
-}
-
-# vim: filetype=sh
diff --git a/test/system/250-systemd.bats b/test/system/250-systemd.bats
new file mode 100644
index 000000000..902a7cad8
--- /dev/null
+++ b/test/system/250-systemd.bats
@@ -0,0 +1,49 @@
+#!/usr/bin/env bats -*- bats -*-
+#
+# Tests generated configurations for systemd.
+#
+
+load helpers
+
+SERVICE_NAME="podman_test_$(random_string)"
+UNIT_DIR="/usr/lib/systemd/system"
+UNIT_FILE="$UNIT_DIR/$SERVICE_NAME.service"
+
+function setup() {
+ skip_if_remote
+ skip_if_rootless "systemd tests are root-only for now"
+
+ basic_setup
+}
+
+function teardown() {
+ rm -f "$UNIT_FILE"
+ systemctl daemon-reload
+ basic_teardown
+}
+
+@test "podman generate - systemd - basic" {
+ run_podman create --name keepme --detach busybox:latest top
+
+ run_podman generate systemd --new keepme > "$UNIT_FILE"
+ run_podman rm keepme
+
+ systemctl daemon-reload
+
+ run systemctl start "$SERVICE_NAME"
+ if [ $status -ne 0 ]; then
+ die "Error starting systemd unit $SERVICE_NAME, output: $output"
+ fi
+
+ run systemctl status "$SERVICE_NAME"
+ if [ $status -ne 0 ]; then
+ die "Non-zero status of systemd unit $SERVICE_NAME, output: $output"
+ fi
+
+ run systemctl stop "$SERVICE_NAME"
+ if [ $status -ne 0 ]; then
+ die "Error stopping systemd unit $SERVICE_NAME, output: $output"
+ fi
+}
+
+# vim: filetype=sh
diff --git a/test/system/helpers.bash b/test/system/helpers.bash
index 51240edc9..7ec2105d1 100644
--- a/test/system/helpers.bash
+++ b/test/system/helpers.bash
@@ -252,17 +252,6 @@ function skip_if_remote() {
fi
}
-#########################
-# skip_if_not_systemd # ...with an optional message
-#########################
-function skip_if_not_systemd() {
- if systemctl --user >/dev/null 2>&1; then
- return
- fi
-
- skip "${1:-no systemd or daemon does not respond}"
-}
-
#########
# die # Abort with helpful message
#########
diff --git a/vendor/github.com/containers/common/pkg/auth/auth.go b/vendor/github.com/containers/common/pkg/auth/auth.go
index 4e0400d23..1aa9f8b31 100644
--- a/vendor/github.com/containers/common/pkg/auth/auth.go
+++ b/vendor/github.com/containers/common/pkg/auth/auth.go
@@ -34,9 +34,32 @@ func CheckAuthFile(authfile string) error {
return nil
}
+// systemContextWithOptions returns a version of sys
+// updated with authFile and certDir values (if they are not "").
+// NOTE: this is a shallow copy that can be used and updated, but may share
+// data with the original parameter.
+func systemContextWithOptions(sys *types.SystemContext, authFile, certDir string) *types.SystemContext {
+ if sys != nil {
+ copy := *sys
+ sys = &copy
+ } else {
+ sys = &types.SystemContext{}
+ }
+
+ if authFile != "" {
+ sys.AuthFilePath = authFile
+ }
+ if certDir != "" {
+ sys.DockerCertPath = certDir
+ }
+ return sys
+}
+
// Login implements a “log in” command with the provided opts and args
// reading the password from opts.Stdin or the options in opts.
func Login(ctx context.Context, systemContext *types.SystemContext, opts *LoginOptions, args []string) error {
+ systemContext = systemContextWithOptions(systemContext, opts.AuthFile, opts.CertDir)
+
var (
server string
err error
@@ -172,6 +195,11 @@ func getUserAndPass(opts *LoginOptions, password, userFromAuthFile string) (stri
// Logout implements a “log out” command with the provided opts and args
func Logout(systemContext *types.SystemContext, opts *LogoutOptions, args []string) error {
+ if err := CheckAuthFile(opts.AuthFile); err != nil {
+ return err
+ }
+ systemContext = systemContextWithOptions(systemContext, opts.AuthFile, "")
+
var (
server string
err error
@@ -194,9 +222,6 @@ func Logout(systemContext *types.SystemContext, opts *LogoutOptions, args []stri
}
server = getRegistryName(args[0])
}
- if err := CheckAuthFile(opts.AuthFile); err != nil {
- return err
- }
if opts.All {
if err := config.RemoveAllAuthentication(systemContext); err != nil {
diff --git a/vendor/github.com/containers/common/pkg/auth/cli.go b/vendor/github.com/containers/common/pkg/auth/cli.go
index 3384b0731..ab033681d 100644
--- a/vendor/github.com/containers/common/pkg/auth/cli.go
+++ b/vendor/github.com/containers/common/pkg/auth/cli.go
@@ -7,16 +7,19 @@ import (
)
// LoginOptions represents common flags in login
-// caller should define bool or optionalBool fields for flags --get-login and --tls-verify
+// In addition, the caller should probably provide a --tls-verify flag (that affects the provided
+// *types.SystemContest)
type LoginOptions struct {
// CLI flags managed by the FlagSet returned by GetLoginFlags
+ // Callers that use GetLoginFlags should not need to touch these values at all; callers that use
+ // other CLI frameworks should set them based on user input.
AuthFile string
CertDir string
Password string
Username string
StdinPassword bool
+ GetLoginSet bool
// Options caller can set
- GetLoginSet bool // set to true if --get-login is explicitly set
Stdin io.Reader // set to os.Stdin
Stdout io.Writer // set to os.Stdout
AcceptUnspecifiedRegistry bool // set to true if allows login with unspecified registry
@@ -25,10 +28,11 @@ type LoginOptions struct {
// LogoutOptions represents the results for flags in logout
type LogoutOptions struct {
// CLI flags managed by the FlagSet returned by GetLogoutFlags
+ // Callers that use GetLogoutFlags should not need to touch these values at all; callers that use
+ // other CLI frameworks should set them based on user input.
AuthFile string
All bool
// Options caller can set
- Stdin io.Reader // set to os.Stdin
Stdout io.Writer // set to os.Stdout
AcceptUnspecifiedRegistry bool // set to true if allows logout with unspecified registry
}
@@ -41,6 +45,7 @@ func GetLoginFlags(flags *LoginOptions) *pflag.FlagSet {
fs.StringVarP(&flags.Password, "password", "p", "", "Password for registry")
fs.StringVarP(&flags.Username, "username", "u", "", "Username for registry")
fs.BoolVar(&flags.StdinPassword, "password-stdin", false, "Take the password from stdin")
+ fs.BoolVar(&flags.GetLoginSet, "get-login", false, "Return the current login user for the registry")
return &fs
}
diff --git a/vendor/github.com/containers/common/pkg/config/config.go b/vendor/github.com/containers/common/pkg/config/config.go
index 0f17c27c9..611284476 100644
--- a/vendor/github.com/containers/common/pkg/config/config.go
+++ b/vendor/github.com/containers/common/pkg/config/config.go
@@ -442,16 +442,6 @@ func readConfigFromFile(path string, config *Config) (*Config, error) {
if err != nil {
return nil, fmt.Errorf("unable to decode configuration %v: %v", path, err)
}
- if config.Engine.VolumePath != "" {
- config.Engine.VolumePathSet = true
- }
- if config.Engine.StaticDir != "" {
- config.Engine.StaticDirSet = true
- }
- if config.Engine.TmpDir != "" {
- config.Engine.TmpDirSet = true
- }
-
return config, err
}
diff --git a/vendor/github.com/containers/common/pkg/config/default.go b/vendor/github.com/containers/common/pkg/config/default.go
index ec52ff706..7debd2984 100644
--- a/vendor/github.com/containers/common/pkg/config/default.go
+++ b/vendor/github.com/containers/common/pkg/config/default.go
@@ -479,6 +479,8 @@ func (c *Config) PidsLimit() int64 {
cgroup2, _ := cgroupv2.Enabled()
if cgroup2 {
return c.Containers.PidsLimit
+ } else {
+ return 0
}
}
return sysinfo.GetDefaultPidsLimit()
diff --git a/vendor/github.com/onsi/gomega/.travis.yml b/vendor/github.com/onsi/gomega/.travis.yml
index c6391855a..072fdd2db 100644
--- a/vendor/github.com/onsi/gomega/.travis.yml
+++ b/vendor/github.com/onsi/gomega/.travis.yml
@@ -1,8 +1,8 @@
language: go
go:
- - 1.12.x
- 1.13.x
+ - 1.14.x
- gotip
env:
diff --git a/vendor/github.com/onsi/gomega/CHANGELOG.md b/vendor/github.com/onsi/gomega/CHANGELOG.md
index 3e9b5961b..35adfb8d7 100644
--- a/vendor/github.com/onsi/gomega/CHANGELOG.md
+++ b/vendor/github.com/onsi/gomega/CHANGELOG.md
@@ -1,3 +1,11 @@
+## 1.10.0
+
+### Features
+- Add HaveHTTPStatusMatcher (#378) [f335c94]
+- Changed matcher for content-type in VerifyJSONRepresenting (#377) [6024f5b]
+- Make ghttp usable with x-unit style tests (#376) [c0be499]
+- Implement PanicWith matcher (#381) [f8032b4]
+
## 1.9.0
### Features
diff --git a/vendor/github.com/onsi/gomega/gomega_dsl.go b/vendor/github.com/onsi/gomega/gomega_dsl.go
index 0ab35bc7a..65e837e20 100644
--- a/vendor/github.com/onsi/gomega/gomega_dsl.go
+++ b/vendor/github.com/onsi/gomega/gomega_dsl.go
@@ -24,7 +24,7 @@ import (
"github.com/onsi/gomega/types"
)
-const GOMEGA_VERSION = "1.9.0"
+const GOMEGA_VERSION = "1.10.0"
const nilFailHandlerPanic = `You are trying to make an assertion, but Gomega's fail handler is nil.
If you're using Ginkgo then you probably forgot to put your assertion in an It().
@@ -252,7 +252,7 @@ func Consistently(actual interface{}, intervals ...interface{}) AsyncAssertion {
return ConsistentlyWithOffset(0, actual, intervals...)
}
-// ConsistentlyWithOffset operates like Consistnetly but takes an additional
+// ConsistentlyWithOffset operates like Consistently but takes an additional
// initial argument to indicate an offset in the call stack. This is useful when building helper
// functions that contain matchers. To learn more, read about `ExpectWithOffset`.
func ConsistentlyWithOffset(offset int, actual interface{}, intervals ...interface{}) AsyncAssertion {
@@ -432,3 +432,32 @@ func toDuration(input interface{}) time.Duration {
panic(fmt.Sprintf("%v is not a valid interval. Must be time.Duration, parsable duration string or a number.", input))
}
+
+// Gomega describes the essential Gomega DSL. This interface allows libraries
+// to abstract between the standard package-level function implementations
+// and alternatives like *WithT.
+type Gomega interface {
+ Expect(actual interface{}, extra ...interface{}) Assertion
+ Eventually(actual interface{}, intervals ...interface{}) AsyncAssertion
+ Consistently(actual interface{}, intervals ...interface{}) AsyncAssertion
+}
+
+type globalFailHandlerGomega struct{}
+
+// DefaultGomega supplies the standard package-level implementation
+var Default Gomega = globalFailHandlerGomega{}
+
+// Expect is used to make assertions. See documentation for Expect.
+func (globalFailHandlerGomega) Expect(actual interface{}, extra ...interface{}) Assertion {
+ return Expect(actual, extra...)
+}
+
+// Eventually is used to make asynchronous assertions. See documentation for Eventually.
+func (globalFailHandlerGomega) Eventually(actual interface{}, extra ...interface{}) AsyncAssertion {
+ return Eventually(actual, extra...)
+}
+
+// Consistently is used to make asynchronous assertions. See documentation for Consistently.
+func (globalFailHandlerGomega) Consistently(actual interface{}, extra ...interface{}) AsyncAssertion {
+ return Consistently(actual, extra...)
+}
diff --git a/vendor/github.com/onsi/gomega/matchers.go b/vendor/github.com/onsi/gomega/matchers.go
index 11f5b1070..16218d4c5 100644
--- a/vendor/github.com/onsi/gomega/matchers.go
+++ b/vendor/github.com/onsi/gomega/matchers.go
@@ -390,6 +390,16 @@ func Panic() types.GomegaMatcher {
return &matchers.PanicMatcher{}
}
+//PanicWith succeeds if actual is a function that, when invoked, panics with a specific value.
+//Actual must be a function that takes no arguments and returns no results.
+//
+//By default PanicWith uses Equal() to perform the match, however a
+//matcher can be passed in instead:
+// Expect(fn).Should(PanicWith(MatchRegexp(`.+Foo$`)))
+func PanicWith(expected interface{}) types.GomegaMatcher {
+ return &matchers.PanicMatcher{Expected: expected}
+}
+
//BeAnExistingFile succeeds if a file exists.
//Actual must be a string representing the abs path to the file being checked.
func BeAnExistingFile() types.GomegaMatcher {
@@ -408,6 +418,15 @@ func BeADirectory() types.GomegaMatcher {
return &matchers.BeADirectoryMatcher{}
}
+//HaveHTTPStatus succeeds if the Status or StatusCode field of an HTTP response matches.
+//Actual must be either a *http.Response or *httptest.ResponseRecorder.
+//Expected must be either an int or a string.
+// Expect(resp).Should(HaveHTTPStatus(http.StatusOK)) // asserts that resp.StatusCode == 200
+// Expect(resp).Should(HaveHTTPStatus("404 Not Found")) // asserts that resp.Status == "404 Not Found"
+func HaveHTTPStatus(expected interface{}) types.GomegaMatcher {
+ return &matchers.HaveHTTPStatusMatcher{Expected: expected}
+}
+
//And succeeds only if all of the given matchers succeed.
//The matchers are tried in order, and will fail-fast if one doesn't succeed.
// Expect("hi").To(And(HaveLen(2), Equal("hi"))
diff --git a/vendor/github.com/onsi/gomega/matchers/have_http_status_matcher.go b/vendor/github.com/onsi/gomega/matchers/have_http_status_matcher.go
new file mode 100644
index 000000000..3ce4800b7
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/have_http_status_matcher.go
@@ -0,0 +1,42 @@
+package matchers
+
+import (
+ "fmt"
+ "net/http"
+ "net/http/httptest"
+
+ "github.com/onsi/gomega/format"
+)
+
+type HaveHTTPStatusMatcher struct {
+ Expected interface{}
+}
+
+func (matcher *HaveHTTPStatusMatcher) Match(actual interface{}) (success bool, err error) {
+ var resp *http.Response
+ switch a := actual.(type) {
+ case *http.Response:
+ resp = a
+ case *httptest.ResponseRecorder:
+ resp = a.Result()
+ default:
+ return false, fmt.Errorf("HaveHTTPStatus matcher expects *http.Response or *httptest.ResponseRecorder. Got:\n%s", format.Object(actual, 1))
+ }
+
+ switch e := matcher.Expected.(type) {
+ case int:
+ return resp.StatusCode == e, nil
+ case string:
+ return resp.Status == e, nil
+ }
+
+ return false, fmt.Errorf("HaveHTTPStatus matcher must be passed an int or a string. Got:\n%s", format.Object(matcher.Expected, 1))
+}
+
+func (matcher *HaveHTTPStatusMatcher) FailureMessage(actual interface{}) (message string) {
+ return format.Message(actual, "to have HTTP status", matcher.Expected)
+}
+
+func (matcher *HaveHTTPStatusMatcher) NegatedFailureMessage(actual interface{}) (message string) {
+ return format.Message(actual, "not to have HTTP status", matcher.Expected)
+}
diff --git a/vendor/github.com/onsi/gomega/matchers/panic_matcher.go b/vendor/github.com/onsi/gomega/matchers/panic_matcher.go
index 640f4db1a..adc8cee63 100644
--- a/vendor/github.com/onsi/gomega/matchers/panic_matcher.go
+++ b/vendor/github.com/onsi/gomega/matchers/panic_matcher.go
@@ -8,7 +8,8 @@ import (
)
type PanicMatcher struct {
- object interface{}
+ Expected interface{}
+ object interface{}
}
func (matcher *PanicMatcher) Match(actual interface{}) (success bool, err error) {
@@ -28,7 +29,21 @@ func (matcher *PanicMatcher) Match(actual interface{}) (success bool, err error)
defer func() {
if e := recover(); e != nil {
matcher.object = e
- success = true
+
+ if matcher.Expected == nil {
+ success = true
+ return
+ }
+
+ valueMatcher, valueIsMatcher := matcher.Expected.(omegaMatcher)
+ if !valueIsMatcher {
+ valueMatcher = &EqualMatcher{Expected: matcher.Expected}
+ }
+
+ success, err = valueMatcher.Match(e)
+ if err != nil {
+ err = fmt.Errorf("PanicMatcher's value matcher failed with:\n%s%s", format.Indent, err.Error())
+ }
}
}()
@@ -38,9 +53,62 @@ func (matcher *PanicMatcher) Match(actual interface{}) (success bool, err error)
}
func (matcher *PanicMatcher) FailureMessage(actual interface{}) (message string) {
- return format.Message(actual, "to panic")
+ if matcher.Expected == nil {
+ // We wanted any panic to occur, but none did.
+ return format.Message(actual, "to panic")
+ }
+
+ if matcher.object == nil {
+ // We wanted a panic with a specific value to occur, but none did.
+ switch matcher.Expected.(type) {
+ case omegaMatcher:
+ return format.Message(actual, "to panic with a value matching", matcher.Expected)
+ default:
+ return format.Message(actual, "to panic with", matcher.Expected)
+ }
+ }
+
+ // We got a panic, but the value isn't what we expected.
+ switch matcher.Expected.(type) {
+ case omegaMatcher:
+ return format.Message(
+ actual,
+ fmt.Sprintf(
+ "to panic with a value matching\n%s\nbut panicked with\n%s",
+ format.Object(matcher.Expected, 1),
+ format.Object(matcher.object, 1),
+ ),
+ )
+ default:
+ return format.Message(
+ actual,
+ fmt.Sprintf(
+ "to panic with\n%s\nbut panicked with\n%s",
+ format.Object(matcher.Expected, 1),
+ format.Object(matcher.object, 1),
+ ),
+ )
+ }
}
func (matcher *PanicMatcher) NegatedFailureMessage(actual interface{}) (message string) {
- return format.Message(actual, fmt.Sprintf("not to panic, but panicked with\n%s", format.Object(matcher.object, 1)))
+ if matcher.Expected == nil {
+ // We didn't want any panic to occur, but one did.
+ return format.Message(actual, fmt.Sprintf("not to panic, but panicked with\n%s", format.Object(matcher.object, 1)))
+ }
+
+ // We wanted a to ensure a panic with a specific value did not occur, but it did.
+ switch matcher.Expected.(type) {
+ case omegaMatcher:
+ return format.Message(
+ actual,
+ fmt.Sprintf(
+ "not to panic with a value matching\n%s\nbut panicked with\n%s",
+ format.Object(matcher.Expected, 1),
+ format.Object(matcher.object, 1),
+ ),
+ )
+ default:
+ return format.Message(actual, "not to panic with", matcher.Expected)
+ }
}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index da97b24fe..b638d1ad0 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -82,7 +82,7 @@ github.com/containers/buildah/pkg/secrets
github.com/containers/buildah/pkg/supplemented
github.com/containers/buildah/pkg/umask
github.com/containers/buildah/util
-# github.com/containers/common v0.11.0
+# github.com/containers/common v0.11.1
github.com/containers/common/pkg/apparmor
github.com/containers/common/pkg/auth
github.com/containers/common/pkg/capabilities
@@ -375,7 +375,7 @@ github.com/onsi/ginkgo/reporters/stenographer
github.com/onsi/ginkgo/reporters/stenographer/support/go-colorable
github.com/onsi/ginkgo/reporters/stenographer/support/go-isatty
github.com/onsi/ginkgo/types
-# github.com/onsi/gomega v1.9.0
+# github.com/onsi/gomega v1.10.0
github.com/onsi/gomega
github.com/onsi/gomega/format
github.com/onsi/gomega/gbytes