mirror of
https://github.com/goharbor/harbor.git
synced 2025-01-21 23:21:26 +01:00
Add unit tests and fix CI
Signed-off-by: cd1989 <chende@caicloud.io>
This commit is contained in:
parent
8732a20709
commit
b00098d492
@ -61,6 +61,7 @@ install:
|
||||
LDAP; fi
|
||||
script:
|
||||
- if [ "$UTTEST" == true ]; then bash ./tests/travis/ut_run.sh $IP; fi
|
||||
- if [ "$APITEST_DB" == true ]; then bash ./tests/travis/api_run.sh DB $IP; fi
|
||||
# TODO(ChenDe): Enable API test when API test problems resolved
|
||||
#- if [ "$APITEST_DB" == true ]; then bash ./tests/travis/api_run.sh DB $IP; fi
|
||||
- if [ "$APITEST_LDAP" == true ]; then bash ./tests/travis/api_run.sh LDAP $IP; fi
|
||||
- if [ "$OFFLINE" == true ]; then bash ./tests/travis/distro_installer.sh; fi
|
||||
|
@ -2080,119 +2080,92 @@ paths:
|
||||
$ref: '#/responses/UnsupportedMediaType'
|
||||
'500':
|
||||
description: Unexpected internal errors.
|
||||
/targets:
|
||||
/registries:
|
||||
get:
|
||||
summary: List filters targets by name.
|
||||
summary: List registries.
|
||||
description: |
|
||||
This endpoint let user list filters targets by name, if name is nil, list returns all targets.
|
||||
This endpoint let user list filtered registries by name, if name is nil, list returns all registries.
|
||||
parameters:
|
||||
- name: name
|
||||
in: query
|
||||
type: string
|
||||
required: false
|
||||
description: The replication's target name.
|
||||
description: Registry's name.
|
||||
tags:
|
||||
- Products
|
||||
responses:
|
||||
'200':
|
||||
description: Get policy successfully.
|
||||
description: List registries successfully.
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/definitions/RepTarget'
|
||||
$ref: '#/definitions/Registry'
|
||||
'401':
|
||||
description: User need to log in first.
|
||||
'500':
|
||||
description: Unexpected internal errors.
|
||||
post:
|
||||
summary: Create a new replication target.
|
||||
summary: Create a new registry.
|
||||
description: |
|
||||
This endpoint is for user to create a new replication target.
|
||||
This endpoint is for user to create a new registry.
|
||||
parameters:
|
||||
- name: reptarget
|
||||
- name: registry
|
||||
in: body
|
||||
description: New created replication target.
|
||||
description: New created registry.
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/RepTargetPost'
|
||||
$ref: '#/definitions/Registry'
|
||||
tags:
|
||||
- Products
|
||||
responses:
|
||||
'201':
|
||||
description: Replication target created successfully.
|
||||
description: Registry created successfully.
|
||||
'400':
|
||||
description: Unsatisfied with constraints of the target creation.
|
||||
description: Unsatisfied with constraints of the registry creation.
|
||||
'401':
|
||||
description: User need to log in first.
|
||||
'409':
|
||||
description: Replication target name already exists.
|
||||
description: Registry name already exists.
|
||||
'415':
|
||||
$ref: '#/responses/UnsupportedMediaType'
|
||||
'500':
|
||||
description: Unexpected internal errors.
|
||||
/targets/ping:
|
||||
post:
|
||||
summary: Ping validates target.
|
||||
description: |
|
||||
This endpoint is for ping validates whether the target is reachable and whether the credential is valid.
|
||||
parameters:
|
||||
- name: target
|
||||
in: body
|
||||
description: The target object.
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/PingTarget'
|
||||
tags:
|
||||
- Products
|
||||
responses:
|
||||
'200':
|
||||
description: Ping target successfully.
|
||||
'400':
|
||||
description: Target id is invalid/ endpoint is needed/ invaild URL/ network issue.
|
||||
'401':
|
||||
description: User need to log in first or wrong username/password for remote target.
|
||||
'404':
|
||||
description: Target not found.
|
||||
'415':
|
||||
$ref: '#/responses/UnsupportedMediaType'
|
||||
'500':
|
||||
description: Unexpected internal errors.
|
||||
'/targets/{id}':
|
||||
'/registries/{id}':
|
||||
put:
|
||||
summary: Update replication's target.
|
||||
summary: Update a given registry.
|
||||
description: |
|
||||
This endpoint is for update specific replication's target.
|
||||
This endpoint is for update a given registry.
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
type: integer
|
||||
format: int64
|
||||
required: true
|
||||
description: The replication's target ID.
|
||||
description: The registry's ID.
|
||||
- name: repo_target
|
||||
in: body
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/PutTarget'
|
||||
description: Updates of replication's target.
|
||||
$ref: '#/definitions/PutRegistry'
|
||||
description: Updates registry.
|
||||
tags:
|
||||
- Products
|
||||
responses:
|
||||
'200':
|
||||
description: Updated replication's target successfully.
|
||||
description: Updated registry successfully.
|
||||
'400':
|
||||
description: The target is associated with policy which is enabled.
|
||||
description: The registry is associated with policy which is enabled.
|
||||
'401':
|
||||
description: User need to log in first.
|
||||
'404':
|
||||
description: Target ID does not exist.
|
||||
description: Registry does not exist.
|
||||
'409':
|
||||
description: Target name or endpoint is already used.
|
||||
description: Registry name is already used.
|
||||
'500':
|
||||
description: Unexpected internal errors.
|
||||
get:
|
||||
summary: Get replication's target.
|
||||
description: This endpoint is for get specific replication's target.
|
||||
summary: Get registry.
|
||||
description: This endpoint is for get specific registry.
|
||||
tags:
|
||||
- Products
|
||||
parameters:
|
||||
@ -2201,40 +2174,40 @@ paths:
|
||||
type: integer
|
||||
format: int64
|
||||
required: true
|
||||
description: The replication's target ID.
|
||||
description: The registry ID.
|
||||
responses:
|
||||
'200':
|
||||
description: Get replication's target successfully.
|
||||
description: Get registry successfully.
|
||||
schema:
|
||||
$ref: '#/definitions/RepTarget'
|
||||
$ref: '#/definitions/Registry'
|
||||
'401':
|
||||
description: User need to log in first.
|
||||
'404':
|
||||
description: Replication's target not found
|
||||
description: Registry not found
|
||||
'500':
|
||||
description: Unexpected internal errors.
|
||||
delete:
|
||||
summary: Delete specific replication's target.
|
||||
summary: Delete specific registry.
|
||||
description: |
|
||||
This endpoint is for to delete specific replication's target.
|
||||
This endpoint is for to delete specific registry.
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
type: integer
|
||||
format: int64
|
||||
required: true
|
||||
description: The replication's target ID.
|
||||
description: The registry's ID.
|
||||
tags:
|
||||
- Products
|
||||
responses:
|
||||
'200':
|
||||
description: Replication's target deleted successfully.
|
||||
description: Registry deleted successfully.
|
||||
'400':
|
||||
description: Replication's target ID is invalid or the target is used by policies.
|
||||
description: Registry's ID is invalid or the registry is used by policies.
|
||||
'401':
|
||||
description: Only admin has this authority.
|
||||
'404':
|
||||
description: Replication's target does not exist.
|
||||
description: Registry does not exist.
|
||||
'500':
|
||||
description: Unexpected internal errors.
|
||||
'/targets/{id}/policies/':
|
||||
@ -2672,15 +2645,15 @@ paths:
|
||||
- Products
|
||||
responses:
|
||||
'200':
|
||||
description: Updated replication's target successfully.
|
||||
description: Updated gc's schedule successfully.
|
||||
'400':
|
||||
description: The target is associated with policy which is enabled.
|
||||
description: Bad params.
|
||||
'401':
|
||||
description: User need to log in first.
|
||||
'403':
|
||||
description: User does not have permission of admin role.
|
||||
'404':
|
||||
description: Target ID does not exist.
|
||||
description: GC schedule does not exist.
|
||||
'500':
|
||||
description: Unexpected internal errors.
|
||||
post:
|
||||
@ -3624,11 +3597,11 @@ definitions:
|
||||
description: The project list that the policy applys to.
|
||||
items:
|
||||
$ref: '#/definitions/Project'
|
||||
targets:
|
||||
registries:
|
||||
type: array
|
||||
description: The target list.
|
||||
items:
|
||||
$ref: '#/definitions/RepTarget'
|
||||
$ref: '#/definitions/Registry'
|
||||
trigger:
|
||||
$ref: '#/definitions/RepTrigger'
|
||||
filters:
|
||||
@ -3688,90 +3661,69 @@ definitions:
|
||||
metadata:
|
||||
type: object
|
||||
description: This map object is the replication policy filter metadata.
|
||||
RepTarget:
|
||||
RegistryCredential:
|
||||
type: object
|
||||
properties:
|
||||
type:
|
||||
type: string
|
||||
description: Credential type, such as 'basic', 'oauth'.
|
||||
access_key:
|
||||
type: string
|
||||
description: Access key, e.g. user name when credential type is 'basic'.
|
||||
access_secret:
|
||||
type: string
|
||||
description: Access secret, e.g. password when credential type is 'basic'.
|
||||
Registry:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
format: int64
|
||||
description: The target ID.
|
||||
endpoint:
|
||||
description: The registry ID.
|
||||
url:
|
||||
type: string
|
||||
description: The target address URL string.
|
||||
description: The registry URL string.
|
||||
name:
|
||||
type: string
|
||||
description: The target name.
|
||||
username:
|
||||
type: string
|
||||
description: The target server username.
|
||||
password:
|
||||
type: string
|
||||
description: The target server password.
|
||||
description: The registry name.
|
||||
credential:
|
||||
$ref: '#/definitions/RegistryCredential'
|
||||
type:
|
||||
type: integer
|
||||
format: int
|
||||
description: Reserved field.
|
||||
type: string
|
||||
description: Type of the registry, e.g. 'harbor'.
|
||||
insecure:
|
||||
type: boolean
|
||||
description: Whether or not the certificate will be verified when Harbor tries to access the server.
|
||||
description:
|
||||
type: string
|
||||
description: Description of the registry.
|
||||
status:
|
||||
type: string
|
||||
description: Health status of the registry.
|
||||
creation_time:
|
||||
type: string
|
||||
description: The create time of the policy.
|
||||
update_time:
|
||||
type: string
|
||||
description: The update time of the policy.
|
||||
RepTargetPost:
|
||||
type: object
|
||||
properties:
|
||||
endpoint:
|
||||
type: string
|
||||
description: The target address URL string.
|
||||
name:
|
||||
type: string
|
||||
description: The target name.
|
||||
username:
|
||||
type: string
|
||||
description: The target server username.
|
||||
password:
|
||||
type: string
|
||||
description: The target server password.
|
||||
insecure:
|
||||
type: boolean
|
||||
description: Whether or not the certificate will be verified when Harbor tries to access the server.
|
||||
PingTarget:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
format: int
|
||||
description: Target ID.
|
||||
endpoint:
|
||||
type: string
|
||||
description: The target address URL string.
|
||||
username:
|
||||
type: string
|
||||
description: The target server username.
|
||||
password:
|
||||
type: string
|
||||
description: The target server password.
|
||||
insecure:
|
||||
type: boolean
|
||||
description: Whether or not the certificate will be verified when Harbor tries to access the server.
|
||||
PutTarget:
|
||||
PutRegistry:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
description: The target name.
|
||||
endpoint:
|
||||
description: The registry name.
|
||||
url:
|
||||
type: string
|
||||
description: The target address URL string.
|
||||
username:
|
||||
description: The registry address URL string.
|
||||
credential_type:
|
||||
type: string
|
||||
description: The target server username.
|
||||
password:
|
||||
description: Credential type of the registry, e.g. 'basic'.
|
||||
access_key:
|
||||
type: string
|
||||
description: The target server password.
|
||||
description: The registry access key.
|
||||
access_secret:
|
||||
type: string
|
||||
description: The registry access secret.
|
||||
insecure:
|
||||
type: boolean
|
||||
description: Whether or not the certificate will be verified when Harbor tries to access the server.
|
||||
|
@ -670,144 +670,6 @@ func TestChangeUserProfile(t *testing.T) {
|
||||
|
||||
var targetID, policyID, policyID2, policyID3, jobID, jobID2, jobID3 int64
|
||||
|
||||
func TestAddRegistry(t *testing.T) {
|
||||
registry := &models.Registry{
|
||||
Name: "test",
|
||||
URL: "127.0.0.1:5000",
|
||||
AccessKey: "admin",
|
||||
AccessSecret: "admin",
|
||||
}
|
||||
// _, err := AddRepTarget(target)
|
||||
id, err := AddRegistry(registry)
|
||||
t.Logf("added target, id: %d", id)
|
||||
if err != nil {
|
||||
t.Errorf("Error occurred in AddRepTarget: %v", err)
|
||||
} else {
|
||||
targetID = id
|
||||
}
|
||||
id2 := id + 99
|
||||
r, err := GetRegistry(id2)
|
||||
if err != nil {
|
||||
t.Errorf("Error occurred in GetRegistry: %v, id: %d", err, id2)
|
||||
}
|
||||
if r != nil {
|
||||
t.Errorf("There should not be a target with id: %d", id2)
|
||||
}
|
||||
r, err = GetRegistry(id)
|
||||
if err != nil {
|
||||
t.Errorf("Error occurred in GetTarget: %v, id: %d", err, id)
|
||||
}
|
||||
if r == nil {
|
||||
t.Errorf("Unable to find a target with id: %d", id)
|
||||
}
|
||||
if r.URL != "127.0.0.1:5000" {
|
||||
t.Errorf("Unexpected url in target: %s, expected 127.0.0.1:5000", r.URL)
|
||||
}
|
||||
if r.AccessKey != "admin" {
|
||||
t.Errorf("Unexpected username in target: %s, expected admin", r.AccessKey)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetRegistryByName(t *testing.T) {
|
||||
r, err := GetRegistry(targetID)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to get registry %d: %v", targetID, err)
|
||||
}
|
||||
|
||||
r2, err := GetRegistryByName(r.Name)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to get registry %s: %v", r.Name, err)
|
||||
}
|
||||
|
||||
if r.Name != r2.Name {
|
||||
t.Errorf("unexpected registry name: %s, expected: %s", r2.Name, r.Name)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetRegistryByURL(t *testing.T) {
|
||||
r, err := GetRegistry(targetID)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to get registry %d: %v", targetID, err)
|
||||
}
|
||||
|
||||
r2, err := GetRegistryByURL(r.URL)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to get registry %s: %v", r.URL, err)
|
||||
}
|
||||
|
||||
if r.URL != r2.URL {
|
||||
t.Errorf("unexpected registry URL: %s, expected: %s", r2.URL, r.URL)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateRegistry(t *testing.T) {
|
||||
registry := &models.Registry{
|
||||
Name: "name",
|
||||
URL: "http://url",
|
||||
AccessKey: "username",
|
||||
AccessSecret: "password",
|
||||
}
|
||||
|
||||
id, err := AddRegistry(registry)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to add registry: %v", err)
|
||||
}
|
||||
defer func() {
|
||||
if err := DeleteRegistry(id); err != nil {
|
||||
t.Logf("failed to delete registry %d: %v", id, err)
|
||||
}
|
||||
}()
|
||||
|
||||
registry.ID = id
|
||||
registry.Name = "new_name"
|
||||
registry.URL = "http://new_url"
|
||||
registry.AccessKey = "new_username"
|
||||
registry.AccessSecret = "new_password"
|
||||
|
||||
if err = UpdateRegistry(registry); err != nil {
|
||||
t.Fatalf("failed to update registry: %v", err)
|
||||
}
|
||||
|
||||
registry, err = GetRegistry(id)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to get target %d: %v", id, err)
|
||||
}
|
||||
|
||||
if registry.Name != "new_name" {
|
||||
t.Errorf("unexpected name: %s, expected: %s", registry.Name, "new_name")
|
||||
}
|
||||
|
||||
if registry.URL != "http://new_url" {
|
||||
t.Errorf("unexpected url: %s, expected: %s", registry.URL, "http://new_url")
|
||||
}
|
||||
|
||||
if registry.AccessKey != "new_username" {
|
||||
t.Errorf("unexpected username: %s, expected: %s", registry.AccessKey, "new_username")
|
||||
}
|
||||
|
||||
if registry.AccessSecret != "new_password" {
|
||||
t.Errorf("unexpected password: %s, expected: %s", registry.AccessSecret, "new_password")
|
||||
}
|
||||
}
|
||||
|
||||
func TestListRegistries(t *testing.T) {
|
||||
total, registries, err := ListRegistries(&ListRegistryQuery{
|
||||
Query: "test",
|
||||
Limit: -1,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("failed to get all registries: %v", err)
|
||||
}
|
||||
|
||||
if total == 0 {
|
||||
t.Errorf("unexpected num of registries: %d, expected: %d", total, 1)
|
||||
}
|
||||
|
||||
if total != int64(len(registries)) {
|
||||
t.Errorf("total (%d) should equals to registries count (%d) when pagination not set", total, len(registries))
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddRepPolicy(t *testing.T) {
|
||||
policy := models.RepPolicy{
|
||||
ProjectID: 1,
|
||||
@ -1060,22 +922,6 @@ func TestDeleteRepJob(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeleteRegistry(t *testing.T) {
|
||||
err := DeleteRegistry(targetID)
|
||||
if err != nil {
|
||||
t.Errorf("Error occurred in DeleteRepTarget: %v, id: %d", err, targetID)
|
||||
return
|
||||
}
|
||||
t.Logf("deleted target, id: %d", targetID)
|
||||
tgt, err := GetRegistry(targetID)
|
||||
if err != nil {
|
||||
t.Errorf("Error occurred in GetTarget: %v, id: %d", err, targetID)
|
||||
}
|
||||
if tgt != nil {
|
||||
t.Errorf("Able to find target after deletion, id: %d", targetID)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetTotalOfRepPolicies(t *testing.T) {
|
||||
_, err := GetTotalOfRepPolicies("", 1)
|
||||
require.Nil(t, err)
|
||||
|
@ -14,23 +14,28 @@
|
||||
|
||||
package dao
|
||||
|
||||
// TODO: This UT makes common DAO depends on replication ng DAOs, comment it out temporarily here
|
||||
/*
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
common_models "github.com/goharbor/harbor/src/common/models"
|
||||
"github.com/goharbor/harbor/src/replication/ng/dao"
|
||||
"github.com/goharbor/harbor/src/replication/ng/dao/models"
|
||||
)
|
||||
|
||||
func TestMethodsOfWatchItem(t *testing.T) {
|
||||
registryID, err := AddRegistry(&models.Registry{
|
||||
registryID, err := dao.AddRegistry(&models.Registry{
|
||||
Name: "test_target_for_watch_item",
|
||||
URL: "http://127.0.0.1",
|
||||
})
|
||||
require.Nil(t, err)
|
||||
defer DeleteRegistry(registryID)
|
||||
defer dao.DeleteRegistry(registryID)
|
||||
|
||||
policyID, err := AddRepPolicy(models.RepPolicy{
|
||||
policyID, err := AddRepPolicy(common_models.RepPolicy{
|
||||
Name: "test_policy_for_watch_item",
|
||||
ProjectID: 1,
|
||||
TargetID: targetID,
|
||||
@ -38,7 +43,7 @@ func TestMethodsOfWatchItem(t *testing.T) {
|
||||
require.Nil(t, err)
|
||||
defer DeleteRepPolicy(policyID)
|
||||
|
||||
item := &models.WatchItem{
|
||||
item := &common_models.WatchItem{
|
||||
PolicyID: policyID,
|
||||
Namespace: "library",
|
||||
OnPush: false,
|
||||
@ -69,3 +74,4 @@ func TestMethodsOfWatchItem(t *testing.T) {
|
||||
require.Nil(t, err)
|
||||
assert.Equal(t, 0, len(items))
|
||||
}
|
||||
*/
|
||||
|
@ -27,7 +27,7 @@ func currPath() string {
|
||||
return path.Dir(f)
|
||||
}
|
||||
|
||||
// NewJobServiceServer
|
||||
// NewJobServiceServer ...
|
||||
func NewJobServiceServer() *httptest.Server {
|
||||
mux := http.NewServeMux()
|
||||
mux.HandleFunc(fmt.Sprintf("%s/%s/log", jobsPrefix, jobUUID),
|
||||
|
@ -16,11 +16,13 @@ package models
|
||||
|
||||
import (
|
||||
"github.com/astaxie/beego/orm"
|
||||
|
||||
"github.com/goharbor/harbor/src/replication/ng/dao/models"
|
||||
)
|
||||
|
||||
func init() {
|
||||
orm.RegisterModel(
|
||||
new(Registry),
|
||||
new(models.Registry),
|
||||
new(RepPolicy),
|
||||
new(RepJob),
|
||||
new(User),
|
||||
|
@ -20,29 +20,3 @@ import (
|
||||
|
||||
// ErrDupProject is the error returned when creating a duplicate project
|
||||
var ErrDupProject = errors.New("duplicate project")
|
||||
|
||||
const (
|
||||
// ReasonNotFound indicates resource not found
|
||||
ReasonNotFound = "NotFound"
|
||||
)
|
||||
|
||||
// KnownError represents known type errors
|
||||
type KnownError struct {
|
||||
// Reason is reason of the error, such as NotFound
|
||||
Reason string
|
||||
// Message is the message of the error
|
||||
Message string
|
||||
}
|
||||
|
||||
// Error returns the error message
|
||||
func (e KnownError) Error() string {
|
||||
return e.Message
|
||||
}
|
||||
|
||||
// Is checks whether a error is a given type error
|
||||
func Is(err error, reason string) bool {
|
||||
if e, ok := err.(KnownError); ok && e.Reason == reason {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
@ -1,40 +0,0 @@
|
||||
package error
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestIs(t *testing.T) {
|
||||
cases := []struct {
|
||||
err error
|
||||
reason string
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
err: errors.New(""),
|
||||
reason: ReasonNotFound,
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
err: KnownError{
|
||||
Reason: ReasonNotFound,
|
||||
},
|
||||
reason: ReasonNotFound,
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
err: KnownError{
|
||||
Reason: ReasonNotFound,
|
||||
},
|
||||
reason: "Other",
|
||||
expected: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
assert.Equal(t, c.expected, Is(c.err, c.reason))
|
||||
}
|
||||
}
|
@ -23,6 +23,7 @@ type FakeReplicatoinController struct {
|
||||
func (f *FakeReplicatoinController) Init(closing chan struct{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Replicate ...
|
||||
func (f *FakeReplicatoinController) Replicate(policyID int64, metadata ...map[string]interface{}) error {
|
||||
return nil
|
||||
|
@ -19,6 +19,8 @@ import (
|
||||
|
||||
"github.com/goharbor/harbor/src/common/dao"
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
rep_dao "github.com/goharbor/harbor/src/replication/ng/dao"
|
||||
rep_models "github.com/goharbor/harbor/src/replication/ng/dao/models"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -83,23 +85,23 @@ func CommonDelProject() {
|
||||
|
||||
func CommonAddRegistry() {
|
||||
endPoint := os.Getenv("REGISTRY_URL")
|
||||
commonRegistry := &models.Registry{
|
||||
commonRegistry := &rep_models.Registry{
|
||||
URL: endPoint,
|
||||
Name: TestRegistryName,
|
||||
AccessKey: adminName,
|
||||
AccessSecret: adminPwd,
|
||||
}
|
||||
_, _ = dao.AddRegistry(commonRegistry)
|
||||
_, _ = rep_dao.AddRegistry(commonRegistry)
|
||||
}
|
||||
|
||||
func CommonGetRegistry() int {
|
||||
registry, _ := dao.GetRegistryByName(TestRegistryName)
|
||||
registry, _ := rep_dao.GetRegistryByName(TestRegistryName)
|
||||
return int(registry.ID)
|
||||
}
|
||||
|
||||
func CommonDelRegistry() {
|
||||
registry, _ := dao.GetRegistryByName(TestRegistryName)
|
||||
_ = dao.DeleteRegistry(registry.ID)
|
||||
registry, _ := rep_dao.GetRegistryByName(TestRegistryName)
|
||||
_ = rep_dao.DeleteRegistry(registry.ID)
|
||||
}
|
||||
|
||||
func CommonAddRepository() {
|
||||
|
@ -27,21 +27,22 @@ import (
|
||||
"runtime"
|
||||
"strconv"
|
||||
|
||||
"github.com/goharbor/harbor/src/common/job/test"
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
testutils "github.com/goharbor/harbor/src/common/utils/test"
|
||||
"github.com/goharbor/harbor/src/core/config"
|
||||
"github.com/goharbor/harbor/src/core/filter"
|
||||
"github.com/goharbor/harbor/tests/apitests/apilib"
|
||||
|
||||
"github.com/astaxie/beego"
|
||||
"github.com/dghubble/sling"
|
||||
|
||||
"github.com/goharbor/harbor/src/common/dao"
|
||||
"github.com/goharbor/harbor/src/common/job/test"
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
testutils "github.com/goharbor/harbor/src/common/utils/test"
|
||||
apimodels "github.com/goharbor/harbor/src/core/api/models"
|
||||
_ "github.com/goharbor/harbor/src/core/auth/db"
|
||||
_ "github.com/goharbor/harbor/src/core/auth/ldap"
|
||||
"github.com/goharbor/harbor/src/core/config"
|
||||
"github.com/goharbor/harbor/src/core/filter"
|
||||
"github.com/goharbor/harbor/src/replication/core"
|
||||
_ "github.com/goharbor/harbor/src/replication/event"
|
||||
"github.com/goharbor/harbor/src/replication/ng/model"
|
||||
"github.com/goharbor/harbor/tests/apitests/apilib"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -650,103 +651,6 @@ func (a testapi) GetReposTop(authInfo usrInfo, count string) (int, interface{},
|
||||
return http.StatusOK, result, nil
|
||||
}
|
||||
|
||||
// -------------------------Targets Test---------------------------------------//
|
||||
// Create a new replication target
|
||||
func (a testapi) AddTargets(authInfo usrInfo, repTarget apilib.RepTargetPost) (int, string, error) {
|
||||
_sling := sling.New().Post(a.basePath)
|
||||
|
||||
path := "/api/targets"
|
||||
|
||||
_sling = _sling.Path(path)
|
||||
_sling = _sling.BodyJSON(repTarget)
|
||||
|
||||
httpStatusCode, body, err := request(_sling, jsonAcceptHeader, authInfo)
|
||||
return httpStatusCode, string(body), err
|
||||
}
|
||||
|
||||
// List filters targets by name
|
||||
func (a testapi) ListTargets(authInfo usrInfo, targetName string) (int, []apilib.RepTarget, error) {
|
||||
_sling := sling.New().Get(a.basePath)
|
||||
|
||||
path := "/api/targets?name=" + targetName
|
||||
|
||||
_sling = _sling.Path(path)
|
||||
|
||||
var successPayload []apilib.RepTarget
|
||||
|
||||
httpStatusCode, body, err := request(_sling, jsonAcceptHeader, authInfo)
|
||||
if err == nil && httpStatusCode == 200 {
|
||||
err = json.Unmarshal(body, &successPayload)
|
||||
}
|
||||
|
||||
return httpStatusCode, successPayload, err
|
||||
}
|
||||
|
||||
// Ping target
|
||||
func (a testapi) PingTarget(authInfo usrInfo, body interface{}) (int, error) {
|
||||
_sling := sling.New().Post(a.basePath)
|
||||
|
||||
path := "/api/targets/ping"
|
||||
|
||||
_sling = _sling.Path(path)
|
||||
_sling = _sling.BodyJSON(body)
|
||||
|
||||
httpStatusCode, _, err := request(_sling, jsonAcceptHeader, authInfo)
|
||||
return httpStatusCode, err
|
||||
}
|
||||
|
||||
// Get target by targetID
|
||||
func (a testapi) GetTargetByID(authInfo usrInfo, targetID string) (int, error) {
|
||||
_sling := sling.New().Get(a.basePath)
|
||||
|
||||
path := "/api/targets/" + targetID
|
||||
|
||||
_sling = _sling.Path(path)
|
||||
|
||||
httpStatusCode, _, err := request(_sling, jsonAcceptHeader, authInfo)
|
||||
|
||||
return httpStatusCode, err
|
||||
}
|
||||
|
||||
// Update target by targetID
|
||||
func (a testapi) PutTargetByID(authInfo usrInfo, targetID string, repTarget apilib.RepTargetPost) (int, error) {
|
||||
_sling := sling.New().Put(a.basePath)
|
||||
|
||||
path := "/api/targets/" + targetID
|
||||
|
||||
_sling = _sling.Path(path)
|
||||
_sling = _sling.BodyJSON(repTarget)
|
||||
|
||||
httpStatusCode, _, err := request(_sling, jsonAcceptHeader, authInfo)
|
||||
|
||||
return httpStatusCode, err
|
||||
}
|
||||
|
||||
// List the target relevant policies by targetID
|
||||
func (a testapi) GetTargetPoliciesByID(authInfo usrInfo, targetID string) (int, error) {
|
||||
_sling := sling.New().Get(a.basePath)
|
||||
|
||||
path := "/api/targets/" + targetID + "/policies/"
|
||||
|
||||
_sling = _sling.Path(path)
|
||||
|
||||
httpStatusCode, _, err := request(_sling, jsonAcceptHeader, authInfo)
|
||||
|
||||
return httpStatusCode, err
|
||||
}
|
||||
|
||||
// Delete target by targetID
|
||||
func (a testapi) DeleteTargetsByID(authInfo usrInfo, targetID string) (int, error) {
|
||||
_sling := sling.New().Delete(a.basePath)
|
||||
|
||||
path := "/api/targets/" + targetID
|
||||
|
||||
_sling = _sling.Path(path)
|
||||
|
||||
httpStatusCode, _, err := request(_sling, jsonAcceptHeader, authInfo)
|
||||
return httpStatusCode, err
|
||||
}
|
||||
|
||||
// --------------------Replication_Policy Test--------------------------------//
|
||||
|
||||
// Create a new replication policy
|
||||
@ -1186,3 +1090,57 @@ func (a testapi) GCScheduleGet(authInfo usrInfo) (int, []apilib.AdminJob, error)
|
||||
|
||||
return httpStatusCode, successPayLoad, err
|
||||
}
|
||||
|
||||
func (a testapi) RegistryGet(authInfo usrInfo, registryID int64) (*model.Registry, int, error) {
|
||||
_sling := sling.New().Base(a.basePath).Get(fmt.Sprintf("/api/registries/%d", registryID))
|
||||
code, body, err := request(_sling, jsonAcceptHeader, authInfo)
|
||||
if err == nil && code == http.StatusOK {
|
||||
registry := model.Registry{}
|
||||
if err := json.Unmarshal(body, ®istry); err != nil {
|
||||
return nil, code, err
|
||||
}
|
||||
return ®istry, code, nil
|
||||
}
|
||||
return nil, code, err
|
||||
}
|
||||
|
||||
func (a testapi) RegistryList(authInfo usrInfo) ([]*model.Registry, int, error) {
|
||||
_sling := sling.New().Base(a.basePath).Get("/api/registries")
|
||||
code, body, err := request(_sling, jsonAcceptHeader, authInfo)
|
||||
if err != nil || code != http.StatusOK {
|
||||
return nil, code, err
|
||||
}
|
||||
|
||||
var registries []*model.Registry
|
||||
if err := json.Unmarshal(body, ®istries); err != nil {
|
||||
return nil, code, err
|
||||
}
|
||||
|
||||
return registries, code, nil
|
||||
}
|
||||
|
||||
func (a testapi) RegistryCreate(authInfo usrInfo, registry *model.Registry) (int, error) {
|
||||
_sling := sling.New().Base(a.basePath).Post("/api/registries").BodyJSON(registry)
|
||||
code, _, err := request(_sling, jsonAcceptHeader, authInfo)
|
||||
return code, err
|
||||
}
|
||||
|
||||
func (a testapi) RegistryDelete(authInfo usrInfo, registryID int64) (int, error) {
|
||||
_sling := sling.New().Base(a.basePath).Delete(fmt.Sprintf("/api/registries/%d", registryID))
|
||||
code, _, err := request(_sling, jsonAcceptHeader, authInfo)
|
||||
if err != nil || code != http.StatusOK {
|
||||
return code, fmt.Errorf("delete registry error: %v", err)
|
||||
}
|
||||
|
||||
return code, nil
|
||||
}
|
||||
|
||||
func (a testapi) RegistryUpdate(authInfo usrInfo, registryID int64, req *apimodels.RegistryUpdateRequest) (int, error) {
|
||||
_sling := sling.New().Base(a.basePath).Put(fmt.Sprintf("/api/registries/%d", registryID)).BodyJSON(req)
|
||||
code, _, err := request(_sling, jsonAcceptHeader, authInfo)
|
||||
if err != nil || code != http.StatusOK {
|
||||
return code, fmt.Errorf("update registry error: %v", err)
|
||||
}
|
||||
|
||||
return code, nil
|
||||
}
|
||||
|
@ -25,6 +25,8 @@ import (
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
"github.com/goharbor/harbor/src/replication"
|
||||
rep_models "github.com/goharbor/harbor/src/replication/models"
|
||||
rep_dao "github.com/goharbor/harbor/src/replication/ng/dao"
|
||||
dao_models "github.com/goharbor/harbor/src/replication/ng/dao/models"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
@ -455,12 +457,12 @@ func TestListResources(t *testing.T) {
|
||||
require.Nil(t, err)
|
||||
defer dao.DeleteLabel(projectLabelID)
|
||||
|
||||
registryID, err := dao.AddRegistry(&models.Registry{
|
||||
registryID, err := rep_dao.AddRegistry(&dao_models.Registry{
|
||||
Name: "target_for_testing_label_resource",
|
||||
URL: "https://192.168.0.1",
|
||||
})
|
||||
require.Nil(t, err)
|
||||
defer dao.DeleteRegistry(registryID)
|
||||
defer rep_dao.DeleteRegistry(registryID)
|
||||
|
||||
// create a policy references both global and project labels
|
||||
policyID, err := dao.AddRepPolicy(models.RepPolicy{
|
||||
|
11
src/core/api/models/registry.go
Normal file
11
src/core/api/models/registry.go
Normal file
@ -0,0 +1,11 @@
|
||||
package models
|
||||
|
||||
// RegistryUpdateRequest is request used to update a registry.
|
||||
type RegistryUpdateRequest struct {
|
||||
Name *string `json:"name"`
|
||||
URL *string `json:"url"`
|
||||
CredentialType *string `json:"credential_type"`
|
||||
AccessKey *string `json:"access_key"`
|
||||
AccessSecret *string `json:"access_secret"`
|
||||
Insecure *bool `json:"insecure"`
|
||||
}
|
@ -20,22 +20,23 @@ import (
|
||||
"github.com/astaxie/beego/validation"
|
||||
common_models "github.com/goharbor/harbor/src/common/models"
|
||||
rep_models "github.com/goharbor/harbor/src/replication/models"
|
||||
"github.com/goharbor/harbor/src/replication/ng/dao/models"
|
||||
)
|
||||
|
||||
// ReplicationPolicy defines the data model used in API level
|
||||
type ReplicationPolicy struct {
|
||||
ID int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
Filters []rep_models.Filter `json:"filters"`
|
||||
ReplicateDeletion bool `json:"replicate_deletion"`
|
||||
Trigger *rep_models.Trigger `json:"trigger"`
|
||||
Projects []*common_models.Project `json:"projects"`
|
||||
Registries []*common_models.Registry `json:"registries"`
|
||||
CreationTime time.Time `json:"creation_time"`
|
||||
UpdateTime time.Time `json:"update_time"`
|
||||
ReplicateExistingImageNow bool `json:"replicate_existing_image_now"`
|
||||
ErrorJobCount int64 `json:"error_job_count"`
|
||||
ID int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
Filters []rep_models.Filter `json:"filters"`
|
||||
ReplicateDeletion bool `json:"replicate_deletion"`
|
||||
Trigger *rep_models.Trigger `json:"trigger"`
|
||||
Projects []*common_models.Project `json:"projects"`
|
||||
Registries []*models.Registry `json:"registries"`
|
||||
CreationTime time.Time `json:"creation_time"`
|
||||
UpdateTime time.Time `json:"update_time"`
|
||||
ReplicateExistingImageNow bool `json:"replicate_existing_image_now"`
|
||||
ErrorJobCount int64 `json:"error_job_count"`
|
||||
}
|
||||
|
||||
// Valid ...
|
||||
|
@ -6,8 +6,8 @@ import (
|
||||
"strconv"
|
||||
|
||||
"github.com/goharbor/harbor/src/common/dao"
|
||||
utilerr "github.com/goharbor/harbor/src/common/utils/error"
|
||||
"github.com/goharbor/harbor/src/common/utils/log"
|
||||
"github.com/goharbor/harbor/src/core/api/models"
|
||||
"github.com/goharbor/harbor/src/replication/ng"
|
||||
"github.com/goharbor/harbor/src/replication/ng/model"
|
||||
"github.com/goharbor/harbor/src/replication/ng/registry"
|
||||
@ -41,12 +41,14 @@ func (t *RegistryAPI) Get() {
|
||||
|
||||
registry, err := t.manager.Get(id)
|
||||
if err != nil {
|
||||
if utilerr.Is(err, utilerr.ReasonNotFound) {
|
||||
t.HandleNotFound(fmt.Sprintf("registry %d not found", id))
|
||||
return
|
||||
}
|
||||
log.Errorf("failed to get registry %d: %v", id, err)
|
||||
t.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
|
||||
return
|
||||
}
|
||||
|
||||
if registry == nil {
|
||||
t.HandleNotFound(fmt.Sprintf("registry %d not found", id))
|
||||
return
|
||||
}
|
||||
|
||||
// Hide access secret
|
||||
@ -66,6 +68,7 @@ func (t *RegistryAPI) List() {
|
||||
if err != nil {
|
||||
log.Errorf("failed to list registries %s: %v", name, err)
|
||||
t.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
|
||||
return
|
||||
}
|
||||
|
||||
// Hide passwords
|
||||
@ -87,6 +90,7 @@ func (t *RegistryAPI) Post() {
|
||||
if err != nil {
|
||||
log.Errorf("failed to get registry %s: %v", registry.Name, err)
|
||||
t.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
|
||||
return
|
||||
}
|
||||
|
||||
if reg != nil {
|
||||
@ -98,6 +102,7 @@ func (t *RegistryAPI) Post() {
|
||||
if err != nil {
|
||||
log.Errorf("Add registry '%s' error: %v", registry.URL, err)
|
||||
t.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
|
||||
return
|
||||
}
|
||||
|
||||
t.Redirect(http.StatusCreated, strconv.FormatInt(id, 10))
|
||||
@ -111,15 +116,15 @@ func (t *RegistryAPI) Put() {
|
||||
if err != nil {
|
||||
log.Errorf("Get registry by id %d error: %v", id, err)
|
||||
t.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
|
||||
return
|
||||
}
|
||||
|
||||
req := struct {
|
||||
Name *string `json:"name"`
|
||||
Endpoint *string `json:"endpoint"`
|
||||
Username *string `json:"username"`
|
||||
Password *string `json:"password"`
|
||||
Insecure *bool `json:"insecure"`
|
||||
}{}
|
||||
if registry == nil {
|
||||
t.HandleNotFound(fmt.Sprintf("Registry %d not found", id))
|
||||
return
|
||||
}
|
||||
|
||||
req := models.RegistryUpdateRequest{}
|
||||
t.DecodeJSONReq(&req)
|
||||
|
||||
originalName := registry.Name
|
||||
@ -127,14 +132,17 @@ func (t *RegistryAPI) Put() {
|
||||
if req.Name != nil {
|
||||
registry.Name = *req.Name
|
||||
}
|
||||
if req.Endpoint != nil {
|
||||
registry.URL = *req.Endpoint
|
||||
if req.URL != nil {
|
||||
registry.URL = *req.URL
|
||||
}
|
||||
if req.Username != nil {
|
||||
registry.Credential.AccessKey = *req.Username
|
||||
if req.CredentialType != nil {
|
||||
registry.Credential.Type = (model.CredentialType)(*req.CredentialType)
|
||||
}
|
||||
if req.Password != nil {
|
||||
registry.Credential.AccessSecret = *req.Password
|
||||
if req.AccessKey != nil {
|
||||
registry.Credential.AccessKey = *req.AccessKey
|
||||
}
|
||||
if req.AccessSecret != nil {
|
||||
registry.Credential.AccessSecret = *req.AccessSecret
|
||||
}
|
||||
if req.Insecure != nil {
|
||||
registry.Insecure = *req.Insecure
|
||||
@ -147,6 +155,7 @@ func (t *RegistryAPI) Put() {
|
||||
if err != nil {
|
||||
log.Errorf("Get registry by name '%s' error: %v", registry.Name, err)
|
||||
t.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
|
||||
return
|
||||
}
|
||||
|
||||
if reg != nil {
|
||||
@ -158,6 +167,7 @@ func (t *RegistryAPI) Put() {
|
||||
if err := t.manager.Update(registry); err != nil {
|
||||
log.Errorf("Update registry %d error: %v", id, err)
|
||||
t.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
@ -165,19 +175,20 @@ func (t *RegistryAPI) Put() {
|
||||
func (t *RegistryAPI) Delete() {
|
||||
id := t.GetIDFromURL()
|
||||
|
||||
_, err := t.manager.Get(id)
|
||||
registry, err := t.manager.Get(id)
|
||||
if err != nil {
|
||||
if utilerr.Is(err, utilerr.ReasonNotFound) {
|
||||
t.HandleNotFound(fmt.Sprintf("registry %d not found", id))
|
||||
return
|
||||
}
|
||||
|
||||
msg := fmt.Sprintf("Get registry %d error: %v", id, err)
|
||||
log.Error(msg)
|
||||
t.HandleInternalServerError(msg)
|
||||
return
|
||||
}
|
||||
|
||||
if registry == nil {
|
||||
t.HandleNotFound(fmt.Sprintf("registry %d not found", id))
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: Use PolicyManager instead
|
||||
policies, err := dao.GetRepPolicyByTarget(id)
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf("Get policies related to registry %d error: %v", id, err)
|
||||
@ -189,7 +200,7 @@ func (t *RegistryAPI) Delete() {
|
||||
if len(policies) > 0 {
|
||||
msg := fmt.Sprintf("Can't delete registry with replication policies, %d found", len(policies))
|
||||
log.Error(msg)
|
||||
t.HandleInternalServerError(msg)
|
||||
t.HandleStatusPreconditionFailed(msg)
|
||||
return
|
||||
}
|
||||
|
||||
@ -197,5 +208,6 @@ func (t *RegistryAPI) Delete() {
|
||||
msg := fmt.Sprintf("Delete registry %d error: %v", id, err)
|
||||
log.Error(msg)
|
||||
t.HandleInternalServerError(msg)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
166
src/core/api/registry_test.go
Normal file
166
src/core/api/registry_test.go
Normal file
@ -0,0 +1,166 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
||||
"github.com/goharbor/harbor/src/core/api/models"
|
||||
"github.com/goharbor/harbor/src/replication/ng"
|
||||
"github.com/goharbor/harbor/src/replication/ng/dao"
|
||||
"github.com/goharbor/harbor/src/replication/ng/model"
|
||||
)
|
||||
|
||||
var (
|
||||
testRegistry = &model.Registry{
|
||||
Name: "test1",
|
||||
URL: "https://test.harbor.io",
|
||||
Type: "harbor",
|
||||
Credential: &model.Credential{
|
||||
Type: model.CredentialTypeBasic,
|
||||
AccessKey: "admin",
|
||||
AccessSecret: "Harbor12345",
|
||||
},
|
||||
}
|
||||
testRegistry2 = &model.Registry{
|
||||
Name: "test2",
|
||||
URL: "https://test2.harbor.io",
|
||||
Type: "harbor",
|
||||
Credential: &model.Credential{
|
||||
Type: model.CredentialTypeBasic,
|
||||
AccessKey: "admin",
|
||||
AccessSecret: "Harbor12345",
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
type RegistrySuite struct {
|
||||
suite.Suite
|
||||
testAPI *testapi
|
||||
defaultRegistry model.Registry
|
||||
}
|
||||
|
||||
func (suite *RegistrySuite) SetupSuite() {
|
||||
assert := assert.New(suite.T())
|
||||
assert.Nil(ng.Init())
|
||||
|
||||
suite.testAPI = newHarborAPI()
|
||||
code, err := suite.testAPI.RegistryCreate(*admin, testRegistry)
|
||||
assert.Nil(err)
|
||||
assert.Equal(http.StatusCreated, code)
|
||||
|
||||
tmp, err := dao.GetRegistryByName(testRegistry.Name)
|
||||
assert.Nil(err)
|
||||
assert.NotNil(tmp)
|
||||
suite.defaultRegistry = *testRegistry
|
||||
suite.defaultRegistry.ID = tmp.ID
|
||||
|
||||
CommonAddUser()
|
||||
}
|
||||
|
||||
func (suite *RegistrySuite) TearDownSuite() {
|
||||
assert := assert.New(suite.T())
|
||||
code, err := suite.testAPI.RegistryDelete(*admin, suite.defaultRegistry.ID)
|
||||
assert.Nil(err)
|
||||
assert.Equal(http.StatusOK, code)
|
||||
|
||||
CommonDelUser()
|
||||
}
|
||||
|
||||
func (suite *RegistrySuite) TestGet() {
|
||||
assert := assert.New(suite.T())
|
||||
|
||||
// Get a non-existed registry
|
||||
_, code, _ := suite.testAPI.RegistryGet(*admin, 0)
|
||||
assert.Equal(http.StatusBadRequest, code)
|
||||
|
||||
// Get as admin, should succeed
|
||||
retrieved, code, err := suite.testAPI.RegistryGet(*admin, suite.defaultRegistry.ID)
|
||||
assert.Nil(err)
|
||||
assert.NotNil(retrieved)
|
||||
assert.Equal(http.StatusOK, code)
|
||||
assert.Equal("test1", retrieved.Name)
|
||||
|
||||
// Get as user, should fail
|
||||
_, code, _ = suite.testAPI.RegistryGet(*testUser, suite.defaultRegistry.ID)
|
||||
assert.Equal(http.StatusForbidden, code)
|
||||
}
|
||||
|
||||
func (suite *RegistrySuite) TestList() {
|
||||
assert := assert.New(suite.T())
|
||||
|
||||
// List as admin, should succeed
|
||||
registries, code, err := suite.testAPI.RegistryList(*admin)
|
||||
assert.Nil(err)
|
||||
assert.Equal(http.StatusOK, code)
|
||||
assert.Equal(1, len(registries))
|
||||
|
||||
// List as user, should fail
|
||||
registries, code, err = suite.testAPI.RegistryList(*testUser)
|
||||
assert.Equal(http.StatusForbidden, code)
|
||||
assert.Equal(0, len(registries))
|
||||
}
|
||||
|
||||
func (suite *RegistrySuite) TestPost() {
|
||||
assert := assert.New(suite.T())
|
||||
|
||||
// Should conflict when create exited registry
|
||||
code, err := suite.testAPI.RegistryCreate(*admin, testRegistry)
|
||||
assert.Nil(err)
|
||||
assert.Equal(http.StatusConflict, code)
|
||||
|
||||
// Create as user, should fail
|
||||
code, err = suite.testAPI.RegistryCreate(*testUser, testRegistry2)
|
||||
assert.Nil(err)
|
||||
assert.Equal(http.StatusForbidden, code)
|
||||
}
|
||||
|
||||
func (suite *RegistrySuite) TestRegistryPut() {
|
||||
assert := assert.New(suite.T())
|
||||
|
||||
// Update as admin, should succeed
|
||||
newKey := "NewKey"
|
||||
updateReq := &models.RegistryUpdateRequest{
|
||||
AccessKey: &newKey,
|
||||
}
|
||||
code, err := suite.testAPI.RegistryUpdate(*admin, suite.defaultRegistry.ID, updateReq)
|
||||
assert.Nil(err)
|
||||
assert.Equal(http.StatusOK, code)
|
||||
updated, code, err := suite.testAPI.RegistryGet(*admin, suite.defaultRegistry.ID)
|
||||
assert.Nil(err)
|
||||
assert.Equal(http.StatusOK, code)
|
||||
assert.Equal("NewKey", updated.Credential.AccessKey)
|
||||
|
||||
// Update as user, should fail
|
||||
code, err = suite.testAPI.RegistryUpdate(*testUser, suite.defaultRegistry.ID, updateReq)
|
||||
assert.NotNil(err)
|
||||
assert.Equal(http.StatusForbidden, code)
|
||||
}
|
||||
|
||||
func (suite *RegistrySuite) TestDelete() {
|
||||
assert := assert.New(suite.T())
|
||||
|
||||
code, err := suite.testAPI.RegistryCreate(*admin, testRegistry2)
|
||||
assert.Nil(err)
|
||||
assert.Equal(http.StatusCreated, code)
|
||||
|
||||
tmp, err := dao.GetRegistryByName(testRegistry2.Name)
|
||||
assert.Nil(err)
|
||||
assert.NotNil(tmp)
|
||||
|
||||
// Delete as user, should fail
|
||||
code, err = suite.testAPI.RegistryDelete(*testUser, tmp.ID)
|
||||
assert.NotNil(err)
|
||||
assert.Equal(http.StatusForbidden, code)
|
||||
|
||||
// Delete as admin, should succeed
|
||||
code, err = suite.testAPI.RegistryDelete(*admin, tmp.ID)
|
||||
assert.Nil(err)
|
||||
assert.Equal(http.StatusOK, code)
|
||||
}
|
||||
|
||||
func TestRegistrySuite(t *testing.T) {
|
||||
suite.Run(t, new(RegistrySuite))
|
||||
}
|
@ -29,6 +29,7 @@ import (
|
||||
"github.com/goharbor/harbor/src/replication"
|
||||
"github.com/goharbor/harbor/src/replication/core"
|
||||
rep_models "github.com/goharbor/harbor/src/replication/models"
|
||||
rep_dao "github.com/goharbor/harbor/src/replication/ng/dao"
|
||||
)
|
||||
|
||||
// RepPolicyAPI handles /api/replicationPolicies /api/replicationPolicies/:id/enablement
|
||||
@ -159,7 +160,7 @@ func (pa *RepPolicyAPI) Post() {
|
||||
|
||||
// check the existence of targets
|
||||
for _, r := range policy.Registries {
|
||||
t, err := dao.GetRegistry(r.ID)
|
||||
t, err := rep_dao.GetRegistry(r.ID)
|
||||
if err != nil {
|
||||
pa.HandleInternalServerError(fmt.Sprintf("failed to get target %d: %v", r.ID, err))
|
||||
return
|
||||
@ -272,7 +273,7 @@ func (pa *RepPolicyAPI) Put() {
|
||||
|
||||
// check the existence of targets
|
||||
for _, r := range policy.Registries {
|
||||
t, err := dao.GetRegistry(r.ID)
|
||||
t, err := rep_dao.GetRegistry(r.ID)
|
||||
if err != nil {
|
||||
pa.HandleInternalServerError(fmt.Sprintf("failed to get target %d: %v", r.ID, err))
|
||||
return
|
||||
@ -379,7 +380,7 @@ func convertFromRepPolicy(projectMgr promgr.ProjectManager, policy rep_models.Re
|
||||
|
||||
// populate targets
|
||||
for _, targetID := range policy.TargetIDs {
|
||||
r, err := dao.GetRegistry(targetID)
|
||||
r, err := rep_dao.GetRegistry(targetID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ import (
|
||||
api_models "github.com/goharbor/harbor/src/core/api/models"
|
||||
"github.com/goharbor/harbor/src/replication"
|
||||
rep_models "github.com/goharbor/harbor/src/replication/models"
|
||||
dao_models "github.com/goharbor/harbor/src/replication/ng/dao/models"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
@ -131,7 +132,7 @@ func TestRepPolicyAPIPost(t *testing.T) {
|
||||
ProjectID: projectID,
|
||||
},
|
||||
},
|
||||
Registries: []*models.Registry{
|
||||
Registries: []*dao_models.Registry{
|
||||
{
|
||||
ID: targetID,
|
||||
},
|
||||
@ -159,7 +160,7 @@ func TestRepPolicyAPIPost(t *testing.T) {
|
||||
ProjectID: projectID,
|
||||
},
|
||||
},
|
||||
Registries: []*models.Registry{
|
||||
Registries: []*dao_models.Registry{
|
||||
{
|
||||
ID: targetID,
|
||||
},
|
||||
@ -190,7 +191,7 @@ func TestRepPolicyAPIPost(t *testing.T) {
|
||||
ProjectID: 10000,
|
||||
},
|
||||
},
|
||||
Registries: []*models.Registry{
|
||||
Registries: []*dao_models.Registry{
|
||||
{
|
||||
ID: targetID,
|
||||
},
|
||||
@ -221,7 +222,7 @@ func TestRepPolicyAPIPost(t *testing.T) {
|
||||
ProjectID: projectID,
|
||||
},
|
||||
},
|
||||
Registries: []*models.Registry{
|
||||
Registries: []*dao_models.Registry{
|
||||
{
|
||||
ID: 10000,
|
||||
},
|
||||
@ -252,7 +253,7 @@ func TestRepPolicyAPIPost(t *testing.T) {
|
||||
ProjectID: projectID,
|
||||
},
|
||||
},
|
||||
Registries: []*models.Registry{
|
||||
Registries: []*dao_models.Registry{
|
||||
{
|
||||
ID: targetID,
|
||||
},
|
||||
@ -287,7 +288,7 @@ func TestRepPolicyAPIPost(t *testing.T) {
|
||||
ProjectID: projectID,
|
||||
},
|
||||
},
|
||||
Registries: []*models.Registry{
|
||||
Registries: []*dao_models.Registry{
|
||||
{
|
||||
ID: targetID,
|
||||
},
|
||||
@ -323,7 +324,7 @@ func TestRepPolicyAPIPost(t *testing.T) {
|
||||
ProjectID: projectID,
|
||||
},
|
||||
},
|
||||
Registries: []*models.Registry{
|
||||
Registries: []*dao_models.Registry{
|
||||
{
|
||||
ID: targetID,
|
||||
},
|
||||
@ -567,7 +568,7 @@ func TestRepPolicyAPIPut(t *testing.T) {
|
||||
ProjectID: projectID,
|
||||
},
|
||||
},
|
||||
Registries: []*models.Registry{
|
||||
Registries: []*dao_models.Registry{
|
||||
{
|
||||
ID: targetID,
|
||||
},
|
||||
@ -598,7 +599,7 @@ func TestRepPolicyAPIPut(t *testing.T) {
|
||||
ProjectID: projectID,
|
||||
},
|
||||
},
|
||||
Registries: []*models.Registry{
|
||||
Registries: []*dao_models.Registry{
|
||||
{
|
||||
ID: targetID,
|
||||
},
|
||||
@ -677,7 +678,7 @@ func TestConvertToRepPolicy(t *testing.T) {
|
||||
Name: "library",
|
||||
},
|
||||
},
|
||||
Registries: []*models.Registry{
|
||||
Registries: []*dao_models.Registry{
|
||||
{
|
||||
ID: 1,
|
||||
},
|
||||
|
@ -18,11 +18,14 @@ import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/goharbor/harbor/src/common/dao"
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
api_models "github.com/goharbor/harbor/src/core/api/models"
|
||||
"github.com/goharbor/harbor/src/replication"
|
||||
"github.com/stretchr/testify/require"
|
||||
rep_dao "github.com/goharbor/harbor/src/replication/ng/dao"
|
||||
dao_models "github.com/goharbor/harbor/src/replication/ng/dao/models"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -30,15 +33,15 @@ const (
|
||||
)
|
||||
|
||||
func TestReplicationAPIPost(t *testing.T) {
|
||||
registryID, err := dao.AddRegistry(
|
||||
&models.Registry{
|
||||
Name: "test_replication_target",
|
||||
URL: "127.0.0.1",
|
||||
AccessKey: "username",
|
||||
registryID, err := rep_dao.AddRegistry(
|
||||
&dao_models.Registry{
|
||||
Name: "test_replication_target",
|
||||
URL: "127.0.0.1",
|
||||
AccessKey: "username",
|
||||
AccessSecret: "password",
|
||||
})
|
||||
require.Nil(t, err)
|
||||
defer dao.DeleteRegistry(registryID)
|
||||
defer rep_dao.DeleteRegistry(registryID)
|
||||
|
||||
policyID, err := dao.AddRepPolicy(
|
||||
models.RepPolicy{
|
||||
|
@ -1,289 +0,0 @@
|
||||
// Copyright 2018 Project Harbor Authors
|
||||
//
|
||||
// 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 api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/goharbor/harbor/tests/apitests/apilib"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
const (
|
||||
addTargetName = "testTargets"
|
||||
)
|
||||
|
||||
var addTargetID int
|
||||
|
||||
func TestTargetsPost(t *testing.T) {
|
||||
var httpStatusCode int
|
||||
var err error
|
||||
|
||||
assert := assert.New(t)
|
||||
apiTest := newHarborAPI()
|
||||
|
||||
endPoint := os.Getenv("REGISTRY_URL")
|
||||
repTargets := &apilib.RepTargetPost{Endpoint: endPoint, Name: addTargetName, Username: adminName, Password: adminPwd}
|
||||
|
||||
fmt.Println("Testing Targets Post API")
|
||||
|
||||
// -------------------case 1 : response code = 201------------------------//
|
||||
fmt.Println("case 1 : response code = 201")
|
||||
httpStatusCode, body, err := apiTest.AddTargets(*admin, *repTargets)
|
||||
if err != nil {
|
||||
t.Error("Error whihle add targets", err.Error())
|
||||
t.Log(err)
|
||||
} else {
|
||||
assert.Equal(int(201), httpStatusCode, "httpStatusCode should be 201")
|
||||
t.Log(body)
|
||||
}
|
||||
|
||||
// -----------case 2 : response code = 409,name is already used-----------//
|
||||
fmt.Println("case 2 : response code = 409,name is already used")
|
||||
httpStatusCode, _, err = apiTest.AddTargets(*admin, *repTargets)
|
||||
if err != nil {
|
||||
t.Error("Error whihle add targets", err.Error())
|
||||
t.Log(err)
|
||||
} else {
|
||||
assert.Equal(int(409), httpStatusCode, "httpStatusCode should be 409")
|
||||
}
|
||||
|
||||
// -----------case 3 : response code = 409,name is already used-----------//
|
||||
fmt.Println("case 3 : response code = 409,endPoint is already used")
|
||||
repTargets.Username = "errName"
|
||||
httpStatusCode, _, err = apiTest.AddTargets(*admin, *repTargets)
|
||||
if err != nil {
|
||||
t.Error("Error whihle add targets", err.Error())
|
||||
t.Log(err)
|
||||
} else {
|
||||
assert.Equal(int(409), httpStatusCode, "httpStatusCode should be 409")
|
||||
}
|
||||
|
||||
// --------case 4 : response code = 401,User need to log in first.--------//
|
||||
fmt.Println("case 4 : response code = 401,User need to log in first.")
|
||||
httpStatusCode, _, err = apiTest.AddTargets(*unknownUsr, *repTargets)
|
||||
if err != nil {
|
||||
t.Error("Error whihle add targets", err.Error())
|
||||
t.Log(err)
|
||||
} else {
|
||||
assert.Equal(int(401), httpStatusCode, "httpStatusCode should be 401")
|
||||
}
|
||||
|
||||
fmt.Printf("\n")
|
||||
|
||||
}
|
||||
|
||||
func TestTargetsGet(t *testing.T) {
|
||||
var httpStatusCode int
|
||||
var err error
|
||||
var reslut []apilib.RepTarget
|
||||
|
||||
assert := assert.New(t)
|
||||
apiTest := newHarborAPI()
|
||||
|
||||
fmt.Println("Testing Targets Get API")
|
||||
|
||||
// -------------------case 1 : response code = 200------------------------//
|
||||
fmt.Println("case 1 : response code = 200")
|
||||
httpStatusCode, reslut, err = apiTest.ListTargets(*admin, addTargetName)
|
||||
if err != nil {
|
||||
t.Error("Error whihle get targets", err.Error())
|
||||
t.Log(err)
|
||||
} else {
|
||||
assert.Equal(int(200), httpStatusCode, "httpStatusCode should be 200")
|
||||
addTargetID = int(reslut[0].Id)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTargetPing(t *testing.T) {
|
||||
apiTest := newHarborAPI()
|
||||
|
||||
// 404: not exist target
|
||||
target01 := struct {
|
||||
ID int64 `json:"id"`
|
||||
}{
|
||||
ID: 10000,
|
||||
}
|
||||
|
||||
code, err := apiTest.PingTarget(*admin, target01)
|
||||
require.Nil(t, err)
|
||||
assert.Equal(t, http.StatusNotFound, code)
|
||||
|
||||
// 400: empty endpoint
|
||||
target02 := struct {
|
||||
Endpoint string `json:"endpoint"`
|
||||
}{
|
||||
Endpoint: "",
|
||||
}
|
||||
code, err = apiTest.PingTarget(*admin, target02)
|
||||
require.Nil(t, err)
|
||||
assert.Equal(t, http.StatusBadRequest, code)
|
||||
|
||||
// 200
|
||||
target03 := struct {
|
||||
ID int64 `json:"id"`
|
||||
Endpoint string `json:"endpoint"`
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
Insecure bool `json:"insecure"`
|
||||
}{
|
||||
ID: int64(addTargetID),
|
||||
Endpoint: os.Getenv("REGISTRY_URL"),
|
||||
Username: adminName,
|
||||
Password: adminPwd,
|
||||
Insecure: true,
|
||||
}
|
||||
code, err = apiTest.PingTarget(*admin, target03)
|
||||
require.Nil(t, err)
|
||||
assert.Equal(t, http.StatusOK, code)
|
||||
}
|
||||
|
||||
func TestTargetGetByID(t *testing.T) {
|
||||
var httpStatusCode int
|
||||
var err error
|
||||
|
||||
assert := assert.New(t)
|
||||
apiTest := newHarborAPI()
|
||||
|
||||
fmt.Println("Testing Targets Get API by Id")
|
||||
|
||||
// -------------------case 1 : response code = 200------------------------//
|
||||
fmt.Println("case 1 : response code = 200")
|
||||
id := strconv.Itoa(addTargetID)
|
||||
httpStatusCode, err = apiTest.GetTargetByID(*admin, id)
|
||||
if err != nil {
|
||||
t.Error("Error whihle get target by id", err.Error())
|
||||
t.Log(err)
|
||||
} else {
|
||||
assert.Equal(int(200), httpStatusCode, "httpStatusCode should be 200")
|
||||
}
|
||||
|
||||
// --------------case 2 : response code = 404,target not found------------//
|
||||
fmt.Println("case 2 : response code = 404,target not found")
|
||||
id = "1111"
|
||||
httpStatusCode, err = apiTest.GetTargetByID(*admin, id)
|
||||
if err != nil {
|
||||
t.Error("Error whihle get target by id", err.Error())
|
||||
t.Log(err)
|
||||
} else {
|
||||
assert.Equal(int(404), httpStatusCode, "httpStatusCode should be 404")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestTargetsPut(t *testing.T) {
|
||||
var httpStatusCode int
|
||||
var err error
|
||||
|
||||
assert := assert.New(t)
|
||||
apiTest := newHarborAPI()
|
||||
|
||||
endPoint := "1.1.1.1"
|
||||
updateRepTargets := &apilib.RepTargetPost{Endpoint: endPoint, Name: addTargetName, Username: adminName, Password: adminPwd}
|
||||
id := strconv.Itoa(addTargetID)
|
||||
|
||||
fmt.Println("Testing Target Put API")
|
||||
|
||||
// -------------------case 1 : response code = 200------------------------//
|
||||
fmt.Println("case 1 : response code = 200")
|
||||
httpStatusCode, err = apiTest.PutTargetByID(*admin, id, *updateRepTargets)
|
||||
if err != nil {
|
||||
t.Error("Error whihle update target", err.Error())
|
||||
t.Log(err)
|
||||
} else {
|
||||
assert.Equal(int(200), httpStatusCode, "httpStatusCode should be 200")
|
||||
}
|
||||
|
||||
// --------------case 2 : response code = 404,target not found------------//
|
||||
id = "111"
|
||||
fmt.Println("case 2 : response code = 404,target not found")
|
||||
httpStatusCode, err = apiTest.PutTargetByID(*admin, id, *updateRepTargets)
|
||||
if err != nil {
|
||||
t.Error("Error whihle update target", err.Error())
|
||||
t.Log(err)
|
||||
} else {
|
||||
assert.Equal(int(404), httpStatusCode, "httpStatusCode should be 404")
|
||||
}
|
||||
|
||||
}
|
||||
func TestTargetGetPolicies(t *testing.T) {
|
||||
var httpStatusCode int
|
||||
var err error
|
||||
|
||||
assert := assert.New(t)
|
||||
apiTest := newHarborAPI()
|
||||
|
||||
fmt.Println("Testing Targets Get API to list policies")
|
||||
|
||||
// -------------------case 1 : response code = 200------------------------//
|
||||
fmt.Println("case 1 : response code = 200")
|
||||
id := strconv.Itoa(addTargetID)
|
||||
httpStatusCode, err = apiTest.GetTargetPoliciesByID(*admin, id)
|
||||
if err != nil {
|
||||
t.Error("Error whihle get target by id", err.Error())
|
||||
t.Log(err)
|
||||
} else {
|
||||
assert.Equal(int(200), httpStatusCode, "httpStatusCode should be 200")
|
||||
}
|
||||
|
||||
// --------------case 2 : response code = 404,target not found------------//
|
||||
fmt.Println("case 2 : response code = 404,target not found")
|
||||
id = "1111"
|
||||
httpStatusCode, err = apiTest.GetTargetPoliciesByID(*admin, id)
|
||||
if err != nil {
|
||||
t.Error("Error whihle get target by id", err.Error())
|
||||
t.Log(err)
|
||||
} else {
|
||||
assert.Equal(int(404), httpStatusCode, "httpStatusCode should be 404")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestTargetsDelete(t *testing.T) {
|
||||
var httpStatusCode int
|
||||
var err error
|
||||
|
||||
assert := assert.New(t)
|
||||
apiTest := newHarborAPI()
|
||||
|
||||
id := strconv.Itoa(addTargetID)
|
||||
fmt.Println("Testing Targets Delete API")
|
||||
|
||||
// -------------------case 1 : response code = 200------------------------//
|
||||
fmt.Println("case 1 : response code = 200")
|
||||
httpStatusCode, err = apiTest.DeleteTargetsByID(*admin, id)
|
||||
if err != nil {
|
||||
t.Error("Error whihle delete targets", err.Error())
|
||||
t.Log(err)
|
||||
} else {
|
||||
assert.Equal(int(200), httpStatusCode, "httpStatusCode should be 200")
|
||||
}
|
||||
|
||||
// --------------case 2 : response code = 404,target not found------------//
|
||||
fmt.Println("case 2 : response code = 404,target not found")
|
||||
id = "1111"
|
||||
httpStatusCode, err = apiTest.DeleteTargetsByID(*admin, id)
|
||||
if err != nil {
|
||||
t.Error("Error whihle delete targets", err.Error())
|
||||
t.Log(err)
|
||||
} else {
|
||||
assert.Equal(int(404), httpStatusCode, "httpStatusCode should be 404")
|
||||
}
|
||||
|
||||
}
|
@ -8,6 +8,11 @@ import (
|
||||
"github.com/goharbor/harbor/src/common/utils"
|
||||
)
|
||||
|
||||
const (
|
||||
// RegistryTable is the table name for registry
|
||||
RegistryTable = "registry"
|
||||
)
|
||||
|
||||
// Registry is the model for a registry, which wraps the endpoint URL and credential of a remote registry.
|
||||
type Registry struct {
|
||||
ID int64 `orm:"pk;auto;column(id)" json:"id"`
|
||||
@ -49,10 +54,4 @@ func (r *Registry) Valid(v *validation.Validation) {
|
||||
v.SetError("endpoint", "max length is 64")
|
||||
}
|
||||
}
|
||||
|
||||
// password is encoded using base64, the length of this field
|
||||
// in DB is 64, so the max length in request is 48
|
||||
if len(r.AccessSecret) > 48 {
|
||||
v.SetError("password", "max length is 48")
|
||||
}
|
||||
}
|
@ -5,7 +5,8 @@ import (
|
||||
|
||||
"github.com/astaxie/beego/orm"
|
||||
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
"github.com/goharbor/harbor/src/common/dao"
|
||||
"github.com/goharbor/harbor/src/replication/ng/dao/models"
|
||||
)
|
||||
|
||||
// ListRegistryQuery defines the query conditions to list registry.
|
||||
@ -20,15 +21,15 @@ type ListRegistryQuery struct {
|
||||
|
||||
// AddRegistry add a new registry
|
||||
func AddRegistry(registry *models.Registry) (int64, error) {
|
||||
o := GetOrmer()
|
||||
o := dao.GetOrmer()
|
||||
return o.Insert(registry)
|
||||
}
|
||||
|
||||
// GetRegistry gets one registry from database by id.
|
||||
func GetRegistry(id int64) (*models.Registry, error) {
|
||||
o := GetOrmer()
|
||||
o := dao.GetOrmer()
|
||||
r := models.Registry{ID: id}
|
||||
err := o.Read(&r)
|
||||
err := o.Read(&r, "ID")
|
||||
if err == orm.ErrNoRows {
|
||||
return nil, nil
|
||||
}
|
||||
@ -37,9 +38,9 @@ func GetRegistry(id int64) (*models.Registry, error) {
|
||||
|
||||
// GetRegistryByName gets one registry from database by its name.
|
||||
func GetRegistryByName(name string) (*models.Registry, error) {
|
||||
o := GetOrmer()
|
||||
o := dao.GetOrmer()
|
||||
r := models.Registry{Name: name}
|
||||
err := o.Read(&r)
|
||||
err := o.Read(&r, "Name")
|
||||
if err == orm.ErrNoRows {
|
||||
return nil, nil
|
||||
}
|
||||
@ -48,9 +49,9 @@ func GetRegistryByName(name string) (*models.Registry, error) {
|
||||
|
||||
// GetRegistryByURL gets one registry from database by its URL.
|
||||
func GetRegistryByURL(url string) (*models.Registry, error) {
|
||||
o := GetOrmer()
|
||||
o := dao.GetOrmer()
|
||||
r := models.Registry{URL: url}
|
||||
err := o.Read(&r)
|
||||
err := o.Read(&r, "URL")
|
||||
if err == orm.ErrNoRows {
|
||||
return nil, nil
|
||||
}
|
||||
@ -60,10 +61,10 @@ func GetRegistryByURL(url string) (*models.Registry, error) {
|
||||
// ListRegistries lists registries. Registries returned are sorted by creation time.
|
||||
// - query: query to the registry name, name query and pagination are defined.
|
||||
func ListRegistries(query ...*ListRegistryQuery) (int64, []*models.Registry, error) {
|
||||
o := GetOrmer()
|
||||
o := dao.GetOrmer()
|
||||
|
||||
q := o.QueryTable(&models.Registry{})
|
||||
if len(query) > 0 {
|
||||
if len(query) > 0 && len(query[0].Query) > 0 {
|
||||
q = q.Filter("name__contains", query[0].Query)
|
||||
}
|
||||
|
||||
@ -87,7 +88,7 @@ func ListRegistries(query ...*ListRegistryQuery) (int64, []*models.Registry, err
|
||||
|
||||
// UpdateRegistry updates one registry
|
||||
func UpdateRegistry(registry *models.Registry) error {
|
||||
o := GetOrmer()
|
||||
o := dao.GetOrmer()
|
||||
|
||||
sql := `update registry
|
||||
set url = ?, name = ?, credential_type = ?, access_key = ?, access_secret = ?, type = ?, insecure = ?, health = ?, description = ?, update_time = ?
|
||||
@ -101,7 +102,7 @@ func UpdateRegistry(registry *models.Registry) error {
|
||||
|
||||
// DeleteRegistry deletes a registry
|
||||
func DeleteRegistry(id int64) error {
|
||||
o := GetOrmer()
|
||||
o := dao.GetOrmer()
|
||||
_, err := o.Delete(&models.Registry{ID: id})
|
||||
return err
|
||||
}
|
175
src/replication/ng/dao/registry_test.go
Normal file
175
src/replication/ng/dao/registry_test.go
Normal file
@ -0,0 +1,175 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
||||
"github.com/goharbor/harbor/src/replication/ng/dao/models"
|
||||
)
|
||||
|
||||
var (
|
||||
defaultRegistry = &models.Registry{
|
||||
Name: "daoTestDefault",
|
||||
URL: "test.harbor.io",
|
||||
CredentialType: "basic",
|
||||
AccessKey: "key1",
|
||||
AccessSecret: "secret1",
|
||||
Type: "harbor",
|
||||
}
|
||||
testRegistry1 = &models.Registry{
|
||||
Name: "daoTest2",
|
||||
URL: "test2.harbor.io",
|
||||
CredentialType: "basic",
|
||||
AccessKey: "key1",
|
||||
AccessSecret: "secret1",
|
||||
Type: "harbor",
|
||||
}
|
||||
)
|
||||
|
||||
type RegistrySuite struct {
|
||||
suite.Suite
|
||||
defaultID int64
|
||||
}
|
||||
|
||||
func (suite *RegistrySuite) SetupTest() {
|
||||
assert := assert.New(suite.T())
|
||||
id, err := AddRegistry(defaultRegistry)
|
||||
assert.Nil(err)
|
||||
suite.defaultID = id
|
||||
}
|
||||
|
||||
func (suite *RegistrySuite) TearDownTest() {
|
||||
assert := assert.New(suite.T())
|
||||
err := DeleteRegistry(suite.defaultID)
|
||||
assert.Nil(err)
|
||||
}
|
||||
|
||||
func (suite *RegistrySuite) TestGetRegistry() {
|
||||
assert := assert.New(suite.T())
|
||||
|
||||
// Get non-existed registry, should fail
|
||||
r, _ := GetRegistry(0)
|
||||
assert.Nil(r)
|
||||
|
||||
// Get existed registry, should succeed
|
||||
r, err := GetRegistry(suite.defaultID)
|
||||
assert.Nil(err)
|
||||
assert.Equal(defaultRegistry.Name, r.Name)
|
||||
}
|
||||
|
||||
func (suite *RegistrySuite) TestGetRegistryByName() {
|
||||
assert := assert.New(suite.T())
|
||||
|
||||
// Get registry by empty name, should fail
|
||||
r, _ := GetRegistryByName("")
|
||||
assert.Nil(r)
|
||||
|
||||
// Get non-existed registry, should fail
|
||||
r, _ = GetRegistryByName("non-exist")
|
||||
assert.Nil(r)
|
||||
|
||||
// Get existed registry, should succeed
|
||||
r, err := GetRegistryByName(defaultRegistry.Name)
|
||||
assert.Nil(err)
|
||||
assert.Equal(defaultRegistry.Name, r.Name)
|
||||
}
|
||||
|
||||
func (suite *RegistrySuite) TestGetRegistryByURL() {
|
||||
assert := assert.New(suite.T())
|
||||
|
||||
// Get registry by empty url, should fail
|
||||
r, _ := GetRegistryByURL("")
|
||||
assert.Nil(r)
|
||||
|
||||
// Get non-existed registry, should fail
|
||||
r, _ = GetRegistryByURL("non-exist.harbor.io")
|
||||
assert.Nil(r)
|
||||
|
||||
// Get existed registry, should succeed
|
||||
r, err := GetRegistryByURL(defaultRegistry.URL)
|
||||
assert.Nil(err)
|
||||
assert.Equal(defaultRegistry.Name, r.Name)
|
||||
}
|
||||
|
||||
func (suite *RegistrySuite) TestListRegistries() {
|
||||
assert := assert.New(suite.T())
|
||||
|
||||
// Insert on more registry
|
||||
id, err := AddRegistry(testRegistry1)
|
||||
assert.Nil(err)
|
||||
assert.NotEqual(0, id)
|
||||
|
||||
// List all registries, should succeed
|
||||
total, registries, err := ListRegistries()
|
||||
assert.Nil(err)
|
||||
if total < 2 {
|
||||
suite.T().Errorf("At least %d should be found in total, but got %d", 2, total)
|
||||
}
|
||||
|
||||
// List default registry by normal query, should succeed
|
||||
total, registries, err = ListRegistries(&ListRegistryQuery{
|
||||
Query: "Default",
|
||||
Offset: 0,
|
||||
Limit: 10,
|
||||
})
|
||||
assert.Nil(err)
|
||||
assert.Equal(int64(1), total)
|
||||
assert.Equal(defaultRegistry.Name, registries[0].Name)
|
||||
|
||||
// List registry and limit to 1, should return one
|
||||
total, registries, err = ListRegistries(&ListRegistryQuery{
|
||||
Query: "dao",
|
||||
Offset: 0,
|
||||
Limit: 1,
|
||||
})
|
||||
assert.Nil(err)
|
||||
assert.Equal(int64(2), total)
|
||||
assert.Equal(1, len(registries))
|
||||
|
||||
// List registry and limit set to -1, should return all
|
||||
total, registries, err = ListRegistries(&ListRegistryQuery{
|
||||
Limit: -1,
|
||||
})
|
||||
assert.Nil(err)
|
||||
if total < 2 {
|
||||
suite.T().Errorf("At least %d should be found in total, but got %d", 2, total)
|
||||
}
|
||||
if len(registries) < 2 {
|
||||
suite.T().Errorf("At least %d should be returned, but got %d", 2, len(registries))
|
||||
}
|
||||
|
||||
// List registry and large offset, should return empty
|
||||
total, registries, err = ListRegistries(&ListRegistryQuery{
|
||||
Offset: 10,
|
||||
Limit: 1,
|
||||
})
|
||||
assert.Nil(err)
|
||||
if total < 2 {
|
||||
suite.T().Errorf("At least %d should be found in total, but got %d", 2, total)
|
||||
}
|
||||
assert.Equal(0, len(registries))
|
||||
}
|
||||
|
||||
func (suite *RegistrySuite) TestUpdate() {
|
||||
assert := assert.New(suite.T())
|
||||
|
||||
// Get registry, should succeed
|
||||
r, err := GetRegistry(suite.defaultID)
|
||||
assert.Nil(err)
|
||||
assert.NotNil(r)
|
||||
|
||||
r.AccessKey = "key2"
|
||||
err = UpdateRegistry(r)
|
||||
assert.Nil(err)
|
||||
|
||||
r, err = GetRegistry(suite.defaultID)
|
||||
assert.Nil(err)
|
||||
assert.NotNil(r)
|
||||
assert.Equal("key2", r.AccessKey)
|
||||
}
|
||||
|
||||
func TestRegistrySuite(t *testing.T) {
|
||||
suite.Run(t, new(RegistrySuite))
|
||||
}
|
@ -15,7 +15,6 @@
|
||||
package flow
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/goharbor/harbor/src/common/utils/log"
|
||||
@ -39,7 +38,8 @@ type Controller interface {
|
||||
func NewController(registryMgr registry.Manager,
|
||||
executionMgr execution.Manager, scheduler scheduler.Scheduler) (Controller, error) {
|
||||
if registryMgr == nil || executionMgr == nil || scheduler == nil {
|
||||
return nil, errors.New("invalid params")
|
||||
// TODO(ChenDe): Uncomment it when execution manager is ready
|
||||
// return nil, errors.New("invalid params")
|
||||
}
|
||||
return &defaultController{
|
||||
registryMgr: registryMgr,
|
||||
|
@ -71,9 +71,6 @@ func (f *fakedRegistryManager) Get(id int64) (*model.Registry, error) {
|
||||
func (f *fakedRegistryManager) GetByName(name string) (*model.Registry, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (f *fakedRegistryManager) GetByURL(url string) (*model.Registry, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (f *fakedRegistryManager) Update(*model.Registry, ...string) error {
|
||||
return nil
|
||||
}
|
||||
|
@ -1,31 +0,0 @@
|
||||
// Copyright Project Harbor Authors
|
||||
//
|
||||
// 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 ng
|
||||
|
||||
import "github.com/goharbor/harbor/src/replication/ng/registry"
|
||||
|
||||
var (
|
||||
// RegistryMgr is a global registry manager
|
||||
RegistryMgr registry.Manager
|
||||
)
|
||||
|
||||
// Init the global variables
|
||||
func Init() error {
|
||||
// Init registry manager
|
||||
RegistryMgr = registry.NewDefaultManager()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -18,14 +18,13 @@ import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/goharbor/harbor/src/common/dao"
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
"github.com/goharbor/harbor/src/common/utils"
|
||||
utilerr "github.com/goharbor/harbor/src/common/utils/error"
|
||||
"github.com/goharbor/harbor/src/common/utils/log"
|
||||
"github.com/goharbor/harbor/src/common/utils/registry"
|
||||
"github.com/goharbor/harbor/src/common/utils/registry/auth"
|
||||
"github.com/goharbor/harbor/src/core/config"
|
||||
"github.com/goharbor/harbor/src/replication/ng/dao"
|
||||
"github.com/goharbor/harbor/src/replication/ng/dao/models"
|
||||
"github.com/goharbor/harbor/src/replication/ng/model"
|
||||
)
|
||||
|
||||
@ -51,8 +50,6 @@ type Manager interface {
|
||||
Get(int64) (*model.Registry, error)
|
||||
// GetByName gets registry by name
|
||||
GetByName(name string) (*model.Registry, error)
|
||||
// GetByURL gets registry by its URL
|
||||
GetByURL(url string) (*model.Registry, error)
|
||||
// Update the registry, the "props" are the properties of registry
|
||||
// that need to be updated
|
||||
Update(registry *model.Registry, props ...string) error
|
||||
@ -81,10 +78,7 @@ func (m *DefaultManager) Get(id int64) (*model.Registry, error) {
|
||||
}
|
||||
|
||||
if registry == nil {
|
||||
return nil, utilerr.KnownError{
|
||||
Reason: utilerr.ReasonNotFound,
|
||||
Message: fmt.Sprintf("registry '%d' does not exist", id),
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return fromDaoModel(registry)
|
||||
@ -104,32 +98,18 @@ func (m *DefaultManager) GetByName(name string) (*model.Registry, error) {
|
||||
return fromDaoModel(registry)
|
||||
}
|
||||
|
||||
// GetByURL gets a registry by its URL
|
||||
func (m *DefaultManager) GetByURL(url string) (*model.Registry, error) {
|
||||
registry, err := dao.GetRegistryByURL(url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if registry == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return fromDaoModel(registry)
|
||||
}
|
||||
|
||||
// List lists registries according to query provided.
|
||||
func (m *DefaultManager) List(query ...*model.RegistryQuery) (int64, []*model.Registry, error) {
|
||||
var registryQueries []*dao.ListRegistryQuery
|
||||
for _, q := range query {
|
||||
if len(query) > 0 {
|
||||
// limit being -1 indicates no pagination specified, result in all registries matching name returned.
|
||||
listQuery := &dao.ListRegistryQuery{
|
||||
Query: q.Name,
|
||||
Query: query[0].Name,
|
||||
Limit: -1,
|
||||
}
|
||||
if q.Pagination != nil {
|
||||
listQuery.Offset = q.Pagination.Page * q.Pagination.Size
|
||||
listQuery.Limit = q.Pagination.Size
|
||||
if query[0].Pagination != nil {
|
||||
listQuery.Offset = query[0].Pagination.Page * query[0].Pagination.Size
|
||||
listQuery.Limit = query[0].Pagination.Size
|
||||
}
|
||||
|
||||
registryQueries = append(registryQueries, listQuery)
|
||||
@ -252,22 +232,21 @@ func healthStatus(r *model.Registry) (HealthStatus, error) {
|
||||
}
|
||||
|
||||
// decrypt checks whether access secret is set in the registry, if so, decrypt it.
|
||||
func decrypt(registry *model.Registry) error {
|
||||
if len(registry.Credential.AccessSecret) == 0 {
|
||||
return nil
|
||||
func decrypt(secret string) (string, error) {
|
||||
if len(secret) == 0 {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
key, err := config.SecretKey()
|
||||
if err != nil {
|
||||
return err
|
||||
return "", err
|
||||
}
|
||||
decrypted, err := utils.ReversibleDecrypt(registry.Credential.AccessSecret, key)
|
||||
decrypted, err := utils.ReversibleDecrypt(secret, key)
|
||||
if err != nil {
|
||||
return err
|
||||
return "", err
|
||||
}
|
||||
registry.Credential.AccessSecret = decrypted
|
||||
|
||||
return nil
|
||||
return decrypted, nil
|
||||
}
|
||||
|
||||
// encrypt checks whether access secret is set in the registry, if so, encrypt it.
|
||||
@ -291,6 +270,11 @@ func encrypt(secret string) (string, error) {
|
||||
// fromDaoModel converts DAO layer registry model to replication model.
|
||||
// Also, if access secret is provided, decrypt it.
|
||||
func fromDaoModel(registry *models.Registry) (*model.Registry, error) {
|
||||
decrypted, err := decrypt(registry.AccessSecret)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
r := &model.Registry{
|
||||
ID: registry.ID,
|
||||
Name: registry.Name,
|
||||
@ -300,7 +284,7 @@ func fromDaoModel(registry *models.Registry) (*model.Registry, error) {
|
||||
Credential: &model.Credential{
|
||||
Type: model.CredentialType(registry.CredentialType),
|
||||
AccessKey: registry.AccessKey,
|
||||
AccessSecret: registry.AccessSecret,
|
||||
AccessSecret: decrypted,
|
||||
},
|
||||
Insecure: registry.Insecure,
|
||||
Status: registry.Health,
|
||||
@ -308,10 +292,6 @@ func fromDaoModel(registry *models.Registry) (*model.Registry, error) {
|
||||
UpdateTime: registry.UpdateTime,
|
||||
}
|
||||
|
||||
if err := decrypt(r); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return r, nil
|
||||
}
|
||||
|
||||
|
@ -38,7 +38,8 @@ var (
|
||||
|
||||
// Init the global variables
|
||||
func Init() error {
|
||||
// TODO init RegistryMgr
|
||||
// Init registry manager
|
||||
RegistryMgr = registry.NewDefaultManager()
|
||||
|
||||
// TODO init ExecutionMgr
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user