mirror of
https://github.com/goharbor/harbor.git
synced 2024-11-26 04:05:40 +01:00
Merge pull request #14413 from stonezdj/21mar05_config_refact
Change configurations api to new programming model
This commit is contained in:
commit
017132611e
@ -1008,46 +1008,6 @@ paths:
|
||||
description: Only admin has this authority.
|
||||
'500':
|
||||
description: Unexpected internal errors.
|
||||
/configurations:
|
||||
get:
|
||||
summary: Get system configurations.
|
||||
description: |
|
||||
This endpoint is for retrieving system configurations that only provides for admin user.
|
||||
tags:
|
||||
- Products
|
||||
responses:
|
||||
'200':
|
||||
description: Get system configurations successfully. The response body is a map.
|
||||
schema:
|
||||
$ref: '#/definitions/ConfigurationsResponse'
|
||||
'401':
|
||||
description: User need to log in first.ß
|
||||
'403':
|
||||
description: User does not have permission of admin role.
|
||||
'500':
|
||||
description: Unexpected internal errors.
|
||||
put:
|
||||
summary: Modify system configurations.
|
||||
description: |
|
||||
This endpoint is for modifying system configurations that only provides for admin user.
|
||||
tags:
|
||||
- Products
|
||||
parameters:
|
||||
- name: configurations
|
||||
in: body
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/Configurations'
|
||||
description: 'The configuration map can contain a subset of the attributes of the schema, which are to be updated.'
|
||||
responses:
|
||||
'200':
|
||||
description: Modify system configurations successfully.
|
||||
'401':
|
||||
description: User need to log in first.
|
||||
'403':
|
||||
description: User does not have permission of admin role.
|
||||
'500':
|
||||
description: Unexpected internal errors.
|
||||
/email/ping:
|
||||
post:
|
||||
summary: Test connection and authentication with email server.
|
||||
|
@ -163,6 +163,69 @@ paths:
|
||||
$ref: '#/responses/403'
|
||||
'500':
|
||||
$ref: '#/responses/500'
|
||||
/internalconfig:
|
||||
get:
|
||||
summary: Get internal configurations.
|
||||
description: |
|
||||
This endpoint is for retrieving system configurations that only provides for internal api call.
|
||||
tags:
|
||||
- configure
|
||||
parameters:
|
||||
- $ref: '#/parameters/requestId'
|
||||
responses:
|
||||
'200':
|
||||
description: Get system configurations successfully. The response body is a map.
|
||||
schema:
|
||||
$ref: '#/definitions/InternalConfigurationsResponse'
|
||||
'401':
|
||||
description: User need to log in first.
|
||||
'403':
|
||||
description: User does not have permission of admin role.
|
||||
'500':
|
||||
description: Unexpected internal errors.
|
||||
/configurations:
|
||||
get:
|
||||
summary: Get system configurations.
|
||||
description: |
|
||||
This endpoint is for retrieving system configurations that only provides for admin user.
|
||||
tags:
|
||||
- configure
|
||||
parameters:
|
||||
- $ref: '#/parameters/requestId'
|
||||
responses:
|
||||
'200':
|
||||
description: Get system configurations successfully. The response body is a map.
|
||||
schema:
|
||||
$ref: '#/definitions/ConfigurationsResponse'
|
||||
'401':
|
||||
description: User need to log in first.ß
|
||||
'403':
|
||||
description: User does not have permission of admin role.
|
||||
'500':
|
||||
description: Unexpected internal errors.
|
||||
put:
|
||||
summary: Modify system configurations.
|
||||
description: |
|
||||
This endpoint is for modifying system configurations that only provides for admin user.
|
||||
tags:
|
||||
- configure
|
||||
parameters:
|
||||
- $ref: '#/parameters/requestId'
|
||||
- name: configurations
|
||||
in: body
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/Configurations'
|
||||
description: 'The configuration map can contain a subset of the attributes of the schema, which are to be updated.'
|
||||
responses:
|
||||
'200':
|
||||
description: Modify system configurations successfully.
|
||||
'401':
|
||||
description: User need to log in first.
|
||||
'403':
|
||||
description: User does not have permission of admin role.
|
||||
'500':
|
||||
description: Unexpected internal errors.
|
||||
/projects:
|
||||
get:
|
||||
summary: List projects
|
||||
@ -6635,3 +6698,212 @@ definitions:
|
||||
type: string
|
||||
description: The webhook job update time.
|
||||
format: date-time
|
||||
InternalConfigurationsResponse:
|
||||
type: object
|
||||
x-go-type:
|
||||
type: InternalCfg
|
||||
import:
|
||||
package: "github.com/goharbor/harbor/src/lib/config"
|
||||
ConfigurationsResponse:
|
||||
type: object
|
||||
properties:
|
||||
auth_mode:
|
||||
$ref: '#/definitions/StringConfigItem'
|
||||
description: The auth mode of current system, such as "db_auth", "ldap_auth", "oidc_auth"
|
||||
email_from:
|
||||
$ref: '#/definitions/StringConfigItem'
|
||||
description: The sender name for Email notification.
|
||||
email_host:
|
||||
$ref: '#/definitions/StringConfigItem'
|
||||
description: The hostname of SMTP server that sends Email notification.
|
||||
email_identity:
|
||||
$ref: '#/definitions/StringConfigItem'
|
||||
description: By default it's empty so the email_username is picked
|
||||
email_insecure:
|
||||
$ref: '#/definitions/BoolConfigItem'
|
||||
description: Whether or not the certificate will be verified when Harbor tries to access the email server.
|
||||
email_port:
|
||||
$ref: '#/definitions/IntegerConfigItem'
|
||||
description: The port of SMTP server
|
||||
email_ssl:
|
||||
$ref: '#/definitions/BoolConfigItem'
|
||||
description: When it''s set to true the system will access Email server via TLS by default. If it''s set to false, it still will handle "STARTTLS" from server side.
|
||||
email_username:
|
||||
$ref: '#/definitions/StringConfigItem'
|
||||
description: The username for authenticate against SMTP server
|
||||
ldap_base_dn:
|
||||
$ref: '#/definitions/StringConfigItem'
|
||||
description: The Base DN for LDAP binding.
|
||||
ldap_filter:
|
||||
$ref: '#/definitions/StringConfigItem'
|
||||
description: The filter for LDAP search
|
||||
ldap_group_base_dn:
|
||||
$ref: '#/definitions/StringConfigItem'
|
||||
description: The base DN to search LDAP group.
|
||||
ldap_group_admin_dn:
|
||||
$ref: '#/definitions/StringConfigItem'
|
||||
description: Specify the ldap group which have the same privilege with Harbor admin
|
||||
ldap_group_attribute_name:
|
||||
$ref: '#/definitions/StringConfigItem'
|
||||
description: The attribute which is used as identity of the LDAP group, default is cn.'
|
||||
ldap_group_search_filter:
|
||||
$ref: '#/definitions/StringConfigItem'
|
||||
description: The filter to search the ldap group
|
||||
ldap_group_search_scope:
|
||||
$ref: '#/definitions/IntegerConfigItem'
|
||||
description: The scope to search ldap group. ''0-LDAP_SCOPE_BASE, 1-LDAP_SCOPE_ONELEVEL, 2-LDAP_SCOPE_SUBTREE''
|
||||
ldap_scope:
|
||||
$ref: '#/definitions/IntegerConfigItem'
|
||||
description: The scope to search ldap users,'0-LDAP_SCOPE_BASE, 1-LDAP_SCOPE_ONELEVEL, 2-LDAP_SCOPE_SUBTREE'
|
||||
ldap_search_dn:
|
||||
$ref: '#/definitions/StringConfigItem'
|
||||
description: The DN of the user to do the search.
|
||||
ldap_timeout:
|
||||
$ref: '#/definitions/IntegerConfigItem'
|
||||
description: Timeout in seconds for connection to LDAP server
|
||||
ldap_uid:
|
||||
$ref: '#/definitions/StringConfigItem'
|
||||
description: The attribute which is used as identity for the LDAP binding, such as "CN" or "SAMAccountname"
|
||||
ldap_url:
|
||||
$ref: '#/definitions/StringConfigItem'
|
||||
description: The URL of LDAP server
|
||||
ldap_verify_cert:
|
||||
$ref: '#/definitions/BoolConfigItem'
|
||||
description: Whether verify your OIDC server certificate, disable it if your OIDC server is hosted via self-hosted certificate.
|
||||
ldap_group_membership_attribute:
|
||||
$ref: '#/definitions/StringConfigItem'
|
||||
description: The user attribute to identify the group membership
|
||||
project_creation_restriction:
|
||||
$ref: '#/definitions/StringConfigItem'
|
||||
description: Indicate who can create projects, it could be ''adminonly'' or ''everyone''.
|
||||
read_only:
|
||||
$ref: '#/definitions/BoolConfigItem'
|
||||
description: The flag to indicate whether Harbor is in readonly mode.
|
||||
self_registration:
|
||||
$ref: '#/definitions/BoolConfigItem'
|
||||
description: Whether the Harbor instance supports self-registration. If it''s set to false, admin need to add user to the instance.
|
||||
token_expiration:
|
||||
$ref: '#/definitions/IntegerConfigItem'
|
||||
description: The expiration time of the token for internal Registry, in minutes.
|
||||
uaa_client_id:
|
||||
$ref: '#/definitions/StringConfigItem'
|
||||
description: The client id of UAA
|
||||
uaa_client_secret:
|
||||
$ref: '#/definitions/StringConfigItem'
|
||||
description: The client secret of the UAA
|
||||
uaa_endpoint:
|
||||
$ref: '#/definitions/StringConfigItem'
|
||||
description: The endpoint of the UAA
|
||||
uaa_verify_cert:
|
||||
$ref: '#/definitions/BoolConfigItem'
|
||||
description: Verify the certificate in UAA server
|
||||
http_authproxy_endpoint:
|
||||
$ref: '#/definitions/StringConfigItem'
|
||||
description: The endpoint of the HTTP auth
|
||||
http_authproxy_tokenreview_endpoint:
|
||||
$ref: '#/definitions/StringConfigItem'
|
||||
description: The token review endpoint
|
||||
http_authproxy_admin_groups:
|
||||
$ref: '#/definitions/StringConfigItem'
|
||||
description: The group which has the harbor admin privileges
|
||||
http_authproxy_admin_usernames:
|
||||
$ref: '#/definitions/StringConfigItem'
|
||||
description: The usernames which has the harbor admin privileges
|
||||
http_authproxy_verify_cert:
|
||||
$ref: '#/definitions/BoolConfigItem'
|
||||
description: Verify the HTTP auth provider's certificate
|
||||
http_authproxy_skip_search:
|
||||
$ref: '#/definitions/BoolConfigItem'
|
||||
description: Search user before onboard
|
||||
http_authproxy_server_certificate:
|
||||
$ref: '#/definitions/StringConfigItem'
|
||||
description: The certificate of the HTTP auth provider
|
||||
oidc_name:
|
||||
$ref: '#/definitions/StringConfigItem'
|
||||
description: The OIDC provider name
|
||||
oidc_endpoint:
|
||||
$ref: '#/definitions/StringConfigItem'
|
||||
description: The endpoint of the OIDC provider
|
||||
oidc_client_id:
|
||||
$ref: '#/definitions/StringConfigItem'
|
||||
description: The client ID of the OIDC provider
|
||||
oidc_groups_claim:
|
||||
$ref: '#/definitions/StringConfigItem'
|
||||
description: The attribute claims the group name
|
||||
oidc_admin_group:
|
||||
$ref: '#/definitions/StringConfigItem'
|
||||
description: The OIDC group which has the harbor admin privileges
|
||||
oidc_scope:
|
||||
$ref: '#/definitions/StringConfigItem'
|
||||
description: The scope of the OIDC provider
|
||||
oidc_user_claim:
|
||||
$ref: '#/definitions/StringConfigItem'
|
||||
description: The attribute claims the username
|
||||
oidc_verify_cert:
|
||||
$ref: '#/definitions/BoolConfigItem'
|
||||
description: Verify the OIDC provider's certificate'
|
||||
oidc_auto_onboard:
|
||||
$ref: '#/definitions/BoolConfigItem'
|
||||
description: Auto onboard the OIDC user
|
||||
oidc_extra_redirect_parms:
|
||||
$ref: '#/definitions/StringConfigItem'
|
||||
description: Extra parameters to add when redirect request to OIDC provider
|
||||
robot_token_duration:
|
||||
$ref: '#/definitions/IntegerConfigItem'
|
||||
description: The robot account token duration in days
|
||||
robot_name_prefix:
|
||||
$ref: '#/definitions/StringConfigItem'
|
||||
description: The rebot account name prefix
|
||||
notification_enable:
|
||||
$ref: '#/definitions/BoolConfigItem'
|
||||
description: Enable notification
|
||||
quota_per_project_enable:
|
||||
$ref: '#/definitions/BoolConfigItem'
|
||||
description: Enable quota per project
|
||||
storage_per_project:
|
||||
$ref: '#/definitions/IntegerConfigItem'
|
||||
description: The storage quota per project
|
||||
scan_all_policy:
|
||||
type: object
|
||||
properties:
|
||||
type:
|
||||
type: string
|
||||
description: 'The type of scan all policy, currently the valid values are "none" and "daily"'
|
||||
parameter:
|
||||
type: object
|
||||
properties:
|
||||
daily_time:
|
||||
type: integer
|
||||
description: 'The offset in seconds of UTC 0 o''clock, only valid when the policy type is "daily"'
|
||||
description: 'The parameters of the policy, the values are dependant on the type of the policy.'
|
||||
Configurations:
|
||||
type: object
|
||||
additionalProperties:
|
||||
type: object
|
||||
StringConfigItem:
|
||||
type: object
|
||||
properties:
|
||||
value:
|
||||
type: string
|
||||
description: The string value of current config item
|
||||
editable:
|
||||
type: boolean
|
||||
description: The configure item can be updated or not
|
||||
BoolConfigItem:
|
||||
type: object
|
||||
properties:
|
||||
value:
|
||||
type: boolean
|
||||
description: The boolean value of current config item
|
||||
editable:
|
||||
type: boolean
|
||||
description: The configure item can be updated or not
|
||||
IntegerConfigItem:
|
||||
type: object
|
||||
properties:
|
||||
value:
|
||||
type: integer
|
||||
description: The integer value of current config item
|
||||
editable:
|
||||
type: boolean
|
||||
description: The configure item can be updated or not
|
||||
|
@ -2,6 +2,7 @@ package chartserver
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/goharbor/harbor/src/controller/config"
|
||||
"path"
|
||||
"strings"
|
||||
"sync"
|
||||
@ -9,7 +10,6 @@ import (
|
||||
"github.com/goharbor/harbor/src/lib/errors"
|
||||
"helm.sh/helm/v3/cmd/helm/search"
|
||||
|
||||
"github.com/goharbor/harbor/src/core/config"
|
||||
hlog "github.com/goharbor/harbor/src/lib/log"
|
||||
)
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
@ -11,7 +12,6 @@ import (
|
||||
|
||||
"github.com/goharbor/harbor/src/common/dao"
|
||||
commonthttp "github.com/goharbor/harbor/src/common/http"
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
"github.com/goharbor/harbor/src/lib/log"
|
||||
"github.com/goharbor/harbor/src/pkg/exporter"
|
||||
)
|
||||
|
@ -1,11 +1,11 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"github.com/goharbor/harbor/src/common/dao"
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
"github.com/goharbor/harbor/src/lib/log"
|
||||
"github.com/goharbor/harbor/src/migration"
|
||||
)
|
||||
|
@ -1,48 +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 encrypt
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
)
|
||||
|
||||
// KeyProvider provides the key used to encrypt and decrypt attrs
|
||||
type KeyProvider interface {
|
||||
// Get returns the key
|
||||
// params can be used to pass parameters in different implements
|
||||
Get(params map[string]interface{}) (string, error)
|
||||
}
|
||||
|
||||
// FileKeyProvider reads key from file
|
||||
type FileKeyProvider struct {
|
||||
path string
|
||||
}
|
||||
|
||||
// NewFileKeyProvider returns an instance of FileKeyProvider
|
||||
// path: where the key should be read from
|
||||
func NewFileKeyProvider(path string) KeyProvider {
|
||||
return &FileKeyProvider{
|
||||
path: path,
|
||||
}
|
||||
}
|
||||
|
||||
// Get returns the key read from file
|
||||
func (f *FileKeyProvider) Get(params map[string]interface{}) (string, error) {
|
||||
b, err := ioutil.ReadFile(f.path)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(b), nil
|
||||
}
|
@ -1,44 +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 encrypt
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGetOfFileKeyProvider(t *testing.T) {
|
||||
path := "/tmp/key"
|
||||
key := "key_content"
|
||||
|
||||
if err := ioutil.WriteFile(path, []byte(key), 0777); err != nil {
|
||||
t.Errorf("failed to write to file %s: %v", path, err)
|
||||
return
|
||||
}
|
||||
defer os.Remove(path)
|
||||
|
||||
provider := NewFileKeyProvider(path)
|
||||
k, err := provider.Get(nil)
|
||||
if err != nil {
|
||||
t.Errorf("failed to get key from the file provider: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if k != key {
|
||||
t.Errorf("unexpected key: %s != %s", k, key)
|
||||
return
|
||||
}
|
||||
}
|
@ -1,54 +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 config
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGetOfFileKeyProvider(t *testing.T) {
|
||||
path := "/tmp/key"
|
||||
key := "key_content"
|
||||
|
||||
if err := ioutil.WriteFile(path, []byte(key), 0777); err != nil {
|
||||
t.Errorf("failed to write to file %s: %v", path, err)
|
||||
return
|
||||
}
|
||||
defer os.Remove(path)
|
||||
|
||||
provider := NewFileKeyProvider(path)
|
||||
k, err := provider.Get(nil)
|
||||
if err != nil {
|
||||
t.Errorf("failed to get key from the file provider: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if k != key {
|
||||
t.Errorf("unexpected key: %s != %s", k, key)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func TestPresetKeyProvider(t *testing.T) {
|
||||
kp := &PresetKeyProvider{
|
||||
Key: "mykey",
|
||||
}
|
||||
k, err := kp.Get(nil)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "mykey", k)
|
||||
}
|
@ -1,256 +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 config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
"github.com/goharbor/harbor/src/common"
|
||||
"github.com/goharbor/harbor/src/common/config/metadata"
|
||||
"github.com/goharbor/harbor/src/common/config/store"
|
||||
"github.com/goharbor/harbor/src/common/config/store/driver"
|
||||
"github.com/goharbor/harbor/src/common/http/modifier/auth"
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
"github.com/goharbor/harbor/src/common/utils"
|
||||
"github.com/goharbor/harbor/src/lib/cache"
|
||||
"github.com/goharbor/harbor/src/lib/log"
|
||||
)
|
||||
|
||||
// CfgManager ... Configure Manager
|
||||
type CfgManager struct {
|
||||
store *store.ConfigStore
|
||||
}
|
||||
|
||||
// NewDBCfgManager - create DB config manager
|
||||
func NewDBCfgManager() *CfgManager {
|
||||
cfgDriver := (driver.Driver)(&driver.Database{})
|
||||
|
||||
if cache.Default() != nil {
|
||||
log.Debug("create DB config manager with cache enabled")
|
||||
cfgDriver = driver.NewCacheDriver(cache.Default(), cfgDriver)
|
||||
}
|
||||
|
||||
manager := &CfgManager{store: store.NewConfigStore(cfgDriver)}
|
||||
// load default value
|
||||
manager.loadDefault()
|
||||
// load system config from env
|
||||
manager.loadSystemConfigFromEnv()
|
||||
return manager
|
||||
}
|
||||
|
||||
// NewRESTCfgManager - create REST config manager
|
||||
func NewRESTCfgManager(configURL, secret string) *CfgManager {
|
||||
secAuth := auth.NewSecretAuthorizer(secret)
|
||||
manager := &CfgManager{store: store.NewConfigStore(driver.NewRESTDriver(configURL, secAuth))}
|
||||
return manager
|
||||
}
|
||||
|
||||
// InMemoryDriver driver for unit testing
|
||||
type InMemoryDriver struct {
|
||||
sync.Mutex
|
||||
cfgMap map[string]interface{}
|
||||
}
|
||||
|
||||
// Load load data from driver, for example load from database,
|
||||
// it should be invoked before get any user scope config
|
||||
// for system scope config, because it is immutable, no need to call this method
|
||||
func (d *InMemoryDriver) Load() (map[string]interface{}, error) {
|
||||
d.Lock()
|
||||
defer d.Unlock()
|
||||
res := make(map[string]interface{})
|
||||
for k, v := range d.cfgMap {
|
||||
res[k] = v
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// Save only save user config setting to driver, for example: database, REST
|
||||
func (d *InMemoryDriver) Save(cfg map[string]interface{}) error {
|
||||
d.Lock()
|
||||
defer d.Unlock()
|
||||
for k, v := range cfg {
|
||||
d.cfgMap[k] = v
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewInMemoryManager create a manager for unit testing, doesn't involve database or REST
|
||||
func NewInMemoryManager() *CfgManager {
|
||||
manager := &CfgManager{store: store.NewConfigStore(&InMemoryDriver{cfgMap: map[string]interface{}{}})}
|
||||
// load default value
|
||||
manager.loadDefault()
|
||||
// load system config from env
|
||||
manager.loadSystemConfigFromEnv()
|
||||
return manager
|
||||
}
|
||||
|
||||
// loadDefault ...
|
||||
func (c *CfgManager) loadDefault() {
|
||||
// Init Default Value
|
||||
itemArray := metadata.Instance().GetAll()
|
||||
for _, item := range itemArray {
|
||||
if len(item.DefaultValue) > 0 {
|
||||
cfgValue, err := metadata.NewCfgValue(item.Name, item.DefaultValue)
|
||||
if err != nil {
|
||||
log.Errorf("loadDefault failed, config item, key: %v, err: %v", item.Name, err)
|
||||
continue
|
||||
}
|
||||
c.store.Set(item.Name, *cfgValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// loadSystemConfigFromEnv ...
|
||||
func (c *CfgManager) loadSystemConfigFromEnv() {
|
||||
itemArray := metadata.Instance().GetAll()
|
||||
// Init System Value
|
||||
for _, item := range itemArray {
|
||||
if item.Scope == metadata.SystemScope && len(item.EnvKey) > 0 {
|
||||
if envValue, ok := os.LookupEnv(item.EnvKey); ok {
|
||||
configValue, err := metadata.NewCfgValue(item.Name, envValue)
|
||||
if err != nil {
|
||||
log.Errorf("loadSystemConfigFromEnv failed, config item, key: %v, err: %v", item.Name, err)
|
||||
continue
|
||||
}
|
||||
c.store.Set(item.Name, *configValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GetAll get all settings.
|
||||
func (c *CfgManager) GetAll() map[string]interface{} {
|
||||
resultMap := map[string]interface{}{}
|
||||
if err := c.store.Load(); err != nil {
|
||||
log.Errorf("GetAll failed, error %v", err)
|
||||
return resultMap
|
||||
}
|
||||
metaDataList := metadata.Instance().GetAll()
|
||||
for _, item := range metaDataList {
|
||||
cfgValue, err := c.store.GetAnyType(item.Name)
|
||||
if err != nil {
|
||||
if err != metadata.ErrValueNotSet {
|
||||
log.Errorf("Failed to get value of key %v, error %v", item.Name, err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
resultMap[item.Name] = cfgValue
|
||||
}
|
||||
return resultMap
|
||||
}
|
||||
|
||||
// GetUserCfgs retrieve all user configs
|
||||
func (c *CfgManager) GetUserCfgs() map[string]interface{} {
|
||||
resultMap := map[string]interface{}{}
|
||||
if err := c.store.Load(); err != nil {
|
||||
log.Errorf("GetUserCfgs failed, error %v", err)
|
||||
return resultMap
|
||||
}
|
||||
metaDataList := metadata.Instance().GetAll()
|
||||
for _, item := range metaDataList {
|
||||
if item.Scope == metadata.UserScope {
|
||||
cfgValue, err := c.store.GetAnyType(item.Name)
|
||||
if err != nil {
|
||||
if err == metadata.ErrValueNotSet {
|
||||
if _, ok := item.ItemType.(*metadata.StringType); ok {
|
||||
cfgValue = ""
|
||||
}
|
||||
if _, ok := item.ItemType.(*metadata.NonEmptyStringType); ok {
|
||||
cfgValue = ""
|
||||
}
|
||||
} else {
|
||||
log.Errorf("Failed to get value of key %v, error %v", item.Name, err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
resultMap[item.Name] = cfgValue
|
||||
}
|
||||
}
|
||||
return resultMap
|
||||
}
|
||||
|
||||
// Load load configuration from storage, like database or redis
|
||||
func (c *CfgManager) Load() error {
|
||||
return c.store.Load()
|
||||
}
|
||||
|
||||
// Save - Save all current configuration to storage
|
||||
func (c *CfgManager) Save() error {
|
||||
return c.store.Save()
|
||||
}
|
||||
|
||||
// Get ...
|
||||
func (c *CfgManager) Get(key string) *metadata.ConfigureValue {
|
||||
configValue, err := c.store.Get(key)
|
||||
if err != nil {
|
||||
log.Debugf("failed to get key %v, error: %v", key, err)
|
||||
configValue = &metadata.ConfigureValue{}
|
||||
}
|
||||
return configValue
|
||||
}
|
||||
|
||||
// Set ...
|
||||
func (c *CfgManager) Set(key string, value interface{}) {
|
||||
configValue, err := metadata.NewCfgValue(key, utils.GetStrValueOfAnyType(value))
|
||||
if err != nil {
|
||||
log.Errorf("error when setting key: %v, error %v", key, err)
|
||||
return
|
||||
}
|
||||
c.store.Set(key, *configValue)
|
||||
}
|
||||
|
||||
// GetDatabaseCfg - Get database configurations
|
||||
func (c *CfgManager) GetDatabaseCfg() *models.Database {
|
||||
return &models.Database{
|
||||
Type: c.Get(common.DatabaseType).GetString(),
|
||||
PostGreSQL: &models.PostGreSQL{
|
||||
Host: c.Get(common.PostGreSQLHOST).GetString(),
|
||||
Port: c.Get(common.PostGreSQLPort).GetInt(),
|
||||
Username: c.Get(common.PostGreSQLUsername).GetString(),
|
||||
Password: c.Get(common.PostGreSQLPassword).GetString(),
|
||||
Database: c.Get(common.PostGreSQLDatabase).GetString(),
|
||||
SSLMode: c.Get(common.PostGreSQLSSLMode).GetString(),
|
||||
MaxIdleConns: c.Get(common.PostGreSQLMaxIdleConns).GetInt(),
|
||||
MaxOpenConns: c.Get(common.PostGreSQLMaxOpenConns).GetInt(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// UpdateConfig - Update config store with a specified configuration and also save updated configure.
|
||||
func (c *CfgManager) UpdateConfig(cfgs map[string]interface{}) error {
|
||||
return c.store.Update(cfgs)
|
||||
}
|
||||
|
||||
// ValidateCfg validate config by metadata. return the first error if exist.
|
||||
func (c *CfgManager) ValidateCfg(cfgs map[string]interface{}) error {
|
||||
for key, value := range cfgs {
|
||||
strVal := utils.GetStrValueOfAnyType(value)
|
||||
_, err := metadata.NewCfgValue(key, strVal)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%v, item name: %v", err, key)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DumpTrace dump all configurations
|
||||
func (c *CfgManager) DumpTrace() {
|
||||
cfgs := c.GetAll()
|
||||
for k, v := range cfgs {
|
||||
log.Info(k, ":=", v)
|
||||
}
|
||||
}
|
@ -1,141 +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 config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/goharbor/harbor/src/common/utils/test"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var TestDBConfig = map[string]interface{}{
|
||||
"postgresql_host": "localhost",
|
||||
"postgresql_database": "registry",
|
||||
"postgresql_password": "root123",
|
||||
"postgresql_username": "postgres",
|
||||
"postgresql_sslmode": "disable",
|
||||
"email_host": "127.0.0.1",
|
||||
"scan_all_policy": `{"parameter":{"daily_time":0},"type":"daily"}`,
|
||||
}
|
||||
|
||||
var configManager *CfgManager
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
configManager = NewDBCfgManager()
|
||||
test.InitDatabaseFromEnv()
|
||||
configManager.UpdateConfig(TestDBConfig)
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
|
||||
func TestLoadFromDatabase(t *testing.T) {
|
||||
configManager.UpdateConfig(TestDBConfig)
|
||||
configManager.Load()
|
||||
assert.Equal(t, "127.0.0.1", configManager.Get("email_host").GetString())
|
||||
assert.Equal(t, `{"parameter":{"daily_time":0},"type":"daily"}`, configManager.Get("scan_all_policy").GetString())
|
||||
}
|
||||
|
||||
func TestLoadUserCfg(t *testing.T) {
|
||||
configMap := configManager.GetUserCfgs()
|
||||
assert.NotNil(t, configMap["ldap_url"])
|
||||
assert.NotNil(t, configMap["ldap_base_dn"])
|
||||
}
|
||||
|
||||
func TestSaveToDatabase(t *testing.T) {
|
||||
fmt.Printf("database config %#v\n", configManager.GetDatabaseCfg())
|
||||
configManager.Load()
|
||||
configManager.Set("read_only", "true")
|
||||
configManager.Save()
|
||||
configManager.Load()
|
||||
assert.Equal(t, true, configManager.Get("read_only").GetBool())
|
||||
}
|
||||
|
||||
func TestUpdateCfg(t *testing.T) {
|
||||
testConfig := map[string]interface{}{
|
||||
"ldap_url": "ldaps://ldap.vmware.com",
|
||||
"ldap_search_dn": "cn=admin,dc=example,dc=com",
|
||||
"ldap_timeout": 10,
|
||||
"ldap_search_password": "admin",
|
||||
"ldap_base_dn": "dc=example,dc=com",
|
||||
}
|
||||
configManager.Load()
|
||||
configManager.UpdateConfig(testConfig)
|
||||
|
||||
assert.Equal(t, "ldaps://ldap.vmware.com", configManager.Get("ldap_url").GetString())
|
||||
assert.Equal(t, 10, configManager.Get("ldap_timeout").GetInt())
|
||||
assert.Equal(t, "admin", configManager.Get("ldap_search_password").GetPassword())
|
||||
assert.Equal(t, "cn=admin,dc=example,dc=com", configManager.Get("ldap_search_dn").GetString())
|
||||
assert.Equal(t, "dc=example,dc=com", configManager.Get("ldap_base_dn").GetString())
|
||||
}
|
||||
|
||||
func TestCfgManager_loadDefaultValues(t *testing.T) {
|
||||
configManager.loadDefault()
|
||||
if configManager.Get("ldap_timeout").GetInt() != 5 {
|
||||
t.Errorf("Failed to load ldap_timeout")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCfgManger_loadSystemValues(t *testing.T) {
|
||||
configManager.loadDefault()
|
||||
configManager.loadSystemConfigFromEnv()
|
||||
configManager.UpdateConfig(map[string]interface{}{
|
||||
"postgresql_host": "127.0.0.1",
|
||||
})
|
||||
if configManager.Get("postgresql_host").GetString() != "127.0.0.1" {
|
||||
t.Errorf("Failed to set system value postgresql_host, expected %v, actual %v", "127.0.0.1", configManager.Get("postgresql_host").GetString())
|
||||
}
|
||||
}
|
||||
func TestCfgManager_GetDatabaseCfg(t *testing.T) {
|
||||
configManager.UpdateConfig(map[string]interface{}{
|
||||
"postgresql_host": "localhost",
|
||||
"postgresql_database": "registry",
|
||||
"postgresql_password": "root123",
|
||||
"postgresql_username": "postgres",
|
||||
"postgresql_sslmode": "disable",
|
||||
})
|
||||
dbCfg := configManager.GetDatabaseCfg()
|
||||
assert.Equal(t, "localhost", dbCfg.PostGreSQL.Host)
|
||||
assert.Equal(t, "registry", dbCfg.PostGreSQL.Database)
|
||||
assert.Equal(t, "root123", dbCfg.PostGreSQL.Password)
|
||||
assert.Equal(t, "postgres", dbCfg.PostGreSQL.Username)
|
||||
assert.Equal(t, "disable", dbCfg.PostGreSQL.SSLMode)
|
||||
}
|
||||
|
||||
func TestNewInMemoryManager(t *testing.T) {
|
||||
inMemoryManager := NewInMemoryManager()
|
||||
inMemoryManager.UpdateConfig(map[string]interface{}{
|
||||
"ldap_url": "ldaps://ldap.vmware.com",
|
||||
"ldap_timeout": 5,
|
||||
"ldap_verify_cert": true,
|
||||
})
|
||||
assert.Equal(t, "ldaps://ldap.vmware.com", inMemoryManager.Get("ldap_url").GetString())
|
||||
assert.Equal(t, 5, inMemoryManager.Get("ldap_timeout").GetInt())
|
||||
assert.Equal(t, true, inMemoryManager.Get("ldap_verify_cert").GetBool())
|
||||
}
|
||||
|
||||
/*
|
||||
func TestNewRESTCfgManager(t *testing.T) {
|
||||
restMgr := NewRESTCfgManager("http://10.161.47.13:8080"+common.CoreConfigPath, "0XtgSGFx1amMDTaH")
|
||||
err := restMgr.Load()
|
||||
if err != nil {
|
||||
t.Errorf("Failed with error %v", err)
|
||||
}
|
||||
fmt.Printf("db:%v", restMgr.GetDatabaseCfg().Type)
|
||||
fmt.Printf("host:%#v\n", restMgr.GetDatabaseCfg().PostGreSQL.Host)
|
||||
fmt.Printf("port:%#v\n", restMgr.GetDatabaseCfg().PostGreSQL.Port)
|
||||
|
||||
}*/
|
@ -1,85 +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 driver
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/goharbor/harbor/src/common"
|
||||
"github.com/goharbor/harbor/src/common/config/metadata"
|
||||
"github.com/goharbor/harbor/src/common/dao"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
dao.PrepareTestForPostgresSQL()
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
|
||||
func TestDatabase_Load(t *testing.T) {
|
||||
|
||||
cfgs := map[string]interface{}{
|
||||
common.AUTHMode: "db_auth",
|
||||
common.LDAPURL: "ldap://ldap.vmware.com",
|
||||
}
|
||||
driver := Database{}
|
||||
driver.Save(cfgs)
|
||||
cfgMap, err := driver.Load()
|
||||
if err != nil {
|
||||
t.Errorf("failed to load, error %v", err)
|
||||
}
|
||||
assert.True(t, len(cfgMap) >= 1)
|
||||
|
||||
if _, ok := cfgMap["ldap_url"]; !ok {
|
||||
t.Error("Can not find ldap_url")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDatabase_Save(t *testing.T) {
|
||||
ldapURL := "ldap://ldap.vmware.com"
|
||||
driver := Database{}
|
||||
prevCfg, err := driver.Load()
|
||||
if err != nil {
|
||||
t.Errorf("failed to load config %v", err)
|
||||
}
|
||||
cfgMap := map[string]interface{}{"ldap_url": ldapURL}
|
||||
driver.Save(cfgMap)
|
||||
updatedMap, err := driver.Load()
|
||||
if err != nil {
|
||||
t.Errorf("failed to load config %v", err)
|
||||
}
|
||||
assert.Equal(t, updatedMap["ldap_url"], ldapURL)
|
||||
driver.Save(prevCfg)
|
||||
|
||||
}
|
||||
|
||||
func BenchmarkDatabaseLoad(b *testing.B) {
|
||||
cfgs := map[string]interface{}{}
|
||||
for _, item := range metadata.Instance().GetAll() {
|
||||
cfgs[item.Name] = item.DefaultValue
|
||||
}
|
||||
|
||||
driver := Database{}
|
||||
driver.Save(cfgs)
|
||||
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
if _, err := driver.Load(); err != nil {
|
||||
fmt.Printf("load failed %v", err)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
// Package driver provide the implementation of config driver used in CfgManager
|
||||
package driver
|
||||
|
||||
// Driver the interface to save/load config
|
||||
type Driver interface {
|
||||
// Load - load config item from config driver
|
||||
Load() (map[string]interface{}, error)
|
||||
// Save - save config item into config driver
|
||||
Save(cfg map[string]interface{}) error
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
package driver
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
|
||||
commonhttp "github.com/goharbor/harbor/src/common/http"
|
||||
"github.com/goharbor/harbor/src/common/http/modifier"
|
||||
"github.com/goharbor/harbor/src/lib/log"
|
||||
)
|
||||
|
||||
// RESTDriver - config store driver based on REST API
|
||||
type RESTDriver struct {
|
||||
configRESTURL string
|
||||
client *commonhttp.Client
|
||||
}
|
||||
|
||||
// NewRESTDriver - Create RESTDriver
|
||||
func NewRESTDriver(configRESTURL string, modifiers ...modifier.Modifier) *RESTDriver {
|
||||
if commonhttp.InternalTLSEnabled() {
|
||||
tr := commonhttp.GetHTTPTransport(commonhttp.SecureTransport)
|
||||
return &RESTDriver{configRESTURL: configRESTURL, client: commonhttp.NewClient(&http.Client{Transport: tr}, modifiers...)}
|
||||
|
||||
}
|
||||
return &RESTDriver{configRESTURL: configRESTURL, client: commonhttp.NewClient(nil, modifiers...)}
|
||||
}
|
||||
|
||||
// Load - load config data from REST server
|
||||
func (h *RESTDriver) Load() (map[string]interface{}, error) {
|
||||
cfgMap := map[string]interface{}{}
|
||||
log.Infof("get configuration from url: %+v", h.configRESTURL)
|
||||
err := h.client.Get(h.configRESTURL, &cfgMap)
|
||||
if err != nil {
|
||||
log.Errorf("Failed on load rest config err:%v, url:%v", err, h.configRESTURL)
|
||||
}
|
||||
if len(cfgMap) < 1 {
|
||||
return cfgMap, errors.New("failed to load rest config")
|
||||
}
|
||||
return cfgMap, err
|
||||
}
|
||||
|
||||
// Save - Save config data to REST server by PUT method
|
||||
func (h *RESTDriver) Save(cfgMap map[string]interface{}) error {
|
||||
return h.client.Put(h.configRESTURL, cfgMap)
|
||||
}
|
@ -1,93 +0,0 @@
|
||||
package store
|
||||
|
||||
import (
|
||||
"github.com/goharbor/harbor/src/common/config/metadata"
|
||||
"github.com/goharbor/harbor/src/common/config/store/driver"
|
||||
"github.com/goharbor/harbor/src/common/dao"
|
||||
"github.com/goharbor/harbor/src/lib/log"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
dao.PrepareTestForPostgresSQL()
|
||||
cfgStore := NewConfigStore(&driver.Database{})
|
||||
cfgStore.Set("ldap_url", metadata.ConfigureValue{Name: "ldap_url", Value: "ldap://ldap.vmware.com"})
|
||||
err := cfgStore.Save()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
func TestConfigStore_Save(t *testing.T) {
|
||||
cfgStore := NewConfigStore(&driver.Database{})
|
||||
err := cfgStore.Save()
|
||||
cfgStore.Set("ldap_verify_cert", metadata.ConfigureValue{Name: "ldap_verify_cert", Value: "true"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
cfgValue, err := cfgStore.Get("ldap_verify_cert")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.Equal(t, true, cfgValue.GetBool())
|
||||
|
||||
}
|
||||
|
||||
func TestConfigStore_Load(t *testing.T) {
|
||||
cfgStore := NewConfigStore(&driver.Database{})
|
||||
err := cfgStore.Load()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
cfgValue, err := cfgStore.Get("ldap_url")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
assert.Equal(t, "ldap://ldap.vmware.com", cfgValue.GetString())
|
||||
|
||||
}
|
||||
|
||||
func TestToString(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
value interface{}
|
||||
expect string
|
||||
}{
|
||||
{
|
||||
name: "transform int",
|
||||
value: 999,
|
||||
expect: "999",
|
||||
},
|
||||
{
|
||||
name: "transform slice",
|
||||
value: []int{0, 1, 2},
|
||||
expect: "[0,1,2]",
|
||||
},
|
||||
{
|
||||
name: "transform map",
|
||||
value: map[string]string{"k": "v"},
|
||||
expect: "{\"k\":\"v\"}",
|
||||
},
|
||||
{
|
||||
name: "transform bool",
|
||||
value: false,
|
||||
expect: "false",
|
||||
},
|
||||
{
|
||||
name: "transform nil",
|
||||
value: nil,
|
||||
expect: "nil",
|
||||
},
|
||||
}
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
s, err := toString(c.value)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, c.expect, s)
|
||||
})
|
||||
}
|
||||
}
|
@ -23,6 +23,9 @@ const (
|
||||
UAAAuth = "uaa_auth"
|
||||
HTTPAuth = "http_auth"
|
||||
OIDCAuth = "oidc_auth"
|
||||
DBCfgManager = "db_cfg_manager"
|
||||
InMemoryCfgManager = "in_memory_manager"
|
||||
RestCfgManager = "rest_config_manager"
|
||||
ProCrtRestrEveryone = "everyone"
|
||||
ProCrtRestrAdmOnly = "adminonly"
|
||||
LDAPScopeBase = 0
|
||||
@ -141,7 +144,7 @@ const (
|
||||
RobotNamePrefix = "robot_name_prefix"
|
||||
// Use this prefix to index user who tries to login with web hook token.
|
||||
AuthProxyUserNamePrefix = "tokenreview$"
|
||||
CoreConfigPath = "/api/internal/configurations"
|
||||
CoreConfigPath = "/api/v2.0/internalconfig"
|
||||
RobotTokenDuration = "robot_token_duration"
|
||||
|
||||
OIDCCallbackPath = "/c/oidc/callback"
|
||||
|
@ -146,14 +146,6 @@ func PaginateForQuerySetter(qs orm.QuerySeter, page, size int64) orm.QuerySeter
|
||||
return qs
|
||||
}
|
||||
|
||||
// Escape ..
|
||||
func Escape(str string) string {
|
||||
str = strings.Replace(str, `\`, `\\`, -1)
|
||||
str = strings.Replace(str, `%`, `\%`, -1)
|
||||
str = strings.Replace(str, `_`, `\_`, -1)
|
||||
return str
|
||||
}
|
||||
|
||||
// implements github.com/golang-migrate/migrate/v4.Logger
|
||||
type mLogger struct {
|
||||
logger *log.Logger
|
||||
|
@ -1,77 +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 dao
|
||||
|
||||
import (
|
||||
"github.com/goharbor/harbor/src/common"
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
"github.com/goharbor/harbor/src/common/utils"
|
||||
"github.com/goharbor/harbor/src/lib/log"
|
||||
)
|
||||
|
||||
// AuthModeCanBeModified determines whether auth mode can be
|
||||
// modified or not. Auth mode can modified when there is only admin
|
||||
// user in database.
|
||||
func AuthModeCanBeModified() (bool, error) {
|
||||
c, err := GetOrmer().QueryTable(&models.User{}).Count()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
// admin and anonymous
|
||||
return c == 2, nil
|
||||
}
|
||||
|
||||
// GetConfigEntries Get configuration from database
|
||||
func GetConfigEntries() ([]*models.ConfigEntry, error) {
|
||||
o := GetOrmer()
|
||||
var p []*models.ConfigEntry
|
||||
sql := "select * from properties"
|
||||
n, err := o.Raw(sql, []interface{}{}).QueryRows(&p)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if n == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// SaveConfigEntries Save configuration to database.
|
||||
func SaveConfigEntries(entries []models.ConfigEntry) error {
|
||||
o := GetOrmer()
|
||||
for _, entry := range entries {
|
||||
if entry.Key == common.LDAPGroupAdminDn {
|
||||
entry.Value = utils.TrimLower(entry.Value)
|
||||
}
|
||||
tempEntry := models.ConfigEntry{}
|
||||
tempEntry.Key = entry.Key
|
||||
tempEntry.Value = entry.Value
|
||||
created, _, err := o.ReadOrCreate(&tempEntry, "k")
|
||||
if err != nil && !IsDupRecErr(err) {
|
||||
log.Errorf("Error create configuration entry: %v", err)
|
||||
return err
|
||||
}
|
||||
if !created {
|
||||
entry.ID = tempEntry.ID
|
||||
_, err := o.Update(&entry, "v")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
@ -15,19 +15,21 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"github.com/goharbor/harbor/src/lib/orm"
|
||||
"testing"
|
||||
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
)
|
||||
|
||||
func TestAuthModeCanBeModified(t *testing.T) {
|
||||
ctx := orm.Context()
|
||||
c, err := GetOrmer().QueryTable(&models.User{}).Count()
|
||||
if err != nil {
|
||||
t.Fatalf("failed to count users: %v", err)
|
||||
}
|
||||
|
||||
if c == 2 {
|
||||
flag, err := AuthModeCanBeModified()
|
||||
flag, err := AuthModeCanBeModified(ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to determine whether auth mode can be modified: %v", err)
|
||||
}
|
||||
@ -51,7 +53,7 @@ func TestAuthModeCanBeModified(t *testing.T) {
|
||||
}
|
||||
}(id)
|
||||
|
||||
flag, err = AuthModeCanBeModified()
|
||||
flag, err = AuthModeCanBeModified(ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to determine whether auth mode can be modified: %v", err)
|
||||
}
|
||||
@ -60,7 +62,7 @@ func TestAuthModeCanBeModified(t *testing.T) {
|
||||
}
|
||||
|
||||
} else {
|
||||
flag, err := AuthModeCanBeModified()
|
||||
flag, err := AuthModeCanBeModified(ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to determine whether auth mode can be modified: %v", err)
|
||||
}
|
||||
|
@ -15,20 +15,23 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/astaxie/beego/orm"
|
||||
"github.com/goharbor/harbor/src/common"
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
"github.com/goharbor/harbor/src/common/utils"
|
||||
"github.com/goharbor/harbor/src/lib/log"
|
||||
libOrm "github.com/goharbor/harbor/src/lib/orm"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var testCtx context.Context
|
||||
|
||||
func execUpdate(o orm.Ormer, sql string, params ...interface{}) error {
|
||||
p, err := o.Raw(sql).Prepare()
|
||||
if err != nil {
|
||||
@ -120,6 +123,7 @@ func TestMain(m *testing.M) {
|
||||
default:
|
||||
log.Fatalf("invalid database: %s", database)
|
||||
}
|
||||
testCtx = libOrm.Context()
|
||||
result = testForAll(m)
|
||||
|
||||
if result != 0 {
|
||||
@ -566,104 +570,6 @@ func TestIsSuperUser(t *testing.T) {
|
||||
assert.False(IsSuperUser("none"))
|
||||
}
|
||||
|
||||
func TestSaveConfigEntries(t *testing.T) {
|
||||
configEntries := []models.ConfigEntry{
|
||||
{
|
||||
Key: "teststringkey",
|
||||
Value: "192.168.111.211",
|
||||
},
|
||||
{
|
||||
Key: "testboolkey",
|
||||
Value: "true",
|
||||
},
|
||||
{
|
||||
Key: "testnumberkey",
|
||||
Value: "5",
|
||||
},
|
||||
{
|
||||
Key: common.CfgDriverDB,
|
||||
Value: "db",
|
||||
},
|
||||
}
|
||||
err := SaveConfigEntries(configEntries)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to save configuration to database %v", err)
|
||||
}
|
||||
readEntries, err := GetConfigEntries()
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to get configuration from database %v", err)
|
||||
}
|
||||
findItem := 0
|
||||
for _, entry := range readEntries {
|
||||
switch entry.Key {
|
||||
case "teststringkey":
|
||||
if "192.168.111.211" == entry.Value {
|
||||
findItem++
|
||||
}
|
||||
case "testnumberkey":
|
||||
if "5" == entry.Value {
|
||||
findItem++
|
||||
}
|
||||
case "testboolkey":
|
||||
if "true" == entry.Value {
|
||||
findItem++
|
||||
}
|
||||
default:
|
||||
}
|
||||
}
|
||||
if findItem != 3 {
|
||||
t.Fatalf("Should update 3 configuration but only update %d", findItem)
|
||||
}
|
||||
|
||||
configEntries = []models.ConfigEntry{
|
||||
{
|
||||
Key: "teststringkey",
|
||||
Value: "192.168.111.215",
|
||||
},
|
||||
{
|
||||
Key: "testboolkey",
|
||||
Value: "false",
|
||||
},
|
||||
{
|
||||
Key: "testnumberkey",
|
||||
Value: "7",
|
||||
},
|
||||
{
|
||||
Key: common.CfgDriverDB,
|
||||
Value: "db",
|
||||
},
|
||||
}
|
||||
err = SaveConfigEntries(configEntries)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to save configuration to database %v", err)
|
||||
}
|
||||
readEntries, err = GetConfigEntries()
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to get configuration from database %v", err)
|
||||
}
|
||||
findItem = 0
|
||||
for _, entry := range readEntries {
|
||||
switch entry.Key {
|
||||
case "teststringkey":
|
||||
if "192.168.111.215" == entry.Value {
|
||||
findItem++
|
||||
}
|
||||
case "testnumberkey":
|
||||
if "7" == entry.Value {
|
||||
findItem++
|
||||
}
|
||||
case "testboolkey":
|
||||
if "false" == entry.Value {
|
||||
findItem++
|
||||
}
|
||||
default:
|
||||
}
|
||||
}
|
||||
if findItem != 3 {
|
||||
t.Fatalf("Should update 3 configuration but only update %d", findItem)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsDupRecError(t *testing.T) {
|
||||
assert.True(t, IsDupRecErr(fmt.Errorf("pq: duplicate key value violates unique constraint \"properties_k_key\"")))
|
||||
assert.False(t, IsDupRecErr(fmt.Errorf("other error")))
|
||||
|
@ -20,6 +20,7 @@ import (
|
||||
|
||||
"github.com/astaxie/beego/orm"
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
libOrm "github.com/goharbor/harbor/src/lib/orm"
|
||||
)
|
||||
|
||||
// AddLabel creates a label
|
||||
@ -71,7 +72,7 @@ func getLabelQuerySetter(query *models.LabelQuery) orm.QuerySeter {
|
||||
qs := GetOrmer().QueryTable(&models.Label{})
|
||||
if len(query.Name) > 0 {
|
||||
if query.FuzzyMatchName {
|
||||
qs = qs.Filter("Name__icontains", Escape(query.Name))
|
||||
qs = qs.Filter("Name__icontains", libOrm.Escape(query.Name))
|
||||
} else {
|
||||
qs = qs.Filter("Name", query.Name)
|
||||
}
|
||||
|
@ -16,12 +16,12 @@ package dao
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
"net/url"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"github.com/astaxie/beego/orm"
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
"github.com/goharbor/harbor/src/common/utils"
|
||||
"github.com/goharbor/harbor/src/lib/log"
|
||||
migrate "github.com/golang-migrate/migrate/v4"
|
||||
|
@ -16,7 +16,7 @@ package dao
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"github.com/goharbor/harbor/src/lib/orm"
|
||||
"time"
|
||||
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
@ -43,7 +43,7 @@ func DeleteProjectMetadata(projectID int64, name ...string) error {
|
||||
params = append(params, projectID)
|
||||
|
||||
if len(name) > 0 {
|
||||
sql += fmt.Sprintf(` and name in ( %s )`, ParamPlaceholderForIn(len(name)))
|
||||
sql += fmt.Sprintf(` and name in ( %s )`, orm.ParamPlaceholderForIn(len(name)))
|
||||
params = append(params, name)
|
||||
}
|
||||
|
||||
@ -73,7 +73,7 @@ func GetProjectMetadata(projectID int64, name ...string) ([]*models.ProjectMetad
|
||||
params = append(params, projectID)
|
||||
|
||||
if len(name) > 0 {
|
||||
sql += fmt.Sprintf(` and name in ( %s )`, ParamPlaceholderForIn(len(name)))
|
||||
sql += fmt.Sprintf(` and name in ( %s )`, orm.ParamPlaceholderForIn(len(name)))
|
||||
params = append(params, name)
|
||||
}
|
||||
|
||||
@ -81,16 +81,6 @@ func GetProjectMetadata(projectID int64, name ...string) ([]*models.ProjectMetad
|
||||
return proMetas, err
|
||||
}
|
||||
|
||||
// ParamPlaceholderForIn returns a string that contains placeholders for sql keyword "in"
|
||||
// e.g. n=3, returns "?,?,?"
|
||||
func ParamPlaceholderForIn(n int) string {
|
||||
placeholders := []string{}
|
||||
for i := 0; i < n; i++ {
|
||||
placeholders = append(placeholders, "?")
|
||||
}
|
||||
return strings.Join(placeholders, ",")
|
||||
}
|
||||
|
||||
// ListProjectMetadata ...
|
||||
func ListProjectMetadata(name, value string) ([]*models.ProjectMetadata, error) {
|
||||
sql := `select * from project_metadata
|
||||
|
@ -17,7 +17,9 @@ package dao
|
||||
import (
|
||||
"github.com/goharbor/harbor/src/common"
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
"github.com/goharbor/harbor/src/common/utils"
|
||||
"github.com/goharbor/harbor/src/lib/log"
|
||||
libOrm "github.com/goharbor/harbor/src/lib/orm"
|
||||
|
||||
"fmt"
|
||||
"time"
|
||||
@ -234,7 +236,7 @@ func projectQueryConditions(query *models.ProjectQueryParam) (string, []interfac
|
||||
|
||||
if len(query.Name) != 0 {
|
||||
sql += ` and p.name like ?`
|
||||
params = append(params, "%"+Escape(query.Name)+"%")
|
||||
params = append(params, "%"+libOrm.Escape(query.Name)+"%")
|
||||
}
|
||||
|
||||
if query.RegistryID > 0 {
|
||||
@ -266,7 +268,7 @@ func projectQueryConditions(query *models.ProjectQueryParam) (string, []interfac
|
||||
}
|
||||
if len(query.ProjectIDs) > 0 {
|
||||
sql += fmt.Sprintf(` and p.project_id in ( %s )`,
|
||||
ParamPlaceholderForIn(len(query.ProjectIDs)))
|
||||
utils.ParamPlaceholderForIn(len(query.ProjectIDs)))
|
||||
params = append(params, query.ProjectIDs)
|
||||
}
|
||||
return sql, params
|
||||
|
@ -18,7 +18,9 @@ import (
|
||||
"fmt"
|
||||
"github.com/goharbor/harbor/src/common/dao"
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
"github.com/goharbor/harbor/src/common/utils"
|
||||
"github.com/goharbor/harbor/src/lib/log"
|
||||
"github.com/goharbor/harbor/src/lib/orm"
|
||||
)
|
||||
|
||||
// GetProjectMember gets all members of the project.
|
||||
@ -160,9 +162,9 @@ func SearchMemberByName(projectID int64, entityName string) ([]*models.Member, e
|
||||
order by entity_name `
|
||||
queryParam := make([]interface{}, 4)
|
||||
queryParam = append(queryParam, projectID)
|
||||
queryParam = append(queryParam, "%"+dao.Escape(entityName)+"%")
|
||||
queryParam = append(queryParam, "%"+orm.Escape(entityName)+"%")
|
||||
queryParam = append(queryParam, projectID)
|
||||
queryParam = append(queryParam, "%"+dao.Escape(entityName)+"%")
|
||||
queryParam = append(queryParam, "%"+orm.Escape(entityName)+"%")
|
||||
members := []*models.Member{}
|
||||
log.Debugf("Query sql: %v", sql)
|
||||
_, err := o.Raw(sql, queryParam).QueryRows(&members)
|
||||
@ -184,7 +186,7 @@ func ListRoles(user *models.User, projectID int64) ([]int, error) {
|
||||
sql += fmt.Sprintf(`union
|
||||
select role
|
||||
from project_member
|
||||
where entity_type = 'g' and entity_id in ( %s ) and project_id = ? `, dao.ParamPlaceholderForIn(len(user.GroupIDs)))
|
||||
where entity_type = 'g' and entity_id in ( %s ) and project_id = ? `, utils.ParamPlaceholderForIn(len(user.GroupIDs)))
|
||||
params = append(params, user.GroupIDs)
|
||||
params = append(params, projectID)
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ package project
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/goharbor/harbor/src/controller/config"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
@ -28,7 +29,6 @@ import (
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
_ "github.com/goharbor/harbor/src/core/auth/db"
|
||||
_ "github.com/goharbor/harbor/src/core/auth/ldap"
|
||||
cfg "github.com/goharbor/harbor/src/core/config"
|
||||
"github.com/goharbor/harbor/src/lib/log"
|
||||
)
|
||||
|
||||
@ -71,7 +71,7 @@ func TestMain(m *testing.M) {
|
||||
"delete from project_member where id > 1",
|
||||
}
|
||||
dao.PrepareTestData(clearSqls, initSqls)
|
||||
cfg.Init()
|
||||
config.Init()
|
||||
result = m.Run()
|
||||
|
||||
if result != 0 {
|
||||
|
@ -16,6 +16,8 @@ package dao
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/goharbor/harbor/src/common/utils"
|
||||
libOrm "github.com/goharbor/harbor/src/lib/orm"
|
||||
"time"
|
||||
|
||||
"github.com/astaxie/beego/orm"
|
||||
@ -102,12 +104,12 @@ func repositoryQueryConditions(query ...*models.RepositoryQuery) (string, []inte
|
||||
|
||||
if len(q.Name) > 0 {
|
||||
sql += `and r.name like ? `
|
||||
params = append(params, "%"+Escape(q.Name)+"%")
|
||||
params = append(params, "%"+libOrm.Escape(q.Name)+"%")
|
||||
}
|
||||
|
||||
if len(q.ProjectIDs) > 0 {
|
||||
sql += fmt.Sprintf(`and r.project_id in ( %s ) `,
|
||||
ParamPlaceholderForIn(len(q.ProjectIDs)))
|
||||
utils.ParamPlaceholderForIn(len(q.ProjectIDs)))
|
||||
params = append(params, q.ProjectIDs)
|
||||
}
|
||||
|
||||
|
@ -16,10 +16,10 @@ package dao
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
"github.com/goharbor/harbor/src/lib/log"
|
||||
)
|
||||
|
||||
|
@ -15,8 +15,10 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
libOrm "github.com/goharbor/harbor/src/lib/orm"
|
||||
"time"
|
||||
|
||||
"github.com/astaxie/beego/orm"
|
||||
@ -129,11 +131,11 @@ func userQueryConditions(query *models.UserQuery) orm.QuerySeter {
|
||||
}
|
||||
|
||||
if len(query.Username) > 0 {
|
||||
qs = qs.Filter("username__contains", Escape(query.Username))
|
||||
qs = qs.Filter("username__contains", libOrm.Escape(query.Username))
|
||||
}
|
||||
|
||||
if len(query.Email) > 0 {
|
||||
qs = qs.Filter("email__contains", Escape(query.Email))
|
||||
qs = qs.Filter("email__contains", libOrm.Escape(query.Email))
|
||||
}
|
||||
|
||||
return qs
|
||||
@ -292,3 +294,19 @@ func CleanUser(id int64) error {
|
||||
func matchPassword(u *models.User, password string) bool {
|
||||
return utils.Encrypt(password, u.Salt, u.PasswordVersion) == u.Password
|
||||
}
|
||||
|
||||
// AuthModeCanBeModified determines whether auth mode can be
|
||||
// modified or not. Auth mode can modified when there is only admin
|
||||
// user in database.
|
||||
func AuthModeCanBeModified(ctx context.Context) (bool, error) {
|
||||
o, err := libOrm.FromContext(ctx)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
c, err := o.QueryTable(&models.User{}).Count()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
// admin and anonymous
|
||||
return c == 2, nil
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/goharbor/harbor/src/controller/config"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"regexp"
|
||||
@ -13,7 +14,6 @@ import (
|
||||
commonhttp "github.com/goharbor/harbor/src/common/http"
|
||||
"github.com/goharbor/harbor/src/common/http/modifier/auth"
|
||||
"github.com/goharbor/harbor/src/common/job/models"
|
||||
"github.com/goharbor/harbor/src/core/config"
|
||||
"github.com/goharbor/harbor/src/jobservice/job"
|
||||
)
|
||||
|
||||
|
@ -25,7 +25,6 @@ func init() {
|
||||
new(Role),
|
||||
new(RepoRecord),
|
||||
new(ProjectMetadata),
|
||||
new(ConfigEntry),
|
||||
new(Label),
|
||||
new(ResourceLabel),
|
||||
new(UserGroup),
|
||||
|
47
src/common/models/database.go
Normal file
47
src/common/models/database.go
Normal file
@ -0,0 +1,47 @@
|
||||
// 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 models
|
||||
|
||||
// Database ...
|
||||
type Database struct {
|
||||
Type string `json:"type"`
|
||||
PostGreSQL *PostGreSQL `json:"postgresql,omitempty"`
|
||||
}
|
||||
|
||||
// MySQL ...
|
||||
type MySQL struct {
|
||||
Host string `json:"host"`
|
||||
Port int `json:"port"`
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password,omitempty"`
|
||||
Database string `json:"database"`
|
||||
}
|
||||
|
||||
// SQLite ...
|
||||
type SQLite struct {
|
||||
File string `json:"file"`
|
||||
}
|
||||
|
||||
// PostGreSQL ...
|
||||
type PostGreSQL struct {
|
||||
Host string `json:"host"`
|
||||
Port int `json:"port"`
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password,omitempty"`
|
||||
Database string `json:"database"`
|
||||
SSLMode string `json:"sslmode"`
|
||||
MaxIdleConns int `json:"max_idle_conns"`
|
||||
MaxOpenConns int `json:"max_open_conns"`
|
||||
}
|
@ -295,3 +295,13 @@ func FindNamedMatches(regex *regexp.Regexp, str string) map[string]string {
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
// ParamPlaceholderForIn returns a string that contains placeholders for sql keyword "in"
|
||||
// e.g. n=3, returns "?,?,?"
|
||||
func ParamPlaceholderForIn(n int) string {
|
||||
placeholders := []string{}
|
||||
for i := 0; i < n; i++ {
|
||||
placeholders = append(placeholders, "?")
|
||||
}
|
||||
return strings.Join(placeholders, ",")
|
||||
}
|
||||
|
217
src/controller/config/controller.go
Normal file
217
src/controller/config/controller.go
Normal file
@ -0,0 +1,217 @@
|
||||
// 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 config
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/goharbor/harbor/src/common"
|
||||
"github.com/goharbor/harbor/src/common/dao"
|
||||
"github.com/goharbor/harbor/src/lib/config"
|
||||
"github.com/goharbor/harbor/src/lib/config/metadata"
|
||||
"github.com/goharbor/harbor/src/lib/errors"
|
||||
"github.com/goharbor/harbor/src/lib/log"
|
||||
"github.com/goharbor/harbor/src/pkg/config/db"
|
||||
"github.com/goharbor/harbor/src/pkg/config/inmemory"
|
||||
)
|
||||
|
||||
var (
|
||||
// Ctl Global instance of the config controller
|
||||
Ctl = NewController()
|
||||
)
|
||||
|
||||
// Controller define operations related to configures
|
||||
type Controller interface {
|
||||
// UserConfigs get the user scope configurations
|
||||
UserConfigs(ctx context.Context) (map[string]*config.Value, error)
|
||||
// UpdateUserConfigs update the user scope configurations
|
||||
UpdateUserConfigs(ctx context.Context, conf map[string]interface{}) error
|
||||
// GetAll get all configurations, used by internal, should include the system config items
|
||||
AllConfigs(ctx context.Context) (map[string]interface{}, error)
|
||||
// Load ...
|
||||
Load(ctx context.Context) error
|
||||
// GetString ...
|
||||
GetString(ctx context.Context, item string) string
|
||||
// GetBool ...
|
||||
GetBool(ctx context.Context, item string) bool
|
||||
// GetInt ...
|
||||
GetInt(ctx context.Context, item string) int
|
||||
// Get ...
|
||||
Get(ctx context.Context, item string) *metadata.ConfigureValue
|
||||
// GetCfgManager ...
|
||||
GetManager() config.Manager
|
||||
}
|
||||
|
||||
type controller struct {
|
||||
mgr config.Manager
|
||||
}
|
||||
|
||||
// NewController ...
|
||||
func NewController() Controller {
|
||||
return &controller{mgr: db.NewDBCfgManager()}
|
||||
}
|
||||
|
||||
// NewInMemoryController ...
|
||||
func NewInMemoryController() Controller {
|
||||
return &controller{mgr: inmemory.NewInMemoryManager()}
|
||||
}
|
||||
|
||||
func (c *controller) GetManager() config.Manager {
|
||||
return c.mgr
|
||||
}
|
||||
|
||||
func (c *controller) Get(ctx context.Context, item string) *metadata.ConfigureValue {
|
||||
return c.mgr.Get(ctx, item)
|
||||
}
|
||||
|
||||
func (c *controller) Load(ctx context.Context) error {
|
||||
return c.mgr.Load(ctx)
|
||||
}
|
||||
|
||||
func (c *controller) GetString(ctx context.Context, item string) string {
|
||||
return c.mgr.Get(ctx, item).GetString()
|
||||
}
|
||||
|
||||
func (c *controller) GetBool(ctx context.Context, item string) bool {
|
||||
return c.mgr.Get(ctx, item).GetBool()
|
||||
}
|
||||
|
||||
func (c *controller) GetInt(ctx context.Context, item string) int {
|
||||
return c.mgr.Get(ctx, item).GetInt()
|
||||
}
|
||||
|
||||
func (c *controller) UserConfigs(ctx context.Context) (map[string]*config.Value, error) {
|
||||
configs := c.mgr.GetUserCfgs(ctx)
|
||||
return ConvertForGet(ctx, configs, false)
|
||||
}
|
||||
|
||||
func (c *controller) AllConfigs(ctx context.Context) (map[string]interface{}, error) {
|
||||
configs := c.mgr.GetAll(ctx)
|
||||
return configs, nil
|
||||
}
|
||||
|
||||
func (c *controller) UpdateUserConfigs(ctx context.Context, conf map[string]interface{}) error {
|
||||
err := c.mgr.Load(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
isSysErr, err := c.validateCfg(ctx, conf)
|
||||
if err != nil {
|
||||
if isSysErr {
|
||||
log.Errorf("failed to validate configurations: %v", err)
|
||||
return fmt.Errorf("failed to validate configuration")
|
||||
}
|
||||
return err
|
||||
}
|
||||
if err := c.mgr.UpdateConfig(ctx, conf); err != nil {
|
||||
log.Errorf("failed to upload configurations: %v", err)
|
||||
return fmt.Errorf("failed to validate configuration")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *controller) validateCfg(ctx context.Context, cfgs map[string]interface{}) (bool, error) {
|
||||
flag, err := authModeCanBeModified(ctx)
|
||||
if err != nil {
|
||||
return true, err
|
||||
}
|
||||
if !flag {
|
||||
if failedKeys := c.checkUnmodifiable(ctx, cfgs, common.AUTHMode); len(failedKeys) > 0 {
|
||||
return false, errors.BadRequestError(nil).
|
||||
WithMessage(fmt.Sprintf("the keys %v can not be modified as new users have been inserted into database", failedKeys))
|
||||
}
|
||||
}
|
||||
err = c.mgr.ValidateCfg(ctx, cfgs)
|
||||
if err != nil {
|
||||
return false, errors.BadRequestError(err)
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (c *controller) checkUnmodifiable(ctx context.Context, cfgs map[string]interface{}, keys ...string) (failed []string) {
|
||||
if c.mgr == nil || cfgs == nil || keys == nil {
|
||||
return
|
||||
}
|
||||
for _, k := range keys {
|
||||
v := c.mgr.Get(ctx, k).GetString()
|
||||
if nv, ok := cfgs[k]; ok {
|
||||
if v != fmt.Sprintf("%v", nv) {
|
||||
failed = append(failed, k)
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// ScanAllPolicy is represent the json request and object for scan all policy
|
||||
// Only for migrating from the legacy schedule.
|
||||
type ScanAllPolicy struct {
|
||||
Type string `json:"type"`
|
||||
Param map[string]interface{} `json:"parameter,omitempty"`
|
||||
}
|
||||
|
||||
// ConvertForGet - delete sensitive attrs and add editable field to every attr
|
||||
func ConvertForGet(ctx context.Context, cfg map[string]interface{}, internal bool) (map[string]*config.Value, error) {
|
||||
result := map[string]*config.Value{}
|
||||
|
||||
mList := metadata.Instance().GetAll()
|
||||
|
||||
for _, item := range mList {
|
||||
val, exist := cfg[item.Name]
|
||||
// skip undefined items
|
||||
if !exist {
|
||||
continue
|
||||
}
|
||||
|
||||
switch item.ItemType.(type) {
|
||||
case *metadata.PasswordType:
|
||||
// remove password for external api call
|
||||
if !internal {
|
||||
delete(cfg, item.Name)
|
||||
continue
|
||||
}
|
||||
case *metadata.MapType, *metadata.StringToStringMapType:
|
||||
// convert to string for map type
|
||||
valByte, err := json.Marshal(val)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
val = string(valByte)
|
||||
}
|
||||
result[item.Name] = &config.Value{
|
||||
Val: val,
|
||||
Editable: true,
|
||||
}
|
||||
}
|
||||
|
||||
// default value for ScanAllPolicy
|
||||
if _, ok := result[common.ScanAllPolicy]; !ok {
|
||||
cfg[common.ScanAllPolicy] = `{"type":"none"}`
|
||||
}
|
||||
|
||||
// set value for auth_mode
|
||||
flag, err := authModeCanBeModified(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result[common.AUTHMode].Editable = flag
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func authModeCanBeModified(ctx context.Context) (bool, error) {
|
||||
return dao.AuthModeCanBeModified(ctx)
|
||||
}
|
250
src/controller/config/systemcfg.go
Normal file
250
src/controller/config/systemcfg.go
Normal file
@ -0,0 +1,250 @@
|
||||
// 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 config
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"github.com/goharbor/harbor/src/common"
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
"github.com/goharbor/harbor/src/common/secret"
|
||||
"github.com/goharbor/harbor/src/lib/log"
|
||||
"github.com/goharbor/harbor/src/pkg/encrypt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
// Use backgroundCtx to access system scope config
|
||||
backgroundCtx context.Context = context.Background()
|
||||
)
|
||||
|
||||
// It contains all system settings
|
||||
// If the config is set in env, just get it from env
|
||||
// If the config might not be set in env, and may have a default value, get it in this way:
|
||||
// Ctl.GetString(backgroundCtx, "xxxx")
|
||||
|
||||
// TokenPrivateKeyPath returns the path to the key for signing token for registry
|
||||
func TokenPrivateKeyPath() string {
|
||||
path := os.Getenv("TOKEN_PRIVATE_KEY_PATH")
|
||||
if len(path) == 0 {
|
||||
path = defaultRegistryTokenPrivateKeyPath
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
||||
// RegistryURL ...
|
||||
func RegistryURL() (string, error) {
|
||||
url := os.Getenv("REGISTRY_URL")
|
||||
if len(url) == 0 {
|
||||
url = "http://registry:5000"
|
||||
}
|
||||
return url, nil
|
||||
}
|
||||
|
||||
// InternalJobServiceURL returns jobservice URL for internal communication between Harbor containers
|
||||
func InternalJobServiceURL() string {
|
||||
return os.Getenv("JOBSERVICE_URL")
|
||||
}
|
||||
|
||||
// GetCoreURL returns the url of core from env
|
||||
func GetCoreURL() string {
|
||||
return os.Getenv("CORE_URL")
|
||||
}
|
||||
|
||||
// CoreSecret returns a secret to mark harbor-core when communicate with
|
||||
// other component
|
||||
func CoreSecret() string {
|
||||
return os.Getenv("CORE_SECRET")
|
||||
}
|
||||
|
||||
// RegistryCredential returns the username and password the core uses to access registry
|
||||
func RegistryCredential() (string, string) {
|
||||
return os.Getenv("REGISTRY_CREDENTIAL_USERNAME"), os.Getenv("REGISTRY_CREDENTIAL_PASSWORD")
|
||||
}
|
||||
|
||||
// JobserviceSecret returns a secret to mark Jobservice when communicate with
|
||||
// other component
|
||||
// TODO replace it with method of SecretStore
|
||||
func JobserviceSecret() string {
|
||||
return os.Getenv("JOBSERVICE_SECRET")
|
||||
}
|
||||
|
||||
// GetRedisOfRegURL returns the URL of Redis used by registry
|
||||
func GetRedisOfRegURL() string {
|
||||
return os.Getenv("_REDIS_URL_REG")
|
||||
}
|
||||
|
||||
// GetPortalURL returns the URL of portal
|
||||
func GetPortalURL() string {
|
||||
url := os.Getenv("PORTAL_URL")
|
||||
if len(url) == 0 {
|
||||
return common.DefaultPortalURL
|
||||
}
|
||||
return url
|
||||
}
|
||||
|
||||
// GetRegistryCtlURL returns the URL of registryctl
|
||||
func GetRegistryCtlURL() string {
|
||||
url := os.Getenv("REGISTRY_CONTROLLER_URL")
|
||||
if len(url) == 0 {
|
||||
return common.DefaultRegistryCtlURL
|
||||
}
|
||||
return url
|
||||
}
|
||||
|
||||
// GetPermittedRegistryTypesForProxyCache returns the permitted registry types for proxy cache
|
||||
func GetPermittedRegistryTypesForProxyCache() []string {
|
||||
types := os.Getenv("PERMITTED_REGISTRY_TYPES_FOR_PROXY_CACHE")
|
||||
if len(types) == 0 {
|
||||
return []string{}
|
||||
}
|
||||
return strings.Split(types, ",")
|
||||
}
|
||||
|
||||
// GetGCTimeWindow returns the reserve time window of blob.
|
||||
func GetGCTimeWindow() int64 {
|
||||
// the env is for testing/debugging. For production, Do NOT set it.
|
||||
if env, exist := os.LookupEnv("GC_TIME_WINDOW_HOURS"); exist {
|
||||
timeWindow, err := strconv.ParseInt(env, 10, 64)
|
||||
if err == nil {
|
||||
return timeWindow
|
||||
}
|
||||
}
|
||||
return common.DefaultGCTimeWindowHours
|
||||
}
|
||||
|
||||
// WithNotary returns a bool value to indicate if Harbor's deployed with Notary
|
||||
func WithNotary() bool {
|
||||
return Ctl.GetBool(backgroundCtx, common.WithNotary)
|
||||
}
|
||||
|
||||
// WithTrivy returns a bool value to indicate if Harbor's deployed with Trivy.
|
||||
func WithTrivy() bool {
|
||||
return Ctl.GetBool(backgroundCtx, common.WithTrivy)
|
||||
}
|
||||
|
||||
// WithChartMuseum returns a bool to indicate if chartmuseum is deployed with Harbor.
|
||||
func WithChartMuseum() bool {
|
||||
return Ctl.GetBool(backgroundCtx, common.WithChartMuseum)
|
||||
}
|
||||
|
||||
// GetChartMuseumEndpoint returns the endpoint of the chartmuseum service
|
||||
// otherwise an non nil error is returned
|
||||
func GetChartMuseumEndpoint() (string, error) {
|
||||
chartEndpoint := strings.TrimSpace(Ctl.GetString(backgroundCtx, common.ChartRepoURL))
|
||||
if len(chartEndpoint) == 0 {
|
||||
return "", errors.New("empty chartmuseum endpoint")
|
||||
}
|
||||
return chartEndpoint, nil
|
||||
}
|
||||
|
||||
// ExtEndpoint returns the external URL of Harbor: protocol://host:port
|
||||
func ExtEndpoint() (string, error) {
|
||||
return Ctl.GetString(backgroundCtx, common.ExtEndpoint), nil
|
||||
}
|
||||
|
||||
// ExtURL returns the external URL: host:port
|
||||
func ExtURL() (string, error) {
|
||||
endpoint, err := ExtEndpoint()
|
||||
if err != nil {
|
||||
log.Errorf("failed to load config, error %v", err)
|
||||
}
|
||||
l := strings.Split(endpoint, "://")
|
||||
if len(l) > 1 {
|
||||
return l[1], nil
|
||||
}
|
||||
return endpoint, nil
|
||||
}
|
||||
|
||||
// SecretKey returns the secret key to encrypt the password of target
|
||||
func SecretKey() (string, error) {
|
||||
return keyProvider.Get(nil)
|
||||
}
|
||||
|
||||
func initKeyProvider() {
|
||||
path := os.Getenv("KEY_PATH")
|
||||
if len(path) == 0 {
|
||||
path = defaultKeyPath
|
||||
}
|
||||
log.Infof("key path: %s", path)
|
||||
keyProvider = encrypt.NewFileKeyProvider(path)
|
||||
}
|
||||
|
||||
func initSecretStore() {
|
||||
m := map[string]string{}
|
||||
m[JobserviceSecret()] = secret.JobserviceUser
|
||||
SecretStore = secret.NewStore(m)
|
||||
}
|
||||
|
||||
// InternalCoreURL returns the local harbor core url
|
||||
func InternalCoreURL() string {
|
||||
return strings.TrimSuffix(Ctl.GetString(backgroundCtx, common.CoreURL), "/")
|
||||
}
|
||||
|
||||
// LocalCoreURL returns the local harbor core url
|
||||
func LocalCoreURL() string {
|
||||
return Ctl.GetString(backgroundCtx, common.CoreLocalURL)
|
||||
}
|
||||
|
||||
// InternalTokenServiceEndpoint returns token service endpoint for internal communication between Harbor containers
|
||||
func InternalTokenServiceEndpoint() string {
|
||||
return InternalCoreURL() + "/service/token"
|
||||
}
|
||||
|
||||
// InternalNotaryEndpoint returns notary server endpoint for internal communication between Harbor containers
|
||||
// This is currently a conventional value and can be unaccessible when Harbor is not deployed with Notary.
|
||||
func InternalNotaryEndpoint() string {
|
||||
return Ctl.GetString(backgroundCtx, common.NotaryURL)
|
||||
}
|
||||
|
||||
// TrivyAdapterURL returns the endpoint URL of a Trivy adapter instance, by default it's the one deployed within Harbor.
|
||||
func TrivyAdapterURL() string {
|
||||
return Ctl.GetString(backgroundCtx, common.TrivyAdapterURL)
|
||||
}
|
||||
|
||||
// Metric returns the overall metric settings
|
||||
func Metric() *models.Metric {
|
||||
return &models.Metric{
|
||||
Enabled: Ctl.GetBool(backgroundCtx, common.MetricEnable),
|
||||
Port: Ctl.GetInt(backgroundCtx, common.MetricPort),
|
||||
Path: Ctl.GetString(backgroundCtx, common.MetricPath),
|
||||
}
|
||||
}
|
||||
|
||||
// InitialAdminPassword returns the initial password for administrator
|
||||
func InitialAdminPassword() (string, error) {
|
||||
return Ctl.GetString(backgroundCtx, common.AdminInitialPassword), nil
|
||||
}
|
||||
|
||||
// Database returns database settings
|
||||
func Database() (*models.Database, error) {
|
||||
database := &models.Database{}
|
||||
database.Type = Ctl.GetString(backgroundCtx, common.DatabaseType)
|
||||
postgresql := &models.PostGreSQL{
|
||||
Host: Ctl.GetString(backgroundCtx, common.PostGreSQLHOST),
|
||||
Port: Ctl.GetInt(backgroundCtx, common.PostGreSQLPort),
|
||||
Username: Ctl.GetString(backgroundCtx, common.PostGreSQLUsername),
|
||||
Password: Ctl.GetString(backgroundCtx, common.PostGreSQLPassword),
|
||||
Database: Ctl.GetString(backgroundCtx, common.PostGreSQLDatabase),
|
||||
SSLMode: Ctl.GetString(backgroundCtx, common.PostGreSQLSSLMode),
|
||||
MaxIdleConns: Ctl.GetInt(backgroundCtx, common.PostGreSQLMaxIdleConns),
|
||||
MaxOpenConns: Ctl.GetInt(backgroundCtx, common.PostGreSQLMaxOpenConns),
|
||||
}
|
||||
database.PostGreSQL = postgresql
|
||||
|
||||
return database, nil
|
||||
}
|
145
src/controller/config/test/controller_test.go
Normal file
145
src/controller/config/test/controller_test.go
Normal file
@ -0,0 +1,145 @@
|
||||
// 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 test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/goharbor/harbor/src/common"
|
||||
. "github.com/goharbor/harbor/src/controller/config"
|
||||
"github.com/goharbor/harbor/src/lib/errors"
|
||||
htesting "github.com/goharbor/harbor/src/testing"
|
||||
"github.com/stretchr/testify/suite"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var TestDBConfig = map[string]interface{}{
|
||||
common.LDAPBaseDN: "dc=example,dc=com",
|
||||
common.LDAPURL: "ldap.example.com",
|
||||
common.EmailHost: "127.0.0.1",
|
||||
}
|
||||
|
||||
var TestConfigWithScanAll = map[string]interface{}{
|
||||
"postgresql_host": "localhost",
|
||||
"postgresql_database": "registry",
|
||||
"postgresql_password": "root123",
|
||||
"postgresql_username": "postgres",
|
||||
"postgresql_sslmode": "disable",
|
||||
"ldap_base_dn": "dc=example,dc=com",
|
||||
"ldap_url": "ldap.example.com",
|
||||
"email_host": "127.0.0.1",
|
||||
"scan_all_policy": `{"parameter":{"daily_time":0},"type":"daily"}`,
|
||||
}
|
||||
|
||||
var ctx context.Context
|
||||
|
||||
type controllerTestSuite struct {
|
||||
htesting.Suite
|
||||
controller Controller
|
||||
}
|
||||
|
||||
func (c *controllerTestSuite) SetupTest() {
|
||||
c.controller = Ctl
|
||||
ctx = c.Context()
|
||||
c.controller.UpdateUserConfigs(ctx, TestDBConfig)
|
||||
}
|
||||
|
||||
func (c *controllerTestSuite) TestGetUserCfg() {
|
||||
resp, err := c.controller.UserConfigs(ctx)
|
||||
if err != nil {
|
||||
c.Error(err, "failed to get user config")
|
||||
}
|
||||
c.Equal("dc=example,dc=com", resp["ldap_base_dn"].Val)
|
||||
c.Equal("127.0.0.1", resp["email_host"].Val)
|
||||
c.Equal("ldap.example.com", resp["ldap_url"].Val)
|
||||
}
|
||||
|
||||
func (c *controllerTestSuite) TestConvertForGet() {
|
||||
conf := map[string]interface{}{
|
||||
"ldap_url": "ldaps.myexample,com",
|
||||
"ldap_base_dn": "dc=myexample,dc=com",
|
||||
"auth_mode": "ldap_auth",
|
||||
"ldap_search_password": "admin",
|
||||
}
|
||||
|
||||
// password type should not sent to external api call
|
||||
resp, err := ConvertForGet(ctx, conf, false)
|
||||
c.Nil(err)
|
||||
c.Equal("ldaps.myexample,com", resp["ldap_url"].Val)
|
||||
c.Equal("ldap_auth", resp["auth_mode"].Val)
|
||||
_, exist := resp["ldap_search_password"]
|
||||
c.False(exist)
|
||||
|
||||
// password type should be sent to internal api call
|
||||
conf2 := map[string]interface{}{
|
||||
"ldap_url": "ldaps.myexample,com",
|
||||
"ldap_base_dn": "dc=myexample,dc=com",
|
||||
"auth_mode": "ldap_auth",
|
||||
"ldap_search_password": "admin",
|
||||
}
|
||||
resp2, err2 := ConvertForGet(ctx, conf2, true)
|
||||
c.Nil(err2)
|
||||
c.Equal("ldaps.myexample,com", resp2["ldap_url"].Val)
|
||||
c.Equal("ldap_auth", resp2["auth_mode"].Val)
|
||||
_, exist2 := resp2["ldap_search_password"]
|
||||
c.True(exist2)
|
||||
|
||||
}
|
||||
|
||||
func (c *controllerTestSuite) TestGetAll() {
|
||||
resp, err := c.controller.AllConfigs(ctx)
|
||||
if err != nil {
|
||||
c.Error(err, "failed to get user config")
|
||||
}
|
||||
c.Equal("dc=example,dc=com", resp["ldap_base_dn"])
|
||||
c.Equal("127.0.0.1", resp["email_host"])
|
||||
c.Equal("ldap.example.com", resp["ldap_url"])
|
||||
}
|
||||
|
||||
func (c *controllerTestSuite) TestUpdateUserCfg() {
|
||||
|
||||
userConf := map[string]interface{}{
|
||||
common.LDAPURL: "ldaps.myexample,com",
|
||||
common.LDAPBaseDN: "dc=myexample,dc=com",
|
||||
}
|
||||
err := c.controller.UpdateUserConfigs(ctx, userConf)
|
||||
c.Nil(err)
|
||||
cfgResp, err := c.controller.UserConfigs(ctx)
|
||||
if err != nil {
|
||||
c.Error(err, "failed to get user config")
|
||||
}
|
||||
c.Equal("dc=myexample,dc=com", cfgResp["ldap_base_dn"].Val)
|
||||
c.Equal("ldaps.myexample,com", cfgResp["ldap_url"].Val)
|
||||
badCfg := map[string]interface{}{
|
||||
common.LDAPScope: 5,
|
||||
}
|
||||
err2 := c.controller.UpdateUserConfigs(ctx, badCfg)
|
||||
c.NotNil(err2)
|
||||
c.True(errors.IsErr(err2, errors.BadRequestCode))
|
||||
}
|
||||
|
||||
/*func (c *controllerTestSuite) TestCheckUnmodifiable() {
|
||||
conf := map[string]interface{}{
|
||||
"ldap_url": "ldaps.myexample,com",
|
||||
"ldap_base_dn": "dc=myexample,dc=com",
|
||||
"auth_mode": "ldap_auth",
|
||||
}
|
||||
failed := c.controller.checkUnmodifiable(ctx, conf, "auth_mode")
|
||||
c.True(len(failed) > 0)
|
||||
c.Equal(failed[0], "auth_mode")
|
||||
}
|
||||
*/
|
||||
func TestControllerTestSuite(t *testing.T) {
|
||||
suite.Run(t, &controllerTestSuite{})
|
||||
}
|
282
src/controller/config/userconfig.go
Executable file
282
src/controller/config/userconfig.go
Executable file
@ -0,0 +1,282 @@
|
||||
// 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 config provide config for core api and other modules
|
||||
// Before accessing user settings, need to call Load()
|
||||
// For system settings, no need to call Load()
|
||||
package config
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
cfgModels "github.com/goharbor/harbor/src/lib/config/models"
|
||||
"github.com/goharbor/harbor/src/lib/orm"
|
||||
"github.com/goharbor/harbor/src/pkg/config"
|
||||
"github.com/goharbor/harbor/src/pkg/encrypt"
|
||||
"strings"
|
||||
|
||||
"github.com/goharbor/harbor/src/common"
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
"github.com/goharbor/harbor/src/common/secret"
|
||||
"github.com/goharbor/harbor/src/lib/log"
|
||||
"github.com/goharbor/harbor/src/pkg/ldap/model"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultKeyPath = "/etc/core/key"
|
||||
defaultRegistryTokenPrivateKeyPath = "/etc/core/private_key.pem"
|
||||
|
||||
// SessionCookieName is the name of the cookie for session ID
|
||||
SessionCookieName = "sid"
|
||||
)
|
||||
|
||||
var (
|
||||
// SecretStore manages secrets
|
||||
SecretStore *secret.Store
|
||||
keyProvider encrypt.KeyProvider
|
||||
// defined as a var for testing.
|
||||
defaultCACertPath = "/etc/core/ca/ca.crt"
|
||||
)
|
||||
|
||||
// Init configurations
|
||||
func Init() {
|
||||
// init key provider
|
||||
initKeyProvider()
|
||||
log.Info("init secret store")
|
||||
// init secret store
|
||||
initSecretStore()
|
||||
}
|
||||
|
||||
// InitWithSettings init config with predefined configs, and optionally overwrite the keyprovider
|
||||
func InitWithSettings(cfgs map[string]interface{}, kp ...encrypt.KeyProvider) {
|
||||
Init()
|
||||
Ctl = NewInMemoryController()
|
||||
mgr := Ctl.GetManager()
|
||||
mgr.UpdateConfig(backgroundCtx, cfgs)
|
||||
if len(kp) > 0 {
|
||||
keyProvider = kp[0]
|
||||
}
|
||||
}
|
||||
|
||||
// GetCfgManager return the current config manager
|
||||
func GetCfgManager(ctx context.Context) config.Manager {
|
||||
return Ctl.GetManager()
|
||||
}
|
||||
|
||||
// Load configurations
|
||||
func Load(ctx context.Context) error {
|
||||
return Ctl.Load(ctx)
|
||||
}
|
||||
|
||||
// Upload save all configurations, used by testing
|
||||
func Upload(cfg map[string]interface{}) error {
|
||||
mgr := Ctl.GetManager()
|
||||
return mgr.UpdateConfig(orm.Context(), cfg)
|
||||
}
|
||||
|
||||
// GetSystemCfg returns the system configurations
|
||||
func GetSystemCfg(ctx context.Context) (map[string]interface{}, error) {
|
||||
sysCfg, err := Ctl.AllConfigs(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(sysCfg) == 0 {
|
||||
return nil, errors.New("can not load system config, the database might be down")
|
||||
}
|
||||
return sysCfg, nil
|
||||
}
|
||||
|
||||
// AuthMode ...
|
||||
func AuthMode(ctx context.Context) (string, error) {
|
||||
err := Ctl.Load(ctx)
|
||||
if err != nil {
|
||||
log.Errorf("failed to load config, error %v", err)
|
||||
return "db_auth", err
|
||||
}
|
||||
return Ctl.GetString(ctx, common.AUTHMode), nil
|
||||
}
|
||||
|
||||
// LDAPConf returns the setting of ldap server
|
||||
func LDAPConf(ctx context.Context) (*model.LdapConf, error) {
|
||||
err := Ctl.Load(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &model.LdapConf{
|
||||
URL: Ctl.GetString(ctx, common.LDAPURL),
|
||||
SearchDn: Ctl.GetString(ctx, common.LDAPSearchDN),
|
||||
SearchPassword: Ctl.GetString(ctx, common.LDAPSearchPwd),
|
||||
BaseDn: Ctl.GetString(ctx, common.LDAPBaseDN),
|
||||
UID: Ctl.GetString(ctx, common.LDAPUID),
|
||||
Filter: Ctl.GetString(ctx, common.LDAPFilter),
|
||||
Scope: Ctl.GetInt(ctx, common.LDAPScope),
|
||||
ConnectionTimeout: Ctl.GetInt(ctx, common.LDAPTimeout),
|
||||
VerifyCert: Ctl.GetBool(ctx, common.LDAPVerifyCert),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// LDAPGroupConf returns the setting of ldap group search
|
||||
func LDAPGroupConf(ctx context.Context) (*model.GroupConf, error) {
|
||||
err := Ctl.Load(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &model.GroupConf{
|
||||
BaseDN: Ctl.GetString(ctx, common.LDAPGroupBaseDN),
|
||||
Filter: Ctl.GetString(ctx, common.LDAPGroupSearchFilter),
|
||||
NameAttribute: Ctl.GetString(ctx, common.LDAPGroupAttributeName),
|
||||
SearchScope: Ctl.GetInt(ctx, common.LDAPGroupSearchScope),
|
||||
AdminDN: Ctl.GetString(ctx, common.LDAPGroupAdminDn),
|
||||
MembershipAttribute: Ctl.GetString(ctx, common.LDAPGroupMembershipAttribute),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// TokenExpiration returns the token expiration time (in minute)
|
||||
func TokenExpiration(ctx context.Context) (int, error) {
|
||||
return Ctl.GetInt(ctx, common.TokenExpiration), nil
|
||||
}
|
||||
|
||||
// RobotTokenDuration returns the token expiration time of robot account (in minute)
|
||||
func RobotTokenDuration(ctx context.Context) int {
|
||||
return Ctl.GetInt(ctx, common.RobotTokenDuration)
|
||||
}
|
||||
|
||||
// SelfRegistration returns the enablement of self registration
|
||||
func SelfRegistration(ctx context.Context) (bool, error) {
|
||||
return Ctl.GetBool(ctx, common.SelfRegistration), nil
|
||||
}
|
||||
|
||||
// OnlyAdminCreateProject returns the flag to restrict that only sys admin can create project
|
||||
func OnlyAdminCreateProject(ctx context.Context) (bool, error) {
|
||||
err := Ctl.Load(ctx)
|
||||
if err != nil {
|
||||
return true, err
|
||||
}
|
||||
return Ctl.GetString(ctx, common.ProjectCreationRestriction) == common.ProCrtRestrAdmOnly, nil
|
||||
}
|
||||
|
||||
// Email returns email server settings
|
||||
func Email(ctx context.Context) (*cfgModels.Email, error) {
|
||||
err := Ctl.Load(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &cfgModels.Email{
|
||||
Host: Ctl.GetString(ctx, common.EmailHost),
|
||||
Port: Ctl.GetInt(ctx, common.EmailPort),
|
||||
Username: Ctl.GetString(ctx, common.EmailUsername),
|
||||
Password: Ctl.GetString(ctx, common.EmailPassword),
|
||||
SSL: Ctl.GetBool(ctx, common.EmailSSL),
|
||||
From: Ctl.GetString(ctx, common.EmailFrom),
|
||||
Identity: Ctl.GetString(ctx, common.EmailIdentity),
|
||||
Insecure: Ctl.GetBool(ctx, common.EmailInsecure),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UAASettings returns the UAASettings to access UAA service.
|
||||
func UAASettings(ctx context.Context) (*models.UAASettings, error) {
|
||||
err := Ctl.Load(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
us := &models.UAASettings{
|
||||
Endpoint: Ctl.GetString(ctx, common.UAAEndpoint),
|
||||
ClientID: Ctl.GetString(ctx, common.UAAClientID),
|
||||
ClientSecret: Ctl.GetString(ctx, common.UAAClientSecret),
|
||||
VerifyCert: Ctl.GetBool(ctx, common.UAAVerifyCert),
|
||||
}
|
||||
return us, nil
|
||||
}
|
||||
|
||||
// ReadOnly returns a bool to indicates if Harbor is in read only mode.
|
||||
func ReadOnly(ctx context.Context) bool {
|
||||
return Ctl.GetBool(ctx, common.ReadOnly)
|
||||
}
|
||||
|
||||
// HTTPAuthProxySetting returns the setting of HTTP Auth proxy. the settings are only meaningful when the auth_mode is
|
||||
// set to http_auth
|
||||
func HTTPAuthProxySetting(ctx context.Context) (*cfgModels.HTTPAuthProxy, error) {
|
||||
if err := Ctl.Load(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &cfgModels.HTTPAuthProxy{
|
||||
Endpoint: Ctl.GetString(ctx, common.HTTPAuthProxyEndpoint),
|
||||
TokenReviewEndpoint: Ctl.GetString(ctx, common.HTTPAuthProxyTokenReviewEndpoint),
|
||||
AdminGroups: splitAndTrim(Ctl.GetString(ctx, common.HTTPAuthProxyAdminGroups), ","),
|
||||
AdminUsernames: splitAndTrim(Ctl.GetString(ctx, common.HTTPAuthProxyAdminUsernames), ","),
|
||||
VerifyCert: Ctl.GetBool(ctx, common.HTTPAuthProxyVerifyCert),
|
||||
SkipSearch: Ctl.GetBool(ctx, common.HTTPAuthProxySkipSearch),
|
||||
ServerCertificate: Ctl.GetString(ctx, common.HTTPAuthProxyServerCertificate),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// OIDCSetting returns the setting of OIDC provider, currently there's only one OIDC provider allowed for Harbor and it's
|
||||
// only effective when auth_mode is set to oidc_auth
|
||||
func OIDCSetting(ctx context.Context) (*cfgModels.OIDCSetting, error) {
|
||||
if err := Ctl.Load(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
scopeStr := Ctl.GetString(ctx, common.OIDCScope)
|
||||
extEndpoint := strings.TrimSuffix(Ctl.GetString(nil, common.ExtEndpoint), "/")
|
||||
scope := splitAndTrim(scopeStr, ",")
|
||||
return &cfgModels.OIDCSetting{
|
||||
Name: Ctl.GetString(ctx, common.OIDCName),
|
||||
Endpoint: Ctl.GetString(ctx, common.OIDCEndpoint),
|
||||
VerifyCert: Ctl.GetBool(ctx, common.OIDCVerifyCert),
|
||||
AutoOnboard: Ctl.GetBool(ctx, common.OIDCAutoOnboard),
|
||||
ClientID: Ctl.GetString(ctx, common.OIDCCLientID),
|
||||
ClientSecret: Ctl.GetString(ctx, common.OIDCClientSecret),
|
||||
GroupsClaim: Ctl.GetString(ctx, common.OIDCGroupsClaim),
|
||||
AdminGroup: Ctl.GetString(ctx, common.OIDCAdminGroup),
|
||||
RedirectURL: extEndpoint + common.OIDCCallbackPath,
|
||||
Scope: scope,
|
||||
UserClaim: Ctl.GetString(ctx, common.OIDCUserClaim),
|
||||
ExtraRedirectParms: Ctl.Get(ctx, common.OIDCExtraRedirectParms).GetStringToStringMap(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// NotificationEnable returns a bool to indicates if notification enabled in harbor
|
||||
func NotificationEnable(ctx context.Context) bool {
|
||||
return Ctl.GetBool(ctx, common.NotificationEnable)
|
||||
}
|
||||
|
||||
// QuotaPerProjectEnable returns a bool to indicates if quota per project enabled in harbor
|
||||
func QuotaPerProjectEnable(ctx context.Context) bool {
|
||||
return Ctl.GetBool(ctx, common.QuotaPerProjectEnable)
|
||||
}
|
||||
|
||||
// QuotaSetting returns the setting of quota.
|
||||
func QuotaSetting(ctx context.Context) (*cfgModels.QuotaSetting, error) {
|
||||
if err := Ctl.Load(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &cfgModels.QuotaSetting{
|
||||
StoragePerProject: Ctl.Get(ctx, common.StoragePerProject).GetInt64(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// RobotPrefix user defined robot name prefix.
|
||||
func RobotPrefix(ctx context.Context) string {
|
||||
return Ctl.GetString(ctx, common.RobotNamePrefix)
|
||||
}
|
||||
|
||||
func splitAndTrim(s, sep string) []string {
|
||||
res := make([]string, 0)
|
||||
for _, s := range strings.Split(s, sep) {
|
||||
if e := strings.TrimSpace(s); len(e) > 0 {
|
||||
res = append(res, e)
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
@ -1,19 +1,21 @@
|
||||
// Copyright 2018 Project Harbor Authors
|
||||
// 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
|
||||
// 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
|
||||
// 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.
|
||||
// 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 config
|
||||
|
||||
import (
|
||||
"github.com/goharbor/harbor/src/lib/config/models"
|
||||
"github.com/goharbor/harbor/src/lib/orm"
|
||||
"os"
|
||||
"path"
|
||||
"runtime"
|
||||
@ -21,8 +23,8 @@ import (
|
||||
|
||||
"github.com/goharbor/harbor/src/common"
|
||||
"github.com/goharbor/harbor/src/common/dao"
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
"github.com/goharbor/harbor/src/common/utils/test"
|
||||
_ "github.com/goharbor/harbor/src/pkg/config/inmemory"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
@ -62,8 +64,8 @@ func TestConfig(t *testing.T) {
|
||||
os.Setenv("GC_TIME_WINDOW_HOURS", "0")
|
||||
|
||||
Init()
|
||||
|
||||
if err := Load(); err != nil {
|
||||
ctx := orm.Context()
|
||||
if err := Load(ctx); err != nil {
|
||||
t.Fatalf("failed to load configurations: %v", err)
|
||||
}
|
||||
|
||||
@ -71,11 +73,10 @@ func TestConfig(t *testing.T) {
|
||||
t.Fatalf("failed to upload configurations: %v", err)
|
||||
}
|
||||
|
||||
if _, err := GetSystemCfg(); err != nil {
|
||||
if _, err := GetSystemCfg(ctx); err != nil {
|
||||
t.Fatalf("failed to get system configurations: %v", err)
|
||||
}
|
||||
|
||||
mode, err := AuthMode()
|
||||
mode, err := AuthMode(ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to get auth mode: %v", err)
|
||||
}
|
||||
@ -83,19 +84,19 @@ func TestConfig(t *testing.T) {
|
||||
t.Errorf("unexpected mode: %s != %s", mode, "db_auth")
|
||||
}
|
||||
|
||||
if _, err := LDAPConf(); err != nil {
|
||||
if _, err := LDAPConf(ctx); err != nil {
|
||||
t.Fatalf("failed to get ldap settings: %v", err)
|
||||
}
|
||||
|
||||
if _, err := LDAPGroupConf(); err != nil {
|
||||
if _, err := LDAPGroupConf(ctx); err != nil {
|
||||
t.Fatalf("failed to get ldap group settings: %v", err)
|
||||
}
|
||||
|
||||
if _, err := TokenExpiration(); err != nil {
|
||||
if _, err := TokenExpiration(ctx); err != nil {
|
||||
t.Fatalf("failed to get token expiration: %v", err)
|
||||
}
|
||||
|
||||
tkExp := RobotTokenDuration()
|
||||
tkExp := RobotTokenDuration(ctx)
|
||||
assert.Equal(tkExp, 30)
|
||||
|
||||
if _, err := ExtEndpoint(); err != nil {
|
||||
@ -106,7 +107,7 @@ func TestConfig(t *testing.T) {
|
||||
t.Fatalf("failed to get secret key: %v", err)
|
||||
}
|
||||
|
||||
if _, err := SelfRegistration(); err != nil {
|
||||
if _, err := SelfRegistration(ctx); err != nil {
|
||||
t.Fatalf("failed to get self registration: %v", err)
|
||||
}
|
||||
|
||||
@ -126,11 +127,11 @@ func TestConfig(t *testing.T) {
|
||||
t.Fatalf("failed to get initial admin password: %v", err)
|
||||
}
|
||||
|
||||
if _, err := OnlyAdminCreateProject(); err != nil {
|
||||
if _, err := OnlyAdminCreateProject(ctx); err != nil {
|
||||
t.Fatalf("failed to get onldy admin create project: %v", err)
|
||||
}
|
||||
|
||||
if _, err := Email(); err != nil {
|
||||
if _, err := Email(ctx); err != nil {
|
||||
t.Fatalf("failed to get email settings: %v", err)
|
||||
}
|
||||
|
||||
@ -150,7 +151,7 @@ func TestConfig(t *testing.T) {
|
||||
if WithTrivy() {
|
||||
t.Errorf("WithTrivy should be false")
|
||||
}
|
||||
if ReadOnly() {
|
||||
if ReadOnly(ctx) {
|
||||
t.Errorf("ReadOnly should be false")
|
||||
}
|
||||
|
||||
@ -162,7 +163,7 @@ func TestConfig(t *testing.T) {
|
||||
t.Errorf(`extURL should be "host01.com".`)
|
||||
}
|
||||
|
||||
mode, err = AuthMode()
|
||||
mode, err = AuthMode(ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to get auth mode: %v", err)
|
||||
}
|
||||
@ -174,7 +175,7 @@ func TestConfig(t *testing.T) {
|
||||
t.Errorf("Unexpected token private key path: %s, expected: %s", tokenKeyPath, "/etc/core/private_key.pem")
|
||||
}
|
||||
|
||||
us, err := UAASettings()
|
||||
us, err := UAASettings(ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to get UAA setting, error: %v", err)
|
||||
}
|
||||
@ -188,9 +189,9 @@ func TestConfig(t *testing.T) {
|
||||
localCoreURL := LocalCoreURL()
|
||||
assert.Equal("http://127.0.0.1:8080", localCoreURL)
|
||||
|
||||
assert.True(NotificationEnable())
|
||||
assert.True(NotificationEnable(ctx))
|
||||
assert.Equal(int64(0), GetGCTimeWindow())
|
||||
assert.Equal("robot$", RobotPrefix())
|
||||
assert.Equal("robot$", RobotPrefix(ctx))
|
||||
|
||||
}
|
||||
|
||||
@ -243,7 +244,7 @@ y1bQusZMygQezfCuEzsewF+OpANFovCTUEs6s5vyoVNP8lk=
|
||||
common.HTTPAuthProxyServerCertificate: certificate,
|
||||
}
|
||||
InitWithSettings(m)
|
||||
v, e := HTTPAuthProxySetting()
|
||||
v, e := HTTPAuthProxySetting(orm.Context())
|
||||
assert.Nil(t, e)
|
||||
assert.Equal(t, *v, models.HTTPAuthProxy{
|
||||
Endpoint: "https://auth.proxy/suffix",
|
||||
@ -269,7 +270,7 @@ func TestOIDCSetting(t *testing.T) {
|
||||
common.ExtEndpoint: "https://harbor.test",
|
||||
}
|
||||
InitWithSettings(m)
|
||||
v, e := OIDCSetting()
|
||||
v, e := OIDCSetting(orm.Context())
|
||||
assert.Nil(t, e)
|
||||
assert.Equal(t, "test", v.Name)
|
||||
assert.Equal(t, "https://oidc.test", v.Endpoint)
|
@ -3,19 +3,22 @@ package util
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/goharbor/harbor/src/core/config"
|
||||
"strings"
|
||||
|
||||
"github.com/goharbor/harbor/src/controller/config"
|
||||
"github.com/goharbor/harbor/src/lib/orm"
|
||||
|
||||
"github.com/goharbor/harbor/src/lib/log"
|
||||
"github.com/goharbor/harbor/src/pkg/distribution"
|
||||
policy_model "github.com/goharbor/harbor/src/pkg/notification/policy/model"
|
||||
"github.com/goharbor/harbor/src/pkg/notifier/event"
|
||||
notifyModel "github.com/goharbor/harbor/src/pkg/notifier/model"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// SendHookWithPolicies send hook by publishing topic of specified target type(notify type)
|
||||
func SendHookWithPolicies(policies []*policy_model.Policy, payload *notifyModel.Payload, eventType string) error {
|
||||
// if global notification configured disabled, return directly
|
||||
if !config.NotificationEnable() {
|
||||
if !config.NotificationEnable(orm.Context()) {
|
||||
log.Debug("notification feature is not enabled")
|
||||
return nil
|
||||
}
|
||||
|
@ -1,12 +1,20 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"github.com/goharbor/harbor/src/common/utils/test"
|
||||
"github.com/goharbor/harbor/src/controller/config"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/goharbor/harbor/src/common"
|
||||
"github.com/goharbor/harbor/src/core/config"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
// do some initialization
|
||||
test.InitDatabaseFromEnv()
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
|
||||
func TestBuildImageResourceURL(t *testing.T) {
|
||||
cfg := map[string]interface{}{
|
||||
common.ExtEndpoint: "https://demo.goharbor.io",
|
||||
|
@ -6,13 +6,14 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/goharbor/harbor/src/controller/config"
|
||||
|
||||
commonModels "github.com/goharbor/harbor/src/common/models"
|
||||
"github.com/goharbor/harbor/src/controller/event"
|
||||
"github.com/goharbor/harbor/src/controller/event/handler/util"
|
||||
ctlModel "github.com/goharbor/harbor/src/controller/event/model"
|
||||
"github.com/goharbor/harbor/src/controller/project"
|
||||
"github.com/goharbor/harbor/src/controller/replication"
|
||||
"github.com/goharbor/harbor/src/core/config"
|
||||
"github.com/goharbor/harbor/src/jobservice/job"
|
||||
"github.com/goharbor/harbor/src/lib/log"
|
||||
"github.com/goharbor/harbor/src/lib/orm"
|
||||
@ -33,7 +34,7 @@ func (r *ReplicationHandler) Name() string {
|
||||
|
||||
// Handle ...
|
||||
func (r *ReplicationHandler) Handle(ctx context.Context, value interface{}) error {
|
||||
if !config.NotificationEnable() {
|
||||
if !config.NotificationEnable(ctx) {
|
||||
log.Debug("notification feature is not enabled")
|
||||
return nil
|
||||
}
|
||||
|
@ -19,13 +19,14 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/goharbor/harbor/src/controller/config"
|
||||
|
||||
common_dao "github.com/goharbor/harbor/src/common/dao"
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
"github.com/goharbor/harbor/src/controller/event"
|
||||
"github.com/goharbor/harbor/src/controller/project"
|
||||
repctl "github.com/goharbor/harbor/src/controller/replication"
|
||||
repctlmodel "github.com/goharbor/harbor/src/controller/replication/model"
|
||||
"github.com/goharbor/harbor/src/core/config"
|
||||
"github.com/goharbor/harbor/src/pkg/notification"
|
||||
policy_model "github.com/goharbor/harbor/src/pkg/notification/policy/model"
|
||||
projecttesting "github.com/goharbor/harbor/src/testing/controller/project"
|
||||
|
@ -3,14 +3,15 @@ package artifact
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/goharbor/harbor/src/controller/config"
|
||||
"github.com/goharbor/harbor/src/controller/retention"
|
||||
"github.com/goharbor/harbor/src/lib/orm"
|
||||
"strings"
|
||||
|
||||
"github.com/goharbor/harbor/src/controller/event"
|
||||
"github.com/goharbor/harbor/src/controller/event/handler/util"
|
||||
evtModel "github.com/goharbor/harbor/src/controller/event/model"
|
||||
"github.com/goharbor/harbor/src/core/config"
|
||||
"github.com/goharbor/harbor/src/lib/errors"
|
||||
"github.com/goharbor/harbor/src/lib/log"
|
||||
"github.com/goharbor/harbor/src/pkg/notification"
|
||||
@ -28,7 +29,7 @@ func (r *RetentionHandler) Name() string {
|
||||
|
||||
// Handle ...
|
||||
func (r *RetentionHandler) Handle(ctx context.Context, value interface{}) error {
|
||||
if !config.NotificationEnable() {
|
||||
if !config.NotificationEnable(ctx) {
|
||||
log.Debug("notification feature is not enabled")
|
||||
return nil
|
||||
}
|
||||
|
@ -2,10 +2,16 @@ package artifact
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/goharbor/harbor/src/common/dao"
|
||||
"github.com/goharbor/harbor/src/controller/config"
|
||||
|
||||
"github.com/goharbor/harbor/src/controller/event"
|
||||
"github.com/goharbor/harbor/src/controller/retention"
|
||||
"github.com/goharbor/harbor/src/core/config"
|
||||
|
||||
"github.com/goharbor/harbor/src/lib/selector"
|
||||
"github.com/goharbor/harbor/src/pkg/notification"
|
||||
policy_model "github.com/goharbor/harbor/src/pkg/notification/policy/model"
|
||||
@ -15,9 +21,6 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"github.com/stretchr/testify/require"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestRetentionHandler_Handle(t *testing.T) {
|
||||
|
@ -18,12 +18,12 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/goharbor/harbor/src/controller/config"
|
||||
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
"github.com/goharbor/harbor/src/controller/event"
|
||||
"github.com/goharbor/harbor/src/controller/event/handler/util"
|
||||
"github.com/goharbor/harbor/src/controller/project"
|
||||
"github.com/goharbor/harbor/src/core/config"
|
||||
"github.com/goharbor/harbor/src/lib/log"
|
||||
"github.com/goharbor/harbor/src/pkg/notification"
|
||||
"github.com/goharbor/harbor/src/pkg/notifier/model"
|
||||
|
@ -16,12 +16,14 @@ package chart
|
||||
|
||||
import (
|
||||
"context"
|
||||
testutils "github.com/goharbor/harbor/src/common/utils/test"
|
||||
"github.com/goharbor/harbor/src/controller/config"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
"github.com/goharbor/harbor/src/controller/event"
|
||||
"github.com/goharbor/harbor/src/controller/project"
|
||||
"github.com/goharbor/harbor/src/core/config"
|
||||
"github.com/goharbor/harbor/src/pkg/notification"
|
||||
"github.com/goharbor/harbor/src/pkg/notification/policy/model"
|
||||
projecttesting "github.com/goharbor/harbor/src/testing/controller/project"
|
||||
@ -31,6 +33,12 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
// do some initialization
|
||||
testutils.InitDatabaseFromEnv()
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
|
||||
func TestChartPreprocessHandler_Handle(t *testing.T) {
|
||||
PolicyMgr := notification.PolicyMgr
|
||||
defer func() {
|
||||
|
@ -17,6 +17,7 @@ package quota
|
||||
import (
|
||||
"context"
|
||||
common_dao "github.com/goharbor/harbor/src/common/dao"
|
||||
"github.com/goharbor/harbor/src/controller/config"
|
||||
"github.com/goharbor/harbor/src/controller/event"
|
||||
policy_model "github.com/goharbor/harbor/src/pkg/notification/policy/model"
|
||||
"github.com/goharbor/harbor/src/testing/mock"
|
||||
@ -25,7 +26,6 @@ import (
|
||||
|
||||
"github.com/goharbor/harbor/src/common"
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
"github.com/goharbor/harbor/src/core/config"
|
||||
"github.com/goharbor/harbor/src/pkg/notification"
|
||||
"github.com/goharbor/harbor/src/pkg/notification/policy"
|
||||
"github.com/goharbor/harbor/src/pkg/notifier"
|
||||
|
@ -17,6 +17,7 @@ package scan
|
||||
import (
|
||||
"context"
|
||||
common_dao "github.com/goharbor/harbor/src/common/dao"
|
||||
"github.com/goharbor/harbor/src/controller/config"
|
||||
"github.com/goharbor/harbor/src/controller/event"
|
||||
policy_model "github.com/goharbor/harbor/src/pkg/notification/policy/model"
|
||||
"testing"
|
||||
@ -25,7 +26,6 @@ import (
|
||||
"github.com/goharbor/harbor/src/common"
|
||||
"github.com/goharbor/harbor/src/controller/artifact"
|
||||
sc "github.com/goharbor/harbor/src/controller/scan"
|
||||
"github.com/goharbor/harbor/src/core/config"
|
||||
"github.com/goharbor/harbor/src/pkg/notification"
|
||||
"github.com/goharbor/harbor/src/pkg/notification/policy"
|
||||
"github.com/goharbor/harbor/src/pkg/notifier"
|
||||
|
@ -4,9 +4,9 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/goharbor/harbor/src/controller/config"
|
||||
|
||||
"github.com/goharbor/harbor/src/controller/quota"
|
||||
"github.com/goharbor/harbor/src/core/config"
|
||||
"github.com/goharbor/harbor/src/jobservice/job"
|
||||
"github.com/goharbor/harbor/src/lib/log"
|
||||
"github.com/goharbor/harbor/src/lib/orm"
|
||||
@ -39,7 +39,7 @@ func gcCallback(ctx context.Context, p string) error {
|
||||
}
|
||||
|
||||
func gcTaskStatusChange(ctx context.Context, taskID int64, status string) error {
|
||||
if status == job.SuccessStatus.String() && config.QuotaPerProjectEnable() {
|
||||
if status == job.SuccessStatus.String() && config.QuotaPerProjectEnable(ctx) {
|
||||
go func() {
|
||||
quota.RefreshForProjects(orm.Context())
|
||||
}()
|
||||
|
@ -17,7 +17,7 @@ package ldap
|
||||
import (
|
||||
"context"
|
||||
"github.com/goharbor/harbor/src/common"
|
||||
"github.com/goharbor/harbor/src/core/config"
|
||||
"github.com/goharbor/harbor/src/controller/config"
|
||||
"github.com/goharbor/harbor/src/lib/log"
|
||||
"github.com/goharbor/harbor/src/pkg/ldap"
|
||||
"github.com/goharbor/harbor/src/pkg/ldap/model"
|
||||
@ -52,7 +52,7 @@ func NewController() Controller {
|
||||
}
|
||||
|
||||
func (c *controller) Session(ctx context.Context) (*ldap.Session, error) {
|
||||
cfg, groupCfg, err := c.ldapConfigs()
|
||||
cfg, groupCfg, err := c.ldapConfigs(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -61,7 +61,7 @@ func (c *controller) Session(ctx context.Context) (*ldap.Session, error) {
|
||||
|
||||
func (c *controller) Ping(ctx context.Context, cfg model.LdapConf) (bool, error) {
|
||||
if len(cfg.SearchPassword) == 0 {
|
||||
pwd, err := defaultPassword()
|
||||
pwd, err := defaultPassword(ctx)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
@ -73,12 +73,12 @@ func (c *controller) Ping(ctx context.Context, cfg model.LdapConf) (bool, error)
|
||||
return c.mgr.Ping(ctx, cfg)
|
||||
}
|
||||
|
||||
func (c *controller) ldapConfigs() (*model.LdapConf, *model.GroupConf, error) {
|
||||
cfg, err := config.LDAPConf()
|
||||
func (c *controller) ldapConfigs(ctx context.Context) (*model.LdapConf, *model.GroupConf, error) {
|
||||
cfg, err := config.LDAPConf(ctx)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
groupCfg, err := config.LDAPGroupConf()
|
||||
groupCfg, err := config.LDAPGroupConf(ctx)
|
||||
if err != nil {
|
||||
log.Warningf("failed to get the ldap group config, error %v", err)
|
||||
groupCfg = &model.GroupConf{}
|
||||
@ -87,20 +87,20 @@ func (c *controller) ldapConfigs() (*model.LdapConf, *model.GroupConf, error) {
|
||||
}
|
||||
|
||||
func (c *controller) SearchUser(ctx context.Context, username string) ([]model.User, error) {
|
||||
cfg, groupCfg, err := c.ldapConfigs()
|
||||
cfg, groupCfg, err := c.ldapConfigs(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c.mgr.SearchUser(ctx, ldap.NewSession(*cfg, *groupCfg), username)
|
||||
}
|
||||
|
||||
func defaultPassword() (string, error) {
|
||||
mod, err := config.AuthMode()
|
||||
func defaultPassword(ctx context.Context) (string, error) {
|
||||
mod, err := config.AuthMode(ctx)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if mod == common.LDAPAuth {
|
||||
conf, err := config.LDAPConf()
|
||||
conf, err := config.LDAPConf(ctx)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@ -113,7 +113,7 @@ func defaultPassword() (string, error) {
|
||||
}
|
||||
|
||||
func (c *controller) ImportUser(ctx context.Context, ldapImportUsers []string) ([]model.FailedImportUser, error) {
|
||||
cfg, groupCfg, err := c.ldapConfigs()
|
||||
cfg, groupCfg, err := c.ldapConfigs(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -121,7 +121,7 @@ func (c *controller) ImportUser(ctx context.Context, ldapImportUsers []string) (
|
||||
}
|
||||
|
||||
func (c *controller) SearchGroup(ctx context.Context, groupName, groupDN string) ([]model.Group, error) {
|
||||
cfg, groupCfg, err := c.ldapConfigs()
|
||||
cfg, groupCfg, err := c.ldapConfigs(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ package ldap
|
||||
|
||||
import (
|
||||
"github.com/goharbor/harbor/src/common"
|
||||
"github.com/goharbor/harbor/src/core/config"
|
||||
"github.com/goharbor/harbor/src/controller/config"
|
||||
"github.com/goharbor/harbor/src/pkg/ldap/model"
|
||||
htesting "github.com/goharbor/harbor/src/testing"
|
||||
"github.com/goharbor/harbor/src/testing/mock"
|
||||
|
@ -4,11 +4,11 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/goharbor/harbor/src/controller/config"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/goharbor/harbor/src/core/config"
|
||||
"github.com/goharbor/harbor/src/lib/orm"
|
||||
"github.com/goharbor/harbor/src/lib/q"
|
||||
"github.com/goharbor/harbor/src/pkg/p2p/preheat/models/policy"
|
||||
|
@ -17,6 +17,8 @@ package preheat
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/goharbor/harbor/src/controller/config"
|
||||
"github.com/goharbor/harbor/src/lib/orm"
|
||||
"strings"
|
||||
|
||||
tk "github.com/docker/distribution/registry/auth/token"
|
||||
@ -25,7 +27,6 @@ import (
|
||||
"github.com/goharbor/harbor/src/controller/project"
|
||||
"github.com/goharbor/harbor/src/controller/scan"
|
||||
"github.com/goharbor/harbor/src/controller/tag"
|
||||
"github.com/goharbor/harbor/src/core/config"
|
||||
"github.com/goharbor/harbor/src/core/service/token"
|
||||
"github.com/goharbor/harbor/src/jobservice/job"
|
||||
"github.com/goharbor/harbor/src/lib/errors"
|
||||
@ -170,7 +171,7 @@ func NewEnforcer() Enforcer {
|
||||
Actions: []string{resourcePullAction},
|
||||
},
|
||||
}
|
||||
t, err := token.MakeToken("distributor", token.Registry, ac)
|
||||
t, err := token.MakeToken(orm.Context(), "distributor", token.Registry, ac)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
@ -18,8 +18,8 @@ import (
|
||||
"context"
|
||||
"github.com/docker/distribution"
|
||||
"github.com/goharbor/harbor/src/controller/artifact"
|
||||
"github.com/goharbor/harbor/src/controller/config"
|
||||
"github.com/goharbor/harbor/src/controller/event/metadata"
|
||||
"github.com/goharbor/harbor/src/core/config"
|
||||
"github.com/goharbor/harbor/src/lib"
|
||||
"github.com/goharbor/harbor/src/lib/cache"
|
||||
"github.com/goharbor/harbor/src/lib/errors"
|
||||
|
@ -17,10 +17,11 @@ package project
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/goharbor/harbor/src/lib/config"
|
||||
"github.com/goharbor/harbor/src/pkg/config/db"
|
||||
"strconv"
|
||||
|
||||
"github.com/goharbor/harbor/src/common"
|
||||
"github.com/goharbor/harbor/src/common/config"
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
"github.com/goharbor/harbor/src/controller/blob"
|
||||
"github.com/goharbor/harbor/src/lib/log"
|
||||
@ -34,7 +35,7 @@ func init() {
|
||||
}
|
||||
|
||||
type driver struct {
|
||||
cfg *config.CfgManager
|
||||
cfg config.Manager
|
||||
loader *dataloader.Loader
|
||||
|
||||
blobCtl blob.Controller
|
||||
@ -42,20 +43,20 @@ type driver struct {
|
||||
|
||||
func (d *driver) Enabled(ctx context.Context, key string) (bool, error) {
|
||||
// NOTE: every time load the new configurations from the db to get the latest configurations may have performance problem.
|
||||
if err := d.cfg.Load(); err != nil {
|
||||
if err := d.cfg.Load(ctx); err != nil {
|
||||
return false, err
|
||||
}
|
||||
return d.cfg.Get(common.QuotaPerProjectEnable).GetBool(), nil
|
||||
return d.cfg.Get(ctx, common.QuotaPerProjectEnable).GetBool(), nil
|
||||
}
|
||||
|
||||
func (d *driver) HardLimits(ctx context.Context) types.ResourceList {
|
||||
// NOTE: every time load the new configurations from the db to get the latest configurations may have performance problem.
|
||||
if err := d.cfg.Load(); err != nil {
|
||||
if err := d.cfg.Load(ctx); err != nil {
|
||||
log.Warningf("load configurations failed, error: %v", err)
|
||||
}
|
||||
|
||||
return types.ResourceList{
|
||||
types.ResourceStorage: d.cfg.Get(common.StoragePerProject).GetInt64(),
|
||||
types.ResourceStorage: d.cfg.Get(ctx, common.StoragePerProject).GetInt64(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -118,7 +119,7 @@ func (d *driver) CalculateUsage(ctx context.Context, key string) (types.Resource
|
||||
}
|
||||
|
||||
func newDriver() dr.Driver {
|
||||
cfg := config.NewDBCfgManager()
|
||||
cfg := db.NewDBCfgManager()
|
||||
|
||||
loader := dataloader.NewBatchedLoader(getProjectsBatchFn, dataloader.WithClearCacheOnBatch())
|
||||
|
||||
|
@ -5,7 +5,7 @@ import (
|
||||
"fmt"
|
||||
rbac_project "github.com/goharbor/harbor/src/common/rbac/project"
|
||||
"github.com/goharbor/harbor/src/common/utils"
|
||||
"github.com/goharbor/harbor/src/core/config"
|
||||
"github.com/goharbor/harbor/src/controller/config"
|
||||
"github.com/goharbor/harbor/src/lib/errors"
|
||||
"github.com/goharbor/harbor/src/lib/log"
|
||||
"github.com/goharbor/harbor/src/lib/q"
|
||||
@ -85,8 +85,8 @@ func (d *controller) Create(ctx context.Context, r *Robot) (int64, string, error
|
||||
expiresAt = -1
|
||||
} else if r.Duration == 0 {
|
||||
// system default robot duration
|
||||
r.Duration = int64(config.RobotTokenDuration())
|
||||
expiresAt = time.Now().AddDate(0, 0, config.RobotTokenDuration()).Unix()
|
||||
r.Duration = int64(config.RobotTokenDuration(ctx))
|
||||
expiresAt = time.Now().AddDate(0, 0, config.RobotTokenDuration(ctx)).Unix()
|
||||
} else {
|
||||
expiresAt = time.Now().AddDate(0, 0, int(r.Duration)).Unix()
|
||||
}
|
||||
@ -216,7 +216,7 @@ func (d *controller) populate(ctx context.Context, r *model.Robot, option *Optio
|
||||
// for the v2 robots, add prefix to the robot name
|
||||
// for the v1 legacy robots, keep the robot name
|
||||
if robot.Editable {
|
||||
robot.Name = fmt.Sprintf("%s%s", config.RobotPrefix(), r.Name)
|
||||
robot.Name = fmt.Sprintf("%s%s", config.RobotPrefix(ctx), r.Name)
|
||||
} else {
|
||||
robot.Name = r.Name
|
||||
}
|
||||
|
@ -6,12 +6,12 @@ import (
|
||||
"github.com/goharbor/harbor/src/common"
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
"github.com/goharbor/harbor/src/common/utils/test"
|
||||
"github.com/goharbor/harbor/src/core/config"
|
||||
core_cfg "github.com/goharbor/harbor/src/core/config"
|
||||
"github.com/goharbor/harbor/src/controller/config"
|
||||
"github.com/goharbor/harbor/src/lib/q"
|
||||
"github.com/goharbor/harbor/src/pkg/permission/types"
|
||||
rbac_model "github.com/goharbor/harbor/src/pkg/rbac/model"
|
||||
"github.com/goharbor/harbor/src/pkg/robot/model"
|
||||
htesting "github.com/goharbor/harbor/src/testing"
|
||||
"github.com/goharbor/harbor/src/testing/mock"
|
||||
"github.com/goharbor/harbor/src/testing/pkg/project"
|
||||
"github.com/goharbor/harbor/src/testing/pkg/rbac"
|
||||
@ -22,7 +22,7 @@ import (
|
||||
)
|
||||
|
||||
type ControllerTestSuite struct {
|
||||
suite.Suite
|
||||
htesting.Suite
|
||||
}
|
||||
|
||||
func (suite *ControllerTestSuite) TestGet() {
|
||||
@ -92,7 +92,7 @@ func (suite *ControllerTestSuite) TestCreate() {
|
||||
conf := map[string]interface{}{
|
||||
common.RobotTokenDuration: "30",
|
||||
}
|
||||
core_cfg.InitWithSettings(conf)
|
||||
config.InitWithSettings(conf)
|
||||
|
||||
projectMgr := &project.Manager{}
|
||||
rbacMgr := &rbac.Manager{}
|
||||
|
@ -3,12 +3,13 @@ package robot
|
||||
import (
|
||||
"github.com/goharbor/harbor/src/pkg/permission/types"
|
||||
"github.com/goharbor/harbor/src/pkg/robot/model"
|
||||
htesting "github.com/goharbor/harbor/src/testing"
|
||||
"github.com/stretchr/testify/suite"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type ModelTestSuite struct {
|
||||
suite.Suite
|
||||
htesting.Suite
|
||||
}
|
||||
|
||||
func (suite *ModelTestSuite) TestSetLevel() {
|
||||
|
@ -18,6 +18,7 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/goharbor/harbor/src/controller/config"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
@ -25,7 +26,6 @@ import (
|
||||
ar "github.com/goharbor/harbor/src/controller/artifact"
|
||||
"github.com/goharbor/harbor/src/controller/robot"
|
||||
sc "github.com/goharbor/harbor/src/controller/scanner"
|
||||
"github.com/goharbor/harbor/src/core/config"
|
||||
"github.com/goharbor/harbor/src/jobservice/job"
|
||||
"github.com/goharbor/harbor/src/lib"
|
||||
"github.com/goharbor/harbor/src/lib/errors"
|
||||
|
@ -19,6 +19,7 @@ import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/goharbor/harbor/src/controller/config"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@ -26,7 +27,6 @@ import (
|
||||
"github.com/goharbor/harbor/src/common/rbac"
|
||||
"github.com/goharbor/harbor/src/controller/artifact"
|
||||
"github.com/goharbor/harbor/src/controller/robot"
|
||||
"github.com/goharbor/harbor/src/core/config"
|
||||
"github.com/goharbor/harbor/src/lib/orm"
|
||||
"github.com/goharbor/harbor/src/lib/q"
|
||||
"github.com/goharbor/harbor/src/pkg/permission/types"
|
||||
|
@ -17,14 +17,14 @@ package systeminfo
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/goharbor/harbor/src/controller/config"
|
||||
"github.com/goharbor/harbor/src/lib/config/models"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/goharbor/harbor/src/common"
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
"github.com/goharbor/harbor/src/common/utils"
|
||||
"github.com/goharbor/harbor/src/core/config"
|
||||
"github.com/goharbor/harbor/src/lib/errors"
|
||||
"github.com/goharbor/harbor/src/lib/log"
|
||||
"github.com/goharbor/harbor/src/pkg/systeminfo"
|
||||
@ -84,7 +84,7 @@ type controller struct{}
|
||||
|
||||
func (c *controller) GetInfo(ctx context.Context, opt Options) (*Data, error) {
|
||||
logger := log.GetLogger(ctx)
|
||||
cfg, err := config.GetSystemCfg()
|
||||
cfg, err := config.GetSystemCfg(ctx)
|
||||
if err != nil {
|
||||
logger.Errorf("Error occurred getting config: %v", err)
|
||||
return nil, err
|
||||
@ -95,7 +95,7 @@ func (c *controller) GetInfo(ctx context.Context, opt Options) (*Data, error) {
|
||||
HarborVersion: fmt.Sprintf("%s-%s", version.ReleaseVersion, version.GitCommit),
|
||||
}
|
||||
if res.AuthMode == common.HTTPAuth {
|
||||
if s, err := config.HTTPAuthProxySetting(); err == nil {
|
||||
if s, err := config.HTTPAuthProxySetting(ctx); err == nil {
|
||||
res.AuthProxySettings = s
|
||||
} else {
|
||||
logger.Warningf("Failed to get auth proxy setting, error: %v", err)
|
||||
@ -117,7 +117,7 @@ func (c *controller) GetInfo(ctx context.Context, opt Options) (*Data, error) {
|
||||
res.Protected = &protectedData{
|
||||
WithNotary: config.WithNotary(),
|
||||
WithChartMuseum: config.WithChartMuseum(),
|
||||
ReadOnly: config.ReadOnly(),
|
||||
ReadOnly: config.ReadOnly(ctx),
|
||||
ExtURL: extURL,
|
||||
RegistryURL: registryURL,
|
||||
HasCARoot: enableCADownload,
|
||||
|
@ -2,17 +2,18 @@ package systeminfo
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/goharbor/harbor/src/controller/config"
|
||||
htesting "github.com/goharbor/harbor/src/testing"
|
||||
"testing"
|
||||
|
||||
"github.com/goharbor/harbor/src/common"
|
||||
"github.com/goharbor/harbor/src/core/config"
|
||||
"github.com/goharbor/harbor/src/lib/errors"
|
||||
"github.com/goharbor/harbor/src/pkg/version"
|
||||
"github.com/stretchr/testify/suite"
|
||||
)
|
||||
|
||||
type sysInfoCtlTestSuite struct {
|
||||
suite.Suite
|
||||
htesting.Suite
|
||||
ctl Controller
|
||||
}
|
||||
|
||||
|
@ -16,7 +16,7 @@ package tag
|
||||
|
||||
import (
|
||||
"github.com/goharbor/harbor/src/common"
|
||||
coreConfig "github.com/goharbor/harbor/src/core/config"
|
||||
"github.com/goharbor/harbor/src/controller/config"
|
||||
"github.com/goharbor/harbor/src/lib/errors"
|
||||
"github.com/goharbor/harbor/src/lib/orm"
|
||||
pkg_artifact "github.com/goharbor/harbor/src/pkg/artifact"
|
||||
@ -54,7 +54,7 @@ func (c *controllerTestSuite) SetupTest() {
|
||||
var tagCtlTestConfig = map[string]interface{}{
|
||||
common.WithNotary: false,
|
||||
}
|
||||
coreConfig.InitWithSettings(tagCtlTestConfig)
|
||||
config.InitWithSettings(tagCtlTestConfig)
|
||||
}
|
||||
|
||||
func (c *controllerTestSuite) TestEnsureTag() {
|
||||
|
@ -18,6 +18,7 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/goharbor/harbor/src/controller/config"
|
||||
"net/http"
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
@ -29,7 +30,6 @@ import (
|
||||
"github.com/goharbor/harbor/src/common/utils"
|
||||
"github.com/goharbor/harbor/src/controller/p2p/preheat"
|
||||
projectcontroller "github.com/goharbor/harbor/src/controller/project"
|
||||
"github.com/goharbor/harbor/src/core/config"
|
||||
"github.com/goharbor/harbor/src/lib/errors"
|
||||
"github.com/goharbor/harbor/src/lib/log"
|
||||
"github.com/goharbor/harbor/src/pkg/scheduler"
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/goharbor/harbor/src/controller/config"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"mime/multipart"
|
||||
@ -21,7 +22,6 @@ import (
|
||||
rep_event "github.com/goharbor/harbor/src/controller/event/handler/replication/event"
|
||||
"github.com/goharbor/harbor/src/controller/event/metadata"
|
||||
"github.com/goharbor/harbor/src/controller/project"
|
||||
"github.com/goharbor/harbor/src/core/config"
|
||||
"github.com/goharbor/harbor/src/core/label"
|
||||
hlog "github.com/goharbor/harbor/src/lib/log"
|
||||
n_event "github.com/goharbor/harbor/src/pkg/notifier/event"
|
||||
|
@ -1,191 +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 (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/goharbor/harbor/src/common"
|
||||
"github.com/goharbor/harbor/src/common/config"
|
||||
"github.com/goharbor/harbor/src/common/config/metadata"
|
||||
"github.com/goharbor/harbor/src/common/dao"
|
||||
"github.com/goharbor/harbor/src/common/security"
|
||||
corecfg "github.com/goharbor/harbor/src/core/config"
|
||||
"github.com/goharbor/harbor/src/lib/log"
|
||||
)
|
||||
|
||||
// ConfigAPI ...
|
||||
type ConfigAPI struct {
|
||||
BaseController
|
||||
cfgManager *config.CfgManager
|
||||
}
|
||||
|
||||
// Prepare validates the user
|
||||
func (c *ConfigAPI) Prepare() {
|
||||
c.BaseController.Prepare()
|
||||
c.cfgManager = corecfg.GetCfgManager()
|
||||
if !c.SecurityCtx.IsAuthenticated() {
|
||||
c.SendUnAuthorizedError(errors.New("UnAuthorized"))
|
||||
return
|
||||
}
|
||||
|
||||
// Only internal container can access /api/internal/configurations
|
||||
if strings.EqualFold(c.Ctx.Request.RequestURI, "/api/internal/configurations") {
|
||||
if s, ok := security.FromContext(c.Ctx.Request.Context()); !ok || s.Name() != "secret" {
|
||||
c.SendUnAuthorizedError(errors.New("UnAuthorized"))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if !c.SecurityCtx.IsSysAdmin() && !c.SecurityCtx.IsSolutionUser() {
|
||||
c.SendForbiddenError(errors.New(c.SecurityCtx.GetUsername()))
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
type value struct {
|
||||
Value interface{} `json:"value"`
|
||||
Editable bool `json:"editable"`
|
||||
}
|
||||
|
||||
// Get returns configurations
|
||||
func (c *ConfigAPI) Get() {
|
||||
configs := c.cfgManager.GetUserCfgs()
|
||||
m, err := convertForGet(configs)
|
||||
if err != nil {
|
||||
log.Errorf("failed to convert configurations: %v", err)
|
||||
c.SendInternalServerError(errors.New(""))
|
||||
return
|
||||
}
|
||||
|
||||
c.Data["json"] = m
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
// GetInternalConfig returns internal configurations
|
||||
func (c *ConfigAPI) GetInternalConfig() {
|
||||
|
||||
configs := c.cfgManager.GetAll()
|
||||
c.Data["json"] = configs
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
// Put updates configurations
|
||||
func (c *ConfigAPI) Put() {
|
||||
m := map[string]interface{}{}
|
||||
if err := c.DecodeJSONReq(&m); err != nil {
|
||||
c.SendBadRequestError(err)
|
||||
return
|
||||
}
|
||||
err := c.cfgManager.Load()
|
||||
if err != nil {
|
||||
log.Errorf("failed to get configurations: %v", err)
|
||||
c.SendInternalServerError(errors.New(""))
|
||||
return
|
||||
}
|
||||
isSysErr, err := c.validateCfg(m)
|
||||
if err != nil {
|
||||
if isSysErr {
|
||||
log.Errorf("failed to validate configurations: %v", err)
|
||||
c.SendInternalServerError(errors.New(""))
|
||||
return
|
||||
}
|
||||
|
||||
c.SendBadRequestError(err)
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
if err := c.cfgManager.UpdateConfig(m); err != nil {
|
||||
log.Errorf("failed to upload configurations: %v", err)
|
||||
c.SendInternalServerError(errors.New(""))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (c *ConfigAPI) validateCfg(cfgs map[string]interface{}) (bool, error) {
|
||||
flag, err := authModeCanBeModified()
|
||||
if err != nil {
|
||||
return true, err
|
||||
}
|
||||
if !flag {
|
||||
if failedKeys := checkUnmodifiable(c.cfgManager, cfgs, common.AUTHMode); len(failedKeys) > 0 {
|
||||
return false, fmt.Errorf("the keys %v can not be modified as new users have been inserted into database", failedKeys)
|
||||
}
|
||||
}
|
||||
err = c.cfgManager.ValidateCfg(cfgs)
|
||||
return false, err
|
||||
}
|
||||
|
||||
func checkUnmodifiable(mgr *config.CfgManager, cfgs map[string]interface{}, keys ...string) (failed []string) {
|
||||
if mgr == nil || cfgs == nil || keys == nil {
|
||||
return
|
||||
}
|
||||
for _, k := range keys {
|
||||
v := mgr.Get(k).GetString()
|
||||
if nv, ok := cfgs[k]; ok {
|
||||
if v != fmt.Sprintf("%v", nv) {
|
||||
failed = append(failed, k)
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// ScanAllPolicy is represent the json request and object for scan all policy
|
||||
// Only for migrating from the legacy schedule.
|
||||
type ScanAllPolicy struct {
|
||||
Type string `json:"type"`
|
||||
Param map[string]interface{} `json:"parameter,omitempty"`
|
||||
}
|
||||
|
||||
// delete sensitive attrs and add editable field to every attr
|
||||
func convertForGet(cfg map[string]interface{}) (map[string]*value, error) {
|
||||
result := map[string]*value{}
|
||||
|
||||
mList := metadata.Instance().GetAll()
|
||||
|
||||
for _, item := range mList {
|
||||
if _, ok := item.ItemType.(*metadata.PasswordType); ok {
|
||||
delete(cfg, item.Name)
|
||||
}
|
||||
}
|
||||
|
||||
if _, ok := cfg[common.ScanAllPolicy]; !ok {
|
||||
cfg[common.ScanAllPolicy] = ScanAllPolicy{
|
||||
Type: "none", // For legacy compatible
|
||||
}
|
||||
}
|
||||
for k, v := range cfg {
|
||||
result[k] = &value{
|
||||
Value: v,
|
||||
Editable: true,
|
||||
}
|
||||
}
|
||||
|
||||
flag, err := authModeCanBeModified()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result[common.AUTHMode].Editable = flag
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func authModeCanBeModified() (bool, error) {
|
||||
return dao.AuthModeCanBeModified()
|
||||
}
|
@ -1,127 +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"
|
||||
"testing"
|
||||
|
||||
"github.com/goharbor/harbor/src/common"
|
||||
"github.com/goharbor/harbor/src/core/config"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestGetConfig(t *testing.T) {
|
||||
fmt.Println("Testing getting configurations")
|
||||
assert := assert.New(t)
|
||||
apiTest := newHarborAPI()
|
||||
|
||||
// case 1: get configurations without admin role
|
||||
code, _, err := apiTest.GetConfig(*testUser)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to get configurations: %v", err)
|
||||
}
|
||||
|
||||
assert.Equal(401, code, "the status code of getting configurations with non-admin user should be 401")
|
||||
|
||||
// case 2: get configurations with admin role
|
||||
code, cfg, err := apiTest.GetConfig(*admin)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to get configurations: %v", err)
|
||||
}
|
||||
|
||||
if !assert.Equal(200, code, "the status code of getting configurations with admin user should be 200") {
|
||||
return
|
||||
}
|
||||
t.Logf("cfg: %+v", cfg)
|
||||
mode := cfg[common.AUTHMode].Value.(string)
|
||||
assert.Equal(common.DBAuth, mode, fmt.Sprintf("the auth mode should be %s", common.DBAuth))
|
||||
ccc, err := config.GetSystemCfg()
|
||||
if err != nil {
|
||||
t.Logf("failed to get system configurations: %v", err)
|
||||
}
|
||||
t.Logf("%v", ccc)
|
||||
}
|
||||
|
||||
func TestInternalConfig(t *testing.T) {
|
||||
fmt.Println("Testing internal configurations")
|
||||
assert := assert.New(t)
|
||||
apiTest := newHarborAPI()
|
||||
|
||||
// case 1: get configurations without admin role
|
||||
code, _, err := apiTest.GetInternalConfig(*testUser)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to get configurations: %v", err)
|
||||
}
|
||||
|
||||
assert.Equal(401, code, "the status code of getting configurations with non-admin user should be 401")
|
||||
|
||||
// case 2: get configurations with admin role
|
||||
code, _, err = apiTest.GetInternalConfig(*admin)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to get configurations: %v", err)
|
||||
}
|
||||
|
||||
if !assert.Equal(200, code, "the status code of getting configurations with admin user should be 200") {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func TestPutConfig(t *testing.T) {
|
||||
fmt.Println("Testing modifying configurations")
|
||||
assert := assert.New(t)
|
||||
apiTest := newHarborAPI()
|
||||
|
||||
cfg := map[string]interface{}{
|
||||
common.TokenExpiration: 60,
|
||||
}
|
||||
|
||||
code, err := apiTest.PutConfig(*admin, cfg)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to get configurations: %v", err)
|
||||
}
|
||||
|
||||
if !assert.Equal(200, code, "the status code of modifying configurations with admin user should be 200") {
|
||||
return
|
||||
}
|
||||
ccc, err := config.GetSystemCfg()
|
||||
if err != nil {
|
||||
t.Logf("failed to get system configurations: %v", err)
|
||||
}
|
||||
t.Logf("%v", ccc)
|
||||
}
|
||||
|
||||
func TestPutConfigMaxLength(t *testing.T) {
|
||||
fmt.Println("Testing modifying configurations with max length.")
|
||||
assert := assert.New(t)
|
||||
apiTest := newHarborAPI()
|
||||
|
||||
// length is 1059,expected code: 200
|
||||
cfg := map[string]interface{}{
|
||||
common.LDAPGroupSearchFilter: "YU2YcM13JtSx5jtBiftTjfaEM9KZFQ0XA5fKQHU02E9Xe0aLYaSy7YBokrTA8oHFjSkWFSgWZJ6FEmTS" +
|
||||
"Vy5Ovsy5to2kWnFtbVNX3pzbeQpZeAqK3mEGnXdMkMSQu9WTq74s99GpwjEdA628pcZqLx6wCR0IvwryqIcNoRtqPlUcuRGODWA8ZXaC0d" +
|
||||
"Qs7cRUYSe8onHsM2c9JWuUS8Jv4E7KggfytrxeKAT0WGP5DBZsB7rHZKxoAppE3C0NueEeC4yV791PUOODJt9rc0RrcD6ORUIO5RriCwym" +
|
||||
"IinJZa03MtTk3vGFTmL9wM0wEYZP3fEBmoiB0iF8o4wkHGyMpNJoDyPuo7huuCbipAXClEcX1R7xD4aijTF9iOMKymvsObMZ4qqI7flco5" +
|
||||
"yLFf7W8cpSisk3YJSvxDWfrl91WT4IFE5KHK976DgLQJhTZ8msGOImnFiUGtuIUNQpOgFFtlXJV41OltSsjW5jwAzxcko0MFkOIc7XuPjB" +
|
||||
"XMrdjC9poYldrxNFrGOPFSyh19iS2UWKayKrtnhvDYAWrNCqOmRs01awEXBlwHp17VcLuze6XGCx7ZoPQX1Nu4uF1InAGpSm1B3pKtteeR" +
|
||||
"WNNeLZjmNGNuiorHyxLTx1bQTfkG2UzZTTR0e2XatiXt5nCDxSqP2OkOxH7dew36fm9LpkFbmgtlxWxjHX8buYzSJCAjTqqwW3rHCEfQjv" +
|
||||
"B4T7CTJrAgehCG9zL82P59DQbGXXWqRHbw5g9QszREQys1m56SHLosNptVPUwy7vD70rRf5s8knohW5npEZS9f3RGel64mj5g7bQBBkopx" +
|
||||
"f6uac3MlJAe9d6C0B7fexZJABln2kCtXXYzITflICISwxuZ0YXHJmT2sMSIpn9VwMnMidV4JsM2BD8ykExZ5QyeVyOCXHDxvRvFwQwjQfR" +
|
||||
"kkqQmtFREitKWl5njO8wLJw0XyeIVAej75NsGKKZWVjyaupaM9Bqn6NFrWjELFacLox6OCcRIDSDl3ntNN8tIzGOF7aXVCIqljJl0IL9Pz" +
|
||||
"NenmmubaNm48YjfkBk8MqOUSYJYaFkO1qCKbVdMg7yTqKEHgSUqEkoFPoJMH6GAozC",
|
||||
}
|
||||
sc, _ := apiTest.PutConfig(*admin, cfg)
|
||||
assert.Equal(200, sc, "the status code of modifying configurations with admin user should be 200")
|
||||
}
|
@ -16,11 +16,12 @@ package api
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/goharbor/harbor/src/controller/config"
|
||||
"github.com/goharbor/harbor/src/lib/orm"
|
||||
"net"
|
||||
"strconv"
|
||||
|
||||
"github.com/goharbor/harbor/src/common/utils/email"
|
||||
"github.com/goharbor/harbor/src/core/config"
|
||||
"github.com/goharbor/harbor/src/lib/log"
|
||||
)
|
||||
|
||||
@ -52,9 +53,10 @@ func (e *EmailAPI) Ping() {
|
||||
var host, username, password, identity string
|
||||
var port int
|
||||
var ssl, insecure bool
|
||||
ctx := orm.Context()
|
||||
body := e.Ctx.Input.CopyBody(1 << 32)
|
||||
if body == nil || len(body) == 0 {
|
||||
cfg, err := config.Email()
|
||||
cfg, err := config.Email(ctx)
|
||||
if err != nil {
|
||||
log.Errorf("failed to get email configurations: %v", err)
|
||||
e.SendInternalServerError(err)
|
||||
@ -88,7 +90,7 @@ func (e *EmailAPI) Ping() {
|
||||
}
|
||||
|
||||
if settings.Password == nil {
|
||||
cfg, err := config.Email()
|
||||
cfg, err := config.Email(ctx)
|
||||
if err != nil {
|
||||
log.Errorf("failed to get email configurations: %v", err)
|
||||
e.SendInternalServerError(err)
|
||||
|
@ -35,10 +35,11 @@ import (
|
||||
"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/controller/config"
|
||||
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"
|
||||
libOrm "github.com/goharbor/harbor/src/lib/orm"
|
||||
"github.com/goharbor/harbor/src/server/middleware"
|
||||
"github.com/goharbor/harbor/src/server/middleware/orm"
|
||||
"github.com/goharbor/harbor/src/server/middleware/security"
|
||||
@ -77,12 +78,12 @@ type usrInfo struct {
|
||||
}
|
||||
|
||||
func init() {
|
||||
config.Init()
|
||||
testutils.InitDatabaseFromEnv()
|
||||
config.Init()
|
||||
dao.PrepareTestData([]string{"delete from harbor_user where user_id >2", "delete from project where owner_id >2"}, []string{})
|
||||
config.Upload(testutils.GetUnitTestConfig())
|
||||
|
||||
allCfgs, _ := config.GetSystemCfg()
|
||||
allCfgs, _ := config.GetSystemCfg(libOrm.Context())
|
||||
testutils.TraceCfgMap(allCfgs)
|
||||
|
||||
_, file, _, _ := runtime.Caller(0)
|
||||
@ -106,8 +107,6 @@ func init() {
|
||||
beego.Router("/api/statistics", &StatisticAPI{})
|
||||
beego.Router("/api/users/?:id", &UserAPI{})
|
||||
beego.Router("/api/usergroups/?:ugid([0-9]+)", &UserGroupAPI{})
|
||||
beego.Router("/api/configurations", &ConfigAPI{})
|
||||
beego.Router("/api/configs", &ConfigAPI{}, "get:GetInternalConfig")
|
||||
beego.Router("/api/email/ping", &EmailAPI{}, "post:Ping")
|
||||
beego.Router("/api/labels", &LabelAPI{}, "post:Post;get:List")
|
||||
beego.Router("/api/labels/:id([0-9]+", &LabelAPI{}, "get:Get;put:Put;delete:Delete")
|
||||
@ -677,82 +676,6 @@ func (a testapi) UsersDelete(userID int, authInfo usrInfo) (int, error) {
|
||||
return httpStatusCode, err
|
||||
}
|
||||
|
||||
// Post ldap test
|
||||
func (a testapi) LdapPost(authInfo usrInfo, ldapConf apilib.LdapConf) (int, error) {
|
||||
|
||||
_sling := sling.New().Post(a.basePath)
|
||||
|
||||
// create path and map variables
|
||||
path := "/api/ldap/ping"
|
||||
|
||||
_sling = _sling.Path(path)
|
||||
|
||||
// body params
|
||||
_sling = _sling.BodyJSON(ldapConf)
|
||||
httpStatusCode, _, err := request(_sling, jsonAcceptHeader, authInfo)
|
||||
return httpStatusCode, err
|
||||
}
|
||||
|
||||
// Search Ldap Groups
|
||||
func (a testapi) LdapGroupsSearch(groupName, groupDN string, authInfo ...usrInfo) (int, []apilib.LdapGroupsSearch, error) {
|
||||
_sling := sling.New().Get(a.basePath)
|
||||
// create path and map variables
|
||||
path := "/api/ldap/groups/search"
|
||||
_sling = _sling.Path(path)
|
||||
// body params
|
||||
type QueryParams struct {
|
||||
GroupName string `url:"groupname, omitempty"`
|
||||
GroupDN string `url:"groupdn, omitempty"`
|
||||
}
|
||||
_sling = _sling.QueryStruct(&QueryParams{GroupName: groupName, GroupDN: groupDN})
|
||||
httpStatusCode, body, err := request(_sling, jsonAcceptHeader, authInfo...)
|
||||
var successPayLoad []apilib.LdapGroupsSearch
|
||||
if 200 == httpStatusCode && nil == err {
|
||||
err = json.Unmarshal(body, &successPayLoad)
|
||||
}
|
||||
return httpStatusCode, successPayLoad, err
|
||||
}
|
||||
|
||||
func (a testapi) GetConfig(authInfo usrInfo) (int, map[string]*value, error) {
|
||||
_sling := sling.New().Base(a.basePath).Get("/api/configurations")
|
||||
|
||||
cfg := map[string]*value{}
|
||||
|
||||
code, body, err := request(_sling, jsonAcceptHeader, authInfo)
|
||||
if err == nil && code == 200 {
|
||||
err = json.Unmarshal(body, &cfg)
|
||||
}
|
||||
return code, cfg, err
|
||||
}
|
||||
|
||||
func (a testapi) GetInternalConfig(authInfo usrInfo) (int, map[string]interface{}, error) {
|
||||
_sling := sling.New().Base(a.basePath).Get("/api/configs")
|
||||
|
||||
cfg := map[string]interface{}{}
|
||||
|
||||
code, body, err := request(_sling, jsonAcceptHeader, authInfo)
|
||||
if err == nil && code == 200 {
|
||||
err = json.Unmarshal(body, &cfg)
|
||||
}
|
||||
return code, cfg, err
|
||||
}
|
||||
|
||||
func (a testapi) PutConfig(authInfo usrInfo, cfg map[string]interface{}) (int, error) {
|
||||
_sling := sling.New().Base(a.basePath).Put("/api/configurations").BodyJSON(cfg)
|
||||
|
||||
code, _, err := request(_sling, jsonAcceptHeader, authInfo)
|
||||
|
||||
return code, err
|
||||
}
|
||||
|
||||
func (a testapi) ResetConfig(authInfo usrInfo) (int, error) {
|
||||
_sling := sling.New().Base(a.basePath).Post("/api/configurations/reset")
|
||||
|
||||
code, _, err := request(_sling, jsonAcceptHeader, authInfo)
|
||||
|
||||
return code, err
|
||||
}
|
||||
|
||||
func (a testapi) PingEmail(authInfo usrInfo, settings []byte) (int, string, error) {
|
||||
_sling := sling.New().Base(a.basePath).Post("/api/email/ping").Body(bytes.NewReader(settings))
|
||||
|
||||
|
@ -17,6 +17,7 @@ package api
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/goharbor/harbor/src/controller/config"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"sort"
|
||||
@ -28,7 +29,6 @@ import (
|
||||
"github.com/goharbor/harbor/src/common/dao"
|
||||
httputil "github.com/goharbor/harbor/src/common/http"
|
||||
"github.com/goharbor/harbor/src/common/utils"
|
||||
"github.com/goharbor/harbor/src/core/config"
|
||||
"github.com/goharbor/harbor/src/lib/log"
|
||||
"github.com/goharbor/harbor/src/lib/redis"
|
||||
)
|
||||
|
@ -16,13 +16,13 @@ package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/goharbor/harbor/src/controller/config"
|
||||
|
||||
o "github.com/astaxie/beego/orm"
|
||||
"github.com/goharbor/harbor/src/common"
|
||||
"github.com/goharbor/harbor/src/common/dao"
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
"github.com/goharbor/harbor/src/controller/quota"
|
||||
"github.com/goharbor/harbor/src/core/config"
|
||||
"github.com/goharbor/harbor/src/lib/errors"
|
||||
"github.com/goharbor/harbor/src/lib/log"
|
||||
"github.com/goharbor/harbor/src/lib/orm"
|
||||
@ -78,46 +78,47 @@ func (ia *InternalAPI) SwitchQuota() {
|
||||
ia.SendBadRequestError(err)
|
||||
return
|
||||
}
|
||||
cur := config.ReadOnly()
|
||||
ctx := orm.NewContext(ia.Ctx.Request.Context(), o.NewOrm())
|
||||
cur := config.ReadOnly(ctx)
|
||||
// quota per project from disable to enable, it needs to update the quota usage bases on the DB records.
|
||||
if !config.QuotaPerProjectEnable() && req.Enabled {
|
||||
if !config.QuotaPerProjectEnable(ctx) && req.Enabled {
|
||||
if !cur {
|
||||
config.GetCfgManager().Set(common.ReadOnly, true)
|
||||
config.GetCfgManager().Save()
|
||||
config.GetCfgManager(ctx).Set(ctx, common.ReadOnly, true)
|
||||
config.GetCfgManager(ctx).Save(ctx)
|
||||
}
|
||||
|
||||
ctx := orm.NewContext(ia.Ctx.Request.Context(), o.NewOrm())
|
||||
if err := quota.RefreshForProjects(ctx); err != nil {
|
||||
ia.SendInternalServerError(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
defer func() {
|
||||
config.GetCfgManager().Set(common.ReadOnly, cur)
|
||||
config.GetCfgManager().Set(common.QuotaPerProjectEnable, req.Enabled)
|
||||
config.GetCfgManager().Save()
|
||||
ctx := orm.Context()
|
||||
config.GetCfgManager(ctx).Set(ctx, common.ReadOnly, cur)
|
||||
config.GetCfgManager(ctx).Set(ctx, common.QuotaPerProjectEnable, req.Enabled)
|
||||
config.GetCfgManager(ctx).Save(ctx)
|
||||
}()
|
||||
return
|
||||
}
|
||||
|
||||
// SyncQuota ...
|
||||
func (ia *InternalAPI) SyncQuota() {
|
||||
if !config.QuotaPerProjectEnable() {
|
||||
if !config.QuotaPerProjectEnable(orm.Context()) {
|
||||
ia.SendError(errors.ForbiddenError(nil).WithMessage("quota per project is disabled"))
|
||||
return
|
||||
}
|
||||
|
||||
cur := config.ReadOnly()
|
||||
cfgMgr := config.GetCfgManager()
|
||||
ctx := orm.Context()
|
||||
cur := config.ReadOnly(ctx)
|
||||
cfgMgr := config.GetCfgManager(ctx)
|
||||
if !cur {
|
||||
cfgMgr.Set(common.ReadOnly, true)
|
||||
cfgMgr.Save()
|
||||
cfgMgr.Set(ctx, common.ReadOnly, true)
|
||||
cfgMgr.Save(ctx)
|
||||
}
|
||||
// For api call, to avoid the timeout, it should be asynchronous
|
||||
go func() {
|
||||
defer func() {
|
||||
cfgMgr.Set(common.ReadOnly, cur)
|
||||
cfgMgr.Save()
|
||||
ctx := orm.Context()
|
||||
cfgMgr.Set(ctx, common.ReadOnly, cur)
|
||||
cfgMgr.Save(ctx)
|
||||
}()
|
||||
log.Info("start to sync quota(API), the system will be set to ReadOnly and back it normal once it done.")
|
||||
ctx := orm.NewContext(context.TODO(), o.NewOrm())
|
||||
|
@ -16,6 +16,8 @@ package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/goharbor/harbor/src/controller/config"
|
||||
"github.com/goharbor/harbor/src/lib/orm"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
@ -27,7 +29,6 @@ import (
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
"github.com/goharbor/harbor/src/common/rbac"
|
||||
"github.com/goharbor/harbor/src/core/auth"
|
||||
"github.com/goharbor/harbor/src/core/config"
|
||||
"github.com/goharbor/harbor/src/lib/errors"
|
||||
)
|
||||
|
||||
@ -98,7 +99,7 @@ func (pma *ProjectMemberAPI) Prepare() {
|
||||
pma.member = members[0]
|
||||
}
|
||||
|
||||
authMode, err := config.AuthMode()
|
||||
authMode, err := config.AuthMode(orm.Context())
|
||||
if err != nil {
|
||||
pma.SendInternalServerError(fmt.Errorf("failed to get authentication mode"))
|
||||
}
|
||||
|
@ -19,6 +19,8 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/goharbor/harbor/src/common/rbac/system"
|
||||
"github.com/goharbor/harbor/src/controller/config"
|
||||
"github.com/goharbor/harbor/src/lib/orm"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strconv"
|
||||
@ -29,7 +31,6 @@ import (
|
||||
"github.com/goharbor/harbor/src/common/rbac"
|
||||
"github.com/goharbor/harbor/src/common/security/local"
|
||||
"github.com/goharbor/harbor/src/common/utils"
|
||||
"github.com/goharbor/harbor/src/core/config"
|
||||
"github.com/goharbor/harbor/src/lib"
|
||||
"github.com/goharbor/harbor/src/lib/log"
|
||||
"github.com/goharbor/harbor/src/pkg/permission/types"
|
||||
@ -63,7 +64,7 @@ type secretReq struct {
|
||||
// Prepare validates the URL and parms
|
||||
func (ua *UserAPI) Prepare() {
|
||||
ua.BaseController.Prepare()
|
||||
mode, err := config.AuthMode()
|
||||
mode, err := config.AuthMode(orm.Context())
|
||||
if err != nil {
|
||||
log.Errorf("failed to get auth mode: %v", err)
|
||||
ua.SendInternalServerError(errors.New(""))
|
||||
@ -81,7 +82,7 @@ func (ua *UserAPI) Prepare() {
|
||||
ua.secretKey = key
|
||||
}
|
||||
|
||||
self, err := config.SelfRegistration()
|
||||
self, err := config.SelfRegistration(orm.Context())
|
||||
if err != nil {
|
||||
log.Errorf("failed to get self registration: %v", err)
|
||||
ua.SendInternalServerError(errors.New(""))
|
||||
|
@ -16,6 +16,7 @@ package api
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/goharbor/harbor/src/controller/config"
|
||||
securitytesting "github.com/goharbor/harbor/src/testing/common/security"
|
||||
"github.com/goharbor/harbor/src/testing/mock"
|
||||
"net/http"
|
||||
@ -31,7 +32,6 @@ import (
|
||||
|
||||
"github.com/astaxie/beego"
|
||||
"github.com/goharbor/harbor/src/common"
|
||||
"github.com/goharbor/harbor/src/core/config"
|
||||
)
|
||||
|
||||
var testUser0002ID, testUser0003ID int
|
||||
|
@ -19,6 +19,8 @@ import (
|
||||
"fmt"
|
||||
"github.com/goharbor/harbor/src/common/rbac"
|
||||
"github.com/goharbor/harbor/src/common/rbac/system"
|
||||
"github.com/goharbor/harbor/src/controller/config"
|
||||
"github.com/goharbor/harbor/src/lib/orm"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
@ -27,7 +29,6 @@ import (
|
||||
"github.com/goharbor/harbor/src/common/dao/group"
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
"github.com/goharbor/harbor/src/core/auth"
|
||||
"github.com/goharbor/harbor/src/core/config"
|
||||
"github.com/goharbor/harbor/src/lib/log"
|
||||
"github.com/goharbor/harbor/src/pkg/ldap"
|
||||
)
|
||||
@ -60,7 +61,7 @@ func (uga *UserGroupAPI) Prepare() {
|
||||
return
|
||||
}
|
||||
uga.id = int(ugid)
|
||||
authMode, err := config.AuthMode()
|
||||
authMode, err := config.AuthMode(orm.Context())
|
||||
if err != nil {
|
||||
uga.SendInternalServerError(errors.New("failed to get authentication mode"))
|
||||
}
|
||||
|
@ -17,12 +17,13 @@ package auth
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/goharbor/harbor/src/controller/config"
|
||||
"github.com/goharbor/harbor/src/lib/orm"
|
||||
"time"
|
||||
|
||||
"github.com/goharbor/harbor/src/common"
|
||||
"github.com/goharbor/harbor/src/common/dao"
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
"github.com/goharbor/harbor/src/core/config"
|
||||
"github.com/goharbor/harbor/src/lib/log"
|
||||
)
|
||||
|
||||
@ -129,7 +130,7 @@ func Register(name string, h AuthenticateHelper) {
|
||||
// Login authenticates user credentials based on setting.
|
||||
func Login(m models.AuthModel) (*models.User, error) {
|
||||
|
||||
authMode, err := config.AuthMode()
|
||||
authMode, err := config.AuthMode(orm.Context())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -160,7 +161,7 @@ func Login(m models.AuthModel) (*models.User, error) {
|
||||
}
|
||||
|
||||
func getHelper() (AuthenticateHelper, error) {
|
||||
authMode, err := config.AuthMode()
|
||||
authMode, err := config.AuthMode(orm.Context())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -20,7 +20,10 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/goharbor/harbor/src/controller/config"
|
||||
"github.com/goharbor/harbor/src/jobservice/logger"
|
||||
cfgModels "github.com/goharbor/harbor/src/lib/config/models"
|
||||
"github.com/goharbor/harbor/src/lib/orm"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
@ -33,7 +36,6 @@ import (
|
||||
"github.com/goharbor/harbor/src/common/dao"
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
"github.com/goharbor/harbor/src/core/auth"
|
||||
"github.com/goharbor/harbor/src/core/config"
|
||||
"github.com/goharbor/harbor/src/lib/log"
|
||||
"github.com/goharbor/harbor/src/pkg/authproxy"
|
||||
)
|
||||
@ -108,7 +110,7 @@ func (a *Auth) Authenticate(m models.AuthModel) (*models.User, error) {
|
||||
}
|
||||
|
||||
func (a *Auth) tokenReview(sessionID string) (*models.User, error) {
|
||||
httpAuthProxySetting, err := config.HTTPAuthProxySetting()
|
||||
httpAuthProxySetting, err := config.HTTPAuthProxySetting(orm.Context())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -216,7 +218,7 @@ func (a *Auth) ensure() error {
|
||||
a.client = &http.Client{}
|
||||
}
|
||||
if time.Now().Sub(a.settingTimeStamp) >= refreshDuration {
|
||||
setting, err := config.HTTPAuthProxySetting()
|
||||
setting, err := config.HTTPAuthProxySetting(orm.Context())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -233,7 +235,7 @@ func (a *Auth) ensure() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func getTLSConfig(setting *models.HTTPAuthProxy) (*tls.Config, error) {
|
||||
func getTLSConfig(setting *cfgModels.HTTPAuthProxy) (*tls.Config, error) {
|
||||
c := setting.ServerCertificate
|
||||
if setting.VerifyCert && len(c) > 0 {
|
||||
certs := x509.NewCertPool()
|
||||
|
@ -20,9 +20,10 @@ import (
|
||||
"github.com/goharbor/harbor/src/common/dao/group"
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
cut "github.com/goharbor/harbor/src/common/utils/test"
|
||||
"github.com/goharbor/harbor/src/controller/config"
|
||||
"github.com/goharbor/harbor/src/core/auth"
|
||||
"github.com/goharbor/harbor/src/core/auth/authproxy/test"
|
||||
"github.com/goharbor/harbor/src/core/config"
|
||||
cfgModels "github.com/goharbor/harbor/src/lib/config/models"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
@ -214,11 +215,11 @@ func TestGetTLSConfig(t *testing.T) {
|
||||
nilRootCA bool
|
||||
}
|
||||
cases := []struct {
|
||||
input *models.HTTPAuthProxy
|
||||
input *cfgModels.HTTPAuthProxy
|
||||
expect result
|
||||
}{
|
||||
{
|
||||
input: &models.HTTPAuthProxy{
|
||||
input: &cfgModels.HTTPAuthProxy{
|
||||
Endpoint: "https://127.0.0.1/login",
|
||||
TokenReviewEndpoint: "https://127.0.0.1/tokenreview",
|
||||
VerifyCert: false,
|
||||
@ -232,7 +233,7 @@ func TestGetTLSConfig(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
input: &models.HTTPAuthProxy{
|
||||
input: &cfgModels.HTTPAuthProxy{
|
||||
Endpoint: "https://127.0.0.1/login",
|
||||
TokenReviewEndpoint: "https://127.0.0.1/tokenreview",
|
||||
VerifyCert: false,
|
||||
@ -246,7 +247,7 @@ func TestGetTLSConfig(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
input: &models.HTTPAuthProxy{
|
||||
input: &cfgModels.HTTPAuthProxy{
|
||||
Endpoint: "https://127.0.0.1/login",
|
||||
TokenReviewEndpoint: "https://127.0.0.1/tokenreview",
|
||||
VerifyCert: true,
|
||||
@ -258,7 +259,7 @@ func TestGetTLSConfig(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
input: &models.HTTPAuthProxy{
|
||||
input: &cfgModels.HTTPAuthProxy{
|
||||
Endpoint: "https://127.0.0.1/login",
|
||||
TokenReviewEndpoint: "https://127.0.0.1/tokenreview",
|
||||
VerifyCert: true,
|
||||
@ -272,7 +273,7 @@ func TestGetTLSConfig(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
input: &models.HTTPAuthProxy{
|
||||
input: &cfgModels.HTTPAuthProxy{
|
||||
Endpoint: "https://127.0.0.1/login",
|
||||
TokenReviewEndpoint: "https://127.0.0.1/tokenreview",
|
||||
VerifyCert: true,
|
||||
|
@ -14,6 +14,7 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"github.com/goharbor/harbor/src/controller/config"
|
||||
"log"
|
||||
"os"
|
||||
"testing"
|
||||
@ -24,8 +25,6 @@ import (
|
||||
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
"github.com/goharbor/harbor/src/core/auth"
|
||||
"github.com/goharbor/harbor/src/core/config"
|
||||
coreConfig "github.com/goharbor/harbor/src/core/config"
|
||||
)
|
||||
|
||||
var testConfig = map[string]interface{}{
|
||||
@ -62,7 +61,7 @@ func TestMain(m *testing.M) {
|
||||
log.Fatalf("failed to set env %s: %v", "KEY_PATH", err)
|
||||
}
|
||||
|
||||
coreConfig.Init()
|
||||
config.Init()
|
||||
|
||||
config.Upload(testConfig)
|
||||
retCode := m.Run()
|
||||
|
@ -17,6 +17,8 @@ package ldap
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/goharbor/harbor/src/controller/config"
|
||||
"github.com/goharbor/harbor/src/lib/orm"
|
||||
"github.com/goharbor/harbor/src/pkg/ldap/model"
|
||||
"regexp"
|
||||
"strings"
|
||||
@ -32,7 +34,6 @@ import (
|
||||
"github.com/goharbor/harbor/src/pkg/ldap"
|
||||
|
||||
"github.com/goharbor/harbor/src/core/auth"
|
||||
"github.com/goharbor/harbor/src/core/config"
|
||||
"github.com/goharbor/harbor/src/lib/log"
|
||||
)
|
||||
|
||||
@ -45,13 +46,13 @@ type Auth struct {
|
||||
// if the check is successful a dummy record will be inserted into DB, such that this user can
|
||||
// be associated to other entities in the system.
|
||||
func (l *Auth) Authenticate(m models.AuthModel) (*models.User, error) {
|
||||
|
||||
ctx := orm.Context()
|
||||
p := m.Principal
|
||||
if len(strings.TrimSpace(p)) == 0 {
|
||||
log.Debugf("LDAP authentication failed for empty user id.")
|
||||
return nil, auth.NewErrAuth("Empty user id")
|
||||
}
|
||||
ldapSession, err := ldapCtl.Ctl.Session(context.Background())
|
||||
ldapSession, err := ldapCtl.Ctl.Session(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("can not load system ldap config: %v", err)
|
||||
}
|
||||
@ -88,15 +89,15 @@ func (l *Auth) Authenticate(m models.AuthModel) (*models.User, error) {
|
||||
u.Email = strings.TrimSpace(ldapUsers[0].Email)
|
||||
|
||||
l.syncUserInfoFromDB(&u)
|
||||
l.attachLDAPGroup(ldapUsers, &u, ldapSession)
|
||||
l.attachLDAPGroup(ctx, ldapUsers, &u, ldapSession)
|
||||
|
||||
return &u, nil
|
||||
}
|
||||
|
||||
func (l *Auth) attachLDAPGroup(ldapUsers []model.User, u *models.User, sess *ldap.Session) {
|
||||
func (l *Auth) attachLDAPGroup(ctx context.Context, ldapUsers []model.User, u *models.User, sess *ldap.Session) {
|
||||
// Retrieve ldap related info in login to avoid too many traffic with LDAP server.
|
||||
// Get group admin dn
|
||||
groupCfg, err := config.LDAPGroupConf()
|
||||
groupCfg, err := config.LDAPGroupConf(ctx)
|
||||
if err != nil {
|
||||
log.Warningf("Failed to fetch ldap group configuration:%v", err)
|
||||
// most likely user doesn't configure user group info, it should not block user login
|
||||
@ -161,7 +162,7 @@ func (l *Auth) OnBoardUser(u *models.User) error {
|
||||
// SearchUser -- Search user in ldap
|
||||
func (l *Auth) SearchUser(username string) (*models.User, error) {
|
||||
var user models.User
|
||||
s, err := ldapCtl.Ctl.Session(context.Background())
|
||||
s, err := ldapCtl.Ctl.Session(orm.Context())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -196,7 +197,7 @@ func (l *Auth) SearchGroup(groupKey string) (*models.UserGroup, error) {
|
||||
if _, err := goldap.ParseDN(groupKey); err != nil {
|
||||
return nil, auth.ErrInvalidLDAPGroupDN
|
||||
}
|
||||
s, err := ldapCtl.Ctl.Session(context.Background())
|
||||
s, err := ldapCtl.Ctl.Session(orm.Context())
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("can not load system ldap config: %v", err)
|
||||
|
@ -14,6 +14,7 @@
|
||||
package ldap
|
||||
|
||||
import (
|
||||
"github.com/goharbor/harbor/src/controller/config"
|
||||
"github.com/stretchr/testify/assert"
|
||||
// "fmt"
|
||||
// "strings"
|
||||
@ -30,7 +31,6 @@ import (
|
||||
|
||||
"github.com/goharbor/harbor/src/common/dao/group"
|
||||
"github.com/goharbor/harbor/src/core/auth"
|
||||
coreConfig "github.com/goharbor/harbor/src/core/config"
|
||||
)
|
||||
|
||||
var ldapTestConfig = map[string]interface{}{
|
||||
@ -61,7 +61,7 @@ var ldapTestConfig = map[string]interface{}{
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
test.InitDatabaseFromEnv()
|
||||
coreConfig.InitWithSettings(ldapTestConfig)
|
||||
config.InitWithSettings(ldapTestConfig)
|
||||
|
||||
secretKeyPath := "/tmp/secretkey"
|
||||
_, err := test.GenerateKey(secretKeyPath)
|
||||
|
@ -16,6 +16,8 @@ package uaa
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/goharbor/harbor/src/controller/config"
|
||||
"github.com/goharbor/harbor/src/lib/orm"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
@ -25,7 +27,6 @@ import (
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
"github.com/goharbor/harbor/src/common/utils/uaa"
|
||||
"github.com/goharbor/harbor/src/core/auth"
|
||||
"github.com/goharbor/harbor/src/core/config"
|
||||
"github.com/goharbor/harbor/src/lib/log"
|
||||
)
|
||||
|
||||
@ -129,7 +130,7 @@ func (u *Auth) SearchUser(username string) (*models.User, error) {
|
||||
|
||||
func (u *Auth) ensureClient() error {
|
||||
var cfg *uaa.ClientConfig
|
||||
UAASettings, err := config.UAASettings()
|
||||
UAASettings, err := config.UAASettings(orm.Context())
|
||||
// log.Debugf("Uaa settings: %+v", UAASettings)
|
||||
if err != nil {
|
||||
log.Warningf("Failed to get UAA setting from Admin Server, error: %v", err)
|
||||
|
@ -15,6 +15,7 @@
|
||||
package uaa
|
||||
|
||||
import (
|
||||
"github.com/goharbor/harbor/src/controller/config"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
@ -22,7 +23,6 @@ import (
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
"github.com/goharbor/harbor/src/common/utils/test"
|
||||
"github.com/goharbor/harbor/src/common/utils/uaa"
|
||||
"github.com/goharbor/harbor/src/core/config"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
|
@ -1,491 +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 config provide config for core api and other modules
|
||||
// Before accessing user settings, need to call Load()
|
||||
// For system settings, no need to call Load()
|
||||
package config
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/goharbor/harbor/src/common"
|
||||
comcfg "github.com/goharbor/harbor/src/common/config"
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
"github.com/goharbor/harbor/src/common/secret"
|
||||
"github.com/goharbor/harbor/src/lib/log"
|
||||
"github.com/goharbor/harbor/src/pkg/ldap/model"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultKeyPath = "/etc/core/key"
|
||||
defaultRegistryTokenPrivateKeyPath = "/etc/core/private_key.pem"
|
||||
|
||||
// SessionCookieName is the name of the cookie for session ID
|
||||
SessionCookieName = "sid"
|
||||
)
|
||||
|
||||
var (
|
||||
// SecretStore manages secrets
|
||||
SecretStore *secret.Store
|
||||
keyProvider comcfg.KeyProvider
|
||||
// defined as a var for testing.
|
||||
defaultCACertPath = "/etc/core/ca/ca.crt"
|
||||
cfgMgr *comcfg.CfgManager
|
||||
)
|
||||
|
||||
// Init configurations
|
||||
func Init() {
|
||||
// init key provider
|
||||
initKeyProvider()
|
||||
|
||||
cfgMgr = comcfg.NewDBCfgManager()
|
||||
|
||||
log.Info("init secret store")
|
||||
// init secret store
|
||||
initSecretStore()
|
||||
}
|
||||
|
||||
// InitWithSettings init config with predefined configs, and optionally overwrite the keyprovider
|
||||
func InitWithSettings(cfgs map[string]interface{}, kp ...comcfg.KeyProvider) {
|
||||
Init()
|
||||
cfgMgr = comcfg.NewInMemoryManager()
|
||||
cfgMgr.UpdateConfig(cfgs)
|
||||
if len(kp) > 0 {
|
||||
keyProvider = kp[0]
|
||||
}
|
||||
}
|
||||
|
||||
func initKeyProvider() {
|
||||
path := os.Getenv("KEY_PATH")
|
||||
if len(path) == 0 {
|
||||
path = defaultKeyPath
|
||||
}
|
||||
log.Infof("key path: %s", path)
|
||||
|
||||
keyProvider = comcfg.NewFileKeyProvider(path)
|
||||
}
|
||||
|
||||
func initSecretStore() {
|
||||
m := map[string]string{}
|
||||
m[JobserviceSecret()] = secret.JobserviceUser
|
||||
SecretStore = secret.NewStore(m)
|
||||
}
|
||||
|
||||
// GetCfgManager return the current config manager
|
||||
func GetCfgManager() *comcfg.CfgManager {
|
||||
if cfgMgr == nil {
|
||||
return comcfg.NewDBCfgManager()
|
||||
}
|
||||
return cfgMgr
|
||||
}
|
||||
|
||||
// Load configurations
|
||||
func Load() error {
|
||||
return cfgMgr.Load()
|
||||
}
|
||||
|
||||
// Upload save all system configurations
|
||||
func Upload(cfg map[string]interface{}) error {
|
||||
return cfgMgr.UpdateConfig(cfg)
|
||||
}
|
||||
|
||||
// GetSystemCfg returns the system configurations
|
||||
func GetSystemCfg() (map[string]interface{}, error) {
|
||||
sysCfg := cfgMgr.GetAll()
|
||||
if len(sysCfg) == 0 {
|
||||
return nil, errors.New("can not load system config, the database might be down")
|
||||
}
|
||||
return sysCfg, nil
|
||||
}
|
||||
|
||||
// AuthMode ...
|
||||
func AuthMode() (string, error) {
|
||||
err := cfgMgr.Load()
|
||||
if err != nil {
|
||||
log.Errorf("failed to load config, error %v", err)
|
||||
return "db_auth", err
|
||||
}
|
||||
return cfgMgr.Get(common.AUTHMode).GetString(), nil
|
||||
}
|
||||
|
||||
// TokenPrivateKeyPath returns the path to the key for signing token for registry
|
||||
func TokenPrivateKeyPath() string {
|
||||
path := os.Getenv("TOKEN_PRIVATE_KEY_PATH")
|
||||
if len(path) == 0 {
|
||||
path = defaultRegistryTokenPrivateKeyPath
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
||||
// LDAPConf returns the setting of ldap server
|
||||
func LDAPConf() (*model.LdapConf, error) {
|
||||
err := cfgMgr.Load()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &model.LdapConf{
|
||||
URL: cfgMgr.Get(common.LDAPURL).GetString(),
|
||||
SearchDn: cfgMgr.Get(common.LDAPSearchDN).GetString(),
|
||||
SearchPassword: cfgMgr.Get(common.LDAPSearchPwd).GetString(),
|
||||
BaseDn: cfgMgr.Get(common.LDAPBaseDN).GetString(),
|
||||
UID: cfgMgr.Get(common.LDAPUID).GetString(),
|
||||
Filter: cfgMgr.Get(common.LDAPFilter).GetString(),
|
||||
Scope: cfgMgr.Get(common.LDAPScope).GetInt(),
|
||||
ConnectionTimeout: cfgMgr.Get(common.LDAPTimeout).GetInt(),
|
||||
VerifyCert: cfgMgr.Get(common.LDAPVerifyCert).GetBool(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// LDAPGroupConf returns the setting of ldap group search
|
||||
func LDAPGroupConf() (*model.GroupConf, error) {
|
||||
err := cfgMgr.Load()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &model.GroupConf{
|
||||
BaseDN: cfgMgr.Get(common.LDAPGroupBaseDN).GetString(),
|
||||
Filter: cfgMgr.Get(common.LDAPGroupSearchFilter).GetString(),
|
||||
NameAttribute: cfgMgr.Get(common.LDAPGroupAttributeName).GetString(),
|
||||
SearchScope: cfgMgr.Get(common.LDAPGroupSearchScope).GetInt(),
|
||||
AdminDN: cfgMgr.Get(common.LDAPGroupAdminDn).GetString(),
|
||||
MembershipAttribute: cfgMgr.Get(common.LDAPGroupMembershipAttribute).GetString(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// TokenExpiration returns the token expiration time (in minute)
|
||||
func TokenExpiration() (int, error) {
|
||||
return cfgMgr.Get(common.TokenExpiration).GetInt(), nil
|
||||
}
|
||||
|
||||
// RobotTokenDuration returns the token expiration time of robot account (in minute)
|
||||
func RobotTokenDuration() int {
|
||||
return cfgMgr.Get(common.RobotTokenDuration).GetInt()
|
||||
}
|
||||
|
||||
// ExtEndpoint returns the external URL of Harbor: protocol://host:port
|
||||
func ExtEndpoint() (string, error) {
|
||||
return cfgMgr.Get(common.ExtEndpoint).GetString(), nil
|
||||
}
|
||||
|
||||
// ExtURL returns the external URL: host:port
|
||||
func ExtURL() (string, error) {
|
||||
endpoint, err := ExtEndpoint()
|
||||
if err != nil {
|
||||
log.Errorf("failed to load config, error %v", err)
|
||||
}
|
||||
l := strings.Split(endpoint, "://")
|
||||
if len(l) > 1 {
|
||||
return l[1], nil
|
||||
}
|
||||
return endpoint, nil
|
||||
}
|
||||
|
||||
// SecretKey returns the secret key to encrypt the password of target
|
||||
func SecretKey() (string, error) {
|
||||
return keyProvider.Get(nil)
|
||||
}
|
||||
|
||||
// SelfRegistration returns the enablement of self registration
|
||||
func SelfRegistration() (bool, error) {
|
||||
return cfgMgr.Get(common.SelfRegistration).GetBool(), nil
|
||||
}
|
||||
|
||||
// RegistryURL ...
|
||||
func RegistryURL() (string, error) {
|
||||
url := os.Getenv("REGISTRY_URL")
|
||||
if len(url) == 0 {
|
||||
url = "http://registry:5000"
|
||||
}
|
||||
return url, nil
|
||||
}
|
||||
|
||||
// InternalJobServiceURL returns jobservice URL for internal communication between Harbor containers
|
||||
func InternalJobServiceURL() string {
|
||||
return os.Getenv("JOBSERVICE_URL")
|
||||
}
|
||||
|
||||
// GetCoreURL returns the url of core from env
|
||||
func GetCoreURL() string {
|
||||
return os.Getenv("CORE_URL")
|
||||
}
|
||||
|
||||
// InternalCoreURL returns the local harbor core url
|
||||
func InternalCoreURL() string {
|
||||
return strings.TrimSuffix(cfgMgr.Get(common.CoreURL).GetString(), "/")
|
||||
}
|
||||
|
||||
// LocalCoreURL returns the local harbor core url
|
||||
func LocalCoreURL() string {
|
||||
return cfgMgr.Get(common.CoreLocalURL).GetString()
|
||||
}
|
||||
|
||||
// InternalTokenServiceEndpoint returns token service endpoint for internal communication between Harbor containers
|
||||
func InternalTokenServiceEndpoint() string {
|
||||
return InternalCoreURL() + "/service/token"
|
||||
}
|
||||
|
||||
// InternalNotaryEndpoint returns notary server endpoint for internal communication between Harbor containers
|
||||
// This is currently a conventional value and can be unaccessible when Harbor is not deployed with Notary.
|
||||
func InternalNotaryEndpoint() string {
|
||||
return cfgMgr.Get(common.NotaryURL).GetString()
|
||||
}
|
||||
|
||||
// InitialAdminPassword returns the initial password for administrator
|
||||
func InitialAdminPassword() (string, error) {
|
||||
return cfgMgr.Get(common.AdminInitialPassword).GetString(), nil
|
||||
}
|
||||
|
||||
// OnlyAdminCreateProject returns the flag to restrict that only sys admin can create project
|
||||
func OnlyAdminCreateProject() (bool, error) {
|
||||
return cfgMgr.Get(common.ProjectCreationRestriction).GetString() == common.ProCrtRestrAdmOnly, nil
|
||||
}
|
||||
|
||||
// Email returns email server settings
|
||||
func Email() (*models.Email, error) {
|
||||
err := cfgMgr.Load()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &models.Email{
|
||||
Host: cfgMgr.Get(common.EmailHost).GetString(),
|
||||
Port: cfgMgr.Get(common.EmailPort).GetInt(),
|
||||
Username: cfgMgr.Get(common.EmailUsername).GetString(),
|
||||
Password: cfgMgr.Get(common.EmailPassword).GetString(),
|
||||
SSL: cfgMgr.Get(common.EmailSSL).GetBool(),
|
||||
From: cfgMgr.Get(common.EmailFrom).GetString(),
|
||||
Identity: cfgMgr.Get(common.EmailIdentity).GetString(),
|
||||
Insecure: cfgMgr.Get(common.EmailInsecure).GetBool(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Database returns database settings
|
||||
func Database() (*models.Database, error) {
|
||||
database := &models.Database{}
|
||||
database.Type = cfgMgr.Get(common.DatabaseType).GetString()
|
||||
postgresql := &models.PostGreSQL{
|
||||
Host: cfgMgr.Get(common.PostGreSQLHOST).GetString(),
|
||||
Port: cfgMgr.Get(common.PostGreSQLPort).GetInt(),
|
||||
Username: cfgMgr.Get(common.PostGreSQLUsername).GetString(),
|
||||
Password: cfgMgr.Get(common.PostGreSQLPassword).GetString(),
|
||||
Database: cfgMgr.Get(common.PostGreSQLDatabase).GetString(),
|
||||
SSLMode: cfgMgr.Get(common.PostGreSQLSSLMode).GetString(),
|
||||
MaxIdleConns: cfgMgr.Get(common.PostGreSQLMaxIdleConns).GetInt(),
|
||||
MaxOpenConns: cfgMgr.Get(common.PostGreSQLMaxOpenConns).GetInt(),
|
||||
}
|
||||
database.PostGreSQL = postgresql
|
||||
|
||||
return database, nil
|
||||
}
|
||||
|
||||
// CoreSecret returns a secret to mark harbor-core when communicate with
|
||||
// other component
|
||||
func CoreSecret() string {
|
||||
return os.Getenv("CORE_SECRET")
|
||||
}
|
||||
|
||||
// RegistryCredential returns the username and password the core uses to access registry
|
||||
func RegistryCredential() (string, string) {
|
||||
return os.Getenv("REGISTRY_CREDENTIAL_USERNAME"), os.Getenv("REGISTRY_CREDENTIAL_PASSWORD")
|
||||
}
|
||||
|
||||
// JobserviceSecret returns a secret to mark Jobservice when communicate with
|
||||
// other component
|
||||
// TODO replace it with method of SecretStore
|
||||
func JobserviceSecret() string {
|
||||
return os.Getenv("JOBSERVICE_SECRET")
|
||||
}
|
||||
|
||||
// WithNotary returns a bool value to indicate if Harbor's deployed with Notary
|
||||
func WithNotary() bool {
|
||||
return cfgMgr.Get(common.WithNotary).GetBool()
|
||||
}
|
||||
|
||||
// WithTrivy returns a bool value to indicate if Harbor's deployed with Trivy.
|
||||
func WithTrivy() bool {
|
||||
return cfgMgr.Get(common.WithTrivy).GetBool()
|
||||
}
|
||||
|
||||
// TrivyAdapterURL returns the endpoint URL of a Trivy adapter instance, by default it's the one deployed within Harbor.
|
||||
func TrivyAdapterURL() string {
|
||||
return cfgMgr.Get(common.TrivyAdapterURL).GetString()
|
||||
}
|
||||
|
||||
// UAASettings returns the UAASettings to access UAA service.
|
||||
func UAASettings() (*models.UAASettings, error) {
|
||||
err := cfgMgr.Load()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
us := &models.UAASettings{
|
||||
Endpoint: cfgMgr.Get(common.UAAEndpoint).GetString(),
|
||||
ClientID: cfgMgr.Get(common.UAAClientID).GetString(),
|
||||
ClientSecret: cfgMgr.Get(common.UAAClientSecret).GetString(),
|
||||
VerifyCert: cfgMgr.Get(common.UAAVerifyCert).GetBool(),
|
||||
}
|
||||
return us, nil
|
||||
}
|
||||
|
||||
// ReadOnly returns a bool to indicates if Harbor is in read only mode.
|
||||
func ReadOnly() bool {
|
||||
return cfgMgr.Get(common.ReadOnly).GetBool()
|
||||
}
|
||||
|
||||
// WithChartMuseum returns a bool to indicate if chartmuseum is deployed with Harbor.
|
||||
func WithChartMuseum() bool {
|
||||
return cfgMgr.Get(common.WithChartMuseum).GetBool()
|
||||
}
|
||||
|
||||
// GetChartMuseumEndpoint returns the endpoint of the chartmuseum service
|
||||
// otherwise an non nil error is returned
|
||||
func GetChartMuseumEndpoint() (string, error) {
|
||||
chartEndpoint := strings.TrimSpace(cfgMgr.Get(common.ChartRepoURL).GetString())
|
||||
if len(chartEndpoint) == 0 {
|
||||
return "", errors.New("empty chartmuseum endpoint")
|
||||
}
|
||||
return chartEndpoint, nil
|
||||
}
|
||||
|
||||
// GetRedisOfRegURL returns the URL of Redis used by registry
|
||||
func GetRedisOfRegURL() string {
|
||||
return os.Getenv("_REDIS_URL_REG")
|
||||
}
|
||||
|
||||
// GetPortalURL returns the URL of portal
|
||||
func GetPortalURL() string {
|
||||
url := os.Getenv("PORTAL_URL")
|
||||
if len(url) == 0 {
|
||||
return common.DefaultPortalURL
|
||||
}
|
||||
return url
|
||||
}
|
||||
|
||||
// GetRegistryCtlURL returns the URL of registryctl
|
||||
func GetRegistryCtlURL() string {
|
||||
url := os.Getenv("REGISTRY_CONTROLLER_URL")
|
||||
if len(url) == 0 {
|
||||
return common.DefaultRegistryCtlURL
|
||||
}
|
||||
return url
|
||||
}
|
||||
|
||||
// HTTPAuthProxySetting returns the setting of HTTP Auth proxy. the settings are only meaningful when the auth_mode is
|
||||
// set to http_auth
|
||||
func HTTPAuthProxySetting() (*models.HTTPAuthProxy, error) {
|
||||
if err := cfgMgr.Load(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &models.HTTPAuthProxy{
|
||||
Endpoint: cfgMgr.Get(common.HTTPAuthProxyEndpoint).GetString(),
|
||||
TokenReviewEndpoint: cfgMgr.Get(common.HTTPAuthProxyTokenReviewEndpoint).GetString(),
|
||||
AdminGroups: splitAndTrim(cfgMgr.Get(common.HTTPAuthProxyAdminGroups).GetString(), ","),
|
||||
AdminUsernames: splitAndTrim(cfgMgr.Get(common.HTTPAuthProxyAdminUsernames).GetString(), ","),
|
||||
VerifyCert: cfgMgr.Get(common.HTTPAuthProxyVerifyCert).GetBool(),
|
||||
SkipSearch: cfgMgr.Get(common.HTTPAuthProxySkipSearch).GetBool(),
|
||||
ServerCertificate: cfgMgr.Get(common.HTTPAuthProxyServerCertificate).GetString(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// OIDCSetting returns the setting of OIDC provider, currently there's only one OIDC provider allowed for Harbor and it's
|
||||
// only effective when auth_mode is set to oidc_auth
|
||||
func OIDCSetting() (*models.OIDCSetting, error) {
|
||||
if err := cfgMgr.Load(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
scopeStr := cfgMgr.Get(common.OIDCScope).GetString()
|
||||
extEndpoint := strings.TrimSuffix(cfgMgr.Get(common.ExtEndpoint).GetString(), "/")
|
||||
scope := splitAndTrim(scopeStr, ",")
|
||||
return &models.OIDCSetting{
|
||||
Name: cfgMgr.Get(common.OIDCName).GetString(),
|
||||
Endpoint: cfgMgr.Get(common.OIDCEndpoint).GetString(),
|
||||
VerifyCert: cfgMgr.Get(common.OIDCVerifyCert).GetBool(),
|
||||
AutoOnboard: cfgMgr.Get(common.OIDCAutoOnboard).GetBool(),
|
||||
ClientID: cfgMgr.Get(common.OIDCCLientID).GetString(),
|
||||
ClientSecret: cfgMgr.Get(common.OIDCClientSecret).GetString(),
|
||||
GroupsClaim: cfgMgr.Get(common.OIDCGroupsClaim).GetString(),
|
||||
AdminGroup: cfgMgr.Get(common.OIDCAdminGroup).GetString(),
|
||||
RedirectURL: extEndpoint + common.OIDCCallbackPath,
|
||||
Scope: scope,
|
||||
UserClaim: cfgMgr.Get(common.OIDCUserClaim).GetString(),
|
||||
ExtraRedirectParms: cfgMgr.Get(common.OIDCExtraRedirectParms).GetStringToStringMap(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// NotificationEnable returns a bool to indicates if notification enabled in harbor
|
||||
func NotificationEnable() bool {
|
||||
return cfgMgr.Get(common.NotificationEnable).GetBool()
|
||||
}
|
||||
|
||||
// QuotaPerProjectEnable returns a bool to indicates if quota per project enabled in harbor
|
||||
func QuotaPerProjectEnable() bool {
|
||||
return cfgMgr.Get(common.QuotaPerProjectEnable).GetBool()
|
||||
}
|
||||
|
||||
// QuotaSetting returns the setting of quota.
|
||||
func QuotaSetting() (*models.QuotaSetting, error) {
|
||||
if err := cfgMgr.Load(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &models.QuotaSetting{
|
||||
StoragePerProject: cfgMgr.Get(common.StoragePerProject).GetInt64(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetPermittedRegistryTypesForProxyCache returns the permitted registry types for proxy cache
|
||||
func GetPermittedRegistryTypesForProxyCache() []string {
|
||||
types := os.Getenv("PERMITTED_REGISTRY_TYPES_FOR_PROXY_CACHE")
|
||||
if len(types) == 0 {
|
||||
return []string{}
|
||||
}
|
||||
return strings.Split(types, ",")
|
||||
}
|
||||
|
||||
// GetGCTimeWindow returns the reserve time window of blob.
|
||||
func GetGCTimeWindow() int64 {
|
||||
// the env is for testing/debugging. For production, Do NOT set it.
|
||||
if env, exist := os.LookupEnv("GC_TIME_WINDOW_HOURS"); exist {
|
||||
timeWindow, err := strconv.ParseInt(env, 10, 64)
|
||||
if err == nil {
|
||||
return timeWindow
|
||||
}
|
||||
}
|
||||
return common.DefaultGCTimeWindowHours
|
||||
}
|
||||
|
||||
// RobotPrefix user defined robot name prefix.
|
||||
func RobotPrefix() string {
|
||||
return cfgMgr.Get(common.RobotNamePrefix).GetString()
|
||||
}
|
||||
|
||||
// Metric returns the overall metric settings
|
||||
func Metric() *models.Metric {
|
||||
return &models.Metric{
|
||||
Enabled: cfgMgr.Get(common.MetricEnable).GetBool(),
|
||||
Port: cfgMgr.Get(common.MetricPort).GetInt(),
|
||||
Path: cfgMgr.Get(common.MetricPath).GetString(),
|
||||
}
|
||||
}
|
||||
|
||||
func splitAndTrim(s, sep string) []string {
|
||||
res := make([]string, 0)
|
||||
for _, s := range strings.Split(s, sep) {
|
||||
if e := strings.TrimSpace(s); len(e) > 0 {
|
||||
res = append(res, e)
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
@ -2,12 +2,13 @@ package controllers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/goharbor/harbor/src/controller/config"
|
||||
"github.com/goharbor/harbor/src/lib/orm"
|
||||
"net/http"
|
||||
|
||||
"github.com/goharbor/harbor/src/common"
|
||||
"github.com/goharbor/harbor/src/core/api"
|
||||
"github.com/goharbor/harbor/src/core/auth/authproxy"
|
||||
"github.com/goharbor/harbor/src/core/config"
|
||||
"github.com/goharbor/harbor/src/lib/log"
|
||||
)
|
||||
|
||||
@ -25,7 +26,7 @@ type AuthProxyController struct {
|
||||
|
||||
// Prepare checks the auth mode and fail early
|
||||
func (apc *AuthProxyController) Prepare() {
|
||||
am, err := config.AuthMode()
|
||||
am, err := config.AuthMode(orm.Context())
|
||||
if err != nil {
|
||||
apc.SendInternalServerError(err)
|
||||
return
|
||||
|
@ -17,6 +17,8 @@ package controllers
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"github.com/goharbor/harbor/src/controller/config"
|
||||
"github.com/goharbor/harbor/src/lib/orm"
|
||||
"html/template"
|
||||
"net"
|
||||
"net/http"
|
||||
@ -35,7 +37,6 @@ import (
|
||||
email_util "github.com/goharbor/harbor/src/common/utils/email"
|
||||
"github.com/goharbor/harbor/src/core/api"
|
||||
"github.com/goharbor/harbor/src/core/auth"
|
||||
"github.com/goharbor/harbor/src/core/config"
|
||||
"github.com/goharbor/harbor/src/lib"
|
||||
"github.com/goharbor/harbor/src/lib/log"
|
||||
)
|
||||
@ -123,7 +124,7 @@ func (cc *CommonController) LogOut() {
|
||||
|
||||
// UserExists checks if user exists when user input value in sign in form.
|
||||
func (cc *CommonController) UserExists() {
|
||||
flag, err := config.SelfRegistration()
|
||||
flag, err := config.SelfRegistration(orm.Context())
|
||||
if err != nil {
|
||||
log.Errorf("Failed to get the status of self registration flag, error: %v, disabling user existence check", err)
|
||||
}
|
||||
@ -216,7 +217,7 @@ func (cc *CommonController) SendResetEmail() {
|
||||
cc.CustomAbort(http.StatusInternalServerError, "internal_error")
|
||||
}
|
||||
|
||||
settings, err := config.Email()
|
||||
settings, err := config.Email(orm.Context())
|
||||
if err != nil {
|
||||
log.Errorf("failed to get email configurations: %v", err)
|
||||
cc.CustomAbort(http.StatusInternalServerError, "internal_error")
|
||||
@ -281,7 +282,7 @@ func isUserResetable(u *models.User) bool {
|
||||
if u == nil {
|
||||
return false
|
||||
}
|
||||
mode, err := config.AuthMode()
|
||||
mode, err := config.AuthMode(orm.Context())
|
||||
if err != nil {
|
||||
log.Errorf("Failed to get the auth mode, error: %v", err)
|
||||
return false
|
||||
|
@ -14,10 +14,11 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/goharbor/harbor/src/controller/config"
|
||||
"github.com/goharbor/harbor/src/core/middlewares"
|
||||
"github.com/goharbor/harbor/src/lib"
|
||||
"github.com/goharbor/harbor/src/lib/orm"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
@ -30,7 +31,6 @@ import (
|
||||
"github.com/goharbor/harbor/src/common"
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
utilstest "github.com/goharbor/harbor/src/common/utils/test"
|
||||
"github.com/goharbor/harbor/src/core/config"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
@ -86,9 +86,9 @@ func TestUserResettable(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRedirectForOIDC(t *testing.T) {
|
||||
ctx := lib.WithAuthMode(context.Background(), common.DBAuth)
|
||||
ctx := lib.WithAuthMode(orm.Context(), common.DBAuth)
|
||||
assert.False(t, redirectForOIDC(ctx, "nonexist"))
|
||||
ctx = lib.WithAuthMode(context.Background(), common.OIDCAuth)
|
||||
ctx = lib.WithAuthMode(orm.Context(), common.OIDCAuth)
|
||||
assert.True(t, redirectForOIDC(ctx, "nonexist"))
|
||||
assert.False(t, redirectForOIDC(ctx, "admin"))
|
||||
|
||||
|
@ -17,6 +17,8 @@ package controllers
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/goharbor/harbor/src/controller/config"
|
||||
"github.com/goharbor/harbor/src/lib/orm"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
@ -25,7 +27,6 @@ import (
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
"github.com/goharbor/harbor/src/common/utils"
|
||||
"github.com/goharbor/harbor/src/core/api"
|
||||
"github.com/goharbor/harbor/src/core/config"
|
||||
"github.com/goharbor/harbor/src/lib/errors"
|
||||
"github.com/goharbor/harbor/src/lib/log"
|
||||
"github.com/goharbor/harbor/src/pkg/oidc"
|
||||
@ -47,7 +48,7 @@ type onboardReq struct {
|
||||
|
||||
// Prepare include public code path for call request handler of OIDCController
|
||||
func (oc *OIDCController) Prepare() {
|
||||
if mode, _ := config.AuthMode(); mode != common.OIDCAuth {
|
||||
if mode, _ := config.AuthMode(orm.Context()); mode != common.OIDCAuth {
|
||||
oc.SendPreconditionFailedError(fmt.Errorf("auth mode: %s is not OIDC based", mode))
|
||||
return
|
||||
}
|
||||
@ -121,7 +122,7 @@ func (oc *OIDCController) Callback() {
|
||||
}
|
||||
oc.SetSession(tokenKey, tokenBytes)
|
||||
|
||||
oidcSettings, err := config.OIDCSetting()
|
||||
oidcSettings, err := config.OIDCSetting(ctx)
|
||||
if err != nil {
|
||||
oc.SendInternalServerError(err)
|
||||
return
|
||||
|
@ -18,6 +18,7 @@ import (
|
||||
"context"
|
||||
"encoding/gob"
|
||||
"fmt"
|
||||
"github.com/goharbor/harbor/src/controller/config"
|
||||
"net/url"
|
||||
"os"
|
||||
"os/signal"
|
||||
@ -41,7 +42,6 @@ import (
|
||||
_ "github.com/goharbor/harbor/src/core/auth/ldap"
|
||||
_ "github.com/goharbor/harbor/src/core/auth/oidc"
|
||||
_ "github.com/goharbor/harbor/src/core/auth/uaa"
|
||||
"github.com/goharbor/harbor/src/core/config"
|
||||
"github.com/goharbor/harbor/src/core/middlewares"
|
||||
"github.com/goharbor/harbor/src/core/service/token"
|
||||
"github.com/goharbor/harbor/src/lib/cache"
|
||||
@ -189,7 +189,7 @@ func main() {
|
||||
if err = migration.Migrate(database); err != nil {
|
||||
log.Fatalf("failed to migrate: %v", err)
|
||||
}
|
||||
if err := config.Load(); err != nil {
|
||||
if err := config.Load(orm.Context()); err != nil {
|
||||
log.Fatalf("failed to load config: %v", err)
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,7 @@ package token
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/goharbor/harbor/src/controller/config"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@ -27,7 +28,6 @@ import (
|
||||
"github.com/goharbor/harbor/src/common/security"
|
||||
"github.com/goharbor/harbor/src/common/utils"
|
||||
"github.com/goharbor/harbor/src/controller/project"
|
||||
"github.com/goharbor/harbor/src/core/config"
|
||||
"github.com/goharbor/harbor/src/lib/log"
|
||||
tokenpkg "github.com/goharbor/harbor/src/pkg/token"
|
||||
v2 "github.com/goharbor/harbor/src/pkg/token/claims/v2"
|
||||
@ -109,12 +109,12 @@ func filterAccess(ctx context.Context, access []*token.ResourceActions,
|
||||
}
|
||||
|
||||
// MakeToken makes a valid jwt token based on parms.
|
||||
func MakeToken(username, service string, access []*token.ResourceActions) (*models.Token, error) {
|
||||
func MakeToken(ctx context.Context, username, service string, access []*token.ResourceActions) (*models.Token, error) {
|
||||
options, err := tokenpkg.NewOptions(signingMethod, v2.Issuer, privateKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
expiration, err := config.TokenExpiration()
|
||||
expiration, err := config.TokenExpiration(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
rbac_project "github.com/goharbor/harbor/src/common/rbac/project"
|
||||
"github.com/goharbor/harbor/src/controller/config"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
@ -27,7 +28,6 @@ import (
|
||||
"github.com/goharbor/harbor/src/common/rbac"
|
||||
"github.com/goharbor/harbor/src/common/security"
|
||||
"github.com/goharbor/harbor/src/controller/project"
|
||||
"github.com/goharbor/harbor/src/core/config"
|
||||
"github.com/goharbor/harbor/src/lib/errors"
|
||||
"github.com/goharbor/harbor/src/lib/log"
|
||||
)
|
||||
@ -245,7 +245,7 @@ func (g generalCreator) Create(r *http.Request) (*models.Token, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return MakeToken(ctx.GetUsername(), g.service, access)
|
||||
return MakeToken(r.Context(), ctx.GetUsername(), g.service, access)
|
||||
}
|
||||
|
||||
func parseScopes(u *url.URL) []string {
|
||||
|
@ -20,6 +20,9 @@ import (
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"github.com/goharbor/harbor/src/common/rbac/project"
|
||||
"github.com/goharbor/harbor/src/common/utils/test"
|
||||
"github.com/goharbor/harbor/src/controller/config"
|
||||
"github.com/goharbor/harbor/src/lib/orm"
|
||||
"io/ioutil"
|
||||
"net/url"
|
||||
"os"
|
||||
@ -32,11 +35,11 @@ import (
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
"github.com/goharbor/harbor/src/common/rbac"
|
||||
"github.com/goharbor/harbor/src/common/security"
|
||||
"github.com/goharbor/harbor/src/core/config"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
test.InitDatabaseFromEnv()
|
||||
config.Init()
|
||||
InitCreators()
|
||||
result := m.Run()
|
||||
@ -133,7 +136,7 @@ func TestMakeToken(t *testing.T) {
|
||||
}}
|
||||
svc := "harbor-registry"
|
||||
u := "tester"
|
||||
tokenJSON, err := MakeToken(u, svc, ra)
|
||||
tokenJSON, err := MakeToken(orm.Context(), u, svc, ra)
|
||||
if err != nil {
|
||||
t.Errorf("Error while making token: %v", err)
|
||||
}
|
||||
|
@ -17,8 +17,7 @@ package utils
|
||||
|
||||
import (
|
||||
"github.com/goharbor/harbor/src/common/job"
|
||||
"github.com/goharbor/harbor/src/core/config"
|
||||
|
||||
"github.com/goharbor/harbor/src/controller/config"
|
||||
"sync"
|
||||
)
|
||||
|
||||
|
@ -23,12 +23,12 @@ import (
|
||||
"time"
|
||||
|
||||
o "github.com/astaxie/beego/orm"
|
||||
comcfg "github.com/goharbor/harbor/src/common/config"
|
||||
"github.com/goharbor/harbor/src/common/dao"
|
||||
"github.com/goharbor/harbor/src/jobservice/config"
|
||||
"github.com/goharbor/harbor/src/jobservice/job"
|
||||
"github.com/goharbor/harbor/src/jobservice/logger"
|
||||
"github.com/goharbor/harbor/src/jobservice/logger/sweeper"
|
||||
libCfg "github.com/goharbor/harbor/src/lib/config"
|
||||
"github.com/goharbor/harbor/src/lib/orm"
|
||||
)
|
||||
|
||||
@ -45,7 +45,7 @@ type Context struct {
|
||||
// other required information
|
||||
properties map[string]interface{}
|
||||
// admin server client
|
||||
cfgMgr comcfg.CfgManager
|
||||
cfgMgr libCfg.Manager
|
||||
// job life cycle tracker
|
||||
tracker job.Tracker
|
||||
// job logger configs settings map lock
|
||||
@ -53,10 +53,10 @@ type Context struct {
|
||||
}
|
||||
|
||||
// NewContext ...
|
||||
func NewContext(sysCtx context.Context, cfgMgr *comcfg.CfgManager) *Context {
|
||||
func NewContext(sysCtx context.Context, cfgMgr libCfg.Manager) *Context {
|
||||
return &Context{
|
||||
sysContext: comcfg.NewContext(sysCtx, cfgMgr),
|
||||
cfgMgr: *cfgMgr,
|
||||
sysContext: libCfg.NewContext(sysCtx, cfgMgr),
|
||||
cfgMgr: cfgMgr,
|
||||
properties: make(map[string]interface{}),
|
||||
}
|
||||
}
|
||||
@ -70,7 +70,7 @@ func (c *Context) Init() error {
|
||||
|
||||
for counter == 0 || err != nil {
|
||||
counter++
|
||||
err = c.cfgMgr.Load()
|
||||
err = c.cfgMgr.Load(c.sysContext)
|
||||
if err != nil {
|
||||
logger.Errorf("Job context initialization error: %s\n", err.Error())
|
||||
if counter < maxRetryTimes {
|
||||
@ -117,12 +117,12 @@ func (c *Context) Build(tracker job.Tracker) (job.Context, error) {
|
||||
}
|
||||
|
||||
// Refresh config properties
|
||||
err := c.cfgMgr.Load()
|
||||
err := c.cfgMgr.Load(c.sysContext)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
props := c.cfgMgr.GetAll()
|
||||
props := c.cfgMgr.GetAll(c.sysContext)
|
||||
for k, v := range props {
|
||||
jContext.properties[k] = v
|
||||
}
|
||||
|
@ -16,17 +16,20 @@ package impl
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/goharbor/harbor/src/common"
|
||||
common_dao "github.com/goharbor/harbor/src/common/dao"
|
||||
libCfg "github.com/goharbor/harbor/src/lib/config"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/goharbor/harbor/src/jobservice/common/list"
|
||||
|
||||
comcfg "github.com/goharbor/harbor/src/common/config"
|
||||
"github.com/goharbor/harbor/src/jobservice/common/utils"
|
||||
"github.com/goharbor/harbor/src/jobservice/config"
|
||||
"github.com/goharbor/harbor/src/jobservice/job"
|
||||
"github.com/goharbor/harbor/src/jobservice/tests"
|
||||
_ "github.com/goharbor/harbor/src/pkg/config/inmemory"
|
||||
_ "github.com/goharbor/harbor/src/pkg/config/rest"
|
||||
"github.com/gomodule/redigo/redis"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
@ -110,9 +113,11 @@ func (suite *ContextImplTestSuite) TearDownSuite() {
|
||||
|
||||
// TestContextImpl tests the context impl
|
||||
func (suite *ContextImplTestSuite) TestContextImpl() {
|
||||
cfgMem := comcfg.NewInMemoryManager()
|
||||
cfgMem.Set("read_only", "true")
|
||||
ctx := NewContext(context.Background(), cfgMem)
|
||||
cfgMem, err := libCfg.GetManager(common.InMemoryCfgManager)
|
||||
assert.Nil(suite.T(), err)
|
||||
cont := context.Background()
|
||||
cfgMem.Set(cont, "read_only", "true")
|
||||
ctx := NewContext(cont, cfgMem)
|
||||
jCtx, err := ctx.Build(suite.tracker)
|
||||
|
||||
require.NoErrorf(suite.T(), err, "build job context: nil error expected but got %s", err)
|
||||
|
@ -16,11 +16,12 @@ package gcreadonly
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/goharbor/harbor/src/lib/config"
|
||||
"github.com/goharbor/harbor/src/lib/orm"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/goharbor/harbor/src/common"
|
||||
"github.com/goharbor/harbor/src/common/config"
|
||||
"github.com/goharbor/harbor/src/common/registryctl"
|
||||
"github.com/goharbor/harbor/src/controller/artifact"
|
||||
"github.com/goharbor/harbor/src/controller/project"
|
||||
@ -36,19 +37,21 @@ import (
|
||||
var (
|
||||
regCtlInit = registryctl.Init
|
||||
|
||||
getReadOnly = func(cfgMgr *config.CfgManager) (bool, error) {
|
||||
if err := cfgMgr.Load(); err != nil {
|
||||
getReadOnly = func(cfgMgr config.Manager) (bool, error) {
|
||||
cxt := orm.Context()
|
||||
if err := cfgMgr.Load(cxt); err != nil {
|
||||
return false, err
|
||||
}
|
||||
return cfgMgr.Get(common.ReadOnly).GetBool(), nil
|
||||
return cfgMgr.Get(cxt, common.ReadOnly).GetBool(), nil
|
||||
}
|
||||
|
||||
setReadOnly = func(cfgMgr *config.CfgManager, switcher bool) error {
|
||||
setReadOnly = func(cfgMgr config.Manager, switcher bool) error {
|
||||
cxt := orm.Context()
|
||||
cfg := map[string]interface{}{
|
||||
common.ReadOnly: switcher,
|
||||
}
|
||||
cfgMgr.UpdateConfig(cfg)
|
||||
return cfgMgr.Save()
|
||||
cfgMgr.UpdateConfig(cxt, cfg)
|
||||
return cfgMgr.Save(cxt)
|
||||
}
|
||||
)
|
||||
|
||||
@ -69,7 +72,7 @@ type GarbageCollector struct {
|
||||
projectCtl project.Controller
|
||||
registryCtlClient client.Client
|
||||
logger logger.Interface
|
||||
cfgMgr *config.CfgManager
|
||||
cfgMgr config.Manager
|
||||
CoreURL string
|
||||
redisURL string
|
||||
deleteUntagged bool
|
||||
@ -164,15 +167,11 @@ func (gc *GarbageCollector) init(ctx job.Context, params job.Parameters) error {
|
||||
return err
|
||||
}
|
||||
|
||||
errTpl := "failed to get required property: %s"
|
||||
if v, ok := ctx.Get(common.CoreURL); ok && len(v.(string)) > 0 {
|
||||
gc.CoreURL = v.(string)
|
||||
} else {
|
||||
return fmt.Errorf(errTpl, common.CoreURL)
|
||||
mgr, err := config.GetManager(common.RestCfgManager)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
secret := os.Getenv("JOBSERVICE_SECRET")
|
||||
configURL := gc.CoreURL + common.CoreConfigPath
|
||||
gc.cfgMgr = config.NewRESTCfgManager(configURL, secret)
|
||||
gc.cfgMgr = mgr
|
||||
gc.redisURL = params["redis_url_reg"].(string)
|
||||
|
||||
// default is to delete the untagged artifact
|
||||
|
@ -15,10 +15,11 @@
|
||||
package gcreadonly
|
||||
|
||||
import (
|
||||
"github.com/goharbor/harbor/src/common"
|
||||
"github.com/goharbor/harbor/src/lib/config"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/goharbor/harbor/src/common/config"
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
commom_regctl "github.com/goharbor/harbor/src/common/registryctl"
|
||||
"github.com/goharbor/harbor/src/controller/project"
|
||||
@ -26,6 +27,10 @@ import (
|
||||
"github.com/goharbor/harbor/src/pkg/artifact"
|
||||
"github.com/goharbor/harbor/src/pkg/artifactrash/model"
|
||||
pkg_blob "github.com/goharbor/harbor/src/pkg/blob/models"
|
||||
_ "github.com/goharbor/harbor/src/pkg/config/db"
|
||||
_ "github.com/goharbor/harbor/src/pkg/config/inmemory"
|
||||
_ "github.com/goharbor/harbor/src/pkg/config/rest"
|
||||
|
||||
artifacttesting "github.com/goharbor/harbor/src/testing/controller/artifact"
|
||||
projecttesting "github.com/goharbor/harbor/src/testing/controller/project"
|
||||
mockjobservice "github.com/goharbor/harbor/src/testing/jobservice"
|
||||
@ -47,8 +52,8 @@ type gcTestSuite struct {
|
||||
originalProjectCtl project.Controller
|
||||
|
||||
regCtlInit func()
|
||||
setReadOnly func(cfgMgr *config.CfgManager, switcher bool) error
|
||||
getReadOnly func(cfgMgr *config.CfgManager) (bool, error)
|
||||
setReadOnly func(cfgMgr config.Manager, switcher bool) error
|
||||
getReadOnly func(cfgMgr config.Manager) (bool, error)
|
||||
}
|
||||
|
||||
func (suite *gcTestSuite) SetupTest() {
|
||||
@ -62,8 +67,8 @@ func (suite *gcTestSuite) SetupTest() {
|
||||
project.Ctl = suite.projectCtl
|
||||
|
||||
regCtlInit = func() { commom_regctl.RegistryCtlClient = suite.registryCtlClient }
|
||||
setReadOnly = func(cfgMgr *config.CfgManager, switcher bool) error { return nil }
|
||||
getReadOnly = func(cfgMgr *config.CfgManager) (bool, error) { return true, nil }
|
||||
setReadOnly = func(cfgMgr config.Manager, switcher bool) error { return nil }
|
||||
getReadOnly = func(cfgMgr config.Manager) (bool, error) { return true, nil }
|
||||
}
|
||||
|
||||
func (suite *gcTestSuite) TearDownTest() {
|
||||
@ -237,11 +242,12 @@ func (suite *gcTestSuite) TestRun() {
|
||||
}, nil)
|
||||
|
||||
mock.OnAnything(suite.blobMgr, "CleanupAssociationsForProject").Return(nil)
|
||||
|
||||
mgr, err := config.GetManager(common.InMemoryCfgManager)
|
||||
suite.Nil(err)
|
||||
gc := &GarbageCollector{
|
||||
artCtl: suite.artifactCtl,
|
||||
artrashMgr: suite.artrashMgr,
|
||||
cfgMgr: config.NewInMemoryManager(),
|
||||
cfgMgr: mgr,
|
||||
blobMgr: suite.blobMgr,
|
||||
registryCtlClient: suite.registryCtlClient,
|
||||
}
|
||||
|
@ -19,15 +19,15 @@ import (
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
|
||||
"github.com/goharbor/harbor/src/common"
|
||||
comcfg "github.com/goharbor/harbor/src/common/config"
|
||||
"github.com/goharbor/harbor/src/jobservice/common/utils"
|
||||
"github.com/goharbor/harbor/src/jobservice/config"
|
||||
"github.com/goharbor/harbor/src/jobservice/job"
|
||||
"github.com/goharbor/harbor/src/jobservice/job/impl"
|
||||
"github.com/goharbor/harbor/src/jobservice/logger"
|
||||
"github.com/goharbor/harbor/src/jobservice/runtime"
|
||||
cfgLib "github.com/goharbor/harbor/src/lib/config"
|
||||
_ "github.com/goharbor/harbor/src/pkg/config/rest"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@ -63,9 +63,10 @@ func main() {
|
||||
if utils.IsEmptyStr(secret) {
|
||||
return nil, errors.New("empty auth secret")
|
||||
}
|
||||
coreURL := config.GetCoreURL()
|
||||
configURL := coreURL + common.CoreConfigPath
|
||||
cfgMgr := comcfg.NewRESTCfgManager(configURL, secret)
|
||||
cfgMgr, err := cfgLib.GetManager(common.RestCfgManager)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
jobCtx := impl.NewContext(ctx, cfgMgr)
|
||||
|
||||
if err := jobCtx.Init(); err != nil {
|
||||
|
48
src/lib/config/config.go
Normal file
48
src/lib/config/config.go
Normal file
@ -0,0 +1,48 @@
|
||||
// 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 config
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/goharbor/harbor/src/lib/log"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var (
|
||||
managersMU sync.RWMutex
|
||||
managers = make(map[string]Manager)
|
||||
)
|
||||
|
||||
// Register register the config manager
|
||||
func Register(name string, mgr Manager) {
|
||||
managersMU.Lock()
|
||||
defer managersMU.Unlock()
|
||||
if mgr == nil {
|
||||
log.Error("Register manager is nil")
|
||||
}
|
||||
if _, dup := managers[name]; dup {
|
||||
log.Errorf("Register called twice for manager " + name)
|
||||
}
|
||||
managers[name] = mgr
|
||||
}
|
||||
|
||||
// GetManager get the configure manager by name
|
||||
func GetManager(name string) (Manager, error) {
|
||||
mgr, ok := managers[name]
|
||||
if !ok {
|
||||
return nil, errors.New("config manager is not registered: " + name)
|
||||
}
|
||||
return mgr, nil
|
||||
}
|
@ -16,17 +16,32 @@ package config
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
"github.com/goharbor/harbor/src/lib/config/metadata"
|
||||
)
|
||||
|
||||
type cfgMgrKey struct{}
|
||||
|
||||
// Manager defines the operation for config
|
||||
type Manager interface {
|
||||
Load(ctx context.Context) error
|
||||
Set(ctx context.Context, key string, value interface{})
|
||||
Save(ctx context.Context) error
|
||||
Get(ctx context.Context, key string) *metadata.ConfigureValue
|
||||
UpdateConfig(ctx context.Context, cfgs map[string]interface{}) error
|
||||
GetUserCfgs(ctx context.Context) map[string]interface{}
|
||||
ValidateCfg(ctx context.Context, cfgs map[string]interface{}) error
|
||||
GetAll(ctx context.Context) map[string]interface{}
|
||||
GetDatabaseCfg() *models.Database
|
||||
}
|
||||
|
||||
// FromContext returns CfgManager from context
|
||||
func FromContext(ctx context.Context) (*CfgManager, bool) {
|
||||
m, ok := ctx.Value(cfgMgrKey{}).(*CfgManager)
|
||||
func FromContext(ctx context.Context) (Manager, bool) {
|
||||
m, ok := ctx.Value(cfgMgrKey{}).(Manager)
|
||||
return m, ok
|
||||
}
|
||||
|
||||
// NewContext returns context with CfgManager
|
||||
func NewContext(ctx context.Context, m *CfgManager) context.Context {
|
||||
func NewContext(ctx context.Context, m Manager) context.Context {
|
||||
return context.WithValue(ctx, cfgMgrKey{}, m)
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user