Remove everything of adminserver

Signed-off-by: stonezdj <stonezdj@gmail.com>
This commit is contained in:
stonezdj 2019-02-22 16:34:26 +08:00
parent a1063edae6
commit 0cba36d79f
49 changed files with 32 additions and 2832 deletions

1
.gitignore vendored
View File

@ -41,3 +41,4 @@ src/portal/src/**/*.js.map
**/aot
**/dist
**/.bin
src/core/conf/app.conf

View File

@ -4,13 +4,13 @@
#
# all: prepare env, compile binaries, build images and install images
# prepare: prepare env
# compile: compile adminserver, ui and jobservice code
# compile: compile core and jobservice code
#
# compile_golangimage:
# compile from golang image
# for example: make compile_golangimage -e GOBUILDIMAGE= \
# golang:1.11.2
# compile_adminserver, compile_core, compile_jobservice: compile specific binary
# compile_core, compile_jobservice: compile specific binary
#
# build: build Harbor docker images from photon baseimage
#
@ -43,7 +43,7 @@
#
# clean: remove binary, Harbor images, specific version docker-compose \
# file, specific version tag and online/offline install package
# cleanbinary: remove adminserver, ui and jobservice binary
# cleanbinary: remove core and jobservice binary
# cleanimage: remove Harbor images
# cleandockercomposefile:
# remove specific version docker-compose
@ -129,21 +129,17 @@ GOBUILDIMAGE=golang:1.11.2
GOBUILDPATH=$(GOBASEPATH)/harbor
GOIMAGEBUILDCMD=/usr/local/go/bin/go
GOIMAGEBUILD=$(GOIMAGEBUILDCMD) build
GOBUILDPATH_ADMINSERVER=$(GOBUILDPATH)/src/adminserver
GOBUILDPATH_CORE=$(GOBUILDPATH)/src/core
GOBUILDPATH_JOBSERVICE=$(GOBUILDPATH)/src/jobservice
GOBUILDPATH_REGISTRYCTL=$(GOBUILDPATH)/src/registryctl
GOBUILDPATH_MIGRATEPATCH=$(GOBUILDPATH)/src/cmd/migrate-patch
GOBUILDMAKEPATH=$(GOBUILDPATH)/make
GOBUILDMAKEPATH_ADMINSERVER=$(GOBUILDMAKEPATH)/photon/adminserver
GOBUILDMAKEPATH_CORE=$(GOBUILDMAKEPATH)/photon/core
GOBUILDMAKEPATH_JOBSERVICE=$(GOBUILDMAKEPATH)/photon/jobservice
GOBUILDMAKEPATH_REGISTRYCTL=$(GOBUILDMAKEPATH)/photon/registryctl
GOBUILDMAKEPATH_NOTARY=$(GOBUILDMAKEPATH)/photon/notary
# binary
ADMINSERVERBINARYPATH=$(MAKEDEVPATH)/adminserver
ADMINSERVERBINARYNAME=harbor_adminserver
CORE_BINARYPATH=$(MAKEDEVPATH)/core
CORE_BINARYNAME=harbor_core
JOBSERVICEBINARYPATH=$(MAKEDEVPATH)/jobservice
@ -178,7 +174,6 @@ MAKEFILEPATH_PHOTON=$(MAKEPATH)/photon
DOCKERFILEPATH_COMMON=$(MAKEPATH)/common
# docker image name
DOCKERIMAGENAME_ADMINSERVER=goharbor/harbor-adminserver
DOCKERIMAGENAME_PORTAL=goharbor/harbor-portal
DOCKERIMAGENAME_CORE=goharbor/harbor-core
DOCKERIMAGENAME_JOBSERVICE=goharbor/harbor-jobservice
@ -213,8 +208,7 @@ REGISTRYUSER=user
REGISTRYPASSWORD=default
# cmds
DOCKERSAVE_PARA=$(DOCKERIMAGENAME_ADMINSERVER):$(VERSIONTAG) \
$(DOCKERIMAGENAME_PORTAL):$(VERSIONTAG) \
DOCKERSAVE_PARA= $(DOCKERIMAGENAME_PORTAL):$(VERSIONTAG) \
$(DOCKERIMAGENAME_CORE):$(VERSIONTAG) \
$(DOCKERIMAGENAME_LOG):$(VERSIONTAG) \
$(DOCKERIMAGENAME_DB):$(VERSIONTAG) \
@ -268,13 +262,6 @@ ui_version:
check_environment:
@$(MAKEPATH)/$(CHECKENVCMD)
compile_adminserver:
@echo "compiling binary for adminserver (golang image)..."
@echo $(GOBASEPATH)
@echo $(GOBUILDPATH)
$(DOCKERCMD) run --rm -v $(BUILDPATH):$(GOBUILDPATH) -w $(GOBUILDPATH_ADMINSERVER) $(GOBUILDIMAGE) $(GOIMAGEBUILD) -o $(GOBUILDMAKEPATH_ADMINSERVER)/$(ADMINSERVERBINARYNAME)
@echo "Done."
compile_core:
@echo "compiling binary for core (golang image)..."
@echo $(GOBASEPATH)
@ -297,7 +284,7 @@ compile_notary_migrate_patch:
@$(DOCKERCMD) run --rm -v $(BUILDPATH):$(GOBUILDPATH) -w $(GOBUILDPATH_MIGRATEPATCH) $(GOBUILDIMAGE) $(GOIMAGEBUILD) -o $(GOBUILDMAKEPATH_NOTARY)/$(MIGRATEPATCHBINARYNAME)
@echo "Done."
compile:check_environment compile_adminserver compile_core compile_jobservice compile_registryctl compile_notary_migrate_patch
compile:check_environment compile_core compile_jobservice compile_registryctl compile_notary_migrate_patch
prepare:
@echo "preparing..."
@ -417,11 +404,6 @@ govet:
pushimage:
@echo "pushing harbor images ..."
@$(DOCKERTAG) $(DOCKERIMAGENAME_ADMINSERVER):$(VERSIONTAG) $(REGISTRYSERVER)$(DOCKERIMAGENAME_ADMINSERVER):$(VERSIONTAG)
@$(PUSHSCRIPTPATH)/$(PUSHSCRIPTNAME) $(REGISTRYSERVER)$(DOCKERIMAGENAME_ADMINSERVER):$(VERSIONTAG) \
$(REGISTRYUSER) $(REGISTRYPASSWORD) $(REGISTRYSERVER)
@$(DOCKERRMIMAGE) $(REGISTRYSERVER)$(DOCKERIMAGENAME_ADMINSERVER):$(VERSIONTAG)
@$(DOCKERTAG) $(DOCKERIMAGENAME_PORTAL):$(VERSIONTAG) $(REGISTRYSERVER)$(DOCKERIMAGENAME_PORTAL):$(VERSIONTAG)
@$(PUSHSCRIPTPATH)/$(PUSHSCRIPTNAME) $(REGISTRYSERVER)$(DOCKERIMAGENAME_PORTAL):$(VERSIONTAG) \
$(REGISTRYUSER) $(REGISTRYPASSWORD) $(REGISTRYSERVER)
@ -474,13 +456,11 @@ swagger_client:
cleanbinary:
@echo "cleaning binary..."
@if [ -f $(ADMINSERVERBINARYPATH)/$(ADMINSERVERBINARYNAME) ] ; then rm $(ADMINSERVERBINARYPATH)/$(ADMINSERVERBINARYNAME) ; fi
@if [ -f $(CORE_BINARYPATH)/$(CORE_BINARYNAME) ] ; then rm $(CORE_BINARYPATH)/$(CORE_BINARYNAME) ; fi
@if [ -f $(JOBSERVICEBINARYPATH)/$(JOBSERVICEBINARYNAME) ] ; then rm $(JOBSERVICEBINARYPATH)/$(JOBSERVICEBINARYNAME) ; fi
cleanimage:
@echo "cleaning image for photon..."
- $(DOCKERRMIMAGE) -f $(DOCKERIMAGENAME_ADMINSERVER):$(VERSIONTAG)
- $(DOCKERRMIMAGE) -f $(DOCKERIMAGENAME_CORE):$(VERSIONTAG)
- $(DOCKERRMIMAGE) -f $(DOCKERIMAGENAME_DB):$(VERSIONTAG)
- $(DOCKERRMIMAGE) -f $(DOCKERIMAGENAME_JOBSERVICE):$(VERSIONTAG)

View File

@ -210,7 +210,6 @@ Stopping registry ... done
Stopping redis ... done
Stopping registryctl ... done
Stopping harbor-db ... done
Stopping harbor-adminserver ... done
Stopping harbor-log ... done
```
Restarting Harbor after stopping:
@ -220,7 +219,6 @@ Starting log ... done
Starting registry ... done
Starting registryctl ... done
Starting postgresql ... done
Starting adminserver ... done
Starting core ... done
Starting portal ... done
Starting redis ... done
@ -390,7 +388,6 @@ By default, Harbor limits the CPU usage of Clair container to 150000 and avoids
$ sudo docker-compose ps
Name Command State Ports
-----------------------------------------------------------------------------------------------------------------------------
harbor-adminserver /harbor/start.sh Up
harbor-core /harbor/start.sh Up
harbor-db /entrypoint.sh postgres Up 5432/tcp
harbor-jobservice /harbor/start.sh Up

View File

@ -47,8 +47,8 @@ or above it's not necessary to call the migrator tool to migrate the schema.
```
docker run -it --rm -v ${harbor_cfg}:/harbor-migration/harbor-cfg/harbor.cfg goharbor/harbor-migrator:[tag] --cfg up
```
**NOTE:** The schema upgrade and data migration of Database is performed by adminserver when Harbor starts, if the migration fails,
please check the log of adminserver to debug.
**NOTE:** The schema upgrade and data migration of Database is performed by core when Harbor starts, if the migration fails,
please check the log of core to debug.
6. Under the directory `./harbor`, run the `./install.sh` script to install the new Harbor instance. If you choose to install Harbor with components like Notary, Clair, and chartmuseum, refer to [Installation & Configuration Guide](../docs/installation_guide.md) for more information.

View File

@ -15,9 +15,8 @@ all | prepare env, compile binaries, build images and install im
prepare | prepare env
compile | compile ui and jobservice code
compile_portal | compile portal code
compile_ui | compile ui binary
compile_core | compile core binary
compile_jobservice | compile jobservice binary
compile_adminserver | compile admin server binary
build | build Harbor docker images (default: using build_photon)
build_photon | build Harbor docker images from Photon OS base image
install | compile binaries, build images, prepare specific version of compose file and startup Harbor instance

View File

@ -2,7 +2,6 @@ LOG_LEVEL=info
CONFIG_PATH=/etc/core/app.conf
CORE_SECRET=$core_secret
JOBSERVICE_SECRET=$jobservice_secret
ADMINSERVER_URL=$adminserver_url
UAA_CA_ROOT=/etc/core/certificates/uaa_ca.pem
_REDIS_URL=$redis_host:$redis_port,100,$redis_password
SYNC_REGISTRY=false

View File

@ -99,7 +99,7 @@ services:
container_name: harbor-core
env_file:
- ./common/config/core/env
- ./common/config/adminserver/env
- ./common/config/core/config_env
restart: always
cap_drop:
- ALL

View File

@ -3,7 +3,7 @@
# Targets:
#
# build: build harbor photon images
# clean: clean adminserver, ui and jobservice harbor images
# clean: clean core and jobservice harbor images
# common
SHELL := /bin/bash
@ -21,10 +21,7 @@ DOCKERBUILD=$(DOCKERCMD) build --pull
DOCKERRMIMAGE=$(DOCKERCMD) rmi
DOCKERIMASES=$(DOCKERCMD) images
# binary
ADMINSERVERSOURCECODE=$(SRCPATH)/adminserver
ADMINSERVERBINARYPATH=$(MAKEDEVPATH)/adminserver
ADMINSERVERBINARYNAME=harbor_adminserver
# binary
CORE_SOURCECODE=$(SRCPATH)/core
CORE_BINARYPATH=$(MAKEDEVPATH)/core
CORE_BINARYNAME=harbor_core
@ -35,10 +32,6 @@ JOBSERVICEBINARYNAME=harbor_jobservice
# photon dockerfile
DOCKERFILEPATH=$(MAKEPATH)/photon
DOCKERFILEPATH_ADMINSERVER=$(DOCKERFILEPATH)/adminserver
DOCKERFILENAME_ADMINSERVER=Dockerfile
DOCKERIMAGENAME_ADMINSERVER=goharbor/harbor-adminserver
DOCKERFILEPATH_PORTAL=$(DOCKERFILEPATH)/portal
DOCKERFILENAME_PORTAL=Dockerfile
DOCKERIMAGENAME_PORTAL=goharbor/harbor-portal
@ -105,11 +98,6 @@ _build_db:
@$(DOCKERBUILD) -f $(DOCKERFILEPATH_DB)/$(DOCKERFILENAME_DB) -t $(DOCKERIMAGENAME_DB):$(VERSIONTAG) .
@echo "Done."
_build_adminserver:
@echo "building adminserver container for photon..."
@$(DOCKERBUILD) -f $(DOCKERFILEPATH_ADMINSERVER)/$(DOCKERFILENAME_ADMINSERVER) -t $(DOCKERIMAGENAME_ADMINSERVER):$(VERSIONTAG) .
@echo "Done."
_build_portal:
@echo "building portal container for photon..."
$(DOCKERBUILD) -f $(DOCKERFILEPATH_PORTAL)/$(DOCKERFILENAME_PORTAL) -t $(DOCKERIMAGENAME_PORTAL):$(VERSIONTAG) .
@ -212,11 +200,10 @@ define _get_binary
$(WGET) --timeout 30 --no-check-certificate $1 -O $2
endef
build: _build_db _build_adminserver _build_portal _build_core _build_jobservice _build_log _build_nginx _build_registry _build_registryctl _build_notary _build_clair _build_redis _build_migrator _build_chart_server
build: _build_db _build_portal _build_core _build_jobservice _build_log _build_nginx _build_registry _build_registryctl _build_notary _build_clair _build_redis _build_migrator _build_chart_server
cleanimage:
@echo "cleaning image for photon..."
- $(DOCKERRMIMAGE) -f $(DOCKERIMAGENAME_ADMINSERVER):$(VERSIONTAG)
- $(DOCKERRMIMAGE) -f $(DOCKERIMAGENAME_PORTAL):$(VERSIONTAG)
- $(DOCKERRMIMAGE) -f $(DOCKERIMAGENAME_CORE):$(VERSIONTAG)
- $(DOCKERRMIMAGE) -f $(DOCKERIMAGENAME_JOBSERVICE):$(VERSIONTAG)

View File

@ -1,15 +0,0 @@
FROM photon:2.0
RUN tdnf install -y sudo >> /dev/null \
&& tdnf clean all \
&& groupadd -r -g 10000 harbor && useradd --no-log-init -r -g 10000 -u 10000 harbor \
&& mkdir /harbor/
COPY ./make/photon/adminserver/harbor_adminserver ./make/photon/adminserver/start.sh /harbor/
#As UI will be blocked until adminserver is ready, let adminserver do the initialise work for DB
COPY ./make/migrations /harbor/migrations
HEALTHCHECK CMD curl --fail -s http://127.0.0.1:8080/api/ping || exit 1
RUN chmod u+x /harbor/harbor_adminserver /harbor/start.sh
WORKDIR /harbor/
ENTRYPOINT ["/harbor/start.sh"]

View File

@ -1,7 +0,0 @@
#!/bin/sh
#In the case when the config store is set to filesystem, the directory has to be writable.
if [ -d /etc/adminserver/config ]; then
chown -R 10000:10000 /etc/adminserver/config
fi
sudo -E -u \#10000 "/harbor/harbor_adminserver"

View File

@ -253,10 +253,6 @@ registry_custom_ca_bundle_path = rcp.get("configuration", "registry_custom_ca_bu
core_secret = ''.join(random.choice(string.ascii_letters+string.digits) for i in range(16))
jobservice_secret = ''.join(random.choice(string.ascii_letters+string.digits) for i in range(16))
adminserver_config_dir = os.path.join(config_dir,"adminserver")
if not os.path.exists(adminserver_config_dir):
os.makedirs(os.path.join(config_dir, "adminserver"))
core_config_dir = prep_conf_dir(config_dir,"core")
core_certificates_dir = prep_conf_dir(core_config_dir,"certificates")
db_config_dir = prep_conf_dir(config_dir, "db")
@ -267,7 +263,7 @@ nginx_config_dir = prep_conf_dir (config_dir, "nginx")
nginx_conf_d = prep_conf_dir(nginx_config_dir, "conf.d")
log_config_dir = prep_conf_dir (config_dir, "log")
adminserver_conf_env = os.path.join(config_dir, "adminserver", "env")
conf_env = os.path.join(config_dir, "core", "config_env")
core_conf_env = os.path.join(config_dir, "core", "env")
core_conf = os.path.join(config_dir, "core", "app.conf")
core_cert_dir = os.path.join(config_dir, "core", "certificates")
@ -279,8 +275,7 @@ db_conf_env = os.path.join(config_dir, "db", "env")
job_conf_env = os.path.join(config_dir, "jobservice", "env")
nginx_conf = os.path.join(config_dir, "nginx", "nginx.conf")
cert_dir = os.path.join(config_dir, "nginx", "cert")
log_rotate_config = os.path.join(config_dir, "log", "logrotate.conf")
adminserver_url = "http://adminserver:8080"
log_rotate_config = os.path.join(config_dir, "log", "logrotate.conf")
registry_url = "http://registry:5000"
registry_controller_url = "http://registryctl:8080"
core_url = "http://core:8080"
@ -338,8 +333,8 @@ reload_key = ''.join(random.choice(string.ascii_uppercase + string.digits) for _
ldap_group_admin_dn = rcp.get("configuration", "ldap_group_admin_dn") if rcp.has_option("configuration", "ldap_group_admin_dn") else ""
render(os.path.join(templates_dir, "adminserver", "env"),
adminserver_conf_env,
render(os.path.join(templates_dir, "core", "config_env"),
conf_env,
reload_config=reload_config,
public_url=public_url,
core_url=core_url,
@ -415,7 +410,6 @@ render(os.path.join(templates_dir, "core", "env"),
redis_host=redis_host,
redis_port=redis_port,
redis_password=redis_password,
adminserver_url = adminserver_url,
chart_cache_driver = chart_cache_driver,
redis_url_reg = redis_url_reg)

View File

@ -1,48 +0,0 @@
// Copyright Project Harbor Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package api
import (
"encoding/json"
"net/http"
)
func handleInternalServerError(w http.ResponseWriter) {
http.Error(w, http.StatusText(http.StatusInternalServerError),
http.StatusInternalServerError)
}
func handleBadRequestError(w http.ResponseWriter, error string) {
http.Error(w, error, http.StatusBadRequest)
}
func handleUnauthorized(w http.ResponseWriter) {
http.Error(w, http.StatusText(http.StatusUnauthorized),
http.StatusUnauthorized)
}
// response status code will be written automatically if there is an error
func writeJSON(w http.ResponseWriter, v interface{}) error {
b, err := json.Marshal(v)
if err != nil {
handleInternalServerError(w)
return err
}
if _, err = w.Write(b); err != nil {
return err
}
return nil
}

View File

@ -1,78 +0,0 @@
// Copyright Project Harbor Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package 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)
}
}
func TestHandleBadRequestError(t *testing.T) {
w := httptest.NewRecorder()
err := "error message"
handleBadRequestError(w, err)
if w.Code != http.StatusBadRequest {
t.Errorf("unexpected status code: %d != %d", w.Code, http.StatusBadRequest)
}
}
func TestHandleUnauthorized(t *testing.T) {
w := httptest.NewRecorder()
handleUnauthorized(w)
if w.Code != http.StatusUnauthorized {
t.Errorf("unexpected status code: %d != %d", w.Code, http.StatusUnauthorized)
}
}
func TestWriteJSONNilInterface(t *testing.T) {
w := httptest.NewRecorder()
if err := writeJSON(w, nil); err != nil {
t.Errorf("Expected nil error, received: %v", err)
}
}
func TestWriteJSONMarshallErr(t *testing.T) {
// Tests capture json.Marshall error
x := map[string]interface{}{
"foo": make(chan int),
}
w := httptest.NewRecorder()
if err := writeJSON(w, x); err == nil {
t.Errorf("Expected %v error received: no no error", err)
}
}
func TestWriteJSON(t *testing.T) {
w := httptest.NewRecorder()
if err := writeJSON(w, "Pong"); err != nil {
t.Errorf("Expected nil error, received: %v", err)
}
}

View File

@ -1,75 +0,0 @@
// Copyright Project Harbor Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package api
import (
"encoding/json"
"io/ioutil"
"net/http"
"github.com/goharbor/harbor/src/adminserver/systemcfg"
"github.com/goharbor/harbor/src/common/utils/log"
)
// ListCfgs lists configurations
func ListCfgs(w http.ResponseWriter, r *http.Request) {
cfg, err := systemcfg.CfgStore.Read()
if err != nil {
log.Errorf("failed to get system configurations: %v", err)
handleInternalServerError(w)
return
}
systemcfg.AddMissedKey(cfg)
if err = writeJSON(w, cfg); err != nil {
log.Errorf("failed to write response: %v", err)
return
}
}
// UpdateCfgs updates configurations
func UpdateCfgs(w http.ResponseWriter, r *http.Request) {
b, err := ioutil.ReadAll(r.Body)
if err != nil {
log.Errorf("failed to read request body: %v", err)
handleInternalServerError(w)
return
}
m := map[string]interface{}{}
if err = json.Unmarshal(b, &m); err != nil {
handleBadRequestError(w, err.Error())
return
}
if err = systemcfg.CfgStore.Write(m); err != nil {
log.Errorf("failed to update system configurations: %v", err)
handleInternalServerError(w)
return
}
}
// ResetCfgs resets configurations from environment variables
func ResetCfgs(w http.ResponseWriter, r *http.Request) {
cfgs := map[string]interface{}{}
if err := systemcfg.LoadFromEnv(cfgs, true); err != nil {
log.Errorf("failed to reset system configurations: %v", err)
handleInternalServerError(w)
return
}
if err := systemcfg.CfgStore.Write(cfgs); err != nil {
log.Errorf("failed to write system configurations to storage: %v", err)
handleInternalServerError(w)
return
}
}

View File

@ -1,168 +0,0 @@
// Copyright Project Harbor Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package api
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/http/httptest"
"os"
"testing"
"github.com/goharbor/harbor/src/adminserver/systemcfg"
"github.com/goharbor/harbor/src/common"
"github.com/stretchr/testify/assert"
)
type fakeCfgStore struct {
cfgs map[string]interface{}
err error
}
func (f *fakeCfgStore) Name() string {
return "fake"
}
func (f *fakeCfgStore) Read() (map[string]interface{}, error) {
return f.cfgs, f.err
}
func (f *fakeCfgStore) Write(cfgs map[string]interface{}) error {
f.cfgs = cfgs
return f.err
}
func TestListCfgs(t *testing.T) {
// 500
systemcfg.CfgStore = &fakeCfgStore{
cfgs: nil,
err: errors.New("error"),
}
w := httptest.NewRecorder()
ListCfgs(w, nil)
assert.Equal(t, http.StatusInternalServerError, w.Code)
// 200
key := "key"
value := "value"
cfgs := map[string]interface{}{
key: value,
}
systemcfg.CfgStore = &fakeCfgStore{
cfgs: cfgs,
err: nil,
}
w = httptest.NewRecorder()
ListCfgs(w, nil)
assert.Equal(t, http.StatusOK, w.Code)
result, err := parse(w.Body)
if err != nil {
t.Fatalf("failed to parse response body: %v", err)
}
assert.Equal(t, value, result[key])
}
func TestUpdateCfgs(t *testing.T) {
// 400
w := httptest.NewRecorder()
r, err := http.NewRequest("", "", bytes.NewReader([]byte{'a'}))
if err != nil {
t.Fatalf("failed to create request: %v", err)
}
UpdateCfgs(w, r)
assert.Equal(t, http.StatusBadRequest, w.Code)
// 500
systemcfg.CfgStore = &fakeCfgStore{
cfgs: nil,
err: errors.New("error"),
}
w = httptest.NewRecorder()
r, err = http.NewRequest("", "", bytes.NewBufferString("{}"))
if err != nil {
t.Fatalf("failed to create request: %v", err)
}
UpdateCfgs(w, r)
assert.Equal(t, http.StatusInternalServerError, w.Code)
// 200
key := "key"
value := "value"
systemcfg.CfgStore = &fakeCfgStore{
cfgs: nil,
err: nil,
}
w = httptest.NewRecorder()
r, err = http.NewRequest("", "",
bytes.NewBufferString(fmt.Sprintf(`{"%s":"%s"}`, key, value)))
if err != nil {
t.Fatalf("failed to create request: %v", err)
}
UpdateCfgs(w, r)
assert.Equal(t, http.StatusOK, w.Code)
}
func TestResetCfgs(t *testing.T) {
// 500
systemcfg.CfgStore = &fakeCfgStore{
cfgs: nil,
err: errors.New("error"),
}
w := httptest.NewRecorder()
ResetCfgs(w, nil)
assert.Equal(t, http.StatusInternalServerError, w.Code)
// 200
os.Clearenv()
key := "LDAP_URL"
value := "ldap://ldap.com"
if err := os.Setenv(key, value); err != nil {
t.Fatalf("failed to set env: %v", err)
}
store := &fakeCfgStore{
cfgs: nil,
err: nil,
}
systemcfg.CfgStore = store
w = httptest.NewRecorder()
ResetCfgs(w, nil)
assert.Equal(t, http.StatusOK, w.Code)
assert.Equal(t, value, store.cfgs[common.LDAPURL])
}
func parse(reader io.Reader) (map[string]interface{}, error) {
b, err := ioutil.ReadAll(reader)
if err != nil {
return nil, err
}
m := map[string]interface{}{}
if err := json.Unmarshal(b, &m); err != nil {
return nil, err
}
return m, nil
}

View File

@ -1,14 +0,0 @@
package api
import (
"github.com/goharbor/harbor/src/common/utils/log"
"net/http"
)
// Ping monitor the server status
func Ping(w http.ResponseWriter, r *http.Request) {
if err := writeJSON(w, "Pong"); err != nil {
log.Errorf("Failed to write response: %v", err)
return
}
}

View File

@ -1,17 +0,0 @@
package api
import (
"github.com/stretchr/testify/assert"
"io/ioutil"
"net/http"
"net/http/httptest"
"testing"
)
func TestPing(t *testing.T) {
w := httptest.NewRecorder()
Ping(w, nil)
assert.Equal(t, http.StatusOK, w.Code)
result, _ := ioutil.ReadAll(w.Body)
assert.Equal(t, "\"Pong\"", string(result))
}

View File

@ -1,54 +0,0 @@
// Copyright Project Harbor Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package auth
import (
"github.com/goharbor/harbor/src/common/secret"
"net/http"
)
// Authenticator defines Authenticate function to authenticate requests
type Authenticator interface {
// Authenticate the request, if there is no error, the bool value
// determines whether the request is authenticated or not
Authenticate(req *http.Request) (bool, error)
}
type secretAuthenticator struct {
secrets map[string]string
}
// NewSecretAuthenticator returns an instance of secretAuthenticator
func NewSecretAuthenticator(secrets map[string]string) Authenticator {
return &secretAuthenticator{
secrets: secrets,
}
}
// Authenticate the request according the secret
func (s *secretAuthenticator) Authenticate(req *http.Request) (bool, error) {
if len(s.secrets) == 0 {
return true, nil
}
reqSecret := secret.FromRequest(req)
for _, v := range s.secrets {
if reqSecret == v {
return true, nil
}
}
return false, nil
}

View File

@ -1,53 +0,0 @@
// Copyright Project Harbor Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package auth
import (
"net/http"
"testing"
commonsecret "github.com/goharbor/harbor/src/common/secret"
"github.com/stretchr/testify/assert"
)
func TestAuthenticate(t *testing.T) {
secret := "correct"
req1, err := http.NewRequest("", "", nil)
if err != nil {
t.Fatalf("failed to create request: %v", err)
}
req2, err := http.NewRequest("", "", nil)
if err != nil {
t.Fatalf("failed to create request: %v", err)
}
_ = commonsecret.AddToRequest(req2, secret)
cases := []struct {
secrets map[string]string
req *http.Request
result bool
}{
{nil, req1, true},
{map[string]string{"secret1": "incorrect"}, req2, false},
{map[string]string{"secret1": "incorrect", "secret2": secret}, req2, true},
}
for _, c := range cases {
authenticator := NewSecretAuthenticator(c.secrets)
authenticated, err := authenticator.Authenticate(c.req)
assert.Nil(t, err, "unexpected error")
assert.Equal(t, c.result, authenticated, "unexpected result")
}
}

View File

@ -1,105 +0,0 @@
// Copyright Project Harbor Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package client
import (
"strings"
"github.com/goharbor/harbor/src/common/http"
"github.com/goharbor/harbor/src/common/http/modifier/auth"
"github.com/goharbor/harbor/src/common/utils"
"github.com/goharbor/harbor/src/core/systeminfo/imagestorage"
)
// 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, cfg *Config) Client {
baseURL = strings.TrimRight(baseURL, "/")
if !strings.Contains(baseURL, "://") {
baseURL = "http://" + baseURL
}
client := &client{
baseURL: baseURL,
}
if cfg != nil {
authorizer := auth.NewSecretAuthorizer(cfg.Secret)
client.client = http.NewClient(nil, authorizer)
}
return client
}
type client struct {
baseURL string
client *http.Client
}
// Config contains configurations needed for client
type Config struct {
Secret string
}
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) {
url := c.baseURL + "/api/configs"
cfgs := map[string]interface{}{}
if err := c.client.Get(url, &cfgs); err != nil {
return nil, err
}
return cfgs, nil
}
// UpdateCfgs ...
func (c *client) UpdateCfgs(cfgs map[string]interface{}) error {
url := c.baseURL + "/api/configurations"
return c.client.Put(url, cfgs)
}
// ResetCfgs ...
func (c *client) ResetCfgs() error {
url := c.baseURL + "/api/configurations/reset"
return c.client.Post(url)
}
// Capacity ...
func (c *client) Capacity() (*imagestorage.Capacity, error) {
url := c.baseURL + "/api/systeminfo/capacity"
capacity := &imagestorage.Capacity{}
if err := c.client.Get(url, capacity); err != nil {
return nil, err
}
return capacity, nil
}

View File

@ -1,71 +0,0 @@
// Copyright Project Harbor Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package client
import (
"fmt"
"os"
"testing"
"github.com/goharbor/harbor/src/common"
"github.com/goharbor/harbor/src/common/utils/test"
"github.com/stretchr/testify/assert"
)
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, &Config{})
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
}
}

View File

@ -1,88 +0,0 @@
// Copyright Project Harbor Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package handlers
import (
"net/http"
"os"
"github.com/goharbor/harbor/src/adminserver/auth"
"github.com/goharbor/harbor/src/common/utils/log"
gorilla_handlers "github.com/gorilla/handlers"
)
// NewHandler returns a gorilla router which is wrapped by authenticate handler
// and logging handler
func NewHandler() http.Handler {
h := newRouter()
secrets := map[string]string{
"uiSecret": os.Getenv("CORE_SECRET"),
"jobserviceSecret": os.Getenv("JOBSERVICE_SECRET"),
}
insecureAPIs := map[string]bool{
"/api/ping": true,
}
h = newAuthHandler(auth.NewSecretAuthenticator(secrets), h, insecureAPIs)
h = gorilla_handlers.LoggingHandler(os.Stdout, h)
return h
}
type authHandler struct {
authenticator auth.Authenticator
handler http.Handler
insecureAPIs map[string]bool
}
func newAuthHandler(authenticator auth.Authenticator, handler http.Handler, insecureAPIs map[string]bool) http.Handler {
return &authHandler{
authenticator: authenticator,
handler: handler,
insecureAPIs: insecureAPIs,
}
}
func (a *authHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if a.authenticator == nil {
if a.handler != nil {
a.handler.ServeHTTP(w, r)
}
return
}
if a.insecureAPIs != nil && a.insecureAPIs[r.URL.Path] {
if a.handler != nil {
a.handler.ServeHTTP(w, r)
}
return
}
valid, err := a.authenticator.Authenticate(r)
if err != nil {
log.Errorf("failed to authenticate request: %v", err)
http.Error(w, http.StatusText(http.StatusInternalServerError),
http.StatusInternalServerError)
return
}
if !valid {
http.Error(w, http.StatusText(http.StatusUnauthorized),
http.StatusUnauthorized)
return
}
if a.handler != nil {
a.handler.ServeHTTP(w, r)
}
return
}

View File

@ -1,84 +0,0 @@
// Copyright Project Harbor Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package handlers
import (
"errors"
"net/http"
"net/http/httptest"
"testing"
"github.com/goharbor/harbor/src/adminserver/auth"
"github.com/stretchr/testify/assert"
)
type fakeAuthenticator struct {
authenticated bool
err error
}
func (f *fakeAuthenticator) Authenticate(req *http.Request) (bool, error) {
return f.authenticated, f.err
}
type fakeHandler struct {
responseCode int
}
func (f *fakeHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(f.responseCode)
}
func TestNewAuthHandler(t *testing.T) {
cases := []struct {
authenticator auth.Authenticator
handler http.Handler
insecureAPIs map[string]bool
responseCode int
requestURL string
}{
{nil, nil, nil, http.StatusOK, "http://localhost/good"},
{&fakeAuthenticator{
authenticated: false,
err: nil,
}, nil, nil, http.StatusUnauthorized, "http://localhost/hello"},
{&fakeAuthenticator{
authenticated: false,
err: errors.New("error"),
}, nil, nil, http.StatusInternalServerError, "http://localhost/hello"},
{&fakeAuthenticator{
authenticated: true,
err: nil,
}, &fakeHandler{http.StatusNotFound}, nil, http.StatusNotFound, "http://localhost/notexsit"},
{&fakeAuthenticator{
authenticated: false,
err: nil,
}, &fakeHandler{http.StatusOK}, map[string]bool{"/api/ping": true}, http.StatusOK, "http://localhost/api/ping"},
}
for _, c := range cases {
handler := newAuthHandler(c.authenticator, c.handler, c.insecureAPIs)
w := httptest.NewRecorder()
r := httptest.NewRequest("GET", c.requestURL, nil)
handler.ServeHTTP(w, r)
assert.Equal(t, c.responseCode, w.Code, "unexpected response code")
}
handler := NewHandler()
w := httptest.NewRecorder()
r := httptest.NewRequest("GET", "http://localhost/api/ping", nil)
handler.ServeHTTP(w, r)
}

View File

@ -1,31 +0,0 @@
// Copyright Project Harbor Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package handlers
import (
"net/http"
"github.com/goharbor/harbor/src/adminserver/api"
"github.com/gorilla/mux"
)
func newRouter() http.Handler {
r := mux.NewRouter()
r.HandleFunc("/api/configurations", api.UpdateCfgs).Methods("PUT")
r.HandleFunc("/api/configs", api.ListCfgs).Methods("GET")
r.HandleFunc("/api/configurations/reset", api.ResetCfgs).Methods("POST")
r.HandleFunc("/api/ping", api.Ping).Methods("GET")
return r
}

View File

@ -1,60 +0,0 @@
// Copyright Project Harbor Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
import (
"net/http"
"os"
"github.com/goharbor/harbor/src/adminserver/handlers"
syscfg "github.com/goharbor/harbor/src/adminserver/systemcfg"
"github.com/goharbor/harbor/src/common/utils/log"
)
// Server for admin component
type Server struct {
Port string
Handler http.Handler
}
// Serve the API
func (s *Server) Serve() error {
server := &http.Server{
Addr: ":" + s.Port,
Handler: s.Handler,
}
return server.ListenAndServe()
}
func main() {
log.Info("initializing system configurations...")
if err := syscfg.Init(); err != nil {
log.Fatalf("failed to initialize the system: %v", err)
}
log.Info("system initialization completed")
port := os.Getenv("PORT")
if len(port) == 0 {
port = "80"
}
server := &Server{
Port: port,
Handler: handlers.NewHandler(),
}
if err := server.Serve(); err != nil {
log.Fatal(err)
}
}

View File

@ -1,60 +0,0 @@
// Copyright Project Harbor Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package encrypt
import (
comcfg "github.com/goharbor/harbor/src/common/config"
"github.com/goharbor/harbor/src/common/utils"
)
// Encryptor encrypts or decrypts a strings
type Encryptor interface {
// Encrypt encrypts plaintext
Encrypt(string) (string, error)
// Decrypt decrypts ciphertext
Decrypt(string) (string, error)
}
// AESEncryptor uses AES to encrypt or decrypt string
type AESEncryptor struct {
keyProvider comcfg.KeyProvider
keyParams map[string]interface{}
}
// NewAESEncryptor returns an instance of an AESEncryptor
func NewAESEncryptor(keyProvider comcfg.KeyProvider,
keyParams map[string]interface{}) Encryptor {
return &AESEncryptor{
keyProvider: keyProvider,
}
}
// Encrypt ...
func (a *AESEncryptor) Encrypt(plaintext string) (string, error) {
key, err := a.keyProvider.Get(a.keyParams)
if err != nil {
return "", err
}
return utils.ReversibleEncrypt(plaintext, key)
}
// Decrypt ...
func (a *AESEncryptor) Decrypt(ciphertext string) (string, error) {
key, err := a.keyProvider.Get(a.keyParams)
if err != nil {
return "", err
}
return utils.ReversibleDecrypt(ciphertext, key)
}

View File

@ -1,92 +0,0 @@
// Copyright Project Harbor Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package encrypt
import (
"errors"
"testing"
comcfg "github.com/goharbor/harbor/src/common/config"
"github.com/stretchr/testify/assert"
)
type fakeKeyProvider struct {
key string
err error
}
func (f *fakeKeyProvider) Get(params map[string]interface{}) (
string, error) {
return f.key, f.err
}
func TestEncrypt(t *testing.T) {
cases := []struct {
plaintext string
keyProvider comcfg.KeyProvider
err bool
}{
{"", &fakeKeyProvider{"", errors.New("error")}, true},
{"text", &fakeKeyProvider{"1234567890123456", nil}, false},
}
for _, c := range cases {
encrptor := NewAESEncryptor(c.keyProvider, nil)
ciphertext, err := encrptor.Encrypt(c.plaintext)
if c.err {
assert.NotNil(t, err)
} else {
assert.Nil(t, err)
str, err := encrptor.Decrypt(ciphertext)
assert.Nil(t, err)
assert.Equal(t, c.plaintext, str)
}
}
}
func TestDecrypt(t *testing.T) {
plaintext := "text"
key := "1234567890123456"
encrptor := NewAESEncryptor(&fakeKeyProvider{
key: key,
err: nil,
}, nil)
ciphertext, err := encrptor.Encrypt(plaintext)
if err != nil {
t.Fatalf("failed to encrpt %s: %v", plaintext, err)
}
cases := []struct {
ciphertext string
keyProvider comcfg.KeyProvider
err bool
}{
{"", &fakeKeyProvider{"", errors.New("error")}, true},
{ciphertext, &fakeKeyProvider{key, nil}, false},
}
for _, c := range cases {
encrptor := NewAESEncryptor(c.keyProvider, nil)
str, err := encrptor.Decrypt(c.ciphertext)
if c.err {
assert.NotNil(t, err)
} else {
assert.Nil(t, err)
assert.Equal(t, plaintext, str)
}
}
}

View File

@ -1,151 +0,0 @@
// Copyright Project Harbor Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package database
import (
"encoding/json"
"fmt"
"strconv"
"github.com/goharbor/harbor/src/adminserver/systemcfg/store"
"github.com/goharbor/harbor/src/common"
"github.com/goharbor/harbor/src/common/dao"
"github.com/goharbor/harbor/src/common/models"
)
const (
name = "database"
)
var (
numKeys = map[string]bool{
common.EmailPort: true,
common.LDAPScope: true,
common.LDAPGroupSearchScope: true,
common.LDAPTimeout: true,
common.TokenExpiration: true,
common.MaxJobWorkers: true,
common.CfgExpiration: true,
common.ClairDBPort: true,
common.PostGreSQLPort: true,
}
boolKeys = map[string]bool{
common.WithClair: true,
common.WithNotary: true,
common.SelfRegistration: true,
common.EmailSSL: true,
common.EmailInsecure: true,
common.LDAPVerifyCert: true,
common.UAAVerifyCert: true,
common.ReadOnly: true,
common.WithChartMuseum: true,
}
mapKeys = map[string]bool{
common.ScanAllPolicy: true,
}
)
type cfgStore struct {
name string
}
// Name The name of the driver
func (c *cfgStore) Name() string {
return name
}
// NewCfgStore New a cfg store for database driver
func NewCfgStore() (store.Driver, error) {
return &cfgStore{
name: name,
}, nil
}
// Read configuration from database
func (c *cfgStore) Read() (map[string]interface{}, error) {
configEntries, err := dao.GetConfigEntries()
if err != nil {
return nil, err
}
return WrapperConfig(configEntries)
}
// WrapperConfig Wrapper the configuration
func WrapperConfig(configEntries []*models.ConfigEntry) (map[string]interface{}, error) {
config := make(map[string]interface{})
for _, entry := range configEntries {
if numKeys[entry.Key] {
strvalue, err := strconv.Atoi(entry.Value)
if err != nil {
return nil, err
}
config[entry.Key] = float64(strvalue)
} else if boolKeys[entry.Key] {
strvalue, err := strconv.ParseBool(entry.Value)
if err != nil {
return nil, err
}
config[entry.Key] = strvalue
} else if mapKeys[entry.Key] {
m := map[string]interface{}{}
if err := json.Unmarshal([]byte(entry.Value), &m); err != nil {
return nil, err
}
config[entry.Key] = m
} else {
config[entry.Key] = entry.Value
}
}
return config, nil
}
// Write save configuration to database
func (c *cfgStore) Write(config map[string]interface{}) error {
configEntries, err := TranslateConfig(config)
if err != nil {
return err
}
return dao.SaveConfigEntries(configEntries)
}
// TranslateConfig Translate configuration from int, bool, float64 to string
func TranslateConfig(config map[string]interface{}) ([]models.ConfigEntry, error) {
var configEntries []models.ConfigEntry
for k, v := range config {
var entry = new(models.ConfigEntry)
entry.Key = k
switch v.(type) {
case string:
entry.Value = v.(string)
case int:
entry.Value = strconv.Itoa(v.(int))
case bool:
entry.Value = strconv.FormatBool(v.(bool))
case float64:
entry.Value = strconv.Itoa(int(v.(float64)))
case map[string]interface{}:
data, err := json.Marshal(v)
if err != nil {
return nil, err
}
entry.Value = string(data)
default:
return nil, fmt.Errorf("unknown type %v", v)
}
configEntries = append(configEntries, *entry)
}
return configEntries, nil
}

View File

@ -1,75 +0,0 @@
package database
import (
"testing"
"github.com/goharbor/harbor/src/common"
"github.com/goharbor/harbor/src/common/models"
"github.com/stretchr/testify/assert"
)
func TestCfgStore_Name(t *testing.T) {
driver, err := NewCfgStore()
if err != nil {
t.Fatalf("Failed to create db configuration store %v", err)
}
assert.Equal(t, name, driver.Name())
}
func TestWrapperConfig(t *testing.T) {
cfg := []*models.ConfigEntry{
{
Key: common.CfgExpiration,
Value: "500",
},
{
Key: common.WithNotary,
Value: "true",
},
{
Key: common.PostGreSQLHOST,
Value: "192.168.1.210",
},
}
result, err := WrapperConfig(cfg)
if err != nil {
t.Fatalf("Failed to wrapper config %v", err)
}
withNotary, _ := result[common.WithNotary].(bool)
assert.Equal(t, true, withNotary)
postgresqlhost, ok := result[common.PostGreSQLHOST].(string)
assert.True(t, ok)
assert.Equal(t, "192.168.1.210", postgresqlhost)
expiration, ok := result[common.CfgExpiration].(float64)
assert.True(t, ok)
assert.Equal(t, float64(500), expiration)
}
func TestTranslateConfig(t *testing.T) {
config := map[string]interface{}{}
config[common.PostGreSQLHOST] = "192.168.1.210"
entries, err := TranslateConfig(config)
if err != nil {
t.Fatalf("Failed to translate configuration %v", err)
}
assert.Equal(t, "192.168.1.210", entries[0].Value)
config = make(map[string]interface{})
config[common.WithNotary] = true
entries, err = TranslateConfig(config)
if err != nil {
t.Fatalf("Failed to translate configuration %v", err)
}
assert.Equal(t, "true", entries[0].Value)
config = make(map[string]interface{})
config[common.CfgExpiration] = float64(500)
entries, err = TranslateConfig(config)
if err != nil {
t.Fatalf("Failed to translate configuration %v", err)
}
assert.Equal(t, "500", entries[0].Value)
}

View File

@ -1,26 +0,0 @@
// Copyright Project Harbor Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package store
// 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 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

@ -1,97 +0,0 @@
// Copyright Project Harbor Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package encrypt
import (
"github.com/goharbor/harbor/src/adminserver/systemcfg/encrypt"
"github.com/goharbor/harbor/src/adminserver/systemcfg/store"
"github.com/goharbor/harbor/src/common/utils/log"
)
const (
name = "encrypt"
)
// cfgStore wraps a store.Driver with an encryptor
type cfgStore struct {
// attrs need to be encrypted and decrypted
keys []string
encryptor encrypt.Encryptor
store store.Driver
}
// NewCfgStore returns an instance of cfgStore
// keys are the attrs need to be encrypted or decrypted
func NewCfgStore(encryptor encrypt.Encryptor,
keys []string, store store.Driver) store.Driver {
return &cfgStore{
keys: keys,
encryptor: encryptor,
store: store,
}
}
func (c *cfgStore) Name() string {
return name
}
func (c *cfgStore) Read() (map[string]interface{}, error) {
m, err := c.store.Read()
if err != nil {
return nil, err
}
for _, key := range c.keys {
v, ok := m[key]
if !ok {
continue
}
str, ok := v.(string)
if !ok {
log.Warningf("the value of %s is not string, skip decrypt", key)
continue
}
text, err := c.encryptor.Decrypt(str)
if err != nil {
return nil, err
}
m[key] = text
}
return m, nil
}
func (c *cfgStore) Write(m map[string]interface{}) error {
for _, key := range c.keys {
v, ok := m[key]
if !ok {
continue
}
str, ok := v.(string)
if !ok {
log.Warningf("%v is not string, skip encrypt", v)
continue
}
ciphertext, err := c.encryptor.Encrypt(str)
if err != nil {
return err
}
m[key] = ciphertext
}
return c.store.Write(m)
}

View File

@ -1,81 +0,0 @@
// Copyright Project Harbor Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package encrypt
import (
"testing"
"github.com/stretchr/testify/assert"
)
type fakeCfgStore struct {
cfgs map[string]interface{}
}
func (f *fakeCfgStore) Name() string {
return "fake"
}
func (f *fakeCfgStore) Read() (map[string]interface{}, error) {
return f.cfgs, nil
}
func (f *fakeCfgStore) Write(cfgs map[string]interface{}) error {
f.cfgs = cfgs
return nil
}
type fakeEncryptor struct {
}
func (f *fakeEncryptor) Encrypt(plaintext string) (string, error) {
return "encrypted" + plaintext, nil
}
func (f *fakeEncryptor) Decrypt(ciphertext string) (string, error) {
return "decrypted" + ciphertext, nil
}
func TestName(t *testing.T) {
driver := NewCfgStore(nil, nil, nil)
assert.Equal(t, name, driver.Name())
}
func TestRead(t *testing.T) {
keys := []string{"key"}
driver := NewCfgStore(&fakeEncryptor{}, keys, &fakeCfgStore{
cfgs: map[string]interface{}{"key": "value"},
})
cfgs, err := driver.Read()
assert.Nil(t, err)
assert.Equal(t, "decryptedvalue", cfgs["key"])
}
func TestWrite(t *testing.T) {
keys := []string{"key"}
store := &fakeCfgStore{
cfgs: map[string]interface{}{},
}
driver := NewCfgStore(&fakeEncryptor{}, keys, store)
cfgs := map[string]interface{}{
"key": "value",
}
err := driver.Write(cfgs)
assert.Nil(t, err)
assert.Equal(t, "encryptedvalue", store.cfgs["key"])
}

View File

@ -1,119 +0,0 @@
// Copyright Project Harbor Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package json
import (
"encoding/json"
"io/ioutil"
"os"
"path/filepath"
"sync"
"github.com/goharbor/harbor/src/adminserver/systemcfg/store"
"github.com/goharbor/harbor/src/common/utils/log"
)
const (
// the default path of configuration file
defaultPath = "/etc/harbor/config.json"
)
type cfgStore struct {
path string // the path of cfg file
sync.RWMutex
}
// NewCfgStore returns an instance of cfgStore that stores the configurations
// in a json file. The file will be created if it does not exist.
func NewCfgStore(path ...string) (store.Driver, error) {
p := defaultPath
if len(path) > 0 && len(path[0]) > 0 {
p = path[0]
}
log.Debugf("path of configuration file: %s", p)
if _, err := os.Stat(p); os.IsNotExist(err) {
log.Infof("the configuration file %s does not exist, creating it...", p)
if err = os.MkdirAll(filepath.Dir(p), 0600); err != nil {
return nil, err
}
if err = ioutil.WriteFile(p, []byte{}, 0600); err != nil {
return nil, err
}
}
return &cfgStore{
path: p,
}, nil
}
// Name ...
func (c *cfgStore) Name() string {
return "JSON"
}
// Read ...
func (c *cfgStore) Read() (map[string]interface{}, error) {
c.RLock()
defer c.RUnlock()
return read(c.path)
}
func read(path string) (map[string]interface{}, error) {
b, err := ioutil.ReadFile(path)
if err != nil {
return nil, err
}
// empty file
if len(b) == 0 {
return nil, nil
}
config := map[string]interface{}{}
if err = json.Unmarshal(b, &config); err != nil {
return nil, err
}
return config, nil
}
// Write ...
func (c *cfgStore) Write(config map[string]interface{}) error {
c.Lock()
defer c.Unlock()
cfg, err := read(c.path)
if err != nil {
return err
}
if cfg == nil {
cfg = config
} else {
for k, v := range config {
cfg[k] = v
}
}
b, err := json.MarshalIndent(cfg, "", " ")
if err != nil {
return err
}
return ioutil.WriteFile(c.path, b, 0600)
}

View File

@ -1,51 +0,0 @@
// Copyright Project Harbor Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package json
import (
"os"
"testing"
)
func TestReadWrite(t *testing.T) {
path := "/tmp/config.json"
store, err := NewCfgStore(path)
if err != nil {
t.Fatalf("failed to create json cfg store: %v", err)
}
defer func() {
if err := os.Remove(path); err != nil {
t.Fatalf("failed to remove the json file %s: %v", path, err)
}
}()
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.Errorf("failed to write configurations to json file: %v", err)
return
}
if _, err = store.Read(); err != nil {
t.Errorf("failed to read configurations from json file: %v", err)
return
}
}

View File

@ -1,483 +0,0 @@
// Copyright Project Harbor Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package systemcfg
import (
"fmt"
"os"
"regexp"
"strconv"
"strings"
enpt "github.com/goharbor/harbor/src/adminserver/systemcfg/encrypt"
"github.com/goharbor/harbor/src/adminserver/systemcfg/store"
"github.com/goharbor/harbor/src/adminserver/systemcfg/store/database"
"github.com/goharbor/harbor/src/adminserver/systemcfg/store/encrypt"
"github.com/goharbor/harbor/src/adminserver/systemcfg/store/json"
"github.com/goharbor/harbor/src/common"
comcfg "github.com/goharbor/harbor/src/common/config"
"github.com/goharbor/harbor/src/common/dao"
"github.com/goharbor/harbor/src/common/models"
"github.com/goharbor/harbor/src/common/utils"
"github.com/goharbor/harbor/src/common/utils/log"
)
const (
defaultJSONCfgStorePath string = "/etc/adminserver/config/config.json"
defaultKeyPath string = "/etc/adminserver/key"
ldapScopeKey string = "ldap_scope"
)
var (
// CfgStore is a storage driver that configurations
// can be read from and wrote to
CfgStore store.Driver
// attrs need to be encrypted or decrypted
attrs = []string{
common.EmailPassword,
common.LDAPSearchPwd,
common.PostGreSQLPassword,
common.AdminInitialPassword,
common.ClairDBPassword,
common.UAAClientSecret,
}
// all configurations need read from environment variables
allEnvs = map[string]interface{}{
common.ExtEndpoint: "EXT_ENDPOINT",
common.AUTHMode: "AUTH_MODE",
common.SelfRegistration: &parser{
env: "SELF_REGISTRATION",
parse: parseStringToBool,
},
common.DatabaseType: "DATABASE_TYPE",
common.PostGreSQLHOST: "POSTGRESQL_HOST",
common.PostGreSQLPort: &parser{
env: "POSTGRESQL_PORT",
parse: parseStringToInt,
},
common.PostGreSQLUsername: "POSTGRESQL_USERNAME",
common.PostGreSQLPassword: "POSTGRESQL_PASSWORD",
common.PostGreSQLDatabase: "POSTGRESQL_DATABASE",
common.PostGreSQLSSLMode: "POSTGRESQL_SSLMODE",
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,
},
common.LDAPTimeout: &parser{
env: "LDAP_TIMEOUT",
parse: parseStringToInt,
},
common.LDAPVerifyCert: &parser{
env: "LDAP_VERIFY_CERT",
parse: parseStringToBool,
},
common.LDAPGroupBaseDN: "LDAP_GROUP_BASEDN",
common.LDAPGroupSearchFilter: "LDAP_GROUP_FILTER",
common.LDAPGroupAttributeName: "LDAP_GROUP_GID",
common.LDAPGroupSearchScope: &parser{
env: "LDAP_GROUP_SCOPE",
parse: parseStringToInt,
},
common.EmailHost: "EMAIL_HOST",
common.EmailPort: &parser{
env: "EMAIL_PORT",
parse: parseStringToInt,
},
common.EmailUsername: "EMAIL_USR",
common.EmailPassword: "EMAIL_PWD",
common.EmailSSL: &parser{
env: "EMAIL_SSL",
parse: parseStringToBool,
},
common.EmailInsecure: &parser{
env: "EMAIL_INSECURE",
parse: parseStringToBool,
},
common.EmailFrom: "EMAIL_FROM",
common.EmailIdentity: "EMAIL_IDENTITY",
common.RegistryURL: "REGISTRY_URL",
common.TokenExpiration: &parser{
env: "TOKEN_EXPIRATION",
parse: parseStringToInt,
},
common.CfgExpiration: &parser{
env: "CFG_EXPIRATION",
parse: parseStringToInt,
},
common.MaxJobWorkers: &parser{
env: "MAX_JOB_WORKERS",
parse: parseStringToInt,
},
common.ProjectCreationRestriction: "PROJECT_CREATION_RESTRICTION",
common.AdminInitialPassword: "HARBOR_ADMIN_PASSWORD",
common.AdmiralEndpoint: "ADMIRAL_URL",
common.WithNotary: &parser{
env: "WITH_NOTARY",
parse: parseStringToBool,
},
common.WithClair: &parser{
env: "WITH_CLAIR",
parse: parseStringToBool,
},
common.ClairDBPassword: "CLAIR_DB_PASSWORD",
common.ClairDB: "CLAIR_DB",
common.ClairDBUsername: "CLAIR_DB_USERNAME",
common.ClairDBHost: "CLAIR_DB_HOST",
common.ClairDBPort: &parser{
env: "CLAIR_DB_PORT",
parse: parseStringToInt,
},
common.ClairDBSSLMode: "CLAIR_DB_SSLMODE",
common.UAAEndpoint: "UAA_ENDPOINT",
common.UAAClientID: "UAA_CLIENTID",
common.UAAClientSecret: "UAA_CLIENTSECRET",
common.UAAVerifyCert: &parser{
env: "UAA_VERIFY_CERT",
parse: parseStringToBool,
},
common.CoreURL: "CORE_URL",
common.JobServiceURL: "JOBSERVICE_URL",
common.TokenServiceURL: "TOKEN_SERVICE_URL",
common.ClairURL: "CLAIR_URL",
common.NotaryURL: "NOTARY_URL",
common.RegistryStorageProviderName: "REGISTRY_STORAGE_PROVIDER_NAME",
common.ReadOnly: &parser{
env: "READ_ONLY",
parse: parseStringToBool,
},
common.ReloadKey: "RELOAD_KEY",
common.LdapGroupAdminDn: "LDAP_GROUP_ADMIN_DN",
common.ChartRepoURL: "CHART_REPOSITORY_URL",
common.WithChartMuseum: &parser{
env: "WITH_CHARTMUSEUM",
parse: parseStringToBool,
},
}
// configurations need read from environment variables
// every time the system startup
repeatLoadEnvs = map[string]interface{}{
common.ExtEndpoint: "EXT_ENDPOINT",
common.PostGreSQLHOST: "POSTGRESQL_HOST",
common.PostGreSQLPort: &parser{
env: "POSTGRESQL_PORT",
parse: parseStringToInt,
},
common.PostGreSQLUsername: "POSTGRESQL_USERNAME",
common.PostGreSQLPassword: "POSTGRESQL_PASSWORD",
common.PostGreSQLDatabase: "POSTGRESQL_DATABASE",
common.PostGreSQLSSLMode: "POSTGRESQL_SSLMODE",
common.MaxJobWorkers: &parser{
env: "MAX_JOB_WORKERS",
parse: parseStringToInt,
},
common.CfgExpiration: &parser{
env: "CFG_EXPIRATION",
parse: parseStringToInt,
},
common.AdmiralEndpoint: "ADMIRAL_URL",
common.WithNotary: &parser{
env: "WITH_NOTARY",
parse: parseStringToBool,
},
common.WithClair: &parser{
env: "WITH_CLAIR",
parse: parseStringToBool,
},
common.ClairDBPassword: "CLAIR_DB_PASSWORD",
common.ClairDBHost: "CLAIR_DB_HOST",
common.ClairDBUsername: "CLAIR_DB_USERNAME",
common.ClairDBPort: &parser{
env: "CLAIR_DB_PORT",
parse: parseStringToInt,
},
common.ClairDBSSLMode: "CLAIR_DB_SSLMODE",
common.UAAEndpoint: "UAA_ENDPOINT",
common.UAAClientID: "UAA_CLIENTID",
common.UAAClientSecret: "UAA_CLIENTSECRET",
common.UAAVerifyCert: &parser{
env: "UAA_VERIFY_CERT",
parse: parseStringToBool,
},
common.RegistryStorageProviderName: "REGISTRY_STORAGE_PROVIDER_NAME",
common.CoreURL: "CORE_URL",
common.JobServiceURL: "JOBSERVICE_URL",
common.RegistryURL: "REGISTRY_URL",
common.TokenServiceURL: "TOKEN_SERVICE_URL",
common.ClairURL: "CLAIR_URL",
common.NotaryURL: "NOTARY_URL",
common.DatabaseType: "DATABASE_TYPE",
common.ChartRepoURL: "CHART_REPOSITORY_URL",
common.WithChartMuseum: &parser{
env: "WITH_CHARTMUSEUM",
parse: parseStringToBool,
},
}
)
type parser struct {
// the name of env
env string
// parse the value of env, e.g. parse string to int or
// parse string to bool
parse func(string) (interface{}, error)
}
func parseStringToInt(str string) (interface{}, error) {
if len(str) == 0 {
return 0, nil
}
return strconv.Atoi(str)
}
func parseStringToBool(str string) (interface{}, error) {
return strings.ToLower(str) == "true" ||
strings.ToLower(str) == "on", nil
}
// Init system configurations. If env RESET is set or configurations
// read from storage driver is null, load all configurations from env
func Init() (err error) {
// init database
envCfgs := map[string]interface{}{}
if err := LoadFromEnv(envCfgs, true); err != nil {
return err
}
db := GetDatabaseFromCfg(envCfgs)
if err := dao.InitDatabase(db); err != nil {
return err
}
if err := dao.UpgradeSchema(db); err != nil {
return err
}
if err := dao.CheckSchemaVersion(); err != nil {
return err
}
if err := initCfgStore(); err != nil {
return err
}
// Use reload key to avoid reset customed setting after restart
curCfgs, err := CfgStore.Read()
if err != nil {
return err
}
loadAll := isLoadAll(curCfgs)
if curCfgs == nil {
curCfgs = map[string]interface{}{}
}
// restart: only repeatload envs will be load
// reload_config: all envs will be reload except the skiped envs
if err = LoadFromEnv(curCfgs, loadAll); err != nil {
return err
}
AddMissedKey(curCfgs)
return CfgStore.Write(curCfgs)
}
func isLoadAll(cfg map[string]interface{}) bool {
return cfg == nil || strings.EqualFold(os.Getenv("RESET"), "true") && os.Getenv("RELOAD_KEY") != cfg[common.ReloadKey]
}
func initCfgStore() (err error) {
drivertype := os.Getenv("CFG_DRIVER")
if len(drivertype) == 0 {
drivertype = common.CfgDriverDB
}
path := os.Getenv("JSON_CFG_STORE_PATH")
if len(path) == 0 {
path = defaultJSONCfgStorePath
}
log.Infof("the path of json configuration storage: %s", path)
if drivertype == common.CfgDriverDB {
CfgStore, err = database.NewCfgStore()
if err != nil {
return err
}
// migration check: if no data in the db , then will try to load from path
m, err := CfgStore.Read()
if err != nil {
return err
}
if m == nil || len(m) == 0 {
if _, err := os.Stat(path); err == nil {
jsondriver, err := json.NewCfgStore(path)
if err != nil {
log.Errorf("Failed to migrate configuration from %s", path)
return err
}
jsonconfig, err := jsondriver.Read()
if err != nil {
log.Errorf("Failed to read old configuration from %s", path)
return err
}
// Update LDAP Scope for migration
// only used when migrating harbor release before v1.3
// after v1.3 there is always a db configuration before migrate.
validLdapScope(jsonconfig, true)
err = CfgStore.Write(jsonconfig)
if err != nil {
log.Error("Failed to update old configuration to database")
return err
}
}
}
} else {
CfgStore, err = json.NewCfgStore(path)
if err != nil {
return err
}
}
kp := os.Getenv("KEY_PATH")
if len(kp) == 0 {
kp = defaultKeyPath
}
log.Infof("the path of key used by key provider: %s", kp)
encryptor := enpt.NewAESEncryptor(
comcfg.NewFileKeyProvider(kp), nil)
CfgStore = encrypt.NewCfgStore(encryptor, attrs, CfgStore)
return nil
}
// LoadFromEnv loads the configurations from allEnvs, if all is false, it just loads
// the repeatLoadEnvs and the env which is absent in cfgs
func LoadFromEnv(cfgs map[string]interface{}, all bool) error {
var envs map[string]interface{}
if all {
envs = allEnvs
} else {
envs = make(map[string]interface{})
for k, v := range repeatLoadEnvs {
envs[k] = v
}
for k, v := range allEnvs {
if _, exist := cfgs[k]; !exist {
envs[k] = v
}
}
}
reloadCfg := os.Getenv("RESET")
skipPattern := os.Getenv("SKIP_RELOAD_ENV_PATTERN")
skipPattern = strings.TrimSpace(skipPattern)
if len(skipPattern) == 0 {
skipPattern = "$^" // doesn't match any string by default
}
skipMatcher, err := regexp.Compile(skipPattern)
if err != nil {
log.Errorf("Regular express parse error, skipPattern:%v", skipPattern)
skipMatcher = regexp.MustCompile("$^")
}
for k, v := range envs {
if str, ok := v.(string); ok {
if skipMatcher.MatchString(str) && strings.EqualFold(reloadCfg, "true") {
continue
}
cfgs[k] = os.Getenv(str)
continue
}
if parser, ok := v.(*parser); ok {
if skipMatcher.MatchString(parser.env) && strings.EqualFold(reloadCfg, "true") {
continue
}
i, err := parser.parse(os.Getenv(parser.env))
if err != nil {
return err
}
cfgs[k] = i
continue
}
return fmt.Errorf("%v is not string or parse type", v)
}
validLdapScope(cfgs, false)
return nil
}
// GetDatabaseFromCfg Create database object from config
func GetDatabaseFromCfg(cfg map[string]interface{}) *models.Database {
database := &models.Database{}
database.Type = cfg[common.DatabaseType].(string)
postgresql := &models.PostGreSQL{}
postgresql.Host = utils.SafeCastString(cfg[common.PostGreSQLHOST])
postgresql.Port = int(utils.SafeCastInt(cfg[common.PostGreSQLPort]))
postgresql.Username = utils.SafeCastString(cfg[common.PostGreSQLUsername])
postgresql.Password = utils.SafeCastString(cfg[common.PostGreSQLPassword])
postgresql.Database = utils.SafeCastString(cfg[common.PostGreSQLDatabase])
postgresql.SSLMode = utils.SafeCastString(cfg[common.PostGreSQLSSLMode])
database.PostGreSQL = postgresql
return database
}
// Valid LDAP Scope
func validLdapScope(cfg map[string]interface{}, isMigrate bool) {
ldapScope, ok := cfg[ldapScopeKey].(int)
if !ok {
ldapScopeFloat, ok := cfg[ldapScopeKey].(float64)
if ok {
ldapScope = int(ldapScopeFloat)
}
}
if isMigrate && ldapScope > 0 && ldapScope < 3 {
ldapScope = ldapScope - 1
}
if ldapScope >= 3 {
ldapScope = 2
}
if ldapScope < 0 {
ldapScope = 0
}
cfg[ldapScopeKey] = ldapScope
}
// AddMissedKey ... If the configure key is missing in the cfg map, add default value to it
func AddMissedKey(cfg map[string]interface{}) {
for k, v := range common.HarborStringKeysMap {
if _, exist := cfg[k]; !exist {
cfg[k] = v
}
}
for k, v := range common.HarborNumKeysMap {
if _, exist := cfg[k]; !exist {
cfg[k] = v
}
}
for k, v := range common.HarborBoolKeysMap {
if _, exist := cfg[k]; !exist {
cfg[k] = v
}
}
}

View File

@ -1,290 +0,0 @@
// Copyright Project Harbor Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package systemcfg
import (
"os"
"testing"
"github.com/goharbor/harbor/src/common"
"github.com/stretchr/testify/assert"
)
func TestParseStringToInt(t *testing.T) {
cases := []struct {
input string
result int
}{
{"1", 1},
{"-1", -1},
{"0", 0},
{"", 0},
}
for _, c := range cases {
i, err := parseStringToInt(c.input)
assert.Nil(t, err)
assert.Equal(t, c.result, i)
}
}
func TestParseStringToBool(t *testing.T) {
cases := []struct {
input string
result bool
}{
{"true", true},
{"on", true},
{"TRUE", true},
{"ON", true},
{"other", false},
{"", false},
}
for _, c := range cases {
b, _ := parseStringToBool(c.input)
assert.Equal(t, c.result, b)
}
}
func TestInitCfgStore(t *testing.T) {
os.Clearenv()
path := "/tmp/config.json"
if err := os.Setenv("CFG_DRIVER", "json"); err != nil {
t.Fatalf("failed to set env: %v", err)
}
if err := os.Setenv("JSON_CFG_STORE_PATH", path); err != nil {
t.Fatalf("failed to set env: %v", err)
}
defer os.RemoveAll(path)
err := initCfgStore()
assert.Nil(t, err)
}
func TestLoadFromEnv(t *testing.T) {
os.Clearenv()
ldapURL := "ldap://ldap.com"
extEndpoint := "http://harbor.com"
if err := os.Setenv("LDAP_URL", ldapURL); err != nil {
t.Fatalf("failed to set env: %v", err)
}
cfgs := map[string]interface{}{}
err := LoadFromEnv(cfgs, true)
assert.Nil(t, err)
assert.Equal(t, ldapURL, cfgs[common.LDAPURL])
os.Clearenv()
if err := os.Setenv("LDAP_URL", ldapURL); err != nil {
t.Fatalf("failed to set env: %v", err)
}
if err := os.Setenv("EXT_ENDPOINT", extEndpoint); err != nil {
t.Fatalf("failed to set env: %v", err)
}
if err := os.Setenv("LDAP_VERIFY_CERT", "false"); err != nil {
t.Fatalf("failed to set env: %v", err)
}
cfgs = map[string]interface{}{}
err = LoadFromEnv(cfgs, false)
assert.Nil(t, err)
assert.Equal(t, extEndpoint, cfgs[common.ExtEndpoint])
assert.Equal(t, ldapURL, cfgs[common.LDAPURL])
assert.Equal(t, false, cfgs[common.LDAPVerifyCert])
os.Clearenv()
if err := os.Setenv("LDAP_URL", ldapURL); err != nil {
t.Fatalf("failed to set env: %v", err)
}
if err := os.Setenv("EXT_ENDPOINT", extEndpoint); err != nil {
t.Fatalf("failed to set env: %v", err)
}
if err := os.Setenv("LDAP_VERIFY_CERT", "true"); err != nil {
t.Fatalf("failed to set env: %v", err)
}
cfgs = map[string]interface{}{
common.LDAPURL: "ldap_url",
}
err = LoadFromEnv(cfgs, false)
assert.Nil(t, err)
assert.Equal(t, extEndpoint, cfgs[common.ExtEndpoint])
assert.Equal(t, "ldap_url", cfgs[common.LDAPURL])
assert.Equal(t, true, cfgs[common.LDAPVerifyCert])
}
func TestIsLoadAll(t *testing.T) {
os.Clearenv()
if err := os.Setenv("RELOAD_KEY", "123456"); err != nil {
t.Fatalf("failed to set env: %v", err)
}
if err := os.Setenv("RESET", "True"); err != nil {
t.Fatalf("failed to set env: %v", err)
}
cfg1 := map[string]interface{}{common.ReloadKey: "123456"}
cfg2 := map[string]interface{}{common.ReloadKey: "654321"}
assert.False(t, isLoadAll(cfg1))
assert.True(t, isLoadAll(cfg2))
}
func TestLoadFromEnvWithReloadConfigInvalidSkipPattern(t *testing.T) {
os.Clearenv()
ldapURL := "ldap://ldap.com"
extEndpoint := "http://harbor.com"
cfgsReload := map[string]interface{}{
common.LDAPURL: "ldap_url",
}
if err := os.Setenv("LDAP_URL", ldapURL); err != nil {
t.Fatalf("failed to set env: %v", err)
}
if err := os.Setenv("EXT_ENDPOINT", extEndpoint); err != nil {
t.Fatalf("failed to set env: %v", err)
}
if err := os.Setenv("LDAP_VERIFY_CERT", "false"); err != nil {
t.Fatalf("failed to set env: %v", err)
}
if err := os.Setenv("SKIP_RELOAD_ENV_PATTERN", "a(b"); err != nil {
t.Fatalf("failed to set env: %v", err)
}
err := LoadFromEnv(cfgsReload, true)
if err != nil {
t.Fatalf("failed to load From env: %v", err)
}
assert.Equal(t, ldapURL, cfgsReload[common.LDAPURL])
os.Clearenv()
}
func TestLoadFromEnvWithReloadConfigSkipPattern(t *testing.T) {
os.Clearenv()
ldapURL := "ldap://ldap.com"
extEndpoint := "http://harbor.com"
cfgsReload := map[string]interface{}{
common.LDAPURL: "ldap_url",
}
if err := os.Setenv("LDAP_URL", ldapURL); err != nil {
t.Fatalf("failed to set env: %v", err)
}
if err := os.Setenv("EXT_ENDPOINT", extEndpoint); err != nil {
t.Fatalf("failed to set env: %v", err)
}
if err := os.Setenv("LDAP_VERIFY_CERT", "false"); err != nil {
t.Fatalf("failed to set env: %v", err)
}
if err := os.Setenv("SKIP_RELOAD_ENV_PATTERN", "^LDAP.*"); err != nil {
t.Fatalf("failed to set env: %v", err)
}
if err := os.Setenv("RESET", "true"); err != nil {
t.Fatalf("failed to set env: %v", err)
}
err := LoadFromEnv(cfgsReload, false)
if err != nil {
t.Fatalf("failed to load From env: %v", err)
}
assert.Equal(t, "ldap_url", cfgsReload[common.LDAPURL]) // env value ignored
os.Clearenv()
}
func TestGetDatabaseFromCfg(t *testing.T) {
cfg := map[string]interface{}{
common.DatabaseType: "postgresql",
common.PostGreSQLDatabase: "registry",
common.PostGreSQLHOST: "127.0.0.1",
common.PostGreSQLPort: 5432,
common.PostGreSQLPassword: "root123",
common.PostGreSQLUsername: "postgres",
}
database := GetDatabaseFromCfg(cfg)
assert.Equal(t, "postgresql", database.Type)
}
func TestValidLdapScope(t *testing.T) {
var dbValue float64
dbValue = 2
ldapScopeKey := "ldap_scope"
testCfgs := []struct {
config map[string]interface{}
migrate bool
ldapScopeResult int
}{
{map[string]interface{}{
ldapScopeKey: 1,
}, true, 0},
{map[string]interface{}{
ldapScopeKey: 2,
}, true, 1},
{map[string]interface{}{
ldapScopeKey: 3,
}, true, 2},
{map[string]interface{}{
ldapScopeKey: -1,
}, true, 0},
{map[string]interface{}{
ldapScopeKey: 100,
}, false, 2},
{map[string]interface{}{
ldapScopeKey: -100,
}, false, 0},
{map[string]interface{}{
ldapScopeKey: dbValue,
}, false, 2},
}
for i, item := range testCfgs {
validLdapScope(item.config, item.migrate)
if item.config[ldapScopeKey].(int) != item.ldapScopeResult {
t.Fatalf("Failed to update ldapScope expected %v, actual %v at index %v", item.ldapScopeResult, item.config[ldapScopeKey], i)
}
}
}
func Test_AddMissingKey(t *testing.T) {
cfg := map[string]interface{}{
common.LDAPURL: "sampleurl",
common.EmailPort: 555,
common.LDAPVerifyCert: true,
}
type args struct {
cfg map[string]interface{}
}
tests := []struct {
name string
args args
}{
{"Add default value", args{cfg}},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
AddMissedKey(tt.args.cfg)
})
}
if _, ok := cfg[common.LDAPBaseDN]; !ok {
t.Errorf("Can not found default value for %v", common.LDAPBaseDN)
}
}

View File

@ -1,112 +0,0 @@
// Copyright Project Harbor Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package config provide methods to get the configurations reqruied by code in src/common
package config
import (
"fmt"
"time"
"github.com/astaxie/beego/cache"
"github.com/goharbor/harbor/src/adminserver/client"
"github.com/goharbor/harbor/src/common"
)
// Manager manages configurations
type Manager struct {
client client.Client
Cache bool
cache cache.Cache
key string
}
// NewManager returns an instance of Manager
func NewManager(client client.Client, enableCache bool) *Manager {
m := &Manager{
client: client,
}
if enableCache {
m.Cache = true
m.cache = cache.NewMemoryCache()
m.key = "cfg"
}
return m
}
// Load configurations, if cache is enabled, cache the configurations
func (m *Manager) Load() (map[string]interface{}, error) {
c, err := m.client.GetCfgs()
if err != nil {
return nil, err
}
if m.Cache {
expi, err := getCfgExpiration(c)
if err != nil {
return nil, err
}
// 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
}
}
return c, nil
}
// Reset configurations
func (m *Manager) Reset() error {
return m.client.ResetCfgs()
}
func getCfgExpiration(m map[string]interface{}) (int, error) {
if m == nil {
return 0, fmt.Errorf("can not get cfg expiration as configurations are null")
}
expi, ok := m[common.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() (map[string]interface{}, error) {
if m.Cache {
c := m.cache.Get(m.key)
if c != nil {
return c.(map[string]interface{}), nil
}
}
return m.Load()
}
// Upload configurations
func (m *Manager) Upload(cfgs map[string]interface{}) error {
return m.client.UpdateCfgs(cfgs)
}

View File

@ -1,17 +0,0 @@
// Copyright Project Harbor Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package config
// the functions in common/config/config.go have been tested
// by cases in UI and Jobservice

View File

@ -125,8 +125,10 @@ func (c *CfgManager) GetAll() map[string]interface{} {
metaDataList := metadata.Instance().GetAll()
for _, item := range metaDataList {
cfgValue, err := c.store.GetAnyType(item.Name)
if err != metadata.ErrValueNotSet && err != nil {
log.Errorf("Failed to get value of key %v, error %v", item.Name, err)
if err != nil {
if err != metadata.ErrValueNotSet {
log.Errorf("Failed to get value of key %v, error %v", item.Name, err)
}
continue
}
resultMap[item.Name] = cfgValue
@ -145,8 +147,10 @@ func (c *CfgManager) GetUserCfgs() map[string]interface{} {
for _, item := range metaDataList {
if item.Scope == metadata.UserScope {
cfgValue, err := c.store.GetAnyType(item.Name)
if err != metadata.ErrValueNotSet && err != nil {
log.Errorf("Failed to get value of key %v, error %v", item.Name, err)
if err != nil {
if err != metadata.ErrValueNotSet {
log.Errorf("Failed to get value of key %v, error %v", item.Name, err)
}
continue
}
resultMap[item.Name] = cfgValue

View File

@ -80,7 +80,6 @@ const (
MaxJobWorkers = "max_job_workers"
TokenExpiration = "token_expiration"
CfgExpiration = "cfg_expiration"
JobLogDir = "job_log_dir"
AdminInitialPassword = "admin_initial_password"
AdmiralEndpoint = "admiral_url"
WithNotary = "with_notary"
@ -98,7 +97,6 @@ const (
UAAVerifyCert = "uaa_verify_cert"
DefaultClairEndpoint = "http://clair:6060"
CfgDriverDB = "db"
CfgDriverJSON = "json"
NewHarborAdminName = "admin@harbor.local"
RegistryStorageProviderName = "registry_storage_provider_name"
UserMember = "u"
@ -106,7 +104,6 @@ const (
ReadOnly = "read_only"
ClairURL = "clair_url"
NotaryURL = "notary_url"
DefaultAdminserverEndpoint = "http://adminserver:8080"
DefaultCoreEndpoint = "http://core:8080"
DefaultNotaryEndpoint = "http://notary-server:4443"
LdapGroupType = 1
@ -123,48 +120,3 @@ const (
RobotPrefix = "robot$"
CoreConfigPath = "/api/internal/configurations"
)
// TODO remove with adminserver
// Shared variable, not allowed to modify
var (
// value is default value
HarborStringKeysMap = map[string]string{
AUTHMode: "db_auth",
LDAPURL: "",
LDAPSearchDN: "",
LDAPSearchPwd: "",
LDAPBaseDN: "",
LDAPUID: "",
LDAPFilter: "",
LDAPGroupAttributeName: "",
LDAPGroupBaseDN: "",
LdapGroupAdminDn: "",
LDAPGroupSearchFilter: "",
EmailHost: "smtp.mydomain.com",
EmailUsername: "sample_admin@mydomain.com",
EmailPassword: "abc",
EmailFrom: "admin <sample_admin@mydomain.com>",
EmailIdentity: "",
ProjectCreationRestriction: ProCrtRestrEveryone,
UAAClientID: "",
UAAEndpoint: "",
}
HarborNumKeysMap = map[string]int{
EmailPort: 25,
LDAPScope: 2,
LDAPTimeout: 5,
LDAPGroupSearchScope: 2,
TokenExpiration: 30,
}
HarborBoolKeysMap = map[string]bool{
EmailSSL: false,
EmailInsecure: false,
SelfRegistration: true,
LDAPVerifyCert: true,
UAAVerifyCert: true,
ReadOnly: false,
}
)

View File

@ -1,25 +1,15 @@
package token
import (
"github.com/goharbor/harbor/src/common/rbac"
"github.com/goharbor/harbor/src/common/utils/test"
"github.com/goharbor/harbor/src/core/config"
"github.com/stretchr/testify/assert"
"os"
"testing"
"github.com/goharbor/harbor/src/common/rbac"
"github.com/goharbor/harbor/src/core/config"
"github.com/stretchr/testify/assert"
)
func TestMain(m *testing.M) {
server, err := test.NewAdminserver(nil)
if err != nil {
panic(err)
}
defer server.Close()
if err := os.Setenv("ADMINSERVER_URL", server.URL); err != nil {
panic(err)
}
if err := config.Init(); err != nil {
panic(err)
}

View File

@ -15,14 +15,10 @@
package test
import (
"encoding/json"
"net/http"
"net/http/httptest"
"github.com/goharbor/harbor/src/common"
)
var adminServerDefaultConfig = map[string]interface{}{
var defaultConfig = map[string]interface{}{
common.ExtEndpoint: "https://host01.com",
common.AUTHMode: common.DBAuth,
common.DatabaseType: "postgresql",
@ -77,54 +73,7 @@ var adminServerDefaultConfig = map[string]interface{}{
common.NotaryURL: "http://notary-server:4443",
}
// NewAdminserver returns a mock admin server
func NewAdminserver(config map[string]interface{}) (*httptest.Server, error) {
m := []*RequestHandlerMapping{}
if config == nil {
config = adminServerDefaultConfig
} else {
for k, v := range adminServerDefaultConfig {
if _, ok := config[k]; !ok {
config[k] = v
}
}
}
b, err := json.Marshal(config)
if err != nil {
return nil, err
}
resp := &Response{
StatusCode: http.StatusOK,
Body: b,
}
m = append(m, &RequestHandlerMapping{
Method: "GET",
Pattern: "/api/configs",
Handler: Handler(resp),
})
m = append(m, &RequestHandlerMapping{
Method: "PUT",
Pattern: "/api/configurations",
Handler: Handler(&Response{
StatusCode: http.StatusOK,
}),
})
m = append(m, &RequestHandlerMapping{
Method: "POST",
Pattern: "/api/configurations/reset",
Handler: Handler(&Response{
StatusCode: http.StatusOK,
}),
})
return NewServer(m...), nil
}
// GetDefaultConfigMap returns the defailt config map for easier modification.
func GetDefaultConfigMap() map[string]interface{} {
return adminServerDefaultConfig
return defaultConfig
}

View File

@ -382,7 +382,7 @@ The following configuration options are supported:
| worker_pool.redis_pool.namespace | The namespace used in redis| JOB_SERVICE_POOL_REDIS_NAMESPACE |
| loggers | Loggers for job service itself. Refer to [Configure loggers](#configure-loggers)| |
| job_loggers | Loggers for the running jobs. Refer to [Configure loggers](#configure-loggers) | |
| admin_server | The harbor admin server endpoint which used to retrieve Harbor configures| ADMINSERVER_URL |
| core_server | The harbor core server endpoint which used to retrieve Harbor configures| CORE_URL |
### Sample
@ -428,9 +428,6 @@ job_loggers:
loggers:
- name: "STD_OUTPUT" # Same with above
level: "DEBUG"
#Admin server endpoint
admin_server: "http://adminserver:9010/"
```
## API

View File

@ -65,8 +65,6 @@ type Configuration struct {
// Server listening port
Port uint `yaml:"port"`
AdminServer string `yaml:"admin_server"`
// Additional config when using https
HTTPSConfig *HTTPSConfig `yaml:"https_config,omitempty"`
@ -171,11 +169,6 @@ func GetUIAuthSecret() string {
return utils.ReadEnv(uiAuthSecret)
}
// GetAdminServerEndpoint return the admin server endpoint
func GetAdminServerEndpoint() string {
return DefaultConfig.AdminServer
}
// Load env variables
func (c *Configuration) loadEnvs() {
prot := utils.ReadEnv(jobServiceProtocol)
@ -251,11 +244,6 @@ func (c *Configuration) loadEnvs() {
}
}
// admin server
if coreServer := utils.ReadEnv(jobServiceCoreServerEndpoint); !utils.IsEmptyStr(coreServer) {
c.AdminServer = coreServer
}
}
// Check if the configurations are valid settings.
@ -325,9 +313,5 @@ func (c *Configuration) validate() error {
return errors.New("missing logger config of job")
}
if _, err := url.Parse(c.AdminServer); err != nil {
return fmt.Errorf("invalid admin server endpoint: %s", err)
}
return nil // valid
}

View File

@ -69,11 +69,6 @@ func TestDefaultConfig(t *testing.T) {
if err := DefaultConfig.Load("../config_test.yml", true); err != nil {
t.Fatalf("Load config from yaml file, expect nil error but got error '%s'\n", err)
}
if endpoint := GetAdminServerEndpoint(); endpoint != "http://127.0.0.1:8888" {
t.Errorf("expect default admin server endpoint 'http://127.0.0.1:8888' but got '%s'\n", endpoint)
}
redisURL := DefaultConfig.PoolConfig.RedisPoolCfg.RedisURL
if redisURL != "redis://localhost:6379" {
t.Errorf("expect redisURL '%s' but got '%s'\n", "redis://localhost:6379", redisURL)

View File

@ -46,4 +46,3 @@ if response.status_code == 200 :
else:
print("Failed with http return code:"+ str(response.status_code))
sys.exit(1)

View File

@ -14,8 +14,4 @@ else
fi
echo "server ip is "$IP
sed -i -r "s/POSTGRESQL_HOST=postgresql/POSTGRESQL_HOST=$IP/" make/common/config/adminserver/env
sed -i -r "s|REGISTRY_URL=http://registry:5000|REGISTRY_URL=http://$IP:5000|" make/common/config/adminserver/env
sed -i -r "s/CORE_SECRET=.*/CORE_SECRET=$CORE_SECRET/" make/common/config/adminserver/env
chmod 777 /data/

View File

@ -32,7 +32,6 @@ sudo mkdir -p /harbor && sudo mv ./VERSION /harbor/UIVERSION
sudo ./tests/testprepare.sh
cd tests && sudo ./ldapprepare.sh && sudo ./admiral.sh && cd ..
sudo make compile_adminserver
sudo make -f make/photon/Makefile _build_db _build_registry -e VERSIONTAG=dev -e CLAIRDBVERSION=dev -e REGISTRYVERSION=${REG_VERSION}
sudo sed -i 's/__reg_version__/${REG_VERSION}-dev/g' ./make/docker-compose.test.yml
sudo sed -i 's/__version__/dev/g' ./make/docker-compose.test.yml