mirror of
https://github.com/goharbor/harbor.git
synced 2024-11-27 04:35:16 +01:00
merge code from master and fix conflicts
Signed-off-by: Steven Zou <szou@vmware.com>
This commit is contained in:
commit
c44747fd3c
@ -3478,6 +3478,37 @@ paths:
|
||||
description: The robot account is not found.
|
||||
'500':
|
||||
description: Unexpected internal errors.
|
||||
'/system/oidc/ping':
|
||||
post:
|
||||
summary: Test the OIDC endpoint.
|
||||
description: Test the OIDC endpoint, the setting of the endpoint is provided in the request. This API can only
|
||||
be called by system admin.
|
||||
tags:
|
||||
- Products
|
||||
- System
|
||||
parameters:
|
||||
- name: endpoint
|
||||
in: body
|
||||
description: Request body for OIDC endpoint to be tested.
|
||||
required: true
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
url:
|
||||
type: string
|
||||
description: The URL of OIDC endpoint to be tested.
|
||||
verify_cert:
|
||||
type: boolean
|
||||
description: Whether the certificate should be verified
|
||||
responses:
|
||||
'200':
|
||||
description: Ping succeeded. The OIDC endpoint is valid.
|
||||
'400':
|
||||
description: The ping failed
|
||||
'401':
|
||||
description: User need to log in first.
|
||||
'403':
|
||||
description: User does not have permission to call this API
|
||||
'/system/CVEWhitelist':
|
||||
get:
|
||||
summary: Get the system level whitelist of CVE.
|
||||
|
@ -1,16 +1,16 @@
|
||||
package chartserver
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
commonhttp "github.com/goharbor/harbor/src/common/http"
|
||||
hlog "github.com/goharbor/harbor/src/common/utils/log"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
commonhttp "github.com/goharbor/harbor/src/common/http"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -49,11 +49,13 @@ func NewChartClient(credential *Credential) *ChartClient { // Create http client
|
||||
func (cc *ChartClient) GetContent(addr string) ([]byte, error) {
|
||||
response, err := cc.sendRequest(addr, http.MethodGet, nil)
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, "get content failed")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
content, err := ioutil.ReadAll(response.Body)
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, "Read response body error")
|
||||
return nil, err
|
||||
}
|
||||
defer response.Body.Close()
|
||||
@ -61,6 +63,7 @@ func (cc *ChartClient) GetContent(addr string) ([]byte, error) {
|
||||
if response.StatusCode != http.StatusOK {
|
||||
text, err := extractError(content)
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, "Extract content error failed")
|
||||
return nil, err
|
||||
}
|
||||
return nil, &commonhttp.Error{
|
||||
@ -106,7 +109,8 @@ func (cc *ChartClient) sendRequest(addr string, method string, body io.Reader) (
|
||||
|
||||
fullURI, err := url.Parse(addr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid url: %s", err.Error())
|
||||
err = errors.Wrap(err, "Invalid url")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
request, err := http.NewRequest(method, addr, body)
|
||||
@ -121,7 +125,7 @@ func (cc *ChartClient) sendRequest(addr string, method string, body io.Reader) (
|
||||
|
||||
response, err := cc.httpClient.Do(request)
|
||||
if err != nil {
|
||||
hlog.Errorf("%s '%s' failed with error: %s", method, fullURI.Path, err)
|
||||
err = errors.Wrap(err, fmt.Sprintf("send request %s %s failed", method, fullURI.Path))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
@ -2,19 +2,17 @@ package chartserver
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
"github.com/goharbor/harbor/src/common/utils/log"
|
||||
"github.com/goharbor/harbor/src/replication"
|
||||
rep_event "github.com/goharbor/harbor/src/replication/event"
|
||||
"github.com/goharbor/harbor/src/replication/model"
|
||||
"github.com/pkg/errors"
|
||||
helm_repo "k8s.io/helm/pkg/repo"
|
||||
|
||||
"os"
|
||||
|
||||
"github.com/goharbor/harbor/src/common/utils/log"
|
||||
)
|
||||
|
||||
// ListCharts gets the chart list under the namespace
|
||||
|
@ -20,12 +20,11 @@ import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/astaxie/beego"
|
||||
"github.com/astaxie/beego/validation"
|
||||
commonhttp "github.com/goharbor/harbor/src/common/http"
|
||||
"github.com/goharbor/harbor/src/common/utils/log"
|
||||
|
||||
"errors"
|
||||
"github.com/astaxie/beego"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -144,11 +144,7 @@ func UpdateUserGroupName(id int, groupName string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// OnBoardUserGroup will check if a usergroup exists in usergroup table, if not insert the usergroup and
|
||||
// put the id in the pointer of usergroup model, if it does exist, return the usergroup's profile.
|
||||
// This is used for ldap and uaa authentication, such the usergroup can have an ID in Harbor.
|
||||
// the keyAttribute and combinedKeyAttribute are key columns used to check duplicate usergroup in harbor
|
||||
func OnBoardUserGroup(g *models.UserGroup, keyAttribute string, combinedKeyAttributes ...string) error {
|
||||
func onBoardCommonUserGroup(g *models.UserGroup, keyAttribute string, combinedKeyAttributes ...string) error {
|
||||
g.LdapGroupDN = utils.TrimLower(g.LdapGroupDN)
|
||||
|
||||
o := dao.GetOrmer()
|
||||
@ -172,3 +168,12 @@ func OnBoardUserGroup(g *models.UserGroup, keyAttribute string, combinedKeyAttri
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// OnBoardUserGroup will check if a usergroup exists in usergroup table, if not insert the usergroup and
|
||||
// put the id in the pointer of usergroup model, if it does exist, return the usergroup's profile.
|
||||
func OnBoardUserGroup(g *models.UserGroup) error {
|
||||
if g.GroupType == common.LDAPGroupType {
|
||||
return onBoardCommonUserGroup(g, "LdapGroupDN", "GroupType")
|
||||
}
|
||||
return onBoardCommonUserGroup(g, "GroupName", "GroupType")
|
||||
}
|
||||
|
@ -256,7 +256,7 @@ func TestOnBoardUserGroup(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if err := OnBoardUserGroup(tt.args.g, "LdapGroupDN", "GroupType"); (err != nil) != tt.wantErr {
|
||||
if err := OnBoardUserGroup(tt.args.g); (err != nil) != tt.wantErr {
|
||||
t.Errorf("OnBoardUserGroup() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
})
|
||||
|
@ -206,3 +206,19 @@ func RefreshToken(ctx context.Context, token *Token) (*Token, error) {
|
||||
}
|
||||
return &Token{Token: *t, IDToken: it}, nil
|
||||
}
|
||||
|
||||
// Conn wraps connection info of an OIDC endpoint
|
||||
type Conn struct {
|
||||
URL string `json:"url"`
|
||||
VerifyCert bool `json:"verify_cert"`
|
||||
}
|
||||
|
||||
// TestEndpoint tests whether the endpoint is a valid OIDC endpoint.
|
||||
// The nil return value indicates the success of the test
|
||||
func TestEndpoint(conn Conn) error {
|
||||
|
||||
// gooidc will try to call the discovery api when creating the provider and that's all we need to check
|
||||
ctx := clientCtx(context.Background(), conn.VerifyCert)
|
||||
_, err := gooidc.NewProvider(ctx, conn.URL)
|
||||
return err
|
||||
}
|
||||
|
@ -97,3 +97,16 @@ func TestAuthCodeURL(t *testing.T) {
|
||||
assert.Equal(t, "offline", q.Get("access_type"))
|
||||
assert.False(t, strings.Contains(q.Get("scope"), "offline_access"))
|
||||
}
|
||||
|
||||
func TestTestEndpoint(t *testing.T) {
|
||||
c1 := Conn{
|
||||
URL: googleEndpoint,
|
||||
VerifyCert: true,
|
||||
}
|
||||
c2 := Conn{
|
||||
URL: "https://www.baidu.com",
|
||||
VerifyCert: false,
|
||||
}
|
||||
assert.Nil(t, TestEndpoint(c1))
|
||||
assert.NotNil(t, TestEndpoint(c2))
|
||||
}
|
||||
|
@ -16,8 +16,10 @@ package api
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/goharbor/harbor/src/pkg/retention"
|
||||
"github.com/goharbor/harbor/src/pkg/scheduler"
|
||||
|
||||
"net/http"
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
@ -33,10 +35,6 @@ import (
|
||||
|
||||
const (
|
||||
yamlFileContentType = "application/x-yaml"
|
||||
// ReplicationJobType ...
|
||||
ReplicationJobType = "replication"
|
||||
// ScanJobType ...
|
||||
ScanJobType = "scan"
|
||||
)
|
||||
|
||||
// the managers/controllers used globally
|
||||
@ -96,7 +94,7 @@ func (b *BaseController) WriteYamlData(object interface{}) {
|
||||
w := b.Ctx.ResponseWriter
|
||||
w.Header().Set("Content-Type", yamlFileContentType)
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write(yData)
|
||||
_, _ = w.Write(yData)
|
||||
}
|
||||
|
||||
// Init related objects/configurations for the API controllers
|
||||
|
@ -145,6 +145,7 @@ func init() {
|
||||
beego.Router("/api/system/gc/schedule", &GCAPI{}, "get:Get;put:Put;post:Post")
|
||||
beego.Router("/api/system/scanAll/schedule", &ScanAllAPI{}, "get:Get;put:Put;post:Post")
|
||||
beego.Router("/api/system/CVEWhitelist", &SysCVEWhitelistAPI{}, "get:Get;put:Put")
|
||||
beego.Router("/api/system/oidc/ping", &OIDCAPI{}, "post:Ping")
|
||||
|
||||
beego.Router("/api/projects/:pid([0-9]+)/robots/", &RobotAPI{}, "post:Post;get:List")
|
||||
beego.Router("/api/projects/:pid([0-9]+)/robots/:id([0-9]+)", &RobotAPI{}, "get:Get;put:Put;delete:Delete")
|
||||
|
56
src/core/api/oidc.go
Normal file
56
src/core/api/oidc.go
Normal file
@ -0,0 +1,56 @@
|
||||
// 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 api
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/goharbor/harbor/src/common/utils/log"
|
||||
"github.com/goharbor/harbor/src/common/utils/oidc"
|
||||
)
|
||||
|
||||
// OIDCAPI handles the requests to /api/system/oidc/xxx
|
||||
type OIDCAPI struct {
|
||||
BaseController
|
||||
}
|
||||
|
||||
// Prepare validates the request initially
|
||||
func (oa *OIDCAPI) Prepare() {
|
||||
oa.BaseController.Prepare()
|
||||
if !oa.SecurityCtx.IsAuthenticated() {
|
||||
oa.SendUnAuthorizedError(errors.New("unauthorized"))
|
||||
return
|
||||
}
|
||||
if !oa.SecurityCtx.IsSysAdmin() {
|
||||
msg := "only system admin has permission to access this API"
|
||||
log.Errorf(msg)
|
||||
oa.SendForbiddenError(errors.New(msg))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Ping will handles the request to test connection to OIDC endpoint
|
||||
func (oa *OIDCAPI) Ping() {
|
||||
var c oidc.Conn
|
||||
if err := oa.DecodeJSONReq(&c); err != nil {
|
||||
log.Error("Failed to decode JSON request.")
|
||||
oa.SendBadRequestError(err)
|
||||
return
|
||||
}
|
||||
if err := oidc.TestEndpoint(c); err != nil {
|
||||
log.Errorf("Failed to verify connection: %+v, err: %v", c, err)
|
||||
oa.SendBadRequestError(err)
|
||||
return
|
||||
}
|
||||
}
|
69
src/core/api/oidc_test.go
Normal file
69
src/core/api/oidc_test.go
Normal file
@ -0,0 +1,69 @@
|
||||
// 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 api
|
||||
|
||||
import (
|
||||
"github.com/goharbor/harbor/src/common/utils/oidc"
|
||||
"net/http"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestOIDCAPI_Ping(t *testing.T) {
|
||||
url := "/api/system/oidc/ping"
|
||||
cases := []*codeCheckingCase{
|
||||
{ // 401
|
||||
request: &testingRequest{
|
||||
method: http.MethodPost,
|
||||
bodyJSON: oidc.Conn{},
|
||||
url: url,
|
||||
},
|
||||
code: http.StatusUnauthorized,
|
||||
},
|
||||
{ // 403
|
||||
request: &testingRequest{
|
||||
method: http.MethodPost,
|
||||
bodyJSON: oidc.Conn{},
|
||||
url: url,
|
||||
credential: nonSysAdmin,
|
||||
},
|
||||
code: http.StatusForbidden,
|
||||
},
|
||||
{ // 400
|
||||
request: &testingRequest{
|
||||
method: http.MethodPost,
|
||||
bodyJSON: oidc.Conn{
|
||||
URL: "https://www.baidu.com",
|
||||
VerifyCert: true,
|
||||
},
|
||||
url: url,
|
||||
credential: sysAdmin,
|
||||
},
|
||||
code: http.StatusBadRequest,
|
||||
},
|
||||
{ // 200
|
||||
request: &testingRequest{
|
||||
method: http.MethodPost,
|
||||
bodyJSON: oidc.Conn{
|
||||
URL: "https://accounts.google.com",
|
||||
VerifyCert: true,
|
||||
},
|
||||
url: url,
|
||||
credential: sysAdmin,
|
||||
},
|
||||
code: http.StatusOK,
|
||||
},
|
||||
}
|
||||
runCodeCheckingCases(t, cases...)
|
||||
}
|
@ -18,6 +18,8 @@ import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/goharbor/harbor/src/common"
|
||||
"github.com/goharbor/harbor/src/common/dao"
|
||||
@ -27,10 +29,7 @@ import (
|
||||
errutil "github.com/goharbor/harbor/src/common/utils/error"
|
||||
"github.com/goharbor/harbor/src/common/utils/log"
|
||||
"github.com/goharbor/harbor/src/core/config"
|
||||
|
||||
"errors"
|
||||
"strconv"
|
||||
"time"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type deletableResp struct {
|
||||
@ -232,7 +231,10 @@ func (p *ProjectAPI) Get() {
|
||||
return
|
||||
}
|
||||
|
||||
p.populateProperties(p.project)
|
||||
err := p.populateProperties(p.project)
|
||||
if err != nil {
|
||||
log.Errorf("populate project poroperties failed with : %+v", err)
|
||||
}
|
||||
|
||||
p.Data["json"] = p.project
|
||||
p.ServeJSON()
|
||||
@ -402,15 +404,17 @@ func (p *ProjectAPI) List() {
|
||||
}
|
||||
|
||||
for _, project := range result.Projects {
|
||||
p.populateProperties(project)
|
||||
err = p.populateProperties(project)
|
||||
if err != nil {
|
||||
log.Errorf("populate project properties failed %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
p.SetPaginationHeader(result.Total, page, size)
|
||||
p.Data["json"] = result.Projects
|
||||
p.ServeJSON()
|
||||
}
|
||||
|
||||
func (p *ProjectAPI) populateProperties(project *models.Project) {
|
||||
func (p *ProjectAPI) populateProperties(project *models.Project) error {
|
||||
if p.SecurityCtx.IsAuthenticated() {
|
||||
roles := p.SecurityCtx.GetProjectRoles(project.ProjectID)
|
||||
if len(roles) != 0 {
|
||||
@ -427,9 +431,8 @@ func (p *ProjectAPI) populateProperties(project *models.Project) {
|
||||
ProjectIDs: []int64{project.ProjectID},
|
||||
})
|
||||
if err != nil {
|
||||
log.Errorf("failed to get total of repositories of project %d: %v", project.ProjectID, err)
|
||||
p.SendInternalServerError(errors.New(""))
|
||||
return
|
||||
err = errors.Wrap(err, fmt.Sprintf("get repo count of project %d failed", project.ProjectID))
|
||||
return err
|
||||
}
|
||||
|
||||
project.RepoCount = total
|
||||
@ -438,13 +441,13 @@ func (p *ProjectAPI) populateProperties(project *models.Project) {
|
||||
if config.WithChartMuseum() {
|
||||
count, err := chartController.GetCountOfCharts([]string{project.Name})
|
||||
if err != nil {
|
||||
log.Errorf("Failed to get total of charts under project %s: %v", project.Name, err)
|
||||
p.SendInternalServerError(errors.New(""))
|
||||
return
|
||||
err = errors.Wrap(err, fmt.Sprintf("get chart count of project %d failed", project.ProjectID))
|
||||
return err
|
||||
}
|
||||
|
||||
project.ChartCount = count
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Put ...
|
||||
|
@ -17,6 +17,7 @@ package authproxy
|
||||
import (
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
@ -190,12 +191,14 @@ func (a *Auth) SearchGroup(groupKey string) (*models.UserGroup, error) {
|
||||
// OnBoardGroup create user group entity in Harbor DB, altGroupName is not used.
|
||||
func (a *Auth) OnBoardGroup(u *models.UserGroup, altGroupName string) error {
|
||||
// if group name provided, on board the user group
|
||||
userGroup := &models.UserGroup{GroupName: u.GroupName, GroupType: common.HTTPGroupType}
|
||||
err := group.OnBoardUserGroup(u, "GroupName", "GroupType")
|
||||
if len(u.GroupName) == 0 {
|
||||
return errors.New("Should provide a group name")
|
||||
}
|
||||
u.GroupType = common.HTTPGroupType
|
||||
err := group.OnBoardUserGroup(u)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
u.ID = userGroup.ID
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -43,6 +43,7 @@ func TestMain(m *testing.M) {
|
||||
}
|
||||
mockSvr = test.NewMockServer(map[string]string{"jt": "pp", "Admin@vsphere.local": "Admin!23"})
|
||||
defer mockSvr.Close()
|
||||
defer dao.ExecuteBatchSQL([]string{"delete from user_group where group_name='OnBoardTest'"})
|
||||
a = &Auth{
|
||||
Endpoint: mockSvr.URL + "/test/login",
|
||||
TokenReviewEndpoint: mockSvr.URL + "/test/tokenreview",
|
||||
@ -50,10 +51,17 @@ func TestMain(m *testing.M) {
|
||||
// So it won't require mocking the cfgManager
|
||||
settingTimeStamp: time.Now(),
|
||||
}
|
||||
cfgMap := cut.GetUnitTestConfig()
|
||||
conf := map[string]interface{}{
|
||||
common.HTTPAuthProxyEndpoint: a.Endpoint,
|
||||
common.HTTPAuthProxyTokenReviewEndpoint: a.TokenReviewEndpoint,
|
||||
common.HTTPAuthProxyVerifyCert: !a.SkipCertVerify,
|
||||
common.PostGreSQLSSLMode: cfgMap[common.PostGreSQLSSLMode],
|
||||
common.PostGreSQLUsername: cfgMap[common.PostGreSQLUsername],
|
||||
common.PostGreSQLPort: cfgMap[common.PostGreSQLPort],
|
||||
common.PostGreSQLHOST: cfgMap[common.PostGreSQLHOST],
|
||||
common.PostGreSQLPassword: cfgMap[common.PostGreSQLPassword],
|
||||
common.PostGreSQLDatabase: cfgMap[common.PostGreSQLDatabase],
|
||||
}
|
||||
|
||||
config.InitWithSettings(conf)
|
||||
@ -174,3 +182,19 @@ func TestAuth_PostAuthenticate(t *testing.T) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestAuth_OnBoardGroup(t *testing.T) {
|
||||
input := &models.UserGroup{
|
||||
GroupName: "OnBoardTest",
|
||||
GroupType: common.HTTPGroupType,
|
||||
}
|
||||
a.OnBoardGroup(input, "")
|
||||
|
||||
assert.True(t, input.ID > 0, "The OnBoardGroup should have a valid group ID")
|
||||
|
||||
emptyGroup := &models.UserGroup{}
|
||||
err := a.OnBoardGroup(emptyGroup, "")
|
||||
if err == nil {
|
||||
t.Fatal("Empty user group should failed to OnBoard")
|
||||
}
|
||||
}
|
||||
|
@ -214,7 +214,7 @@ func (l *Auth) OnBoardGroup(u *models.UserGroup, altGroupName string) error {
|
||||
if len(userGroupList) > 0 {
|
||||
return auth.ErrDuplicateLDAPGroup
|
||||
}
|
||||
return group.OnBoardUserGroup(u, "LdapGroupDN", "GroupType")
|
||||
return group.OnBoardUserGroup(u)
|
||||
}
|
||||
|
||||
// PostAuthenticate -- If user exist in harbor DB, sync email address, if not exist, call OnBoardUser
|
||||
|
@ -98,6 +98,7 @@ func initRouters() {
|
||||
beego.Router("/api/system/gc/schedule", &api.GCAPI{}, "get:Get;put:Put;post:Post")
|
||||
beego.Router("/api/system/scanAll/schedule", &api.ScanAllAPI{}, "get:Get;put:Put;post:Post")
|
||||
beego.Router("/api/system/CVEWhitelist", &api.SysCVEWhitelistAPI{}, "get:Get;put:Put")
|
||||
beego.Router("/api/system/oidc/ping", &api.OIDCAPI{}, "post:Ping")
|
||||
|
||||
beego.Router("/api/logs", &api.LogAPI{})
|
||||
|
||||
|
@ -21,18 +21,10 @@ import (
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"context"
|
||||
"github.com/goharbor/harbor/src/jobservice/common/utils"
|
||||
)
|
||||
|
||||
const (
|
||||
proxyEnvHTTP = "http_proxy"
|
||||
proxyEnvHTTPS = "https_proxy"
|
||||
)
|
||||
|
||||
// Client for handling the hook events
|
||||
@ -60,19 +52,7 @@ func NewClient(ctx context.Context) Client {
|
||||
TLSHandshakeTimeout: 10 * time.Second,
|
||||
ResponseHeaderTimeout: 10 * time.Second,
|
||||
ExpectContinueTimeout: 1 * time.Second,
|
||||
}
|
||||
|
||||
// Get the http/https proxies
|
||||
proxyAddr, ok := os.LookupEnv(proxyEnvHTTP)
|
||||
if !ok {
|
||||
proxyAddr, ok = os.LookupEnv(proxyEnvHTTPS)
|
||||
}
|
||||
|
||||
if ok && !utils.IsEmptyStr(proxyAddr) {
|
||||
proxyURL, err := url.Parse(proxyAddr)
|
||||
if err == nil {
|
||||
transport.Proxy = http.ProxyURL(proxyURL)
|
||||
}
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
}
|
||||
|
||||
client := &http.Client{
|
||||
|
@ -99,6 +99,7 @@
|
||||
class="btn btn-link">{{'CVE_WHITELIST.ADD'|translate}}</button>
|
||||
</div>
|
||||
<div class="add-modal" *ngIf="showAddModal">
|
||||
<clr-icon (click)="showAddModal=false" class="float-lg-right margin-top-4" shape="window-close"></clr-icon>
|
||||
<div>
|
||||
<clr-textarea-container>
|
||||
<label>{{'CVE_WHITELIST.ENTER'|translate}}</label>
|
||||
@ -115,7 +116,8 @@
|
||||
<ul class="whitelist-window">
|
||||
<li *ngIf="systemWhitelist?.items?.length<1"
|
||||
class="none">{{'CVE_WHITELIST.NONE'|translate}}</li>
|
||||
<li *ngFor="let item of systemWhitelist?.items;let i = index;">{{item.cve_id}}
|
||||
<li *ngFor="let item of systemWhitelist?.items;let i = index;">
|
||||
<span class="hand" (click)="goToDetail(item.cve_id)">{{item.cve_id}}</span>
|
||||
<clr-icon (click)="deleteItem(i)" class="float-lg-right margin-top-4"
|
||||
shape="times-circle"></clr-icon>
|
||||
</li>
|
||||
|
@ -31,6 +31,7 @@
|
||||
|
||||
li {
|
||||
height: 24px;
|
||||
line-height: 24px;
|
||||
list-style-type: none;
|
||||
}
|
||||
}
|
||||
@ -72,4 +73,8 @@
|
||||
button {
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
.hand{
|
||||
cursor: pointer;
|
||||
margin: 0;
|
||||
}
|
@ -28,6 +28,8 @@ const fakePass = 'aWpLOSYkIzJTTU4wMDkx';
|
||||
const ONE_HOUR_MINUTES: number = 60;
|
||||
const ONE_DAY_MINUTES: number = 24 * ONE_HOUR_MINUTES;
|
||||
const ONE_THOUSAND: number = 1000;
|
||||
const CVE_DETAIL_PRE_URL = `https://nvd.nist.gov/vuln/detail/`;
|
||||
const TARGET_BLANK = "_blank";
|
||||
|
||||
@Component({
|
||||
selector: 'system-settings',
|
||||
@ -380,4 +382,8 @@ export class SystemSettingsComponent implements OnChanges, OnInit {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
goToDetail(cveId) {
|
||||
window.open(CVE_DETAIL_PRE_URL + `${cveId}`, TARGET_BLANK);
|
||||
}
|
||||
}
|
||||
|
@ -11,17 +11,17 @@
|
||||
</clr-tooltip>
|
||||
<clr-dropdown *ngIf="isClairDBFullyReady && showScanningNamespaces" class="clr-dropdown-override">
|
||||
<button class="btn btn-link btn-font" clrDropdownToggle>
|
||||
{{ updatedTimestamp | date:'MM/dd/y HH:mm:ss' }} AM
|
||||
{{ updatedTimestamp | date:'short' }}
|
||||
<clr-icon shape="caret down"></clr-icon>
|
||||
</button>
|
||||
<clr-dropdown-menu [clrPosition]="'bottom-right'" class="dropdown-namespace">
|
||||
<div *ngFor="let nt of namespaceTimestamps" class="namespace">
|
||||
<span class="label label-info">{{nt.namespace}}</span>
|
||||
<span>{{ convertToLocalTime(nt.last_update) | date:'MM/dd/y HH:mm:ss'}} AM</span>
|
||||
<span>{{ convertToLocalTime(nt.last_update) | date:'short'}} </span>
|
||||
</div>
|
||||
</clr-dropdown-menu>
|
||||
</clr-dropdown>
|
||||
<span *ngIf="isClairDBFullyReady && !showScanningNamespaces">{{ updatedTimestamp | date:'MM/dd/y HH:mm:ss' }} AM</span>
|
||||
<span *ngIf="isClairDBFullyReady && !showScanningNamespaces">{{ updatedTimestamp | date:'short' }} </span>
|
||||
</div>
|
||||
<div class="button-group">
|
||||
<cron-selection #CronScheduleComponent [labelCurrent]="getLabelCurrent" [labelEdit]='getLabelCurrent' [originCron]='originCron' (inputvalue)="scanAll($event)"></cron-selection>
|
||||
|
@ -109,6 +109,7 @@
|
||||
class="btn btn-link ml-1">{{'CVE_WHITELIST.ADD_SYSTEM'|translate}}</button>
|
||||
</div>
|
||||
<div class="add-modal" *ngIf="showAddModal && !isUseSystemWhitelist()">
|
||||
<clr-icon (click)="showAddModal=false" class="float-lg-right margin-top-4" shape="window-close"></clr-icon>
|
||||
<div>
|
||||
<clr-textarea-container>
|
||||
<label>{{'CVE_WHITELIST.ENTER'|translate}}</label>
|
||||
@ -124,12 +125,15 @@
|
||||
<ul class="whitelist-window" *ngIf="isUseSystemWhitelist()">
|
||||
<li *ngIf="systemWhitelist?.items?.length<1"
|
||||
class="none">{{'CVE_WHITELIST.NONE'|translate}}</li>
|
||||
<li *ngFor="let item of systemWhitelist?.items">{{item.cve_id}}</li>
|
||||
<li *ngFor="let item of systemWhitelist?.items">
|
||||
<span class="hand" (click)="goToDetail(item.cve_id)">{{item.cve_id}}</span>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="whitelist-window" *ngIf="!isUseSystemWhitelist()">
|
||||
<li class="none"
|
||||
*ngIf="projectWhitelist?.items?.length<1">{{'CVE_WHITELIST.NONE'|translate}}</li>
|
||||
<li *ngFor="let item of projectWhitelist?.items;let i = index;">{{item.cve_id}}
|
||||
<li *ngFor="let item of projectWhitelist?.items;let i = index;">
|
||||
<span class="hand" (click)="goToDetail(item.cve_id)">{{item.cve_id}}</span>
|
||||
<clr-icon (click)="deleteItem(i)" class="float-lg-right margin-top-4"
|
||||
shape="times-circle"></clr-icon>
|
||||
</li>
|
||||
|
@ -5,6 +5,9 @@
|
||||
.select {
|
||||
width: 120px;
|
||||
}
|
||||
.margin-top-4 {
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.whitelist-window {
|
||||
border: 1px solid #ccc;
|
||||
@ -18,6 +21,7 @@
|
||||
|
||||
li {
|
||||
height: 24px;
|
||||
line-height: 24px;
|
||||
list-style-type: none;
|
||||
}
|
||||
}
|
||||
@ -61,3 +65,8 @@
|
||||
}
|
||||
}
|
||||
|
||||
.hand{
|
||||
cursor: pointer;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,8 @@ import {USERSTATICPERMISSION} from '../service/permission-static';
|
||||
|
||||
const ONE_THOUSAND: number = 1000;
|
||||
const LOW: string = 'low';
|
||||
const CVE_DETAIL_PRE_URL = `https://nvd.nist.gov/vuln/detail/`;
|
||||
const TARGET_BLANK = "_blank";
|
||||
|
||||
export class ProjectPolicy {
|
||||
Public: boolean;
|
||||
@ -367,4 +369,7 @@ export class ProjectPolicyConfigComponent implements OnInit {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
goToDetail(cveId) {
|
||||
window.open(CVE_DETAIL_PRE_URL + `${cveId}`, TARGET_BLANK);
|
||||
}
|
||||
}
|
||||
|
@ -44,42 +44,46 @@
|
||||
{{'ROBOT_ACCOUNT.PERMISSIONS' | translate}}
|
||||
</label>
|
||||
</div>
|
||||
<div class="clr-col">
|
||||
<div class="form-group padding-left-120">
|
||||
<label>{{'ROBOT_ACCOUNT.PERMISSIONS_IMAGE' | translate}}</label>
|
||||
<div class="radio-inline">
|
||||
<input type="radio" name="image-permission"
|
||||
id="image-permission-pull"
|
||||
value="pull"
|
||||
[(ngModel)]="imagePermission">
|
||||
<label for="image-permission-pull">{{'ROBOT_ACCOUNT.PULL' | translate}}</label>
|
||||
</div>
|
||||
<div class="radio-inline">
|
||||
<input type="radio" name="image-permission"
|
||||
id="image-permission-push-and-pull"
|
||||
value="push-and-pull"
|
||||
[(ngModel)]="imagePermission">
|
||||
<label for="image-permission-push-and-pull">{{'ROBOT_ACCOUNT.PUSH' | translate}}
|
||||
& {{'ROBOT_ACCOUNT.PULL' | translate}}</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group padding-left-120">
|
||||
<label>{{'ROBOT_ACCOUNT.PERMISSIONS_HELMCHART' | translate}}</label>
|
||||
<div class="checkbox-inline">
|
||||
<input type="checkbox" id="helm-permission-push"
|
||||
[checked]="robot.access.isPushChart"
|
||||
[(ngModel)]="robot.access.isPushChart"
|
||||
name="helm-permission">
|
||||
<label for="helm-permission-push">{{'ROBOT_ACCOUNT.PUSH' | translate}}</label>
|
||||
</div>
|
||||
<div class="checkbox-inline">
|
||||
<input type="checkbox" id="helm-permission-pull"
|
||||
[checked]="robot.access.isPullChart"
|
||||
[(ngModel)]="robot.access.isPullChart"
|
||||
name="helm-permission">
|
||||
<label for="helm-permission-pull">{{'ROBOT_ACCOUNT.PULL' | translate}}</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="clr-col p-0">
|
||||
<table class="table table-noborder m-0 w-90">
|
||||
<tr>
|
||||
<th></th>
|
||||
<th class="left">{{'ROBOT_ACCOUNT.PUSH' | translate}}</th>
|
||||
<th class="left">{{'ROBOT_ACCOUNT.PULL' | translate}}</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="left">
|
||||
<span>{{'ROBOT_ACCOUNT.PERMISSIONS_IMAGE' | translate}}</span>
|
||||
<clr-tooltip>
|
||||
<clr-icon clrTooltipTrigger shape="info-circle" size="24"></clr-icon>
|
||||
<clr-tooltip-content clrPosition="top-right" clrSize="lg" *clrIfOpen>
|
||||
<span>{{'ROBOT_ACCOUNT.PULL_IS_MUST' | translate}}</span>
|
||||
</clr-tooltip-content>
|
||||
</clr-tooltip>
|
||||
</td>
|
||||
<td>
|
||||
<input type="checkbox" name="image-permission-push"
|
||||
[(ngModel)]="imagePermissionPush" clrCheckbox>
|
||||
</td>
|
||||
<td class="clr-form-control-disabled">
|
||||
<input disabled type="checkbox" name="image-permission-pull"
|
||||
[(ngModel)]="imagePermissionPull" clrCheckbox>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="left">{{'ROBOT_ACCOUNT.PERMISSIONS_HELMCHART' | translate}}</td>
|
||||
<td>
|
||||
<input type="checkbox"
|
||||
[(ngModel)]="robot.access.isPushChart"
|
||||
name="helm-permission" clrCheckbox>
|
||||
</td>
|
||||
<td>
|
||||
<input type="checkbox"
|
||||
[(ngModel)]="robot.access.isPullChart"
|
||||
name="helm-permission" clrCheckbox>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
@ -42,5 +42,8 @@
|
||||
}
|
||||
|
||||
.padding-left-120{
|
||||
padding-left: 120px;
|
||||
padding-left: 126px;
|
||||
}
|
||||
.w-90{
|
||||
width: 90%;
|
||||
}
|
@ -38,7 +38,8 @@ export class AddRobotComponent implements OnInit, OnDestroy {
|
||||
robotNameChecker: Subject<string> = new Subject<string>();
|
||||
nameTooltipText = "ROBOT_ACCOUNT.ROBOT_NAME";
|
||||
robotForm: NgForm;
|
||||
imagePermission: string = "push-and-pull";
|
||||
imagePermissionPush: boolean = true;
|
||||
imagePermissionPull: boolean = true;
|
||||
@Input() projectId: number;
|
||||
@Input() projectName: string;
|
||||
@Output() create = new EventEmitter<boolean>();
|
||||
@ -99,6 +100,8 @@ export class AddRobotComponent implements OnInit, OnDestroy {
|
||||
this.robot.name = "";
|
||||
this.robot.description = "";
|
||||
this.addRobotOpened = true;
|
||||
this.imagePermissionPush = true;
|
||||
this.imagePermissionPull = true;
|
||||
this.isRobotNameValid = true;
|
||||
this.robot = new Robot();
|
||||
this.nameTooltipText = "ROBOT_ACCOUNT.ROBOT_NAME";
|
||||
@ -118,12 +121,12 @@ export class AddRobotComponent implements OnInit, OnDestroy {
|
||||
return;
|
||||
}
|
||||
// set value to robot.access.isPullImage and robot.access.isPushOrPullImage when submit
|
||||
if ( this.imagePermission === 'pull' ) {
|
||||
this.robot.access.isPullImage = true;
|
||||
this.robot.access.isPushOrPullImage = false;
|
||||
} else {
|
||||
if ( this.imagePermissionPush && this.imagePermissionPull) {
|
||||
this.robot.access.isPullImage = false;
|
||||
this.robot.access.isPushOrPullImage = true;
|
||||
} else {
|
||||
this.robot.access.isPullImage = true;
|
||||
this.robot.access.isPushOrPullImage = false;
|
||||
}
|
||||
this.isSubmitOnGoing = true;
|
||||
this.robotService
|
||||
|
@ -322,7 +322,8 @@
|
||||
"CREATED_SUCCESS": "Created '{{param}}' successfully.",
|
||||
"COPY_SUCCESS": "Copy token successfully of '{{param}}'",
|
||||
"DELETION_TITLE": "Confirm removal of robot accounts",
|
||||
"DELETION_SUMMARY": "Do you want to delete robot accounts {{param}}?"
|
||||
"DELETION_SUMMARY": "Do you want to delete robot accounts {{param}}?",
|
||||
"PULL_IS_MUST" : "Pull permission is checked by default and can not be modified."
|
||||
},
|
||||
"GROUP": {
|
||||
"GROUP": "Group",
|
||||
|
@ -323,7 +323,8 @@
|
||||
"CREATED_SUCCESS": "Created '{{param}}' successfully.",
|
||||
"COPY_SUCCESS": "Copy token successfully of '{{param}}'",
|
||||
"DELETION_TITLE": "Confirm removal of robot accounts",
|
||||
"DELETION_SUMMARY": "Do you want to delete robot accounts {{param}}?"
|
||||
"DELETION_SUMMARY": "Do you want to delete robot accounts {{param}}?",
|
||||
"PULL_IS_MUST" : "Pull permission is checked by default and can not be modified."
|
||||
},
|
||||
"GROUP": {
|
||||
"GROUP": "Group",
|
||||
|
@ -315,7 +315,8 @@
|
||||
"CREATED_SUCCESS": "Created '{{param}}' successfully.",
|
||||
"COPY_SUCCESS": "Copy token successfully of '{{param}}'",
|
||||
"DELETION_TITLE": "confirmer l'enlèvement des comptes du robot ",
|
||||
"DELETION_SUMMARY": "Voulez-vous supprimer la règle {{param}}?"
|
||||
"DELETION_SUMMARY": "Voulez-vous supprimer la règle {{param}}?",
|
||||
"PULL_IS_MUST" : "Pull permission is checked by default and can not be modified."
|
||||
},
|
||||
"GROUP": {
|
||||
"Group": "Group",
|
||||
|
@ -320,7 +320,8 @@
|
||||
"CREATED_SUCCESS": "Created '{{param}}' successfully.",
|
||||
"COPY_SUCCESS": "Copy token successfully of '{{param}}'",
|
||||
"DELETION_TITLE": "Confirmar a remoção do robô Contas",
|
||||
"DELETION_SUMMARY": "Você quer remover a regra {{param}}?"
|
||||
"DELETION_SUMMARY": "Você quer remover a regra {{param}}?",
|
||||
"PULL_IS_MUST" : "Pull permission is checked by default and can not be modified."
|
||||
},
|
||||
"GROUP": {
|
||||
"GROUP": "Grupo",
|
||||
|
@ -321,7 +321,8 @@
|
||||
"CREATED_SUCCESS": "创建账户 '{{param}}' 成功。",
|
||||
"COPY_SUCCESS": "成功复制 '{{param}}' 的令牌",
|
||||
"DELETION_TITLE": "删除账户确认",
|
||||
"DELETION_SUMMARY": "你确认删除机器人账户 {{param}}?"
|
||||
"DELETION_SUMMARY": "你确认删除机器人账户 {{param}}?",
|
||||
"PULL_IS_MUST" : "拉取权限默认选中且不可修改。"
|
||||
},
|
||||
"GROUP": {
|
||||
"GROUP": "组",
|
||||
|
@ -1,8 +1,6 @@
|
||||
package huawei
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
@ -10,7 +8,10 @@ import (
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
common_http "github.com/goharbor/harbor/src/common/http"
|
||||
"github.com/goharbor/harbor/src/common/http/modifier"
|
||||
"github.com/goharbor/harbor/src/common/utils/log"
|
||||
"github.com/goharbor/harbor/src/common/utils/registry/auth"
|
||||
adp "github.com/goharbor/harbor/src/replication/adapter"
|
||||
"github.com/goharbor/harbor/src/replication/adapter/native"
|
||||
"github.com/goharbor/harbor/src/replication/model"
|
||||
@ -30,6 +31,7 @@ func init() {
|
||||
type adapter struct {
|
||||
*native.Adapter
|
||||
registry *model.Registry
|
||||
client *common_http.Client
|
||||
}
|
||||
|
||||
// Info gets info about Huawei SWR
|
||||
@ -56,18 +58,8 @@ func (a *adapter) ListNamespaces(query *model.NamespaceQuery) ([]*model.Namespac
|
||||
}
|
||||
|
||||
r.Header.Add("content-type", "application/json; charset=utf-8")
|
||||
encodeAuth := base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", a.registry.Credential.AccessKey, a.registry.Credential.AccessSecret)))
|
||||
r.Header.Add("Authorization", "Basic "+encodeAuth)
|
||||
|
||||
client := &http.Client{}
|
||||
if a.registry.Insecure == true {
|
||||
client = &http.Client{
|
||||
Transport: &http.Transport{
|
||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
||||
},
|
||||
}
|
||||
}
|
||||
resp, err := client.Do(r)
|
||||
resp, err := a.client.Do(r)
|
||||
if err != nil {
|
||||
return namespaces, err
|
||||
}
|
||||
@ -120,8 +112,11 @@ func (a *adapter) ConvertResourceMetadata(resourceMetadata *model.ResourceMetada
|
||||
func (a *adapter) PrepareForPush(resources []*model.Resource) error {
|
||||
namespaces := map[string]struct{}{}
|
||||
for _, resource := range resources {
|
||||
var namespace string
|
||||
paths := strings.Split(resource.Metadata.Repository.Name, "/")
|
||||
namespace := paths[0]
|
||||
if len(paths) > 0 {
|
||||
namespace = paths[0]
|
||||
}
|
||||
ns, err := a.GetNamespace(namespace)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -133,9 +128,7 @@ func (a *adapter) PrepareForPush(resources []*model.Resource) error {
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/dockyard/v2/namespaces", a.registry.URL)
|
||||
client := &http.Client{
|
||||
Transport: util.GetHTTPTransport(a.registry.Insecure),
|
||||
}
|
||||
|
||||
for namespace := range namespaces {
|
||||
namespacebyte, err := json.Marshal(struct {
|
||||
Namespace string `json:"namespace"`
|
||||
@ -152,10 +145,8 @@ func (a *adapter) PrepareForPush(resources []*model.Resource) error {
|
||||
}
|
||||
|
||||
r.Header.Add("content-type", "application/json; charset=utf-8")
|
||||
encodeAuth := base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", a.registry.Credential.AccessKey, a.registry.Credential.AccessSecret)))
|
||||
r.Header.Add("Authorization", "Basic "+encodeAuth)
|
||||
|
||||
resp, err := client.Do(r)
|
||||
resp, err := a.client.Do(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -185,20 +176,8 @@ func (a *adapter) GetNamespace(namespaceStr string) (*model.Namespace, error) {
|
||||
}
|
||||
|
||||
r.Header.Add("content-type", "application/json; charset=utf-8")
|
||||
encodeAuth := base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", a.registry.Credential.AccessKey, a.registry.Credential.AccessSecret)))
|
||||
r.Header.Add("Authorization", "Basic "+encodeAuth)
|
||||
|
||||
var client *http.Client
|
||||
if a.registry.Insecure == true {
|
||||
client = &http.Client{
|
||||
Transport: &http.Transport{
|
||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
||||
},
|
||||
}
|
||||
} else {
|
||||
client = &http.Client{}
|
||||
}
|
||||
resp, err := client.Do(r)
|
||||
resp, err := a.client.Do(r)
|
||||
if err != nil {
|
||||
return namespace, err
|
||||
}
|
||||
@ -237,9 +216,30 @@ func AdapterFactory(registry *model.Registry) (adp.Adapter, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var (
|
||||
modifiers = []modifier.Modifier{
|
||||
&auth.UserAgentModifier{
|
||||
UserAgent: adp.UserAgentReplication,
|
||||
}}
|
||||
authorizer modifier.Modifier
|
||||
)
|
||||
if registry.Credential != nil {
|
||||
authorizer = auth.NewBasicAuthCredential(
|
||||
registry.Credential.AccessKey,
|
||||
registry.Credential.AccessSecret)
|
||||
modifiers = append(modifiers, authorizer)
|
||||
}
|
||||
|
||||
return &adapter{
|
||||
registry: registry,
|
||||
Adapter: dockerRegistryAdapter,
|
||||
registry: registry,
|
||||
client: common_http.NewClient(
|
||||
&http.Client{
|
||||
Transport: util.GetHTTPTransport(registry.Insecure),
|
||||
},
|
||||
modifiers...,
|
||||
),
|
||||
}, nil
|
||||
|
||||
}
|
||||
|
@ -1,8 +1,6 @@
|
||||
package huawei
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
@ -25,18 +23,8 @@ func (a *adapter) FetchImages(filters []*model.Filter) ([]*model.Resource, error
|
||||
}
|
||||
|
||||
r.Header.Add("content-type", "application/json; charset=utf-8")
|
||||
encodeAuth := base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", a.registry.Credential.AccessKey, a.registry.Credential.AccessSecret)))
|
||||
r.Header.Add("Authorization", "Basic "+encodeAuth)
|
||||
|
||||
client := &http.Client{}
|
||||
if a.registry.Insecure == true {
|
||||
client = &http.Client{
|
||||
Transport: &http.Transport{
|
||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
||||
},
|
||||
}
|
||||
}
|
||||
resp, err := client.Do(r)
|
||||
resp, err := a.client.Do(r)
|
||||
if err != nil {
|
||||
return resources, err
|
||||
}
|
||||
@ -82,15 +70,7 @@ func (a *adapter) ManifestExist(repository, reference string) (exist bool, diges
|
||||
r.Header.Add("content-type", "application/json; charset=utf-8")
|
||||
r.Header.Add("Authorization", "Bearer "+token.Token)
|
||||
|
||||
client := &http.Client{}
|
||||
if a.registry.Insecure == true {
|
||||
client = &http.Client{
|
||||
Transport: &http.Transport{
|
||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
||||
},
|
||||
}
|
||||
}
|
||||
resp, err := client.Do(r)
|
||||
resp, err := a.client.Do(r)
|
||||
if err != nil {
|
||||
return exist, digest, err
|
||||
}
|
||||
@ -133,15 +113,7 @@ func (a *adapter) DeleteManifest(repository, reference string) error {
|
||||
r.Header.Add("content-type", "application/json; charset=utf-8")
|
||||
r.Header.Add("Authorization", "Bearer "+token.Token)
|
||||
|
||||
client := &http.Client{}
|
||||
if a.registry.Insecure == true {
|
||||
client = &http.Client{
|
||||
Transport: &http.Transport{
|
||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
||||
},
|
||||
}
|
||||
}
|
||||
resp, err := client.Do(r)
|
||||
resp, err := a.client.Do(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -220,18 +192,8 @@ func getJwtToken(a *adapter, repository string) (token jwtToken, err error) {
|
||||
}
|
||||
|
||||
r.Header.Add("content-type", "application/json; charset=utf-8")
|
||||
encodeAuth := base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", a.registry.Credential.AccessKey, a.registry.Credential.AccessSecret)))
|
||||
r.Header.Add("Authorization", "Basic "+encodeAuth)
|
||||
|
||||
client := &http.Client{}
|
||||
if a.registry.Insecure == true {
|
||||
client = &http.Client{
|
||||
Transport: &http.Transport{
|
||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
||||
},
|
||||
}
|
||||
}
|
||||
resp, err := client.Do(r)
|
||||
resp, err := a.client.Do(r)
|
||||
if err != nil {
|
||||
return token, err
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package huawei
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
@ -20,7 +21,11 @@ func init() {
|
||||
Insecure: false,
|
||||
Status: "",
|
||||
}
|
||||
HWAdapter.registry = hwRegistry
|
||||
adp, err := AdapterFactory(hwRegistry)
|
||||
if err != nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
HWAdapter = *adp.(*adapter)
|
||||
}
|
||||
|
||||
func TestAdapter_FetchImages(t *testing.T) {
|
||||
|
@ -25,6 +25,7 @@ sleep 2
|
||||
sudo -E env "PATH=$PATH" make go_check
|
||||
sudo ./tests/hostcfg.sh
|
||||
sudo ./tests/generateCerts.sh
|
||||
sudo make -f make/photon/Makefile _build_db _build_registry _build_prepare -e VERSIONTAG=dev -e CLAIRDBVERSION=dev -e REGISTRYVERSION=${REG_VERSION}
|
||||
sudo MAKEPATH=$(pwd)/make ./make/prepare
|
||||
sudo mkdir -p "/data/redis"
|
||||
sudo mkdir -p /etc/core/ca/ && sudo mv ./tests/ca.crt /etc/core/ca/
|
||||
@ -32,7 +33,6 @@ sudo mkdir -p /harbor && sudo mv ./VERSION /harbor/UIVERSION
|
||||
sudo ./tests/testprepare.sh
|
||||
|
||||
cd tests && sudo ./ldapprepare.sh && sudo ./admiral.sh && cd ..
|
||||
sudo make -f make/photon/Makefile _build_db _build_registry -e VERSIONTAG=dev -e CLAIRDBVERSION=dev -e REGISTRYVERSION=${REG_VERSION}
|
||||
sudo sed -i 's/__reg_version__/${REG_VERSION}-dev/g' ./make/docker-compose.test.yml
|
||||
sudo sed -i 's/__version__/dev/g' ./make/docker-compose.test.yml
|
||||
sudo mkdir -p ./make/common/config/registry/ && sudo mv ./tests/reg_config.yml ./make/common/config/registry/config.yml
|
Loading…
Reference in New Issue
Block a user