mirror of
https://github.com/goharbor/harbor.git
synced 2024-12-26 10:38:00 +01:00
implement project manager based on PMS
This commit is contained in:
parent
0679796528
commit
0925fd35f1
@ -91,6 +91,7 @@ script:
|
||||
- ./tests/pushimage.sh
|
||||
- cd tests
|
||||
- sudo ./ldapprepare.sh
|
||||
- sudo ./admiral.sh
|
||||
- cd ..
|
||||
- go test -i ./src/ui ./src/adminserver ./src/jobservice
|
||||
- sudo -E env "PATH=$PATH" ./tests/coverage4gotest.sh
|
||||
|
@ -28,9 +28,6 @@ const (
|
||||
RoleDeveloper = 2
|
||||
RoleGuest = 3
|
||||
|
||||
DeployModeStandAlone = "standalone"
|
||||
DeployModeIntegration = "integration"
|
||||
|
||||
ExtEndpoint = "ext_endpoint"
|
||||
AUTHMode = "auth_mode"
|
||||
DatabaseType = "database_type"
|
||||
|
@ -31,11 +31,14 @@ type Project struct {
|
||||
OwnerName string `orm:"-" json:"owner_name"`
|
||||
Public int `orm:"column(public)" json:"public"`
|
||||
//This field does not have correspondent column in DB, this is just for UI to disable button
|
||||
Togglable bool `orm:"-"`
|
||||
|
||||
UpdateTime time.Time `orm:"update_time" json:"update_time"`
|
||||
Role int `orm:"-" json:"current_user_role_id"`
|
||||
RepoCount int `orm:"-" json:"repo_count"`
|
||||
Togglable bool `orm:"-"`
|
||||
UpdateTime time.Time `orm:"update_time" json:"update_time"`
|
||||
Role int `orm:"-" json:"current_user_role_id"`
|
||||
RepoCount int `orm:"-" json:"repo_count"`
|
||||
EnableContentTrust bool `orm:"-" json:"enable_content_trust"`
|
||||
PreventVulnerableImagesFromRunning bool `orm:"-" json:"prevent_vulnerable_images_from_running"`
|
||||
PreventVulnerableImagesFromRunningSeverity string `orm:"-" json:"prevent_vulnerable_images_from_running_severity"`
|
||||
AutomaticallyScanImagesOnPush bool `orm:"-" json:"automatically_scan_images_on_push"`
|
||||
}
|
||||
|
||||
// ProjectSorter holds an array of projects
|
||||
|
@ -95,8 +95,7 @@ func initSecretStore() {
|
||||
}
|
||||
|
||||
func initProjectManager() {
|
||||
if len(DeployMode()) == 0 ||
|
||||
DeployMode() == common.DeployModeStandAlone {
|
||||
if !WithAdmiral() {
|
||||
log.Info("initializing the project manager based on database...")
|
||||
GlobalProjectMgr = &db.ProjectManager{}
|
||||
}
|
||||
@ -332,9 +331,3 @@ func AdmiralEndpoint() string {
|
||||
func WithAdmiral() bool {
|
||||
return len(AdmiralEndpoint()) > 0
|
||||
}
|
||||
|
||||
// DeployMode returns the deploy mode
|
||||
// TODO read from adminserver
|
||||
func DeployMode() string {
|
||||
return common.DeployModeStandAlone
|
||||
}
|
||||
|
@ -21,7 +21,6 @@ import (
|
||||
"strings"
|
||||
|
||||
beegoctx "github.com/astaxie/beego/context"
|
||||
"github.com/vmware/harbor/src/common"
|
||||
"github.com/vmware/harbor/src/common/models"
|
||||
"github.com/vmware/harbor/src/common/security"
|
||||
"github.com/vmware/harbor/src/common/security/rbac"
|
||||
@ -30,6 +29,7 @@ import (
|
||||
"github.com/vmware/harbor/src/ui/auth"
|
||||
"github.com/vmware/harbor/src/ui/config"
|
||||
"github.com/vmware/harbor/src/ui/projectmanager"
|
||||
"github.com/vmware/harbor/src/ui/projectmanager/pms"
|
||||
)
|
||||
|
||||
type key string
|
||||
@ -133,15 +133,14 @@ func fillContext(ctx *beegoctx.Context) {
|
||||
}
|
||||
|
||||
func getProjectManager(ctx *beegoctx.Context) projectmanager.ProjectManager {
|
||||
if len(config.DeployMode()) == 0 ||
|
||||
config.DeployMode() == common.DeployModeStandAlone {
|
||||
if !config.WithAdmiral() {
|
||||
log.Info("filling a project manager based on database...")
|
||||
return config.GlobalProjectMgr
|
||||
}
|
||||
|
||||
// TODO create project manager based on pms
|
||||
log.Info("filling a project manager based on pms...")
|
||||
return nil
|
||||
log.Info("filling a project manager based on PMS...")
|
||||
// TODO pass the token to the function
|
||||
return pms.NewProjectManager(config.AdmiralEndpoint(), "")
|
||||
}
|
||||
|
||||
// GetSecurityContext tries to get security context from request and returns it
|
||||
|
410
src/ui/projectmanager/pms/pm.go
Normal file
410
src/ui/projectmanager/pms/pm.go
Normal file
@ -0,0 +1,410 @@
|
||||
// Copyright (c) 2017 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.
|
||||
|
||||
package pms
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/vmware/harbor/src/common"
|
||||
"github.com/vmware/harbor/src/common/models"
|
||||
"github.com/vmware/harbor/src/common/utils/log"
|
||||
er "github.com/vmware/harbor/src/common/utils/registry/error"
|
||||
)
|
||||
|
||||
var transport = &http.Transport{}
|
||||
|
||||
// ProjectManager implements projectmanager.ProjecdtManager interface
|
||||
// base on project management service
|
||||
type ProjectManager struct {
|
||||
endpoint string
|
||||
token string
|
||||
client *http.Client
|
||||
}
|
||||
|
||||
type user struct {
|
||||
Email string `json:"email"`
|
||||
}
|
||||
|
||||
type project struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Public bool `json:"isPublic"`
|
||||
OwnerID string `json:"documentOwner"`
|
||||
CustomProperties map[string]string `json:"customProperties"`
|
||||
Administrators []*user `json:"administrators"`
|
||||
Developers []*user `json:"members"`
|
||||
Guests []*user `json:"guests"` // TODO the json name needs to be modified according to the API
|
||||
}
|
||||
|
||||
// NewProjectManager returns an instance of ProjectManager
|
||||
func NewProjectManager(endpoint, token string) *ProjectManager {
|
||||
return &ProjectManager{
|
||||
endpoint: strings.TrimRight(endpoint, "/"),
|
||||
token: token,
|
||||
client: &http.Client{
|
||||
Transport: transport,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Get ...
|
||||
func (p *ProjectManager) Get(projectIDOrName interface{}) (*models.Project, error) {
|
||||
project, err := p.get(projectIDOrName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return convert(project)
|
||||
}
|
||||
|
||||
func (p *ProjectManager) get(projectIDOrName interface{}) (*project, error) {
|
||||
var key, value interface{}
|
||||
if id, ok := projectIDOrName.(int64); ok {
|
||||
key = "customProperties.__harborId"
|
||||
value = id
|
||||
} else if name, ok := projectIDOrName.(string); ok {
|
||||
key = "name"
|
||||
value = name
|
||||
} else {
|
||||
return nil, fmt.Errorf("unsupported type: %v", projectIDOrName)
|
||||
}
|
||||
|
||||
path := fmt.Sprintf("/projects?$filter=%s eq '%v'", key, value)
|
||||
data, err := p.send(http.MethodGet, path, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
projects, err := parse(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(projects) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if len(projects) != 1 {
|
||||
return nil, fmt.Errorf("unexpected size of project list: %d != 1", len(projects))
|
||||
}
|
||||
|
||||
return projects[0], nil
|
||||
}
|
||||
|
||||
// parse the response of GET /projects?xxx to project list
|
||||
func parse(b []byte) ([]*project, error) {
|
||||
documents := &struct {
|
||||
//TotalCount int64 `json:"totalCount"`
|
||||
//DocumentCount int64 `json:"documentCount"`
|
||||
Projects map[string]*project `json:"documents"`
|
||||
}{}
|
||||
if err := json.Unmarshal(b, documents); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
projects := []*project{}
|
||||
for link, project := range documents.Projects {
|
||||
project.ID = strings.TrimLeft(link, "/projects/")
|
||||
projects = append(projects, project)
|
||||
}
|
||||
|
||||
return projects, nil
|
||||
}
|
||||
|
||||
func convert(p *project) (*models.Project, error) {
|
||||
if p == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
project := &models.Project{
|
||||
Name: p.Name,
|
||||
}
|
||||
if p.Public {
|
||||
project.Public = 1
|
||||
}
|
||||
|
||||
value := p.CustomProperties["__harborId"]
|
||||
if len(value) == 0 {
|
||||
return nil, fmt.Errorf("property __harborId is null")
|
||||
}
|
||||
|
||||
id, err := strconv.ParseInt(value, 10, 64)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse __harborId %s to int64: %v", value, err)
|
||||
}
|
||||
project.ProjectID = id
|
||||
|
||||
value = p.CustomProperties["__enableContentTrust"]
|
||||
if len(value) != 0 {
|
||||
enable, err := strconv.ParseBool(value)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse __enableContentTrust %s to bool: %v", value, err)
|
||||
}
|
||||
project.EnableContentTrust = enable
|
||||
}
|
||||
|
||||
value = p.CustomProperties["__preventVulnerableImagesFromRunning"]
|
||||
if len(value) != 0 {
|
||||
prevent, err := strconv.ParseBool(value)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse __preventVulnerableImagesFromRunning %s to bool: %v", value, err)
|
||||
}
|
||||
project.PreventVulnerableImagesFromRunning = prevent
|
||||
}
|
||||
|
||||
value = p.CustomProperties["__preventVulnerableImagesFromRunningSeverity"]
|
||||
if len(value) != 0 {
|
||||
project.PreventVulnerableImagesFromRunningSeverity = value
|
||||
}
|
||||
|
||||
value = p.CustomProperties["__automaticallyScanImagesOnPush"]
|
||||
if len(value) != 0 {
|
||||
scan, err := strconv.ParseBool(value)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse __automaticallyScanImagesOnPush %s to bool: %v", value, err)
|
||||
}
|
||||
project.AutomaticallyScanImagesOnPush = scan
|
||||
}
|
||||
|
||||
return project, nil
|
||||
}
|
||||
|
||||
// IsPublic ...
|
||||
func (p *ProjectManager) IsPublic(projectIDOrName interface{}) (bool, error) {
|
||||
project, err := p.get(projectIDOrName)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if project == nil {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return project.Public, nil
|
||||
}
|
||||
|
||||
// Exist ...
|
||||
func (p *ProjectManager) Exist(projectIDOrName interface{}) (bool, error) {
|
||||
project, err := p.get(projectIDOrName)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return project != nil, nil
|
||||
}
|
||||
|
||||
// GetRoles ...
|
||||
func (p *ProjectManager) GetRoles(username string, projectIDOrName interface{}) ([]int, error) {
|
||||
if len(username) == 0 || projectIDOrName == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
id, err := p.getIDbyHarborIDOrName(projectIDOrName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// get expanded project which contains role info by GET /projects/id?expand=true
|
||||
path := fmt.Sprintf("/projects/%s?expand=true", id)
|
||||
data, err := p.send(http.MethodGet, path, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pro := &project{}
|
||||
if err = json.Unmarshal(data, pro); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
roles := []int{}
|
||||
|
||||
for _, user := range pro.Administrators {
|
||||
if user.Email == username {
|
||||
roles = append(roles, common.RoleProjectAdmin)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
for _, user := range pro.Developers {
|
||||
if user.Email == username {
|
||||
roles = append(roles, common.RoleDeveloper)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
for _, user := range pro.Guests {
|
||||
if user.Email == username {
|
||||
roles = append(roles, common.RoleGuest)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return roles, nil
|
||||
}
|
||||
|
||||
func (p *ProjectManager) getIDbyHarborIDOrName(projectIDOrName interface{}) (string, error) {
|
||||
pro, err := p.get(projectIDOrName)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if pro == nil {
|
||||
return "", fmt.Errorf("project %v not found", projectIDOrName)
|
||||
}
|
||||
|
||||
return pro.ID, nil
|
||||
}
|
||||
|
||||
// GetPublic ...
|
||||
func (p *ProjectManager) GetPublic() ([]*models.Project, error) {
|
||||
path := "/projects?$filter=isPublic eq 'true'"
|
||||
data, err := p.send(http.MethodGet, path, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
projects, err := parse(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
list := []*models.Project{}
|
||||
for _, p := range projects {
|
||||
project, err := convert(p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
list = append(list, project)
|
||||
}
|
||||
|
||||
return list, nil
|
||||
}
|
||||
|
||||
// GetByMember ...
|
||||
func (p *ProjectManager) GetByMember(username string) ([]*models.Project, error) {
|
||||
// TODO add implement
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Create ...
|
||||
func (p *ProjectManager) Create(pro *models.Project) (int64, error) {
|
||||
proj := &project{
|
||||
CustomProperties: make(map[string]string),
|
||||
}
|
||||
proj.Name = pro.Name
|
||||
proj.Public = pro.Public == 1
|
||||
proj.CustomProperties["__enableContentTrust"] = strconv.FormatBool(pro.EnableContentTrust)
|
||||
proj.CustomProperties["__preventVulnerableImagesFromRunning"] = strconv.FormatBool(pro.PreventVulnerableImagesFromRunning)
|
||||
proj.CustomProperties["__preventVulnerableImagesFromRunningSeverity"] = pro.PreventVulnerableImagesFromRunningSeverity
|
||||
proj.CustomProperties["__automaticallyScanImagesOnPush"] = strconv.FormatBool(pro.AutomaticallyScanImagesOnPush)
|
||||
|
||||
// TODO remove the logic if Admiral generates the harborId
|
||||
proj.CustomProperties["__harborId"] = strconv.FormatInt(time.Now().UnixNano(), 10)
|
||||
|
||||
data, err := json.Marshal(proj)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
b, err := p.send(http.MethodPost, "/projects", bytes.NewBuffer(data))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
proj = &project{}
|
||||
if err = json.Unmarshal(b, proj); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
pp, err := convert(proj)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return pp.ProjectID, err
|
||||
}
|
||||
|
||||
// Delete ...
|
||||
func (p *ProjectManager) Delete(projectIDOrName interface{}) error {
|
||||
id, err := p.getIDbyHarborIDOrName(projectIDOrName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = p.send(http.MethodDelete, fmt.Sprintf("/projects/%s", id), nil)
|
||||
return err
|
||||
}
|
||||
|
||||
// Update ...
|
||||
func (p *ProjectManager) Update(projectIDOrName interface{}, project *models.Project) error {
|
||||
return errors.New("project update is unsupported")
|
||||
}
|
||||
|
||||
// GetAll ...
|
||||
func (p *ProjectManager) GetAll(query *models.ProjectQueryParam) ([]*models.Project, error) {
|
||||
return nil, errors.New("get all projects is unsupported")
|
||||
}
|
||||
|
||||
// GetTotal ...
|
||||
func (p *ProjectManager) GetTotal(query *models.ProjectQueryParam) (int64, error) {
|
||||
return 0, errors.New("get total of projects is unsupported")
|
||||
}
|
||||
|
||||
// GetHasReadPerm ...
|
||||
func (p *ProjectManager) GetHasReadPerm(username ...string) ([]*models.Project, error) {
|
||||
// TODO add implement
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (p *ProjectManager) send(method, path string, body io.Reader) ([]byte, error) {
|
||||
req, err := http.NewRequest(method, p.endpoint+path, body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req.Header.Add("x-xenon-auth-token", p.token)
|
||||
|
||||
req.URL.RawQuery = req.URL.Query().Encode()
|
||||
url := req.URL.String()
|
||||
|
||||
resp, err := p.client.Do(req)
|
||||
if err != nil {
|
||||
log.Debugf("\"%s %s\" %d", req.Method, url, 0)
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
log.Debugf("\"%s %s\" %d", req.Method, url, resp.StatusCode)
|
||||
|
||||
b, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, &er.Error{
|
||||
StatusCode: resp.StatusCode,
|
||||
Detail: string(b),
|
||||
}
|
||||
}
|
||||
|
||||
return b, nil
|
||||
}
|
424
src/ui/projectmanager/pms/pm_test.go
Normal file
424
src/ui/projectmanager/pms/pm_test.go
Normal file
@ -0,0 +1,424 @@
|
||||
// Copyright (c) 2017 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.
|
||||
|
||||
package pms
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/vmware/harbor/src/common/models"
|
||||
)
|
||||
|
||||
var (
|
||||
endpoint = "http://127.0.0.1:8282"
|
||||
token = ""
|
||||
)
|
||||
|
||||
func TestConvert(t *testing.T) {
|
||||
//nil project
|
||||
pro, err := convert(nil)
|
||||
assert.Nil(t, err)
|
||||
assert.Nil(t, pro)
|
||||
|
||||
//project without property __harborId
|
||||
p := &project{}
|
||||
pro, err = convert(p)
|
||||
assert.NotNil(t, err)
|
||||
assert.Nil(t, pro)
|
||||
|
||||
//project with invalid __harborId
|
||||
p = &project{
|
||||
CustomProperties: map[string]string{
|
||||
"__harborId": "invalid_value",
|
||||
},
|
||||
}
|
||||
pro, err = convert(p)
|
||||
assert.NotNil(t, err)
|
||||
assert.Nil(t, pro)
|
||||
|
||||
//project with invalid __enableContentTrust
|
||||
p = &project{
|
||||
CustomProperties: map[string]string{
|
||||
"__enableContentTrust": "invalid_value",
|
||||
},
|
||||
}
|
||||
pro, err = convert(p)
|
||||
assert.NotNil(t, err)
|
||||
assert.Nil(t, pro)
|
||||
|
||||
//project with invalid __preventVulnerableImagesFromRunning
|
||||
p = &project{
|
||||
CustomProperties: map[string]string{
|
||||
"__preventVulnerableImagesFromRunning": "invalid_value",
|
||||
},
|
||||
}
|
||||
pro, err = convert(p)
|
||||
assert.NotNil(t, err)
|
||||
assert.Nil(t, pro)
|
||||
|
||||
//project with invalid __automaticallyScanImagesOnPush
|
||||
p = &project{
|
||||
CustomProperties: map[string]string{
|
||||
"__automaticallyScanImagesOnPush": "invalid_value",
|
||||
},
|
||||
}
|
||||
pro, err = convert(p)
|
||||
assert.NotNil(t, err)
|
||||
assert.Nil(t, pro)
|
||||
|
||||
//valid project
|
||||
p = &project{
|
||||
Name: "test",
|
||||
Public: true,
|
||||
CustomProperties: map[string]string{
|
||||
"__harborId": "1",
|
||||
"__enableContentTrust": "true",
|
||||
"__preventVulnerableImagesFromRunning": "true",
|
||||
"__preventVulnerableImagesFromRunningSeverity": "medium",
|
||||
"__automaticallyScanImagesOnPush": "true",
|
||||
},
|
||||
}
|
||||
pro, err = convert(p)
|
||||
assert.Nil(t, err)
|
||||
assert.NotNil(t, pro)
|
||||
assert.Equal(t, "test", pro.Name)
|
||||
assert.Equal(t, 1, pro.Public)
|
||||
assert.Equal(t, int64(1), pro.ProjectID)
|
||||
assert.True(t, pro.EnableContentTrust)
|
||||
assert.True(t, pro.PreventVulnerableImagesFromRunning)
|
||||
assert.Equal(t, "medium", pro.PreventVulnerableImagesFromRunningSeverity)
|
||||
assert.True(t, pro.AutomaticallyScanImagesOnPush)
|
||||
}
|
||||
|
||||
func TestParse(t *testing.T) {
|
||||
data := `{
|
||||
"totalCount": 2,
|
||||
"documentLinks": [
|
||||
"/projects/default-project",
|
||||
"/projects/fc6c6c7ddd430875551449a65e7c8"
|
||||
],
|
||||
"documents": {
|
||||
"/projects/fc6c6c7ddd430875551449a65e7c8": {
|
||||
"isPublic": false,
|
||||
"description": "This is a test project.",
|
||||
"id": "41427587-70e9-4671-9a9e-b9def0a07bb7",
|
||||
"name": "project02",
|
||||
"customProperties": {
|
||||
"__harborId": "2",
|
||||
"__enableContentTrust": "true",
|
||||
"__preventVulnerableImagesFromRunning": "true",
|
||||
"__preventVulnerableImagesFromRunningSeverity": "medium",
|
||||
"__automaticallyScanImagesOnPush": "false"
|
||||
},
|
||||
"documentVersion": 0,
|
||||
"documentEpoch": 0,
|
||||
"documentKind": "com:vmware:admiral:auth:project:ProjectService:ProjectState",
|
||||
"documentSelfLink": "/projects/fc6c6c7ddd430875551449a65e7c8",
|
||||
"documentUpdateTimeMicros": 1496729973549001,
|
||||
"documentUpdateAction": "POST",
|
||||
"documentExpirationTimeMicros": 0,
|
||||
"documentOwner": "f65900c4-2b6a-4671-8cf7-c17340dd3d39"
|
||||
},
|
||||
"/projects/default-project": {
|
||||
"isPublic": false,
|
||||
"administratorsUserGroupLink": "/core/authz/user-groups/fc6c6c7ddd43087555143835bcaf8",
|
||||
"membersUserGroupLink": "/core/authz/user-groups/fc6c6c7ddd43087555143835bde80",
|
||||
"id": "default-project",
|
||||
"name": "default-project",
|
||||
"customProperties": {
|
||||
"__harborId": "2",
|
||||
"__enableContentTrust": "true",
|
||||
"__preventVulnerableImagesFromRunning": "true",
|
||||
"__preventVulnerableImagesFromRunningSeverity": "medium",
|
||||
"__automaticallyScanImagesOnPush": "false"
|
||||
},
|
||||
"documentVersion": 0,
|
||||
"documentEpoch": 0,
|
||||
"documentKind": "com:vmware:admiral:auth:project:ProjectService:ProjectState",
|
||||
"documentSelfLink": "/projects/default-project",
|
||||
"documentUpdateTimeMicros": 1496725292012001,
|
||||
"documentUpdateAction": "POST",
|
||||
"documentExpirationTimeMicros": 0,
|
||||
"documentOwner": "f65900c4-2b6a-4671-8cf7-c17340dd3d39",
|
||||
"documentAuthPrincipalLink": "/core/authz/system-user"
|
||||
}
|
||||
},
|
||||
"documentCount": 2,
|
||||
"queryTimeMicros": 1,
|
||||
"documentVersion": 0,
|
||||
"documentUpdateTimeMicros": 0,
|
||||
"documentExpirationTimeMicros": 0,
|
||||
"documentOwner": "f65900c4-2b6a-4671-8cf7-c17340dd3d39"
|
||||
}`
|
||||
|
||||
projects, err := parse([]byte(data))
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 2, len(projects))
|
||||
|
||||
ids := []string{projects[0].ID, projects[1].ID}
|
||||
sort.Strings(ids)
|
||||
|
||||
assert.Equal(t, "default-project", ids[0])
|
||||
assert.Equal(t, "fc6c6c7ddd430875551449a65e7c8", ids[1])
|
||||
}
|
||||
|
||||
func TestGet(t *testing.T) {
|
||||
pm := NewProjectManager(endpoint, token)
|
||||
name := "project_for_pm_based_on_pms"
|
||||
id, err := pm.Create(&models.Project{
|
||||
Name: name,
|
||||
})
|
||||
require.Nil(t, err)
|
||||
defer pm.Delete(id)
|
||||
|
||||
// get by invalid input type
|
||||
_, err = pm.Get([]string{})
|
||||
assert.NotNil(t, err)
|
||||
|
||||
// get by invalid ID
|
||||
project, err := pm.Get(int64(0))
|
||||
assert.Nil(t, err)
|
||||
assert.Nil(t, project)
|
||||
|
||||
// get by invalid name
|
||||
project, err = pm.Get("invalid_name")
|
||||
assert.Nil(t, err)
|
||||
assert.Nil(t, project)
|
||||
|
||||
// get by valid ID
|
||||
project, err = pm.Get(id)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, id, project.ProjectID)
|
||||
|
||||
// get by valid name
|
||||
project, err = pm.Get(name)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, id, project.ProjectID)
|
||||
}
|
||||
|
||||
func TestIsPublic(t *testing.T) {
|
||||
pm := NewProjectManager(endpoint, token)
|
||||
|
||||
// invalid input type
|
||||
public, err := pm.IsPublic([]string{})
|
||||
assert.NotNil(t, err)
|
||||
assert.False(t, public)
|
||||
|
||||
// non-exist project
|
||||
public, err = pm.IsPublic(int64(0))
|
||||
assert.Nil(t, err)
|
||||
assert.False(t, public)
|
||||
|
||||
// public project
|
||||
name := "project_for_pm_based_on_pms_public"
|
||||
id, err := pm.Create(&models.Project{
|
||||
Name: name,
|
||||
Public: 1,
|
||||
})
|
||||
require.Nil(t, err)
|
||||
defer pm.Delete(id)
|
||||
|
||||
public, err = pm.IsPublic(id)
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, public)
|
||||
|
||||
public, err = pm.IsPublic(name)
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, public)
|
||||
|
||||
// private project
|
||||
name = "project_for_pm_based_on_pms_private"
|
||||
id, err = pm.Create(&models.Project{
|
||||
Name: name,
|
||||
Public: 0,
|
||||
})
|
||||
require.Nil(t, err)
|
||||
defer pm.Delete(id)
|
||||
|
||||
public, err = pm.IsPublic(id)
|
||||
assert.Nil(t, err)
|
||||
assert.False(t, public)
|
||||
|
||||
public, err = pm.IsPublic(name)
|
||||
assert.Nil(t, err)
|
||||
assert.False(t, public)
|
||||
}
|
||||
|
||||
func TestExist(t *testing.T) {
|
||||
pm := NewProjectManager(endpoint, token)
|
||||
|
||||
// invalid input type
|
||||
exist, err := pm.Exist([]string{})
|
||||
assert.NotNil(t, err)
|
||||
assert.False(t, exist)
|
||||
|
||||
// non-exist project
|
||||
exist, err = pm.Exist(int64(0))
|
||||
assert.Nil(t, err)
|
||||
assert.False(t, exist)
|
||||
|
||||
// exist project
|
||||
name := "project_for_pm_based_on_pms"
|
||||
id, err := pm.Create(&models.Project{
|
||||
Name: name,
|
||||
})
|
||||
require.Nil(t, err)
|
||||
defer pm.Delete(id)
|
||||
|
||||
exist, err = pm.Exist(id)
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, exist)
|
||||
|
||||
exist, err = pm.Exist(name)
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, exist)
|
||||
}
|
||||
|
||||
func TestGetRoles(t *testing.T) {
|
||||
pm := NewProjectManager(endpoint, token)
|
||||
|
||||
// nil username, nil project
|
||||
roles, err := pm.GetRoles("", nil)
|
||||
assert.Nil(t, err)
|
||||
assert.Zero(t, len(roles))
|
||||
|
||||
// non-exist project
|
||||
_, err = pm.GetRoles("user01", "non_exist_project")
|
||||
assert.NotNil(t, err)
|
||||
|
||||
// exist project
|
||||
name := "project_for_pm_based_on_pms"
|
||||
id, err := pm.Create(&models.Project{
|
||||
Name: name,
|
||||
})
|
||||
require.Nil(t, err)
|
||||
defer pm.Delete(id)
|
||||
|
||||
roles, err = pm.GetRoles("user01", id)
|
||||
assert.Nil(t, err)
|
||||
assert.Zero(t, len(roles))
|
||||
|
||||
// TODO add test cases for real role of user
|
||||
}
|
||||
|
||||
func TestGetPublic(t *testing.T) {
|
||||
pm := NewProjectManager(endpoint, token)
|
||||
|
||||
projects, err := pm.GetPublic()
|
||||
assert.Nil(t, nil)
|
||||
size := len(projects)
|
||||
|
||||
name := "project_for_pm_based_on_pms"
|
||||
id, err := pm.Create(&models.Project{
|
||||
Name: name,
|
||||
Public: 1,
|
||||
})
|
||||
require.Nil(t, err)
|
||||
defer pm.Delete(id)
|
||||
|
||||
projects, err = pm.GetPublic()
|
||||
assert.Nil(t, nil)
|
||||
assert.Equal(t, size+1, len(projects))
|
||||
|
||||
found := false
|
||||
for _, project := range projects {
|
||||
if project.ProjectID == id {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
assert.True(t, found)
|
||||
}
|
||||
|
||||
// TODO add test case
|
||||
func TestGetByMember(t *testing.T) {
|
||||
|
||||
}
|
||||
|
||||
func TestCreate(t *testing.T) {
|
||||
pm := NewProjectManager(endpoint, token)
|
||||
|
||||
name := "project_for_pm_based_on_pms"
|
||||
id, err := pm.Create(&models.Project{
|
||||
Name: name,
|
||||
Public: 1,
|
||||
EnableContentTrust: true,
|
||||
PreventVulnerableImagesFromRunning: true,
|
||||
PreventVulnerableImagesFromRunningSeverity: "medium",
|
||||
AutomaticallyScanImagesOnPush: true,
|
||||
})
|
||||
require.Nil(t, err)
|
||||
defer pm.Delete(id)
|
||||
|
||||
project, err := pm.Get(id)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, name, project.Name)
|
||||
assert.Equal(t, 1, project.Public)
|
||||
assert.True(t, project.EnableContentTrust)
|
||||
assert.True(t, project.PreventVulnerableImagesFromRunning)
|
||||
assert.Equal(t, "medium", project.PreventVulnerableImagesFromRunningSeverity)
|
||||
assert.True(t, project.AutomaticallyScanImagesOnPush)
|
||||
}
|
||||
|
||||
func TestDelete(t *testing.T) {
|
||||
pm := NewProjectManager(endpoint, token)
|
||||
|
||||
// non-exist project
|
||||
err := pm.Delete(int64(0))
|
||||
assert.NotNil(t, err)
|
||||
|
||||
// delete by ID
|
||||
name := "project_for_pm_based_on_pms_id"
|
||||
id, err := pm.Create(&models.Project{
|
||||
Name: name,
|
||||
})
|
||||
require.Nil(t, err)
|
||||
err = pm.Delete(id)
|
||||
assert.Nil(t, err)
|
||||
|
||||
// delete by name
|
||||
name = "project_for_pm_based_on_pms_name"
|
||||
id, err = pm.Create(&models.Project{
|
||||
Name: name,
|
||||
})
|
||||
require.Nil(t, err)
|
||||
err = pm.Delete(name)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
|
||||
func TestUpdate(t *testing.T) {
|
||||
pm := NewProjectManager(endpoint, token)
|
||||
err := pm.Update(nil, nil)
|
||||
assert.NotNil(t, err)
|
||||
}
|
||||
|
||||
func TestGetAll(t *testing.T) {
|
||||
pm := NewProjectManager(endpoint, token)
|
||||
_, err := pm.GetAll(nil)
|
||||
assert.NotNil(t, err)
|
||||
}
|
||||
|
||||
func TestGetTotal(t *testing.T) {
|
||||
pm := NewProjectManager(endpoint, token)
|
||||
_, err := pm.GetTotal(nil)
|
||||
assert.NotNil(t, err)
|
||||
}
|
||||
|
||||
// TODO add test case
|
||||
func TestGetHasReadPerm(t *testing.T) {
|
||||
|
||||
}
|
7
tests/admiral.sh
Executable file
7
tests/admiral.sh
Executable file
@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
# run admiral for unit test
|
||||
name=admiral
|
||||
port=8282
|
||||
docker rm -f $name 2>/dev/null
|
||||
docker run -d -p $port:8282 --name $name vmware/admiral:dev
|
Loading…
Reference in New Issue
Block a user