コード例 #1
0
ファイル: target.go プロジェクト: yaolingling/harbor
// Delete ...
func (t *TargetAPI) Delete() {
	id := t.GetIDFromURL()

	target, err := dao.GetRepTarget(id)
	if err != nil {
		log.Errorf("failed to get target %d: %v", id, err)
		t.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
	}

	if target == nil {
		t.CustomAbort(http.StatusNotFound, http.StatusText(http.StatusNotFound))
	}

	policies, err := dao.GetRepPolicyByTarget(id)
	if err != nil {
		log.Errorf("failed to get policies according target %d: %v", id, err)
		t.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
	}

	if len(policies) > 0 {
		t.CustomAbort(http.StatusBadRequest, "the target is used by policies, can not be deleted")
	}

	if err = dao.DeleteRepTarget(id); err != nil {
		log.Errorf("failed to delete target %d: %v", id, err)
		t.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
	}
}
コード例 #2
0
ファイル: target.go プロジェクト: yaolingling/harbor
// List ...
func (t *TargetAPI) List() {
	name := t.GetString("name")
	targets, err := dao.FilterRepTargets(name)
	if err != nil {
		log.Errorf("failed to filter targets %s: %v", name, err)
		t.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
	}

	for _, target := range targets {
		if len(target.Password) == 0 {
			continue
		}

		str, err := utils.ReversibleDecrypt(target.Password)
		if err != nil {
			log.Errorf("failed to decrypt password: %v", err)
			t.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
		}
		target.Password = str
	}

	t.Data["json"] = targets
	t.ServeJSON()
	return
}
コード例 #3
0
ファイル: repository.go プロジェクト: yaolingling/harbor
//GetTopRepos handles request GET /api/repositories/top
func (ra *RepositoryAPI) GetTopRepos() {
	var err error
	var countNum int
	count := ra.GetString("count")
	if len(count) == 0 {
		countNum = 10
	} else {
		countNum, err = strconv.Atoi(count)
		if err != nil {
			log.Errorf("Get parameters error--count, err: %v", err)
			ra.CustomAbort(http.StatusBadRequest, "bad request of count")
		}
		if countNum <= 0 {
			log.Warning("count must be a positive integer")
			ra.CustomAbort(http.StatusBadRequest, "count is 0 or negative")
		}
	}
	repos, err := dao.GetTopRepos(countNum)
	if err != nil {
		log.Errorf("error occured in get top 10 repos: %v", err)
		ra.CustomAbort(http.StatusInternalServerError, "internal server error")
	}
	ra.Data["json"] = repos
	ra.ServeJSON()
}
コード例 #4
0
ファイル: member.go プロジェクト: yaolingling/harbor
// Prepare validates the URL and parms
func (pma *ProjectMemberAPI) Prepare() {
	pid, err := strconv.ParseInt(pma.Ctx.Input.Param(":pid"), 10, 64)
	if err != nil {
		log.Errorf("Error parsing project id: %d, error: %v", pid, err)
		pma.CustomAbort(http.StatusBadRequest, "invalid project Id")
		return
	}
	p, err := dao.GetProjectByID(pid)
	if err != nil {
		log.Errorf("Error occurred in GetProjectById, error: %v", err)
		pma.CustomAbort(http.StatusInternalServerError, "Internal error.")
	}

	if p == nil {
		log.Warningf("Project with id: %d does not exist.", pid)
		pma.CustomAbort(http.StatusNotFound, "Project does not exist")
	}
	pma.project = p
	pma.currentUserID = pma.ValidateUser()
	mid := pma.Ctx.Input.Param(":mid")
	if mid == "current" {
		pma.memberID = pma.currentUserID
	} else if len(mid) == 0 {
		pma.memberID = 0
	} else if len(mid) > 0 {
		memberID, err := strconv.Atoi(mid)
		if err != nil {
			log.Errorf("Invalid member Id, error: %v", err)
			pma.CustomAbort(http.StatusBadRequest, "Invalid member id")
		}
		pma.memberID = memberID
	}
}
コード例 #5
0
ファイル: target.go プロジェクト: yaolingling/harbor
// Get ...
func (t *TargetAPI) Get() {
	id := t.GetIDFromURL()

	target, err := dao.GetRepTarget(id)
	if err != nil {
		log.Errorf("failed to get target %d: %v", id, err)
		t.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
	}

	if target == nil {
		t.CustomAbort(http.StatusNotFound, http.StatusText(http.StatusNotFound))
	}

	// The reason why the password is returned is that when user just wants to
	// modify other fields of target he does not need to input the password again.
	// The security issue can be fixed by enable https.
	if len(target.Password) != 0 {
		pwd, err := utils.ReversibleDecrypt(target.Password)
		if err != nil {
			log.Errorf("failed to decrypt password: %v", err)
			t.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
		}
		target.Password = pwd
	}

	t.Data["json"] = target
	t.ServeJSON()
}
コード例 #6
0
ファイル: project.go プロジェクト: yaolingling/harbor
func isProjectAdmin(userID int, pid int64) bool {
	isSysAdmin, err := dao.IsAdminRole(userID)
	if err != nil {
		log.Errorf("Error occurred in IsAdminRole, returning false, error: %v", err)
		return false
	}

	if isSysAdmin {
		return true
	}

	rolelist, err := dao.GetUserProjectRoles(userID, pid)
	if err != nil {
		log.Errorf("Error occurred in GetUserProjectRoles, returning false, error: %v", err)
		return false
	}

	hasProjectAdminRole := false
	for _, role := range rolelist {
		if role.RoleID == models.PROJECTADMIN {
			hasProjectAdminRole = true
			break
		}
	}

	return hasProjectAdminRole
}
コード例 #7
0
ファイル: replication_job.go プロジェクト: yaolingling/harbor
// GetLog ...
func (ra *RepJobAPI) GetLog() {
	if ra.jobID == 0 {
		ra.CustomAbort(http.StatusBadRequest, "id is nil")
	}

	resp, err := http.Get(buildJobLogURL(strconv.FormatInt(ra.jobID, 10)))
	if err != nil {
		log.Errorf("failed to get log for job %d: %v", ra.jobID, err)
		ra.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
	}

	if resp.StatusCode == http.StatusOK {
		ra.Ctx.ResponseWriter.Header().Set(http.CanonicalHeaderKey("Content-Length"), resp.Header.Get(http.CanonicalHeaderKey("Content-Length")))
		ra.Ctx.ResponseWriter.Header().Set(http.CanonicalHeaderKey("Content-Type"), "text/plain")

		if _, err = io.Copy(ra.Ctx.ResponseWriter, resp.Body); err != nil {
			log.Errorf("failed to write log to response; %v", err)
			ra.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
		}
		return
	}

	defer resp.Body.Close()
	b, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Errorf("failed to read reponse body: %v", err)
		ra.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
	}

	ra.CustomAbort(resp.StatusCode, string(b))
}
コード例 #8
0
ファイル: project.go プロジェクト: yaolingling/harbor
// ToggleProjectPublic ...
func (p *ProjectAPI) ToggleProjectPublic() {
	p.userID = p.ValidateUser()
	var req projectReq
	var public int

	projectID, err := strconv.ParseInt(p.Ctx.Input.Param(":id"), 10, 64)
	if err != nil {
		log.Errorf("Error parsing project id: %d, error: %v", projectID, err)
		p.RenderError(http.StatusBadRequest, "invalid project id")
		return
	}

	p.DecodeJSONReq(&req)
	if req.Public {
		public = 1
	}
	if !isProjectAdmin(p.userID, projectID) {
		log.Warningf("Current user, id: %d does not have project admin role for project, id: %d", p.userID, projectID)
		p.RenderError(http.StatusForbidden, "")
		return
	}
	err = dao.ToggleProjectPublicity(p.projectID, public)
	if err != nil {
		log.Errorf("Error while updating project, project id: %d, error: %v", projectID, err)
		p.RenderError(http.StatusInternalServerError, "Failed to update project")
	}
}
コード例 #9
0
ファイル: user.go プロジェクト: yaolingling/harbor
// Get ...
func (ua *UserAPI) Get() {
	if ua.userID == 0 { //list users
		if !ua.IsAdmin {
			log.Errorf("Current user, id: %d does not have admin role, can not list users", ua.currentUserID)
			ua.RenderError(http.StatusForbidden, "User does not have admin role")
			return
		}
		username := ua.GetString("username")
		userQuery := models.User{}
		if len(username) > 0 {
			userQuery.Username = "******" + username + "%"
		}
		userList, err := dao.ListUsers(userQuery)
		if err != nil {
			log.Errorf("Failed to get data from database, error: %v", err)
			ua.RenderError(http.StatusInternalServerError, "Failed to query from database")
			return
		}
		ua.Data["json"] = userList

	} else if ua.userID == ua.currentUserID || ua.IsAdmin {
		userQuery := models.User{UserID: ua.userID}
		u, err := dao.GetUser(userQuery)
		if err != nil {
			log.Errorf("Error occurred in GetUser, error: %v", err)
			ua.CustomAbort(http.StatusInternalServerError, "Internal error.")
		}
		ua.Data["json"] = u
	} else {
		log.Errorf("Current user, id: %d does not have admin role, can not view other user's detail", ua.currentUserID)
		ua.RenderError(http.StatusForbidden, "User does not have admin role")
		return
	}
	ua.ServeJSON()
}
コード例 #10
0
ファイル: project.go プロジェクト: yaolingling/harbor
// Post ...
func (p *ProjectAPI) Post() {
	p.userID = p.ValidateUser()

	var req projectReq
	var public int
	p.DecodeJSONReq(&req)
	if req.Public {
		public = 1
	}
	err := validateProjectReq(req)
	if err != nil {
		log.Errorf("Invalid project request, error: %v", err)
		p.RenderError(http.StatusBadRequest, fmt.Sprintf("invalid request: %v", err))
		return
	}
	projectName := req.ProjectName
	exist, err := dao.ProjectExists(projectName)
	if err != nil {
		log.Errorf("Error happened checking project existence in db, error: %v, project name: %s", err, projectName)
	}
	if exist {
		p.RenderError(http.StatusConflict, "")
		return
	}
	project := models.Project{OwnerID: p.userID, Name: projectName, CreationTime: time.Now(), Public: public}
	projectID, err := dao.AddProject(project)
	if err != nil {
		log.Errorf("Failed to add project, error: %v", err)
		p.RenderError(http.StatusInternalServerError, "Failed to add project")
	}

	p.Redirect(http.StatusCreated, strconv.FormatInt(projectID, 10))
}
コード例 #11
0
ファイル: base.go プロジェクト: yaolingling/harbor
// ValidateUser checks if the request triggered by a valid user
func (b *BaseAPI) ValidateUser() int {

	username, password, ok := b.Ctx.Request.BasicAuth()
	if ok {
		log.Infof("Requst with Basic Authentication header, username: %s", username)
		user, err := auth.Login(models.AuthModel{
			Principal: username,
			Password:  password,
		})
		if err != nil {
			log.Errorf("Error while trying to login, username: %s, error: %v", username, err)
			user = nil
		}
		if user != nil {
			return user.UserID
		}
	}
	sessionUserID := b.GetSession("userId")
	if sessionUserID == nil {
		log.Warning("No user id in session, canceling request")
		b.CustomAbort(http.StatusUnauthorized, "")
	}
	userID := sessionUserID.(int)
	u, err := dao.GetUser(models.User{UserID: userID})
	if err != nil {
		log.Errorf("Error occurred in GetUser, error: %v", err)
		b.CustomAbort(http.StatusInternalServerError, "Internal error.")
	}
	if u == nil {
		log.Warningf("User was deleted already, user id: %d, canceling request.", userID)
		b.CustomAbort(http.StatusUnauthorized, "")
	}
	return userID
}
コード例 #12
0
ファイル: password.go プロジェクト: yaolingling/harbor
// ResetPassword handles request from the reset page and reset password
func (cc *CommonController) ResetPassword() {

	resetUUID := cc.GetString("reset_uuid")
	if resetUUID == "" {
		cc.CustomAbort(http.StatusBadRequest, "Reset uuid is blank.")
	}

	queryUser := models.User{ResetUUID: resetUUID}
	user, err := dao.GetUser(queryUser)
	if err != nil {
		log.Errorf("Error occurred in GetUser: %v", err)
		cc.CustomAbort(http.StatusInternalServerError, "Internal error.")
	}
	if user == nil {
		log.Error("User does not exist")
		cc.CustomAbort(http.StatusBadRequest, "User does not exist")
	}

	password := cc.GetString("password")

	if password != "" {
		user.Password = password
		err = dao.ResetUserPassword(*user)
		if err != nil {
			log.Errorf("Error occurred in ResetUserPassword: %v", err)
			cc.CustomAbort(http.StatusInternalServerError, "Internal error.")
		}
	} else {
		cc.CustomAbort(http.StatusBadRequest, "password_is_required")
	}
}
コード例 #13
0
ファイル: repository.go プロジェクト: yaolingling/harbor
// GetManifests handles GET /api/repositories/manifests
func (ra *RepositoryAPI) GetManifests() {
	repoName := ra.GetString("repo_name")
	tag := ra.GetString("tag")

	if len(repoName) == 0 || len(tag) == 0 {
		ra.CustomAbort(http.StatusBadRequest, "repo_name or tag is nil")
	}

	projectName := getProjectName(repoName)
	project, err := dao.GetProjectByName(projectName)
	if err != nil {
		log.Errorf("failed to get project %s: %v", projectName, err)
		ra.CustomAbort(http.StatusInternalServerError, "")
	}

	if project.Public == 0 {
		userID := ra.ValidateUser()
		if !checkProjectPermission(userID, project.ProjectID) {
			ra.CustomAbort(http.StatusForbidden, "")
		}
	}

	rc, err := ra.initRepositoryClient(repoName)
	if err != nil {
		log.Errorf("error occurred while initializing repository client for %s: %v", repoName, err)
		ra.CustomAbort(http.StatusInternalServerError, "internal error")
	}

	item := models.RepoItem{}

	mediaTypes := []string{schema1.MediaTypeManifest}
	_, _, payload, err := rc.PullManifest(tag, mediaTypes)
	if err != nil {
		if regErr, ok := err.(*registry_error.Error); ok {
			ra.CustomAbort(regErr.StatusCode, regErr.Detail)
		}

		log.Errorf("error occurred while getting manifest of %s:%s: %v", repoName, tag, err)
		ra.CustomAbort(http.StatusInternalServerError, "internal error")
	}
	mani := models.Manifest{}
	err = json.Unmarshal(payload, &mani)
	if err != nil {
		log.Errorf("Failed to decode json from response for manifests, repo name: %s, tag: %s, error: %v", repoName, tag, err)
		ra.RenderError(http.StatusInternalServerError, "Internal Server Error")
		return
	}
	v1Compatibility := mani.History[0].V1Compatibility

	err = json.Unmarshal([]byte(v1Compatibility), &item)
	if err != nil {
		log.Errorf("Failed to decode V1 field for repo, repo name: %s, tag: %s, error: %v", repoName, tag, err)
		ra.RenderError(http.StatusInternalServerError, "Internal Server Error")
		return
	}
	item.DurationDays = strconv.Itoa(int(time.Since(item.Created).Hours()/24)) + " days"

	ra.Data["json"] = item
	ra.ServeJSON()
}
コード例 #14
0
ファイル: utils.go プロジェクト: yaoyu26/harbor
//sysadmin has all privileges to all projects
func listRoles(userID int, projectID int64) ([]models.Role, error) {
	roles := make([]models.Role, 0, 1)
	isSysAdmin, err := dao.IsAdminRole(userID)
	if err != nil {
		log.Errorf("failed to determine whether the user %d is system admin: %v", userID, err)
		return roles, err
	}
	if isSysAdmin {
		role, err := dao.GetRoleByID(models.PROJECTADMIN)
		if err != nil {
			log.Errorf("failed to get role %d: %v", models.PROJECTADMIN, err)
			return roles, err
		}
		roles = append(roles, *role)
		return roles, nil
	}

	rs, err := dao.GetUserProjectRoles(userID, projectID)
	if err != nil {
		log.Errorf("failed to get user %d 's roles for project %d: %v", userID, projectID, err)
		return roles, err
	}
	roles = append(roles, rs...)
	return roles, nil
}
コード例 #15
0
ファイル: search.go プロジェクト: yaolingling/harbor
// Get ...
func (s *SearchAPI) Get() {
	userID, ok := s.GetSession("userId").(int)
	if !ok {
		userID = dao.NonExistUserID
	}

	keyword := s.GetString("q")

	isSysAdmin, err := dao.IsAdminRole(userID)
	if err != nil {
		log.Errorf("failed to check whether the user %d is system admin: %v", userID, err)
		s.CustomAbort(http.StatusInternalServerError, "internal error")
	}

	var projects []models.Project

	if isSysAdmin {
		projects, err = dao.GetAllProjects("")
		if err != nil {
			log.Errorf("failed to get all projects: %v", err)
			s.CustomAbort(http.StatusInternalServerError, "internal error")
		}
	} else {
		projects, err = dao.SearchProjects(userID)
		if err != nil {
			log.Errorf("failed to get user %d 's relevant projects: %v", userID, err)
			s.CustomAbort(http.StatusInternalServerError, "internal error")
		}
	}

	projectSorter := &models.ProjectSorter{Projects: projects}
	sort.Sort(projectSorter)
	projectResult := []map[string]interface{}{}
	for _, p := range projects {
		match := true
		if len(keyword) > 0 && !strings.Contains(p.Name, keyword) {
			match = false
		}
		if match {
			entry := make(map[string]interface{})
			entry["id"] = p.ProjectID
			entry["name"] = p.Name
			entry["public"] = p.Public
			projectResult = append(projectResult, entry)
		}
	}

	repositories, err2 := cache.GetRepoFromCache()
	if err2 != nil {
		log.Errorf("Failed to get repos from cache, error: %v", err2)
		s.CustomAbort(http.StatusInternalServerError, "Failed to get repositories search result")
	}
	sort.Strings(repositories)
	repositoryResult := filterRepositories(repositories, projects, keyword)
	result := &searchResult{Project: projectResult, Repository: repositoryResult}
	s.Data["json"] = result
	s.ServeJSON()
}
コード例 #16
0
ファイル: user.go プロジェクト: yaolingling/harbor
// Prepare validates the URL and parms
func (ua *UserAPI) Prepare() {

	authMode := strings.ToLower(os.Getenv("AUTH_MODE"))
	if authMode == "" {
		authMode = "db_auth"
	}
	ua.AuthMode = authMode

	selfRegistration := strings.ToLower(os.Getenv("SELF_REGISTRATION"))
	if selfRegistration == "on" {
		ua.SelfRegistration = true
	}

	if ua.Ctx.Input.IsPost() {
		sessionUserID := ua.GetSession("userId")
		_, _, ok := ua.Ctx.Request.BasicAuth()
		if sessionUserID == nil && !ok {
			return
		}
	}

	ua.currentUserID = ua.ValidateUser()
	id := ua.Ctx.Input.Param(":id")
	if id == "current" {
		ua.userID = ua.currentUserID
	} else if len(id) > 0 {
		var err error
		ua.userID, err = strconv.Atoi(id)
		if err != nil {
			log.Errorf("Invalid user id, error: %v", err)
			ua.CustomAbort(http.StatusBadRequest, "Invalid user Id")
		}
		userQuery := models.User{UserID: ua.userID}
		u, err := dao.GetUser(userQuery)
		if err != nil {
			log.Errorf("Error occurred in GetUser, error: %v", err)
			ua.CustomAbort(http.StatusInternalServerError, "Internal error.")
		}
		if u == nil {
			log.Errorf("User with Id: %d does not exist", ua.userID)
			ua.CustomAbort(http.StatusNotFound, "")
		}
	}

	var err error
	ua.IsAdmin, err = dao.IsAdminRole(ua.currentUserID)
	if err != nil {
		log.Errorf("Error occurred in IsAdminRole:%v", err)
		ua.CustomAbort(http.StatusInternalServerError, "Internal error.")
	}

}
コード例 #17
0
ファイル: notification.go プロジェクト: yaolingling/harbor
// Post handles POST request, and records audit log or refreshes cache based on event.
func (n *NotificationHandler) Post() {
	var notification models.Notification
	err := json.Unmarshal(n.Ctx.Input.CopyBody(1<<32), &notification)

	if err != nil {
		log.Errorf("failed to decode notification: %v", err)
		return
	}

	events, err := filterEvents(&notification)
	if err != nil {
		log.Errorf("failed to filter events: %v", err)
		return
	}

	for _, event := range events {
		repository := event.Target.Repository

		project := ""
		if strings.Contains(repository, "/") {
			project = repository[0:strings.LastIndex(repository, "/")]
		}

		tag := event.Target.Tag
		action := event.Action

		user := event.Actor.Name
		if len(user) == 0 {
			user = "******"
		}

		go func() {
			if err := dao.AccessLog(user, project, repository, tag, action); err != nil {
				log.Errorf("failed to add access log: %v", err)
			}
		}()
		if action == "push" {
			go func() {
				if err := cache.RefreshCatalogCache(); err != nil {
					log.Errorf("failed to refresh cache: %v", err)
				}
			}()

			operation := ""
			if action == "push" {
				operation = models.RepOpTransfer
			}

			go api.TriggerReplicationByRepository(repository, []string{tag}, operation)
		}
	}
}
コード例 #18
0
ファイル: authutils.go プロジェクト: CodingDance/harbor
// FilterAccess modify the action list in access based on permission
// determine if the request needs to be authenticated.
func FilterAccess(username string, authenticated bool, a *token.ResourceActions) {

	if a.Type == "registry" && a.Name == "catalog" {
		log.Infof("current access, type: %s, name:%s, actions:%v \n", a.Type, a.Name, a.Actions)
		return
	}

	//clear action list to assign to new acess element after perm check.
	a.Actions = []string{}
	if a.Type == "repository" {
		if strings.Contains(a.Name, "/") { //Only check the permission when the requested image has a namespace, i.e. project
			projectName := a.Name[0:strings.LastIndex(a.Name, "/")]
			var permission string
			if authenticated {
				isAdmin, err := dao.IsAdminRole(username)
				if err != nil {
					log.Errorf("Error occurred in IsAdminRole: %v", err)
				}
				if isAdmin {
					exist, err := dao.ProjectExists(projectName)
					if err != nil {
						log.Errorf("Error occurred in CheckExistProject: %v", err)
						return
					}
					if exist {
						permission = "RWM"
					} else {
						permission = ""
						log.Infof("project %s does not exist, set empty permission for admin\n", projectName)
					}
				} else {
					permission, err = dao.GetPermission(username, projectName)
					if err != nil {
						log.Errorf("Error occurred in GetPermission: %v", err)
						return
					}
				}
			}
			if strings.Contains(permission, "W") {
				a.Actions = append(a.Actions, "push")
			}
			if strings.Contains(permission, "M") {
				a.Actions = append(a.Actions, "*")
			}
			if strings.Contains(permission, "R") || dao.IsProjectPublic(projectName) {
				a.Actions = append(a.Actions, "pull")
			}
		}
	}
	log.Infof("current access, type: %s, name:%s, actions:%v \n", a.Type, a.Name, a.Actions)
}
コード例 #19
0
ファイル: repository.go プロジェクト: yeyupl/harbor
// GetTags handles GET /api/repositories/tags
func (ra *RepositoryAPI) GetTags() {
	repoName := ra.GetString("repo_name")
	if len(repoName) == 0 {
		ra.CustomAbort(http.StatusBadRequest, "repo_name is nil")
	}

	projectName := getProjectName(repoName)
	project, err := dao.GetProjectByName(projectName)
	if err != nil {
		log.Errorf("failed to get project %s: %v", projectName, err)
		ra.CustomAbort(http.StatusInternalServerError, "")
	}

	if project.Public == 0 {
		userID := ra.ValidateUser()
		if !checkProjectPermission(userID, project.ProjectID) {
			ra.CustomAbort(http.StatusForbidden, "")
		}
	}

	rc, err := ra.initRepositoryClient(repoName)
	if err != nil {
		log.Errorf("error occurred while initializing repository client for %s: %v", repoName, err)
		ra.CustomAbort(http.StatusInternalServerError, "internal error")
	}

	tags := []string{}

	ts, err := rc.ListTag()
	if err != nil {
		regErr, ok := err.(*registry_error.Error)
		if !ok {
			log.Errorf("error occurred while listing tags of %s: %v", repoName, err)
			ra.CustomAbort(http.StatusInternalServerError, "internal error")
		}
		// TODO remove the logic if the bug of registry is fixed
		// It's a workaround for a bug of registry: when listing tags of
		// a repository which is being pushed, a "NAME_UNKNOWN" error will
		// been returned, while the catalog API can list this repository.
		if regErr.StatusCode != http.StatusNotFound {
			ra.CustomAbort(regErr.StatusCode, regErr.Detail)
		}
	}

	tags = append(tags, ts...)

	sort.Strings(tags)

	ra.Data["json"] = tags
	ra.ServeJSON()
}
コード例 #20
0
ファイル: project.go プロジェクト: yaolingling/harbor
// List ...
func (p *ProjectAPI) List() {
	var projectList []models.Project
	projectName := p.GetString("project_name")
	if len(projectName) > 0 {
		projectName = "%" + projectName + "%"
	}
	var public int
	var err error
	isPublic := p.GetString("is_public")
	if len(isPublic) > 0 {
		public, err = strconv.Atoi(isPublic)
		if err != nil {
			log.Errorf("Error parsing public property: %v, error: %v", isPublic, err)
			p.CustomAbort(http.StatusBadRequest, "invalid project Id")
		}
	}
	isAdmin := false
	if public == 1 {
		projectList, err = dao.GetPublicProjects(projectName)
	} else {
		//if the request is not for public projects, user must login or provide credential
		p.userID = p.ValidateUser()
		isAdmin, err = dao.IsAdminRole(p.userID)
		if err != nil {
			log.Errorf("Error occured in check admin, error: %v", err)
			p.CustomAbort(http.StatusInternalServerError, "Internal error.")
		}
		if isAdmin {
			projectList, err = dao.GetAllProjects(projectName)
		} else {
			projectList, err = dao.GetUserRelevantProjects(p.userID, projectName)
		}
	}
	if err != nil {
		log.Errorf("Error occured in get projects info, error: %v", err)
		p.CustomAbort(http.StatusInternalServerError, "Internal error.")
	}
	for i := 0; i < len(projectList); i++ {
		if public != 1 {
			if isAdmin {
				projectList[i].Role = models.PROJECTADMIN
			}
			if projectList[i].Role == models.PROJECTADMIN {
				projectList[i].Togglable = true
			}
		}
		projectList[i].RepoCount = getRepoCountByProject(projectList[i].Name)
	}
	p.Data["json"] = projectList
	p.ServeJSON()
}
コード例 #21
0
ファイル: dao_test.go プロジェクト: yaolingling/harbor
func TestGetRepoJobToStop(t *testing.T) {
	jobs := [...]models.RepJob{
		models.RepJob{
			Repository: "library/ubuntu",
			PolicyID:   policyID,
			Operation:  "transfer",
			Status:     models.JobRunning,
		},
		models.RepJob{
			Repository: "library/ubuntu",
			PolicyID:   policyID,
			Operation:  "transfer",
			Status:     models.JobFinished,
		},
		models.RepJob{
			Repository: "library/ubuntu",
			PolicyID:   policyID,
			Operation:  "transfer",
			Status:     models.JobCanceled,
		},
	}
	var err error
	var i int64
	var ids []int64
	for _, j := range jobs {
		i, err = AddRepJob(j)
		ids = append(ids, i)
		if err != nil {
			log.Errorf("Failed to add Job: %+v, error: %v", j, err)
			return
		}
	}
	res, err := GetRepJobToStop(policyID)
	if err != nil {
		log.Errorf("Failed to Get Jobs, error: %v", err)
		return
	}
	//time.Sleep(15 * time.Second)
	if len(res) != 1 {
		log.Errorf("Expected length of stoppable jobs, expected:1, in fact: %d", len(res))
		return
	}
	for _, id := range ids {
		err = DeleteRepJob(id)
		if err != nil {
			log.Errorf("Failed to delete job, id: %d, error: %v", id, err)
			return
		}
	}
}
コード例 #22
0
ファイル: statistic.go プロジェクト: CodingDance/harbor
// Get total projects and repos of the user
func (s *StatisticAPI) Get() {
	isAdmin, err := dao.IsAdminRole(s.userID)
	if err != nil {
		log.Errorf("Error occured in check admin, error: %v", err)
		s.CustomAbort(http.StatusInternalServerError, "Internal error.")
	}
	var projectList []models.Project
	if isAdmin {
		projectList, err = dao.GetAllProjects("")
	} else {
		projectList, err = dao.GetUserRelevantProjects(s.userID, "")
	}
	if err != nil {
		log.Errorf("Error occured in QueryProject, error: %v", err)
		s.CustomAbort(http.StatusInternalServerError, "Internal error.")
	}
	proMap := map[string]int{}
	proMap["my_project_count"] = 0
	proMap["my_repo_count"] = 0
	proMap["public_project_count"] = 0
	proMap["public_repo_count"] = 0
	var publicProjects []models.Project
	publicProjects, err = dao.GetPublicProjects("")
	if err != nil {
		log.Errorf("Error occured in QueryPublicProject, error: %v", err)
		s.CustomAbort(http.StatusInternalServerError, "Internal error.")
	}
	proMap["public_project_count"] = len(publicProjects)
	for i := 0; i < len(publicProjects); i++ {
		proMap["public_repo_count"] += getRepoCountByProject(publicProjects[i].Name)
	}
	if isAdmin {
		proMap["total_project_count"] = len(projectList)
		proMap["total_repo_count"] = getTotalRepoCount()
	}
	for i := 0; i < len(projectList); i++ {
		if isAdmin {
			projectList[i].Role = models.PROJECTADMIN
		}
		if projectList[i].Role == models.PROJECTADMIN || projectList[i].Role == models.DEVELOPER ||
			projectList[i].Role == models.GUEST {
			proMap["my_project_count"]++
			proMap["my_repo_count"] += getRepoCountByProject(projectList[i].Name)
		}
	}
	s.Data["json"] = proMap
	s.ServeJSON()
}
コード例 #23
0
ファイル: notification.go プロジェクト: yaolingling/harbor
func filterEvents(notification *models.Notification) ([]*models.Event, error) {
	events := []*models.Event{}

	for _, event := range notification.Events {
		isManifest, err := regexp.MatchString(manifestPattern, event.Target.MediaType)
		if err != nil {
			log.Errorf("failed to match the media type against pattern: %v", err)
			continue
		}

		if !isManifest {
			continue
		}

		//pull and push manifest by docker-client
		if strings.HasPrefix(event.Request.UserAgent, "docker") && (event.Action == "pull" || event.Action == "push") {
			events = append(events, &event)
			continue
		}

		//push manifest by docker-client or job-service
		if strings.ToLower(strings.TrimSpace(event.Request.UserAgent)) == "harbor-registry-client" && event.Action == "push" {
			events = append(events, &event)
			continue
		}
	}

	return events, nil
}
コード例 #24
0
ファイル: base.go プロジェクト: yaolingling/harbor
// DecodeJSONReq decodes a json request
func (b *BaseAPI) DecodeJSONReq(v interface{}) {
	err := json.Unmarshal(b.Ctx.Input.CopyBody(1<<32), v)
	if err != nil {
		log.Errorf("Error while decoding the json request, error: %v", err)
		b.CustomAbort(http.StatusBadRequest, "Invalid json request")
	}
}
コード例 #25
0
ファイル: project.go プロジェクト: yaolingling/harbor
// FilterAccessLog handles GET to /api/projects/{}/logs
func (p *ProjectAPI) FilterAccessLog() {
	p.userID = p.ValidateUser()

	var filter models.AccessLog
	p.DecodeJSONReq(&filter)

	username := filter.Username
	keywords := filter.Keywords

	beginTime := time.Unix(filter.BeginTimestamp, 0)
	endTime := time.Unix(filter.EndTimestamp, 0)

	query := models.AccessLog{ProjectID: p.projectID, Username: "******" + username + "%", Keywords: keywords, BeginTime: beginTime, BeginTimestamp: filter.BeginTimestamp, EndTime: endTime, EndTimestamp: filter.EndTimestamp}

	log.Infof("Query AccessLog: begin: %v, end: %v, keywords: %s", query.BeginTime, query.EndTime, query.Keywords)

	accessLogList, err := dao.GetAccessLogs(query)
	if err != nil {
		log.Errorf("Error occurred in GetAccessLogs, error: %v", err)
		p.CustomAbort(http.StatusInternalServerError, "Internal error.")
	}
	p.Data["json"] = accessLogList

	p.ServeJSON()
}
コード例 #26
0
ファイル: project.go プロジェクト: yaolingling/harbor
// Head ...
func (p *ProjectAPI) Head() {
	projectName := p.GetString("project_name")
	if len(projectName) == 0 {
		p.CustomAbort(http.StatusBadRequest, "project_name is needed")
	}

	project, err := dao.GetProjectByName(projectName)
	if err != nil {
		log.Errorf("error occurred in GetProjectByName: %v", err)
		p.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
	}

	// only public project can be Headed by user without login
	if project != nil && project.Public == 1 {
		return
	}

	userID := p.ValidateUser()
	if project == nil {
		p.CustomAbort(http.StatusNotFound, http.StatusText(http.StatusNotFound))
	}

	if !checkProjectPermission(userID, project.ProjectID) {
		p.CustomAbort(http.StatusForbidden, http.StatusText(http.StatusForbidden))
	}
}
コード例 #27
0
ファイル: base.go プロジェクト: CodingDance/harbor
//InitDB initializes the database
func InitDB() {
	orm.RegisterDriver("mysql", orm.DRMySQL)
	addr := os.Getenv("MYSQL_HOST")
	port := os.Getenv("MYSQL_PORT")
	username := os.Getenv("MYSQL_USR")
	password := os.Getenv("MYSQL_PWD")

	log.Debugf("db url: %s:%s, db user: %s", addr, port, username)
	dbStr := username + ":" + password + "@tcp(" + addr + ":" + port + ")/registry"
	ch := make(chan int, 1)
	go func() {
		var err error
		var c net.Conn
		for {
			c, err = net.DialTimeout("tcp", addr+":"+port, 20*time.Second)
			if err == nil {
				c.Close()
				ch <- 1
			} else {
				log.Errorf("failed to connect to db, retry after 2 seconds :%v", err)
				time.Sleep(2 * time.Second)
			}
		}
	}()
	select {
	case <-ch:
	case <-time.After(60 * time.Second):
		panic("Failed to connect to DB after 60 seconds")
	}
	err := orm.RegisterDataBase("default", "mysql", dbStr)
	if err != nil {
		panic(err)
	}
}
コード例 #28
0
ファイル: base.go プロジェクト: yaolingling/harbor
func init() {

	//conf/app.conf -> os.Getenv("config_path")
	configPath := os.Getenv("CONFIG_PATH")
	if len(configPath) != 0 {
		log.Infof("Config path: %s", configPath)
		beego.LoadAppConfig("ini", configPath)
	}

	beego.AddFuncMap("i18n", i18n.Tr)

	langs := strings.Split(beego.AppConfig.String("lang::types"), "|")
	names := strings.Split(beego.AppConfig.String("lang::names"), "|")

	supportLanguages = make(map[string]langType)

	langTypes = make([]*langType, 0, len(langs))

	for i, lang := range langs {
		t := langType{
			Lang: lang,
			Name: names[i],
		}
		langTypes = append(langTypes, &t)
		supportLanguages[lang] = t
		if err := i18n.SetMessage(lang, "static/i18n/"+"locale_"+lang+".ini"); err != nil {
			log.Errorf("Fail to set message file: %s", err.Error())
		}
	}

}
コード例 #29
0
ファイル: logger.go プロジェクト: yaolingling/harbor
// NewLogger create a logger for a speicified job
func NewLogger(jobID int64) *log.Logger {
	logFile := GetJobLogPath(jobID)
	d := filepath.Dir(logFile)
	if _, err := os.Stat(d); os.IsNotExist(err) {
		err := os.MkdirAll(d, 0660)
		if err != nil {
			log.Errorf("Failed to create directory for log file %s, the error: %v", logFile, err)
		}
	}
	f, err := os.OpenFile(logFile, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0660)
	if err != nil {
		log.Errorf("Failed to open log file %s, the log of job %d will be printed to standard output, the error: %v", logFile, jobID, err)
		f = os.Stdout
	}
	return log.New(f, log.NewTextFormatter(), log.InfoLevel)
}
コード例 #30
0
ファイル: statemachine.go プロジェクト: yaolingling/harbor
// Start kicks off the statemachine to transit from current state to s, and moves on
// It will search the transit map if the next state is "_continue", and
// will enter error state if there's more than one possible path when next state is "_continue"
func (sm *SM) Start(s string) {
	n, err := sm.EnterState(s)
	log.Debugf("Job id: %d, next state from handler: %s", sm.JobID, n)
	for len(n) > 0 && err == nil {
		if d := sm.getDesiredState(); len(d) > 0 {
			log.Debugf("Job id: %d. Desired state: %s, will ignore the next state from handler", sm.JobID, d)
			n = d
			sm.setDesiredState("")
			continue
		}
		if n == models.JobContinue && len(sm.Transitions[sm.CurrentState]) == 1 {
			for n = range sm.Transitions[sm.CurrentState] {
				break
			}
			log.Debugf("Job id: %d, Continue to state: %s", sm.JobID, n)
			continue
		}
		if n == models.JobContinue && len(sm.Transitions[sm.CurrentState]) != 1 {
			log.Errorf("Job id: %d, next state is continue but there are %d possible next states in transition table", sm.JobID, len(sm.Transitions[sm.CurrentState]))
			err = fmt.Errorf("Unable to continue")
			break
		}
		n, err = sm.EnterState(n)
		log.Debugf("Job id: %d, next state from handler: %s", sm.JobID, n)
	}
	if err != nil {
		log.Warningf("Job id: %d, the statemachin will enter error state due to error: %v", sm.JobID, err)
		sm.EnterState(models.JobError)
	}
}