2016-02-01 12:59:10 +01:00
|
|
|
/*
|
|
|
|
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
you may not use this file except in compliance with the License.
|
|
|
|
You may obtain a copy of the License at
|
|
|
|
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
See the License for the specific language governing permissions and
|
|
|
|
limitations under the License.
|
|
|
|
*/
|
2016-02-26 11:54:14 +01:00
|
|
|
|
2016-02-01 12:59:10 +01:00
|
|
|
package api
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
2016-02-24 07:31:52 +01:00
|
|
|
"net/http"
|
2016-02-01 12:59:10 +01:00
|
|
|
"strconv"
|
|
|
|
"strings"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/vmware/harbor/dao"
|
|
|
|
"github.com/vmware/harbor/models"
|
|
|
|
svc_utils "github.com/vmware/harbor/service/utils"
|
2016-03-28 02:50:09 +02:00
|
|
|
"github.com/vmware/harbor/utils/log"
|
2016-02-01 12:59:10 +01:00
|
|
|
)
|
|
|
|
|
2016-02-26 11:35:55 +01:00
|
|
|
// RepositoryAPI handles request to /api/repositories /api/repositories/tags /api/repositories/manifests, the parm has to be put
|
|
|
|
// in the query string as the web framework can not parse the URL if it contains veriadic sectors.
|
|
|
|
// For repostiories, we won't check the session in this API due to search functionality, querying manifest will be contorlled by
|
|
|
|
// the security of registry
|
2016-02-01 12:59:10 +01:00
|
|
|
type RepositoryAPI struct {
|
|
|
|
BaseAPI
|
2016-02-25 06:40:08 +01:00
|
|
|
userID int
|
2016-02-01 12:59:10 +01:00
|
|
|
username string
|
|
|
|
}
|
|
|
|
|
2016-02-26 11:35:55 +01:00
|
|
|
// Prepare will set a non existent user ID in case the request tries to view repositories under a project he doesn't has permission.
|
2016-02-01 12:59:10 +01:00
|
|
|
func (ra *RepositoryAPI) Prepare() {
|
2016-02-25 06:40:08 +01:00
|
|
|
userID, ok := ra.GetSession("userId").(int)
|
2016-02-01 12:59:10 +01:00
|
|
|
if !ok {
|
2016-02-26 04:26:54 +01:00
|
|
|
ra.userID = dao.NonExistUserID
|
2016-02-01 12:59:10 +01:00
|
|
|
} else {
|
2016-02-25 06:40:08 +01:00
|
|
|
ra.userID = userID
|
2016-02-01 12:59:10 +01:00
|
|
|
}
|
|
|
|
username, ok := ra.GetSession("username").(string)
|
|
|
|
if !ok {
|
2016-03-28 02:50:09 +02:00
|
|
|
log.Warning("failed to get username from session")
|
2016-02-01 12:59:10 +01:00
|
|
|
ra.username = ""
|
|
|
|
} else {
|
|
|
|
ra.username = username
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-26 11:35:55 +01:00
|
|
|
// Get ...
|
2016-02-01 12:59:10 +01:00
|
|
|
func (ra *RepositoryAPI) Get() {
|
2016-02-25 06:40:08 +01:00
|
|
|
projectID, err0 := ra.GetInt64("project_id")
|
2016-02-01 12:59:10 +01:00
|
|
|
if err0 != nil {
|
2016-03-28 02:50:09 +02:00
|
|
|
log.Errorf("Failed to get project id, error: %v", err0)
|
2016-02-24 07:31:52 +01:00
|
|
|
ra.RenderError(http.StatusBadRequest, "Invalid project id")
|
2016-02-01 12:59:10 +01:00
|
|
|
return
|
|
|
|
}
|
2016-02-26 04:26:54 +01:00
|
|
|
p, err := dao.GetProjectByID(projectID)
|
2016-02-01 12:59:10 +01:00
|
|
|
if err != nil {
|
2016-03-28 02:50:09 +02:00
|
|
|
log.Errorf("Error occurred in GetProjectById, error: %v", err)
|
2016-02-24 07:31:52 +01:00
|
|
|
ra.CustomAbort(http.StatusInternalServerError, "Internal error.")
|
2016-02-01 12:59:10 +01:00
|
|
|
}
|
|
|
|
if p == nil {
|
2016-03-28 02:50:09 +02:00
|
|
|
log.Warningf("Project with Id: %d does not exist", projectID)
|
2016-02-24 07:31:52 +01:00
|
|
|
ra.RenderError(http.StatusNotFound, "")
|
2016-02-01 12:59:10 +01:00
|
|
|
return
|
|
|
|
}
|
2016-02-26 11:35:55 +01:00
|
|
|
if p.Public == 0 && !checkProjectPermission(ra.userID, projectID) {
|
2016-02-24 07:31:52 +01:00
|
|
|
ra.RenderError(http.StatusForbidden, "")
|
2016-02-01 12:59:10 +01:00
|
|
|
return
|
|
|
|
}
|
|
|
|
repoList, err := svc_utils.GetRepoFromCache()
|
|
|
|
if err != nil {
|
2016-03-28 02:50:09 +02:00
|
|
|
log.Errorf("Failed to get repo from cache, error: %v", err)
|
2016-02-24 07:31:52 +01:00
|
|
|
ra.RenderError(http.StatusInternalServerError, "internal sever error")
|
2016-02-01 12:59:10 +01:00
|
|
|
}
|
|
|
|
projectName := p.Name
|
|
|
|
q := ra.GetString("q")
|
|
|
|
var resp []string
|
|
|
|
if len(q) > 0 {
|
|
|
|
for _, r := range repoList {
|
|
|
|
if strings.Contains(r, "/") && strings.Contains(r[strings.LastIndex(r, "/")+1:], q) && r[0:strings.LastIndex(r, "/")] == projectName {
|
|
|
|
resp = append(resp, r)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ra.Data["json"] = resp
|
|
|
|
} else if len(projectName) > 0 {
|
|
|
|
for _, r := range repoList {
|
|
|
|
if strings.Contains(r, "/") && r[0:strings.LastIndex(r, "/")] == projectName {
|
|
|
|
resp = append(resp, r)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ra.Data["json"] = resp
|
|
|
|
} else {
|
|
|
|
ra.Data["json"] = repoList
|
|
|
|
}
|
|
|
|
ra.ServeJSON()
|
|
|
|
}
|
|
|
|
|
2016-02-26 11:35:55 +01:00
|
|
|
type tag struct {
|
2016-02-26 07:24:44 +01:00
|
|
|
Name string `json:"name"`
|
2016-02-01 12:59:10 +01:00
|
|
|
Tags []string `json:"tags"`
|
|
|
|
}
|
|
|
|
|
2016-02-26 11:35:55 +01:00
|
|
|
type histroyItem struct {
|
2016-02-01 12:59:10 +01:00
|
|
|
V1Compatibility string `json:"v1Compatibility"`
|
|
|
|
}
|
|
|
|
|
2016-02-26 11:35:55 +01:00
|
|
|
type manifest struct {
|
2016-02-01 12:59:10 +01:00
|
|
|
Name string `json:"name"`
|
|
|
|
Tag string `json:"tag"`
|
|
|
|
Architecture string `json:"architecture"`
|
|
|
|
SchemaVersion int `json:"schemaVersion"`
|
2016-02-26 11:35:55 +01:00
|
|
|
History []histroyItem `json:"history"`
|
2016-02-01 12:59:10 +01:00
|
|
|
}
|
|
|
|
|
2016-02-26 11:35:55 +01:00
|
|
|
// GetTags handles GET /api/repositories/tags
|
2016-02-01 12:59:10 +01:00
|
|
|
func (ra *RepositoryAPI) GetTags() {
|
|
|
|
|
|
|
|
var tags []string
|
|
|
|
|
|
|
|
repoName := ra.GetString("repo_name")
|
2016-02-25 07:14:39 +01:00
|
|
|
result, err := svc_utils.RegistryAPIGet(svc_utils.BuildRegistryURL(repoName, "tags", "list"), ra.username)
|
2016-02-01 12:59:10 +01:00
|
|
|
if err != nil {
|
2016-03-28 02:50:09 +02:00
|
|
|
log.Errorf("Failed to get repo tags, repo name: %s, error: %v", repoName, err)
|
2016-02-24 07:31:52 +01:00
|
|
|
ra.RenderError(http.StatusInternalServerError, "Failed to get repo tags")
|
2016-02-01 12:59:10 +01:00
|
|
|
} else {
|
2016-02-26 11:35:55 +01:00
|
|
|
t := tag{}
|
2016-02-01 12:59:10 +01:00
|
|
|
json.Unmarshal(result, &t)
|
|
|
|
tags = t.Tags
|
|
|
|
}
|
|
|
|
ra.Data["json"] = tags
|
|
|
|
ra.ServeJSON()
|
|
|
|
}
|
|
|
|
|
2016-02-26 11:35:55 +01:00
|
|
|
// GetManifests handles GET /api/repositories/manifests
|
2016-02-01 12:59:10 +01:00
|
|
|
func (ra *RepositoryAPI) GetManifests() {
|
|
|
|
repoName := ra.GetString("repo_name")
|
|
|
|
tag := ra.GetString("tag")
|
|
|
|
|
|
|
|
item := models.RepoItem{}
|
|
|
|
|
2016-02-25 07:14:39 +01:00
|
|
|
result, err := svc_utils.RegistryAPIGet(svc_utils.BuildRegistryURL(repoName, "manifests", tag), ra.username)
|
2016-02-01 12:59:10 +01:00
|
|
|
if err != nil {
|
2016-03-28 02:50:09 +02:00
|
|
|
log.Errorf("Failed to get manifests for repo, repo name: %s, tag: %s, error: %v", repoName, tag, err)
|
2016-02-24 07:31:52 +01:00
|
|
|
ra.RenderError(http.StatusInternalServerError, "Internal Server Error")
|
2016-02-01 12:59:10 +01:00
|
|
|
return
|
|
|
|
}
|
2016-02-26 11:35:55 +01:00
|
|
|
mani := manifest{}
|
2016-02-25 06:40:08 +01:00
|
|
|
err = json.Unmarshal(result, &mani)
|
|
|
|
if err != nil {
|
2016-03-28 02:50:09 +02:00
|
|
|
log.Errorf("Failed to decode json from response for manifests, repo name: %s, tag: %s, error: %v", repoName, tag, err)
|
2016-02-25 06:40:08 +01:00
|
|
|
ra.RenderError(http.StatusInternalServerError, "Internal Server Error")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
v1Compatibility := mani.History[0].V1Compatibility
|
|
|
|
|
|
|
|
err = json.Unmarshal([]byte(v1Compatibility), &item)
|
|
|
|
if err != nil {
|
2016-03-28 02:50:09 +02:00
|
|
|
log.Errorf("Failed to decode V1 field for repo, repo name: %s, tag: %s, error: %v", repoName, tag, err)
|
2016-02-25 06:40:08 +01:00
|
|
|
ra.RenderError(http.StatusInternalServerError, "Internal Server Error")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
item.CreatedStr = item.Created.Format("2006-01-02 15:04:05")
|
|
|
|
item.DurationDays = strconv.Itoa(int(time.Since(item.Created).Hours()/24)) + " days"
|
2016-02-01 12:59:10 +01:00
|
|
|
|
|
|
|
ra.Data["json"] = item
|
|
|
|
ra.ServeJSON()
|
|
|
|
}
|