浏览代码

Handle push/pull of repositories

creack 12 年之前
父节点
当前提交
11c4294846
共有 3 个文件被更改,包括 128 次插入9 次删除
  1. 2 1
      auth/auth.go
  2. 29 6
      commands.go
  3. 97 2
      registry.go

+ 2 - 1
auth/auth.go

@@ -15,7 +15,8 @@ import (
 const CONFIGFILE = "/var/lib/docker/.dockercfg"
 
 // the registry server we want to login against
-const REGISTRY_SERVER = "https://registry.docker.io"
+//const REGISTRY_SERVER = "https://registry.docker.io"
+const REGISTRY_SERVER = "http://192.168.56.1:5000"
 
 type AuthConfig struct {
 	Username string `json:"username"`

+ 29 - 6
commands.go

@@ -423,7 +423,8 @@ func (srv *Server) CmdImport(stdin io.ReadCloser, stdout io.Writer, args ...stri
 }
 
 func (srv *Server) CmdPush(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
-	cmd := rcli.Subcmd(stdout, "push", "[OPTIONS] IMAGE", "Push an image to the registry")
+	cmd := rcli.Subcmd(stdout, "push", "[OPTIONS] IMAGE", "Push an image or a repository to the registry")
+	user := cmd.String("u", "", "specify the user for the repository")
 	if err := cmd.Parse(args); err != nil {
 		return nil
 	}
@@ -432,16 +433,31 @@ func (srv *Server) CmdPush(stdin io.ReadCloser, stdout io.Writer, args ...string
 		return nil
 	}
 
+	// Try to get the image
+	// FIXME: Handle lookup
+	// FIXME: Also push the tags in case of ./docker push myrepo:mytag
+	//	img, err := srv.runtime.LookupImage(cmd.Arg(0))
 	img, err := srv.runtime.graph.Get(cmd.Arg(0))
 	if err != nil {
-		return err
+		if *user == "" {
+			return fmt.Errorf("Not logged in and no user specified\n")
+		}
+		// If it fails, try to get the repository
+		if repo, exists := srv.runtime.repositories.Repositories[cmd.Arg(0)]; exists {
+			if err := srv.runtime.graph.PushRepository(*user, cmd.Arg(0), repo); err != nil {
+				return err
+			}
+		} else {
+			return err
+		}
+		return nil
 	}
-	// FIXME: Handle repositories, etc. Not jist images
 	return srv.runtime.graph.PushImage(img)
 }
 
 func (srv *Server) CmdPull(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
-	cmd := rcli.Subcmd(stdout, "pull", "[OPTIONS] IMAGE", "Pull an image from the registry")
+	cmd := rcli.Subcmd(stdout, "pull", "[OPTIONS] IMAGE", "Pull an image or a repository from the registry")
+	user := cmd.String("u", "", "specify the user for the repository")
 	if err := cmd.Parse(args); err != nil {
 		return nil
 	}
@@ -449,8 +465,15 @@ func (srv *Server) CmdPull(stdin io.ReadCloser, stdout io.Writer, args ...string
 		cmd.Usage()
 		return nil
 	}
-	// FIXME: Handle repositories, etc. Not jist images
-	return srv.runtime.graph.PullImage(cmd.Arg(0))
+
+	if srv.runtime.graph.LookupRemoteImage(cmd.Arg(0)) {
+		return srv.runtime.graph.PullImage(cmd.Arg(0))
+	}
+	if *user == "" {
+		return fmt.Errorf("Not loggin and no user specified\n")
+	}
+	// FIXME: Allow pull repo:tag
+	return srv.runtime.graph.PullRepository(*user, cmd.Arg(0), "", srv.runtime.repositories)
 }
 
 func (srv *Server) CmdImages(stdin io.ReadCloser, stdout io.Writer, args ...string) error {

+ 97 - 2
registry.go

@@ -3,6 +3,7 @@ package docker
 import (
 	"encoding/json"
 	"fmt"
+	"github.com/dotcloud/docker/auth"
 	"io"
 	"io/ioutil"
 	"net/http"
@@ -12,7 +13,7 @@ import (
 
 //FIXME: Set the endpoint in a conf file or via commandline
 //const REGISTRY_ENDPOINT = "http://registry-creack.dotcloud.com/v1"
-const REGISTRY_ENDPOINT = "http://192.168.56.1:5000/v1"
+const REGISTRY_ENDPOINT = auth.REGISTRY_SERVER + "/v1"
 
 // Build an Image object from raw json data
 func NewImgJson(src []byte) (*Image, error) {
@@ -67,6 +68,15 @@ func (graph *Graph) getRemoteHistory(imgId string) ([]*Image, error) {
 	return history, nil
 }
 
+// Check if an image exists in the Registry
+func (graph *Graph) LookupRemoteImage(imgId string) bool {
+	res, err := http.Get(REGISTRY_ENDPOINT + "/images/" + imgId + "/json")
+	if err != nil {
+		return false
+	}
+	return res.StatusCode == 307
+}
+
 // Retrieve an image from the Registry.
 // Returns the Image object as well as the layer as an Archive (io.Reader)
 func (graph *Graph) getRemoteImage(imgId string) (*Image, Archive, error) {
@@ -118,6 +128,46 @@ func (graph *Graph) PullImage(imgId string) error {
 	return nil
 }
 
+// FIXME: Handle the askedTag parameter
+func (graph *Graph) PullRepository(user, repoName, askedTag string, repositories *TagStore) error {
+	client := &http.Client{}
+
+	req, err := http.NewRequest("GET", REGISTRY_ENDPOINT+"/users/"+user+"/"+repoName, nil)
+	if err != nil {
+		return err
+	}
+	authStruct, err := auth.LoadConfig()
+	if err != nil {
+		return err
+	}
+
+	req.SetBasicAuth(authStruct.Username, authStruct.Password)
+	res, err := client.Do(req)
+	if err != nil {
+		return err
+	}
+	rawJson, err := ioutil.ReadAll(res.Body)
+	if err != nil {
+		return err
+	}
+	t := map[string]string{}
+	if err = json.Unmarshal(rawJson, &t); err != nil {
+		return err
+	}
+	for tag, rev := range t {
+		if err = graph.PullImage(rev); err != nil {
+			return err
+		}
+		if err = repositories.Set(repoName, tag, rev); err != nil {
+			return err
+		}
+	}
+	if err = repositories.Save(); err != nil {
+		return err
+	}
+	return nil
+}
+
 // Push a local image to the registry with its history if needed
 func (graph *Graph) PushImage(imgOrig *Image) error {
 	client := &http.Client{}
@@ -130,9 +180,12 @@ func (graph *Graph) PushImage(imgOrig *Image) error {
 		if err != nil {
 			return fmt.Errorf("Error while retreiving the path for {%s}: %s", img.Id, err)
 		}
-		// FIXME: try json with URF8
+		// FIXME: try json with UTF8
 		jsonData := strings.NewReader(string(jsonRaw))
 		req, err := http.NewRequest("PUT", REGISTRY_ENDPOINT+"/images/"+img.Id+"/json", jsonData)
+		if err != nil {
+			return err
+		}
 		res, err := client.Do(req)
 		if err != nil || res.StatusCode != 200 {
 			if res == nil {
@@ -199,3 +252,45 @@ func (graph *Graph) PushImage(imgOrig *Image) error {
 	}
 	return nil
 }
+
+func (graph *Graph) pushTag(user, repo, revision, tag string) error {
+
+	if tag == "" {
+		tag = "lastest"
+	}
+
+	revision = "\"" + revision + "\""
+
+	client := &http.Client{}
+	req, err := http.NewRequest("PUT", REGISTRY_ENDPOINT+"/users/"+user+"/"+repo+"/"+tag, strings.NewReader(revision))
+	req.Header.Add("Content-type", "application/json")
+	res, err := client.Do(req)
+	if err != nil {
+		return err
+	}
+	fmt.Printf("Result of push tag: %d\n", res.StatusCode)
+	switch res.StatusCode {
+	default:
+		return fmt.Errorf("Error %d\n", res.StatusCode)
+	case 200:
+	case 201:
+	}
+	return nil
+}
+
+func (graph *Graph) PushRepository(user, repoName string, repo Repository) error {
+	for tag, imgId := range repo {
+		fmt.Printf("tag: %s, imgId: %s\n", tag, imgId)
+		img, err := graph.Get(imgId)
+		if err != nil {
+			return err
+		}
+		if err = graph.PushImage(img); err != nil {
+			return err
+		}
+		if err = graph.pushTag(user, repoName, imgId, tag); err != nil {
+			return err
+		}
+	}
+	return nil
+}