summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/podman/common/volumes.go29
-rw-r--r--cmd/podman/containers/exec.go4
-rw-r--r--go.mod6
-rw-r--r--go.sum10
-rw-r--r--pkg/api/handlers/compat/resize.go4
-rw-r--r--pkg/api/server/register_exec.go2
-rw-r--r--pkg/bindings/connection.go60
-rw-r--r--pkg/bindings/containers/attach.go481
-rw-r--r--pkg/bindings/containers/containers.go253
-rw-r--r--pkg/domain/infra/tunnel/containers.go36
-rw-r--r--test/e2e/exec_test.go2
-rw-r--r--troubleshooting.md39
-rw-r--r--vendor/github.com/onsi/ginkgo/CHANGELOG.md5
-rw-r--r--vendor/github.com/onsi/ginkgo/README.md18
-rw-r--r--vendor/github.com/onsi/ginkgo/config/config.go2
-rw-r--r--vendor/github.com/onsi/ginkgo/extensions/table/table.go37
-rw-r--r--vendor/github.com/onsi/ginkgo/extensions/table/table_entry.go33
-rw-r--r--vendor/github.com/onsi/ginkgo/ginkgo_dsl.go85
-rw-r--r--vendor/github.com/onsi/ginkgo/internal/global/init.go18
-rw-r--r--vendor/github.com/opencontainers/runc/libcontainer/cgroups/cgroups.go10
-rw-r--r--vendor/github.com/opencontainers/runc/libcontainer/cgroups/utils.go29
-rw-r--r--vendor/modules.txt7
22 files changed, 755 insertions, 415 deletions
diff --git a/cmd/podman/common/volumes.go b/cmd/podman/common/volumes.go
index a70410ad3..63bb8e5f0 100644
--- a/cmd/podman/common/volumes.go
+++ b/cmd/podman/common/volumes.go
@@ -209,36 +209,21 @@ func getBindMount(args []string) (spec.Mount, error) {
switch kv[0] {
case "bind-nonrecursive":
newMount.Options = append(newMount.Options, "bind")
- case "readonly", "read-only":
- if setRORW {
- return newMount, errors.Wrapf(optionArgError, "cannot pass 'readonly', 'ro', or 'rw' options more than once")
- }
- setRORW = true
- switch len(kv) {
- case 1:
- newMount.Options = append(newMount.Options, "ro")
- case 2:
- switch strings.ToLower(kv[1]) {
- case "true":
- newMount.Options = append(newMount.Options, "ro")
- case "false":
- // RW is default, so do nothing
- default:
- return newMount, errors.Wrapf(optionArgError, "readonly must be set to true or false, instead received %q", kv[1])
- }
- default:
- return newMount, errors.Wrapf(optionArgError, "badly formatted option %q", val)
- }
- case "ro", "rw":
+ case "readonly", "ro", "rw":
if setRORW {
return newMount, errors.Wrapf(optionArgError, "cannot pass 'readonly', 'ro', or 'rw' options more than once")
}
setRORW = true
// Can be formatted as one of:
+ // readonly
+ // readonly=[true|false]
// ro
// ro=[true|false]
// rw
// rw=[true|false]
+ if kv[0] == "readonly" {
+ kv[0] = "ro"
+ }
switch len(kv) {
case 1:
newMount.Options = append(newMount.Options, kv[0])
@@ -253,7 +238,7 @@ func getBindMount(args []string) (spec.Mount, error) {
newMount.Options = append(newMount.Options, "ro")
}
default:
- return newMount, errors.Wrapf(optionArgError, "%s must be set to true or false, instead received %q", kv[0], kv[1])
+ return newMount, errors.Wrapf(optionArgError, "'readonly', 'ro', or 'rw' must be set to true or false, instead received %q", kv[1])
}
default:
return newMount, errors.Wrapf(optionArgError, "badly formatted option %q", val)
diff --git a/cmd/podman/containers/exec.go b/cmd/podman/containers/exec.go
index 7554d6a93..41f100768 100644
--- a/cmd/podman/containers/exec.go
+++ b/cmd/podman/containers/exec.go
@@ -67,14 +67,14 @@ func execFlags(flags *pflag.FlagSet) {
func init() {
registry.Commands = append(registry.Commands, registry.CliCommand{
- Mode: []entities.EngineMode{entities.ABIMode},
+ Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
Command: execCommand,
})
flags := execCommand.Flags()
execFlags(flags)
registry.Commands = append(registry.Commands, registry.CliCommand{
- Mode: []entities.EngineMode{entities.ABIMode},
+ Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
Command: containerExecCommand,
Parent: containerCmd,
})
diff --git a/go.mod b/go.mod
index 5a7ffae94..617f118f1 100644
--- a/go.mod
+++ b/go.mod
@@ -16,7 +16,7 @@ require (
github.com/containers/image/v5 v5.4.5-0.20200529084758-46b2ee6aebb0
github.com/containers/psgo v1.5.1
github.com/containers/storage v1.20.1
- github.com/coreos/go-systemd/v22 v22.0.0
+ github.com/coreos/go-systemd/v22 v22.1.0
github.com/cri-o/ocicni v0.2.0
github.com/cyphar/filepath-securejoin v0.2.2
github.com/davecgh/go-spew v1.1.1
@@ -35,11 +35,11 @@ require (
github.com/hpcloud/tail v1.0.0
github.com/json-iterator/go v1.1.9
github.com/mrunalp/fileutils v0.0.0-20171103030105-7d4729fb3618
- github.com/onsi/ginkgo v1.12.2
+ github.com/onsi/ginkgo v1.12.3
github.com/onsi/gomega v1.10.1
github.com/opencontainers/go-digest v1.0.0
github.com/opencontainers/image-spec v1.0.2-0.20190823105129-775207bd45b6
- github.com/opencontainers/runc v1.0.0-rc9
+ github.com/opencontainers/runc v1.0.0-rc90
github.com/opencontainers/runtime-spec v1.0.3-0.20200520003142-237cc4f519e2
github.com/opencontainers/runtime-tools v0.9.0
github.com/opencontainers/selinux v1.5.2
diff --git a/go.sum b/go.sum
index ba4414b28..38fdfe902 100644
--- a/go.sum
+++ b/go.sum
@@ -47,6 +47,7 @@ github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd h1:qMd81Ts1T
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f h1:tSNMc+rJDfmYntojat8lljbt1mgKNpTxUZJsSzJ9Y1s=
github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko=
+github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1 h1:uict5mhHFTzKLUCufdSLym7z/J0CbBJT59lYbP9wtbg=
github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw=
github.com/containerd/containerd v1.2.10/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
github.com/containerd/containerd v1.3.0-beta.2.0.20190828155532-0293cbd26c69/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
@@ -96,8 +97,8 @@ github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9/ZjdUKyjop4mf3Qdd+1TvvltAvM3m8=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
-github.com/coreos/go-systemd/v22 v22.0.0 h1:XJIw/+VlJ+87J+doOxznsAWIdmWuViOVhkQamW5YV28=
-github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
+github.com/coreos/go-systemd/v22 v22.1.0 h1:kq/SbG2BCKLkDKkjQf5OWwKWUKj1lgs3lFI4PxnR5lg=
+github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
@@ -315,6 +316,8 @@ github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.12.2 h1:Ke9m3h2Hu0wsZ45yewCqhYr3Z+emcNTuLY2nMWCkrSI=
github.com/onsi/ginkgo v1.12.2/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
+github.com/onsi/ginkgo v1.12.3 h1:+RYp9QczoWz9zfUyLP/5SLXQVhfr6gZOoKGfQqHuLZQ=
+github.com/onsi/ginkgo v1.12.3/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v0.0.0-20190113212917-5533ce8a0da3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
@@ -336,6 +339,8 @@ github.com/opencontainers/runc v0.0.0-20190425234816-dae70e8efea4/go.mod h1:qT5X
github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
github.com/opencontainers/runc v1.0.0-rc9 h1:/k06BMULKF5hidyoZymkoDCzdJzltZpz/UU4LguQVtc=
github.com/opencontainers/runc v1.0.0-rc9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
+github.com/opencontainers/runc v1.0.0-rc90 h1:4+xo8mtWixbHoEm451+WJNUrq12o2/tDsyK9Vgc/NcA=
+github.com/opencontainers/runc v1.0.0-rc90/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/runtime-spec v0.1.2-0.20190618234442-a950415649c7/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/runtime-spec v1.0.3-0.20200520003142-237cc4f519e2 h1:9mv9SC7GWmRWE0J/+oD8w3GsN2KYGKtg6uwLN7hfP5E=
@@ -448,6 +453,7 @@ github.com/uber/jaeger-lib v2.2.0+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
github.com/ulikunitz/xz v0.5.7 h1:YvTNdFzX6+W5m9msiYg/zpkSURPPtOlzbqYjrFn7Yt4=
github.com/ulikunitz/xz v0.5.7/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
+github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5 h1:MCfT24H3f//U5+UCrZp1/riVO3B50BovxtDiNn0XKkk=
github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=
github.com/varlink/go v0.0.0-20190502142041-0f1d566d194b h1:hdDRrn9OP/roL8a/e/5Zu85ldrcdndu9IeBj2OEvQm0=
diff --git a/pkg/api/handlers/compat/resize.go b/pkg/api/handlers/compat/resize.go
index 231b53175..478a8fab4 100644
--- a/pkg/api/handlers/compat/resize.go
+++ b/pkg/api/handlers/compat/resize.go
@@ -8,6 +8,7 @@ import (
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/pkg/api/handlers/utils"
+ "github.com/gorilla/mux"
"github.com/gorilla/schema"
"github.com/pkg/errors"
"k8s.io/client-go/tools/remotecommand"
@@ -37,9 +38,9 @@ func ResizeTTY(w http.ResponseWriter, r *http.Request) {
}
var status int
- name := utils.GetName(r)
switch {
case strings.Contains(r.URL.Path, "/containers/"):
+ name := utils.GetName(r)
ctnr, err := runtime.LookupContainer(name)
if err != nil {
utils.ContainerNotFound(w, name, err)
@@ -61,6 +62,7 @@ func ResizeTTY(w http.ResponseWriter, r *http.Request) {
// reasons.
status = http.StatusOK
case strings.Contains(r.URL.Path, "/exec/"):
+ name := mux.Vars(r)["id"]
ctnr, err := runtime.GetExecSessionContainer(name)
if err != nil {
utils.SessionNotFound(w, name, err)
diff --git a/pkg/api/server/register_exec.go b/pkg/api/server/register_exec.go
index 1533edba9..17181d286 100644
--- a/pkg/api/server/register_exec.go
+++ b/pkg/api/server/register_exec.go
@@ -310,7 +310,7 @@ func (s *APIServer) registerExecHandlers(r *mux.Router) error {
// $ref: "#/responses/NoSuchExecInstance"
// 500:
// $ref: "#/responses/InternalError"
- r.Handle(VersionedPath("/libpod/exec/{id}/resize"), s.APIHandler(compat.UnsupportedHandler)).Methods(http.MethodPost)
+ r.Handle(VersionedPath("/libpod/exec/{id}/resize"), s.APIHandler(compat.ResizeTTY)).Methods(http.MethodPost)
// swagger:operation GET /libpod/exec/{id}/json libpod libpodInspectExec
// ---
// tags:
diff --git a/pkg/bindings/connection.go b/pkg/bindings/connection.go
index e9032f083..c26093a7f 100644
--- a/pkg/bindings/connection.go
+++ b/pkg/bindings/connection.go
@@ -24,7 +24,7 @@ import (
)
var (
- basePath = &url.URL{
+ BasePath = &url.URL{
Scheme: "http",
Host: "d",
Path: "/v" + APIVersion.String() + "/libpod",
@@ -37,15 +37,14 @@ type APIResponse struct {
}
type Connection struct {
- _url *url.URL
- client *http.Client
- conn *net.Conn
+ Uri *url.URL
+ Client *http.Client
}
type valueKey string
const (
- clientKey = valueKey("client")
+ clientKey = valueKey("Client")
)
// GetClient from context build by NewConnection()
@@ -59,7 +58,7 @@ func GetClient(ctx context.Context) (*Connection, error) {
// JoinURL elements with '/'
func JoinURL(elements ...string) string {
- return strings.Join(elements, "/")
+ return "/" + strings.Join(elements, "/")
}
// NewConnection takes a URI as a string and returns a context with the
@@ -88,7 +87,7 @@ func NewConnection(ctx context.Context, uri string, identity ...string) (context
return nil, errors.Wrapf(err, "Value of PODMAN_HOST is not a valid url: %s", uri)
}
- // Now we setup the http client to use the connection above
+ // Now we setup the http Client to use the connection above
var connection Connection
switch _url.Scheme {
case "ssh":
@@ -125,16 +124,12 @@ func NewConnection(ctx context.Context, uri string, identity ...string) (context
func tcpClient(_url *url.URL) (Connection, error) {
connection := Connection{
- _url: _url,
+ Uri: _url,
}
- connection.client = &http.Client{
+ connection.Client = &http.Client{
Transport: &http.Transport{
DialContext: func(ctx context.Context, _, _ string) (net.Conn, error) {
- conn, err := net.Dial("tcp", _url.Host)
- if c, ok := ctx.Value(clientKey).(*Connection); ok {
- c.conn = &conn
- }
- return conn, err
+ return net.Dial("tcp", _url.Host)
},
DisableCompression: true,
},
@@ -167,11 +162,11 @@ func pingNewConnection(ctx context.Context) error {
}
switch APIVersion.Compare(versionSrv) {
- case 1, 0:
- // Server's job when client version is equal or older
+ case -1, 0:
+ // Server's job when Client version is equal or older
return nil
- case -1:
- return errors.Errorf("server API version is too old. client %q server %q", APIVersion.String(), versionSrv.String())
+ case 1:
+ return errors.Errorf("server API version is too old. Client %q server %q", APIVersion.String(), versionSrv.String())
}
}
return errors.Errorf("ping response was %q", response.StatusCode)
@@ -217,31 +212,22 @@ func sshClient(_url *url.URL, identity string, secure bool) (Connection, error)
return Connection{}, errors.Wrapf(err, "Connection to bastion host (%s) failed.", _url.String())
}
- connection := Connection{_url: _url}
- connection.client = &http.Client{
+ connection := Connection{Uri: _url}
+ connection.Client = &http.Client{
Transport: &http.Transport{
DialContext: func(ctx context.Context, _, _ string) (net.Conn, error) {
- conn, err := bastion.Dial("unix", _url.Path)
- if c, ok := ctx.Value(clientKey).(*Connection); ok {
- c.conn = &conn
- }
- return conn, err
+ return bastion.Dial("unix", _url.Path)
},
}}
return connection, nil
}
func unixClient(_url *url.URL) (Connection, error) {
- connection := Connection{_url: _url}
- connection.client = &http.Client{
+ connection := Connection{Uri: _url}
+ connection.Client = &http.Client{
Transport: &http.Transport{
DialContext: func(ctx context.Context, _, _ string) (net.Conn, error) {
- d := net.Dialer{}
- conn, err := d.DialContext(ctx, "unix", _url.Path)
- if c, ok := ctx.Value(clientKey).(*Connection); ok {
- c.conn = &conn
- }
- return conn, err
+ return (&net.Dialer{}).DialContext(ctx, "unix", _url.Path)
},
DisableCompression: true,
},
@@ -263,7 +249,7 @@ func (c *Connection) DoRequest(httpBody io.Reader, httpMethod, endpoint string,
// Lets eventually use URL for this which might lead to safer
// usage
safeEndpoint := fmt.Sprintf(endpoint, safePathValues...)
- e := basePath.String() + safeEndpoint
+ e := BasePath.String() + safeEndpoint
req, err := http.NewRequest(httpMethod, e, httpBody)
if err != nil {
return nil, err
@@ -277,7 +263,7 @@ func (c *Connection) DoRequest(httpBody io.Reader, httpMethod, endpoint string,
req = req.WithContext(context.WithValue(context.Background(), clientKey, c))
// Give the Do three chances in the case of a comm/service hiccup
for i := 0; i < 3; i++ {
- response, err = c.client.Do(req) // nolint
+ response, err = c.Client.Do(req) // nolint
if err == nil {
break
}
@@ -286,10 +272,6 @@ func (c *Connection) DoRequest(httpBody io.Reader, httpMethod, endpoint string,
return &APIResponse{response, req}, err
}
-func (c *Connection) Write(b []byte) (int, error) {
- return (*c.conn).Write(b)
-}
-
// FiltersToString converts our typical filter format of a
// map[string][]string to a query/html safe string.
func FiltersToString(filters map[string][]string) (string, error) {
diff --git a/pkg/bindings/containers/attach.go b/pkg/bindings/containers/attach.go
new file mode 100644
index 000000000..b7f35c30d
--- /dev/null
+++ b/pkg/bindings/containers/attach.go
@@ -0,0 +1,481 @@
+package containers
+
+import (
+ "bytes"
+ "context"
+ "encoding/binary"
+ "fmt"
+ "io"
+ "net"
+ "net/http"
+ "net/url"
+ "os"
+ "os/signal"
+ "reflect"
+ "strconv"
+ "time"
+
+ "github.com/containers/libpod/libpod/define"
+ "github.com/containers/libpod/pkg/bindings"
+ sig "github.com/containers/libpod/pkg/signal"
+ "github.com/containers/libpod/utils"
+ "github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
+ "golang.org/x/crypto/ssh/terminal"
+)
+
+// Attach attaches to a running container
+func Attach(ctx context.Context, nameOrId string, detachKeys *string, logs, stream *bool, stdin io.Reader, stdout io.Writer, stderr io.Writer, attachReady chan bool) error {
+ isSet := struct {
+ stdin bool
+ stdout bool
+ stderr bool
+ }{
+ stdin: !(stdin == nil || reflect.ValueOf(stdin).IsNil()),
+ stdout: !(stdout == nil || reflect.ValueOf(stdout).IsNil()),
+ stderr: !(stderr == nil || reflect.ValueOf(stderr).IsNil()),
+ }
+ // Ensure golang can determine that interfaces are "really" nil
+ if !isSet.stdin {
+ stdin = (io.Reader)(nil)
+ }
+ if !isSet.stdout {
+ stdout = (io.Writer)(nil)
+ }
+ if !isSet.stderr {
+ stderr = (io.Writer)(nil)
+ }
+
+ conn, err := bindings.GetClient(ctx)
+ if err != nil {
+ return err
+ }
+
+ // Do we need to wire in stdin?
+ ctnr, err := Inspect(ctx, nameOrId, bindings.PFalse)
+ if err != nil {
+ return err
+ }
+
+ params := url.Values{}
+ if detachKeys != nil {
+ params.Add("detachKeys", *detachKeys)
+ }
+ if logs != nil {
+ params.Add("logs", fmt.Sprintf("%t", *logs))
+ }
+ if stream != nil {
+ params.Add("stream", fmt.Sprintf("%t", *stream))
+ }
+ if isSet.stdin {
+ params.Add("stdin", "true")
+ }
+ if isSet.stdout {
+ params.Add("stdout", "true")
+ }
+ if isSet.stderr {
+ params.Add("stderr", "true")
+ }
+
+ // Unless all requirements are met, don't use "stdin" is a terminal
+ file, ok := stdin.(*os.File)
+ needTTY := ok && terminal.IsTerminal(int(file.Fd())) && ctnr.Config.Tty
+ if needTTY {
+ state, err := setRawTerminal(file)
+ if err != nil {
+ return err
+ }
+ defer func() {
+ if err := terminal.Restore(int(file.Fd()), state); err != nil {
+ logrus.Errorf("unable to restore terminal: %q", err)
+ }
+ logrus.SetFormatter(&logrus.TextFormatter{})
+ }()
+ }
+
+ headers := make(map[string]string)
+ headers["Connection"] = "Upgrade"
+ headers["Upgrade"] = "tcp"
+
+ var socket net.Conn
+ socketSet := false
+ dialContext := conn.Client.Transport.(*http.Transport).DialContext
+ t := &http.Transport{
+ DialContext: func(ctx context.Context, network, address string) (net.Conn, error) {
+ c, err := dialContext(ctx, network, address)
+ if err != nil {
+ return nil, err
+ }
+ if !socketSet {
+ socket = c
+ socketSet = true
+ }
+ return c, err
+ },
+ IdleConnTimeout: time.Duration(0),
+ }
+ conn.Client.Transport = t
+ response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/attach", params, headers, nameOrId)
+ if err != nil {
+ return err
+ }
+ if !(response.IsSuccess() || response.IsInformational()) {
+ return response.Process(nil)
+ }
+
+ if needTTY {
+ winChange := make(chan os.Signal, 1)
+ signal.Notify(winChange, sig.SIGWINCH)
+ winCtx, winCancel := context.WithCancel(ctx)
+ defer winCancel()
+
+ go attachHandleResize(ctx, winCtx, winChange, false, nameOrId, file)
+ }
+
+ // If we are attaching around a start, we need to "signal"
+ // back that we are in fact attached so that started does
+ // not execute before we can attach.
+ if attachReady != nil {
+ attachReady <- true
+ }
+
+ if isSet.stdin {
+ go func() {
+ logrus.Debugf("Copying STDIN to socket")
+ _, err := utils.CopyDetachable(socket, stdin, []byte{})
+ if err != nil {
+ logrus.Error("failed to write input to service: " + err.Error())
+ }
+ }()
+ }
+
+ buffer := make([]byte, 1024)
+ if ctnr.Config.Tty {
+ logrus.Debugf("Copying STDOUT of container in terminal mode")
+
+ if !isSet.stdout {
+ return fmt.Errorf("container %q requires stdout to be set", ctnr.ID)
+ }
+ // If not multiplex'ed, read from server and write to stdout
+ _, err := io.Copy(stdout, socket)
+ if err != nil {
+ return err
+ }
+ } else {
+ logrus.Debugf("Copying standard streams of container in non-terminal mode")
+ for {
+ // Read multiplexed channels and write to appropriate stream
+ fd, l, err := DemuxHeader(socket, buffer)
+ if err != nil {
+ if errors.Is(err, io.EOF) {
+ return nil
+ }
+ return err
+ }
+ frame, err := DemuxFrame(socket, buffer, l)
+ if err != nil {
+ return err
+ }
+
+ switch {
+ case fd == 0 && isSet.stdout:
+ _, err := stdout.Write(frame[0:l])
+ if err != nil {
+ return err
+ }
+ case fd == 1 && isSet.stdout:
+ _, err := stdout.Write(frame[0:l])
+ if err != nil {
+ return err
+ }
+ case fd == 2 && isSet.stderr:
+ _, err := stderr.Write(frame[0:l])
+ if err != nil {
+ return err
+ }
+ case fd == 3:
+ return fmt.Errorf("error from service from stream: %s", frame)
+ default:
+ return fmt.Errorf("unrecognized channel in header: %d, 0-3 supported", fd)
+ }
+ }
+ }
+ return nil
+}
+
+// DemuxHeader reads header for stream from server multiplexed stdin/stdout/stderr/2nd error channel
+func DemuxHeader(r io.Reader, buffer []byte) (fd, sz int, err error) {
+ n, err := io.ReadFull(r, buffer[0:8])
+ if err != nil {
+ return
+ }
+ if n < 8 {
+ err = io.ErrUnexpectedEOF
+ return
+ }
+
+ fd = int(buffer[0])
+ if fd < 0 || fd > 3 {
+ err = errors.Wrapf(ErrLostSync, fmt.Sprintf(`channel "%d" found, 0-3 supported`, fd))
+ return
+ }
+
+ sz = int(binary.BigEndian.Uint32(buffer[4:8]))
+ return
+}
+
+// DemuxFrame reads contents for frame from server multiplexed stdin/stdout/stderr/2nd error channel
+func DemuxFrame(r io.Reader, buffer []byte, length int) (frame []byte, err error) {
+ if len(buffer) < length {
+ buffer = append(buffer, make([]byte, length-len(buffer)+1)...)
+ }
+
+ n, err := io.ReadFull(r, buffer[0:length])
+ if err != nil {
+ return nil, nil
+ }
+ if n < length {
+ err = io.ErrUnexpectedEOF
+ return
+ }
+
+ return buffer[0:length], nil
+}
+
+// ResizeContainerTTY sets container's TTY height and width in characters
+func ResizeContainerTTY(ctx context.Context, nameOrId string, height *int, width *int) error {
+ return resizeTTY(ctx, bindings.JoinURL("containers", nameOrId, "resize"), height, width)
+}
+
+// ResizeExecTTY sets session's TTY height and width in characters
+func ResizeExecTTY(ctx context.Context, nameOrId string, height *int, width *int) error {
+ return resizeTTY(ctx, bindings.JoinURL("exec", nameOrId, "resize"), height, width)
+}
+
+// resizeTTY set size of TTY of container
+func resizeTTY(ctx context.Context, endpoint string, height *int, width *int) error {
+ conn, err := bindings.GetClient(ctx)
+ if err != nil {
+ return err
+ }
+
+ params := url.Values{}
+ if height != nil {
+ params.Set("h", strconv.Itoa(*height))
+ }
+ if width != nil {
+ params.Set("w", strconv.Itoa(*width))
+ }
+ rsp, err := conn.DoRequest(nil, http.MethodPost, endpoint, params, nil)
+ if err != nil {
+ return err
+ }
+ return rsp.Process(nil)
+}
+
+type rawFormatter struct {
+ logrus.TextFormatter
+}
+
+func (f *rawFormatter) Format(entry *logrus.Entry) ([]byte, error) {
+ buffer, err := f.TextFormatter.Format(entry)
+ if err != nil {
+ return buffer, err
+ }
+ return append(buffer, '\r'), nil
+}
+
+// This is intended to be run as a goroutine, handling resizing for a container
+// or exec session.
+func attachHandleResize(ctx, winCtx context.Context, winChange chan os.Signal, isExec bool, id string, file *os.File) {
+ // Prime the pump, we need one reset to ensure everything is ready
+ winChange <- sig.SIGWINCH
+ for {
+ select {
+ case <-winCtx.Done():
+ return
+ case <-winChange:
+ h, w, err := terminal.GetSize(int(file.Fd()))
+ if err != nil {
+ logrus.Warnf("failed to obtain TTY size: " + err.Error())
+ }
+
+ var resizeErr error
+ if isExec {
+ resizeErr = ResizeExecTTY(ctx, id, &h, &w)
+ } else {
+ resizeErr = ResizeContainerTTY(ctx, id, &h, &w)
+ }
+ if resizeErr != nil {
+ logrus.Warnf("failed to resize TTY: " + resizeErr.Error())
+ }
+ }
+ }
+}
+
+// Configure the given terminal for raw mode
+func setRawTerminal(file *os.File) (*terminal.State, error) {
+ state, err := terminal.MakeRaw(int(file.Fd()))
+ if err != nil {
+ return nil, err
+ }
+
+ logrus.SetFormatter(&rawFormatter{})
+
+ return state, err
+}
+
+// ExecStartAndAttach starts and attaches to a given exec session.
+func ExecStartAndAttach(ctx context.Context, sessionID string, streams *define.AttachStreams) error {
+ conn, err := bindings.GetClient(ctx)
+ if err != nil {
+ return err
+ }
+
+ // TODO: Make this configurable (can't use streams' InputStream as it's
+ // buffered)
+ terminalFile := os.Stdin
+
+ logrus.Debugf("Starting & Attaching to exec session ID %q", sessionID)
+
+ // We need to inspect the exec session first to determine whether to use
+ // -t.
+ resp, err := conn.DoRequest(nil, http.MethodGet, "/exec/%s/json", nil, nil, sessionID)
+ if err != nil {
+ return err
+ }
+
+ respStruct := new(define.InspectExecSession)
+ if err := resp.Process(respStruct); err != nil {
+ return err
+ }
+ isTerm := true
+ if respStruct.ProcessConfig != nil {
+ isTerm = respStruct.ProcessConfig.Tty
+ }
+
+ // If we are in TTY mode, we need to set raw mode for the terminal.
+ // TODO: Share all of this with Attach() for containers.
+ needTTY := terminalFile != nil && terminal.IsTerminal(int(terminalFile.Fd())) && isTerm
+ if needTTY {
+ state, err := setRawTerminal(terminalFile)
+ if err != nil {
+ return err
+ }
+ defer func() {
+ if err := terminal.Restore(int(terminalFile.Fd()), state); err != nil {
+ logrus.Errorf("unable to restore terminal: %q", err)
+ }
+ logrus.SetFormatter(&logrus.TextFormatter{})
+ }()
+ }
+
+ body := struct {
+ Detach bool `json:"Detach"`
+ }{
+ Detach: false,
+ }
+ bodyJSON, err := json.Marshal(body)
+ if err != nil {
+ return err
+ }
+
+ var socket net.Conn
+ socketSet := false
+ dialContext := conn.Client.Transport.(*http.Transport).DialContext
+ t := &http.Transport{
+ DialContext: func(ctx context.Context, network, address string) (net.Conn, error) {
+ c, err := dialContext(ctx, network, address)
+ if err != nil {
+ return nil, err
+ }
+ if !socketSet {
+ socket = c
+ socketSet = true
+ }
+ return c, err
+ },
+ IdleConnTimeout: time.Duration(0),
+ }
+ conn.Client.Transport = t
+ response, err := conn.DoRequest(bytes.NewReader(bodyJSON), http.MethodPost, "/exec/%s/start", nil, nil, sessionID)
+ if err != nil {
+ return err
+ }
+ if !(response.IsSuccess() || response.IsInformational()) {
+ return response.Process(nil)
+ }
+
+ if needTTY {
+ winChange := make(chan os.Signal, 1)
+ signal.Notify(winChange, sig.SIGWINCH)
+ winCtx, winCancel := context.WithCancel(ctx)
+ defer winCancel()
+
+ go attachHandleResize(ctx, winCtx, winChange, true, sessionID, terminalFile)
+ }
+
+ if streams.AttachInput {
+ go func() {
+ logrus.Debugf("Copying STDIN to socket")
+ _, err := utils.CopyDetachable(socket, streams.InputStream, []byte{})
+ if err != nil {
+ logrus.Error("failed to write input to service: " + err.Error())
+ }
+ }()
+ }
+
+ buffer := make([]byte, 1024)
+ if isTerm {
+ logrus.Debugf("Handling terminal attach to exec")
+ if !streams.AttachOutput {
+ return fmt.Errorf("exec session %s has a terminal and must have STDOUT enabled", sessionID)
+ }
+ // If not multiplex'ed, read from server and write to stdout
+ _, err := utils.CopyDetachable(streams.OutputStream, socket, []byte{})
+ if err != nil {
+ return err
+ }
+ } else {
+ logrus.Debugf("Handling non-terminal attach to exec")
+ for {
+ // Read multiplexed channels and write to appropriate stream
+ fd, l, err := DemuxHeader(socket, buffer)
+ if err != nil {
+ if errors.Is(err, io.EOF) {
+ return nil
+ }
+ return err
+ }
+ frame, err := DemuxFrame(socket, buffer, l)
+ if err != nil {
+ return err
+ }
+
+ switch {
+ case fd == 0 && streams.AttachOutput:
+ _, err := streams.OutputStream.Write(frame[0:l])
+ if err != nil {
+ return err
+ }
+ case fd == 1 && streams.AttachInput:
+ // Write STDIN to STDOUT (echoing characters
+ // typed by another attach session)
+ _, err := streams.OutputStream.Write(frame[0:l])
+ if err != nil {
+ return err
+ }
+ case fd == 2 && streams.AttachError:
+ _, err := streams.ErrorStream.Write(frame[0:l])
+ if err != nil {
+ return err
+ }
+ case fd == 3:
+ return fmt.Errorf("error from service from stream: %s", frame)
+ default:
+ return fmt.Errorf("unrecognized channel in header: %d, 0-3 supported", fd)
+ }
+ }
+ }
+ return nil
+}
diff --git a/pkg/bindings/containers/containers.go b/pkg/bindings/containers/containers.go
index 516f3d282..929b6bbd5 100644
--- a/pkg/bindings/containers/containers.go
+++ b/pkg/bindings/containers/containers.go
@@ -2,14 +2,9 @@ package containers
import (
"context"
- "encoding/binary"
- "fmt"
"io"
"net/http"
"net/url"
- "os"
- "os/signal"
- "reflect"
"strconv"
"strings"
@@ -17,10 +12,7 @@ import (
"github.com/containers/libpod/pkg/api/handlers"
"github.com/containers/libpod/pkg/bindings"
"github.com/containers/libpod/pkg/domain/entities"
- sig "github.com/containers/libpod/pkg/signal"
"github.com/pkg/errors"
- "github.com/sirupsen/logrus"
- "golang.org/x/crypto/ssh/terminal"
)
var (
@@ -345,248 +337,3 @@ func ContainerInit(ctx context.Context, nameOrID string) error {
}
return response.Process(nil)
}
-
-// Attach attaches to a running container
-func Attach(ctx context.Context, nameOrId string, detachKeys *string, logs, stream *bool, stdin io.Reader, stdout io.Writer, stderr io.Writer, attachReady chan bool) error {
- isSet := struct {
- stdin bool
- stdout bool
- stderr bool
- }{
- stdin: !(stdin == nil || reflect.ValueOf(stdin).IsNil()),
- stdout: !(stdout == nil || reflect.ValueOf(stdout).IsNil()),
- stderr: !(stderr == nil || reflect.ValueOf(stderr).IsNil()),
- }
- // Ensure golang can determine that interfaces are "really" nil
- if !isSet.stdin {
- stdin = (io.Reader)(nil)
- }
- if !isSet.stdout {
- stdout = (io.Writer)(nil)
- }
- if !isSet.stderr {
- stderr = (io.Writer)(nil)
- }
-
- conn, err := bindings.GetClient(ctx)
- if err != nil {
- return err
- }
-
- // Do we need to wire in stdin?
- ctnr, err := Inspect(ctx, nameOrId, bindings.PFalse)
- if err != nil {
- return err
- }
-
- params := url.Values{}
- if detachKeys != nil {
- params.Add("detachKeys", *detachKeys)
- }
- if logs != nil {
- params.Add("logs", fmt.Sprintf("%t", *logs))
- }
- if stream != nil {
- params.Add("stream", fmt.Sprintf("%t", *stream))
- }
- if isSet.stdin {
- params.Add("stdin", "true")
- }
- if isSet.stdout {
- params.Add("stdout", "true")
- }
- if isSet.stderr {
- params.Add("stderr", "true")
- }
-
- // Unless all requirements are met, don't use "stdin" is a terminal
- file, ok := stdin.(*os.File)
- needTTY := ok && terminal.IsTerminal(int(file.Fd())) && ctnr.Config.Tty
- if needTTY {
- state, err := terminal.MakeRaw(int(file.Fd()))
- if err != nil {
- return err
- }
-
- logrus.SetFormatter(&rawFormatter{})
-
- defer func() {
- if err := terminal.Restore(int(file.Fd()), state); err != nil {
- logrus.Errorf("unable to restore terminal: %q", err)
- }
- logrus.SetFormatter(&logrus.TextFormatter{})
- }()
-
- winChange := make(chan os.Signal, 1)
- signal.Notify(winChange, sig.SIGWINCH)
- winCtx, winCancel := context.WithCancel(ctx)
- defer winCancel()
-
- go func() {
- // Prime the pump, we need one reset to ensure everything is ready
- winChange <- sig.SIGWINCH
- for {
- select {
- case <-winCtx.Done():
- return
- case <-winChange:
- h, w, err := terminal.GetSize(int(file.Fd()))
- if err != nil {
- logrus.Warnf("failed to obtain TTY size: " + err.Error())
- }
-
- if err := ResizeContainerTTY(ctx, nameOrId, &h, &w); err != nil {
- logrus.Warnf("failed to resize TTY: " + err.Error())
- }
- }
- }
- }()
- }
-
- response, err := conn.DoRequest(stdin, http.MethodPost, "/containers/%s/attach", params, nil, nameOrId)
- if err != nil {
- return err
- }
- if !(response.IsSuccess() || response.IsInformational()) {
- return response.Process(nil)
- }
-
- // If we are attaching around a start, we need to "signal"
- // back that we are in fact attached so that started does
- // not execute before we can attach.
- if attachReady != nil {
- attachReady <- true
- }
-
- buffer := make([]byte, 1024)
- if ctnr.Config.Tty {
- if !isSet.stdout {
- return fmt.Errorf("container %q requires stdout to be set", ctnr.ID)
- }
- // If not multiplex'ed, read from server and write to stdout
- _, err := io.Copy(stdout, response.Body)
- if err != nil {
- return err
- }
- } else {
- for {
- // Read multiplexed channels and write to appropriate stream
- fd, l, err := DemuxHeader(response.Body, buffer)
- if err != nil {
- if errors.Is(err, io.EOF) {
- return nil
- }
- return err
- }
- frame, err := DemuxFrame(response.Body, buffer, l)
- if err != nil {
- return err
- }
-
- switch {
- case fd == 0 && isSet.stdout:
- _, err := stdout.Write(frame[0:l])
- if err != nil {
- return err
- }
- case fd == 1 && isSet.stdout:
- _, err := stdout.Write(frame[0:l])
- if err != nil {
- return err
- }
- case fd == 2 && isSet.stderr:
- _, err := stderr.Write(frame[0:l])
- if err != nil {
- return err
- }
- case fd == 3:
- return fmt.Errorf("error from service from stream: %s", frame)
- default:
- return fmt.Errorf("unrecognized channel in header: %d, 0-3 supported", fd)
- }
- }
- }
- return nil
-}
-
-// DemuxHeader reads header for stream from server multiplexed stdin/stdout/stderr/2nd error channel
-func DemuxHeader(r io.Reader, buffer []byte) (fd, sz int, err error) {
- n, err := io.ReadFull(r, buffer[0:8])
- if err != nil {
- return
- }
- if n < 8 {
- err = io.ErrUnexpectedEOF
- return
- }
-
- fd = int(buffer[0])
- if fd < 0 || fd > 3 {
- err = errors.Wrapf(ErrLostSync, fmt.Sprintf(`channel "%d" found, 0-3 supported`, fd))
- return
- }
-
- sz = int(binary.BigEndian.Uint32(buffer[4:8]))
- return
-}
-
-// DemuxFrame reads contents for frame from server multiplexed stdin/stdout/stderr/2nd error channel
-func DemuxFrame(r io.Reader, buffer []byte, length int) (frame []byte, err error) {
- if len(buffer) < length {
- buffer = append(buffer, make([]byte, length-len(buffer)+1)...)
- }
-
- n, err := io.ReadFull(r, buffer[0:length])
- if err != nil {
- return nil, nil
- }
- if n < length {
- err = io.ErrUnexpectedEOF
- return
- }
-
- return buffer[0:length], nil
-}
-
-// ResizeContainerTTY sets container's TTY height and width in characters
-func ResizeContainerTTY(ctx context.Context, nameOrId string, height *int, width *int) error {
- return resizeTTY(ctx, bindings.JoinURL("containers", nameOrId, "resize"), height, width)
-}
-
-// ResizeExecTTY sets session's TTY height and width in characters
-func ResizeExecTTY(ctx context.Context, nameOrId string, height *int, width *int) error {
- return resizeTTY(ctx, bindings.JoinURL("exec", nameOrId, "resize"), height, width)
-}
-
-// resizeTTY set size of TTY of container
-func resizeTTY(ctx context.Context, endpoint string, height *int, width *int) error {
- conn, err := bindings.GetClient(ctx)
- if err != nil {
- return err
- }
-
- params := url.Values{}
- if height != nil {
- params.Set("h", strconv.Itoa(*height))
- }
- if width != nil {
- params.Set("w", strconv.Itoa(*width))
- }
- rsp, err := conn.DoRequest(nil, http.MethodPost, endpoint, params, nil)
- if err != nil {
- return err
- }
- return rsp.Process(nil)
-}
-
-type rawFormatter struct {
- logrus.TextFormatter
-}
-
-func (f *rawFormatter) Format(entry *logrus.Entry) ([]byte, error) {
- buffer, err := f.TextFormatter.Format(entry)
- if err != nil {
- return buffer, err
- }
- return append(buffer, '\r'), nil
-}
diff --git a/pkg/domain/infra/tunnel/containers.go b/pkg/domain/infra/tunnel/containers.go
index beba55c2b..e1c859e7c 100644
--- a/pkg/domain/infra/tunnel/containers.go
+++ b/pkg/domain/infra/tunnel/containers.go
@@ -2,6 +2,7 @@ package tunnel
import (
"context"
+ "fmt"
"io"
"os"
"strconv"
@@ -11,6 +12,7 @@ import (
"github.com/containers/common/pkg/config"
"github.com/containers/image/v5/docker/reference"
"github.com/containers/libpod/libpod/define"
+ "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/domain/entities"
@@ -375,7 +377,39 @@ func (ic *ContainerEngine) ContainerAttach(ctx context.Context, nameOrId string,
}
func (ic *ContainerEngine) ContainerExec(ctx context.Context, nameOrId string, options entities.ExecOptions, streams define.AttachStreams) (int, error) {
- return 125, errors.New("not implemented")
+ env := []string{}
+ for k, v := range options.Envs {
+ env = append(env, fmt.Sprintf("%s=%s", k, v))
+ }
+
+ createConfig := new(handlers.ExecCreateConfig)
+ createConfig.User = options.User
+ createConfig.Privileged = options.Privileged
+ createConfig.Tty = options.Tty
+ createConfig.AttachStdin = options.Interactive
+ createConfig.AttachStdout = true
+ createConfig.AttachStderr = true
+ createConfig.Detach = false
+ createConfig.DetachKeys = options.DetachKeys
+ createConfig.Env = env
+ createConfig.WorkingDir = options.WorkDir
+ createConfig.Cmd = options.Cmd
+
+ sessionID, err := containers.ExecCreate(ic.ClientCxt, nameOrId, createConfig)
+ if err != nil {
+ return 125, err
+ }
+
+ if err := containers.ExecStartAndAttach(ic.ClientCxt, sessionID, &streams); err != nil {
+ return 125, err
+ }
+
+ inspectOut, err := containers.ExecInspect(ic.ClientCxt, sessionID)
+ if err != nil {
+ return 125, err
+ }
+
+ return inspectOut.ExitCode, nil
}
func (ic *ContainerEngine) ContainerExecDetached(ctx context.Context, nameOrID string, options entities.ExecOptions) (string, error) {
diff --git a/test/e2e/exec_test.go b/test/e2e/exec_test.go
index 87dddb233..8ec666c2b 100644
--- a/test/e2e/exec_test.go
+++ b/test/e2e/exec_test.go
@@ -18,7 +18,6 @@ var _ = Describe("Podman exec", func() {
)
BeforeEach(func() {
- Skip(v2remotefail)
tempdir, err = CreateTempDirInTempDir()
if err != nil {
os.Exit(1)
@@ -285,6 +284,7 @@ var _ = Describe("Podman exec", func() {
})
It("podman exec --detach", func() {
+ Skip(v2remotefail)
ctrName := "testctr"
ctr := podmanTest.Podman([]string{"run", "-t", "-i", "-d", "--name", ctrName, ALPINE, "top"})
ctr.WaitWithDefaultTimeout()
diff --git a/troubleshooting.md b/troubleshooting.md
index 167ee14c3..bad9d8102 100644
--- a/troubleshooting.md
+++ b/troubleshooting.md
@@ -553,3 +553,42 @@ this, use the following command before logging out: `loginctl enable-linger`.
To later revert the linger functionality, use `loginctl disable-linger`.
LOGINCTL(1), SYSTEMD(1)
+
+### 23) Containers default detach keys conflict with shell history navigation
+
+Podman defaults to `ctrl-p,ctrl-q` to detach from a running containers. The
+bash and zsh shells default to ctrl-p for the displaying of the previous
+command. This causes issues when running a shell inside of a container.
+
+#### Symptom
+
+With the default detach key combo ctrl-p,ctrl-q, shell history navigation
+(tested in bash and zsh) using ctrl-p to access the previous command will not
+display this previous command. Or anything else. Conmon is waiting for an
+additional character to see if the user wants to detach from the container.
+Adding additional characters to the command will cause it to be displayed along
+with the additonal character. If the user types ctrl-p a second time the shell
+display the 2nd to last command.
+
+#### Solution
+
+The solution to this is to change the default detach_keys. For example in order
+to change the defaults to `ctrl-q,ctrl-q` use the `--detach-keys` option.
+
+```
+podman run -ti --detach-keys ctrl-q,ctrl-q fedora sh
+```
+
+To make this change the default for all containers, users can modify the
+containers.conf file. This can be done simply in your homedir, but adding the
+following lines to users containers.conf
+
+```
+$ cat >> ~/.config/containers/containers.conf < _eof
+[engine]
+detach_keys="ctrl-q,ctrl-q"
+_eof
+```
+
+In order to effect root running containers and all users, modify the system
+wide defaults in /etc/containers/containers.conf
diff --git a/vendor/github.com/onsi/ginkgo/CHANGELOG.md b/vendor/github.com/onsi/ginkgo/CHANGELOG.md
index 52d8ca36d..395fa90f4 100644
--- a/vendor/github.com/onsi/ginkgo/CHANGELOG.md
+++ b/vendor/github.com/onsi/ginkgo/CHANGELOG.md
@@ -1,3 +1,8 @@
+## 1.12.3
+
+### Fixes
+- Print correct code location of failing table test (#666) [c6d7afb]
+
## 1.12.2
### Fixes
diff --git a/vendor/github.com/onsi/ginkgo/README.md b/vendor/github.com/onsi/ginkgo/README.md
index 2fda7b9eb..ddb0cd882 100644
--- a/vendor/github.com/onsi/ginkgo/README.md
+++ b/vendor/github.com/onsi/ginkgo/README.md
@@ -4,7 +4,23 @@
Jump to the [docs](https://onsi.github.io/ginkgo/) to learn more. To start rolling your Ginkgo tests *now* [keep reading](#set-me-up)!
-If you have a question, comment, bug report, feature request, etc. please open a GitHub issue.
+If you have a question, comment, bug report, feature request, etc. please open a GitHub issue, or visit the [Ginkgo Slack channel](https://app.slack.com/client/T029RQSE6/CQQ50BBNW).
+
+## TLDR
+Ginkgo builds on Go's `testing` package, allowing expressive [Behavior-Driven Development](https://en.wikipedia.org/wiki/Behavior-driven_development) ("BDD") style tests.
+It is typically (and optionally) paired with the [Gomega](https://github.com/onsi/gomega) matcher library.
+
+```go
+Describe("the strings package", func() {
+ Context("strings.Contains()", func() {
+ When("the string contains the substring in the middle", func() {
+ It("returns `true`", func() {
+ Expect(strings.Contains("Ginkgo is awesome", "is")).To(BeTrue())
+ })
+ })
+ })
+})
+```
## Feature List
diff --git a/vendor/github.com/onsi/ginkgo/config/config.go b/vendor/github.com/onsi/ginkgo/config/config.go
index 342645022..5d4b35732 100644
--- a/vendor/github.com/onsi/ginkgo/config/config.go
+++ b/vendor/github.com/onsi/ginkgo/config/config.go
@@ -20,7 +20,7 @@ import (
"fmt"
)
-const VERSION = "1.12.2"
+const VERSION = "1.12.3"
type GinkgoConfigType struct {
RandomSeed int64
diff --git a/vendor/github.com/onsi/ginkgo/extensions/table/table.go b/vendor/github.com/onsi/ginkgo/extensions/table/table.go
index ae8ab7d24..2ed5314f2 100644
--- a/vendor/github.com/onsi/ginkgo/extensions/table/table.go
+++ b/vendor/github.com/onsi/ginkgo/extensions/table/table.go
@@ -12,7 +12,9 @@ import (
"fmt"
"reflect"
- "github.com/onsi/ginkgo"
+ "github.com/onsi/ginkgo/internal/codelocation"
+ "github.com/onsi/ginkgo/internal/global"
+ "github.com/onsi/ginkgo/types"
)
/*
@@ -42,7 +44,7 @@ It's important to understand that the `Describe`s and `It`s are generated at eva
Individual Entries can be focused (with FEntry) or marked pending (with PEntry or XEntry). In addition, the entire table can be focused or marked pending with FDescribeTable and PDescribeTable/XDescribeTable.
*/
func DescribeTable(description string, itBody interface{}, entries ...TableEntry) bool {
- describeTable(description, itBody, entries, false, false)
+ describeTable(description, itBody, entries, types.FlagTypeNone)
return true
}
@@ -50,7 +52,7 @@ func DescribeTable(description string, itBody interface{}, entries ...TableEntry
You can focus a table with `FDescribeTable`. This is equivalent to `FDescribe`.
*/
func FDescribeTable(description string, itBody interface{}, entries ...TableEntry) bool {
- describeTable(description, itBody, entries, false, true)
+ describeTable(description, itBody, entries, types.FlagTypeFocused)
return true
}
@@ -58,7 +60,7 @@ func FDescribeTable(description string, itBody interface{}, entries ...TableEntr
You can mark a table as pending with `PDescribeTable`. This is equivalent to `PDescribe`.
*/
func PDescribeTable(description string, itBody interface{}, entries ...TableEntry) bool {
- describeTable(description, itBody, entries, true, false)
+ describeTable(description, itBody, entries, types.FlagTypePending)
return true
}
@@ -66,33 +68,24 @@ func PDescribeTable(description string, itBody interface{}, entries ...TableEntr
You can mark a table as pending with `XDescribeTable`. This is equivalent to `XDescribe`.
*/
func XDescribeTable(description string, itBody interface{}, entries ...TableEntry) bool {
- describeTable(description, itBody, entries, true, false)
+ describeTable(description, itBody, entries, types.FlagTypePending)
return true
}
-func describeTable(description string, itBody interface{}, entries []TableEntry, pending bool, focused bool) {
+func describeTable(description string, itBody interface{}, entries []TableEntry, flag types.FlagType) {
itBodyValue := reflect.ValueOf(itBody)
if itBodyValue.Kind() != reflect.Func {
panic(fmt.Sprintf("DescribeTable expects a function, got %#v", itBody))
}
- if pending {
- ginkgo.PDescribe(description, func() {
+ global.Suite.PushContainerNode(
+ description,
+ func() {
for _, entry := range entries {
entry.generateIt(itBodyValue)
}
- })
- } else if focused {
- ginkgo.FDescribe(description, func() {
- for _, entry := range entries {
- entry.generateIt(itBodyValue)
- }
- })
- } else {
- ginkgo.Describe(description, func() {
- for _, entry := range entries {
- entry.generateIt(itBodyValue)
- }
- })
- }
+ },
+ flag,
+ codelocation.New(2),
+ )
}
diff --git a/vendor/github.com/onsi/ginkgo/extensions/table/table_entry.go b/vendor/github.com/onsi/ginkgo/extensions/table/table_entry.go
index 93f3bc3b0..1a919a1fe 100644
--- a/vendor/github.com/onsi/ginkgo/extensions/table/table_entry.go
+++ b/vendor/github.com/onsi/ginkgo/extensions/table/table_entry.go
@@ -3,22 +3,31 @@ package table
import (
"reflect"
- "github.com/onsi/ginkgo"
+ "github.com/onsi/ginkgo/internal/codelocation"
+ "github.com/onsi/ginkgo/internal/global"
+ "github.com/onsi/ginkgo/types"
)
/*
TableEntry represents an entry in a table test. You generally use the `Entry` constructor.
*/
type TableEntry struct {
- Description string
- Parameters []interface{}
- Pending bool
- Focused bool
+ Description string
+ Parameters []interface{}
+ Pending bool
+ Focused bool
+ codeLocation types.CodeLocation
}
func (t TableEntry) generateIt(itBody reflect.Value) {
+ if t.codeLocation == (types.CodeLocation{}) {
+ // The user created the TableEntry struct directly instead of having used the (F/P/X)Entry constructors.
+ // Therefore default to the code location of the surrounding DescribeTable.
+ t.codeLocation = codelocation.New(5)
+ }
+
if t.Pending {
- ginkgo.PIt(t.Description)
+ global.Suite.PushItNode(t.Description, func() {}, types.FlagTypePending, t.codeLocation, 0)
return
}
@@ -38,9 +47,9 @@ func (t TableEntry) generateIt(itBody reflect.Value) {
}
if t.Focused {
- ginkgo.FIt(t.Description, body)
+ global.Suite.PushItNode(t.Description, body, types.FlagTypeFocused, t.codeLocation, global.DefaultTimeout)
} else {
- ginkgo.It(t.Description, body)
+ global.Suite.PushItNode(t.Description, body, types.FlagTypeNone, t.codeLocation, global.DefaultTimeout)
}
}
@@ -53,26 +62,26 @@ Subsequent parameters are saved off and sent to the callback passed in to `Descr
Each Entry ends up generating an individual Ginkgo It.
*/
func Entry(description string, parameters ...interface{}) TableEntry {
- return TableEntry{description, parameters, false, false}
+ return TableEntry{description, parameters, false, false, codelocation.New(1)}
}
/*
You can focus a particular entry with FEntry. This is equivalent to FIt.
*/
func FEntry(description string, parameters ...interface{}) TableEntry {
- return TableEntry{description, parameters, false, true}
+ return TableEntry{description, parameters, false, true, codelocation.New(1)}
}
/*
You can mark a particular entry as pending with PEntry. This is equivalent to PIt.
*/
func PEntry(description string, parameters ...interface{}) TableEntry {
- return TableEntry{description, parameters, true, false}
+ return TableEntry{description, parameters, true, false, codelocation.New(1)}
}
/*
You can mark a particular entry as pending with XEntry. This is equivalent to XIt.
*/
func XEntry(description string, parameters ...interface{}) TableEntry {
- return TableEntry{description, parameters, true, false}
+ return TableEntry{description, parameters, true, false, codelocation.New(1)}
}
diff --git a/vendor/github.com/onsi/ginkgo/ginkgo_dsl.go b/vendor/github.com/onsi/ginkgo/ginkgo_dsl.go
index 3cbf89a35..30ff86f59 100644
--- a/vendor/github.com/onsi/ginkgo/ginkgo_dsl.go
+++ b/vendor/github.com/onsi/ginkgo/ginkgo_dsl.go
@@ -22,9 +22,8 @@ import (
"github.com/onsi/ginkgo/config"
"github.com/onsi/ginkgo/internal/codelocation"
- "github.com/onsi/ginkgo/internal/failer"
+ "github.com/onsi/ginkgo/internal/global"
"github.com/onsi/ginkgo/internal/remote"
- "github.com/onsi/ginkgo/internal/suite"
"github.com/onsi/ginkgo/internal/testingtproxy"
"github.com/onsi/ginkgo/internal/writer"
"github.com/onsi/ginkgo/reporters"
@@ -46,16 +45,10 @@ To circumvent this, you should call
at the top of the goroutine that caused this panic.
`
-const defaultTimeout = 1
-
-var globalSuite *suite.Suite
-var globalFailer *failer.Failer
func init() {
config.Flags(flag.CommandLine, "ginkgo", true)
GinkgoWriter = writer.New(os.Stdout)
- globalFailer = failer.New()
- globalSuite = suite.New(globalFailer)
}
//GinkgoWriter implements an io.Writer
@@ -156,7 +149,7 @@ type GinkgoTestDescription struct {
//CurrentGinkgoTestDescripton returns information about the current running test.
func CurrentGinkgoTestDescription() GinkgoTestDescription {
- summary, ok := globalSuite.CurrentRunningSpecSummary()
+ summary, ok := global.Suite.CurrentRunningSpecSummary()
if !ok {
return GinkgoTestDescription{}
}
@@ -223,7 +216,7 @@ func RunSpecsWithCustomReporters(t GinkgoTestingT, description string, specRepor
for i, reporter := range specReporters {
reporters[i] = reporter
}
- passed, hasFocusedTests := globalSuite.Run(t, description, reporters, writer, config.GinkgoConfig)
+ passed, hasFocusedTests := global.Suite.Run(t, description, reporters, writer, config.GinkgoConfig)
if passed && hasFocusedTests && strings.TrimSpace(os.Getenv("GINKGO_EDITOR_INTEGRATION")) == "" {
fmt.Println("PASS | FOCUSED")
os.Exit(types.GINKGO_FOCUS_EXIT_CODE)
@@ -252,7 +245,7 @@ func Skip(message string, callerSkip ...int) {
skip = callerSkip[0]
}
- globalFailer.Skip(message, codelocation.New(skip+1))
+ global.Failer.Skip(message, codelocation.New(skip+1))
panic(GINKGO_PANIC)
}
@@ -263,7 +256,7 @@ func Fail(message string, callerSkip ...int) {
skip = callerSkip[0]
}
- globalFailer.Fail(message, codelocation.New(skip+1))
+ global.Failer.Fail(message, codelocation.New(skip+1))
panic(GINKGO_PANIC)
}
@@ -280,7 +273,7 @@ func Fail(message string, callerSkip ...int) {
func GinkgoRecover() {
e := recover()
if e != nil {
- globalFailer.Panic(codelocation.New(1), e)
+ global.Failer.Panic(codelocation.New(1), e)
}
}
@@ -291,25 +284,25 @@ func GinkgoRecover() {
//equivalent. The difference is purely semantic -- you typically Describe the behavior of an object
//or method and, within that Describe, outline a number of Contexts and Whens.
func Describe(text string, body func()) bool {
- globalSuite.PushContainerNode(text, body, types.FlagTypeNone, codelocation.New(1))
+ global.Suite.PushContainerNode(text, body, types.FlagTypeNone, codelocation.New(1))
return true
}
//You can focus the tests within a describe block using FDescribe
func FDescribe(text string, body func()) bool {
- globalSuite.PushContainerNode(text, body, types.FlagTypeFocused, codelocation.New(1))
+ global.Suite.PushContainerNode(text, body, types.FlagTypeFocused, codelocation.New(1))
return true
}
//You can mark the tests within a describe block as pending using PDescribe
func PDescribe(text string, body func()) bool {
- globalSuite.PushContainerNode(text, body, types.FlagTypePending, codelocation.New(1))
+ global.Suite.PushContainerNode(text, body, types.FlagTypePending, codelocation.New(1))
return true
}
//You can mark the tests within a describe block as pending using XDescribe
func XDescribe(text string, body func()) bool {
- globalSuite.PushContainerNode(text, body, types.FlagTypePending, codelocation.New(1))
+ global.Suite.PushContainerNode(text, body, types.FlagTypePending, codelocation.New(1))
return true
}
@@ -320,25 +313,25 @@ func XDescribe(text string, body func()) bool {
//equivalent. The difference is purely semantic -- you typical Describe the behavior of an object
//or method and, within that Describe, outline a number of Contexts and Whens.
func Context(text string, body func()) bool {
- globalSuite.PushContainerNode(text, body, types.FlagTypeNone, codelocation.New(1))
+ global.Suite.PushContainerNode(text, body, types.FlagTypeNone, codelocation.New(1))
return true
}
//You can focus the tests within a describe block using FContext
func FContext(text string, body func()) bool {
- globalSuite.PushContainerNode(text, body, types.FlagTypeFocused, codelocation.New(1))
+ global.Suite.PushContainerNode(text, body, types.FlagTypeFocused, codelocation.New(1))
return true
}
//You can mark the tests within a describe block as pending using PContext
func PContext(text string, body func()) bool {
- globalSuite.PushContainerNode(text, body, types.FlagTypePending, codelocation.New(1))
+ global.Suite.PushContainerNode(text, body, types.FlagTypePending, codelocation.New(1))
return true
}
//You can mark the tests within a describe block as pending using XContext
func XContext(text string, body func()) bool {
- globalSuite.PushContainerNode(text, body, types.FlagTypePending, codelocation.New(1))
+ global.Suite.PushContainerNode(text, body, types.FlagTypePending, codelocation.New(1))
return true
}
@@ -349,25 +342,25 @@ func XContext(text string, body func()) bool {
//equivalent. The difference is purely semantic -- you typical Describe the behavior of an object
//or method and, within that Describe, outline a number of Contexts and Whens.
func When(text string, body func()) bool {
- globalSuite.PushContainerNode("when "+text, body, types.FlagTypeNone, codelocation.New(1))
+ global.Suite.PushContainerNode("when "+text, body, types.FlagTypeNone, codelocation.New(1))
return true
}
//You can focus the tests within a describe block using FWhen
func FWhen(text string, body func()) bool {
- globalSuite.PushContainerNode("when "+text, body, types.FlagTypeFocused, codelocation.New(1))
+ global.Suite.PushContainerNode("when "+text, body, types.FlagTypeFocused, codelocation.New(1))
return true
}
//You can mark the tests within a describe block as pending using PWhen
func PWhen(text string, body func()) bool {
- globalSuite.PushContainerNode("when "+text, body, types.FlagTypePending, codelocation.New(1))
+ global.Suite.PushContainerNode("when "+text, body, types.FlagTypePending, codelocation.New(1))
return true
}
//You can mark the tests within a describe block as pending using XWhen
func XWhen(text string, body func()) bool {
- globalSuite.PushContainerNode("when "+text, body, types.FlagTypePending, codelocation.New(1))
+ global.Suite.PushContainerNode("when "+text, body, types.FlagTypePending, codelocation.New(1))
return true
}
@@ -377,25 +370,25 @@ func XWhen(text string, body func()) bool {
//Ginkgo will normally run It blocks synchronously. To perform asynchronous tests, pass a
//function that accepts a Done channel. When you do this, you can also provide an optional timeout.
func It(text string, body interface{}, timeout ...float64) bool {
- globalSuite.PushItNode(text, body, types.FlagTypeNone, codelocation.New(1), parseTimeout(timeout...))
+ global.Suite.PushItNode(text, body, types.FlagTypeNone, codelocation.New(1), parseTimeout(timeout...))
return true
}
//You can focus individual Its using FIt
func FIt(text string, body interface{}, timeout ...float64) bool {
- globalSuite.PushItNode(text, body, types.FlagTypeFocused, codelocation.New(1), parseTimeout(timeout...))
+ global.Suite.PushItNode(text, body, types.FlagTypeFocused, codelocation.New(1), parseTimeout(timeout...))
return true
}
//You can mark Its as pending using PIt
func PIt(text string, _ ...interface{}) bool {
- globalSuite.PushItNode(text, func() {}, types.FlagTypePending, codelocation.New(1), 0)
+ global.Suite.PushItNode(text, func() {}, types.FlagTypePending, codelocation.New(1), 0)
return true
}
//You can mark Its as pending using XIt
func XIt(text string, _ ...interface{}) bool {
- globalSuite.PushItNode(text, func() {}, types.FlagTypePending, codelocation.New(1), 0)
+ global.Suite.PushItNode(text, func() {}, types.FlagTypePending, codelocation.New(1), 0)
return true
}
@@ -403,25 +396,25 @@ func XIt(text string, _ ...interface{}) bool {
//which "It" does not fit into a natural sentence flow. All the same protocols apply for Specify blocks
//which apply to It blocks.
func Specify(text string, body interface{}, timeout ...float64) bool {
- globalSuite.PushItNode(text, body, types.FlagTypeNone, codelocation.New(1), parseTimeout(timeout...))
+ global.Suite.PushItNode(text, body, types.FlagTypeNone, codelocation.New(1), parseTimeout(timeout...))
return true
}
//You can focus individual Specifys using FSpecify
func FSpecify(text string, body interface{}, timeout ...float64) bool {
- globalSuite.PushItNode(text, body, types.FlagTypeFocused, codelocation.New(1), parseTimeout(timeout...))
+ global.Suite.PushItNode(text, body, types.FlagTypeFocused, codelocation.New(1), parseTimeout(timeout...))
return true
}
//You can mark Specifys as pending using PSpecify
func PSpecify(text string, is ...interface{}) bool {
- globalSuite.PushItNode(text, func() {}, types.FlagTypePending, codelocation.New(1), 0)
+ global.Suite.PushItNode(text, func() {}, types.FlagTypePending, codelocation.New(1), 0)
return true
}
//You can mark Specifys as pending using XSpecify
func XSpecify(text string, is ...interface{}) bool {
- globalSuite.PushItNode(text, func() {}, types.FlagTypePending, codelocation.New(1), 0)
+ global.Suite.PushItNode(text, func() {}, types.FlagTypePending, codelocation.New(1), 0)
return true
}
@@ -452,25 +445,25 @@ func By(text string, callbacks ...func()) {
//The body function must have the signature:
// func(b Benchmarker)
func Measure(text string, body interface{}, samples int) bool {
- globalSuite.PushMeasureNode(text, body, types.FlagTypeNone, codelocation.New(1), samples)
+ global.Suite.PushMeasureNode(text, body, types.FlagTypeNone, codelocation.New(1), samples)
return true
}
//You can focus individual Measures using FMeasure
func FMeasure(text string, body interface{}, samples int) bool {
- globalSuite.PushMeasureNode(text, body, types.FlagTypeFocused, codelocation.New(1), samples)
+ global.Suite.PushMeasureNode(text, body, types.FlagTypeFocused, codelocation.New(1), samples)
return true
}
//You can mark Measurements as pending using PMeasure
func PMeasure(text string, _ ...interface{}) bool {
- globalSuite.PushMeasureNode(text, func(b Benchmarker) {}, types.FlagTypePending, codelocation.New(1), 0)
+ global.Suite.PushMeasureNode(text, func(b Benchmarker) {}, types.FlagTypePending, codelocation.New(1), 0)
return true
}
//You can mark Measurements as pending using XMeasure
func XMeasure(text string, _ ...interface{}) bool {
- globalSuite.PushMeasureNode(text, func(b Benchmarker) {}, types.FlagTypePending, codelocation.New(1), 0)
+ global.Suite.PushMeasureNode(text, func(b Benchmarker) {}, types.FlagTypePending, codelocation.New(1), 0)
return true
}
@@ -481,7 +474,7 @@ func XMeasure(text string, _ ...interface{}) bool {
//
//You may only register *one* BeforeSuite handler per test suite. You typically do so in your bootstrap file at the top level.
func BeforeSuite(body interface{}, timeout ...float64) bool {
- globalSuite.SetBeforeSuiteNode(body, codelocation.New(1), parseTimeout(timeout...))
+ global.Suite.SetBeforeSuiteNode(body, codelocation.New(1), parseTimeout(timeout...))
return true
}
@@ -494,7 +487,7 @@ func BeforeSuite(body interface{}, timeout ...float64) bool {
//
//You may only register *one* AfterSuite handler per test suite. You typically do so in your bootstrap file at the top level.
func AfterSuite(body interface{}, timeout ...float64) bool {
- globalSuite.SetAfterSuiteNode(body, codelocation.New(1), parseTimeout(timeout...))
+ global.Suite.SetAfterSuiteNode(body, codelocation.New(1), parseTimeout(timeout...))
return true
}
@@ -539,7 +532,7 @@ func AfterSuite(body interface{}, timeout ...float64) bool {
// Ω(err).ShouldNot(HaveOccurred())
// })
func SynchronizedBeforeSuite(node1Body interface{}, allNodesBody interface{}, timeout ...float64) bool {
- globalSuite.SetSynchronizedBeforeSuiteNode(
+ global.Suite.SetSynchronizedBeforeSuiteNode(
node1Body,
allNodesBody,
codelocation.New(1),
@@ -566,7 +559,7 @@ func SynchronizedBeforeSuite(node1Body interface{}, allNodesBody interface{}, ti
// dbRunner.Stop()
// })
func SynchronizedAfterSuite(allNodesBody interface{}, node1Body interface{}, timeout ...float64) bool {
- globalSuite.SetSynchronizedAfterSuiteNode(
+ global.Suite.SetSynchronizedAfterSuiteNode(
allNodesBody,
node1Body,
codelocation.New(1),
@@ -581,7 +574,7 @@ func SynchronizedAfterSuite(allNodesBody interface{}, node1Body interface{}, tim
//Like It blocks, BeforeEach blocks can be made asynchronous by providing a body function that accepts
//a Done channel
func BeforeEach(body interface{}, timeout ...float64) bool {
- globalSuite.PushBeforeEachNode(body, codelocation.New(1), parseTimeout(timeout...))
+ global.Suite.PushBeforeEachNode(body, codelocation.New(1), parseTimeout(timeout...))
return true
}
@@ -591,7 +584,7 @@ func BeforeEach(body interface{}, timeout ...float64) bool {
//Like It blocks, BeforeEach blocks can be made asynchronous by providing a body function that accepts
//a Done channel
func JustBeforeEach(body interface{}, timeout ...float64) bool {
- globalSuite.PushJustBeforeEachNode(body, codelocation.New(1), parseTimeout(timeout...))
+ global.Suite.PushJustBeforeEachNode(body, codelocation.New(1), parseTimeout(timeout...))
return true
}
@@ -601,7 +594,7 @@ func JustBeforeEach(body interface{}, timeout ...float64) bool {
//Like It blocks, JustAfterEach blocks can be made asynchronous by providing a body function that accepts
//a Done channel
func JustAfterEach(body interface{}, timeout ...float64) bool {
- globalSuite.PushJustAfterEachNode(body, codelocation.New(1), parseTimeout(timeout...))
+ global.Suite.PushJustAfterEachNode(body, codelocation.New(1), parseTimeout(timeout...))
return true
}
@@ -611,13 +604,13 @@ func JustAfterEach(body interface{}, timeout ...float64) bool {
//Like It blocks, AfterEach blocks can be made asynchronous by providing a body function that accepts
//a Done channel
func AfterEach(body interface{}, timeout ...float64) bool {
- globalSuite.PushAfterEachNode(body, codelocation.New(1), parseTimeout(timeout...))
+ global.Suite.PushAfterEachNode(body, codelocation.New(1), parseTimeout(timeout...))
return true
}
func parseTimeout(timeout ...float64) time.Duration {
if len(timeout) == 0 {
- return time.Duration(defaultTimeout * int64(time.Second))
+ return global.DefaultTimeout
} else {
return time.Duration(timeout[0] * float64(time.Second))
}
diff --git a/vendor/github.com/onsi/ginkgo/internal/global/init.go b/vendor/github.com/onsi/ginkgo/internal/global/init.go
new file mode 100644
index 000000000..711443200
--- /dev/null
+++ b/vendor/github.com/onsi/ginkgo/internal/global/init.go
@@ -0,0 +1,18 @@
+package global
+
+import (
+ "time"
+
+ "github.com/onsi/ginkgo/internal/failer"
+ "github.com/onsi/ginkgo/internal/suite"
+)
+
+const DefaultTimeout = time.Duration(1 * time.Second)
+
+var Suite *suite.Suite
+var Failer *failer.Failer
+
+func init() {
+ Failer = failer.New()
+ Suite = suite.New(Failer)
+}
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/cgroups.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/cgroups.go
index 25ff51589..c0a965923 100644
--- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/cgroups.go
+++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/cgroups.go
@@ -37,8 +37,18 @@ type Manager interface {
// restore the object later.
GetPaths() map[string]string
+ // GetUnifiedPath returns the unified path when running in unified mode.
+ // The value corresponds to the all values of GetPaths() map.
+ //
+ // GetUnifiedPath returns error when running in hybrid mode as well as
+ // in legacy mode.
+ GetUnifiedPath() (string, error)
+
// Sets the cgroup as configured.
Set(container *configs.Config) error
+
+ // Gets the cgroup as configured.
+ GetCgroups() (*configs.Cgroup, error)
}
type NotFoundError struct {
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/utils.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/utils.go
index 60790f83b..dbcc58f5b 100644
--- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/utils.go
+++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/utils.go
@@ -20,8 +20,9 @@ import (
)
const (
- CgroupNamePrefix = "name="
- CgroupProcesses = "cgroup.procs"
+ CgroupNamePrefix = "name="
+ CgroupProcesses = "cgroup.procs"
+ unifiedMountpoint = "/sys/fs/cgroup"
)
var (
@@ -40,7 +41,7 @@ var HugePageSizeUnitList = []string{"B", "KB", "MB", "GB", "TB", "PB"}
func IsCgroup2UnifiedMode() bool {
isUnifiedOnce.Do(func() {
var st syscall.Statfs_t
- if err := syscall.Statfs("/sys/fs/cgroup", &st); err != nil {
+ if err := syscall.Statfs(unifiedMountpoint, &st); err != nil {
panic("cannot statfs cgroup root")
}
isUnified = st.Type == unix.CGROUP2_SUPER_MAGIC
@@ -50,6 +51,9 @@ func IsCgroup2UnifiedMode() bool {
// https://www.kernel.org/doc/Documentation/cgroup-v1/cgroups.txt
func FindCgroupMountpoint(cgroupPath, subsystem string) (string, error) {
+ if IsCgroup2UnifiedMode() {
+ return unifiedMountpoint, nil
+ }
mnt, _, err := FindCgroupMountpointAndRoot(cgroupPath, subsystem)
return mnt, err
}
@@ -235,8 +239,8 @@ func GetCgroupMounts(all bool) ([]Mount, error) {
return nil, err
}
m := Mount{
- Mountpoint: "/sys/fs/cgroup",
- Root: "/sys/fs/cgroup",
+ Mountpoint: unifiedMountpoint,
+ Root: unifiedMountpoint,
Subsystems: availableControllers,
}
return []Mount{m}, nil
@@ -262,6 +266,21 @@ func GetCgroupMounts(all bool) ([]Mount, error) {
// GetAllSubsystems returns all the cgroup subsystems supported by the kernel
func GetAllSubsystems() ([]string, error) {
+ // /proc/cgroups is meaningless for v2
+ // https://github.com/torvalds/linux/blob/v5.3/Documentation/admin-guide/cgroup-v2.rst#deprecated-v1-core-features
+ if IsCgroup2UnifiedMode() {
+ // "pseudo" controllers do not appear in /sys/fs/cgroup/cgroup.controllers.
+ // - devices: implemented in kernel 4.15
+ // - freezer: implemented in kernel 5.2
+ // We assume these are always available, as it is hard to detect availability.
+ pseudo := []string{"devices", "freezer"}
+ data, err := ioutil.ReadFile("/sys/fs/cgroup/cgroup.controllers")
+ if err != nil {
+ return nil, err
+ }
+ subsystems := append(pseudo, strings.Fields(string(data))...)
+ return subsystems, nil
+ }
f, err := os.Open("/proc/cgroups")
if err != nil {
return nil, err
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 894e7fc00..b84d9e017 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -197,7 +197,7 @@ github.com/containers/storage/pkg/truncindex
github.com/containers/storage/pkg/unshare
# github.com/coreos/go-iptables v0.4.5
github.com/coreos/go-iptables/iptables
-# github.com/coreos/go-systemd/v22 v22.0.0
+# github.com/coreos/go-systemd/v22 v22.1.0
github.com/coreos/go-systemd/v22/activation
github.com/coreos/go-systemd/v22/dbus
github.com/coreos/go-systemd/v22/internal/dlopen
@@ -361,7 +361,7 @@ github.com/nxadm/tail/ratelimiter
github.com/nxadm/tail/util
github.com/nxadm/tail/watch
github.com/nxadm/tail/winfile
-# github.com/onsi/ginkgo v1.12.2
+# github.com/onsi/ginkgo v1.12.3
github.com/onsi/ginkgo
github.com/onsi/ginkgo/config
github.com/onsi/ginkgo/extensions/table
@@ -375,6 +375,7 @@ github.com/onsi/ginkgo/ginkgo/watch
github.com/onsi/ginkgo/internal/codelocation
github.com/onsi/ginkgo/internal/containernode
github.com/onsi/ginkgo/internal/failer
+github.com/onsi/ginkgo/internal/global
github.com/onsi/ginkgo/internal/leafnodes
github.com/onsi/ginkgo/internal/remote
github.com/onsi/ginkgo/internal/spec
@@ -408,7 +409,7 @@ github.com/opencontainers/go-digest
# github.com/opencontainers/image-spec v1.0.2-0.20190823105129-775207bd45b6
github.com/opencontainers/image-spec/specs-go
github.com/opencontainers/image-spec/specs-go/v1
-# github.com/opencontainers/runc v1.0.0-rc9
+# github.com/opencontainers/runc v1.0.0-rc90
github.com/opencontainers/runc/libcontainer/apparmor
github.com/opencontainers/runc/libcontainer/cgroups
github.com/opencontainers/runc/libcontainer/configs