diff --git a/auth/auth.go b/auth/auth.go index 498b7d8413..2a3d1a439f 100644 --- a/auth/auth.go +++ b/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"` diff --git a/commands.go b/commands.go index d5fcacb9f7..2ed36311e9 100644 --- a/commands.go +++ b/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 { diff --git a/registry.go b/registry.go index 4ce3178fbd..5a80c8eb78 100644 --- a/registry.go +++ b/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 +}