Bläddra i källkod

Implement docker push with standalone client lib.

Signed-off-by: David Calavera <david.calavera@gmail.com>
David Calavera 9 år sedan
förälder
incheckning
42670e30ee
5 ändrade filer med 71 tillägg och 12 borttagningar
  1. 1 0
      api/client/client.go
  2. 36 0
      api/client/lib/image_push.go
  3. 27 6
      api/client/push.go
  4. 4 6
      api/client/trust.go
  5. 3 0
      api/types/client.go

+ 1 - 0
api/client/client.go

@@ -50,6 +50,7 @@ type apiClient interface {
 	ImageList(options types.ImageListOptions) ([]types.Image, error)
 	ImageList(options types.ImageListOptions) ([]types.Image, error)
 	ImageLoad(input io.Reader) (io.ReadCloser, error)
 	ImageLoad(input io.Reader) (io.ReadCloser, error)
 	ImagePull(options types.ImagePullOptions, privilegeFunc lib.RequestPrivilegeFunc) (io.ReadCloser, error)
 	ImagePull(options types.ImagePullOptions, privilegeFunc lib.RequestPrivilegeFunc) (io.ReadCloser, error)
+	ImagePush(options types.ImagePushOptions, privilegeFunc lib.RequestPrivilegeFunc) (io.ReadCloser, error)
 	ImageRemove(options types.ImageRemoveOptions) ([]types.ImageDelete, error)
 	ImageRemove(options types.ImageRemoveOptions) ([]types.ImageDelete, error)
 	ImageSave(imageIDs []string) (io.ReadCloser, error)
 	ImageSave(imageIDs []string) (io.ReadCloser, error)
 	ImageTag(options types.ImageTagOptions) error
 	ImageTag(options types.ImageTagOptions) error

+ 36 - 0
api/client/lib/image_push.go

@@ -0,0 +1,36 @@
+package lib
+
+import (
+	"io"
+	"net/http"
+	"net/url"
+
+	"github.com/docker/docker/api/types"
+)
+
+// ImagePush request the docker host to push an image to a remote registry.
+// It executes the privileged function if the operation is unauthorized
+// and it tries one more time.
+// It's up to the caller to handle the io.ReadCloser and close it properly.
+func (cli *Client) ImagePush(options types.ImagePushOptions, privilegeFunc RequestPrivilegeFunc) (io.ReadCloser, error) {
+	query := url.Values{}
+	query.Set("tag", options.Tag)
+
+	resp, err := cli.tryImagePush(options.ImageID, query, options.RegistryAuth)
+	if resp.statusCode == http.StatusUnauthorized {
+		newAuthHeader, privilegeErr := privilegeFunc()
+		if privilegeErr != nil {
+			return nil, privilegeErr
+		}
+		resp, err = cli.tryImagePush(options.ImageID, query, newAuthHeader)
+	}
+	if err != nil {
+		return nil, err
+	}
+	return resp.body, nil
+}
+
+func (cli *Client) tryImagePush(imageID string, query url.Values, registryAuth string) (*serverResponse, error) {
+	headers := map[string][]string{"X-Registry-Auth": {registryAuth}}
+	return cli.post("/images/"+imageID+"/push", query, nil, headers)
+}

+ 27 - 6
api/client/push.go

@@ -3,10 +3,14 @@ package client
 import (
 import (
 	"errors"
 	"errors"
 	"fmt"
 	"fmt"
-	"net/url"
+	"io"
 
 
 	"github.com/docker/distribution/reference"
 	"github.com/docker/distribution/reference"
+	"github.com/docker/docker/api/client/lib"
+	"github.com/docker/docker/api/types"
 	Cli "github.com/docker/docker/cli"
 	Cli "github.com/docker/docker/cli"
+	"github.com/docker/docker/cliconfig"
+	"github.com/docker/docker/pkg/jsonmessage"
 	flag "github.com/docker/docker/pkg/mflag"
 	flag "github.com/docker/docker/pkg/mflag"
 	"github.com/docker/docker/registry"
 	"github.com/docker/docker/registry"
 )
 )
@@ -53,13 +57,30 @@ func (cli *DockerCli) CmdPush(args ...string) error {
 		return fmt.Errorf("You cannot push a \"root\" repository. Please rename your repository to <user>/<repo> (ex: %s/%s)", username, repoInfo.LocalName)
 		return fmt.Errorf("You cannot push a \"root\" repository. Please rename your repository to <user>/<repo> (ex: %s/%s)", username, repoInfo.LocalName)
 	}
 	}
 
 
+	requestPrivilege := cli.registryAuthenticationPrivilegedFunc(repoInfo.Index, "push")
 	if isTrusted() {
 	if isTrusted() {
-		return cli.trustedPush(repoInfo, tag, authConfig)
+		return cli.trustedPush(repoInfo, tag, authConfig, requestPrivilege)
 	}
 	}
 
 
-	v := url.Values{}
-	v.Set("tag", tag)
+	return cli.imagePushPrivileged(authConfig, ref.Name(), tag, cli.out, requestPrivilege)
+}
+
+func (cli *DockerCli) imagePushPrivileged(authConfig cliconfig.AuthConfig, imageID, tag string, outputStream io.Writer, requestPrivilege lib.RequestPrivilegeFunc) error {
+	encodedAuth, err := authConfig.EncodeToBase64()
+	if err != nil {
+		return err
+	}
+	options := types.ImagePushOptions{
+		ImageID:      imageID,
+		Tag:          tag,
+		RegistryAuth: encodedAuth,
+	}
+
+	responseBody, err := cli.client.ImagePush(options, requestPrivilege)
+	if err != nil {
+		return err
+	}
+	defer responseBody.Close()
 
 
-	_, _, err = cli.clientRequestAttemptLogin("POST", "/images/"+ref.Name()+"/push?"+v.Encode(), nil, cli.out, repoInfo.Index, "push")
-	return err
+	return jsonmessage.DisplayJSONMessagesStream(responseBody, outputStream, cli.outFd, cli.isTerminalOut)
 }
 }

+ 4 - 6
api/client/trust.go

@@ -380,20 +380,18 @@ func targetStream(in io.Writer) (io.WriteCloser, <-chan []target) {
 	return ioutils.NewWriteCloserWrapper(out, w.Close), targetChan
 	return ioutils.NewWriteCloserWrapper(out, w.Close), targetChan
 }
 }
 
 
-func (cli *DockerCli) trustedPush(repoInfo *registry.RepositoryInfo, tag string, authConfig cliconfig.AuthConfig) error {
+func (cli *DockerCli) trustedPush(repoInfo *registry.RepositoryInfo, tag string, authConfig cliconfig.AuthConfig, requestPrivilege lib.RequestPrivilegeFunc) error {
 	streamOut, targetChan := targetStream(cli.out)
 	streamOut, targetChan := targetStream(cli.out)
 
 
-	v := url.Values{}
-	v.Set("tag", tag)
+	reqError := cli.imagePushPrivileged(authConfig, repoInfo.LocalName.Name(), tag, streamOut, requestPrivilege)
 
 
-	_, _, err := cli.clientRequestAttemptLogin("POST", "/images/"+repoInfo.LocalName.Name()+"/push?"+v.Encode(), nil, streamOut, repoInfo.Index, "push")
 	// Close stream channel to finish target parsing
 	// Close stream channel to finish target parsing
 	if err := streamOut.Close(); err != nil {
 	if err := streamOut.Close(); err != nil {
 		return err
 		return err
 	}
 	}
 	// Check error from request
 	// Check error from request
-	if err != nil {
-		return err
+	if reqError != nil {
+		return reqError
 	}
 	}
 
 
 	// Get target results
 	// Get target results

+ 3 - 0
api/types/client.go

@@ -187,6 +187,9 @@ type ImagePullOptions struct {
 	RegistryAuth string
 	RegistryAuth string
 }
 }
 
 
+//ImagePushOptions holds information to push images.
+type ImagePushOptions ImagePullOptions
+
 // ImageRemoveOptions holds parameters to remove images.
 // ImageRemoveOptions holds parameters to remove images.
 type ImageRemoveOptions struct {
 type ImageRemoveOptions struct {
 	ImageID       string
 	ImageID       string