Merge pull request #1684 from ywk253100/170320_adminserver_client

Abstract adminserver client into a single package
This commit is contained in:
Daniel Jiang 2017-03-21 16:08:31 +08:00 committed by GitHub
commit e02dd11703
17 changed files with 818 additions and 525 deletions

View File

@ -26,7 +26,7 @@ import (
"testing"
"github.com/vmware/harbor/src/adminserver/systemcfg"
comcfg "github.com/vmware/harbor/src/common/config"
"github.com/vmware/harbor/src/common"
"github.com/vmware/harbor/src/common/utils/test"
)
@ -43,7 +43,7 @@ func TestConfigAPI(t *testing.T) {
secret := "secret"
envs := map[string]string{
"AUTH_MODE": comcfg.DBAuth,
"AUTH_MODE": common.DBAuth,
"JSON_CFG_STORE_PATH": configPath,
"KEY_PATH": secretKeyPath,
"UI_SECRET": secret,
@ -97,7 +97,7 @@ func TestConfigAPI(t *testing.T) {
return
}
scope := int(m[comcfg.LDAPScope].(float64))
scope := int(m[common.LDAPScope].(float64))
if scope != 3 {
t.Errorf("unexpected ldap scope: %d != %d", scope, 3)
return
@ -105,7 +105,7 @@ func TestConfigAPI(t *testing.T) {
// modify configurations
c := map[string]interface{}{
comcfg.AUTHMode: comcfg.LDAPAuth,
common.AUTHMode: common.LDAPAuth,
}
b, err := json.Marshal(c)
@ -155,9 +155,9 @@ func TestConfigAPI(t *testing.T) {
return
}
mode := m[comcfg.AUTHMode].(string)
if mode != comcfg.LDAPAuth {
t.Errorf("unexpected auth mode: %s != %s", mode, comcfg.LDAPAuth)
mode := m[common.AUTHMode].(string)
if mode != common.LDAPAuth {
t.Errorf("unexpected auth mode: %s != %s", mode, common.LDAPAuth)
return
}
@ -203,9 +203,9 @@ func TestConfigAPI(t *testing.T) {
return
}
mode = m[comcfg.AUTHMode].(string)
if mode != comcfg.DBAuth {
t.Errorf("unexpected auth mode: %s != %s", mode, comcfg.LDAPAuth)
mode = m[common.AUTHMode].(string)
if mode != common.DBAuth {
t.Errorf("unexpected auth mode: %s != %s", mode, common.LDAPAuth)
return
}
}

View File

@ -0,0 +1,51 @@
/*
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 auth
import (
"net/http"
)
// Authorizer authorizes request
type Authorizer interface {
Authorize(*http.Request) error
}
// NewSecretAuthorizer returns an instance of secretAuthorizer
func NewSecretAuthorizer(cookieName, secret string) Authorizer {
return &secretAuthorizer{
cookieName: cookieName,
secret: secret,
}
}
type secretAuthorizer struct {
cookieName string
secret string
}
func (s *secretAuthorizer) Authorize(req *http.Request) error {
if req == nil {
return nil
}
req.AddCookie(&http.Cookie{
Name: s.cookieName,
Value: s.secret,
})
return nil
}

View File

@ -0,0 +1,44 @@
/*
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 auth
import (
"net/http"
"testing"
"github.com/stretchr/testify/assert"
)
func TestAuthorize(t *testing.T) {
cookieName := "secret"
secret := "secret"
authorizer := NewSecretAuthorizer(cookieName, secret)
req, err := http.NewRequest("", "", nil)
if !assert.Nil(t, err, "unexpected error") {
return
}
err = authorizer.Authorize(req)
if !assert.Nil(t, err, "unexpected error") {
return
}
cookie, err := req.Cookie(cookieName)
if !assert.Nil(t, err, "unexpected error") {
return
}
assert.Equal(t, secret, cookie.Value, "unexpected cookie")
}

View File

@ -0,0 +1,184 @@
/*
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 client
import (
"bytes"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
"strings"
"github.com/vmware/harbor/src/adminserver/client/auth"
"github.com/vmware/harbor/src/adminserver/systeminfo/imagestorage"
"github.com/vmware/harbor/src/common/utils"
)
// Client defines methods that an Adminserver client should implement
type Client interface {
// Ping tests the connection with server
Ping() error
// GetCfgs returns system configurations
GetCfgs() (map[string]interface{}, error)
// UpdateCfgs updates system configurations
UpdateCfgs(map[string]interface{}) error
// ResetCfgs resets system configuratoins form environment variables
ResetCfgs() error
// Capacity returns the capacity of image storage
Capacity() (*imagestorage.Capacity, error)
}
// NewClient return an instance of Adminserver client
func NewClient(baseURL string, authorizer auth.Authorizer) Client {
baseURL = strings.TrimRight(baseURL, "/")
if !strings.Contains(baseURL, "://") {
baseURL = "http://" + baseURL
}
return &client{
baseURL: baseURL,
client: &http.Client{},
authorizer: authorizer,
}
}
type client struct {
baseURL string
client *http.Client
authorizer auth.Authorizer
}
// do creates request and authorizes it if authorizer is not nil
func (c *client) do(method, relativePath string, body io.Reader) (*http.Response, error) {
url := c.baseURL + relativePath
req, err := http.NewRequest(method, url, body)
if err != nil {
return nil, err
}
if c.authorizer != nil {
if err := c.authorizer.Authorize(req); err != nil {
return nil, err
}
}
return c.client.Do(req)
}
func (c *client) Ping() error {
addr := strings.Split(c.baseURL, "://")[1]
if !strings.Contains(addr, ":") {
addr = addr + ":80"
}
return utils.TestTCPConn(addr, 60, 2)
}
// GetCfgs ...
func (c *client) GetCfgs() (map[string]interface{}, error) {
resp, err := c.do(http.MethodGet, "/api/configurations", nil)
if err != nil {
return nil, err
}
defer resp.Body.Close()
b, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("failed to get configurations: %d %s",
resp.StatusCode, b)
}
cfgs := map[string]interface{}{}
if err = json.Unmarshal(b, &cfgs); err != nil {
return nil, err
}
return cfgs, nil
}
// UpdateCfgs ...
func (c *client) UpdateCfgs(cfgs map[string]interface{}) error {
data, err := json.Marshal(cfgs)
if err != nil {
return err
}
resp, err := c.do(http.MethodPut, "/api/configurations", bytes.NewReader(data))
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
b, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
}
return fmt.Errorf("failed to update configurations: %d %s",
resp.StatusCode, b)
}
return nil
}
// ResetCfgs ...
func (c *client) ResetCfgs() error {
resp, err := c.do(http.MethodPost, "/api/configurations/reset", nil)
if err != nil {
return err
}
if resp.StatusCode != http.StatusOK {
b, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
}
return fmt.Errorf("failed to reset configurations: %d %s",
resp.StatusCode, b)
}
return nil
}
// Capacity ...
func (c *client) Capacity() (*imagestorage.Capacity, error) {
resp, err := c.do(http.MethodGet, "/api/systeminfo/capacity", nil)
if err != nil {
return nil, err
}
defer resp.Body.Close()
b, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("failed to get capacity: %d %s",
resp.StatusCode, b)
}
capacity := &imagestorage.Capacity{}
if err = json.Unmarshal(b, capacity); err != nil {
return nil, err
}
return capacity, nil
}

View File

@ -0,0 +1,82 @@
/*
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 client
import (
"fmt"
"os"
"testing"
"github.com/stretchr/testify/assert"
"github.com/vmware/harbor/src/common"
"github.com/vmware/harbor/src/common/utils/test"
)
var c Client
func TestMain(m *testing.M) {
server, err := test.NewAdminserver(nil)
if err != nil {
fmt.Printf("failed to create adminserver: %v", err)
os.Exit(1)
}
c = NewClient(server.URL, nil)
os.Exit(m.Run())
}
func TestPing(t *testing.T) {
err := c.Ping()
assert.Nil(t, err, "unexpected error")
}
func TestGetCfgs(t *testing.T) {
cfgs, err := c.GetCfgs()
if !assert.Nil(t, err, "unexpected error") {
return
}
assert.Equal(t, common.DBAuth, cfgs[common.AUTHMode], "unexpected configuration")
}
func TestUpdateCfgs(t *testing.T) {
cfgs := map[string]interface{}{
common.AUTHMode: common.LDAPAuth,
}
err := c.UpdateCfgs(cfgs)
if !assert.Nil(t, err, "unexpected error") {
return
}
}
func TestResetCfgs(t *testing.T) {
err := c.ResetCfgs()
if !assert.Nil(t, err, "unexpected error") {
return
}
}
func TestCapacity(t *testing.T) {
capacity, err := c.Capacity()
if !assert.Nil(t, err, "unexpected error") {
return
}
assert.Equal(t, uint64(100), capacity.Total)
assert.Equal(t, uint64(90), capacity.Free)
}

View File

@ -23,6 +23,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"
comcfg "github.com/vmware/harbor/src/common/config"
"github.com/vmware/harbor/src/common/utils"
"github.com/vmware/harbor/src/common/utils/log"
@ -40,82 +41,82 @@ var (
// attrs need to be encrypted or decrypted
attrs = []string{
comcfg.EmailPassword,
comcfg.LDAPSearchPwd,
comcfg.MySQLPassword,
comcfg.AdminInitialPassword,
common.EmailPassword,
common.LDAPSearchPwd,
common.MySQLPassword,
common.AdminInitialPassword,
}
// all configurations need read from environment variables
allEnvs = map[string]interface{}{
comcfg.ExtEndpoint: "EXT_ENDPOINT",
comcfg.AUTHMode: "AUTH_MODE",
comcfg.SelfRegistration: &parser{
common.ExtEndpoint: "EXT_ENDPOINT",
common.AUTHMode: "AUTH_MODE",
common.SelfRegistration: &parser{
env: "SELF_REGISTRATION",
parse: parseStringToBool,
},
comcfg.DatabaseType: "DATABASE_TYPE",
comcfg.MySQLHost: "MYSQL_HOST",
comcfg.MySQLPort: &parser{
common.DatabaseType: "DATABASE_TYPE",
common.MySQLHost: "MYSQL_HOST",
common.MySQLPort: &parser{
env: "MYSQL_PORT",
parse: parseStringToInt,
},
comcfg.MySQLUsername: "MYSQL_USR",
comcfg.MySQLPassword: "MYSQL_PWD",
comcfg.MySQLDatabase: "MYSQL_DATABASE",
comcfg.SQLiteFile: "SQLITE_FILE",
comcfg.LDAPURL: "LDAP_URL",
comcfg.LDAPSearchDN: "LDAP_SEARCH_DN",
comcfg.LDAPSearchPwd: "LDAP_SEARCH_PWD",
comcfg.LDAPBaseDN: "LDAP_BASE_DN",
comcfg.LDAPFilter: "LDAP_FILTER",
comcfg.LDAPUID: "LDAP_UID",
comcfg.LDAPScope: &parser{
common.MySQLUsername: "MYSQL_USR",
common.MySQLPassword: "MYSQL_PWD",
common.MySQLDatabase: "MYSQL_DATABASE",
common.SQLiteFile: "SQLITE_FILE",
common.LDAPURL: "LDAP_URL",
common.LDAPSearchDN: "LDAP_SEARCH_DN",
common.LDAPSearchPwd: "LDAP_SEARCH_PWD",
common.LDAPBaseDN: "LDAP_BASE_DN",
common.LDAPFilter: "LDAP_FILTER",
common.LDAPUID: "LDAP_UID",
common.LDAPScope: &parser{
env: "LDAP_SCOPE",
parse: parseStringToInt,
},
comcfg.LDAPTimeout: &parser{
common.LDAPTimeout: &parser{
env: "LDAP_TIMEOUT",
parse: parseStringToInt,
},
comcfg.EmailHost: "EMAIL_HOST",
comcfg.EmailPort: &parser{
common.EmailHost: "EMAIL_HOST",
common.EmailPort: &parser{
env: "EMAIL_PORT",
parse: parseStringToInt,
},
comcfg.EmailUsername: "EMAIL_USR",
comcfg.EmailPassword: "EMAIL_PWD",
comcfg.EmailSSL: &parser{
common.EmailUsername: "EMAIL_USR",
common.EmailPassword: "EMAIL_PWD",
common.EmailSSL: &parser{
env: "EMAIL_SSL",
parse: parseStringToBool,
},
comcfg.EmailFrom: "EMAIL_FROM",
comcfg.EmailIdentity: "EMAIL_IDENTITY",
comcfg.RegistryURL: "REGISTRY_URL",
comcfg.TokenExpiration: &parser{
common.EmailFrom: "EMAIL_FROM",
common.EmailIdentity: "EMAIL_IDENTITY",
common.RegistryURL: "REGISTRY_URL",
common.TokenExpiration: &parser{
env: "TOKEN_EXPIRATION",
parse: parseStringToInt,
},
comcfg.UseCompressedJS: &parser{
common.UseCompressedJS: &parser{
env: "USE_COMPRESSED_JS",
parse: parseStringToBool,
},
comcfg.CfgExpiration: &parser{
common.CfgExpiration: &parser{
env: "CFG_EXPIRATION",
parse: parseStringToInt,
},
comcfg.MaxJobWorkers: &parser{
common.MaxJobWorkers: &parser{
env: "MAX_JOB_WORKERS",
parse: parseStringToInt,
},
comcfg.VerifyRemoteCert: &parser{
common.VerifyRemoteCert: &parser{
env: "VERIFY_REMOTE_CERT",
parse: parseStringToBool,
},
comcfg.ProjectCreationRestriction: "PROJECT_CREATION_RESTRICTION",
comcfg.AdminInitialPassword: "HARBOR_ADMIN_PASSWORD",
comcfg.AdmiralEndpoint: "ADMIRAL_URL",
comcfg.WithNotary: &parser{
common.ProjectCreationRestriction: "PROJECT_CREATION_RESTRICTION",
common.AdminInitialPassword: "HARBOR_ADMIN_PASSWORD",
common.AdmiralEndpoint: "ADMIRAL_URL",
common.WithNotary: &parser{
env: "WITH_NOTARY",
parse: parseStringToBool,
},
@ -124,23 +125,23 @@ var (
// configurations need read from environment variables
// every time the system startup
repeatLoadEnvs = map[string]interface{}{
comcfg.ExtEndpoint: "EXT_ENDPOINT",
comcfg.MySQLPassword: "MYSQL_PWD",
comcfg.MaxJobWorkers: &parser{
common.ExtEndpoint: "EXT_ENDPOINT",
common.MySQLPassword: "MYSQL_PWD",
common.MaxJobWorkers: &parser{
env: "MAX_JOB_WORKERS",
parse: parseStringToInt,
},
// TODO remove this config?
comcfg.UseCompressedJS: &parser{
common.UseCompressedJS: &parser{
env: "USE_COMPRESSED_JS",
parse: parseStringToBool,
},
comcfg.CfgExpiration: &parser{
common.CfgExpiration: &parser{
env: "CFG_EXPIRATION",
parse: parseStringToInt,
},
comcfg.AdmiralEndpoint: "ADMIRAL_URL",
comcfg.WithNotary: &parser{
common.AdmiralEndpoint: "ADMIRAL_URL",
common.WithNotary: &parser{
env: "WITH_NOTARY",
parse: parseStringToBool,
},

View File

@ -19,7 +19,7 @@ import (
"os"
"testing"
comcfg "github.com/vmware/harbor/src/common/config"
"github.com/vmware/harbor/src/common"
"github.com/vmware/harbor/src/common/utils/test"
)
@ -54,7 +54,7 @@ func TestSystemcfg(t *testing.T) {
}
m := map[string]string{
"AUTH_MODE": comcfg.DBAuth,
"AUTH_MODE": common.DBAuth,
"LDAP_SCOPE": "1",
"LDAP_TIMEOUT": "30",
"MYSQL_PORT": "3306",
@ -93,13 +93,13 @@ func TestSystemcfg(t *testing.T) {
return
}
if cfg[comcfg.AUTHMode] != comcfg.DBAuth {
if cfg[common.AUTHMode] != common.DBAuth {
t.Errorf("unexpected auth mode: %s != %s",
cfg[comcfg.AUTHMode], comcfg.DBAuth)
cfg[common.AUTHMode], common.DBAuth)
return
}
cfg[comcfg.AUTHMode] = comcfg.LDAPAuth
cfg[common.AUTHMode] = common.LDAPAuth
if err = UpdateSystemCfg(cfg); err != nil {
t.Errorf("failed to update system configurations: %v", err)
@ -112,9 +112,9 @@ func TestSystemcfg(t *testing.T) {
return
}
if cfg[comcfg.AUTHMode] != comcfg.LDAPAuth {
if cfg[common.AUTHMode] != common.LDAPAuth {
t.Errorf("unexpected auth mode: %s != %s",
cfg[comcfg.AUTHMode], comcfg.DBAuth)
cfg[common.AUTHMode], common.DBAuth)
return
}
@ -129,9 +129,9 @@ func TestSystemcfg(t *testing.T) {
return
}
if cfg[comcfg.AUTHMode] != comcfg.DBAuth {
if cfg[common.AUTHMode] != common.DBAuth {
t.Errorf("unexpected auth mode: %s != %s",
cfg[comcfg.AUTHMode], comcfg.DBAuth)
cfg[common.AUTHMode], common.DBAuth)
return
}
}

View File

@ -17,83 +17,26 @@
package config
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"strings"
"time"
"github.com/astaxie/beego/cache"
"github.com/vmware/harbor/src/common/utils"
"github.com/vmware/harbor/src/common/utils/log"
)
// const variables
const (
DBAuth = "db_auth"
LDAPAuth = "ldap_auth"
ProCrtRestrEveryone = "everyone"
ProCrtRestrAdmOnly = "adminonly"
LDAPScopeBase = "1"
LDAPScopeOnelevel = "2"
LDAPScopeSubtree = "3"
ExtEndpoint = "ext_endpoint"
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"
LDAPSearchPwd = "ldap_search_password"
LDAPBaseDN = "ldap_base_dn"
LDAPUID = "ldap_uid"
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"
EmailPassword = "email_password"
EmailFrom = "email_from"
EmailSSL = "email_ssl"
EmailIdentity = "email_identity"
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"
AdminInitialPassword = "admin_initial_password"
AdmiralEndpoint = "admiral_url"
WithNotary = "with_notary"
"github.com/vmware/harbor/src/adminserver/client"
"github.com/vmware/harbor/src/common"
)
// Manager manages configurations
type Manager struct {
Loader *Loader
Parser *Parser
client client.Client
Cache bool
cache cache.Cache
key string
}
// NewManager returns an instance of Manager
// url: the url from which loader loads configurations
func NewManager(url, secret string, enableCache bool) *Manager {
func NewManager(client client.Client, enableCache bool) *Manager {
m := &Manager{
Loader: NewLoader(url, secret),
Parser: &Parser{},
client: client,
}
if enableCache {
@ -105,19 +48,9 @@ func NewManager(url, secret string, enableCache bool) *Manager {
return m
}
// Init loader
func (m *Manager) Init() error {
return m.Loader.Init()
}
// Load configurations, if cache is enabled, cache the configurations
func (m *Manager) Load() (map[string]interface{}, error) {
b, err := m.Loader.Load()
if err != nil {
return nil, err
}
c, err := m.Parser.Parse(b)
c, err := m.client.GetCfgs()
if err != nil {
return nil, err
}
@ -127,7 +60,15 @@ func (m *Manager) Load() (map[string]interface{}, error) {
if err != nil {
return nil, err
}
if err = m.cache.Put(m.key, c,
// copy the configuration map so that later modification to the
// map does not effect the cached value
cachedCfgs := map[string]interface{}{}
for k, v := range c {
cachedCfgs[k] = v
}
if err = m.cache.Put(m.key, cachedCfgs,
time.Duration(expi)*time.Second); err != nil {
return nil, err
}
@ -138,7 +79,7 @@ func (m *Manager) Load() (map[string]interface{}, error) {
// Reset configurations
func (m *Manager) Reset() error {
return m.Loader.Reset()
return m.client.ResetCfgs()
}
func getCfgExpiration(m map[string]interface{}) (int, error) {
@ -146,7 +87,7 @@ func getCfgExpiration(m map[string]interface{}) (int, error) {
return 0, fmt.Errorf("can not get cfg expiration as configurations are null")
}
expi, ok := m[CfgExpiration]
expi, ok := m[common.CfgExpiration]
if !ok {
return 0, fmt.Errorf("cfg expiration is not set")
}
@ -167,133 +108,6 @@ func (m *Manager) Get() (map[string]interface{}, error) {
}
// Upload configurations
func (m *Manager) Upload(b []byte) error {
return m.Loader.Upload(b)
}
// Loader loads and uploads configurations
type Loader struct {
url string
secret string
client *http.Client
}
// NewLoader ...
func NewLoader(url, secret string) *Loader {
return &Loader{
url: url,
secret: secret,
client: &http.Client{},
}
}
// Init waits remote server to be ready by testing connections with it
func (l *Loader) Init() error {
addr := l.url
if strings.Contains(addr, "://") {
addr = strings.Split(addr, "://")[1]
}
if !strings.Contains(addr, ":") {
addr = addr + ":80"
}
return utils.TestTCPConn(addr, 60, 2)
}
// Load configurations from remote server
func (l *Loader) Load() ([]byte, error) {
log.Debug("loading configurations...")
req, err := http.NewRequest("GET", l.url+"/api/configurations", nil)
if err != nil {
return nil, err
}
req.AddCookie(&http.Cookie{
Name: "secret",
Value: l.secret,
})
resp, err := l.client.Do(req)
if err != nil {
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
}
log.Debug("configurations load completed")
return b, nil
}
// Upload configurations to remote server
func (l *Loader) Upload(b []byte) error {
req, err := http.NewRequest("PUT", l.url+"/api/configurations", bytes.NewReader(b))
if err != nil {
return err
}
req.AddCookie(&http.Cookie{
Name: "secret",
Value: l.secret,
})
resp, err := l.client.Do(req)
if err != nil {
return err
}
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("unexpected http status code: %d", resp.StatusCode)
}
log.Debug("configurations uploaded")
return nil
}
// Reset sends configurations resetting command to
// remote server
func (l *Loader) Reset() error {
req, err := http.NewRequest("POST", l.url+"/api/configurations/reset", nil)
if err != nil {
return err
}
req.AddCookie(&http.Cookie{
Name: "secret",
Value: l.secret,
})
resp, err := l.client.Do(req)
if err != nil {
return err
}
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("unexpected http status code: %d", resp.StatusCode)
}
log.Debug("configurations resetted")
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
func (m *Manager) Upload(cfgs map[string]interface{}) error {
return m.client.UpdateCfgs(cfgs)
}

65
src/common/const.go Normal file
View File

@ -0,0 +1,65 @@
/*
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 common
// const variables
const (
DBAuth = "db_auth"
LDAPAuth = "ldap_auth"
ProCrtRestrEveryone = "everyone"
ProCrtRestrAdmOnly = "adminonly"
LDAPScopeBase = "1"
LDAPScopeOnelevel = "2"
LDAPScopeSubtree = "3"
ExtEndpoint = "ext_endpoint"
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"
LDAPSearchPwd = "ldap_search_password"
LDAPBaseDN = "ldap_base_dn"
LDAPUID = "ldap_uid"
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"
EmailPassword = "email_password"
EmailFrom = "email_from"
EmailSSL = "email_ssl"
EmailIdentity = "email_identity"
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"
AdminInitialPassword = "admin_initial_password"
AdmiralEndpoint = "admiral_url"
WithNotary = "with_notary"
)

View File

@ -21,7 +21,7 @@ import (
"os"
"testing"
"github.com/vmware/harbor/src/common/config"
"github.com/vmware/harbor/src/common"
"github.com/vmware/harbor/src/common/dao"
"github.com/vmware/harbor/src/common/models"
"github.com/vmware/harbor/src/common/utils/log"
@ -30,24 +30,24 @@ import (
)
var adminServerLdapTestConfig = map[string]interface{}{
config.ExtEndpoint: "host01.com",
config.AUTHMode: "ldap_auth",
config.DatabaseType: "mysql",
config.MySQLHost: "127.0.0.1",
config.MySQLPort: 3306,
config.MySQLUsername: "root",
config.MySQLPassword: "root123",
config.MySQLDatabase: "registry",
config.SQLiteFile: "/tmp/registry.db",
common.ExtEndpoint: "host01.com",
common.AUTHMode: "ldap_auth",
common.DatabaseType: "mysql",
common.MySQLHost: "127.0.0.1",
common.MySQLPort: 3306,
common.MySQLUsername: "root",
common.MySQLPassword: "root123",
common.MySQLDatabase: "registry",
common.SQLiteFile: "/tmp/registry.db",
//config.SelfRegistration: true,
config.LDAPURL: "ldap://127.0.0.1",
config.LDAPSearchDN: "cn=admin,dc=example,dc=com",
config.LDAPSearchPwd: "admin",
config.LDAPBaseDN: "dc=example,dc=com",
config.LDAPUID: "uid",
config.LDAPFilter: "",
config.LDAPScope: 3,
config.LDAPTimeout: 30,
common.LDAPURL: "ldap://127.0.0.1",
common.LDAPSearchDN: "cn=admin,dc=example,dc=com",
common.LDAPSearchPwd: "admin",
common.LDAPBaseDN: "dc=example,dc=com",
common.LDAPUID: "uid",
common.LDAPFilter: "",
common.LDAPScope: 3,
common.LDAPTimeout: 30,
// config.TokenServiceURL: "",
// config.RegistryURL: "",
// config.EmailHost: "",
@ -61,10 +61,10 @@ var adminServerLdapTestConfig = map[string]interface{}{
// config.VerifyRemoteCert: false,
// config.MaxJobWorkers: 3,
// config.TokenExpiration: 30,
config.CfgExpiration: 5,
common.CfgExpiration: 5,
// config.JobLogDir: "/var/log/jobs",
// config.UseCompressedJS: true,
config.AdminInitialPassword: "password",
common.AdminInitialPassword: "password",
}
func TestMain(t *testing.T) {

View File

@ -20,46 +20,47 @@ import (
"net/http"
"net/http/httptest"
"github.com/vmware/harbor/src/common/config"
"github.com/vmware/harbor/src/adminserver/systeminfo/imagestorage"
"github.com/vmware/harbor/src/common"
)
var adminServerDefaultConfig = map[string]interface{}{
config.ExtEndpoint: "https://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.UseCompressedJS: true,
config.AdminInitialPassword: "password",
config.AdmiralEndpoint: "http://www.vmware.com",
config.WithNotary: false,
common.ExtEndpoint: "https://host01.com",
common.AUTHMode: common.DBAuth,
common.DatabaseType: "mysql",
common.MySQLHost: "127.0.0.1",
common.MySQLPort: 3306,
common.MySQLUsername: "user01",
common.MySQLPassword: "password",
common.MySQLDatabase: "registry",
common.SQLiteFile: "/tmp/registry.db",
common.SelfRegistration: true,
common.LDAPURL: "ldap://127.0.0.1",
common.LDAPSearchDN: "uid=searchuser,ou=people,dc=mydomain,dc=com",
common.LDAPSearchPwd: "password",
common.LDAPBaseDN: "ou=people,dc=mydomain,dc=com",
common.LDAPUID: "uid",
common.LDAPFilter: "",
common.LDAPScope: 3,
common.LDAPTimeout: 30,
common.TokenServiceURL: "http://token_service",
common.RegistryURL: "http://registry",
common.EmailHost: "127.0.0.1",
common.EmailPort: 25,
common.EmailUsername: "user01",
common.EmailPassword: "password",
common.EmailFrom: "from",
common.EmailSSL: true,
common.EmailIdentity: "",
common.ProjectCreationRestriction: common.ProCrtRestrAdmOnly,
common.VerifyRemoteCert: false,
common.MaxJobWorkers: 3,
common.TokenExpiration: 30,
common.CfgExpiration: 5,
common.UseCompressedJS: true,
common.AdminInitialPassword: "password",
common.AdmiralEndpoint: "http://www.vmware.com",
common.WithNotary: false,
}
// NewAdminserver returns a mock admin server
@ -101,5 +102,32 @@ func NewAdminserver(config map[string]interface{}) (*httptest.Server, error) {
}),
})
capacityHandler, err := NewCapacityHandle()
if err != nil {
return nil, err
}
m = append(m, &RequestHandlerMapping{
Method: "GET",
Pattern: "/api/systeminfo/capacity",
Handler: capacityHandler,
})
return NewServer(m...), nil
}
// NewCapacityHandle ...
func NewCapacityHandle() (func(http.ResponseWriter, *http.Request), error) {
capacity := imagestorage.Capacity{
Total: 100,
Free: 90,
}
b, err := json.Marshal(capacity)
if err != nil {
return nil, err
}
resp := &Response{
StatusCode: http.StatusOK,
Body: b,
}
return Handler(resp), nil
}

View File

@ -16,21 +16,28 @@
package config
import (
"fmt"
"os"
"github.com/vmware/harbor/src/adminserver/client"
"github.com/vmware/harbor/src/adminserver/client/auth"
"github.com/vmware/harbor/src/common"
comcfg "github.com/vmware/harbor/src/common/config"
"github.com/vmware/harbor/src/common/models"
"github.com/vmware/harbor/src/common/utils/log"
)
const (
defaultKeyPath string = "/etc/jobservice/key"
defaultLogDir string = "/var/log/jobs"
defaultKeyPath string = "/etc/jobservice/key"
defaultLogDir string = "/var/log/jobs"
secretCookieName string = "secret"
)
var (
mg *comcfg.Manager
keyProvider comcfg.KeyProvider
// AdminserverClient is a client for adminserver
AdminserverClient client.Client
mg *comcfg.Manager
keyProvider comcfg.KeyProvider
)
// Init configurations
@ -42,12 +49,15 @@ func Init() error {
if len(adminServerURL) == 0 {
adminServerURL = "http://adminserver"
}
mg = comcfg.NewManager(adminServerURL, JobserviceSecret(), true)
if err := mg.Init(); err != nil {
return err
log.Infof("initializing client for adminserver %s ...", adminServerURL)
authorizer := auth.NewSecretAuthorizer(secretCookieName, UISecret())
AdminserverClient = client.NewClient(adminServerURL, authorizer)
if err := AdminserverClient.Ping(); err != nil {
return fmt.Errorf("failed to ping adminserver: %v", err)
}
mg = comcfg.NewManager(AdminserverClient, true)
if _, err := mg.Load(); err != nil {
return err
}
@ -71,7 +81,7 @@ func VerifyRemoteCert() (bool, error) {
if err != nil {
return true, err
}
return cfg[comcfg.VerifyRemoteCert].(bool), nil
return cfg[common.VerifyRemoteCert].(bool), nil
}
// Database ...
@ -81,16 +91,16 @@ func Database() (*models.Database, error) {
return nil, err
}
database := &models.Database{}
database.Type = cfg[comcfg.DatabaseType].(string)
database.Type = cfg[common.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)
mysql.Host = cfg[common.MySQLHost].(string)
mysql.Port = int(cfg[common.MySQLPort].(float64))
mysql.Username = cfg[common.MySQLUsername].(string)
mysql.Password = cfg[common.MySQLPassword].(string)
mysql.Database = cfg[common.MySQLDatabase].(string)
database.MySQL = mysql
sqlite := &models.SQLite{}
sqlite.File = cfg[comcfg.SQLiteFile].(string)
sqlite.File = cfg[common.SQLiteFile].(string)
database.SQLite = sqlite
return database, nil
@ -102,7 +112,7 @@ func MaxJobWorkers() (int, error) {
if err != nil {
return 0, err
}
return int(cfg[comcfg.MaxJobWorkers].(float64)), nil
return int(cfg[common.MaxJobWorkers].(float64)), nil
}
// LocalUIURL returns the local ui url, job service will use this URL to call API hosted on ui process
@ -116,7 +126,7 @@ func LocalRegURL() (string, error) {
if err != nil {
return "", err
}
return cfg[comcfg.RegistryURL].(string), nil
return cfg[common.RegistryURL].(string), nil
}
// LogDir returns the absolute path to which the log file will be written
@ -151,7 +161,7 @@ func ExtEndpoint() (string, error) {
if err != nil {
return "", err
}
return cfg[comcfg.ExtEndpoint].(string), nil
return cfg[common.ExtEndpoint].(string), nil
}
// InternalTokenServiceEndpoint ...

View File

@ -20,8 +20,8 @@ import (
"net/http"
"strconv"
"github.com/vmware/harbor/src/common"
"github.com/vmware/harbor/src/common/api"
comcfg "github.com/vmware/harbor/src/common/config"
"github.com/vmware/harbor/src/common/dao"
"github.com/vmware/harbor/src/common/utils/log"
"github.com/vmware/harbor/src/ui/config"
@ -30,65 +30,65 @@ import (
var (
// valid keys of configurations which user can modify
validKeys = []string{
comcfg.ExtEndpoint,
comcfg.AUTHMode,
comcfg.DatabaseType,
comcfg.MySQLHost,
comcfg.MySQLPort,
comcfg.MySQLUsername,
comcfg.MySQLPassword,
comcfg.MySQLDatabase,
comcfg.SQLiteFile,
comcfg.SelfRegistration,
comcfg.LDAPURL,
comcfg.LDAPSearchDN,
comcfg.LDAPSearchPwd,
comcfg.LDAPBaseDN,
comcfg.LDAPUID,
comcfg.LDAPFilter,
comcfg.LDAPScope,
comcfg.LDAPTimeout,
comcfg.TokenServiceURL,
comcfg.RegistryURL,
comcfg.EmailHost,
comcfg.EmailPort,
comcfg.EmailUsername,
comcfg.EmailPassword,
comcfg.EmailFrom,
comcfg.EmailSSL,
comcfg.EmailIdentity,
comcfg.ProjectCreationRestriction,
comcfg.VerifyRemoteCert,
comcfg.MaxJobWorkers,
comcfg.TokenExpiration,
comcfg.CfgExpiration,
comcfg.JobLogDir,
comcfg.UseCompressedJS,
comcfg.AdminInitialPassword,
common.ExtEndpoint,
common.AUTHMode,
common.DatabaseType,
common.MySQLHost,
common.MySQLPort,
common.MySQLUsername,
common.MySQLPassword,
common.MySQLDatabase,
common.SQLiteFile,
common.SelfRegistration,
common.LDAPURL,
common.LDAPSearchDN,
common.LDAPSearchPwd,
common.LDAPBaseDN,
common.LDAPUID,
common.LDAPFilter,
common.LDAPScope,
common.LDAPTimeout,
common.TokenServiceURL,
common.RegistryURL,
common.EmailHost,
common.EmailPort,
common.EmailUsername,
common.EmailPassword,
common.EmailFrom,
common.EmailSSL,
common.EmailIdentity,
common.ProjectCreationRestriction,
common.VerifyRemoteCert,
common.MaxJobWorkers,
common.TokenExpiration,
common.CfgExpiration,
common.JobLogDir,
common.UseCompressedJS,
common.AdminInitialPassword,
}
numKeys = []string{
comcfg.EmailPort,
comcfg.LDAPScope,
comcfg.LDAPTimeout,
comcfg.MySQLPort,
comcfg.MaxJobWorkers,
comcfg.TokenExpiration,
comcfg.CfgExpiration,
common.EmailPort,
common.LDAPScope,
common.LDAPTimeout,
common.MySQLPort,
common.MaxJobWorkers,
common.TokenExpiration,
common.CfgExpiration,
}
boolKeys = []string{
comcfg.EmailSSL,
comcfg.SelfRegistration,
comcfg.VerifyRemoteCert,
comcfg.UseCompressedJS,
common.EmailSSL,
common.SelfRegistration,
common.VerifyRemoteCert,
common.UseCompressedJS,
}
passwordKeys = []string{
comcfg.AdminInitialPassword,
comcfg.EmailPassword,
comcfg.LDAPSearchPwd,
comcfg.MySQLPassword,
common.AdminInitialPassword,
common.EmailPassword,
common.LDAPSearchPwd,
common.MySQLPassword,
}
)
@ -157,7 +157,7 @@ func (c *ConfigAPI) Put() {
c.CustomAbort(http.StatusBadRequest, err.Error())
}
if value, ok := cfg[comcfg.AUTHMode]; ok {
if value, ok := cfg[common.AUTHMode]; ok {
mode, err := config.AuthMode()
if err != nil {
log.Errorf("failed to get auth mode: %v", err)
@ -174,7 +174,7 @@ func (c *ConfigAPI) Put() {
if !flag {
c.CustomAbort(http.StatusBadRequest,
fmt.Sprintf("%s can not be modified as new users have been inserted into database",
comcfg.AUTHMode))
common.AUTHMode))
}
}
}
@ -213,14 +213,14 @@ func validateCfg(c map[string]string) (bool, error) {
return isSysErr, err
}
if value, ok := c[comcfg.AUTHMode]; ok {
if value != comcfg.DBAuth && value != comcfg.LDAPAuth {
return isSysErr, fmt.Errorf("invalid %s, shoud be %s or %s", comcfg.AUTHMode, comcfg.DBAuth, comcfg.LDAPAuth)
if value, ok := c[common.AUTHMode]; ok {
if value != common.DBAuth && value != common.LDAPAuth {
return isSysErr, fmt.Errorf("invalid %s, shoud be %s or %s", common.AUTHMode, common.DBAuth, common.LDAPAuth)
}
mode = value
}
if mode == comcfg.LDAPAuth {
if mode == common.LDAPAuth {
ldap, err := config.LDAP()
if err != nil {
isSysErr = true
@ -228,46 +228,46 @@ func validateCfg(c map[string]string) (bool, error) {
}
if len(ldap.URL) == 0 {
if _, ok := c[comcfg.LDAPURL]; !ok {
return isSysErr, fmt.Errorf("%s is missing", comcfg.LDAPURL)
if _, ok := c[common.LDAPURL]; !ok {
return isSysErr, fmt.Errorf("%s is missing", common.LDAPURL)
}
}
if len(ldap.BaseDN) == 0 {
if _, ok := c[comcfg.LDAPBaseDN]; !ok {
return isSysErr, fmt.Errorf("%s is missing", comcfg.LDAPBaseDN)
if _, ok := c[common.LDAPBaseDN]; !ok {
return isSysErr, fmt.Errorf("%s is missing", common.LDAPBaseDN)
}
}
if len(ldap.UID) == 0 {
if _, ok := c[comcfg.LDAPUID]; !ok {
return isSysErr, fmt.Errorf("%s is missing", comcfg.LDAPUID)
if _, ok := c[common.LDAPUID]; !ok {
return isSysErr, fmt.Errorf("%s is missing", common.LDAPUID)
}
}
if ldap.Scope == 0 {
if _, ok := c[comcfg.LDAPScope]; !ok {
return isSysErr, fmt.Errorf("%s is missing", comcfg.LDAPScope)
if _, ok := c[common.LDAPScope]; !ok {
return isSysErr, fmt.Errorf("%s is missing", common.LDAPScope)
}
}
}
if ldapURL, ok := c[comcfg.LDAPURL]; ok && len(ldapURL) == 0 {
return isSysErr, fmt.Errorf("%s is empty", comcfg.LDAPURL)
if ldapURL, ok := c[common.LDAPURL]; ok && len(ldapURL) == 0 {
return isSysErr, fmt.Errorf("%s is empty", common.LDAPURL)
}
if baseDN, ok := c[comcfg.LDAPBaseDN]; ok && len(baseDN) == 0 {
return isSysErr, fmt.Errorf("%s is empty", comcfg.LDAPBaseDN)
if baseDN, ok := c[common.LDAPBaseDN]; ok && len(baseDN) == 0 {
return isSysErr, fmt.Errorf("%s is empty", common.LDAPBaseDN)
}
if uID, ok := c[comcfg.LDAPUID]; ok && len(uID) == 0 {
return isSysErr, fmt.Errorf("%s is empty", comcfg.LDAPUID)
if uID, ok := c[common.LDAPUID]; ok && len(uID) == 0 {
return isSysErr, fmt.Errorf("%s is empty", common.LDAPUID)
}
if scope, ok := c[comcfg.LDAPScope]; ok &&
scope != comcfg.LDAPScopeBase &&
scope != comcfg.LDAPScopeOnelevel &&
scope != comcfg.LDAPScopeSubtree {
if scope, ok := c[common.LDAPScope]; ok &&
scope != common.LDAPScopeBase &&
scope != common.LDAPScopeOnelevel &&
scope != common.LDAPScopeSubtree {
return isSysErr, fmt.Errorf("invalid %s, should be %s, %s or %s",
comcfg.LDAPScope,
comcfg.LDAPScopeBase,
comcfg.LDAPScopeOnelevel,
comcfg.LDAPScopeSubtree)
common.LDAPScope,
common.LDAPScopeBase,
common.LDAPScopeOnelevel,
common.LDAPScopeSubtree)
}
for _, k := range boolKeys {
@ -293,19 +293,19 @@ func validateCfg(c map[string]string) (bool, error) {
return isSysErr, fmt.Errorf("invalid %s: %s", k, v)
}
if (k == comcfg.EmailPort ||
k == comcfg.MySQLPort) && n > 65535 {
if (k == common.EmailPort ||
k == common.MySQLPort) && n > 65535 {
return isSysErr, fmt.Errorf("invalid %s: %s", k, v)
}
}
if crt, ok := c[comcfg.ProjectCreationRestriction]; ok &&
crt != comcfg.ProCrtRestrEveryone &&
crt != comcfg.ProCrtRestrAdmOnly {
if crt, ok := c[common.ProjectCreationRestriction]; ok &&
crt != common.ProCrtRestrEveryone &&
crt != common.ProCrtRestrAdmOnly {
return isSysErr, fmt.Errorf("invalid %s, should be %s or %s",
comcfg.ProjectCreationRestriction,
comcfg.ProCrtRestrAdmOnly,
comcfg.ProCrtRestrEveryone)
common.ProjectCreationRestriction,
common.ProCrtRestrAdmOnly,
common.ProCrtRestrEveryone)
}
return isSysErr, nil
@ -363,7 +363,7 @@ func convertForGet(cfg map[string]interface{}) (map[string]*value, error) {
if err != nil {
return nil, err
}
result[comcfg.AUTHMode].Editable = flag
result[common.AUTHMode].Editable = flag
return result, nil
}

View File

@ -20,7 +20,8 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/vmware/harbor/src/common/config"
"github.com/vmware/harbor/src/common"
"github.com/vmware/harbor/src/ui/config"
)
func TestGetConfig(t *testing.T) {
@ -46,8 +47,13 @@ func TestGetConfig(t *testing.T) {
return
}
mode := cfg[config.AUTHMode].Value.(string)
assert.Equal(config.DBAuth, mode, fmt.Sprintf("the auth mode should be %s", config.DBAuth))
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 TestPutConfig(t *testing.T) {
@ -56,7 +62,7 @@ func TestPutConfig(t *testing.T) {
apiTest := newHarborAPI()
cfg := map[string]string{
config.VerifyRemoteCert: "0",
common.VerifyRemoteCert: "0",
}
code, err := apiTest.PutConfig(*admin, cfg)
@ -67,6 +73,11 @@ func TestPutConfig(t *testing.T) {
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 TestResetConfig(t *testing.T) {
@ -94,11 +105,17 @@ func TestResetConfig(t *testing.T) {
return
}
value, ok := cfgs[config.VerifyRemoteCert]
value, ok := cfgs[common.VerifyRemoteCert]
if !ok {
t.Errorf("%s not found", config.VerifyRemoteCert)
t.Errorf("%s not found", common.VerifyRemoteCert)
return
}
assert.Equal(value.Value.(bool), true, "unexpected value")
ccc, err := config.GetSystemCfg()
if err != nil {
t.Logf("failed to get system configurations: %v", err)
}
t.Logf("%v", ccc)
}

View File

@ -7,8 +7,8 @@ import (
"strings"
"syscall"
"github.com/vmware/harbor/src/common"
"github.com/vmware/harbor/src/common/api"
comcfg "github.com/vmware/harbor/src/common/config"
"github.com/vmware/harbor/src/common/dao"
"github.com/vmware/harbor/src/common/utils/log"
"github.com/vmware/harbor/src/ui/config"
@ -112,19 +112,19 @@ func (sia *SystemInfoAPI) GetGeneralInfo() {
sia.CustomAbort(http.StatusInternalServerError, "Unexpected error")
}
var registryURL string
if l := strings.Split(cfg[comcfg.ExtEndpoint].(string), "://"); len(l) > 1 {
if l := strings.Split(cfg[common.ExtEndpoint].(string), "://"); len(l) > 1 {
registryURL = l[1]
} else {
registryURL = l[0]
}
_, caStatErr := os.Stat(defaultRootCert)
info := GeneralInfo{
AdmiralEndpoint: cfg[comcfg.AdmiralEndpoint].(string),
AdmiralEndpoint: cfg[common.AdmiralEndpoint].(string),
WithAdmiral: config.WithAdmiral(),
WithNotary: config.WithNotary(),
AuthMode: cfg[comcfg.AUTHMode].(string),
ProjectCreationRestrict: cfg[comcfg.ProjectCreationRestriction].(string),
SelfRegistration: cfg[comcfg.SelfRegistration].(bool),
AuthMode: cfg[common.AUTHMode].(string),
ProjectCreationRestrict: cfg[common.ProjectCreationRestriction].(string),
SelfRegistration: cfg[common.SelfRegistration].(bool),
RegistryURL: registryURL,
HasCARoot: caStatErr == nil,
}

View File

@ -6,7 +6,7 @@ import (
"os"
"testing"
"github.com/vmware/harbor/src/common/config"
"github.com/vmware/harbor/src/common"
"github.com/vmware/harbor/src/common/dao"
"github.com/vmware/harbor/src/common/models"
"github.com/vmware/harbor/src/common/utils/log"
@ -15,24 +15,24 @@ import (
)
var adminServerLdapTestConfig = map[string]interface{}{
config.ExtEndpoint: "host01.com",
config.AUTHMode: "ldap_auth",
config.DatabaseType: "mysql",
config.MySQLHost: "127.0.0.1",
config.MySQLPort: 3306,
config.MySQLUsername: "root",
config.MySQLPassword: "root123",
config.MySQLDatabase: "registry",
config.SQLiteFile: "/tmp/registry.db",
common.ExtEndpoint: "host01.com",
common.AUTHMode: "ldap_auth",
common.DatabaseType: "mysql",
common.MySQLHost: "127.0.0.1",
common.MySQLPort: 3306,
common.MySQLUsername: "root",
common.MySQLPassword: "root123",
common.MySQLDatabase: "registry",
common.SQLiteFile: "/tmp/registry.db",
//config.SelfRegistration: true,
config.LDAPURL: "ldap://127.0.0.1",
config.LDAPSearchDN: "cn=admin,dc=example,dc=com",
config.LDAPSearchPwd: "admin",
config.LDAPBaseDN: "dc=example,dc=com",
config.LDAPUID: "uid",
config.LDAPFilter: "",
config.LDAPScope: 3,
config.LDAPTimeout: 30,
common.LDAPURL: "ldap://127.0.0.1",
common.LDAPSearchDN: "cn=admin,dc=example,dc=com",
common.LDAPSearchPwd: "admin",
common.LDAPBaseDN: "dc=example,dc=com",
common.LDAPUID: "uid",
common.LDAPFilter: "",
common.LDAPScope: 3,
common.LDAPTimeout: 30,
// config.TokenServiceURL: "",
// config.RegistryURL: "",
// config.EmailHost: "",
@ -46,10 +46,10 @@ var adminServerLdapTestConfig = map[string]interface{}{
// config.VerifyRemoteCert: false,
// config.MaxJobWorkers: 3,
// config.TokenExpiration: 30,
config.CfgExpiration: 5,
common.CfgExpiration: 5,
// config.JobLogDir: "/var/log/jobs",
// config.UseCompressedJS: true,
config.AdminInitialPassword: "password",
common.AdminInitialPassword: "password",
}
func TestMain(t *testing.T) {

View File

@ -16,20 +16,28 @@
package config
import (
"encoding/json"
"fmt"
"os"
"strings"
"github.com/vmware/harbor/src/adminserver/client"
"github.com/vmware/harbor/src/adminserver/client/auth"
"github.com/vmware/harbor/src/common"
comcfg "github.com/vmware/harbor/src/common/config"
"github.com/vmware/harbor/src/common/models"
"github.com/vmware/harbor/src/common/utils/log"
)
const defaultKeyPath string = "/etc/ui/key"
const (
defaultKeyPath string = "/etc/ui/key"
secretCookieName string = "secret"
)
var (
mg *comcfg.Manager
keyProvider comcfg.KeyProvider
// AdminserverClient is a client for adminserver
AdminserverClient client.Client
mg *comcfg.Manager
keyProvider comcfg.KeyProvider
)
// Init configurations
@ -41,14 +49,17 @@ func Init() error {
if len(adminServerURL) == 0 {
adminServerURL = "http://adminserver"
}
log.Debugf("admin server URL: %s", adminServerURL)
mg = comcfg.NewManager(adminServerURL, UISecret(), true)
if err := mg.Init(); err != nil {
return err
log.Infof("initializing client for adminserver %s ...", adminServerURL)
authorizer := auth.NewSecretAuthorizer(secretCookieName, UISecret())
AdminserverClient = client.NewClient(adminServerURL, authorizer)
if err := AdminserverClient.Ping(); err != nil {
return fmt.Errorf("failed to ping adminserver: %v", err)
}
if _, err := mg.Load(); err != nil {
mg = comcfg.NewManager(AdminserverClient, true)
if err := Load(); err != nil {
return err
}
@ -78,26 +89,12 @@ func Reset() error {
// Upload uploads all system configutations to admin server
func Upload(cfg map[string]interface{}) error {
b, err := json.Marshal(cfg)
if err != nil {
return err
}
return mg.Upload(b)
return mg.Upload(cfg)
}
// GetSystemCfg returns the system configurations
func GetSystemCfg() (map[string]interface{}, error) {
raw, err := mg.Loader.Load()
if err != nil {
return nil, err
}
c, err := mg.Parser.Parse(raw)
if err != nil {
return nil, err
}
return c, nil
return mg.Load()
}
// AuthMode ...
@ -106,7 +103,7 @@ func AuthMode() (string, error) {
if err != nil {
return "", err
}
return cfg[comcfg.AUTHMode].(string), nil
return cfg[common.AUTHMode].(string), nil
}
// LDAP returns the setting of ldap server
@ -117,14 +114,14 @@ func LDAP() (*models.LDAP, error) {
}
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))
ldap.URL = cfg[common.LDAPURL].(string)
ldap.SearchDN = cfg[common.LDAPSearchDN].(string)
ldap.SearchPassword = cfg[common.LDAPSearchPwd].(string)
ldap.BaseDN = cfg[common.LDAPBaseDN].(string)
ldap.UID = cfg[common.LDAPUID].(string)
ldap.Filter = cfg[common.LDAPFilter].(string)
ldap.Scope = int(cfg[common.LDAPScope].(float64))
ldap.Timeout = int(cfg[common.LDAPTimeout].(float64))
return ldap, nil
}
@ -135,7 +132,7 @@ func TokenExpiration() (int, error) {
if err != nil {
return 0, err
}
return int(cfg[comcfg.TokenExpiration].(float64)), nil
return int(cfg[common.TokenExpiration].(float64)), nil
}
// ExtEndpoint returns the external URL of Harbor: protocol://host:port
@ -144,7 +141,7 @@ func ExtEndpoint() (string, error) {
if err != nil {
return "", err
}
return cfg[comcfg.ExtEndpoint].(string), nil
return cfg[common.ExtEndpoint].(string), nil
}
// ExtURL returns the external URL: host:port
@ -171,7 +168,7 @@ func SelfRegistration() (bool, error) {
if err != nil {
return false, err
}
return cfg[comcfg.SelfRegistration].(bool), nil
return cfg[common.SelfRegistration].(bool), nil
}
// RegistryURL ...
@ -180,7 +177,7 @@ func RegistryURL() (string, error) {
if err != nil {
return "", err
}
return cfg[comcfg.RegistryURL].(string), nil
return cfg[common.RegistryURL].(string), nil
}
// InternalJobServiceURL returns jobservice URL for internal communication between Harbor containers
@ -205,7 +202,7 @@ func InitialAdminPassword() (string, error) {
if err != nil {
return "", err
}
return cfg[comcfg.AdminInitialPassword].(string), nil
return cfg[common.AdminInitialPassword].(string), nil
}
// OnlyAdminCreateProject returns the flag to restrict that only sys admin can create project
@ -214,7 +211,7 @@ func OnlyAdminCreateProject() (bool, error) {
if err != nil {
return true, err
}
return cfg[comcfg.ProjectCreationRestriction].(string) == comcfg.ProCrtRestrAdmOnly, nil
return cfg[common.ProjectCreationRestriction].(string) == common.ProCrtRestrAdmOnly, nil
}
// VerifyRemoteCert returns bool value.
@ -223,7 +220,7 @@ func VerifyRemoteCert() (bool, error) {
if err != nil {
return true, err
}
return cfg[comcfg.VerifyRemoteCert].(bool), nil
return cfg[common.VerifyRemoteCert].(bool), nil
}
// Email returns email server settings
@ -234,13 +231,13 @@ func Email() (*models.Email, error) {
}
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)
email.Host = cfg[common.EmailHost].(string)
email.Port = int(cfg[common.EmailPort].(float64))
email.Username = cfg[common.EmailUsername].(string)
email.Password = cfg[common.EmailPassword].(string)
email.SSL = cfg[common.EmailSSL].(bool)
email.From = cfg[common.EmailFrom].(string)
email.Identity = cfg[common.EmailIdentity].(string)
return email, nil
}
@ -252,16 +249,16 @@ func Database() (*models.Database, error) {
return nil, err
}
database := &models.Database{}
database.Type = cfg[comcfg.DatabaseType].(string)
database.Type = cfg[common.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)
mysql.Host = cfg[common.MySQLHost].(string)
mysql.Port = int(cfg[common.MySQLPort].(float64))
mysql.Username = cfg[common.MySQLUsername].(string)
mysql.Password = cfg[common.MySQLPassword].(string)
mysql.Database = cfg[common.MySQLDatabase].(string)
database.MySQL = mysql
sqlite := &models.SQLite{}
sqlite.File = cfg[comcfg.SQLiteFile].(string)
sqlite.File = cfg[common.SQLiteFile].(string)
database.SQLite = sqlite
return database, nil
@ -286,7 +283,7 @@ func WithNotary() bool {
log.Errorf("Failed to get configuration, will return WithNotary == false")
return false
}
return cfg[comcfg.WithNotary].(bool)
return cfg[common.WithNotary].(bool)
}
// AdmiralEndpoint returns the URL of admiral, if Harbor is not deployed with admiral it should return an empty string.
@ -297,10 +294,10 @@ func AdmiralEndpoint() string {
return ""
}
if e, ok := cfg[comcfg.AdmiralEndpoint].(string); !ok || e == "NA" {
cfg[comcfg.AdmiralEndpoint] = ""
if e, ok := cfg[common.AdmiralEndpoint].(string); !ok || e == "NA" {
cfg[common.AdmiralEndpoint] = ""
}
return cfg[comcfg.AdmiralEndpoint].(string)
return cfg[common.AdmiralEndpoint].(string)
}
// WithAdmiral returns a bool to indicate if Harbor's deployed with admiral.