Merge pull request #2495 from ywk253100/170605_pm

Implement project manager based on PMS
This commit is contained in:
Wenkai Yin 2017-06-13 15:46:48 +08:00 committed by GitHub
commit f0c47b990b
17 changed files with 875 additions and 29 deletions

View File

@ -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

View File

@ -28,9 +28,6 @@ const (
RoleDeveloper = 2
RoleGuest = 3
DeployModeStandAlone = "standalone"
DeployModeIntegration = "integration"
ExtEndpoint = "ext_endpoint"
AUTHMode = "auth_mode"
DatabaseType = "database_type"

View File

@ -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

View File

@ -27,7 +27,7 @@ import (
//"github.com/vmware/harbor/src/common/config"
"github.com/vmware/harbor/src/common/utils/log"
"github.com/vmware/harbor/src/common/utils/registry"
registry_error "github.com/vmware/harbor/src/common/utils/registry/error"
registry_error "github.com/vmware/harbor/src/common/utils/error"
token_util "github.com/vmware/harbor/src/ui/service/token"
)

View File

@ -24,7 +24,7 @@ import (
// "time"
"github.com/vmware/harbor/src/common/utils"
registry_error "github.com/vmware/harbor/src/common/utils/registry/error"
registry_error "github.com/vmware/harbor/src/common/utils/error"
)
// Registry holds information of a registry entity

View File

@ -30,7 +30,7 @@ import (
"github.com/docker/distribution/manifest/schema2"
"github.com/vmware/harbor/src/common/utils"
registry_error "github.com/vmware/harbor/src/common/utils/registry/error"
registry_error "github.com/vmware/harbor/src/common/utils/error"
)
// Repository holds information of a repository entity

View File

@ -25,7 +25,7 @@ import (
"testing"
"github.com/docker/distribution/manifest/schema2"
registry_error "github.com/vmware/harbor/src/common/utils/registry/error"
registry_error "github.com/vmware/harbor/src/common/utils/error"
"github.com/vmware/harbor/src/common/utils/test"
)

View File

@ -30,7 +30,7 @@ import (
"github.com/vmware/harbor/src/common/utils/log"
"github.com/vmware/harbor/src/common/utils/notary"
"github.com/vmware/harbor/src/common/utils/registry"
registry_error "github.com/vmware/harbor/src/common/utils/registry/error"
registry_error "github.com/vmware/harbor/src/common/utils/error"
"github.com/vmware/harbor/src/ui/config"
)

View File

@ -27,7 +27,7 @@ import (
"github.com/vmware/harbor/src/common/utils/log"
"github.com/vmware/harbor/src/common/utils/registry"
"github.com/vmware/harbor/src/common/utils/registry/auth"
registry_error "github.com/vmware/harbor/src/common/utils/registry/error"
registry_error "github.com/vmware/harbor/src/common/utils/error"
"github.com/vmware/harbor/src/ui/config"
)

View File

@ -29,7 +29,7 @@ import (
"github.com/vmware/harbor/src/common/utils/log"
"github.com/vmware/harbor/src/common/utils/registry"
"github.com/vmware/harbor/src/common/utils/registry/auth"
registry_error "github.com/vmware/harbor/src/common/utils/registry/error"
registry_error "github.com/vmware/harbor/src/common/utils/error"
"github.com/vmware/harbor/src/ui/config"
"github.com/vmware/harbor/src/ui/projectmanager"
)

View File

@ -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
}

View File

@ -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

View File

@ -0,0 +1,422 @@
// 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"
er "github.com/vmware/harbor/src/common/utils/error"
"github.com/vmware/harbor/src/common/utils/log"
)
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) {
m := map[string]string{}
if id, ok := projectIDOrName.(int64); ok {
m["customProperties.__harborId"] = strconv.FormatInt(id, 10)
} else if name, ok := projectIDOrName.(string); ok {
m["name"] = name
} else {
return nil, fmt.Errorf("unsupported type: %v", projectIDOrName)
}
projects, err := p.filter(m)
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
}
func (p *ProjectManager) filter(m map[string]string) ([]*project, error) {
query := ""
for k, v := range m {
if len(query) == 0 {
query += "?"
} else {
query += "&"
}
query += fmt.Sprintf("$filter=%s eq '%s'", k, v)
}
path := "/projects" + query
data, err := p.send(http.MethodGet, path, nil)
if err != nil {
return nil, err
}
return parse(data)
}
// 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 ...
// TODO empty this method after implementing security context with auth context
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) {
m := map[string]string{
"isPublic": "true",
}
projects, err := p.filter(m)
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 returns all projects that user has read perm to
// TODO maybe can be removed as search isn't implemented in integration mode
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)
url := req.URL.String()
req.URL.RawQuery = req.URL.Query().Encode()
resp, err := p.client.Do(req)
if err != nil {
log.Debugf("\"%s %s\" failed", req.Method, url)
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
}

View 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
View 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