Explorar el Código

Merge branch 'graph' of ssh://github.com/dotcloud/docker into graph

Solomon Hykes hace 12 años
padre
commit
cdd62522b6
Se han modificado 2 ficheros con 213 adiciones y 7 borrados
  1. 207 1
      commands.go
  2. 6 6
      image.go

+ 207 - 1
commands.go

@@ -8,10 +8,12 @@ import (
 	"github.com/dotcloud/docker/auth"
 	"github.com/dotcloud/docker/rcli"
 	"io"
+	"io/ioutil"
 	"log"
 	"math/rand"
 	"net/http"
 	"net/url"
+	"path"
 	"runtime"
 	"strconv"
 	"strings"
@@ -21,6 +23,7 @@ import (
 )
 
 const VERSION = "0.0.3"
+const REGISTRY_ENDPOINT = "http://registry-creack.dotcloud.com/v1"
 
 func (srv *Server) Name() string {
 	return "docker"
@@ -421,6 +424,209 @@ func (srv *Server) CmdImport(stdin io.ReadCloser, stdout io.Writer, args ...stri
 	return nil
 }
 
+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")
+	if err := cmd.Parse(args); err != nil {
+		return nil
+	}
+	if cmd.NArg() == 0 {
+		cmd.Usage()
+		return nil
+	}
+
+	client := &http.Client{}
+	if img, err := srv.runtime.graph.Get(cmd.Arg(0)); err != nil {
+		return nil
+	} else {
+		img.WalkHistory(func(img *Image) {
+			fmt.Fprintf(stdout, "Pushing %s\n", img.Id)
+
+			jsonRaw, err := ioutil.ReadFile(path.Join(srv.runtime.graph.Root, img.Id, "json"))
+			if err != nil {
+				fmt.Fprintf(stdout, "Error while retreiving the path for {%s}: %s\n", img.Id, err)
+				return
+			}
+			jsonData := strings.NewReader(string(jsonRaw))
+			req, err := http.NewRequest("PUT", REGISTRY_ENDPOINT+"/images/"+img.Id+"/json", jsonData)
+			res, err := client.Do(req)
+			if err != nil || res.StatusCode != 200 {
+				if res == nil {
+					fmt.Fprintf(stdout,
+						"Error: Internal server error trying to push image {%s} (json): %s\n",
+						img.Id, err)
+					return
+				}
+				switch res.StatusCode {
+				case 204:
+					fmt.Fprintf(stdout, "Image already on the repository\n")
+					return
+				case 400:
+					fmt.Fprintf(stdout, "Error: Invalid Json\n")
+					return
+				default:
+					fmt.Fprintf(stdout,
+						"Error: Internal server error trying to push image {%s} (json): %s (%d)\n",
+						img.Id, err, res.StatusCode)
+					return
+				}
+			}
+
+			req2, err := http.NewRequest("PUT", REGISTRY_ENDPOINT+"/images/"+img.Id+"/layer", nil)
+			res2, err := client.Do(req2)
+			if err != nil || res2.StatusCode != 307 {
+				fmt.Fprintf(stdout,
+					"Error trying to push image {%s} (layer 1): %s\n",
+					img.Id, err)
+				return
+			}
+			url, err := res2.Location()
+			if err != nil || url == nil {
+				fmt.Fprintf(stdout,
+					"Fail to retrieve layer storage URL for image {%s}: %s\n",
+					img.Id, err)
+				return
+			}
+			// FIXME: Don't do this :D. Check the S3 requierement and implement chunks of 5MB
+			layerData2, err := Tar(path.Join(srv.runtime.graph.Root, img.Id, "layer"), Gzip)
+			layerData, err := Tar(path.Join(srv.runtime.graph.Root, img.Id, "layer"), Gzip)
+			if err != nil {
+				fmt.Fprintf(stdout,
+					"Error while retrieving layer for {%s}: %s\n",
+					img.Id, err)
+				return
+			}
+			req3, err := http.NewRequest("PUT", url.String(), layerData)
+			tmp, _ := ioutil.ReadAll(layerData2)
+			req3.ContentLength = int64(len(tmp))
+
+			req3.TransferEncoding = []string{"none"}
+			res3, err := client.Do(req3)
+			if err != nil || res3.StatusCode != 200 {
+				if res3 == nil {
+					fmt.Fprintf(stdout,
+						"Error trying to push image {%s} (layer 2): %s\n",
+						img.Id, err)
+				} else {
+					fmt.Fprintf(stdout,
+						"Error trying to push image {%s} (layer 2): %s (%d)\n",
+						img.Id, err, res3.StatusCode)
+				}
+				return
+			}
+		})
+	}
+	return nil
+}
+
+func newImgJson(src []byte) (*Image, error) {
+	ret := &Image{}
+
+	fmt.Printf("Json string: {%s}\n", src)
+	// FIXME: Is there a cleaner way to "puryfy" the input json?
+	src = []byte(strings.Replace(string(src), "null", "\"\"", -1))
+
+	if err := json.Unmarshal(src, ret); err != nil {
+		return nil, err
+	}
+	return ret, nil
+}
+
+func newMultipleImgJson(src []byte) (map[*Image]Archive, error) {
+	ret := map[*Image]Archive{}
+
+	fmt.Printf("Json string2: {%s}\n", src)
+	dec := json.NewDecoder(strings.NewReader(strings.Replace(string(src), "null", "\"\"", -1)))
+	for {
+		m := &Image{}
+		if err := dec.Decode(m); err == io.EOF {
+			break
+		} else if err != nil {
+			return nil, err
+		}
+		ret[m] = nil
+	}
+	return ret, nil
+}
+
+func getHistory(base_uri, id string) (map[*Image]Archive, error) {
+	res, err := http.Get(base_uri + id + "/history")
+	if err != nil {
+		return nil, fmt.Errorf("Error while getting from the server: %s\n", err)
+	}
+	defer res.Body.Close()
+
+	jsonString, err := ioutil.ReadAll(res.Body)
+	if err != nil {
+		return nil, fmt.Errorf("Error while reading the http response: %s\n", err)
+	}
+
+	history, err := newMultipleImgJson(jsonString)
+	if err != nil {
+		return nil, fmt.Errorf("Error while parsing the json: %s\n", err)
+	}
+	return history, nil
+}
+
+func getRemoteImage(base_uri, id string) (*Image, Archive, error) {
+	// Get the Json
+	res, err := http.Get(base_uri + id + "/json")
+	if err != nil {
+		return nil, nil, fmt.Errorf("Error while getting from the server: %s\n", err)
+	}
+	defer res.Body.Close()
+
+	jsonString, err := ioutil.ReadAll(res.Body)
+	if err != nil {
+		return nil, nil, fmt.Errorf("Error while reading the http response: %s\n", err)
+	}
+
+	img, err := newImgJson(jsonString)
+	if err != nil {
+		return nil, nil, fmt.Errorf("Error while parsing the json: %s\n", err)
+	}
+	img.Id = id
+
+	// Get the layer
+	res, err = http.Get(base_uri + id + "/layer")
+	if err != nil {
+		return nil, nil, fmt.Errorf("Error while getting from the server: %s\n", err)
+	}
+	return img, res.Body, nil
+}
+
+func (srv *Server) CmdPulli(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
+	cmd := rcli.Subcmd(stdout, "pulli", "[OPTIONS] IMAGE", "Pull an image from the registry")
+	if err := cmd.Parse(args); err != nil {
+		return nil
+	}
+	if cmd.NArg() == 0 {
+		cmd.Usage()
+		return nil
+	}
+
+	// First, retrieve the history
+	base_uri := REGISTRY_ENDPOINT + "/images/"
+
+	// Now we have the history, remove the images we already have
+	history, err := getHistory(base_uri, cmd.Arg(0))
+	if err != nil {
+		return err
+	}
+	for j := range history {
+		if !srv.runtime.graph.Exists(j.Id) {
+			img, layer, err := getRemoteImage(base_uri, j.Id)
+			if err != nil {
+				// FIXME: Keep goging in case of error?
+				return err
+			}
+			if err = srv.runtime.graph.Register(layer, img); err != nil {
+				return err
+			}
+		}
+	}
+	return nil
+}
+
 func (srv *Server) CmdImages(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
 	cmd := rcli.Subcmd(stdout, "images", "[OPTIONS] [NAME]", "List images")
 	//limit := cmd.Int("l", 0, "Only show the N most recent versions of each image")
@@ -475,7 +681,7 @@ func (srv *Server) CmdImages(stdin io.ReadCloser, stdout io.Writer, args ...stri
 			}
 		}
 	}
-	// Display images which aren't part of a 
+	// Display images which aren't part of a
 	if nameFilter == "" {
 		for id, image := range allImages {
 			if !*quiet {

+ 6 - 6
image.go

@@ -15,12 +15,12 @@ import (
 )
 
 type Image struct {
-	Id              string
-	Parent          string
-	Comment         string
-	Created         time.Time
-	ParentContainer string
-	ParentCommand   []string
+	Id              string    `json:"id"`
+	Parent          string    `json:"parent,omitempty"`
+	Comment         string    `json:"comment,omitempty"`
+	Created         time.Time `json:"created"`
+	ParentContainer string    `json:-`
+	ParentCommand   []string  `json:-`
 	graph           *Graph
 }