summaryrefslogtreecommitdiff
path: root/pkg
diff options
context:
space:
mode:
authorValentin Rothberg <rothberg@redhat.com>2020-05-13 13:44:29 +0200
committerValentin Rothberg <rothberg@redhat.com>2020-05-29 15:39:37 +0200
commitdc80267b594e41cf7e223821dc1446683f0cae36 (patch)
tree8ca8f81cdf302b1905d7a56f7c5c76ba5468c6f1 /pkg
parent78c38460eb8ba9190d414f2da6a1414990cc6cfd (diff)
downloadpodman-dc80267b594e41cf7e223821dc1446683f0cae36.tar.gz
podman-dc80267b594e41cf7e223821dc1446683f0cae36.tar.bz2
podman-dc80267b594e41cf7e223821dc1446683f0cae36.zip
compat handlers: add X-Registry-Auth header support
* Support the `X-Registry-Auth` http-request header. * The content of the header is a base64 encoded JSON payload which can either be a single auth config or a map of auth configs (user+pw or token) with the corresponding registries being the keys. Vanilla Docker, projectatomic Docker and the bindings are transparantly supported. * Add a hidden `--registries-conf` flag. Buildah exposes the same flag, mostly for testing purposes. * Do all credential parsing in the client (i.e., `cmd/podman`) pass the username and password in the backend instead of unparsed credentials. * Add a `pkg/auth` which handles most of the heavy lifting. * Go through the authentication-handling code of most commands, bindings and endpoints. Migrate them to the new code and fix issues as seen. A final evaluation and more tests is still required *after* this change. * The manifest-push endpoint is missing certain parameters and should use the ABI function instead. Adding auth-support isn't really possible without these parts working. * The container commands and endpoints (i.e., create and run) have not been changed yet. The APIs don't yet account for the authfile. * Add authentication tests to `pkg/bindings`. Fixes: #6384 Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
Diffstat (limited to 'pkg')
-rw-r--r--pkg/api/handlers/compat/images.go30
-rw-r--r--pkg/api/handlers/compat/images_push.go15
-rw-r--r--pkg/api/handlers/libpod/images.go58
-rw-r--r--pkg/api/handlers/libpod/manifests.go4
-rw-r--r--pkg/api/handlers/libpod/play.go20
-rw-r--r--pkg/api/server/register_images.go8
-rw-r--r--pkg/api/server/swagger.go7
-rw-r--r--pkg/auth/auth.go216
-rw-r--r--pkg/bindings/connection.go7
-rw-r--r--pkg/bindings/containers/checkpoint.go4
-rw-r--r--pkg/bindings/containers/commit.go2
-rw-r--r--pkg/bindings/containers/containers.go34
-rw-r--r--pkg/bindings/containers/create.go2
-rw-r--r--pkg/bindings/containers/diff.go2
-rw-r--r--pkg/bindings/containers/exec.go4
-rw-r--r--pkg/bindings/containers/healthcheck.go2
-rw-r--r--pkg/bindings/containers/logs.go2
-rw-r--r--pkg/bindings/containers/mount.go6
-rw-r--r--pkg/bindings/generate/generate.go2
-rw-r--r--pkg/bindings/images/diff.go2
-rw-r--r--pkg/bindings/images/images.go58
-rw-r--r--pkg/bindings/images/rm.go4
-rw-r--r--pkg/bindings/manifests/manifests.go10
-rw-r--r--pkg/bindings/network/network.go8
-rw-r--r--pkg/bindings/play/play.go9
-rw-r--r--pkg/bindings/pods/pods.go28
-rw-r--r--pkg/bindings/system/info.go2
-rw-r--r--pkg/bindings/system/system.go8
-rw-r--r--pkg/bindings/test/auth_test.go143
-rw-r--r--pkg/bindings/volumes/volumes.go10
-rw-r--r--pkg/domain/entities/engine.go27
-rw-r--r--pkg/domain/entities/images.go14
-rw-r--r--pkg/domain/entities/manifest.go11
-rw-r--r--pkg/domain/entities/play.go7
-rw-r--r--pkg/domain/entities/system.go6
-rw-r--r--pkg/domain/infra/abi/images.go18
-rw-r--r--pkg/domain/infra/abi/manifest.go21
-rw-r--r--pkg/domain/infra/abi/play.go10
-rw-r--r--pkg/domain/infra/runtime_libpod.go3
39 files changed, 649 insertions, 175 deletions
diff --git a/pkg/api/handlers/compat/images.go b/pkg/api/handlers/compat/images.go
index ea9cbd691..b64ed0036 100644
--- a/pkg/api/handlers/compat/images.go
+++ b/pkg/api/handlers/compat/images.go
@@ -15,6 +15,7 @@ import (
image2 "github.com/containers/libpod/libpod/image"
"github.com/containers/libpod/pkg/api/handlers"
"github.com/containers/libpod/pkg/api/handlers/utils"
+ "github.com/containers/libpod/pkg/auth"
"github.com/containers/libpod/pkg/domain/entities"
"github.com/containers/libpod/pkg/util"
"github.com/docker/docker/api/types"
@@ -251,19 +252,32 @@ func CreateImageFromImage(w http.ResponseWriter, r *http.Request) {
return
}
- /*
- fromImage – Name of the image to pull. The name may include a tag or digest. This parameter may only be used when pulling an image. The pull is cancelled if the HTTP connection is closed.
- repo – Repository name given to an image when it is imported. The repo may include a tag. This parameter may only be used when importing an image.
- tag – Tag or digest. If empty when pulling an image, this causes all tags for the given image to be pulled.
- */
fromImage := query.FromImage
if len(query.Tag) >= 1 {
fromImage = fmt.Sprintf("%s:%s", fromImage, query.Tag)
}
- // TODO
- // We are eating the output right now because we haven't talked about how to deal with multiple responses yet
- img, err := runtime.ImageRuntime().New(r.Context(), fromImage, "", "", nil, &image2.DockerRegistryOptions{}, image2.SigningOptions{}, nil, util.PullImageMissing)
+ authConf, authfile, 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()))
+ return
+ }
+ defer auth.RemoveAuthfile(authfile)
+
+ registryOpts := image2.DockerRegistryOptions{DockerRegistryCreds: authConf}
+ if sys := runtime.SystemContext(); sys != nil {
+ registryOpts.DockerCertPath = sys.DockerCertPath
+ }
+ img, err := runtime.ImageRuntime().New(r.Context(),
+ fromImage,
+ "", // signature policy
+ authfile,
+ nil, // writer
+ &registryOpts,
+ image2.SigningOptions{},
+ nil, // label
+ util.PullImageMissing,
+ )
if err != nil {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, err)
return
diff --git a/pkg/api/handlers/compat/images_push.go b/pkg/api/handlers/compat/images_push.go
index 2260d5557..47976b7c9 100644
--- a/pkg/api/handlers/compat/images_push.go
+++ b/pkg/api/handlers/compat/images_push.go
@@ -9,6 +9,7 @@ import (
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/libpod/image"
"github.com/containers/libpod/pkg/api/handlers/utils"
+ "github.com/containers/libpod/pkg/auth"
"github.com/gorilla/schema"
"github.com/pkg/errors"
)
@@ -48,13 +49,17 @@ func PushImage(w http.ResponseWriter, r *http.Request) {
return
}
- // TODO: the X-Registry-Auth header is not checked yet here nor in any other
- // endpoint. Pushing does NOT work with authentication at the moment.
- dockerRegistryOptions := &image.DockerRegistryOptions{}
- authfile := ""
+ authConf, authfile, 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()))
+ return
+ }
+ defer auth.RemoveAuthfile(authfile)
+
+ dockerRegistryOptions := &image.DockerRegistryOptions{DockerRegistryCreds: authConf}
if sys := runtime.SystemContext(); sys != nil {
dockerRegistryOptions.DockerCertPath = sys.DockerCertPath
- authfile = sys.AuthFilePath
+ dockerRegistryOptions.RegistriesConfPath = sys.SystemRegistriesConfPath
}
err = newImage.PushImageToHeuristicDestination(
diff --git a/pkg/api/handlers/libpod/images.go b/pkg/api/handlers/libpod/images.go
index 1cbcfb52c..4b277d39c 100644
--- a/pkg/api/handlers/libpod/images.go
+++ b/pkg/api/handlers/libpod/images.go
@@ -21,6 +21,7 @@ import (
image2 "github.com/containers/libpod/libpod/image"
"github.com/containers/libpod/pkg/api/handlers"
"github.com/containers/libpod/pkg/api/handlers/utils"
+ "github.com/containers/libpod/pkg/auth"
"github.com/containers/libpod/pkg/domain/entities"
"github.com/containers/libpod/pkg/domain/infra/abi"
"github.com/containers/libpod/pkg/errorhandling"
@@ -28,6 +29,7 @@ import (
utils2 "github.com/containers/libpod/utils"
"github.com/gorilla/schema"
"github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
)
// Commit
@@ -339,7 +341,6 @@ func ImagesPull(w http.ResponseWriter, r *http.Request) {
decoder := r.Context().Value("decoder").(*schema.Decoder)
query := struct {
Reference string `schema:"reference"`
- Credentials string `schema:"credentials"`
OverrideOS string `schema:"overrideOS"`
OverrideArch string `schema:"overrideArch"`
TLSVerify bool `schema:"tlsVerify"`
@@ -382,20 +383,16 @@ func ImagesPull(w http.ResponseWriter, r *http.Request) {
return
}
- var registryCreds *types.DockerAuthConfig
- if len(query.Credentials) != 0 {
- creds, err := util.ParseRegistryCreds(query.Credentials)
- if err != nil {
- utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
- errors.Wrapf(err, "error parsing credentials %q", query.Credentials))
- return
- }
- registryCreds = creds
+ authConf, authfile, 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()))
+ return
}
+ defer auth.RemoveAuthfile(authfile)
// Setup the registry options
dockerRegistryOptions := image.DockerRegistryOptions{
- DockerRegistryCreds: registryCreds,
+ DockerRegistryCreds: authConf,
OSChoice: query.OverrideOS,
ArchitectureChoice: query.OverrideArch,
}
@@ -403,6 +400,13 @@ func ImagesPull(w http.ResponseWriter, r *http.Request) {
dockerRegistryOptions.DockerInsecureSkipTLSVerify = types.NewOptionalBool(!query.TLSVerify)
}
+ sys := runtime.SystemContext()
+ if sys == nil {
+ sys = image.GetSystemContext("", authfile, false)
+ }
+ dockerRegistryOptions.DockerCertPath = sys.DockerCertPath
+ sys.DockerAuthConfig = authConf
+
// Prepare the images we want to pull
imagesToPull := []string{}
res := []handlers.LibpodImagesPullReport{}
@@ -411,8 +415,7 @@ func ImagesPull(w http.ResponseWriter, r *http.Request) {
if !query.AllTags {
imagesToPull = append(imagesToPull, imageName)
} else {
- systemContext := image.GetSystemContext("", "", false)
- tags, err := docker.GetRepositoryTags(context.Background(), systemContext, imageRef)
+ tags, err := docker.GetRepositoryTags(context.Background(), sys, imageRef)
if err != nil {
utils.InternalServerError(w, errors.Wrap(err, "error getting repository tags"))
return
@@ -422,12 +425,6 @@ func ImagesPull(w http.ResponseWriter, r *http.Request) {
}
}
- authfile := ""
- if sys := runtime.SystemContext(); sys != nil {
- dockerRegistryOptions.DockerCertPath = sys.DockerCertPath
- authfile = sys.AuthFilePath
- }
-
// Finally pull the images
for _, img := range imagesToPull {
newImage, err := runtime.ImageRuntime().New(
@@ -456,7 +453,6 @@ func PushImage(w http.ResponseWriter, r *http.Request) {
runtime := r.Context().Value("runtime").(*libpod.Runtime)
query := struct {
- Credentials string `schema:"credentials"`
Destination string `schema:"destination"`
TLSVerify bool `schema:"tlsVerify"`
}{
@@ -492,26 +488,20 @@ func PushImage(w http.ResponseWriter, r *http.Request) {
return
}
- var registryCreds *types.DockerAuthConfig
- if len(query.Credentials) != 0 {
- creds, err := util.ParseRegistryCreds(query.Credentials)
- if err != nil {
- utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
- errors.Wrapf(err, "error parsing credentials %q", query.Credentials))
- return
- }
- registryCreds = creds
+ authConf, authfile, 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()))
+ return
}
+ defer auth.RemoveAuthfile(authfile)
+ logrus.Errorf("AuthConf: %v", authConf)
- // TODO: the X-Registry-Auth header is not checked yet here nor in any other
- // endpoint. Pushing does NOT work with authentication at the moment.
dockerRegistryOptions := &image.DockerRegistryOptions{
- DockerRegistryCreds: registryCreds,
+ DockerRegistryCreds: authConf,
}
- authfile := ""
if sys := runtime.SystemContext(); sys != nil {
dockerRegistryOptions.DockerCertPath = sys.DockerCertPath
- authfile = sys.AuthFilePath
+ dockerRegistryOptions.RegistriesConfPath = sys.SystemRegistriesConfPath
}
if _, found := r.URL.Query()["tlsVerify"]; found {
dockerRegistryOptions.DockerInsecureSkipTLSVerify = types.NewOptionalBool(!query.TLSVerify)
diff --git a/pkg/api/handlers/libpod/manifests.go b/pkg/api/handlers/libpod/manifests.go
index 93ca367f7..aef92368b 100644
--- a/pkg/api/handlers/libpod/manifests.go
+++ b/pkg/api/handlers/libpod/manifests.go
@@ -120,6 +120,10 @@ func ManifestRemove(w http.ResponseWriter, r *http.Request) {
utils.WriteResponse(w, http.StatusOK, handlers.IDResponse{ID: newID})
}
func ManifestPush(w http.ResponseWriter, r *http.Request) {
+ // FIXME: parameters are missing (tlsVerify, format).
+ // Also, we should use the ABI function to avoid duplicate code.
+ // Also, support for XRegistryAuth headers are missing.
+
runtime := r.Context().Value("runtime").(*libpod.Runtime)
decoder := r.Context().Value("decoder").(*schema.Decoder)
query := struct {
diff --git a/pkg/api/handlers/libpod/play.go b/pkg/api/handlers/libpod/play.go
index 26e02bf4f..1cb5cdb6c 100644
--- a/pkg/api/handlers/libpod/play.go
+++ b/pkg/api/handlers/libpod/play.go
@@ -9,6 +9,7 @@ import (
"github.com/containers/image/v5/types"
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/pkg/api/handlers/utils"
+ "github.com/containers/libpod/pkg/auth"
"github.com/containers/libpod/pkg/domain/entities"
"github.com/containers/libpod/pkg/domain/infra/abi"
"github.com/gorilla/schema"
@@ -47,9 +48,26 @@ 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)
+ 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()))
+ return
+ }
+ defer auth.RemoveAuthfile(authfile)
+ var username, password string
+ if authConf != nil {
+ username = authConf.Username
+ password = authConf.Password
+ }
containerEngine := abi.ContainerEngine{Libpod: runtime}
- options := entities.PlayKubeOptions{Network: query.Network, Quiet: true}
+ options := entities.PlayKubeOptions{
+ Authfile: authfile,
+ Username: username,
+ Password: password,
+ Network: query.Network,
+ Quiet: true,
+ }
if _, found := r.URL.Query()["tlsVerify"]; found {
options.SkipTLSVerify = types.NewOptionalBool(!query.TLSVerify)
}
diff --git a/pkg/api/server/register_images.go b/pkg/api/server/register_images.go
index 64094e8e4..83584d0f3 100644
--- a/pkg/api/server/register_images.go
+++ b/pkg/api/server/register_images.go
@@ -8,6 +8,10 @@ import (
"github.com/gorilla/mux"
)
+// TODO
+//
+// * /images/create is missing the "message" and "platform" parameters
+
func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// swagger:operation POST /images/create compat createImage
// ---
@@ -635,10 +639,6 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// type: string
// description: Allows for pushing the image to a different destintation than the image refers to.
// - in: query
- // name: credentials
- // description: username:password for the registry.
- // type: string
- // - in: query
// name: tlsVerify
// description: Require TLS verification.
// type: boolean
diff --git a/pkg/api/server/swagger.go b/pkg/api/server/swagger.go
index ebd99ba27..c463f809e 100644
--- a/pkg/api/server/swagger.go
+++ b/pkg/api/server/swagger.go
@@ -139,6 +139,13 @@ type swagImageSummary struct {
Body []entities.ImageSummary
}
+// Registries summary
+// swagger:response DocsRegistriesList
+type swagRegistriesList struct {
+ // in:body
+ Body entities.ListRegistriesReport
+}
+
// List Containers
// swagger:response DocsListContainer
type swagListContainers struct {
diff --git a/pkg/auth/auth.go b/pkg/auth/auth.go
new file mode 100644
index 000000000..ffa65f7e5
--- /dev/null
+++ b/pkg/auth/auth.go
@@ -0,0 +1,216 @@
+package auth
+
+import (
+ "encoding/base64"
+ "encoding/json"
+ "io/ioutil"
+ "net/http"
+ "os"
+ "strings"
+
+ imageAuth "github.com/containers/image/v5/pkg/docker/config"
+ "github.com/containers/image/v5/types"
+ dockerAPITypes "github.com/docker/docker/api/types"
+ "github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
+)
+
+// XRegistryAuthHeader is the key to the encoded registry authentication
+// configuration in an http-request header.
+const XRegistryAuthHeader = "X-Registry-Auth"
+
+// GetCredentials 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
+ }
+
+ // First look for a multi-auth header (i.e., a map).
+ authConfigs, err := multiAuthHeader(r)
+ if err == nil {
+ authfile, err := authConfigsToAuthFile(authConfigs)
+ return nil, authfile, err
+ }
+
+ // Fallback to looking for a single-auth header (i.e., one config).
+ authConfigs, err = singleAuthHeader(r)
+ if err != nil {
+ return nil, "", err
+ }
+ var conf *types.DockerAuthConfig
+ for k := range authConfigs {
+ c := authConfigs[k]
+ conf = &c
+ break
+ }
+ return conf, "", nil
+}
+
+// Header returns a map with the XRegistryAuthHeader 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
+
+ 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
+ }
+ }
+
+ header := make(map[string]string)
+ header[XRegistryAuthHeader] = content
+
+ return header, nil
+}
+
+// RemoveAuthfile is a convenience function that is meant to be called in a
+// deferred statement. If non-empty, it removes the specified authfile and log
+// errors. It's meant to reduce boilerplate code at call sites of
+// `GetCredentials`.
+func RemoveAuthfile(authfile string) {
+ if authfile == "" {
+ return
+ }
+ if err := os.Remove(authfile); err != nil {
+ logrus.Errorf("Error removing temporary auth file %q: %v", authfile, err)
+ }
+}
+
+// encodeSingleAuthConfig serializes the auth configuration as a base64 encoded JSON payload.
+func encodeSingleAuthConfig(authConfig types.DockerAuthConfig) (string, error) {
+ conf := imageAuthToDockerAuth(authConfig)
+ buf, err := json.Marshal(conf)
+ if err != nil {
+ return "", err
+ }
+ return base64.URLEncoding.EncodeToString(buf), nil
+}
+
+// encodeMultiAuthConfigs serializes the auth configurations as a base64 encoded JSON payload.
+func encodeMultiAuthConfigs(authConfigs map[string]types.DockerAuthConfig) (string, error) {
+ confs := make(map[string]dockerAPITypes.AuthConfig)
+ for registry, authConf := range authConfigs {
+ confs[registry] = imageAuthToDockerAuth(authConf)
+ }
+ buf, err := json.Marshal(confs)
+ if err != nil {
+ return "", err
+ }
+ return base64.URLEncoding.EncodeToString(buf), nil
+}
+
+// authConfigsToAuthFile stores the specified auth configs in a temporary files
+// and returns its path. The file can later be used an auth file for contacting
+// one or more container registries. If tmpDir is empty, the system's default
+// TMPDIR will be used.
+func authConfigsToAuthFile(authConfigs map[string]types.DockerAuthConfig) (string, error) {
+ // Intitialize an empty temporary JSON file.
+ tmpFile, err := ioutil.TempFile("", "auth.json.")
+ if err != nil {
+ return "", err
+ }
+ if _, err := tmpFile.Write([]byte{'{', '}'}); err != nil {
+ return "", errors.Wrap(err, "error initializing temporary auth file")
+ }
+ if err := tmpFile.Close(); err != nil {
+ return "", errors.Wrap(err, "error closing temporary auth file")
+ }
+ authFilePath := tmpFile.Name()
+
+ // TODO: It would be nice if c/image could dump the map at once.
+ //
+ // Now use the c/image packages to store the credentials. It's battle
+ // tested, and we make sure to use the same code as the image backend.
+ sys := types.SystemContext{AuthFilePath: authFilePath}
+ for server, config := range authConfigs {
+ // Note that we do not validate the credentials here. Wassume
+ // that all credentials are valid. They'll be used on demand
+ // later.
+ if err := imageAuth.SetAuthentication(&sys, server, config.Username, config.Password); err != nil {
+ return "", errors.Wrapf(err, "error storing credentials in temporary auth file (server: %q, user: %q)", server, config.Username)
+ }
+ }
+
+ return authFilePath, nil
+}
+
+// dockerAuthToImageAuth converts a docker auth config to one we're using
+// internally from c/image. Note that the Docker types look slightly
+// different, so we need to convert to be extra sure we're not running into
+// undesired side-effects when unmarhalling directly to our types.
+func dockerAuthToImageAuth(authConfig dockerAPITypes.AuthConfig) types.DockerAuthConfig {
+ return types.DockerAuthConfig{
+ Username: authConfig.Username,
+ Password: authConfig.Password,
+ IdentityToken: authConfig.IdentityToken,
+ }
+}
+
+// reverse conversion of `dockerAuthToImageAuth`.
+func imageAuthToDockerAuth(authConfig types.DockerAuthConfig) dockerAPITypes.AuthConfig {
+ return dockerAPITypes.AuthConfig{
+ Username: authConfig.Username,
+ Password: authConfig.Password,
+ IdentityToken: authConfig.IdentityToken,
+ }
+}
+
+// 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)
+ authConfig := dockerAPITypes.AuthConfig{}
+ if len(authHeader) > 0 {
+ authJSON := base64.NewDecoder(base64.URLEncoding, strings.NewReader(authHeader))
+ if err := json.NewDecoder(authJSON).Decode(&authConfig); err != nil {
+ return nil, err
+ }
+ }
+ authConfigs := make(map[string]types.DockerAuthConfig)
+ authConfigs["0"] = dockerAuthToImageAuth(authConfig)
+ return authConfigs, nil
+}
+
+// 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)
+ if len(authHeader) == 0 {
+ return nil, nil
+ }
+
+ dockerAuthConfigs := make(map[string]dockerAPITypes.AuthConfig)
+ authJSON := base64.NewDecoder(base64.URLEncoding, strings.NewReader(authHeader))
+ if err := json.NewDecoder(authJSON).Decode(&dockerAuthConfigs); err != nil {
+ return nil, err
+ }
+
+ // Now convert to the internal types.
+ authConfigs := make(map[string]types.DockerAuthConfig)
+ for server := range dockerAuthConfigs {
+ authConfigs[server] = dockerAuthToImageAuth(dockerAuthConfigs[server])
+ }
+ return authConfigs, nil
+}
diff --git a/pkg/bindings/connection.go b/pkg/bindings/connection.go
index d30698c1d..e9032f083 100644
--- a/pkg/bindings/connection.go
+++ b/pkg/bindings/connection.go
@@ -150,7 +150,7 @@ func pingNewConnection(ctx context.Context) error {
return err
}
// the ping endpoint sits at / in this case
- response, err := client.DoRequest(nil, http.MethodGet, "../../../_ping", nil)
+ response, err := client.DoRequest(nil, http.MethodGet, "../../../_ping", nil, nil)
if err != nil {
return err
}
@@ -250,7 +250,7 @@ func unixClient(_url *url.URL) (Connection, error) {
}
// DoRequest assembles the http request and returns the response
-func (c *Connection) DoRequest(httpBody io.Reader, httpMethod, endpoint string, queryParams url.Values, pathValues ...string) (*APIResponse, error) {
+func (c *Connection) DoRequest(httpBody io.Reader, httpMethod, endpoint string, queryParams url.Values, header map[string]string, pathValues ...string) (*APIResponse, error) {
var (
err error
response *http.Response
@@ -271,6 +271,9 @@ func (c *Connection) DoRequest(httpBody io.Reader, httpMethod, endpoint string,
if len(queryParams) > 0 {
req.URL.RawQuery = queryParams.Encode()
}
+ for key, val := range header {
+ req.Header.Set(key, val)
+ }
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++ {
diff --git a/pkg/bindings/containers/checkpoint.go b/pkg/bindings/containers/checkpoint.go
index 84924587b..f483a9297 100644
--- a/pkg/bindings/containers/checkpoint.go
+++ b/pkg/bindings/containers/checkpoint.go
@@ -34,7 +34,7 @@ func Checkpoint(ctx context.Context, nameOrId string, keep, leaveRunning, tcpEst
if export != nil {
params.Set("export", *export)
}
- response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/checkpoint", params, nameOrId)
+ response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/checkpoint", params, nil, nameOrId)
if err != nil {
return nil, err
}
@@ -71,7 +71,7 @@ func Restore(ctx context.Context, nameOrId string, keep, tcpEstablished, ignoreR
if importArchive != nil {
params.Set("import", *importArchive)
}
- response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/restore", params, nameOrId)
+ response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/restore", params, nil, nameOrId)
if err != nil {
return nil, err
}
diff --git a/pkg/bindings/containers/commit.go b/pkg/bindings/containers/commit.go
index 12c25f842..780d42272 100644
--- a/pkg/bindings/containers/commit.go
+++ b/pkg/bindings/containers/commit.go
@@ -41,7 +41,7 @@ func Commit(ctx context.Context, nameOrId string, options CommitOptions) (handle
if options.Tag != nil {
params.Set("tag", *options.Tag)
}
- response, err := conn.DoRequest(nil, http.MethodPost, "/commit", params)
+ response, err := conn.DoRequest(nil, http.MethodPost, "/commit", params, nil)
if err != nil {
return id, err
}
diff --git a/pkg/bindings/containers/containers.go b/pkg/bindings/containers/containers.go
index 81e213d2b..516f3d282 100644
--- a/pkg/bindings/containers/containers.go
+++ b/pkg/bindings/containers/containers.go
@@ -61,7 +61,7 @@ func List(ctx context.Context, filters map[string][]string, all *bool, last *int
}
params.Set("filters", filterString)
}
- response, err := conn.DoRequest(nil, http.MethodGet, "/containers/json", params)
+ response, err := conn.DoRequest(nil, http.MethodGet, "/containers/json", params, nil)
if err != nil {
return containers, err
}
@@ -86,7 +86,7 @@ func Prune(ctx context.Context, filters map[string][]string) (*entities.Containe
}
params.Set("filters", filterString)
}
- response, err := conn.DoRequest(nil, http.MethodPost, "/containers/prune", params)
+ response, err := conn.DoRequest(nil, http.MethodPost, "/containers/prune", params, nil)
if err != nil {
return nil, err
}
@@ -108,7 +108,7 @@ func Remove(ctx context.Context, nameOrID string, force, volumes *bool) error {
if volumes != nil {
params.Set("vols", strconv.FormatBool(*volumes))
}
- response, err := conn.DoRequest(nil, http.MethodDelete, "/containers/%s", params, nameOrID)
+ response, err := conn.DoRequest(nil, http.MethodDelete, "/containers/%s", params, nil, nameOrID)
if err != nil {
return err
}
@@ -128,7 +128,7 @@ func Inspect(ctx context.Context, nameOrID string, size *bool) (*define.InspectC
if size != nil {
params.Set("size", strconv.FormatBool(*size))
}
- response, err := conn.DoRequest(nil, http.MethodGet, "/containers/%s/json", params, nameOrID)
+ response, err := conn.DoRequest(nil, http.MethodGet, "/containers/%s/json", params, nil, nameOrID)
if err != nil {
return nil, err
}
@@ -146,7 +146,7 @@ func Kill(ctx context.Context, nameOrID string, sig string) error {
}
params := url.Values{}
params.Set("signal", sig)
- response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/kill", params, nameOrID)
+ response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/kill", params, nil, nameOrID)
if err != nil {
return err
}
@@ -161,7 +161,7 @@ func Pause(ctx context.Context, nameOrID string) error {
if err != nil {
return err
}
- response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/pause", nil, nameOrID)
+ response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/pause", nil, nil, nameOrID)
if err != nil {
return err
}
@@ -180,7 +180,7 @@ func Restart(ctx context.Context, nameOrID string, timeout *int) error {
if timeout != nil {
params.Set("t", strconv.Itoa(*timeout))
}
- response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/restart", params, nameOrID)
+ response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/restart", params, nil, nameOrID)
if err != nil {
return err
}
@@ -199,7 +199,7 @@ func Start(ctx context.Context, nameOrID string, detachKeys *string) error {
if detachKeys != nil {
params.Set("detachKeys", *detachKeys)
}
- response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/start", params, nameOrID)
+ response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/start", params, nil, nameOrID)
if err != nil {
return err
}
@@ -221,7 +221,7 @@ func Top(ctx context.Context, nameOrID string, descriptors []string) ([]string,
// flatten the slice into one string
params.Set("ps_args", strings.Join(descriptors, ","))
}
- response, err := conn.DoRequest(nil, http.MethodGet, "/containers/%s/top", params, nameOrID)
+ response, err := conn.DoRequest(nil, http.MethodGet, "/containers/%s/top", params, nil, nameOrID)
if err != nil {
return nil, err
}
@@ -249,7 +249,7 @@ func Unpause(ctx context.Context, nameOrID string) error {
if err != nil {
return err
}
- response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/unpause", nil, nameOrID)
+ response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/unpause", nil, nil, nameOrID)
if err != nil {
return err
}
@@ -269,7 +269,7 @@ func Wait(ctx context.Context, nameOrID string, condition *define.ContainerStatu
if condition != nil {
params.Set("condition", condition.String())
}
- response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/wait", params, nameOrID)
+ response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/wait", params, nil, nameOrID)
if err != nil {
return exitCode, err
}
@@ -284,7 +284,7 @@ func Exists(ctx context.Context, nameOrID string) (bool, error) {
if err != nil {
return false, err
}
- response, err := conn.DoRequest(nil, http.MethodGet, "/containers/%s/exists", nil, nameOrID)
+ response, err := conn.DoRequest(nil, http.MethodGet, "/containers/%s/exists", nil, nil, nameOrID)
if err != nil {
return false, err
}
@@ -302,7 +302,7 @@ func Stop(ctx context.Context, nameOrID string, timeout *uint) error {
if timeout != nil {
params.Set("t", strconv.Itoa(int(*timeout)))
}
- response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/stop", params, nameOrID)
+ response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/stop", params, nil, nameOrID)
if err != nil {
return err
}
@@ -317,7 +317,7 @@ func Export(ctx context.Context, nameOrID string, w io.Writer) error {
if err != nil {
return err
}
- response, err := conn.DoRequest(nil, http.MethodGet, "/containers/%s/export", params, nameOrID)
+ response, err := conn.DoRequest(nil, http.MethodGet, "/containers/%s/export", params, nil, nameOrID)
if err != nil {
return err
}
@@ -336,7 +336,7 @@ func ContainerInit(ctx context.Context, nameOrID string) error {
if err != nil {
return err
}
- response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/init", nil, nameOrID)
+ response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/init", nil, nil, nameOrID)
if err != nil {
return err
}
@@ -443,7 +443,7 @@ func Attach(ctx context.Context, nameOrId string, detachKeys *string, logs, stre
}()
}
- response, err := conn.DoRequest(stdin, http.MethodPost, "/containers/%s/attach", params, nameOrId)
+ response, err := conn.DoRequest(stdin, http.MethodPost, "/containers/%s/attach", params, nil, nameOrId)
if err != nil {
return err
}
@@ -572,7 +572,7 @@ func resizeTTY(ctx context.Context, endpoint string, height *int, width *int) er
if width != nil {
params.Set("w", strconv.Itoa(*width))
}
- rsp, err := conn.DoRequest(nil, http.MethodPost, endpoint, params)
+ rsp, err := conn.DoRequest(nil, http.MethodPost, endpoint, params, nil)
if err != nil {
return err
}
diff --git a/pkg/bindings/containers/create.go b/pkg/bindings/containers/create.go
index 21355f24b..4603b8653 100644
--- a/pkg/bindings/containers/create.go
+++ b/pkg/bindings/containers/create.go
@@ -22,7 +22,7 @@ func CreateWithSpec(ctx context.Context, s *specgen.SpecGenerator) (entities.Con
return ccr, err
}
stringReader := strings.NewReader(specgenString)
- response, err := conn.DoRequest(stringReader, http.MethodPost, "/containers/create", nil)
+ response, err := conn.DoRequest(stringReader, http.MethodPost, "/containers/create", nil, nil)
if err != nil {
return ccr, err
}
diff --git a/pkg/bindings/containers/diff.go b/pkg/bindings/containers/diff.go
index 82070ca9a..06a828c30 100644
--- a/pkg/bindings/containers/diff.go
+++ b/pkg/bindings/containers/diff.go
@@ -15,7 +15,7 @@ func Diff(ctx context.Context, nameOrId string) ([]archive.Change, error) {
return nil, err
}
- response, err := conn.DoRequest(nil, http.MethodGet, "/containers/%s/changes", nil, nameOrId)
+ response, err := conn.DoRequest(nil, http.MethodGet, "/containers/%s/changes", nil, nil, nameOrId)
if err != nil {
return nil, err
}
diff --git a/pkg/bindings/containers/exec.go b/pkg/bindings/containers/exec.go
index 48f9ed697..2aeeae1f8 100644
--- a/pkg/bindings/containers/exec.go
+++ b/pkg/bindings/containers/exec.go
@@ -34,7 +34,7 @@ func ExecCreate(ctx context.Context, nameOrID string, config *handlers.ExecCreat
}
jsonReader := strings.NewReader(string(requestJSON))
- resp, err := conn.DoRequest(jsonReader, http.MethodPost, "/containers/%s/exec", nil, nameOrID)
+ resp, err := conn.DoRequest(jsonReader, http.MethodPost, "/containers/%s/exec", nil, nil, nameOrID)
if err != nil {
return "", err
}
@@ -57,7 +57,7 @@ func ExecInspect(ctx context.Context, sessionID string) (*define.InspectExecSess
logrus.Debugf("Inspecting session ID %q", sessionID)
- resp, err := conn.DoRequest(nil, http.MethodGet, "/exec/%s/json", nil, sessionID)
+ resp, err := conn.DoRequest(nil, http.MethodGet, "/exec/%s/json", nil, nil, sessionID)
if err != nil {
return nil, err
}
diff --git a/pkg/bindings/containers/healthcheck.go b/pkg/bindings/containers/healthcheck.go
index 2b783ac73..b726acf49 100644
--- a/pkg/bindings/containers/healthcheck.go
+++ b/pkg/bindings/containers/healthcheck.go
@@ -18,7 +18,7 @@ func RunHealthCheck(ctx context.Context, nameOrID string) (*define.HealthCheckRe
var (
status define.HealthCheckResults
)
- response, err := conn.DoRequest(nil, http.MethodGet, "/containers/%s/healthcheck", nil, nameOrID)
+ response, err := conn.DoRequest(nil, http.MethodGet, "/containers/%s/healthcheck", nil, nil, nameOrID)
if err != nil {
return nil, err
}
diff --git a/pkg/bindings/containers/logs.go b/pkg/bindings/containers/logs.go
index 7fea30003..bec4ebb3c 100644
--- a/pkg/bindings/containers/logs.go
+++ b/pkg/bindings/containers/logs.go
@@ -46,7 +46,7 @@ func Logs(ctx context.Context, nameOrID string, opts LogOptions, stdoutChan, std
if opts.Stdout == nil && opts.Stderr == nil {
params.Set("stdout", strconv.FormatBool(true))
}
- response, err := conn.DoRequest(nil, http.MethodGet, "/containers/%s/logs", params, nameOrID)
+ response, err := conn.DoRequest(nil, http.MethodGet, "/containers/%s/logs", params, nil, nameOrID)
if err != nil {
return err
}
diff --git a/pkg/bindings/containers/mount.go b/pkg/bindings/containers/mount.go
index e0627d9a3..2d553142f 100644
--- a/pkg/bindings/containers/mount.go
+++ b/pkg/bindings/containers/mount.go
@@ -17,7 +17,7 @@ func Mount(ctx context.Context, nameOrID string) (string, error) {
var (
path string
)
- response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/mount", nil, nameOrID)
+ response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/mount", nil, nil, nameOrID)
if err != nil {
return path, err
}
@@ -31,7 +31,7 @@ func Unmount(ctx context.Context, nameOrID string) error {
if err != nil {
return err
}
- response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/unmount", nil, nameOrID)
+ response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/unmount", nil, nil, nameOrID)
if err != nil {
return err
}
@@ -45,7 +45,7 @@ func GetMountedContainerPaths(ctx context.Context) (map[string]string, error) {
return nil, err
}
mounts := make(map[string]string)
- response, err := conn.DoRequest(nil, http.MethodGet, "/containers/showmounted", nil)
+ response, err := conn.DoRequest(nil, http.MethodGet, "/containers/showmounted", nil, nil)
if err != nil {
return mounts, err
}
diff --git a/pkg/bindings/generate/generate.go b/pkg/bindings/generate/generate.go
index d3177133f..161b722f3 100644
--- a/pkg/bindings/generate/generate.go
+++ b/pkg/bindings/generate/generate.go
@@ -18,7 +18,7 @@ func GenerateKube(ctx context.Context, nameOrID string, options entities.Generat
params := url.Values{}
params.Set("service", strconv.FormatBool(options.Service))
- response, err := conn.DoRequest(nil, http.MethodGet, "/generate/%s/kube", params, nameOrID)
+ response, err := conn.DoRequest(nil, http.MethodGet, "/generate/%s/kube", params, nil, nameOrID)
if err != nil {
return nil, err
}
diff --git a/pkg/bindings/images/diff.go b/pkg/bindings/images/diff.go
index cfdd06a97..e2d344ea0 100644
--- a/pkg/bindings/images/diff.go
+++ b/pkg/bindings/images/diff.go
@@ -15,7 +15,7 @@ func Diff(ctx context.Context, nameOrId string) ([]archive.Change, error) {
return nil, err
}
- response, err := conn.DoRequest(nil, http.MethodGet, "/images/%s/changes", nil, nameOrId)
+ response, err := conn.DoRequest(nil, http.MethodGet, "/images/%s/changes", nil, nil, nameOrId)
if err != nil {
return nil, err
}
diff --git a/pkg/bindings/images/images.go b/pkg/bindings/images/images.go
index f9c02d199..e0802a6e1 100644
--- a/pkg/bindings/images/images.go
+++ b/pkg/bindings/images/images.go
@@ -12,6 +12,7 @@ import (
"github.com/containers/buildah"
"github.com/containers/image/v5/types"
"github.com/containers/libpod/pkg/api/handlers"
+ "github.com/containers/libpod/pkg/auth"
"github.com/containers/libpod/pkg/bindings"
"github.com/containers/libpod/pkg/domain/entities"
"github.com/docker/go-units"
@@ -26,7 +27,7 @@ func Exists(ctx context.Context, nameOrID string) (bool, error) {
if err != nil {
return false, err
}
- response, err := conn.DoRequest(nil, http.MethodGet, "/images/%s/exists", nil, nameOrID)
+ response, err := conn.DoRequest(nil, http.MethodGet, "/images/%s/exists", nil, nil, nameOrID)
if err != nil {
return false, err
}
@@ -52,7 +53,7 @@ func List(ctx context.Context, all *bool, filters map[string][]string) ([]*entit
}
params.Set("filters", strFilters)
}
- response, err := conn.DoRequest(nil, http.MethodGet, "/images/json", params)
+ response, err := conn.DoRequest(nil, http.MethodGet, "/images/json", params, nil)
if err != nil {
return imageSummary, err
}
@@ -71,7 +72,7 @@ func GetImage(ctx context.Context, nameOrID string, size *bool) (*entities.Image
params.Set("size", strconv.FormatBool(*size))
}
inspectedData := entities.ImageInspectReport{}
- response, err := conn.DoRequest(nil, http.MethodGet, "/images/%s/json", params, nameOrID)
+ response, err := conn.DoRequest(nil, http.MethodGet, "/images/%s/json", params, nil, nameOrID)
if err != nil {
return &inspectedData, err
}
@@ -89,7 +90,7 @@ func Tree(ctx context.Context, nameOrId string, whatRequires *bool) (*entities.I
if whatRequires != nil {
params.Set("size", strconv.FormatBool(*whatRequires))
}
- response, err := conn.DoRequest(nil, http.MethodGet, "/images/%s/tree", params, nameOrId)
+ response, err := conn.DoRequest(nil, http.MethodGet, "/images/%s/tree", params, nil, nameOrId)
if err != nil {
return nil, err
}
@@ -103,7 +104,7 @@ func History(ctx context.Context, nameOrID string) ([]*handlers.HistoryResponse,
if err != nil {
return nil, err
}
- response, err := conn.DoRequest(nil, http.MethodGet, "/images/%s/history", nil, nameOrID)
+ response, err := conn.DoRequest(nil, http.MethodGet, "/images/%s/history", nil, nil, nameOrID)
if err != nil {
return history, err
}
@@ -120,7 +121,7 @@ func Load(ctx context.Context, r io.Reader, name *string) (*entities.ImageLoadRe
if name != nil {
params.Set("reference", *name)
}
- response, err := conn.DoRequest(r, http.MethodPost, "/images/load", params)
+ response, err := conn.DoRequest(r, http.MethodPost, "/images/load", params, nil)
if err != nil {
return nil, err
}
@@ -141,7 +142,7 @@ func Export(ctx context.Context, nameOrID string, w io.Writer, format *string, c
if compress != nil {
params.Set("compress", strconv.FormatBool(*compress))
}
- response, err := conn.DoRequest(nil, http.MethodGet, "/images/%s/get", params, nameOrID)
+ response, err := conn.DoRequest(nil, http.MethodGet, "/images/%s/get", params, nil, nameOrID)
if err != nil {
return err
}
@@ -174,7 +175,7 @@ func Prune(ctx context.Context, all *bool, filters map[string][]string) ([]strin
}
params.Set("filters", stringFilter)
}
- response, err := conn.DoRequest(nil, http.MethodPost, "/images/prune", params)
+ response, err := conn.DoRequest(nil, http.MethodPost, "/images/prune", params, nil)
if err != nil {
return deleted, err
}
@@ -190,7 +191,7 @@ func Tag(ctx context.Context, nameOrID, tag, repo string) error {
params := url.Values{}
params.Set("tag", tag)
params.Set("repo", repo)
- response, err := conn.DoRequest(nil, http.MethodPost, "/images/%s/tag", params, nameOrID)
+ response, err := conn.DoRequest(nil, http.MethodPost, "/images/%s/tag", params, nil, nameOrID)
if err != nil {
return err
}
@@ -206,7 +207,7 @@ func Untag(ctx context.Context, nameOrID, tag, repo string) error {
params := url.Values{}
params.Set("tag", tag)
params.Set("repo", repo)
- response, err := conn.DoRequest(nil, http.MethodPost, "/images/%s/untag", params, nameOrID)
+ response, err := conn.DoRequest(nil, http.MethodPost, "/images/%s/untag", params, nil, nameOrID)
if err != nil {
return err
}
@@ -297,7 +298,7 @@ func Build(ctx context.Context, containerFiles []string, options entities.BuildO
}
// TODO outputs?
- response, err := conn.DoRequest(tarfile, http.MethodPost, "/build", params)
+ response, err := conn.DoRequest(tarfile, http.MethodPost, "/build", params, nil)
if err != nil {
return nil, err
}
@@ -341,7 +342,7 @@ func Import(ctx context.Context, changes []string, message, reference, u *string
if u != nil {
params.Set("url", *u)
}
- response, err := conn.DoRequest(r, http.MethodPost, "/images/import", params)
+ response, err := conn.DoRequest(r, http.MethodPost, "/images/import", params, nil)
if err != nil {
return nil, err
}
@@ -359,7 +360,6 @@ func Pull(ctx context.Context, rawImage string, options entities.ImagePullOption
}
params := url.Values{}
params.Set("reference", rawImage)
- params.Set("credentials", options.Credentials)
params.Set("overrideArch", options.OverrideArch)
params.Set("overrideOS", options.OverrideOS)
if options.SkipTLSVerify != types.OptionalBoolUndefined {
@@ -369,7 +369,13 @@ func Pull(ctx context.Context, rawImage string, options entities.ImagePullOption
}
params.Set("allTags", strconv.FormatBool(options.AllTags))
- response, err := conn.DoRequest(nil, http.MethodPost, "/images/pull", params)
+ // TODO: have a global system context we can pass around (1st argument)
+ header, err := auth.Header(nil, options.Authfile, options.Username, options.Password)
+ if err != nil {
+ return nil, err
+ }
+
+ response, err := conn.DoRequest(nil, http.MethodPost, "/images/pull", params, header)
if err != nil {
return nil, err
}
@@ -397,8 +403,14 @@ func Push(ctx context.Context, source string, destination string, options entiti
if err != nil {
return err
}
+
+ // TODO: have a global system context we can pass around (1st argument)
+ header, err := auth.Header(nil, options.Authfile, options.Username, options.Password)
+ if err != nil {
+ return err
+ }
+
params := url.Values{}
- params.Set("credentials", options.Credentials)
params.Set("destination", destination)
if options.SkipTLSVerify != types.OptionalBoolUndefined {
// Note: we have to verify if skipped is false.
@@ -407,8 +419,12 @@ func Push(ctx context.Context, source string, destination string, options entiti
}
path := fmt.Sprintf("/images/%s/push", source)
- _, err = conn.DoRequest(nil, http.MethodPost, path, params)
- return err
+ response, err := conn.DoRequest(nil, http.MethodPost, path, params, header)
+ if err != nil {
+ return err
+ }
+
+ return response.Process(err)
}
// Search is the binding for libpod's v2 endpoints for Search images.
@@ -430,7 +446,13 @@ func Search(ctx context.Context, term string, opts entities.ImageSearchOptions)
params.Set("tlsVerify", strconv.FormatBool(verifyTLS))
}
- response, err := conn.DoRequest(nil, http.MethodGet, "/images/search", params)
+ // TODO: have a global system context we can pass around (1st argument)
+ header, err := auth.Header(nil, opts.Authfile, "", "")
+ if err != nil {
+ return nil, err
+ }
+
+ response, err := conn.DoRequest(nil, http.MethodGet, "/images/search", params, header)
if err != nil {
return nil, err
}
diff --git a/pkg/bindings/images/rm.go b/pkg/bindings/images/rm.go
index 05aa3f9ca..c315bfce7 100644
--- a/pkg/bindings/images/rm.go
+++ b/pkg/bindings/images/rm.go
@@ -30,7 +30,7 @@ func BatchRemove(ctx context.Context, images []string, opts entities.ImageRemove
params.Add("images", i)
}
- response, err := conn.DoRequest(nil, http.MethodDelete, "/images/remove", params)
+ response, err := conn.DoRequest(nil, http.MethodDelete, "/images/remove", params, nil)
if err != nil {
return nil, []error{err}
}
@@ -52,7 +52,7 @@ func Remove(ctx context.Context, nameOrID string, force bool) (*entities.ImageRe
params := url.Values{}
params.Set("force", strconv.FormatBool(force))
- response, err := conn.DoRequest(nil, http.MethodDelete, "/images/%s", params, nameOrID)
+ response, err := conn.DoRequest(nil, http.MethodDelete, "/images/%s", params, nil, nameOrID)
if err != nil {
return nil, err
}
diff --git a/pkg/bindings/manifests/manifests.go b/pkg/bindings/manifests/manifests.go
index f5ee31d93..e89624667 100644
--- a/pkg/bindings/manifests/manifests.go
+++ b/pkg/bindings/manifests/manifests.go
@@ -39,7 +39,7 @@ func Create(ctx context.Context, names, images []string, all *bool) (string, err
params.Add("image", i)
}
- response, err := conn.DoRequest(nil, http.MethodPost, "/manifests/create", params)
+ response, err := conn.DoRequest(nil, http.MethodPost, "/manifests/create", params, nil)
if err != nil {
return "", err
}
@@ -53,7 +53,7 @@ func Inspect(ctx context.Context, name string) (*manifest.Schema2List, error) {
if err != nil {
return nil, err
}
- response, err := conn.DoRequest(nil, http.MethodGet, "/manifests/%s/json", nil, name)
+ response, err := conn.DoRequest(nil, http.MethodGet, "/manifests/%s/json", nil, nil, name)
if err != nil {
return nil, err
}
@@ -73,7 +73,7 @@ func Add(ctx context.Context, name string, options image.ManifestAddOpts) (strin
return "", err
}
stringReader := strings.NewReader(optionsString)
- response, err := conn.DoRequest(stringReader, http.MethodPost, "/manifests/%s/add", nil, name)
+ response, err := conn.DoRequest(stringReader, http.MethodPost, "/manifests/%s/add", nil, nil, name)
if err != nil {
return "", err
}
@@ -90,7 +90,7 @@ func Remove(ctx context.Context, name, digest string) (string, error) {
}
params := url.Values{}
params.Set("digest", digest)
- response, err := conn.DoRequest(nil, http.MethodDelete, "/manifests/%s", params, name)
+ response, err := conn.DoRequest(nil, http.MethodDelete, "/manifests/%s", params, nil, name)
if err != nil {
return "", err
}
@@ -118,7 +118,7 @@ func Push(ctx context.Context, name string, destination *string, all *bool) (str
if all != nil {
params.Set("all", strconv.FormatBool(*all))
}
- _, err = conn.DoRequest(nil, http.MethodPost, "/manifests/%s/push", params, name)
+ _, err = conn.DoRequest(nil, http.MethodPost, "/manifests/%s/push", params, nil, name)
if err != nil {
return "", err
}
diff --git a/pkg/bindings/network/network.go b/pkg/bindings/network/network.go
index 7bba4f478..34881b524 100644
--- a/pkg/bindings/network/network.go
+++ b/pkg/bindings/network/network.go
@@ -28,7 +28,7 @@ func Create(ctx context.Context, options entities.NetworkCreateOptions, name *st
return nil, err
}
stringReader := strings.NewReader(networkConfig)
- response, err := conn.DoRequest(stringReader, http.MethodPost, "/networks/create", params)
+ response, err := conn.DoRequest(stringReader, http.MethodPost, "/networks/create", params, nil)
if err != nil {
return nil, err
}
@@ -42,7 +42,7 @@ func Inspect(ctx context.Context, nameOrID string) ([]entities.NetworkInspectRep
if err != nil {
return nil, err
}
- response, err := conn.DoRequest(nil, http.MethodGet, "/networks/%s/json", nil, nameOrID)
+ response, err := conn.DoRequest(nil, http.MethodGet, "/networks/%s/json", nil, nil, nameOrID)
if err != nil {
return nil, err
}
@@ -62,7 +62,7 @@ func Remove(ctx context.Context, nameOrID string, force *bool) ([]*entities.Netw
if force != nil {
params.Set("size", strconv.FormatBool(*force))
}
- response, err := conn.DoRequest(nil, http.MethodDelete, "/networks/%s", params, nameOrID)
+ response, err := conn.DoRequest(nil, http.MethodDelete, "/networks/%s", params, nil, nameOrID)
if err != nil {
return nil, err
}
@@ -78,7 +78,7 @@ func List(ctx context.Context) ([]*entities.NetworkListReport, error) {
if err != nil {
return nil, err
}
- response, err := conn.DoRequest(nil, http.MethodGet, "/networks/json", nil)
+ response, err := conn.DoRequest(nil, http.MethodGet, "/networks/json", nil, nil)
if err != nil {
return netList, err
}
diff --git a/pkg/bindings/play/play.go b/pkg/bindings/play/play.go
index 653558a3c..288cca454 100644
--- a/pkg/bindings/play/play.go
+++ b/pkg/bindings/play/play.go
@@ -8,6 +8,7 @@ import (
"strconv"
"github.com/containers/image/v5/types"
+ "github.com/containers/libpod/pkg/auth"
"github.com/containers/libpod/pkg/bindings"
"github.com/containers/libpod/pkg/domain/entities"
)
@@ -31,7 +32,13 @@ func PlayKube(ctx context.Context, path string, options entities.PlayKubeOptions
params.Set("tlsVerify", strconv.FormatBool(options.SkipTLSVerify == types.OptionalBoolTrue))
}
- response, err := conn.DoRequest(f, http.MethodPost, "/play/kube", params)
+ // TODO: have a global system context we can pass around (1st argument)
+ header, err := auth.Header(nil, options.Authfile, options.Username, options.Password)
+ if err != nil {
+ return nil, err
+ }
+
+ response, err := conn.DoRequest(f, http.MethodPost, "/play/kube", params, header)
if err != nil {
return nil, err
}
diff --git a/pkg/bindings/pods/pods.go b/pkg/bindings/pods/pods.go
index b213c8c73..fb273fdf3 100644
--- a/pkg/bindings/pods/pods.go
+++ b/pkg/bindings/pods/pods.go
@@ -28,7 +28,7 @@ func CreatePodFromSpec(ctx context.Context, s *specgen.PodSpecGenerator) (*entit
return nil, err
}
stringReader := strings.NewReader(specgenString)
- response, err := conn.DoRequest(stringReader, http.MethodPost, "/pods/create", nil)
+ response, err := conn.DoRequest(stringReader, http.MethodPost, "/pods/create", nil, nil)
if err != nil {
return nil, err
}
@@ -41,7 +41,7 @@ func Exists(ctx context.Context, nameOrID string) (bool, error) {
if err != nil {
return false, err
}
- response, err := conn.DoRequest(nil, http.MethodGet, "/pods/%s/exists", nil, nameOrID)
+ response, err := conn.DoRequest(nil, http.MethodGet, "/pods/%s/exists", nil, nil, nameOrID)
if err != nil {
return false, err
}
@@ -57,7 +57,7 @@ func Inspect(ctx context.Context, nameOrID string) (*entities.PodInspectReport,
if err != nil {
return nil, err
}
- response, err := conn.DoRequest(nil, http.MethodGet, "/pods/%s/json", nil, nameOrID)
+ response, err := conn.DoRequest(nil, http.MethodGet, "/pods/%s/json", nil, nil, nameOrID)
if err != nil {
return nil, err
}
@@ -78,7 +78,7 @@ func Kill(ctx context.Context, nameOrID string, signal *string) (*entities.PodKi
if signal != nil {
params.Set("signal", *signal)
}
- response, err := conn.DoRequest(nil, http.MethodPost, "/pods/%s/kill", params, nameOrID)
+ response, err := conn.DoRequest(nil, http.MethodPost, "/pods/%s/kill", params, nil, nameOrID)
if err != nil {
return nil, err
}
@@ -92,7 +92,7 @@ func Pause(ctx context.Context, nameOrID string) (*entities.PodPauseReport, erro
if err != nil {
return nil, err
}
- response, err := conn.DoRequest(nil, http.MethodPost, "/pods/%s/pause", nil, nameOrID)
+ response, err := conn.DoRequest(nil, http.MethodPost, "/pods/%s/pause", nil, nil, nameOrID)
if err != nil {
return nil, err
}
@@ -107,7 +107,7 @@ func Prune(ctx context.Context) ([]*entities.PodPruneReport, error) {
if err != nil {
return nil, err
}
- response, err := conn.DoRequest(nil, http.MethodPost, "/pods/prune", nil)
+ response, err := conn.DoRequest(nil, http.MethodPost, "/pods/prune", nil, nil)
if err != nil {
return nil, err
}
@@ -132,7 +132,7 @@ func List(ctx context.Context, filters map[string][]string) ([]*entities.ListPod
}
params.Set("filters", stringFilter)
}
- response, err := conn.DoRequest(nil, http.MethodGet, "/pods/json", params)
+ response, err := conn.DoRequest(nil, http.MethodGet, "/pods/json", params, nil)
if err != nil {
return podsReports, err
}
@@ -146,7 +146,7 @@ func Restart(ctx context.Context, nameOrID string) (*entities.PodRestartReport,
if err != nil {
return nil, err
}
- response, err := conn.DoRequest(nil, http.MethodPost, "/pods/%s/restart", nil, nameOrID)
+ response, err := conn.DoRequest(nil, http.MethodPost, "/pods/%s/restart", nil, nil, nameOrID)
if err != nil {
return nil, err
}
@@ -165,7 +165,7 @@ func Remove(ctx context.Context, nameOrID string, force *bool) (*entities.PodRmR
if force != nil {
params.Set("force", strconv.FormatBool(*force))
}
- response, err := conn.DoRequest(nil, http.MethodDelete, "/pods/%s", params, nameOrID)
+ response, err := conn.DoRequest(nil, http.MethodDelete, "/pods/%s", params, nil, nameOrID)
if err != nil {
return nil, err
}
@@ -179,7 +179,7 @@ func Start(ctx context.Context, nameOrID string) (*entities.PodStartReport, erro
if err != nil {
return nil, err
}
- response, err := conn.DoRequest(nil, http.MethodPost, "/pods/%s/start", nil, nameOrID)
+ response, err := conn.DoRequest(nil, http.MethodPost, "/pods/%s/start", nil, nil, nameOrID)
if err != nil {
return nil, err
}
@@ -202,7 +202,7 @@ func Stop(ctx context.Context, nameOrID string, timeout *int) (*entities.PodStop
if timeout != nil {
params.Set("t", strconv.Itoa(*timeout))
}
- response, err := conn.DoRequest(nil, http.MethodPost, "/pods/%s/stop", params, nameOrID)
+ response, err := conn.DoRequest(nil, http.MethodPost, "/pods/%s/stop", params, nil, nameOrID)
if err != nil {
return nil, err
}
@@ -226,7 +226,7 @@ func Top(ctx context.Context, nameOrID string, descriptors []string) ([]string,
// flatten the slice into one string
params.Set("ps_args", strings.Join(descriptors, ","))
}
- response, err := conn.DoRequest(nil, http.MethodGet, "/pods/%s/top", params, nameOrID)
+ response, err := conn.DoRequest(nil, http.MethodGet, "/pods/%s/top", params, nil, nameOrID)
if err != nil {
return nil, err
}
@@ -254,7 +254,7 @@ func Unpause(ctx context.Context, nameOrID string) (*entities.PodUnpauseReport,
if err != nil {
return nil, err
}
- response, err := conn.DoRequest(nil, http.MethodPost, "/pods/%s/unpause", nil, nameOrID)
+ response, err := conn.DoRequest(nil, http.MethodPost, "/pods/%s/unpause", nil, nil, nameOrID)
if err != nil {
return nil, err
}
@@ -277,7 +277,7 @@ func Stats(ctx context.Context, namesOrIDs []string, options entities.PodStatsOp
params.Set("all", strconv.FormatBool(options.All))
var reports []*entities.PodStatsReport
- response, err := conn.DoRequest(nil, http.MethodGet, "/pods/stats", params)
+ response, err := conn.DoRequest(nil, http.MethodGet, "/pods/stats", params, nil)
if err != nil {
return nil, err
}
diff --git a/pkg/bindings/system/info.go b/pkg/bindings/system/info.go
index 13e12645d..8ad704f84 100644
--- a/pkg/bindings/system/info.go
+++ b/pkg/bindings/system/info.go
@@ -15,7 +15,7 @@ func Info(ctx context.Context) (*define.Info, error) {
if err != nil {
return nil, err
}
- response, err := conn.DoRequest(nil, http.MethodGet, "/info", nil)
+ response, err := conn.DoRequest(nil, http.MethodGet, "/info", nil, nil)
if err != nil {
return nil, err
}
diff --git a/pkg/bindings/system/system.go b/pkg/bindings/system/system.go
index 2cd894228..010762bef 100644
--- a/pkg/bindings/system/system.go
+++ b/pkg/bindings/system/system.go
@@ -42,7 +42,7 @@ func Events(ctx context.Context, eventChan chan entities.Event, cancelChan chan
}
params.Set("filters", filterString)
}
- response, err := conn.DoRequest(nil, http.MethodGet, "/events", params)
+ response, err := conn.DoRequest(nil, http.MethodGet, "/events", params, nil)
if err != nil {
return err
}
@@ -89,7 +89,7 @@ func Prune(ctx context.Context, all, volumes *bool) (*entities.SystemPruneReport
if volumes != nil {
params.Set("Volumes", strconv.FormatBool(*volumes))
}
- response, err := conn.DoRequest(nil, http.MethodPost, "/system/prune", params)
+ response, err := conn.DoRequest(nil, http.MethodPost, "/system/prune", params, nil)
if err != nil {
return nil, err
}
@@ -110,7 +110,7 @@ func Version(ctx context.Context) (*entities.SystemVersionReport, error) {
if err != nil {
return nil, err
}
- response, err := conn.DoRequest(nil, http.MethodGet, "/version", nil)
+ response, err := conn.DoRequest(nil, http.MethodGet, "/version", nil, nil)
if err != nil {
return nil, err
}
@@ -139,7 +139,7 @@ func DiskUsage(ctx context.Context) (*entities.SystemDfReport, error) {
if err != nil {
return nil, err
}
- response, err := conn.DoRequest(nil, http.MethodGet, "/system/df", nil)
+ response, err := conn.DoRequest(nil, http.MethodGet, "/system/df", nil, nil)
if err != nil {
return nil, err
}
diff --git a/pkg/bindings/test/auth_test.go b/pkg/bindings/test/auth_test.go
new file mode 100644
index 000000000..fdb190551
--- /dev/null
+++ b/pkg/bindings/test/auth_test.go
@@ -0,0 +1,143 @@
+package test_bindings
+
+import (
+ "io/ioutil"
+ "os"
+ "time"
+
+ "github.com/containers/common/pkg/auth"
+ "github.com/containers/image/v5/types"
+ podmanRegistry "github.com/containers/libpod/hack/podman-registry-go"
+ "github.com/containers/libpod/pkg/bindings/images"
+ "github.com/containers/libpod/pkg/domain/entities"
+ . "github.com/onsi/ginkgo"
+ . "github.com/onsi/gomega"
+ "github.com/onsi/gomega/gexec"
+)
+
+var _ = Describe("Podman images", func() {
+ var (
+ registry *podmanRegistry.Registry
+ bt *bindingTest
+ s *gexec.Session
+ err error
+ )
+
+ BeforeEach(func() {
+ // Note: we need to start the registry **before** setting up
+ // the test. Otherwise, the registry is not reachable for
+ // currently unknown reasons.
+ registry, err = podmanRegistry.Start()
+ Expect(err).To(BeNil())
+
+ bt = newBindingTest()
+ bt.RestoreImagesFromCache()
+ s = bt.startAPIService()
+ time.Sleep(1 * time.Second)
+ err := bt.NewConnection()
+ Expect(err).To(BeNil())
+ })
+
+ AfterEach(func() {
+ s.Kill()
+ bt.cleanup()
+ registry.Stop()
+ })
+
+ // Test using credentials.
+ It("tag + push + pull (with credentials)", func() {
+
+ imageRep := "localhost:" + registry.Port + "/test"
+ imageTag := "latest"
+ imageRef := imageRep + ":" + imageTag
+
+ // Tag the alpine image and verify it has worked.
+ err = images.Tag(bt.conn, alpine.shortName, imageTag, imageRep)
+ Expect(err).To(BeNil())
+ _, err = images.GetImage(bt.conn, imageRef, nil)
+ Expect(err).To(BeNil())
+
+ // Now push the image.
+ pushOpts := entities.ImagePushOptions{
+ Username: registry.User,
+ Password: registry.Password,
+ SkipTLSVerify: types.OptionalBoolTrue,
+ }
+ err = images.Push(bt.conn, imageRef, imageRef, pushOpts)
+ Expect(err).To(BeNil())
+
+ // Now pull the image.
+ pullOpts := entities.ImagePullOptions{
+ Username: registry.User,
+ Password: registry.Password,
+ SkipTLSVerify: types.OptionalBoolTrue,
+ }
+ _, err = images.Pull(bt.conn, imageRef, pullOpts)
+ Expect(err).To(BeNil())
+ })
+
+ // Test using authfile.
+ It("tag + push + pull + search (with authfile)", func() {
+
+ imageRep := "localhost:" + registry.Port + "/test"
+ imageTag := "latest"
+ imageRef := imageRep + ":" + imageTag
+
+ // Create a temporary authentication file.
+ tmpFile, err := ioutil.TempFile("", "auth.json.")
+ Expect(err).To(BeNil())
+ _, err = tmpFile.Write([]byte{'{', '}'})
+ Expect(err).To(BeNil())
+ err = tmpFile.Close()
+ Expect(err).To(BeNil())
+
+ authFilePath := tmpFile.Name()
+
+ // Now login to a) test the credentials and to b) store them in
+ // the authfile for later use.
+ sys := types.SystemContext{
+ AuthFilePath: authFilePath,
+ DockerInsecureSkipTLSVerify: types.OptionalBoolTrue,
+ }
+ loginOptions := auth.LoginOptions{
+ Username: registry.User,
+ Password: registry.Password,
+ AuthFile: authFilePath,
+ Stdin: os.Stdin,
+ Stdout: os.Stdout,
+ }
+ err = auth.Login(bt.conn, &sys, &loginOptions, []string{imageRep})
+ Expect(err).To(BeNil())
+
+ // Tag the alpine image and verify it has worked.
+ err = images.Tag(bt.conn, alpine.shortName, imageTag, imageRep)
+ Expect(err).To(BeNil())
+ _, err = images.GetImage(bt.conn, imageRef, nil)
+ Expect(err).To(BeNil())
+
+ // Now push the image.
+ pushOpts := entities.ImagePushOptions{
+ Authfile: authFilePath,
+ SkipTLSVerify: types.OptionalBoolTrue,
+ }
+ err = images.Push(bt.conn, imageRef, imageRef, pushOpts)
+ Expect(err).To(BeNil())
+
+ // Now pull the image.
+ pullOpts := entities.ImagePullOptions{
+ Authfile: authFilePath,
+ SkipTLSVerify: types.OptionalBoolTrue,
+ }
+ _, err = images.Pull(bt.conn, imageRef, pullOpts)
+ Expect(err).To(BeNil())
+
+ // Last, but not least, exercise search.
+ searchOptions := entities.ImageSearchOptions{
+ Authfile: authFilePath,
+ SkipTLSVerify: types.OptionalBoolTrue,
+ }
+ _, err = images.Search(bt.conn, imageRef, searchOptions)
+ Expect(err).To(BeNil())
+ })
+
+})
diff --git a/pkg/bindings/volumes/volumes.go b/pkg/bindings/volumes/volumes.go
index cef9246cb..ebe19794a 100644
--- a/pkg/bindings/volumes/volumes.go
+++ b/pkg/bindings/volumes/volumes.go
@@ -26,7 +26,7 @@ func Create(ctx context.Context, config entities.VolumeCreateOptions) (*entities
return nil, err
}
stringReader := strings.NewReader(createString)
- response, err := conn.DoRequest(stringReader, http.MethodPost, "/volumes/create", nil)
+ response, err := conn.DoRequest(stringReader, http.MethodPost, "/volumes/create", nil, nil)
if err != nil {
return nil, err
}
@@ -42,7 +42,7 @@ func Inspect(ctx context.Context, nameOrID string) (*entities.VolumeConfigRespon
if err != nil {
return nil, err
}
- response, err := conn.DoRequest(nil, http.MethodGet, "/volumes/%s/json", nil, nameOrID)
+ response, err := conn.DoRequest(nil, http.MethodGet, "/volumes/%s/json", nil, nil, nameOrID)
if err != nil {
return &inspect, err
}
@@ -67,7 +67,7 @@ func List(ctx context.Context, filters map[string][]string) ([]*entities.VolumeL
}
params.Set("filters", strFilters)
}
- response, err := conn.DoRequest(nil, http.MethodGet, "/volumes/json", params)
+ response, err := conn.DoRequest(nil, http.MethodGet, "/volumes/json", params, nil)
if err != nil {
return vols, err
}
@@ -83,7 +83,7 @@ func Prune(ctx context.Context) ([]*entities.VolumePruneReport, error) {
if err != nil {
return nil, err
}
- response, err := conn.DoRequest(nil, http.MethodPost, "/volumes/prune", nil)
+ response, err := conn.DoRequest(nil, http.MethodPost, "/volumes/prune", nil, nil)
if err != nil {
return nil, err
}
@@ -101,7 +101,7 @@ func Remove(ctx context.Context, nameOrID string, force *bool) error {
if force != nil {
params.Set("force", strconv.FormatBool(*force))
}
- response, err := conn.DoRequest(nil, http.MethodDelete, "/volumes/%s", params, nameOrID)
+ response, err := conn.DoRequest(nil, http.MethodDelete, "/volumes/%s", params, nil, nameOrID)
if err != nil {
return err
}
diff --git a/pkg/domain/entities/engine.go b/pkg/domain/entities/engine.go
index 265c9f36f..db58befa5 100644
--- a/pkg/domain/entities/engine.go
+++ b/pkg/domain/entities/engine.go
@@ -37,19 +37,20 @@ type PodmanConfig struct {
*config.Config
*pflag.FlagSet
- CGroupUsage string // rootless code determines Usage message
- ConmonPath string // --conmon flag will set Engine.ConmonPath
- CpuProfile string // Hidden: Should CPU profile be taken
- EngineMode EngineMode // ABI or Tunneling mode
- Identities []string // ssh identities for connecting to server
- MaxWorks int // maximum number of parallel threads
- RuntimePath string // --runtime flag will set Engine.RuntimePath
- SpanCloser io.Closer // Close() for tracing object
- SpanCtx context.Context // context to use when tracing
- Span opentracing.Span // tracing object
- Syslog bool // write to StdOut and Syslog, not supported when tunneling
- Trace bool // Hidden: Trace execution
- Uri string // URI to API Service
+ CGroupUsage string // rootless code determines Usage message
+ ConmonPath string // --conmon flag will set Engine.ConmonPath
+ CpuProfile string // Hidden: Should CPU profile be taken
+ EngineMode EngineMode // ABI or Tunneling mode
+ Identities []string // ssh identities for connecting to server
+ MaxWorks int // maximum number of parallel threads
+ RegistriesConf string // allows for specifying a custom registries.conf
+ RuntimePath string // --runtime flag will set Engine.RuntimePath
+ SpanCloser io.Closer // Close() for tracing object
+ SpanCtx context.Context // context to use when tracing
+ Span opentracing.Span // tracing object
+ Syslog bool // write to StdOut and Syslog, not supported when tunneling
+ Trace bool // Hidden: Trace execution
+ Uri string // URI to API Service
Runroot string
StorageDriver string
diff --git a/pkg/domain/entities/images.go b/pkg/domain/entities/images.go
index 968bcff3b..19a2c87f5 100644
--- a/pkg/domain/entities/images.go
+++ b/pkg/domain/entities/images.go
@@ -128,9 +128,10 @@ type ImagePullOptions struct {
// CertDir is the path to certificate directories. Ignored for remote
// calls.
CertDir string
- // Credentials for authenticating against the registry in the format
- // USERNAME:PASSWORD.
- Credentials string
+ // Username for authenticating against the registry.
+ Username string
+ // Password for authenticating against the registry.
+ Password string
// OverrideArch will overwrite the local architecture for image pulls.
OverrideArch string
// OverrideOS will overwrite the local operating system (OS) for image
@@ -162,9 +163,10 @@ type ImagePushOptions struct {
// transport. Default is same compression type as source. Ignored for remote
// calls.
Compress bool
- // Credentials for authenticating against the registry in the format
- // USERNAME:PASSWORD.
- Credentials string
+ // Username for authenticating against the registry.
+ Username string
+ // Password for authenticating against the registry.
+ Password string
// DigestFile, after copying the image, write the digest of the resulting
// image to the file. Ignored for remote calls.
DigestFile string
diff --git a/pkg/domain/entities/manifest.go b/pkg/domain/entities/manifest.go
index 273052bb9..853619b19 100644
--- a/pkg/domain/entities/manifest.go
+++ b/pkg/domain/entities/manifest.go
@@ -1,5 +1,9 @@
package entities
+import "github.com/containers/image/v5/types"
+
+// TODO: add comments to *all* types and fields.
+
type ManifestCreateOptions struct {
All bool `schema:"all"`
}
@@ -26,6 +30,9 @@ type ManifestAnnotateOptions struct {
}
type ManifestPushOptions struct {
- Purge, Quiet, All, TlsVerify, RemoveSignatures bool
- Authfile, CertDir, Creds, DigestFile, Format, SignBy string
+ Purge, Quiet, All, RemoveSignatures bool
+
+ Authfile, CertDir, Username, Password, DigestFile, Format, SignBy string
+
+ SkipTLSVerify types.OptionalBool
}
diff --git a/pkg/domain/entities/play.go b/pkg/domain/entities/play.go
index 93864c23b..4f485cbee 100644
--- a/pkg/domain/entities/play.go
+++ b/pkg/domain/entities/play.go
@@ -8,9 +8,10 @@ type PlayKubeOptions struct {
Authfile string
// CertDir - to a directory containing TLS certifications and keys.
CertDir string
- // Credentials - `username:password` for authentication against a
- // container registry.
- Credentials string
+ // Username for authenticating against the registry.
+ Username string
+ // Password for authenticating against the registry.
+ Password string
// Network - name of the CNI network to connect to.
Network string
// Quiet - suppress output when pulling images.
diff --git a/pkg/domain/entities/system.go b/pkg/domain/entities/system.go
index 5e4760d12..79a90be48 100644
--- a/pkg/domain/entities/system.go
+++ b/pkg/domain/entities/system.go
@@ -97,3 +97,9 @@ type SystemVersionReport struct {
type ComponentVersion struct {
types.Version
}
+
+// ListRegistriesReport is the report when querying for a sorted list of
+// registries which may be contacted during certain operations.
+type ListRegistriesReport struct {
+ Registries []string
+}
diff --git a/pkg/domain/infra/abi/images.go b/pkg/domain/infra/abi/images.go
index 6e774df8e..d8af4d339 100644
--- a/pkg/domain/infra/abi/images.go
+++ b/pkg/domain/infra/abi/images.go
@@ -121,12 +121,11 @@ func (ir *ImageEngine) Pull(ctx context.Context, rawImage string, options entiti
}
var registryCreds *types.DockerAuthConfig
- if options.Credentials != "" {
- creds, err := util.ParseRegistryCreds(options.Credentials)
- if err != nil {
- return nil, err
+ if len(options.Username) > 0 && len(options.Password) > 0 {
+ registryCreds = &types.DockerAuthConfig{
+ Username: options.Username,
+ Password: options.Password,
}
- registryCreds = creds
}
dockerRegistryOptions := image.DockerRegistryOptions{
DockerRegistryCreds: registryCreds,
@@ -226,12 +225,11 @@ func (ir *ImageEngine) Push(ctx context.Context, source string, destination stri
}
var registryCreds *types.DockerAuthConfig
- if options.Credentials != "" {
- creds, err := util.ParseRegistryCreds(options.Credentials)
- if err != nil {
- return err
+ if len(options.Username) > 0 && len(options.Password) > 0 {
+ registryCreds = &types.DockerAuthConfig{
+ Username: options.Username,
+ Password: options.Password,
}
- registryCreds = creds
}
dockerRegistryOptions := image.DockerRegistryOptions{
DockerRegistryCreds: registryCreds,
diff --git a/pkg/domain/infra/abi/manifest.go b/pkg/domain/infra/abi/manifest.go
index fca34dda2..6e311dec7 100644
--- a/pkg/domain/infra/abi/manifest.go
+++ b/pkg/domain/infra/abi/manifest.go
@@ -16,6 +16,7 @@ import (
"github.com/containers/image/v5/docker"
"github.com/containers/image/v5/manifest"
"github.com/containers/image/v5/transports/alltransports"
+ "github.com/containers/image/v5/types"
libpodImage "github.com/containers/libpod/libpod/image"
"github.com/containers/libpod/pkg/domain/entities"
"github.com/containers/libpod/pkg/util"
@@ -179,12 +180,28 @@ func (ir *ImageEngine) ManifestPush(ctx context.Context, names []string, opts en
case "v2s2", "docker":
manifestType = manifest.DockerV2Schema2MediaType
default:
- return errors.Errorf("unknown format %q. Choose on of the supported formats: 'oci' or 'v2s2'", opts.Format)
+ return errors.Errorf("unknown format %q. Choose one of the supported formats: 'oci' or 'v2s2'", opts.Format)
}
}
+
+ // Set the system context.
+ sys := ir.Libpod.SystemContext()
+ if sys != nil {
+ sys = &types.SystemContext{}
+ }
+ sys.AuthFilePath = opts.Authfile
+ sys.DockerInsecureSkipTLSVerify = opts.SkipTLSVerify
+
+ if opts.Username != "" && opts.Password != "" {
+ sys.DockerAuthConfig = &types.DockerAuthConfig{
+ Username: opts.Username,
+ Password: opts.Password,
+ }
+ }
+
options := manifests.PushOptions{
Store: ir.Libpod.GetStore(),
- SystemContext: ir.Libpod.SystemContext(),
+ SystemContext: sys,
ImageListSelection: cp.CopySpecificImages,
Instances: nil,
RemoveSignatures: opts.RemoveSignatures,
diff --git a/pkg/domain/infra/abi/play.go b/pkg/domain/infra/abi/play.go
index cd7eec7e6..6d0919d2b 100644
--- a/pkg/domain/infra/abi/play.go
+++ b/pkg/domain/infra/abi/play.go
@@ -56,6 +56,9 @@ func (ic *ContainerEngine) PlayKube(ctx context.Context, path string, options en
return nil, errors.Wrapf(err, "unable to read %q as YAML", path)
}
+ // NOTE: pkg/bindings/play is also parsing the file.
+ // A pkg/kube would be nice to refactor and abstract
+ // parts of the K8s-related code.
if podYAML.Kind != "Pod" {
return nil, errors.Errorf("invalid YAML kind: %q. Pod is the only supported Kubernetes YAML kind", podYAML.Kind)
}
@@ -147,6 +150,13 @@ func (ic *ContainerEngine) PlayKube(ctx context.Context, path string, options en
writer = os.Stderr
}
+ if len(options.Username) > 0 && len(options.Password) > 0 {
+ registryCreds = &types.DockerAuthConfig{
+ Username: options.Username,
+ Password: options.Password,
+ }
+ }
+
dockerRegistryOptions := image.DockerRegistryOptions{
DockerRegistryCreds: registryCreds,
DockerCertPath: options.CertDir,
diff --git a/pkg/domain/infra/runtime_libpod.go b/pkg/domain/infra/runtime_libpod.go
index 7c9180d43..a57eadc63 100644
--- a/pkg/domain/infra/runtime_libpod.go
+++ b/pkg/domain/infra/runtime_libpod.go
@@ -213,6 +213,9 @@ func getRuntime(ctx context.Context, fs *flag.FlagSet, opts *engineOpts) (*libpo
if fs.Changed("hooks-dir") {
options = append(options, libpod.WithHooksDir(cfg.Engine.HooksDir...))
}
+ if fs.Changed("registries-conf") {
+ options = append(options, libpod.WithRegistriesConf(cfg.RegistriesConf))
+ }
// TODO flag to set CNI plugins dir?