aboutsummaryrefslogtreecommitdiff
path: root/pkg
diff options
context:
space:
mode:
Diffstat (limited to 'pkg')
-rw-r--r--pkg/api/handlers/compat/images.go12
-rw-r--r--pkg/api/handlers/compat/images_build.go26
-rw-r--r--pkg/api/handlers/compat/images_push.go4
-rw-r--r--pkg/api/handlers/libpod/images.go4
-rw-r--r--pkg/api/handlers/libpod/images_pull.go4
-rw-r--r--pkg/api/handlers/libpod/play.go4
-rw-r--r--pkg/api/server/handler_api.go23
-rw-r--r--pkg/auth/auth.go189
-rw-r--r--pkg/bindings/images/build.go20
-rw-r--r--pkg/bindings/images/images.go4
-rw-r--r--pkg/bindings/images/pull.go2
-rw-r--r--pkg/bindings/play/play.go2
-rw-r--r--pkg/domain/infra/tunnel/helpers.go92
-rw-r--r--pkg/spec/config_linux.go3
-rw-r--r--pkg/spec/spec.go19
-rw-r--r--pkg/specgen/generate/config_linux.go7
16 files changed, 314 insertions, 101 deletions
diff --git a/pkg/api/handlers/compat/images.go b/pkg/api/handlers/compat/images.go
index 0900d1793..940b57343 100644
--- a/pkg/api/handlers/compat/images.go
+++ b/pkg/api/handlers/compat/images.go
@@ -93,7 +93,7 @@ func PruneImages(w http.ResponseWriter, r *http.Request) {
})
}
- //FIXME/TODO to do this exactly correct, pruneimages needs to return idrs and space-reclaimed, then we are golden
+ // FIXME/TODO to do this exactly correct, pruneimages needs to return idrs and space-reclaimed, then we are golden
ipr := types.ImagesPruneReport{
ImagesDeleted: idr,
SpaceReclaimed: 1, // TODO we cannot supply this right now
@@ -113,7 +113,7 @@ func CommitContainer(w http.ResponseWriter, r *http.Request) {
Changes string `schema:"changes"`
Comment string `schema:"comment"`
Container string `schema:"container"`
- //fromSrc string # fromSrc is currently unused
+ // fromSrc string # fromSrc is currently unused
Pause bool `schema:"pause"`
Repo string `schema:"repo"`
Tag string `schema:"tag"`
@@ -224,7 +224,7 @@ func CreateImageFromSrc(w http.ResponseWriter, r *http.Request) {
Status string `json:"status"`
Progress string `json:"progress"`
ProgressDetail map[string]string `json:"progressDetail"`
- Id string `json:"id"` //nolint
+ Id string `json:"id"` // nolint
}{
Status: iid,
ProgressDetail: map[string]string{},
@@ -257,9 +257,9 @@ func CreateImageFromImage(w http.ResponseWriter, r *http.Request) {
fromImage = fmt.Sprintf("%s:%s", fromImage, query.Tag)
}
- authConf, authfile, err := auth.GetCredentials(r)
+ authConf, authfile, key, err := auth.GetCredentials(r)
if err != nil {
- utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "Failed to parse %q header for %s", auth.XRegistryAuthHeader, r.URL.String()))
+ utils.Error(w, "Failed to retrieve repository credentials", http.StatusBadRequest, errors.Wrapf(err, "Failed to parse %q header for %s", key, r.URL.String()))
return
}
defer auth.RemoveAuthfile(authfile)
@@ -299,7 +299,7 @@ func CreateImageFromImage(w http.ResponseWriter, r *http.Request) {
Error string `json:"error"`
Progress string `json:"progress"`
ProgressDetail map[string]string `json:"progressDetail"`
- Id string `json:"id"` //nolint
+ Id string `json:"id"` // nolint
}{
Status: fmt.Sprintf("pulling image (%s) from %s", img.Tag, strings.Join(img.Names(), ", ")),
ProgressDetail: map[string]string{},
diff --git a/pkg/api/handlers/compat/images_build.go b/pkg/api/handlers/compat/images_build.go
index cd10ac6ba..d5ccf56fe 100644
--- a/pkg/api/handlers/compat/images_build.go
+++ b/pkg/api/handlers/compat/images_build.go
@@ -2,7 +2,6 @@ package compat
import (
"context"
- "encoding/base64"
"encoding/json"
"fmt"
"io"
@@ -11,13 +10,13 @@ import (
"os"
"path/filepath"
"strconv"
- "strings"
"github.com/containers/buildah"
"github.com/containers/buildah/imagebuildah"
+ "github.com/containers/image/v5/types"
"github.com/containers/podman/v2/libpod"
- "github.com/containers/podman/v2/pkg/api/handlers"
"github.com/containers/podman/v2/pkg/api/handlers/utils"
+ "github.com/containers/podman/v2/pkg/auth"
"github.com/containers/podman/v2/pkg/channel"
"github.com/containers/storage/pkg/archive"
"github.com/gorilla/schema"
@@ -26,15 +25,6 @@ import (
)
func BuildImage(w http.ResponseWriter, r *http.Request) {
- authConfigs := map[string]handlers.AuthConfig{}
- if hdr, found := r.Header["X-Registry-Config"]; found && len(hdr) > 0 {
- authConfigsJSON := base64.NewDecoder(base64.URLEncoding, strings.NewReader(hdr[0]))
- if json.NewDecoder(authConfigsJSON).Decode(&authConfigs) != nil {
- utils.BadRequest(w, "X-Registry-Config", hdr[0], json.NewDecoder(authConfigsJSON).Decode(&authConfigs))
- return
- }
- }
-
if hdr, found := r.Header["Content-Type"]; found && len(hdr) > 0 {
contentType := hdr[0]
switch contentType {
@@ -152,6 +142,14 @@ func BuildImage(w http.ResponseWriter, r *http.Request) {
}
}
+ creds, authfile, key, err := auth.GetCredentials(r)
+ if err != nil {
+ // Credential value(s) not returned as their value is not human readable
+ utils.BadRequest(w, key.String(), "n/a", err)
+ return
+ }
+ defer auth.RemoveAuthfile(authfile)
+
// Channels all mux'ed in select{} below to follow API build protocol
stdout := channel.NewWriter(make(chan []byte, 1))
defer stdout.Close()
@@ -180,6 +178,10 @@ func BuildImage(w http.ResponseWriter, r *http.Request) {
Err: auxout,
ReportWriter: reporter,
OutputFormat: buildah.Dockerv2ImageManifest,
+ SystemContext: &types.SystemContext{
+ AuthFilePath: authfile,
+ DockerAuthConfig: creds,
+ },
CommonBuildOpts: &buildah.CommonBuildOptions{
CPUPeriod: query.CpuPeriod,
CPUQuota: query.CpuQuota,
diff --git a/pkg/api/handlers/compat/images_push.go b/pkg/api/handlers/compat/images_push.go
index e69a2212a..dd706a156 100644
--- a/pkg/api/handlers/compat/images_push.go
+++ b/pkg/api/handlers/compat/images_push.go
@@ -49,9 +49,9 @@ func PushImage(w http.ResponseWriter, r *http.Request) {
return
}
- authConf, authfile, err := auth.GetCredentials(r)
+ authConf, authfile, key, err := auth.GetCredentials(r)
if err != nil {
- utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "Failed to parse %q header for %s", auth.XRegistryAuthHeader, r.URL.String()))
+ utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "Failed to parse %q header for %s", key, r.URL.String()))
return
}
defer auth.RemoveAuthfile(authfile)
diff --git a/pkg/api/handlers/libpod/images.go b/pkg/api/handlers/libpod/images.go
index 2f9c10746..3054922c2 100644
--- a/pkg/api/handlers/libpod/images.go
+++ b/pkg/api/handlers/libpod/images.go
@@ -438,9 +438,9 @@ func PushImage(w http.ResponseWriter, r *http.Request) {
return
}
- authConf, authfile, err := auth.GetCredentials(r)
+ authConf, authfile, key, err := auth.GetCredentials(r)
if err != nil {
- utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "Failed to parse %q header for %s", auth.XRegistryAuthHeader, r.URL.String()))
+ utils.Error(w, "Failed to retrieve repository credentials", http.StatusBadRequest, errors.Wrapf(err, "Failed to parse %q header for %s", key, r.URL.String()))
return
}
defer auth.RemoveAuthfile(authfile)
diff --git a/pkg/api/handlers/libpod/images_pull.go b/pkg/api/handlers/libpod/images_pull.go
index ad8d1f38e..791ef7a48 100644
--- a/pkg/api/handlers/libpod/images_pull.go
+++ b/pkg/api/handlers/libpod/images_pull.go
@@ -74,9 +74,9 @@ func ImagesPull(w http.ResponseWriter, r *http.Request) {
return
}
- authConf, authfile, err := auth.GetCredentials(r)
+ authConf, authfile, key, err := auth.GetCredentials(r)
if err != nil {
- utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "Failed to parse %q header for %s", auth.XRegistryAuthHeader, r.URL.String()))
+ utils.Error(w, "Failed to retrieve repository credentials", http.StatusBadRequest, errors.Wrapf(err, "Failed to parse %q header for %s", key, r.URL.String()))
return
}
defer auth.RemoveAuthfile(authfile)
diff --git a/pkg/api/handlers/libpod/play.go b/pkg/api/handlers/libpod/play.go
index 59f78da8c..2296e170a 100644
--- a/pkg/api/handlers/libpod/play.go
+++ b/pkg/api/handlers/libpod/play.go
@@ -48,9 +48,9 @@ func PlayKube(w http.ResponseWriter, r *http.Request) {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "error closing temporary file"))
return
}
- authConf, authfile, err := auth.GetCredentials(r)
+ authConf, authfile, key, err := auth.GetCredentials(r)
if err != nil {
- utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "Failed to parse %q header for %s", auth.XRegistryAuthHeader, r.URL.String()))
+ utils.Error(w, "Failed to retrieve repository credentials", http.StatusBadRequest, errors.Wrapf(err, "Failed to parse %q header for %s", key, r.URL.String()))
return
}
defer auth.RemoveAuthfile(authfile)
diff --git a/pkg/api/server/handler_api.go b/pkg/api/server/handler_api.go
index 920811c51..28f5a0b42 100644
--- a/pkg/api/server/handler_api.go
+++ b/pkg/api/server/handler_api.go
@@ -7,7 +7,9 @@ import (
"runtime"
"github.com/containers/podman/v2/pkg/api/handlers/utils"
- log "github.com/sirupsen/logrus"
+ "github.com/containers/podman/v2/pkg/auth"
+ "github.com/google/uuid"
+ "github.com/sirupsen/logrus"
)
// APIHandler is a wrapper to enhance HandlerFunc's and remove redundant code
@@ -19,7 +21,7 @@ func (s *APIServer) APIHandler(h http.HandlerFunc) http.HandlerFunc {
if err != nil {
buf := make([]byte, 1<<20)
n := runtime.Stack(buf, true)
- log.Warnf("Recovering from API handler panic: %v, %s", err, buf[:n])
+ logrus.Warnf("Recovering from API handler panic: %v, %s", err, buf[:n])
// Try to inform client things went south... won't work if handler already started writing response body
utils.InternalServerError(w, fmt.Errorf("%v", err))
}
@@ -27,10 +29,23 @@ func (s *APIServer) APIHandler(h http.HandlerFunc) http.HandlerFunc {
// Wrapper to hide some boiler plate
fn := func(w http.ResponseWriter, r *http.Request) {
- log.Debugf("APIHandler -- Method: %s URL: %s", r.Method, r.URL.String())
+ rid := uuid.New().String()
+ if logrus.IsLevelEnabled(logrus.DebugLevel) {
+ logrus.Debugf("APIHandler(%s) -- Method: %s URL: %s", rid, r.Method, r.URL.String())
+ for k, v := range r.Header {
+ switch auth.HeaderAuthName(k) {
+ case auth.XRegistryConfigHeader, auth.XRegistryAuthHeader:
+ logrus.Debugf("APIHandler(%s) -- Header: %s: <hidden>", rid, k)
+ default:
+ logrus.Debugf("APIHandler(%s) -- Header: %s: %v", rid, k, v)
+ }
+ }
+ }
+ // Set in case handler wishes to correlate logging events
+ r.Header.Set("X-Reference-Id", rid)
if err := r.ParseForm(); err != nil {
- log.Infof("Failed Request: unable to parse form: %q", err)
+ logrus.Infof("Failed Request: unable to parse form: %q (%s)", err, rid)
}
// TODO: Use r.ConnContext when ported to go 1.13
diff --git a/pkg/auth/auth.go b/pkg/auth/auth.go
index 69a7da869..fcbf6fe39 100644
--- a/pkg/auth/auth.go
+++ b/pkg/auth/auth.go
@@ -3,6 +3,7 @@ package auth
import (
"encoding/base64"
"encoding/json"
+ "fmt"
"io/ioutil"
"net/http"
"os"
@@ -15,21 +16,98 @@ import (
"github.com/sirupsen/logrus"
)
-// XRegistryAuthHeader is the key to the encoded registry authentication
-// configuration in an http-request header.
-const XRegistryAuthHeader = "X-Registry-Auth"
+type HeaderAuthName string
-// GetCredentials extracts one or more DockerAuthConfigs from the request's
+func (h HeaderAuthName) String() string { return string(h) }
+
+// XRegistryAuthHeader is the key to the encoded registry authentication configuration in an http-request header.
+// This header supports one registry per header occurrence. To support N registries provided N headers, one per registry.
+// As of Docker API 1.40 and Libpod API 1.0.0, this header is supported by all endpoints.
+const XRegistryAuthHeader HeaderAuthName = "X-Registry-Auth"
+
+// XRegistryConfigHeader is the key to the encoded registry authentication configuration in an http-request header.
+// This header supports N registries in one header via a Base64 encoded, JSON map.
+// As of Docker API 1.40 and Libpod API 2.0.0, this header is supported by build endpoints.
+const XRegistryConfigHeader HeaderAuthName = "X-Registry-Config"
+
+// GetCredentials queries the http.Request for X-Registry-.* headers and extracts
+// the necessary authentication information for libpod operations
+func GetCredentials(r *http.Request) (*types.DockerAuthConfig, string, HeaderAuthName, error) {
+ has := func(key HeaderAuthName) bool { hdr, found := r.Header[string(key)]; return found && len(hdr) > 0 }
+ switch {
+ case has(XRegistryConfigHeader):
+ c, f, err := getConfigCredentials(r)
+ return c, f, XRegistryConfigHeader, err
+ case has(XRegistryAuthHeader):
+ c, f, err := getAuthCredentials(r)
+ return c, f, XRegistryAuthHeader, err
+
+ }
+ return nil, "", "", nil
+}
+
+// getConfigCredentials extracts one or more docker.AuthConfig from the request's
+// header. An empty key will be used as default while a named registry will be
+// returned as types.DockerAuthConfig
+func getConfigCredentials(r *http.Request) (*types.DockerAuthConfig, string, error) {
+ var auth *types.DockerAuthConfig
+ configs := make(map[string]types.DockerAuthConfig)
+
+ for _, h := range r.Header[string(XRegistryConfigHeader)] {
+ param, err := base64.URLEncoding.DecodeString(h)
+ if err != nil {
+ return nil, "", errors.Wrapf(err, "failed to decode %q", XRegistryConfigHeader)
+ }
+
+ ac := make(map[string]dockerAPITypes.AuthConfig)
+ err = json.Unmarshal(param, &ac)
+ if err != nil {
+ return nil, "", errors.Wrapf(err, "failed to unmarshal %q", XRegistryConfigHeader)
+ }
+
+ for k, v := range ac {
+ configs[k] = dockerAuthToImageAuth(v)
+ }
+ }
+
+ // Empty key implies no registry given in API
+ if c, found := configs[""]; found {
+ auth = &c
+ }
+
+ // Override any default given above if specialized credentials provided
+ if registries, found := r.URL.Query()["registry"]; found {
+ for _, r := range registries {
+ for k, v := range configs {
+ if strings.Contains(k, r) {
+ v := v
+ auth = &v
+ break
+ }
+ }
+ if auth != nil {
+ break
+ }
+ }
+
+ if auth == nil {
+ logrus.Debugf("%q header found in request, but \"registry=%v\" query parameter not provided",
+ XRegistryConfigHeader, registries)
+ } else {
+ logrus.Debugf("%q header found in request for username %q", XRegistryConfigHeader, auth.Username)
+ }
+ }
+
+ authfile, err := authConfigsToAuthFile(configs)
+ return auth, authfile, err
+}
+
+// getAuthCredentials extracts one or more DockerAuthConfigs from the request's
// header. The header could specify a single-auth config in which case the
// first return value is set. In case of a multi-auth header, the contents are
// stored in a temporary auth file (2nd return value). Note that the auth file
// should be removed after usage.
-func GetCredentials(r *http.Request) (*types.DockerAuthConfig, string, error) {
- authHeader := r.Header.Get(XRegistryAuthHeader)
- if len(authHeader) == 0 {
- return nil, "", nil
- }
-
+func getAuthCredentials(r *http.Request) (*types.DockerAuthConfig, string, error) {
// First look for a multi-auth header (i.e., a map).
authConfigs, err := multiAuthHeader(r)
if err == nil {
@@ -51,38 +129,75 @@ func GetCredentials(r *http.Request) (*types.DockerAuthConfig, string, error) {
return conf, "", nil
}
-// Header returns a map with the XRegistryAuthHeader set which can
+// Header builds the requested Authentication Header
+func Header(sys *types.SystemContext, headerName HeaderAuthName, authfile, username, password string) (map[string]string, error) {
+ var (
+ content string
+ err error
+ )
+ switch headerName {
+ case XRegistryAuthHeader:
+ content, err = headerAuth(sys, authfile, username, password)
+ case XRegistryConfigHeader:
+ content, err = headerConfig(sys, authfile, username, password)
+ default:
+ err = fmt.Errorf("unsupported authentication header: %q", headerName)
+ }
+ if err != nil {
+ return nil, err
+ }
+
+ if len(content) > 0 {
+ return map[string]string{string(headerName): content}, nil
+ }
+ return nil, nil
+}
+
+// headerConfig returns a map with the XRegistryConfigHeader set which can
// conveniently be used in the http stack.
-func Header(sys *types.SystemContext, authfile, username, password string) (map[string]string, error) {
- var content string
- var err error
+func headerConfig(sys *types.SystemContext, authfile, username, password string) (string, error) {
+ if sys == nil {
+ sys = &types.SystemContext{}
+ }
+ if authfile != "" {
+ sys.AuthFilePath = authfile
+ }
+ authConfigs, err := imageAuth.GetAllCredentials(sys)
+ if err != nil {
+ return "", err
+ }
if username != "" {
- content, err = encodeSingleAuthConfig(types.DockerAuthConfig{Username: username, Password: password})
- if err != nil {
- return nil, err
- }
- } else {
- if sys == nil {
- sys = &types.SystemContext{}
- }
- if authfile != "" {
- sys.AuthFilePath = authfile
- }
- authConfigs, err := imageAuth.GetAllCredentials(sys)
- if err != nil {
- return nil, err
- }
- content, err = encodeMultiAuthConfigs(authConfigs)
- if err != nil {
- return nil, err
+ authConfigs[""] = types.DockerAuthConfig{
+ Username: username,
+ Password: password,
}
}
- header := make(map[string]string)
- header[XRegistryAuthHeader] = content
+ if len(authConfigs) == 0 {
+ return "", nil
+ }
+ return encodeMultiAuthConfigs(authConfigs)
+}
- return header, nil
+// headerAuth returns a base64 encoded map with the XRegistryAuthHeader set which can
+// conveniently be used in the http stack.
+func headerAuth(sys *types.SystemContext, authfile, username, password string) (string, error) {
+ if username != "" {
+ return encodeSingleAuthConfig(types.DockerAuthConfig{Username: username, Password: password})
+ }
+
+ if sys == nil {
+ sys = &types.SystemContext{}
+ }
+ if authfile != "" {
+ sys.AuthFilePath = authfile
+ }
+ authConfigs, err := imageAuth.GetAllCredentials(sys)
+ if err != nil {
+ return "", err
+ }
+ return encodeMultiAuthConfigs(authConfigs)
}
// RemoveAuthfile is a convenience function that is meant to be called in a
@@ -180,7 +295,7 @@ func imageAuthToDockerAuth(authConfig types.DockerAuthConfig) dockerAPITypes.Aut
// singleAuthHeader extracts a DockerAuthConfig from the request's header.
// The header content is a single DockerAuthConfig.
func singleAuthHeader(r *http.Request) (map[string]types.DockerAuthConfig, error) {
- authHeader := r.Header.Get(XRegistryAuthHeader)
+ authHeader := r.Header.Get(string(XRegistryAuthHeader))
authConfig := dockerAPITypes.AuthConfig{}
if len(authHeader) > 0 {
authJSON := base64.NewDecoder(base64.URLEncoding, strings.NewReader(authHeader))
@@ -196,7 +311,7 @@ func singleAuthHeader(r *http.Request) (map[string]types.DockerAuthConfig, error
// multiAuthHeader extracts a DockerAuthConfig from the request's header.
// The header content is a map[string]DockerAuthConfigs.
func multiAuthHeader(r *http.Request) (map[string]types.DockerAuthConfig, error) {
- authHeader := r.Header.Get(XRegistryAuthHeader)
+ authHeader := r.Header.Get(string(XRegistryAuthHeader))
if len(authHeader) == 0 {
return nil, nil
}
diff --git a/pkg/bindings/images/build.go b/pkg/bindings/images/build.go
index e65a04f7b..60ffea548 100644
--- a/pkg/bindings/images/build.go
+++ b/pkg/bindings/images/build.go
@@ -15,6 +15,7 @@ import (
"strings"
"github.com/containers/buildah"
+ "github.com/containers/podman/v2/pkg/auth"
"github.com/containers/podman/v2/pkg/bindings"
"github.com/containers/podman/v2/pkg/domain/entities"
"github.com/docker/go-units"
@@ -96,6 +97,23 @@ func Build(ctx context.Context, containerFiles []string, options entities.BuildO
params.Set("httpproxy", "1")
}
+ var (
+ headers map[string]string
+ err error
+ )
+ if options.SystemContext == nil {
+ headers, err = auth.Header(options.SystemContext, auth.XRegistryConfigHeader, "", "", "")
+ } else {
+ if options.SystemContext.DockerAuthConfig != nil {
+ headers, err = auth.Header(options.SystemContext, auth.XRegistryAuthHeader, options.SystemContext.AuthFilePath, options.SystemContext.DockerAuthConfig.Username, options.SystemContext.DockerAuthConfig.Password)
+ } else {
+ headers, err = auth.Header(options.SystemContext, auth.XRegistryConfigHeader, options.SystemContext.AuthFilePath, "", "")
+ }
+ }
+ if err != nil {
+ return nil, err
+ }
+
stdout := io.Writer(os.Stdout)
if options.Out != nil {
stdout = options.Out
@@ -128,7 +146,7 @@ func Build(ctx context.Context, containerFiles []string, options entities.BuildO
if err != nil {
return nil, err
}
- response, err := conn.DoRequest(tarfile, http.MethodPost, "/build", params, nil)
+ response, err := conn.DoRequest(tarfile, http.MethodPost, "/build", params, headers)
if err != nil {
return nil, err
}
diff --git a/pkg/bindings/images/images.go b/pkg/bindings/images/images.go
index 596491044..a78e7f4c6 100644
--- a/pkg/bindings/images/images.go
+++ b/pkg/bindings/images/images.go
@@ -282,7 +282,7 @@ func Push(ctx context.Context, source string, destination string, options entiti
}
// TODO: have a global system context we can pass around (1st argument)
- header, err := auth.Header(nil, options.Authfile, options.Username, options.Password)
+ header, err := auth.Header(nil, auth.XRegistryAuthHeader, options.Authfile, options.Username, options.Password)
if err != nil {
return err
}
@@ -325,7 +325,7 @@ func Search(ctx context.Context, term string, opts entities.ImageSearchOptions)
}
// TODO: have a global system context we can pass around (1st argument)
- header, err := auth.Header(nil, opts.Authfile, "", "")
+ header, err := auth.Header(nil, auth.XRegistryAuthHeader, opts.Authfile, "", "")
if err != nil {
return nil, err
}
diff --git a/pkg/bindings/images/pull.go b/pkg/bindings/images/pull.go
index 2bfbbb2ac..c827b3283 100644
--- a/pkg/bindings/images/pull.go
+++ b/pkg/bindings/images/pull.go
@@ -42,7 +42,7 @@ func Pull(ctx context.Context, rawImage string, options entities.ImagePullOption
params.Set("allTags", strconv.FormatBool(options.AllTags))
// TODO: have a global system context we can pass around (1st argument)
- header, err := auth.Header(nil, options.Authfile, options.Username, options.Password)
+ header, err := auth.Header(nil, auth.XRegistryAuthHeader, options.Authfile, options.Username, options.Password)
if err != nil {
return nil, err
}
diff --git a/pkg/bindings/play/play.go b/pkg/bindings/play/play.go
index 32f9bb4a9..ffaee3208 100644
--- a/pkg/bindings/play/play.go
+++ b/pkg/bindings/play/play.go
@@ -33,7 +33,7 @@ func Kube(ctx context.Context, path string, options entities.PlayKubeOptions) (*
}
// TODO: have a global system context we can pass around (1st argument)
- header, err := auth.Header(nil, options.Authfile, options.Username, options.Password)
+ header, err := auth.Header(nil, auth.XRegistryAuthHeader, options.Authfile, options.Username, options.Password)
if err != nil {
return nil, err
}
diff --git a/pkg/domain/infra/tunnel/helpers.go b/pkg/domain/infra/tunnel/helpers.go
index 5944f855a..7d28f1bd3 100644
--- a/pkg/domain/infra/tunnel/helpers.go
+++ b/pkg/domain/infra/tunnel/helpers.go
@@ -2,74 +2,118 @@ package tunnel
import (
"context"
- "strings"
"github.com/containers/podman/v2/libpod/define"
"github.com/containers/podman/v2/pkg/bindings"
"github.com/containers/podman/v2/pkg/bindings/containers"
"github.com/containers/podman/v2/pkg/bindings/pods"
"github.com/containers/podman/v2/pkg/domain/entities"
- "github.com/containers/podman/v2/pkg/util"
+ "github.com/containers/podman/v2/pkg/errorhandling"
"github.com/pkg/errors"
)
+// FIXME: the `ignore` parameter is very likely wrong here as it should rather
+// be used on *errors* from operations such as remove.
func getContainersByContext(contextWithConnection context.Context, all, ignore bool, namesOrIDs []string) ([]entities.ListContainer, error) {
- var (
- cons []entities.ListContainer
- )
if all && len(namesOrIDs) > 0 {
return nil, errors.New("cannot lookup containers and all")
}
- c, err := containers.List(contextWithConnection, nil, bindings.PTrue, nil, nil, bindings.PTrue)
+
+ allContainers, err := containers.List(contextWithConnection, nil, bindings.PTrue, nil, nil, bindings.PTrue)
if err != nil {
return nil, err
}
if all {
- return c, err
+ return allContainers, err
}
- for _, id := range namesOrIDs {
- var found bool
- for _, con := range c {
- if id == con.ID || strings.HasPrefix(con.ID, id) || util.StringInSlice(id, con.Names) {
- cons = append(cons, con)
+
+ // Note: it would be nicer if the lists endpoint would support that as
+ // we could use the libpod backend for looking up containers rather
+ // than risking diverging the local and remote lookups.
+ //
+ // A `--filter nameOrId=abc` that can be specified multiple times would
+ // be awesome to have.
+ filtered := []entities.ListContainer{}
+ for _, nameOrID := range namesOrIDs {
+ // First determine if the container exists by doing an inspect.
+ // Inspect takes supports names and IDs and let's us determine
+ // a containers full ID.
+ inspectData, err := containers.Inspect(contextWithConnection, nameOrID, bindings.PFalse)
+ if err != nil {
+ if ignore && errorhandling.Contains(err, define.ErrNoSuchCtr) {
+ continue
+ }
+ return nil, err
+ }
+
+ // Now we can do a full match of the ID to find the right
+ // container. Note that we *really* need a full ID match to
+ // prevent any ambiguities between IDs and names (see #7837).
+ found := false
+ for _, ctr := range allContainers {
+ if ctr.ID == inspectData.ID {
+ filtered = append(filtered, ctr)
found = true
break
}
+
}
+
if !found && !ignore {
- return nil, errors.Wrapf(define.ErrNoSuchCtr, "unable to find container %q", id)
+ return nil, errors.Wrapf(define.ErrNoSuchCtr, "unable to find container %q", nameOrID)
}
}
- return cons, nil
+ return filtered, nil
}
func getPodsByContext(contextWithConnection context.Context, all bool, namesOrIDs []string) ([]*entities.ListPodsReport, error) {
- var (
- sPods []*entities.ListPodsReport
- )
if all && len(namesOrIDs) > 0 {
return nil, errors.New("cannot lookup specific pods and all")
}
- fPods, err := pods.List(contextWithConnection, nil)
+ allPods, err := pods.List(contextWithConnection, nil)
if err != nil {
return nil, err
}
if all {
- return fPods, nil
+ return allPods, nil
}
+
+ filtered := []*entities.ListPodsReport{}
+ // Note: it would be nicer if the lists endpoint would support that as
+ // we could use the libpod backend for looking up pods rather than
+ // risking diverging the local and remote lookups.
+ //
+ // A `--filter nameOrId=abc` that can be specified multiple times would
+ // be awesome to have.
for _, nameOrID := range namesOrIDs {
- var found bool
- for _, f := range fPods {
- if f.Name == nameOrID || strings.HasPrefix(f.Id, nameOrID) {
- sPods = append(sPods, f)
+ // First determine if the pod exists by doing an inspect.
+ // Inspect takes supports names and IDs and let's us determine
+ // a containers full ID.
+ inspectData, err := pods.Inspect(contextWithConnection, nameOrID)
+ if err != nil {
+ if errorhandling.Contains(err, define.ErrNoSuchPod) {
+ return nil, errors.Wrapf(define.ErrNoSuchPod, "unable to find pod %q", nameOrID)
+ }
+ return nil, err
+ }
+
+ // Now we can do a full match of the ID to find the right pod.
+ // Note that we *really* need a full ID match to prevent any
+ // ambiguities between IDs and names (see #7837).
+ found := false
+ for _, pod := range allPods {
+ if pod.Id == inspectData.ID {
+ filtered = append(filtered, pod)
found = true
break
}
+
}
+
if !found {
return nil, errors.Wrapf(define.ErrNoSuchPod, "unable to find pod %q", nameOrID)
}
}
- return sPods, nil
+ return filtered, nil
}
diff --git a/pkg/spec/config_linux.go b/pkg/spec/config_linux.go
index d03663f12..319cce61f 100644
--- a/pkg/spec/config_linux.go
+++ b/pkg/spec/config_linux.go
@@ -200,6 +200,9 @@ func getDevices(path string) ([]*configs.Device, error) {
}
case f.Name() == "console":
continue
+ case f.Mode()&os.ModeSymlink != 0:
+ // do not add symlink'd devices to privileged devices
+ continue
}
device, err := devices.DeviceFromPath(filepath.Join(path, f.Name()), "rwm")
if err != nil {
diff --git a/pkg/spec/spec.go b/pkg/spec/spec.go
index 42228540c..81620997f 100644
--- a/pkg/spec/spec.go
+++ b/pkg/spec/spec.go
@@ -182,14 +182,23 @@ func (config *CreateConfig) createConfigToOCISpec(runtime *libpod.Runtime, userM
g.SetProcessCwd(config.WorkDir)
ProcessArgs := make([]string, 0)
- if len(config.Entrypoint) > 0 {
- ProcessArgs = config.Entrypoint
+ // We need to iterate the input for entrypoint because it is a []string
+ // but "" is a legit json input, which translates into a []string with an
+ // empty position. This messes up the eventual command being executed
+ // in the container
+ for _, a := range config.Entrypoint {
+ if len(a) > 0 {
+ ProcessArgs = append(ProcessArgs, a)
+ }
}
- if len(config.Command) > 0 {
- ProcessArgs = append(ProcessArgs, config.Command...)
+ // Same issue as explained above for config.Entrypoint.
+ for _, a := range config.Command {
+ if len(a) > 0 {
+ ProcessArgs = append(ProcessArgs, a)
+ }
}
- g.SetProcessArgs(ProcessArgs)
+ g.SetProcessArgs(ProcessArgs)
g.SetProcessTerminal(config.Tty)
for key, val := range config.Annotations {
diff --git a/pkg/specgen/generate/config_linux.go b/pkg/specgen/generate/config_linux.go
index 1d5dcd8e7..fac02ad01 100644
--- a/pkg/specgen/generate/config_linux.go
+++ b/pkg/specgen/generate/config_linux.go
@@ -248,6 +248,13 @@ func addDevice(g *generate.Generator, device string) error {
}
g.Config.Mounts = append(g.Config.Mounts, devMnt)
return nil
+ } else if src == "/dev/fuse" {
+ // if the user is asking for fuse inside the container
+ // make sure the module is loaded.
+ f, err := unix.Open(src, unix.O_RDONLY|unix.O_NONBLOCK, 0)
+ if err == nil {
+ unix.Close(f)
+ }
}
dev.Path = dst
g.AddDevice(*dev)