This commit is contained in:
Wenkai Yin 2017-01-20 13:30:49 +08:00
parent b6e27f6ea2
commit f113f4a54f
22 changed files with 512 additions and 534 deletions

View File

@ -0,0 +1,32 @@
/*
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package api
import (
"net/http"
"net/http/httptest"
"testing"
)
func TestHandleInternalServerError(t *testing.T) {
w := httptest.NewRecorder()
handleInternalServerError(w)
if w.Code != http.StatusInternalServerError {
t.Errorf("unexpected status code: %d != %d", w.Code, http.StatusInternalServerError)
}
}

View File

@ -20,11 +20,8 @@ import (
"io/ioutil"
"net/http"
"os"
"strconv"
cfg "github.com/vmware/harbor/src/adminserver/systemcfg"
comcfg "github.com/vmware/harbor/src/common/config"
"github.com/vmware/harbor/src/common/models"
"github.com/vmware/harbor/src/common/utils/log"
)
@ -93,31 +90,20 @@ func UpdateCfgs(w http.ResponseWriter, r *http.Request) {
return
}
m := &map[string]string{}
if err = json.Unmarshal(b, m); err != nil {
m := map[string]interface{}{}
if err = json.Unmarshal(b, &m); err != nil {
handleBadRequestError(w, err.Error())
return
}
system, err := cfg.GetSystemCfg()
if err != nil {
handleInternalServerError(w)
return
}
if err := populate(system, *m); err != nil {
log.Errorf("failed to populate system configurations: %v", err)
handleInternalServerError(w)
return
}
if err = cfg.UpdateSystemCfg(system); err != nil {
if err = cfg.UpdateSystemCfg(m); err != nil {
log.Errorf("failed to update system configurations: %v", err)
handleInternalServerError(w)
return
}
}
/*
// populate attrs of cfg according to m
func populate(cfg *models.SystemCfg, m map[string]string) error {
if mode, ok := m[comcfg.AUTHMode]; ok {
@ -133,7 +119,7 @@ func populate(cfg *models.SystemCfg, m map[string]string) error {
cfg.Authentication.LDAP.SearchDN = dn
}
if pwd, ok := m[comcfg.LDAPSearchPwd]; ok {
cfg.Authentication.LDAP.SearchPwd = pwd
cfg.Authentication.LDAP.SearchPassword = pwd
}
if dn, ok := m[comcfg.LDAPBaseDN]; ok {
cfg.Authentication.LDAP.BaseDN = dn
@ -191,3 +177,4 @@ func populate(cfg *models.SystemCfg, m map[string]string) error {
return nil
}
*/

View File

@ -0,0 +1,25 @@
/*
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package api
import (
"net/http/httptest"
)
func test() {
httptest.NewRecorder()
}

View File

@ -15,16 +15,13 @@
package store
import (
"github.com/vmware/harbor/src/common/models"
)
// Driver defines methods that a configuration store driver must implement
type Driver interface {
// Name returns a human-readable name of the driver
Name() string
// Read reads the configurations from store
Read() (*models.SystemCfg, error)
// Write writes the configurations to store
Write(*models.SystemCfg) error
// Read reads all the configurations from store
Read() (map[string]interface{}, error)
// Write writes the configurations to store, the configurations can be
// part of all
Write(map[string]interface{}) error
}

View File

@ -23,7 +23,6 @@ import (
"sync"
"github.com/vmware/harbor/src/adminserver/systemcfg/store"
"github.com/vmware/harbor/src/common/models"
"github.com/vmware/harbor/src/common/utils/log"
)
@ -68,11 +67,15 @@ func (c *cfgStore) Name() string {
}
// Read ...
func (c *cfgStore) Read() (*models.SystemCfg, error) {
func (c *cfgStore) Read() (map[string]interface{}, error) {
c.RLock()
defer c.RUnlock()
b, err := ioutil.ReadFile(c.path)
return read(c.path)
}
func read(path string) (map[string]interface{}, error) {
b, err := ioutil.ReadFile(path)
if err != nil {
return nil, err
}
@ -82,8 +85,8 @@ func (c *cfgStore) Read() (*models.SystemCfg, error) {
return nil, nil
}
config := &models.SystemCfg{}
if err = json.Unmarshal(b, config); err != nil {
config := map[string]interface{}{}
if err = json.Unmarshal(b, &config); err != nil {
return nil, err
}
@ -91,14 +94,27 @@ func (c *cfgStore) Read() (*models.SystemCfg, error) {
}
// Write ...
func (c *cfgStore) Write(config *models.SystemCfg) error {
b, err := json.MarshalIndent(config, "", " ")
func (c *cfgStore) Write(config map[string]interface{}) error {
c.Lock()
defer c.Unlock()
cfg, err := read(c.path)
if err != nil {
return err
}
c.Lock()
defer c.Unlock()
if cfg == nil {
cfg = config
} else {
for k, v := range config {
cfg[k] = v
}
}
b, err := json.MarshalIndent(cfg, "", " ")
if err != nil {
return err
}
if err = ioutil.WriteFile(c.path, b, 0600); err != nil {
return err

View File

@ -18,8 +18,6 @@ package json
import (
"os"
"testing"
"github.com/vmware/harbor/src/common/models"
)
func TestReadWrite(t *testing.T) {
@ -34,19 +32,21 @@ func TestReadWrite(t *testing.T) {
}
}()
config := &models.SystemCfg{
Authentication: &models.Authentication{
LDAP: &models.LDAP{},
},
Database: &models.Database{
MySQL: &models.MySQL{},
},
if store.Name() != "JSON" {
t.Errorf("unexpected name: %s != %s", store.Name(), "JSON")
return
}
config := map[string]interface{}{
"key": "value",
}
if err := store.Write(config); err != nil {
t.Fatalf("failed to write configurations to json file: %v", err)
t.Errorf("failed to write configurations to json file: %v", err)
return
}
if _, err = store.Read(); err != nil {
t.Fatalf("failed to read configurations from json file: %v", err)
t.Errorf("failed to read configurations from json file: %v", err)
return
}
}

View File

@ -22,7 +22,7 @@ import (
"github.com/vmware/harbor/src/adminserver/systemcfg/store"
"github.com/vmware/harbor/src/adminserver/systemcfg/store/json"
"github.com/vmware/harbor/src/common/models"
comcfg "github.com/vmware/harbor/src/common/config"
"github.com/vmware/harbor/src/common/utils/log"
)
@ -77,112 +77,95 @@ func getCfgStore() string {
}
//read the following attrs from env every time boots up
func readFromEnv(cfg *models.SystemCfg) error {
cfg.DomainName = os.Getenv("EXT_ENDPOINT")
func readFromEnv(cfg map[string]interface{}) error {
cfg[comcfg.DomainName] = os.Getenv("EXT_ENDPOINT")
cfg.Database = &models.Database{
Type: os.Getenv("DATABASE_TYPE"),
MySQL: &models.MySQL{
Host: os.Getenv("MYSQL_HOST"),
Username: os.Getenv("MYSQL_USR"),
Password: os.Getenv("MYSQL_PWD"),
Database: os.Getenv("MYSQL_DATABASE"),
},
SQLite: &models.SQLite{
File: os.Getenv("SQLITE_FILE"),
},
}
cfg[comcfg.DatabaseType] = os.Getenv("DATABASE_TYPE")
cfg[comcfg.MySQLHost] = os.Getenv("MYSQL_HOST")
port, err := strconv.Atoi(os.Getenv("MYSQL_PORT"))
if err != nil {
return err
}
cfg.Database.MySQL.Port = port
cfg.TokenService = &models.TokenService{
URL: os.Getenv("TOKEN_SERVICE_URL"),
}
cfg.Registry = &models.Registry{
URL: os.Getenv("REGISTRY_URL"),
}
//TODO remove
cfg.JobLogDir = os.Getenv("LOG_DIR")
//TODO remove
cfg.CompressJS = os.Getenv("USE_COMPRESSED_JS") == "on"
exp, err := strconv.Atoi(os.Getenv("TOKEN_EXPIRATION"))
cfg[comcfg.MySQLPort] = port
cfg[comcfg.MySQLUsername] = os.Getenv("MYSQL_USR")
cfg[comcfg.MySQLPassword] = os.Getenv("MYSQL_PWD")
cfg[comcfg.MySQLDatabase] = os.Getenv("MYSQL_DATABASE")
cfg[comcfg.SQLiteFile] = os.Getenv("SQLITE_FILE")
cfg[comcfg.TokenServiceURL] = os.Getenv("TOKEN_SERVICE_URL")
tokenExpi, err := strconv.Atoi(os.Getenv("TOKEN_EXPIRATION"))
if err != nil {
return err
}
cfg.TokenExpiration = exp
cfg.SecretKey = os.Getenv("SECRET_KEY")
cfgExp, err := strconv.Atoi(os.Getenv("CFG_EXPIRATION"))
cfg[comcfg.TokenExpiration] = tokenExpi
cfg[comcfg.RegistryURL] = os.Getenv("REGISTRY_URL")
//TODO remove
cfg[comcfg.JobLogDir] = os.Getenv("LOG_DIR")
//TODO remove
cfg[comcfg.UseCompressedJS] = os.Getenv("USE_COMPRESSED_JS") == "on"
cfg[comcfg.SecretKey] = os.Getenv("SECRET_KEY")
cfgExpi, err := strconv.Atoi(os.Getenv("CFG_EXPIRATION"))
if err != nil {
return err
}
cfg.CfgExpiration = cfgExp
cfg[comcfg.CfgExpiration] = cfgExpi
workers, err := strconv.Atoi(os.Getenv("MAX_JOB_WORKERS"))
if err != nil {
return err
}
cfg.MaxJobWorkers = workers
cfg[comcfg.MaxJobWorkers] = workers
return nil
}
func initFromEnv() (*models.SystemCfg, error) {
cfg := &models.SystemCfg{}
func initFromEnv() (map[string]interface{}, error) {
cfg := map[string]interface{}{}
if err := readFromEnv(cfg); err != nil {
return nil, err
}
cfg.Authentication = &models.Authentication{
Mode: os.Getenv("AUTH_MODE"),
SelfRegistration: os.Getenv("SELF_REGISTRATION") == "on",
LDAP: &models.LDAP{
URL: os.Getenv("LDAP_URL"),
SearchDN: os.Getenv("LDAP_SEARCH_DN"),
SearchPwd: os.Getenv("LDAP_SEARCH_PWD"),
BaseDN: os.Getenv("LDAP_BASE_DN"),
Filter: os.Getenv("LDAP_FILTER"),
UID: os.Getenv("LDAP_UID"),
},
}
cfg[comcfg.AUTHMode] = os.Getenv("AUTH_MODE")
cfg[comcfg.SelfRegistration] = os.Getenv("SELF_REGISTRATION") == "on"
cfg[comcfg.LDAPURL] = os.Getenv("LDAP_URL")
cfg[comcfg.LDAPSearchDN] = os.Getenv("LDAP_SEARCH_DN")
cfg[comcfg.LDAPSearchPwd] = os.Getenv("LDAP_SEARCH_PWD")
cfg[comcfg.LDAPBaseDN] = os.Getenv("LDAP_BASE_DN")
cfg[comcfg.LDAPFilter] = os.Getenv("LDAP_FILTER")
cfg[comcfg.LDAPUID] = os.Getenv("LDAP_UID")
scope, err := strconv.Atoi(os.Getenv("LDAP_SCOPE"))
if err != nil {
return nil, err
}
cfg.Authentication.LDAP.Scope = scope
cfg[comcfg.LDAPScope] = scope
timeout, err := strconv.Atoi(os.Getenv("LDAP_TIMEOUT"))
if err != nil {
return nil, err
}
cfg.Authentication.LDAP.Timeout = timeout
cfg.Email = &models.Email{
Host: os.Getenv("EMAIL_HOST"),
Port: os.Getenv("EMAIL_PORT"),
Username: os.Getenv("EMAIL_USR"),
Password: os.Getenv("EMAIL_PWD"),
SSL: os.Getenv("EMAIL_SSL") == "true",
From: os.Getenv("EMAIL_FROM"),
Identity: os.Getenv("EMAIL_IDENTITY"),
cfg[comcfg.LDAPTimeout] = timeout
cfg[comcfg.EmailHost] = os.Getenv("EMAIL_HOST")
port, err := strconv.Atoi(os.Getenv("EMAIL_PORT"))
if err != nil {
return nil, err
}
cfg.VerifyRemoteCert = os.Getenv("VERIFY_REMOTE_CERT") == "on"
cfg.ProjectCreationRestriction = os.Getenv("PROJECT_CREATION_RESTRICTION")
cfg[comcfg.EmailPort] = port
cfg[comcfg.EmailUsername] = os.Getenv("EMAIL_USR")
cfg[comcfg.EmailPassword] = os.Getenv("EMAIL_PWD")
cfg[comcfg.EmailSSL] = os.Getenv("EMAIL_SSL") == "true"
cfg[comcfg.EmailFrom] = os.Getenv("EMAIL_FROM")
cfg[comcfg.EmailIdentity] = os.Getenv("EMAIL_IDENTITY")
cfg[comcfg.VerifyRemoteCert] = os.Getenv("VERIFY_REMOTE_CERT") == "on"
cfg[comcfg.ProjectCreationRestriction] = os.Getenv("PROJECT_CREATION_RESTRICTION")
cfg[comcfg.AdminInitialPassword] = os.Getenv("HARBOR_ADMIN_PASSWORD")
cfg.InitialAdminPwd = os.Getenv("HARBOR_ADMIN_PASSWORD")
return cfg, nil
}
// GetSystemCfg returns the system configurations
func GetSystemCfg() (*models.SystemCfg, error) {
func GetSystemCfg() (map[string]interface{}, error) {
return cfgStore.Read()
}
// UpdateSystemCfg updates the system configurations
func UpdateSystemCfg(cfg *models.SystemCfg) error {
func UpdateSystemCfg(cfg map[string]interface{}) error {
return cfgStore.Write(cfg)
}

View File

@ -15,51 +15,43 @@
package systemcfg
/*
import (
"os"
"testing"
comcfg "github.com/vmware/harbor/src/common/config"
)
// test functions under adminserver/systemcfg
func TestSystemcfg(t *testing.T) {
key := "JSON_STORE_PATH"
tmpPath := "/tmp/config.json"
originalPath := os.Getenv(key)
defer func() {
if err := os.Remove(tmpPath); err != nil {
t.Errorf("failed to remove %s: %v", tmpPath, err)
path := "/tmp/config.json"
if _, err := os.Stat(path); err == nil {
if err := os.Remove(path); err != nil {
t.Fatalf("failed to remove %s: %v", path, err)
}
} else if !os.IsNotExist(err) {
t.Fatalf("failed to check the existence of %s: %v", path, err)
}
if len(originalPath) == 0 {
if err := os.Unsetenv(key); err != nil {
t.Fatalf("failed to unset env %s: %v", key, err)
}
return
}
if err := os.Setenv(key, originalPath); err != nil {
t.Fatalf("failed to set env %s: %v", key, err)
}
}()
if err := os.Setenv(key, tmpPath); err != nil {
if err := os.Setenv(key, path); err != nil {
t.Fatalf("failed to set env %s: %v", key, err)
}
m := map[string]string{
"AUTH_MODE": comcfg.DBAuth,
"LDAP_SCOPE": "1",
"LDAP_TIMEOUT": "30",
"MYSQL_PORT": "3306",
"MAX_JOB_WORKERS": "3",
"TOKEN_EXPIRATION": "30",
"CFG_EXPIRATION": "5",
"EMAIL_PORT": "25",
}
for k, v := range m {
if err := os.Setenv(k, v); err != nil {
t.Errorf("failed to set env %s: %v", k, err)
return
t.Fatalf("failed to set env %s: %v", k, err)
}
}
@ -67,5 +59,46 @@ func TestSystemcfg(t *testing.T) {
t.Errorf("failed to initialize system configurations: %v", err)
return
}
defer func() {
if err := os.Remove(path); err != nil {
t.Fatalf("failed to remove %s: %v", path, err)
}
}()
// run Init again to make sure it works well when the configuration file
// already exists
if err := Init(); err != nil {
t.Errorf("failed to initialize system configurations: %v", err)
return
}
cfg, err := GetSystemCfg()
if err != nil {
t.Errorf("failed to get system configurations: %v", err)
return
}
if cfg[comcfg.AUTHMode] != comcfg.DBAuth {
t.Errorf("unexpected auth mode: %s != %s",
cfg[comcfg.AUTHMode], comcfg.DBAuth)
return
}
cfg[comcfg.AUTHMode] = comcfg.LDAPAuth
if err = UpdateSystemCfg(cfg); err != nil {
t.Errorf("failed to update system configurations: %v", err)
return
}
cfg, err = GetSystemCfg()
if err != nil {
t.Errorf("failed to get system configurations: %v", err)
return
}
if cfg[comcfg.AUTHMode] != comcfg.LDAPAuth {
t.Errorf("unexpected auth mode: %s != %s",
cfg[comcfg.AUTHMode], comcfg.DBAuth)
return
}
}
*/

View File

@ -26,7 +26,6 @@ import (
"github.com/vmware/harbor/src/common/models"
"github.com/vmware/harbor/src/common/utils/log"
"github.com/vmware/harbor/src/ui/auth"
"github.com/vmware/harbor/src/ui/config"
"github.com/astaxie/beego"
)
@ -210,12 +209,3 @@ func (b *BaseAPI) GetPaginationParams() (page, pageSize int64) {
return page, pageSize
}
// GetIsInsecure ...
func GetIsInsecure() (bool, error) {
verify, err := config.VerifyRemoteCert()
if err != nil {
return false, err
}
return !verify, nil
}

View File

@ -13,23 +13,3 @@
limitations under the License.
*/
package api
/*
import (
"github.com/vmware/harbor/src/common/config"
"os"
"testing"
)
func TestGetIsInsecure(t *testing.T) {
os.Setenv("VERIFY_REMOTE_CERT", "off")
err := config.Reload()
if err != nil {
t.Errorf("Failed to load config, error: %v", err)
}
if !GetIsInsecure() {
t.Errorf("GetIsInsecure() should be true when VERIFY_REMOTE_CERT is off, in fact: false")
}
os.Unsetenv("VERIFY_REMOTE_CERT")
}
*/

View File

@ -40,7 +40,15 @@ const (
LDAPScopeOnelevel = "2"
LDAPScopeSubtree = "3"
DomainName = "domain_name"
AUTHMode = "auth_mode"
DatabaseType = "database_type"
MySQLHost = "mysql_host"
MySQLPort = "mysql_port"
MySQLUsername = "mysql_username"
MySQLPassword = "mysql_password"
MySQLDatabase = "mysql_database"
SQLiteFile = "sqlite_file"
SelfRegistration = "self_registration"
LDAPURL = "ldap_url"
LDAPSearchDN = "ldap_search_dn"
@ -50,6 +58,8 @@ const (
LDAPFilter = "ldap_filter"
LDAPScope = "ldap_scope"
LDAPTimeout = "ldap_timeout"
TokenServiceURL = "token_service_url"
RegistryURL = "registry_url"
EmailHost = "email_host"
EmailPort = "email_port"
EmailUsername = "email_username"
@ -60,30 +70,29 @@ const (
ProjectCreationRestriction = "project_creation_restriction"
VerifyRemoteCert = "verify_remote_cert"
MaxJobWorkers = "max_job_workers"
TokenExpiration = "token_expiration"
CfgExpiration = "cfg_expiration"
JobLogDir = "job_log_dir"
UseCompressedJS = "use_compressed_js"
SecretKey = "secret_key"
AdminInitialPassword = "admin_initial_password"
)
// Manager manages configurations
type Manager struct {
Loader *Loader
Parser Parser
Parser *Parser
Cache bool
cache cache.Cache
key string
}
// Parser parses []byte to a specific configuration
type Parser interface {
// Parse ...
Parse([]byte) (interface{}, error)
}
// NewManager returns an instance of Manager
// url: the url from which loader loads configurations
func NewManager(url, secret string, parser Parser, enableCache bool) *Manager {
func NewManager(url, secret string, enableCache bool) *Manager {
m := &Manager{
Loader: NewLoader(url, secret),
Parser: parser,
Parser: &Parser{},
}
if enableCache {
@ -101,7 +110,7 @@ func (m *Manager) Init() error {
}
// Load configurations, if cache is enabled, cache the configurations
func (m *Manager) Load() (interface{}, error) {
func (m *Manager) Load() (map[string]interface{}, error) {
b, err := m.Loader.Load()
if err != nil {
return nil, err
@ -113,7 +122,7 @@ func (m *Manager) Load() (interface{}, error) {
}
if m.Cache {
expi, err := parseExpiration(b)
expi, err := getCfgExpiration(c)
if err != nil {
return nil, err
}
@ -126,23 +135,26 @@ func (m *Manager) Load() (interface{}, error) {
return c, nil
}
func parseExpiration(b []byte) (int, error) {
expi := &struct {
Expi int `json:"cfg_expiration"`
}{}
if err := json.Unmarshal(b, expi); err != nil {
return 0, err
func getCfgExpiration(m map[string]interface{}) (int, error) {
if m == nil {
return 0, fmt.Errorf("can not get cfg expiration as configurations are null")
}
return expi.Expi, nil
expi, ok := m[CfgExpiration]
if !ok {
return 0, fmt.Errorf("cfg expiration is not set")
}
return int(expi.(float64)), nil
}
// Get : if cache is enabled, read configurations from cache,
// if cache is null or cache is disabled it loads configurations directly
func (m *Manager) Get() (interface{}, error) {
func (m *Manager) Get() (map[string]interface{}, error) {
if m.Cache {
c := m.cache.Get(m.key)
if c != nil {
return c, nil
return c.(map[string]interface{}), nil
}
}
return m.Load()
@ -201,6 +213,11 @@ func (l *Loader) Load() ([]byte, error) {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("%d", resp.StatusCode)
}
b, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
@ -230,5 +247,20 @@ func (l *Loader) Upload(b []byte) error {
return fmt.Errorf("unexpected http status code: %d", resp.StatusCode)
}
log.Debug("configurations uploaded")
return nil
}
// Parser parses configurations
type Parser struct {
}
// Parse parses []byte to a map configuration
func (p *Parser) Parse(b []byte) (map[string]interface{}, error) {
c := map[string]interface{}{}
if err := json.Unmarshal(b, &c); err != nil {
return nil, err
}
return c, nil
}

View File

@ -15,175 +15,12 @@
package dao
/*
import (
"testing"
"github.com/vmware/harbor/src/common/models"
)
func deleteConfigByKey(key string) error {
if _, err := GetOrmer().Raw("delete from properties where k = ?", key).
Exec(); err != nil {
return err
}
return nil
}
func TestGetConfigByKey(t *testing.T) {
cfg := &models.Config{
Key: "key",
Value: "value",
}
if err := InsertConfig(cfg); err != nil {
t.Fatalf("failed to insert configuration into table: %v", err)
}
defer func(key string) {
if err := deleteConfigByKey(key); err != nil {
t.Fatalf("failed to delete configuration %s: %v", key, err)
}
}(cfg.Key)
config, err := GetConfigByKey(cfg.Key)
if err != nil {
t.Fatalf("failed to get configuration by key %s: %v", cfg.Key, err)
}
if config == nil {
t.Fatal("configuration is nil")
}
if config.Value != cfg.Value {
t.Fatalf("unexpected value: %s != %s", config.Value, cfg.Value)
}
}
func TestListConfigs(t *testing.T) {
configs, err := ListConfigs()
if err != nil {
t.Fatalf("failed to list configurations: %v", err)
}
size := len(configs)
cfg := &models.Config{
Key: "key",
Value: "value",
}
if err := InsertConfig(cfg); err != nil {
t.Fatalf("failed to insert configuration into table: %v", err)
}
defer func(key string) {
if err := deleteConfigByKey(key); err != nil {
t.Fatalf("failed to delete configuration %s: %v", key, err)
}
}(cfg.Key)
configs, err = ListConfigs()
if err != nil {
t.Fatalf("failed to list configurations: %v", err)
}
if size+1 != len(configs) {
t.Fatalf("unexpected length of configurations: %d != %d", len(configs), size+1)
}
}
func TestInsertConfig(t *testing.T) {
cfg := &models.Config{
Key: "key1",
Value: "value1",
}
if err := InsertConfig(cfg); err != nil {
t.Fatalf("failed to insert configuration into table: %v", err)
}
defer func(key string) {
if err := deleteConfigByKey(key); err != nil {
t.Fatalf("failed to delete configuration %s: %v", key, err)
}
}(cfg.Key)
config, err := GetConfigByKey(cfg.Key)
if err != nil {
t.Fatalf("failed to get configuration by key %s: %v", cfg.Key, err)
}
if config == nil {
t.Fatal("configuration is nil")
}
if config.Value != cfg.Value {
t.Fatalf("unexpected value: %s != %s", config.Value, cfg.Value)
}
}
func TestUpdateConfig(t *testing.T) {
cfg := &models.Config{
Key: "key",
Value: "value",
}
if err := InsertConfig(cfg); err != nil {
t.Fatalf("failed to insert configuration into table: %v", err)
}
defer func(key string) {
if err := deleteConfigByKey(key); err != nil {
t.Fatalf("failed to delete configuration %s: %v", key, err)
}
}(cfg.Key)
newCfg := &models.Config{
Key: "key",
Value: "new_value",
}
if err := UpdateConfig(newCfg); err != nil {
t.Fatalf("failed to update configuration: %v", err)
}
config, err := GetConfigByKey(cfg.Key)
if err != nil {
t.Fatalf("failed to get configuration by key %s: %v", cfg.Key, err)
}
if config == nil {
t.Fatal("configuration is nil")
}
if config.Value != newCfg.Value {
t.Fatalf("unexpected value: %s != %s", config.Value, newCfg.Value)
}
}
func TestInsertOrUpdateConfigs(t *testing.T) {
cfg1 := &models.Config{
Key: "key1",
Value: "value1",
}
if err := InsertConfig(cfg1); err != nil {
t.Fatalf("failed to insert configuration into table: %v", err)
}
defer func(key string) {
if err := deleteConfigByKey(key); err != nil {
t.Fatalf("failed to delete configuration %s: %v", key, err)
}
}(cfg1.Key)
cfg2 := &models.Config{
Key: "key2",
Value: "value2",
}
if err := InsertOrUpdateConfigs([]*models.Config{cfg1, cfg2}); err != nil {
t.Fatalf("failed to insert or update configurations: %v", err)
}
defer func(key string) {
if err := deleteConfigByKey(key); err != nil {
t.Fatalf("failed to delete configuration %s: %v", key, err)
}
}(cfg2.Key)
}
func TestAuthModeCanBeModified(t *testing.T) {
c, err := GetOrmer().QueryTable(&models.User{}).Count()
if err != nil {
@ -233,4 +70,3 @@ func TestAuthModeCanBeModified(t *testing.T) {
}
}
}
*/

View File

@ -26,7 +26,7 @@ type Authentication struct {
type LDAP struct {
URL string `json:"url"`
SearchDN string `json:"search_dn"`
SearchPwd string `json:"search_pwd"`
SearchPassword string `json:"search_password"`
BaseDN string `json:"base_dn"`
Filter string `json:"filter"`
UID string `json:"uid"`
@ -58,7 +58,7 @@ type SQLite struct {
// Email ...
type Email struct {
Host string `json:"host"`
Port string `json:"port"`
Port int `json:"port"`
Username string `json:"username"`
Password string `json:"password"`
SSL bool `json:"ssl"`

View File

@ -18,6 +18,7 @@ package email
import (
"bytes"
"crypto/tls"
"strconv"
//"strings"
"net/smtp"
@ -67,11 +68,11 @@ func (m Mail) SendMail() error {
}
func sendMail(m Mail, auth smtp.Auth, content []byte) error {
return smtp.SendMail(mc.Host+":"+mc.Port, auth, m.From, m.To, content)
return smtp.SendMail(mc.Host+":"+strconv.Itoa(mc.Port), auth, m.From, m.To, content)
}
func sendMailWithTLS(m Mail, auth smtp.Auth, content []byte) error {
conn, err := tls.Dial("tcp", mc.Host+":"+mc.Port, nil)
conn, err := tls.Dial("tcp", mc.Host+":"+strconv.Itoa(mc.Port), nil)
if err != nil {
return err
}

View File

@ -20,17 +20,49 @@ import (
"net/http"
"net/http/httptest"
"github.com/vmware/harbor/src/common/models"
"github.com/vmware/harbor/src/common/config"
)
// NewAdminserver returns a mock admin server
func NewAdminserver() (*httptest.Server, error) {
m := []*RequestHandlerMapping{}
b, err := json.Marshal(&models.SystemCfg{
Authentication: &models.Authentication{
Mode: "db_auth",
},
Registry: &models.Registry{},
b, err := json.Marshal(map[string]interface{}{
config.DomainName: "host01.com",
config.AUTHMode: config.DBAuth,
config.DatabaseType: "mysql",
config.MySQLHost: "127.0.0.1",
config.MySQLPort: 3306,
config.MySQLUsername: "user01",
config.MySQLPassword: "password",
config.MySQLDatabase: "registry",
config.SQLiteFile: "/tmp/registry.db",
config.SelfRegistration: true,
config.LDAPURL: "ldap://127.0.0.1",
config.LDAPSearchDN: "uid=searchuser,ou=people,dc=mydomain,dc=com",
config.LDAPSearchPwd: "password",
config.LDAPBaseDN: "ou=people,dc=mydomain,dc=com",
config.LDAPUID: "uid",
config.LDAPFilter: "",
config.LDAPScope: 3,
config.LDAPTimeout: 30,
config.TokenServiceURL: "http://token_service",
config.RegistryURL: "http://registry",
config.EmailHost: "127.0.0.1",
config.EmailPort: 25,
config.EmailUsername: "user01",
config.EmailPassword: "password",
config.EmailFrom: "from",
config.EmailSSL: true,
config.EmailIdentity: "",
config.ProjectCreationRestriction: config.ProCrtRestrAdmOnly,
config.VerifyRemoteCert: false,
config.MaxJobWorkers: 3,
config.TokenExpiration: 30,
config.CfgExpiration: 5,
config.JobLogDir: "/var/log/jobs",
config.UseCompressedJS: true,
config.SecretKey: "secret",
config.AdminInitialPassword: "password",
})
if err != nil {
return nil, err

View File

@ -16,7 +16,6 @@
package config
import (
"encoding/json"
"os"
comcfg "github.com/vmware/harbor/src/common/config"
@ -25,35 +24,13 @@ import (
var mg *comcfg.Manager
// Configuration of Jobservice
type Configuration struct {
Database *models.Database `json:"database"`
Registry *models.Registry `json:"registry"`
VerifyRemoteCert bool `json:"verify_remote_cert"`
MaxJobWorkers int `json:"max_job_workers"`
JobLogDir string `json:"job_log_dir"`
SecretKey string `json:"secret_key"`
CfgExpiration int `json:"cfg_expiration"`
}
type parser struct {
}
func (p *parser) Parse(b []byte) (interface{}, error) {
c := &Configuration{}
if err := json.Unmarshal(b, c); err != nil {
return nil, err
}
return c, nil
}
// Init configurations
func Init() error {
adminServerURL := os.Getenv("ADMIN_SERVER_URL")
if len(adminServerURL) == 0 {
adminServerURL = "http://adminserver"
}
mg = comcfg.NewManager(adminServerURL, UISecret(), &parser{}, true)
mg = comcfg.NewManager(adminServerURL, UISecret(), true)
if err := mg.Init(); err != nil {
return err
@ -66,39 +43,44 @@ func Init() error {
return nil
}
func get() (*Configuration, error) {
c, err := mg.Get()
if err != nil {
return nil, err
}
return c.(*Configuration), nil
}
// VerifyRemoteCert returns bool value.
func VerifyRemoteCert() (bool, error) {
cfg, err := get()
cfg, err := mg.Get()
if err != nil {
return true, err
}
return cfg.VerifyRemoteCert, nil
return cfg[comcfg.VerifyRemoteCert].(bool), nil
}
// Database ...
func Database() (*models.Database, error) {
cfg, err := get()
cfg, err := mg.Get()
if err != nil {
return nil, err
}
return cfg.Database, nil
database := &models.Database{}
database.Type = cfg[comcfg.DatabaseType].(string)
mysql := &models.MySQL{}
mysql.Host = cfg[comcfg.MySQLHost].(string)
mysql.Port = int(cfg[comcfg.MySQLPort].(float64))
mysql.Username = cfg[comcfg.MySQLUsername].(string)
mysql.Password = cfg[comcfg.MySQLPassword].(string)
mysql.Database = cfg[comcfg.MySQLDatabase].(string)
database.MySQL = mysql
sqlite := &models.SQLite{}
sqlite.File = cfg[comcfg.SQLiteFile].(string)
database.SQLite = sqlite
return database, nil
}
// MaxJobWorkers ...
func MaxJobWorkers() (int, error) {
cfg, err := get()
cfg, err := mg.Get()
if err != nil {
return 0, err
}
return cfg.MaxJobWorkers, nil
return int(cfg[comcfg.MaxJobWorkers].(float64)), nil
}
// LocalUIURL returns the local ui url, job service will use this URL to call API hosted on ui process
@ -108,29 +90,29 @@ func LocalUIURL() string {
// LocalRegURL returns the local registry url, job service will use this URL to pull image from the registry
func LocalRegURL() (string, error) {
cfg, err := get()
cfg, err := mg.Get()
if err != nil {
return "", err
}
return cfg.Registry.URL, nil
return cfg[comcfg.RegistryURL].(string), nil
}
// LogDir returns the absolute path to which the log file will be written
func LogDir() (string, error) {
cfg, err := get()
cfg, err := mg.Get()
if err != nil {
return "", err
}
return cfg.JobLogDir, nil
return cfg[comcfg.JobLogDir].(string), nil
}
// SecretKey will return the secret key for encryption/decryption password in target.
func SecretKey() (string, error) {
cfg, err := get()
cfg, err := mg.Get()
if err != nil {
return "", err
}
return cfg.SecretKey, nil
return cfg[comcfg.SecretKey].(string), nil
}
// UISecret returns the value of UI secret cookie, used for communication between UI and JobService

View File

@ -30,6 +30,41 @@ import (
"github.com/vmware/harbor/src/ui/config"
)
// keys of attrs which user can modify
var validKeys = []string{
comcfg.AUTHMode,
comcfg.EmailFrom,
comcfg.EmailHost,
comcfg.EmailIdentity,
comcfg.EmailPassword,
comcfg.EmailPort,
comcfg.EmailSSL,
comcfg.EmailUsername,
comcfg.LDAPBaseDN,
comcfg.LDAPFilter,
comcfg.LDAPScope,
comcfg.LDAPSearchDN,
comcfg.LDAPSearchPwd,
comcfg.LDAPTimeout,
comcfg.LDAPUID,
comcfg.LDAPURL,
comcfg.ProjectCreationRestriction,
comcfg.SelfRegistration,
comcfg.VerifyRemoteCert,
}
var numKeys = []string{
comcfg.EmailPort,
comcfg.LDAPScope,
comcfg.LDAPTimeout,
}
var boolKeys = []string{
comcfg.EmailSSL,
comcfg.SelfRegistration,
comcfg.VerifyRemoteCert,
}
// ConfigAPI ...
type ConfigAPI struct {
api.BaseAPI
@ -49,6 +84,11 @@ func (c *ConfigAPI) Prepare() {
}
}
type value struct {
Value interface{} `json:"value"`
Editable bool `json:"editable"`
}
// Get returns configurations
func (c *ConfigAPI) Get() {
cfg, err := config.GetSystemCfg()
@ -57,24 +97,12 @@ func (c *ConfigAPI) Get() {
c.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
}
if cfg.Database.MySQL != nil {
cfg.Database.MySQL.Password = ""
}
cfg.InitialAdminPwd = ""
cfg.SecretKey = ""
m := map[string]interface{}{}
m["config"] = cfg
editable, err := dao.AuthModeCanBeModified()
m, err := convertForGet(cfg)
if err != nil {
log.Errorf("failed to determinie whether auth mode can be modified: %v", err)
log.Errorf("failed to convert configurations: %v", err)
c.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
}
m["auth_mode_editable"] = editable
c.Data["json"] = m
c.ServeJSON()
}
@ -83,11 +111,19 @@ func (c *ConfigAPI) Get() {
func (c *ConfigAPI) Put() {
m := map[string]string{}
c.DecodeJSONReq(&m)
if err := validateCfg(m); err != nil {
cfg := map[string]string{}
for _, k := range validKeys {
if v, ok := m[k]; ok {
cfg[k] = v
}
}
if err := validateCfg(cfg); err != nil {
c.CustomAbort(http.StatusBadRequest, err.Error())
}
if value, ok := m[comcfg.AUTHMode]; ok {
if value, ok := cfg[comcfg.AUTHMode]; ok {
mode, err := config.AuthMode()
if err != nil {
log.Errorf("failed to get auth mode: %v", err)
@ -109,7 +145,13 @@ func (c *ConfigAPI) Put() {
}
}
if err := config.Upload(m); err != nil {
result, err := convertForPut(cfg)
if err != nil {
log.Errorf("failed to convert configurations: %v", err)
c.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
}
if err := config.Upload(result); err != nil {
log.Errorf("failed to upload configurations: %v", err)
c.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
}
@ -200,10 +242,11 @@ func validateCfg(c map[string]string) error {
return nil
}
/*
func convert() ([]*models.Config, error) {
cfgs := []*models.Config{}
var err error
//encode passwords and convert map[string]string to map[string]interface{}
func convertForPut(m map[string]string) (map[string]interface{}, error) {
cfg := map[string]interface{}{}
/*
pwdKeys := []string{config.LDAP_SEARCH_PWD, config.EMAIL_PWD}
for _, pwdKey := range pwdKeys {
if pwd, ok := c[pwdKey]; ok && len(pwd) != 0 {
@ -213,47 +256,58 @@ func convert() ([]*models.Config, error) {
}
}
}
for _, key := range configKeys {
if value, ok := c[key]; ok {
cfgs = append(cfgs, &models.Config{
Key: key,
Value: value,
})
}
*/
for k, v := range m {
cfg[k] = v
}
return cfgs, nil
for _, k := range numKeys {
v, err := strconv.Atoi(cfg[k].(string))
if err != nil {
return nil, err
}
cfg[k] = v
}
for _, k := range boolKeys {
cfg[k] = cfg[k] == "1"
}
return cfg, nil
}
*/
/*
//[]*models.Config >> cfgForGet
func convert(cfg *config.Configuration) (map[string]interface{}, error) {
result := map[string]interface{}{}
for _, config := range configs {
cfg[config.Key] = &value{
Value: config.Value,
Editable: true,
}
}
// delete sensitive attrs and add editable field to every attr
func convertForGet(cfg map[string]interface{}) (map[string]*value, error) {
result := map[string]*value{}
dels := []string{config.LDAP_SEARCH_PWD, config.EMAIL_PWD}
dels := []string{
comcfg.AdminInitialPassword,
comcfg.EmailPassword,
comcfg.LDAPSearchPwd,
comcfg.MySQLPassword,
comcfg.SecretKey}
for _, del := range dels {
if _, ok := cfg[del]; ok {
delete(cfg, del)
}
}
for k, v := range cfg {
result[k] = &value{
Value: v,
Editable: true,
}
}
flag, err := authModeCanBeModified()
if err != nil {
return nil, err
}
cfg[config.AUTH_MODE].Editable = flag
result[comcfg.AUTHMode].Editable = flag
return cfgForGet(cfg), nil
return result, nil
}
*/
func authModeCanBeModified() (bool, error) {
return dao.AuthModeCanBeModified()
}

View File

@ -366,14 +366,14 @@ func (ra *RepositoryAPI) initRepositoryClient(repoName string) (r *registry.Repo
return nil, err
}
insecure, err := api.GetIsInsecure()
verify, err := config.VerifyRemoteCert()
if err != nil {
return nil, err
}
username, password, ok := ra.Ctx.Request.BasicAuth()
if ok {
return newRepositoryClient(endpoint, insecure, username, password,
return newRepositoryClient(endpoint, !verify, username, password,
repoName, "repository", repoName, "pull", "push", "*")
}
@ -382,7 +382,7 @@ func (ra *RepositoryAPI) initRepositoryClient(repoName string) (r *registry.Repo
return nil, err
}
return cache.NewRepositoryClient(endpoint, insecure, username, repoName,
return cache.NewRepositoryClient(endpoint, !verify, username, repoName,
"repository", repoName, "pull", "push", "*")
}

View File

@ -102,12 +102,12 @@ func (t *TargetAPI) Ping() {
password = t.GetString("password")
}
insecure, err := api.GetIsInsecure()
verify, err := config.VerifyRemoteCert()
if err != nil {
log.Errorf("failed to check whether insecure or not: %v", err)
t.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
}
registry, err := newRegistryClient(endpoint, insecure, username, password,
registry, err := newRegistryClient(endpoint, !verify, username, password,
"", "", "")
if err != nil {
// timeout, dns resolve error, connection refused, etc.

View File

@ -116,7 +116,7 @@ func (l *Auth) Authenticate(m models.AuthModel) (*models.User, error) {
ldapSearchDn := settings.SearchDN
if ldapSearchDn != "" {
log.Debug("Search DN: ", ldapSearchDn)
ldapSearchPwd := settings.SearchPwd
ldapSearchPwd := settings.SearchPassword
err = ldap.Bind(ldapSearchDn, ldapSearchPwd)
if err != nil {
log.Debug("Bind search dn error", err)

View File

@ -26,35 +26,6 @@ import (
var mg *comcfg.Manager
// Configuration of UI
type Configuration struct {
DomainName string `json:"domain_name"` // Harbor external URL: protocal://host:port
Authentication *models.Authentication `json:"authentication"`
Database *models.Database `json:"database"`
TokenService *models.TokenService `json:"token_service"`
Registry *models.Registry `json:"registry"`
Email *models.Email `json:"email"`
VerifyRemoteCert bool `json:"verify_remote_cert"`
ProjectCreationRestriction string `json:"project_creation_restriction"`
InitialAdminPwd string `json:"initial_admin_pwd"`
//TODO remove
CompressJS bool `json:"compress_js"`
TokenExpiration int `json:"token_expiration"`
SecretKey string `json:"secret_key"`
CfgExpiration int `json:"cfg_expiration"`
}
type parser struct {
}
func (p *parser) Parse(b []byte) (interface{}, error) {
c := &Configuration{}
if err := json.Unmarshal(b, c); err != nil {
return nil, err
}
return c, nil
}
// Init configurations
func Init() error {
adminServerURL := os.Getenv("ADMIN_SERVER_URL")
@ -62,7 +33,7 @@ func Init() error {
adminServerURL = "http://adminserver"
}
log.Debugf("admin server URL: %s", adminServerURL)
mg = comcfg.NewManager(adminServerURL, UISecret(), &parser{}, true)
mg = comcfg.NewManager(adminServerURL, UISecret(), true)
if err := mg.Init(); err != nil {
return err
@ -75,14 +46,6 @@ func Init() error {
return nil
}
func get() (*Configuration, error) {
c, err := mg.Get()
if err != nil {
return nil, err
}
return c.(*Configuration), nil
}
// Load configurations
func Load() error {
_, err := mg.Load()
@ -90,7 +53,7 @@ func Load() error {
}
// Upload uploads all system configutations to admin server
func Upload(cfg map[string]string) error {
func Upload(cfg map[string]interface{}) error {
b, err := json.Marshal(cfg)
if err != nil {
return err
@ -99,80 +62,92 @@ func Upload(cfg map[string]string) error {
}
// GetSystemCfg returns the system configurations
func GetSystemCfg() (*models.SystemCfg, error) {
func GetSystemCfg() (map[string]interface{}, error) {
raw, err := mg.Loader.Load()
if err != nil {
return nil, err
}
cfg := &models.SystemCfg{}
if err = json.Unmarshal(raw, cfg); err != nil {
c, err := mg.Parser.Parse(raw)
if err != nil {
return nil, err
}
return cfg, nil
return c, nil
}
// AuthMode ...
func AuthMode() (string, error) {
cfg, err := get()
cfg, err := mg.Get()
if err != nil {
return "", err
}
return cfg.Authentication.Mode, nil
return cfg[comcfg.AUTHMode].(string), nil
}
// LDAP returns the setting of ldap server
func LDAP() (*models.LDAP, error) {
cfg, err := get()
cfg, err := mg.Get()
if err != nil {
return nil, err
}
return cfg.Authentication.LDAP, nil
ldap := &models.LDAP{}
ldap.URL = cfg[comcfg.LDAPURL].(string)
ldap.SearchDN = cfg[comcfg.LDAPSearchDN].(string)
ldap.SearchPassword = cfg[comcfg.LDAPSearchPwd].(string)
ldap.BaseDN = cfg[comcfg.LDAPBaseDN].(string)
ldap.UID = cfg[comcfg.LDAPUID].(string)
ldap.Filter = cfg[comcfg.LDAPFilter].(string)
ldap.Scope = int(cfg[comcfg.LDAPScope].(float64))
ldap.Timeout = int(cfg[comcfg.LDAPTimeout].(float64))
return ldap, nil
}
// TokenExpiration returns the token expiration time (in minute)
func TokenExpiration() (int, error) {
cfg, err := get()
cfg, err := mg.Get()
if err != nil {
return 0, err
}
return cfg.TokenExpiration, nil
return int(cfg[comcfg.TokenExpiration].(float64)), nil
}
// DomainName returns the external URL of Harbor: protocal://host:port
func DomainName() (string, error) {
cfg, err := get()
cfg, err := mg.Get()
if err != nil {
return "", err
}
return cfg.DomainName, nil
return cfg[comcfg.DomainName].(string), nil
}
// SecretKey returns the secret key to encrypt the password of target
func SecretKey() (string, error) {
cfg, err := get()
cfg, err := mg.Get()
if err != nil {
return "", err
}
return cfg.SecretKey, nil
return cfg[comcfg.SecretKey].(string), nil
}
// SelfRegistration returns the enablement of self registration
func SelfRegistration() (bool, error) {
cfg, err := get()
cfg, err := mg.Get()
if err != nil {
return false, err
}
return cfg.Authentication.SelfRegistration, nil
return cfg[comcfg.SelfRegistration].(bool), nil
}
// RegistryURL ...
func RegistryURL() (string, error) {
cfg, err := get()
cfg, err := mg.Get()
if err != nil {
return "", err
}
return cfg.Registry.URL, nil
return cfg[comcfg.RegistryURL].(string), nil
}
// InternalJobServiceURL returns jobservice URL for internal communication between Harbor containers
@ -182,47 +157,70 @@ func InternalJobServiceURL() string {
// InitialAdminPassword returns the initial password for administrator
func InitialAdminPassword() (string, error) {
cfg, err := get()
cfg, err := mg.Get()
if err != nil {
return "", err
}
return cfg.InitialAdminPwd, nil
return cfg[comcfg.AdminInitialPassword].(string), nil
}
// OnlyAdminCreateProject returns the flag to restrict that only sys admin can create project
func OnlyAdminCreateProject() (bool, error) {
cfg, err := get()
cfg, err := mg.Get()
if err != nil {
return true, err
}
return cfg.ProjectCreationRestriction == comcfg.ProCrtRestrAdmOnly, nil
return cfg[comcfg.ProjectCreationRestriction].(string) == comcfg.ProCrtRestrAdmOnly, nil
}
// VerifyRemoteCert returns bool value.
func VerifyRemoteCert() (bool, error) {
cfg, err := get()
cfg, err := mg.Get()
if err != nil {
return true, err
}
return cfg.VerifyRemoteCert, nil
return cfg[comcfg.VerifyRemoteCert].(bool), nil
}
// Email returns email server settings
func Email() (*models.Email, error) {
cfg, err := get()
cfg, err := mg.Get()
if err != nil {
return nil, err
}
return cfg.Email, nil
email := &models.Email{}
email.Host = cfg[comcfg.EmailHost].(string)
email.Port = int(cfg[comcfg.EmailPort].(float64))
email.Username = cfg[comcfg.EmailUsername].(string)
email.Password = cfg[comcfg.EmailPassword].(string)
email.SSL = cfg[comcfg.EmailSSL].(bool)
email.From = cfg[comcfg.EmailFrom].(string)
email.Identity = cfg[comcfg.EmailIdentity].(string)
return email, nil
}
// Database returns database settings
func Database() (*models.Database, error) {
cfg, err := get()
cfg, err := mg.Get()
if err != nil {
return nil, err
}
return cfg.Database, nil
database := &models.Database{}
database.Type = cfg[comcfg.DatabaseType].(string)
mysql := &models.MySQL{}
mysql.Host = cfg[comcfg.MySQLHost].(string)
mysql.Port = int(cfg[comcfg.MySQLPort].(float64))
mysql.Username = cfg[comcfg.MySQLUsername].(string)
mysql.Password = cfg[comcfg.MySQLPassword].(string)
mysql.Database = cfg[comcfg.MySQLDatabase].(string)
database.MySQL = mysql
sqlite := &models.SQLite{}
sqlite.File = cfg[comcfg.SQLiteFile].(string)
database.SQLite = sqlite
return database, nil
}
// UISecret returns the value of UI secret cookie, used for communication between UI and JobService

View File

@ -44,7 +44,7 @@ func TestConfig(t *testing.T) {
t.Fatalf("failed to load configurations: %v", err)
}
if err := Upload(map[string]string{}); err != nil {
if err := Upload(map[string]interface{}{}); err != nil {
t.Fatalf("failed to upload configurations: %v", err)
}