//PutRepositoryV1Handler will create or update the repository, it's first step of Docker push. //TODO: @1 When someone create or update the repository, it will be locked to forbidden others action include pull action. //TODO: @2 Add a config option for allow/forbidden Docker client pull action when a repository is locked. //TODO: @3 Intergated with [Crew](https://github.com/containerops/crew). //TODO: @4 Token will be store in Redis, and link the push action with username@repository. func PutRepositoryV1Handler(ctx *macaron.Context) (int, []byte) { var username, body string //var passwd string var err error if username, _, err = utils.DecodeBasicAuth(ctx.Req.Header.Get("Authorization")); err != nil { log.Errorf("[%s] decode Authorization error: %s", ctx.Req.RequestURI, err.Error()) result, _ := json.Marshal(map[string]string{"Error": "Decode Authorization Error"}) return http.StatusUnauthorized, result } //When integrated with crew, like this: //@1: username, passwd, _ := utils.DecodeBasicAuth(ctx.Req.Header.Get("Authorization")) //@2: username, passwd authorizated in Crew. namespace := ctx.Params(":namespace") repository := ctx.Params(":repository") //When integrated the Crew, should be check the privilage. if username != namespace { } //In Docker Registry V1, the repository json data in the body of `PUT /v1/:namespace/:repository` if body, err = ctx.Req.Body().String(); err != nil { log.Errorf("[%s] get repository json from http body error: %s", ctx.Req.RequestURI, err.Error()) result, _ := json.Marshal(map[string]string{"Error": "Get Repository JSON Error"}) return http.StatusBadRequest, result } //Create or update the repository. r := new(models.DockerV1) if e := r.Put(namespace, repository, body, ctx.Req.Header.Get("User-Agent")); e != nil { log.Errorf("[%s] put repository error: %s", ctx.Req.RequestURI, e.Error()) result, _ := json.Marshal(map[string]string{"Error": "PUT Repository Error"}) return http.StatusBadRequest, result } //If the Docker client use "X-Docker-Token", will return a randon token value. if ctx.Req.Header.Get("X-Docker-Token") == "true" { token := fmt.Sprintf("Token signature=%v,repository=\"%v/%v\",access=%v", utils.MD5(username), namespace, repository, "write") ctx.Resp.Header().Set("X-Docker-Token", token) ctx.Resp.Header().Set("WWW-Authenticate", token) } //TODO: When deploy multi instances of dockyard, the endpoints will schedule comply all instances stauts and arithmetic. ctx.Resp.Header().Set("X-Docker-Endpoints", setting.Domains) result, _ := json.Marshal(map[string]string{}) return http.StatusOK, result }
//PutRepositoryImagesV1Handler func PutRepositoryImagesV1Handler(ctx *macaron.Context) (int, []byte) { //TODO: If standalone == true, Dockyard will check HEADER Authorization; if standalone == false, Dockyard will check HEADER TOEKN. namespace := ctx.Params(":namespace") repository := ctx.Params(":repository") r := new(models.DockerV1) if err := r.Unlocked(namespace, repository); err != nil { log.Errorf("[%s] unlock repository error: %s", ctx.Req.RequestURI, err.Error()) result, _ := json.Marshal(map[string]string{"Error": "Unlock Repository Error"}) return http.StatusBadRequest, result } result, _ := json.Marshal(map[string]string{}) return http.StatusNoContent, result }
//GetTagV1Handler is func GetTagV1Handler(ctx *macaron.Context) (int, []byte) { //TODO: If standalone == true, Dockyard will check HEADER Authorization; if standalone == false, Dockyard will check HEADER TOEKN. namespace := ctx.Params(":namespace") repository := ctx.Params(":repository") r := new(models.DockerV1) if tags, err := r.GetTags(namespace, repository); err != nil { log.Errorf("[%s] get repository tags data error: %s", ctx.Req.RequestURI, err.Error()) result, _ := json.Marshal(map[string]string{"Error": "Get Repository Tags Error"}) return http.StatusBadRequest, result } else { result, _ := json.Marshal(tags) ctx.Resp.Header().Set("Content-Length", fmt.Sprint(len(result))) return http.StatusOK, result } }
//GetRepositoryImagesV1Handler will return images json data. func GetRepositoryImagesV1Handler(ctx *macaron.Context) (int, []byte) { var username string var err error if username, _, err = utils.DecodeBasicAuth(ctx.Req.Header.Get("Authorization")); err != nil { log.Errorf("[%s] decode Authorization error: %s", ctx.Req.RequestURI, err.Error()) result, _ := json.Marshal(map[string]string{"Error": "Decode Authorization Error"}) return http.StatusUnauthorized, result } namespace := ctx.Params(":namespace") repository := ctx.Params(":repository") r := new(models.DockerV1) if v1, err := r.Get(namespace, repository); err != nil { log.Errorf("[%s] get repository images data error: %s", ctx.Req.RequestURI, err.Error()) result, _ := json.Marshal(map[string]string{"Error": "Get Repository Images Error"}) return http.StatusBadRequest, result } else { //If the Docker client use "X-Docker-Token", will return a randon token value. if ctx.Req.Header.Get("X-Docker-Token") == "true" { token := fmt.Sprintf("Token signature=%v,repository=\"%v/%v\",access=%v", utils.MD5(username), namespace, repository, "read") ctx.Resp.Header().Set("X-Docker-Token", token) ctx.Resp.Header().Set("WWW-Authenticate", token) } ctx.Resp.Header().Set("Content-Length", fmt.Sprint(len(v1.JSON))) return http.StatusOK, []byte(v1.JSON) } }