harbor/src/pkg/config/manager.go

221 lines
6.8 KiB
Go

// 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"
"fmt"
"os"
"strconv"
"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"
"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/store"
"github.com/goharbor/harbor/src/pkg/config/validate"
)
// CfgManager ... Configure Manager
type CfgManager struct {
Store *store.ConfigStore
}
var validateRules = []validate.Rule{
&validate.LdapGroupValidateRule{},
}
// 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(ctx context.Context) map[string]interface{} {
resultMap := map[string]interface{}{}
if err := c.Store.Load(ctx); err != nil {
log.Errorf("AllConfigs 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(ctx context.Context) map[string]interface{} {
resultMap := map[string]interface{}{}
if err := c.Store.Load(ctx); err != nil {
log.Errorf("UserConfigs 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(ctx context.Context) error {
return c.Store.Load(ctx)
}
// Save - Save all current configuration to storage
func (c *CfgManager) Save(ctx context.Context) error {
return c.Store.Save(ctx)
}
// Get ...
func (c *CfgManager) Get(_ context.Context, key string) *metadata.ConfigureValue {
configValue, err := c.Store.Get(key)
if err != nil {
log.Debugf("failed to get key %v, error: %v, maybe default value not defined before get", key, err)
configValue = &metadata.ConfigureValue{}
}
return configValue
}
// Set ...
func (c *CfgManager) Set(_ context.Context, 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 {
ctx := context.Background()
return &models.Database{
Type: c.Get(ctx, common.DatabaseType).GetString(),
PostGreSQL: &models.PostGreSQL{
Host: c.Get(ctx, common.PostGreSQLHOST).GetString(),
Port: c.Get(ctx, common.PostGreSQLPort).GetInt(),
Username: c.Get(ctx, common.PostGreSQLUsername).GetString(),
Password: c.Get(ctx, common.PostGreSQLPassword).GetString(),
Database: c.Get(ctx, common.PostGreSQLDatabase).GetString(),
SSLMode: c.Get(ctx, common.PostGreSQLSSLMode).GetString(),
MaxIdleConns: c.Get(ctx, common.PostGreSQLMaxIdleConns).GetInt(),
MaxOpenConns: c.Get(ctx, common.PostGreSQLMaxOpenConns).GetInt(),
ConnMaxLifetime: c.Get(ctx, common.PostGreSQLConnMaxLifetime).GetDuration(),
ConnMaxIdleTime: c.Get(ctx, common.PostGreSQLConnMaxIdleTime).GetDuration(),
},
}
}
// UpdateConfig - Update config Store with a specified configuration and also save updated configure.
func (c *CfgManager) UpdateConfig(ctx context.Context, cfgs map[string]interface{}) error {
return c.Store.Update(ctx, cfgs)
}
// ValidateCfg validate config by metadata. return the first error if exist.
func (c *CfgManager) ValidateCfg(ctx context.Context, cfgs map[string]interface{}) error {
for key, value := range cfgs {
item, exist := metadata.Instance().GetByName(key)
if !exist {
return fmt.Errorf("invalid config, item not defined in metadatalist, %v", key)
}
if item.Scope == metadata.SystemScope {
return fmt.Errorf("system config items cannot be updated, item: %v", key)
}
strVal := utils.GetStrValueOfAnyType(value)
// check storage per project before setting it
if key == common.StoragePerProject {
storagePerProject, err := strconv.ParseInt(strVal, 10, 64)
if err != nil {
return fmt.Errorf("cannot parse string value(%v) to int64", strVal)
}
if err := lib.ValidateQuotaLimit(storagePerProject); err != nil {
return err
}
}
_, err := metadata.NewCfgValue(key, strVal)
if err != nil {
return errors.Wrap(err, "item name "+key)
}
}
for _, r := range validateRules {
if err := r.Validate(ctx, c, cfgs); err != nil {
return err
}
}
return nil
}